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 },

Reply via email to