Diff below adds a new feature to bridge(4), similar to Cisco's Protected
Port but with more possibilities.
The idea is to prevent traffic to flow between some members of a bridge(4).
For example:
- you want to prevent some of your servers to talk to each others, or
- you want employees/students/clients to have access to internet and a
printer but not to each other, or
- you want VMs to have access to an uplink but not to each other
With the diff below it is now possible to defined "protected groups".
Interface that are part of such groups cannot send/receive traffic
to/from any other member of the group.
In the example below, em1 and em2 can only send/receive traffic through
em0 because they are both in the protected group 2.
bridge0: flags=41<UP,RUNNING>
index 9 llprio 3
groups: bridge
priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp
designated: id 00:00:00:00:00:00 priority 0
em0 flags=3<LEARNING,DISCOVER>
port 6 ifpriority 0 ifcost 0
em1 flags=3<LEARNING,DISCOVER>
port 7 ifpriority 0 ifcost 0 protected 2
em2 flags=3<LEARNING,DISCOVER>
port 8 ifpriority 0 ifcost 0 protected 2
Adding an interface to a protected group is as simple as:
# ifconfig bridge0 protected em1 2
Removing it:
# ifconfig bridge0 -protected em1
Comments? Oks?
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.301
diff -u -p -r1.301 if_bridge.c
--- sys/net/if_bridge.c 10 Jan 2018 23:50:39 -0000 1.301
+++ sys/net/if_bridge.c 22 Jan 2018 14:27:41 -0000
@@ -409,6 +409,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
}
req->ifbr_ifsflags = p->bif_flags;
req->ifbr_portno = p->ifp->if_index & 0xfff;
+ req->ifbr_protected = p->bif_protected;
if (p->bif_flags & IFBIF_STP) {
bp = p->bif_stp;
req->ifbr_state = bstp_getstate(bs, bp);
@@ -496,6 +497,19 @@ bridge_ioctl(struct ifnet *ifp, u_long c
brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
break;
+ case SIOCBRDGSIFPROT:
+ ifs = ifunit(req->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ p = (struct bridge_iflist *)ifs->if_bridgeport;
+ if (p == NULL || p->bridge_sc != sc) {
+ error = ESRCH;
+ break;
+ }
+ p->bif_protected = req->ifbr_protected;
+ break;
case SIOCBRDGRTS:
case SIOCBRDGGCACHE:
case SIOCBRDGGPRI:
@@ -594,6 +608,7 @@ bridge_bifconf(struct bridge_softc *sc,
strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
breq->ifbr_ifsflags = p->bif_flags;
breq->ifbr_portno = p->ifp->if_index & 0xfff;
+ breq->ifbr_protected = p->bif_protected;
if (p->bif_flags & IFBIF_STP) {
bp = p->bif_stp;
breq->ifbr_state = bstp_getstate(sc->sc_stp, bp);
@@ -848,6 +863,7 @@ bridgeintr_frame(struct bridge_softc *sc
struct bridge_rtnode *dst_p;
struct ether_addr *dst, *src;
struct ether_header eh;
+ u_int32_t protected;
int len;
@@ -960,6 +976,7 @@ bridgeintr_frame(struct bridge_softc *sc
bridge_broadcast(sc, src_if, &eh, m);
return;
}
+ protected = ifl->bif_protected;
/*
* At this point, we're dealing with a unicast frame going to a
@@ -975,6 +992,14 @@ bridgeintr_frame(struct bridge_softc *sc
m_freem(m);
return;
}
+ /*
+ * Do not transmit if both ports are part of the same protected
+ * group.
+ */
+ if (protected != 0 && protected == ifl->bif_protected) {
+ m_freem(m);
+ return;
+ }
if (bridge_filterrule(&ifl->bif_brlout, &eh, m) == BRL_ACTION_BLOCK) {
m_freem(m);
return;
@@ -1159,6 +1184,10 @@ bridge_broadcast(struct bridge_softc *sc
struct mbuf *mc;
struct ifnet *dst_if;
int len, used = 0;
+ u_int32_t protected;
+
+ p = (struct bridge_iflist *)ifp->if_bridgeport;
+ protected = p->bif_protected;
TAILQ_FOREACH(p, &sc->sc_iflist, next) {
dst_if = p->ifp;
@@ -1177,6 +1206,13 @@ bridge_broadcast(struct bridge_softc *sc
/* Drop non-IP frames if the appropriate flag is set. */
if (p->bif_flags & IFBIF_BLOCKNONIP &&
bridge_blocknonip(eh, m))
+ continue;
+
+ /*
+ * Do not transmit if both ports are part of the same
+ * protected group.
+ */
+ if (protected != 0 && protected == p->bif_protected)
continue;
if (bridge_filterrule(&p->bif_brlout, eh, m) ==
BRL_ACTION_BLOCK)
Index: sys/net/if_bridge.h
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.h,v
retrieving revision 1.55
diff -u -p -r1.55 if_bridge.h
--- sys/net/if_bridge.h 20 Jan 2017 05:03:48 -0000 1.55
+++ sys/net/if_bridge.h 22 Jan 2018 15:13:07 -0000
@@ -46,6 +46,7 @@ struct ifbreq {
char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */
u_int32_t ifbr_ifsflags; /* member ifs flags */
u_int32_t ifbr_portno; /* member port number */
+ u_int32_t ifbr_protected; /* protected group number */
u_int8_t ifbr_state; /* member stp state */
u_int8_t ifbr_priority; /* member stp priority */
@@ -398,6 +399,7 @@ struct bridge_iflist {
struct brl_head bif_brlout; /* output rules */
struct ifnet *ifp; /* member interface */
u_int32_t bif_flags; /* member flags */
+ u_int32_t bif_protected; /* protected group */
void *bif_dhcookie;
};
#define bif_state bif_stp->bp_state
Index: sys/sys/sockio.h
===================================================================
RCS file: /cvs/src/sys/sys/sockio.h,v
retrieving revision 1.72
diff -u -p -r1.72 sockio.h
--- sys/sys/sockio.h 24 Oct 2017 09:36:13 -0000 1.72
+++ sys/sys/sockio.h 22 Jan 2018 14:09:09 -0000
@@ -89,6 +89,7 @@
#define SIOCBRDGDADDR _IOW('i', 71, struct ifbareq) /* delete addr
*/
#define SIOCBRDGFLUSH _IOW('i', 72, struct ifbreq) /* flush addr
cache */
#define SIOCBRDGADDL _IOW('i', 73, struct ifbreq) /* add local
port */
+#define SIOCBRDGSIFPROT _IOW('i', 74, struct ifbreq) /* set
protected grp */
#define SIOCBRDGARL _IOW('i', 77, struct ifbrlreq) /* add bridge rule */
#define SIOCBRDGFRL _IOW('i', 78, struct ifbrlreq) /* flush brdg rules */
Index: sbin/ifconfig/brconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.c,v
retrieving revision 1.16
diff -u -p -r1.16 brconfig.c
--- sbin/ifconfig/brconfig.c 31 Jul 2017 02:32:11 -0000 1.16
+++ sbin/ifconfig/brconfig.c 22 Jan 2018 14:30:38 -0000
@@ -336,6 +336,8 @@ bridge_list(char *delim)
printf("port %u ifpriority %u ifcost %u",
reqp->ifbr_portno, reqp->ifbr_priority,
reqp->ifbr_path_cost);
+ if (reqp->ifbr_protected)
+ printf(" protected %u", reqp->ifbr_protected);
if (reqp->ifbr_ifsflags & IFBIF_STP)
printf(" %s role %s",
stpstates[reqp->ifbr_state],
@@ -452,6 +454,41 @@ bridge_priority(const char *arg, int d)
bp.ifbrp_prio = v;
if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0)
err(1, "%s", name);
+}
+
+void
+bridge_protect(const char *ifname, const char *val)
+{
+ struct ifbreq breq;
+ unsigned long v;
+ char *endptr;
+
+ strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
+ strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
+
+ errno = 0;
+ v = strtoul(val, &endptr, 0);
+ if (val[0] == '\0' || endptr[0] != '\0' || v == 0 || v > UINT32_MAX ||
+ (errno == ERANGE && v == ULONG_MAX))
+ err(1, "invalid arg for protected group: %s", val);
+ breq.ifbr_protected = v;
+
+ if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0)
+ err(1, "%s: %s", name, val);
+}
+
+void
+bridge_unprotect(const char *ifname, int d)
+{
+ struct ifbreq breq;
+
+ strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
+ strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
+
+ breq.ifbr_protected = 0;
+
+ if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0)
+ err(1, "%s: %d", name, 0);
}
void
Index: sbin/ifconfig/brconfig.h
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.h,v
retrieving revision 1.12
diff -u -p -r1.12 brconfig.h
--- sbin/ifconfig/brconfig.h 16 Jan 2018 10:33:55 -0000 1.12
+++ sbin/ifconfig/brconfig.h 22 Jan 2018 14:12:39 -0000
@@ -52,6 +52,8 @@ void bridge_addrs(const char *, int);
void bridge_hellotime(const char *, int);
void bridge_fwddelay(const char *, int);
void bridge_maxage(const char *, int);
+void bridge_protect(const char *, const char *);
+void bridge_unprotect(const char *, int);
void bridge_proto(const char *, int);
void bridge_ifprio(const char *, const char *);
void bridge_ifcost(const char *, const char *);
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.292
diff -u -p -r1.292 ifconfig.8
--- sbin/ifconfig/ifconfig.8 16 Jan 2018 10:33:55 -0000 1.292
+++ sbin/ifconfig/ifconfig.8 22 Jan 2018 15:11:32 -0000
@@ -662,6 +662,13 @@ The default is 100 entries.
.It Cm maxage Ar time
Set the time (in seconds) that a spanning tree protocol configuration is valid.
Defaults to 20 seconds, minimum of 6, maximum of 40.
+.It Cm protected Ar interface Ar id
+Put
+.Ar interface
+in protected mode.
+A protected interface does not forward traffic to any other protected interface
+having the same
+.Ar id .
.It Cm proto Ar value
Force the spanning tree protocol version.
The available values are
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.353
diff -u -p -r1.353 ifconfig.c
--- sbin/ifconfig/ifconfig.c 16 Jan 2018 10:33:55 -0000 1.353
+++ sbin/ifconfig/ifconfig.c 22 Jan 2018 14:17:17 -0000
@@ -472,6 +472,8 @@ const struct cmd {
{ "-edge", NEXTARG, 0, unsetedge },
{ "autoedge", NEXTARG, 0, setautoedge },
{ "-autoedge", NEXTARG, 0, unsetautoedge },
+ { "protected", NEXTARG2, 0, NULL, bridge_protect },
+ { "-protected", NEXTARG, 0, bridge_unprotect },
{ "ptp", NEXTARG, 0, setptp },
{ "-ptp", NEXTARG, 0, unsetptp },
{ "autoptp", NEXTARG, 0, setautoptp },