On 22/01/18(Mon) 16:23, Martin Pieuchot wrote:
> 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.
Thanks for all the feedbacks I received. Diff below addresses multiple
points after discussion with dlg@ and martijn@:
- Stop using the word 'group' which confuse people. Instead talk of
'protected domain'. Interfaces that are part of such domain cannot
send traffic to each others.
- Allows interface to be part of multiple protected domains. I'm
using bits for that, meaning that we have a maximum of 31 domains.
In the example below we have to protected domains { em0, em2 } and
{ em1 , em2 }.
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 protected 11
em1 flags=3<LEARNING,DISCOVER>
port 7 ifpriority 0 ifcost 0 protected 2,11
em2 flags=3<LEARNING,DISCOVER>
port 8 ifpriority 0 ifcost 0 protected 2
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 31 Jan 2018 15:42:30 -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
+ * domain.
+ */
+ 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 domain.
+ */
+ 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 31 Jan 2018 15:22:57 -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 domains */
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 domains */
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 31 Jan 2018 15:16:41 -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 31 Jan 2018 16:12:34 -0000
@@ -336,6 +336,16 @@ 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) {
+ int v;
+
+ v = ffs(reqp->ifbr_protected);
+ printf(" protected %u", v);
+ while (++v < 32) {
+ if ((1 << (v - 1)) & reqp->ifbr_protected)
+ printf(",%u", v);
+ }
+ };
if (reqp->ifbr_ifsflags & IFBIF_STP)
printf(" %s role %s",
stpstates[reqp->ifbr_state],
@@ -452,6 +462,54 @@ 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 *optlist, *str;
+ char *endptr;
+
+ strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
+ strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
+ breq.ifbr_protected = 0;
+
+ /* We muck with the string, so copy it. */
+ optlist = strdup(val);
+ if (optlist == NULL)
+ err(1, "strdup");
+
+ str = strtok(optlist, ",");
+ while (str != NULL) {
+ errno = 0;
+ v = strtoul(str, &endptr, 0);
+ if (str[0] == '\0' || endptr[0] != '\0' || v == 0 || v > 31 ||
+ (errno == ERANGE && v == ULONG_MAX))
+ err(1, "invalid value for protected domain: %s", str);
+ breq.ifbr_protected |= (1 << (v - 1));
+ str = strtok(NULL, ",");
+ }
+
+ if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0)
+ err(1, "%s: %s", name, val);
+
+ free(optlist);
+}
+
+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 31 Jan 2018 15:16:41 -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 31 Jan 2018 15:36:35 -0000
@@ -662,6 +662,14 @@ 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 ids
+Put
+.Ar interface
+in protected domains.
+.Ar ids
+is a comma delimited list of domain IDs to put the interface in.
+Interfaces that are part of a protected domain cannot forward traffic to any
+other interface in that domain .
.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 31 Jan 2018 15:53:19 -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 },