On 21/04/19(Sun) 16:45, Martin Pieuchot wrote:
> Diff below removes the KERNEL_LOCK() from bridge(4)'s output fast-path.
> 
> To do so, it redefines the ifp <-> bridge relationship.  Currently every
> interface in a bridge(4) contains a pointer to that bridge's port.  This
> relationship is guaranteed to be valid as long as the KERNEL_LOCK() is
> held.  We cannot use the NET_LOCK() to protect this relation because
> wifi drivers still call bridge_output() in interrupt handlers.  So I
> decided to put the bridge's interface index in `struct ifnet' instead.
> 
> bridge_rtlookup() is now also returning an interface index for similar
> reasons.
> 
> The `interface list' and `span list' are still protected by the
> KERNEL_LOCK() in this diff.  Next step will be to move to SMR and remove
> the intermediate queue in the input path.
> 
> All of that should improve latency of bridge(4) and allow us to continue
> untangle the various locks in the Network Stack.
> 
> This has been quite extensively tested by Hrvoje Popovski.  I'm looking
> for more tests, reviews and oks :)

Updated diff that adds an if_put() in an error path and remove an
unrelated refactoring, both issues pointed by visa@.

Index: net/bridgectl.c
===================================================================
RCS file: /cvs/src/sys/net/bridgectl.c,v
retrieving revision 1.17
diff -u -p -r1.17 bridgectl.c
--- net/bridgectl.c     8 Mar 2019 17:48:35 -0000       1.17
+++ net/bridgectl.c     4 Apr 2019 19:58:21 -0000
@@ -84,8 +84,7 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
@@ -126,8 +125,7 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
@@ -137,6 +135,7 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                        error = EINVAL;
                        break;
                }
+               bif = bridge_getbif(ifs);
                if (brlreq->ifbr_flags & BRL_FLAG_IN) {
                        error = bridge_addrule(bif, brlreq, 0);
                        if (error)
@@ -154,11 +153,11 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
+               bif = bridge_getbif(ifs);
                bridge_flushrule(bif);
                break;
        case SIOCBRDGGRL:
@@ -167,11 +166,11 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
+               bif = bridge_getbif(ifs);
                error = bridge_brlconf(bif, bc);
                break;
        default:
@@ -206,7 +205,7 @@ bridge_rtupdate(struct bridge_softc *sc,
                        goto done;
 
                bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
-               p->brt_if = ifp;
+               p->brt_ifidx = ifp->if_index;
                p->brt_age = 1;
                bridge_copytag(brtag, &p->brt_tunnel);
 
@@ -227,16 +226,14 @@ bridge_rtupdate(struct bridge_softc *sc,
                dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
                if (dir == 0) {
                        if (setflags) {
-                               q->brt_if = ifp;
+                               q->brt_ifidx = ifp->if_index;
                                q->brt_flags = flags;
                        } else if (!(q->brt_flags & IFBAF_STATIC))
-                               q->brt_if = ifp;
+                               q->brt_ifidx = ifp->if_index;
 
-                       if (q->brt_if == ifp)
+                       if (q->brt_ifidx == ifp->if_index)
                                q->brt_age = 1;
-                       ifp = q->brt_if;
                        bridge_copytag(brtag, &q->brt_tunnel);
-
                        goto want;
                }
 
@@ -248,7 +245,7 @@ bridge_rtupdate(struct bridge_softc *sc,
                                goto done;
 
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
-                       p->brt_if = ifp;
+                       p->brt_ifidx = ifp->if_index;
                        p->brt_age = 1;
                        bridge_copytag(brtag, &p->brt_tunnel);
 
@@ -270,7 +267,7 @@ bridge_rtupdate(struct bridge_softc *sc,
                                goto done;
 
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
-                       p->brt_if = ifp;
+                       p->brt_ifidx = ifp->if_index;
                        p->brt_age = 1;
                        bridge_copytag(brtag, &p->brt_tunnel);
 
@@ -291,11 +288,12 @@ want:
        return (error);
 }
 
-struct ifnet *
-bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea, struct mbuf *m)
+unsigned int
+bridge_rtlookup(struct ifnet *brifp, struct ether_addr *ea, struct mbuf *m)
 {
+       struct bridge_softc *sc = brifp->if_softc;
        struct bridge_rtnode *p = NULL;
-       struct ifnet *ifp = NULL;
+       unsigned int ifidx = 0;
        u_int32_t h;
        int dir;
 
@@ -311,7 +309,7 @@ bridge_rtlookup(struct bridge_softc *sc,
                }
        }
        if (p != NULL) {
-               ifp = p->brt_if;
+               ifidx = p->brt_ifidx;
 
                if (p->brt_family != AF_UNSPEC && m != NULL) {
                        struct bridge_tunneltag *brtag;
@@ -323,7 +321,7 @@ bridge_rtlookup(struct bridge_softc *sc,
        }
        mtx_leave(&sc->sc_mtx);
 
-       return (ifp);
+       return (ifidx);
 }
 
 u_int32_t
@@ -378,16 +376,14 @@ void
 bridge_rtagenode(struct ifnet *ifp, int age)
 {
        struct bridge_softc *sc;
-       struct bridge_iflist *bif;
        struct bridge_rtnode *n;
+       struct ifnet *bifp;
        int i;
 
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
-       if (bif == NULL)
-               return;
-       sc = bif->bridge_sc;
-       if (sc == NULL)
+       bifp = if_get(ifp->if_bridgeidx);
+       if (bifp == NULL)
                return;
+       sc = bifp->if_softc;
 
        /*
         * If the age is zero then flush, otherwise set all the expiry times to
@@ -400,7 +396,7 @@ bridge_rtagenode(struct ifnet *ifp, int 
                for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                        LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
                                /* Cap the expiry time to 'age' */
-                               if (n->brt_if == ifp &&
+                               if (n->brt_ifidx == ifp->if_index &&
                                    n->brt_age > time_uptime + age &&
                                    (n->brt_flags & IFBAF_TYPEMASK) == 
IFBAF_DYNAMIC)
                                        n->brt_age = time_uptime + age;
@@ -408,6 +404,8 @@ bridge_rtagenode(struct ifnet *ifp, int 
                }
                mtx_leave(&sc->sc_mtx);
        }
+
+       if_put(bifp);
 }
 
 /*
@@ -479,7 +477,7 @@ bridge_rtdelete(struct bridge_softc *sc,
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
-                       if (n->brt_if != ifp) {
+                       if (n->brt_ifidx != ifp->if_index) {
                                /* Not ours */
                                n = LIST_NEXT(n, brt_next);
                                continue;
@@ -531,13 +529,21 @@ bridge_rtfind(struct bridge_softc *sc, s
        mtx_enter(&sc->sc_mtx);
        for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) {
                LIST_FOREACH(n, &sc->sc_rts[k], brt_next) {
+                       struct ifnet *ifp;
+
                        if (i >= total)
                                goto done;
                        bareq = &bareqs[i];
+
+                       ifp = if_get(n->brt_ifidx);
+                       if (ifp == NULL)
+                               continue;
+                       bcopy(ifp->if_xname, bareq->ifba_ifsname,
+                           sizeof(bareq->ifba_ifsname));
+                       if_put(ifp);
+
                        bcopy(sc->sc_if.if_xname, bareq->ifba_name,
                            sizeof(bareq->ifba_name));
-                       bcopy(n->brt_if->if_xname, bareq->ifba_ifsname,
-                           sizeof(bareq->ifba_ifsname));
                        bcopy(&n->brt_addr, &bareq->ifba_dst,
                            sizeof(bareq->ifba_dst));
                        bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
@@ -565,7 +571,7 @@ bridge_update(struct ifnet *ifp, struct 
 
        addr = (u_int8_t *)ea;
 
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
+       bif = bridge_getbif(ifp);
        if (bif == NULL)
                return;
        sc = bif->bridge_sc;
Index: net/bridgestp.c
===================================================================
RCS file: /cvs/src/sys/net/bridgestp.c,v
retrieving revision 1.68
diff -u -p -r1.68 bridgestp.c
--- net/bridgestp.c     31 Mar 2019 13:56:25 -0000      1.68
+++ net/bridgestp.c     4 Apr 2019 19:58:21 -0000
@@ -1616,7 +1616,7 @@ bstp_ifstate(void *arg)
                return;
 
        s = splnet();
-       if ((bif = (struct bridge_iflist *)ifp->if_bridgeport) == NULL)
+       if ((bif = bridge_getbif(ifp)) == NULL)
                goto done;
        if ((bif->bif_flags & IFBIF_STP) == 0)
                goto done;
@@ -2092,8 +2092,7 @@ bstp_ioctl(struct ifnet *ifp, u_long cmd
                        err = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        err = ESRCH;
                        break;
                }
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.580
diff -u -p -r1.580 if.c
--- net/if.c    22 Apr 2019 03:26:16 -0000      1.580
+++ net/if.c    23 Apr 2019 15:23:08 -0000
@@ -695,12 +695,10 @@ if_enqueue(struct ifnet *ifp, struct mbu
 #endif
 
 #if NBRIDGE > 0
-       if (ifp->if_bridgeport && (m->m_flags & M_PROTO1) == 0) {
+       if (ifp->if_bridgeidx && (m->m_flags & M_PROTO1) == 0) {
                int error;
 
-               KERNEL_LOCK();
-               error = bridge_output(ifp, m, NULL, NULL);
-               KERNEL_UNLOCK();
+               error = bridge_enqueue(ifp, m);
                return (error);
        }
 #endif
@@ -1194,7 +1192,7 @@ if_isconnected(const struct ifnet *ifp0,
                connected = 1;
 
 #if NBRIDGE > 0
-       if (SAME_BRIDGE(ifp0->if_bridgeport, ifp->if_bridgeport))
+       if (ifp0->if_bridgeidx == ifp->if_bridgeidx)
                connected = 1;
 #endif
 #if NCARP > 0
Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.327
diff -u -p -r1.327 if_bridge.c
--- net/if_bridge.c     15 Apr 2019 03:26:55 -0000      1.327
+++ net/if_bridge.c     23 Apr 2019 15:39:15 -0000
@@ -111,14 +111,14 @@ int       bridge_ifremove(struct bridge_iflist
 void   bridge_spanremove(struct bridge_iflist *);
 int    bridge_input(struct ifnet *, struct mbuf *, void *);
 void   bridge_process(struct ifnet *, struct mbuf *);
-void   bridgeintr_frame(struct bridge_softc *, struct ifnet *, struct mbuf *);
+void   bridgeintr_frame(struct ifnet *, struct ifnet *, struct mbuf *);
 void   bridge_bifgetstp(struct bridge_softc *, struct bridge_iflist *,
            struct ifbreq *);
 void   bridge_broadcast(struct bridge_softc *, struct ifnet *,
     struct ether_header *, struct mbuf *);
 int    bridge_localbroadcast(struct ifnet *, struct ether_header *,
     struct mbuf *);
-void   bridge_span(struct bridge_softc *, struct mbuf *);
+void   bridge_span(struct ifnet *, struct mbuf *);
 void   bridge_stop(struct bridge_softc *);
 void   bridge_init(struct bridge_softc *);
 int    bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
@@ -248,7 +248,7 @@ bridge_delete(struct bridge_softc *sc, s
        if (bif->bif_flags & IFBIF_STP)
                bstp_delete(bif->bif_stp);
 
-       bif->ifp->if_bridgeport = NULL;
+       bif->ifp->if_bridgeidx = 0;
        error = ifpromisc(bif->ifp, 0);
        hook_disestablish(bif->ifp->if_detachhooks, bif->bif_dhcookie);
 
@@ -290,9 +290,8 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        break;
                }
 
-               if (ifs->if_bridgeport != NULL) {
-                       bif = (struct bridge_iflist *)ifs->if_bridgeport;
-                       if (bif->bridge_sc == sc)
+               if (ifs->if_bridgeidx != 0) {
+                       if (ifs->if_bridgeidx == ifp->if_index)
                                error = EEXIST;
                        else
                                error = EBUSY;
@@ -331,7 +330,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
                SIMPLEQ_INIT(&bif->bif_brlin);
                SIMPLEQ_INIT(&bif->bif_brlout);
-               ifs->if_bridgeport = (caddr_t)bif;
+               ifs->if_bridgeidx = ifp->if_index;
                bif->bif_dhcookie = hook_establish(ifs->if_detachhooks, 0,
                    bridge_ifdetach, bif);
                if_ih_insert(bif->ifp, bridge_input, NULL);
@@ -345,11 +344,11 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
+               bif = bridge_getbif(ifs);
                error = bridge_ifremove(bif);
                break;
        case SIOCBRDGIFS:
@@ -367,7 +366,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = EINVAL;
                        break;
                }
-               if (ifs->if_bridgeport != NULL) {
+               if (ifs->if_bridgeidx != 0) {
                        error = EBUSY;
                        break;
                }
@@ -417,11 +416,11 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
+               bif = bridge_getbif(ifs);
                req->ifbr_ifsflags = bif->bif_flags;
                req->ifbr_portno = bif->ifp->if_index & 0xfff;
                req->ifbr_protected = bif->bif_protected;
@@ -436,8 +435,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
@@ -445,6 +443,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = EINVAL;
                        break;
                }
+               bif = bridge_getbif(ifs);
                if (req->ifbr_ifsflags & IFBIF_STP) {
                        if ((bif->bif_flags & IFBIF_STP) == 0) {
                                /* Enable STP */
@@ -495,11 +494,11 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        error = ENOENT;
                        break;
                }
-               bif = (struct bridge_iflist *)ifs->if_bridgeport;
-               if (bif == NULL || bif->bridge_sc != sc) {
+               if (ifs->if_bridgeidx != ifp->if_index) {
                        error = ESRCH;
                        break;
                }
+               bif = bridge_getbif(ifs);
                bif->bif_protected = req->ifbr_protected;
                break;
        case SIOCBRDGRTS:
@@ -663,6 +662,28 @@ done:
        return (error);
 }
 
+struct bridge_iflist *
+bridge_getbif(struct ifnet *ifp)
+{
+       struct bridge_iflist *bif;
+       struct bridge_softc *sc;
+       struct ifnet *bifp;
+
+       bifp = if_get(ifp->if_bridgeidx);
+       if (bifp == NULL)
+               return (NULL);
+
+       sc = bifp->if_softc;
+       SLIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+               if (bif->ifp == ifp)
+                       break;
+       }
+
+       if_put(bifp);
+
+       return (bif);
+}
+
 void
 bridge_init(struct bridge_softc *sc)
 {
@@ -702,19 +723,16 @@ bridge_stop(struct bridge_softc *sc)
  * already attached.  We must enqueue or free the mbuf before exiting.
  */
 int
-bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
-    struct rtentry *rt)
+bridge_enqueue(struct ifnet *ifp, struct mbuf *m)
 {
-       struct bridge_iflist *bif;
+       struct ifnet *brifp;
        struct ether_header *eh;
        struct ifnet *dst_if = NULL;
-       struct bridge_softc *sc;
+       unsigned int dst_ifidx = 0;
 #if NBPFILTER > 0
        caddr_t if_bpf;
 #endif
-       int error;
-
-       KERNEL_ASSERT_LOCKED();
+       int error = 0;
 
        if (m->m_len < sizeof(*eh)) {
                m = m_pullup(m, sizeof(*eh));
@@ -723,8 +741,8 @@ bridge_output(struct ifnet *ifp, struct 
        }
 
        /* ifp must be a member interface of the bridge. */
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
-       if (bif == NULL) {
+       brifp = if_get(ifp->if_bridgeidx);
+       if (brifp == NULL) {
                m_freem(m);
                return (EINVAL);
        }
@@ -734,40 +752,43 @@ bridge_output(struct ifnet *ifp, struct 
         * go ahead and send out that interface.  Otherwise the packet
         * is dropped below.
         */
-       sc = bif->bridge_sc;
-       if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
+       if (!ISSET(brifp->if_flags, IFF_RUNNING)) {
                /* Loop prevention. */
                m->m_flags |= M_PROTO1;
                error = if_enqueue(ifp, m);
+               if_put(brifp);
                return (error);
        }
 
 #if NBPFILTER > 0
-       if_bpf = sc->sc_if.if_bpf;
+       if_bpf = brifp->if_bpf;
        if (if_bpf)
                bpf_mtap(if_bpf, m, BPF_DIRECTION_OUT);
 #endif
        ifp->if_opackets++;
        ifp->if_obytes += m->m_pkthdr.len;
 
-       bridge_span(sc, m);
+       bridge_span(brifp, m);
 
        eh = mtod(m, struct ether_header *);
        if (!ETHER_IS_MULTICAST(eh->ether_dhost)) {
                struct ether_addr *dst;
 
                dst = (struct ether_addr *)&eh->ether_dhost[0];
-               dst_if = bridge_rtlookup(sc, dst, m);
+               dst_ifidx = bridge_rtlookup(brifp, dst, m);
        }
 
        /*
         * If the packet is a broadcast or we don't know a better way to
         * get there, send to all interfaces.
         */
-       if (dst_if == NULL) {
+       if (dst_ifidx == 0) {
+               struct bridge_softc *sc = brifp->if_softc;
+               struct bridge_iflist *bif;
                struct mbuf *mc;
                int used = 0;
 
+               KERNEL_LOCK();
                SLIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                        dst_if = bif->ifp;
                        if ((dst_if->if_flags & IFF_RUNNING) == 0)
@@ -793,7 +814,7 @@ bridge_output(struct ifnet *ifp, struct 
                        } else {
                                mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
                                if (mc == NULL) {
-                                       sc->sc_if.if_oerrors++;
+                                       brifp->if_oerrors++;
                                        continue;
                                }
                        }
@@ -802,21 +823,28 @@ bridge_output(struct ifnet *ifp, struct 
                            BRL_ACTION_BLOCK)
                                continue;
 
-                       error = bridge_ifenqueue(&sc->sc_if, dst_if, mc);
+                       error = bridge_ifenqueue(brifp, dst_if, mc);
                        if (error)
                                continue;
                }
+               KERNEL_UNLOCK();
                if (!used)
                        m_freem(m);
-               return (0);
+               goto out;
        }
 
-       if ((dst_if->if_flags & IFF_RUNNING) == 0) {
+       dst_if = if_get(dst_ifidx);
+       if ((dst_if == NULL)  || !ISSET(dst_if->if_flags, IFF_RUNNING)) {
                m_freem(m);
-               return (ENETDOWN);
+               error = ENETDOWN;
+               goto out;
        }
-       bridge_ifenqueue(&sc->sc_if, dst_if, m);
-       return (0);
+
+       bridge_ifenqueue(brifp, dst_if, m);
+out:
+       if_put(dst_if);
+       if_put(brifp);
+       return (error);
 }
 
 /*
@@ -853,12 +881,14 @@ bridgeintr(void)
  * Process a single frame.  Frame must be freed or queued before returning.
  */
 void
-bridgeintr_frame(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m)
+bridgeintr_frame(struct ifnet *brifp, struct ifnet *src_if, struct mbuf *m)
 {
+       struct bridge_softc *sc = brifp->if_softc;
        struct ifnet *dst_if = NULL;
        struct bridge_iflist *bif;
        struct ether_addr *dst, *src;
        struct ether_header eh;
+       unsigned int dst_ifidx;
        u_int32_t protected;
        int len;
 
@@ -866,7 +896,7 @@ bridgeintr_frame(struct bridge_softc *sc
        sc->sc_if.if_ipackets++;
        sc->sc_if.if_ibytes += m->m_pkthdr.len;
 
-       bif = (struct bridge_iflist *)src_if->if_bridgeport;
+       bif = bridge_getbif(src_if);
        KASSERT(bif != NULL);
 
        if (m->m_pkthdr.len < sizeof(eh)) {
@@ -904,8 +934,8 @@ bridgeintr_frame(struct bridge_softc *sc
         * side of the bridge, drop it.
         */
        if (!ETHER_IS_MULTICAST(eh.ether_dhost)) {
-               dst_if = bridge_rtlookup(sc, dst, NULL);
-               if (dst_if == src_if) {
+               dst_ifidx = bridge_rtlookup(brifp, dst, NULL);
+               if (dst_ifidx == src_if->if_index) {
                        m_freem(m);
                        return;
                }
@@ -963,42 +993,38 @@ bridgeintr_frame(struct bridge_softc *sc
         * If the packet is a multicast or broadcast OR if we don't
         * know any better, forward it to all interfaces.
         */
-       if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
+       if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_ifidx == 0) {
                sc->sc_if.if_imcasts++;
                bridge_broadcast(sc, src_if, &eh, m);
                return;
        }
        protected = bif->bif_protected;
 
+       dst_if = if_get(dst_ifidx);
+       if (dst_if == NULL)
+               goto bad;
+
        /*
         * At this point, we're dealing with a unicast frame going to a
         * different interface
         */
-       if ((dst_if->if_flags & IFF_RUNNING) == 0) {
-               m_freem(m);
-               return;
-       }
-       bif = (struct bridge_iflist *)dst_if->if_bridgeport;
+       if (!ISSET(dst_if->if_flags, IFF_RUNNING))
+               goto bad;
+       bif = bridge_getbif(dst_if);
        if ((bif->bif_flags & IFBIF_STP) &&
-           (bif->bif_state == BSTP_IFSTATE_DISCARDING)) {
-               m_freem(m);
-               return;
-       }
+           (bif->bif_state == BSTP_IFSTATE_DISCARDING))
+               goto bad;
        /*
         * Do not transmit if both ports are part of the same protected
         * domain.
         */
-       if (protected != 0 && (protected & bif->bif_protected)) {
-               m_freem(m);
-               return;
-       }
-       if (bridge_filterrule(&bif->bif_brlout, &eh, m) == BRL_ACTION_BLOCK) {
-               m_freem(m);
-               return;
-       }
+       if (protected != 0 && (protected & bif->bif_protected))
+               goto bad;
+       if (bridge_filterrule(&bif->bif_brlout, &eh, m) == BRL_ACTION_BLOCK)
+               goto bad;
        m = bridge_ip(&sc->sc_if, BRIDGE_OUT, dst_if, &eh, m);
        if (m == NULL)
-               return;
+               goto bad;
 
        len = m->m_pkthdr.len;
 #if NVLAN > 0
@@ -1011,6 +1037,10 @@ bridgeintr_frame(struct bridge_softc *sc
        else {
                bridge_ifenqueue(&sc->sc_if, dst_if, m);
        }
+       m = NULL;
+bad:
+       if_put(dst_if);
+       m_freem(m);
 }
 
 /*
@@ -1054,6 +1084,7 @@ bridge_input(struct ifnet *ifp, struct m
 void
 bridge_process(struct ifnet *ifp, struct mbuf *m)
 {
+       struct ifnet *brifp;
        struct bridge_softc *sc;
        struct bridge_iflist *bif, *bif0;
        struct ether_header *eh;
@@ -1064,12 +1095,8 @@ bridge_process(struct ifnet *ifp, struct
 
        KERNEL_ASSERT_LOCKED();
 
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
-       if (bif == NULL)
-               goto reenqueue;
-
-       sc = bif->bridge_sc;
-       if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+       brifp = if_get(ifp->if_bridgeidx);
+       if ((brifp == NULL) || !ISSET(brifp->if_flags, IFF_RUNNING))
                goto reenqueue;
 
 #if NVLAN > 0
@@ -1080,17 +1107,25 @@ bridge_process(struct ifnet *ifp, struct
        if (ISSET(m->m_flags, M_VLANTAG)) {
                m = vlan_inject(m, ETHERTYPE_VLAN, m->m_pkthdr.ether_vtag);
                if (m == NULL)
-                       return;
+                       goto bad;
        }
 #endif
 
 #if NBPFILTER > 0
-       if_bpf = sc->sc_if.if_bpf;
+       if_bpf = brifp->if_bpf;
        if (if_bpf)
                bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_IN);
 #endif
 
-       bridge_span(sc, m);
+       sc = brifp->if_softc;
+       SLIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+               if (bif->ifp == ifp)
+                       break;
+       }
+       if (bif == NULL)
+               goto reenqueue;
+
+       bridge_span(brifp, m);
 
        eh = mtod(m, struct ether_header *);
        if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
@@ -1105,13 +1140,11 @@ bridge_process(struct ifnet *ifp, struct
                    ETHER_ADDR_LEN - 1) == 0) {
                        if (eh->ether_dhost[ETHER_ADDR_LEN - 1] == 0) {
                                /* STP traffic */
-                               if ((m = bstp_input(sc->sc_stp, bif->bif_stp,
-                                   eh, m)) == NULL)
-                                       return;
-                       } else if (eh->ether_dhost[ETHER_ADDR_LEN - 1] <= 0xf) {
-                               m_freem(m);
-                               return;
-                       }
+                               m = bstp_input(sc->sc_stp, bif->bif_stp, eh, m);
+                               if (m == NULL)
+                                       goto bad;
+                       } else if (eh->ether_dhost[ETHER_ADDR_LEN - 1] <= 0xf)
+                               goto bad;
                }
 
                /*
@@ -1127,18 +1160,11 @@ bridge_process(struct ifnet *ifp, struct
 
                bridge_ifinput(ifp, mc);
 
-               bridgeintr_frame(sc, ifp, m);
+               bridgeintr_frame(brifp, ifp, m);
                return;
        }
 
        /*
-        * No need to queue frames for ifs in the discarding state
-        */
-       if ((bif->bif_flags & IFBIF_STP) &&
-           (bif->bif_state == BSTP_IFSTATE_DISCARDING))
-               goto reenqueue;
-
-       /*
         * Unicast, make sure it's not for us.
         */
        bif0 = bif;
@@ -1152,28 +1178,30 @@ bridge_process(struct ifnet *ifp, struct
                                    ifp, 0, IFBAF_DYNAMIC, m);
                        if (bridge_filterrule(&bif0->bif_brlin, eh, m) ==
                            BRL_ACTION_BLOCK) {
-                               m_freem(m);
-                               return;
+                               goto bad;
                        }
 
                        /* Count for the bridge */
-                       sc->sc_if.if_ipackets++;
-                       sc->sc_if.if_ibytes += m->m_pkthdr.len;
+                       brifp->if_ipackets++;
+                       brifp->if_ibytes += m->m_pkthdr.len;
 
-                       bridge_ifinput(bif->ifp, m);
-                       return;
-               }
-               if (bridge_ourether(bif->ifp, eh->ether_shost)) {
-                       m_freem(m);
-                       return;
+                       ifp = bif->ifp;
+                       goto reenqueue;
                }
+               if (bridge_ourether(bif->ifp, eh->ether_shost))
+                       goto bad;
        }
 
-       bridgeintr_frame(sc, ifp, m);
+       bridgeintr_frame(brifp, ifp, m);
+       if_put(brifp);
        return;
 
 reenqueue:
        bridge_ifinput(ifp, m);
+       m = NULL;
+bad:
+       m_freem(m);
+       if_put(brifp);
 }
 
 /*
@@ -1190,7 +1218,7 @@ bridge_broadcast(struct bridge_softc *sc
        int len, used = 0;
        u_int32_t protected;
 
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
+       bif = bridge_getbif(ifp);
        protected = bif->bif_protected;
 
        SLIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
@@ -1301,13 +1329,18 @@ bridge_localbroadcast(struct ifnet *ifp,
 }
 
 void
-bridge_span(struct bridge_softc *sc, struct mbuf *m)
+bridge_span(struct ifnet *brifp, struct mbuf *m)
 {
+       struct bridge_softc *sc = brifp->if_softc;
        struct bridge_iflist *bif;
        struct ifnet *ifp;
        struct mbuf *mc;
        int error;
 
+       if (SLIST_EMPTY(&sc->sc_spanlist))
+               return;
+
+       KERNEL_LOCK();
        SLIST_FOREACH(bif, &sc->sc_spanlist, bif_next) {
                ifp = bif->ifp;
 
@@ -1316,14 +1349,15 @@ bridge_span(struct bridge_softc *sc, str
 
                mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
                if (mc == NULL) {
-                       sc->sc_if.if_oerrors++;
+                       brifp->if_oerrors++;
                        continue;
                }
 
-               error = bridge_ifenqueue(&sc->sc_if, ifp, mc);
+               error = bridge_ifenqueue(brifp, ifp, mc);
                if (error)
                        continue;
        }
+       KERNEL_UNLOCK();
 }
 
 /*
@@ -1936,7 +1970,7 @@ bridge_send_icmp_err(struct ifnet *ifp,
                goto dropit;
        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
 
-       bridge_output(ifp, m, NULL, NULL);
+       bridge_enqueue(ifp, m);
        m_freem(n);
        return;
 
Index: net/if_bridge.h
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.h,v
retrieving revision 1.63
diff -u -p -r1.63 if_bridge.h
--- net/if_bridge.h     8 Mar 2019 17:48:35 -0000       1.63
+++ net/if_bridge.h     4 Apr 2019 19:58:21 -0000
@@ -424,10 +424,6 @@ struct bridge_iflist {
 };
 #define bif_state                      bif_stp->bp_state
 
-#define SAME_BRIDGE(_bp1, _bp2)                                                
\
-       (_bp1 && _bp2 && ((struct bridge_iflist *)_bp1)->bridge_sc ==   \
-           ((struct bridge_iflist *)_bp2)->bridge_sc)
-
 /*
  * XXX ip_ipsp.h's sockaddr_union should be converted to sockaddr *
  * passing with correct sa_len, then a good approach for cleaning this
@@ -453,7 +449,7 @@ struct bridge_tunneltag {
  */
 struct bridge_rtnode {
        LIST_ENTRY(bridge_rtnode)       brt_next;       /* next in list */
-       struct ifnet                    *brt_if;        /* destination ifs */
+       unsigned int                    brt_ifidx;      /* destination ifs */
        u_int8_t                        brt_flags;      /* address flags */
        u_int8_t                        brt_age;        /* age counter */
        struct ether_addr               brt_addr;       /* dst addr */
@@ -470,6 +466,7 @@ struct bridge_rtnode {
  *  Locks used to protect struct members in this file:
  *     I       immutable after creation
  *     m       per-softc mutex
+ *     k       kernel lock
  */
 /*
  * Software state for each bridge
@@ -482,8 +479,8 @@ struct bridge_softc {
        uint64_t                        sc_hashkey[2];  /* [I] siphash key */
        struct timeout                  sc_brtimeout;   /* timeout state */
        struct bstp_state               *sc_stp;        /* stp state */
-       SLIST_HEAD(, bridge_iflist)     sc_iflist;      /* interface list */
-       SLIST_HEAD(, bridge_iflist)     sc_spanlist;    /* span ports */
+       SLIST_HEAD(, bridge_iflist)     sc_iflist;      /* [k] interface list */
+       SLIST_HEAD(, bridge_iflist)     sc_spanlist;    /* [k] span ports */
        struct mutex                    sc_mtx;         /* mutex */
        LIST_HEAD(, bridge_rtnode)      sc_rts[BRIDGE_RTABLE_SIZE];     /* [m] 
hash table */
 };
@@ -491,8 +488,7 @@ struct bridge_softc {
 extern const u_int8_t bstp_etheraddr[];
 struct llc;
 
-int    bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
-    struct rtentry *);
+int    bridge_enqueue(struct ifnet *, struct mbuf *);
 void   bridge_update(struct ifnet *, struct ether_addr *, int);
 void   bridge_rtdelete(struct bridge_softc *, struct ifnet *, int);
 void   bridge_rtagenode(struct ifnet *, int);
@@ -517,8 +513,8 @@ void        bstp_ifsflags(struct bstp_port *, u
 
 int    bridgectl_ioctl(struct ifnet *, u_long, caddr_t);
 int    bridge_rtupdate(struct bridge_softc *,
-    struct ether_addr *, struct ifnet *ifp, int, u_int8_t, struct mbuf *);
-struct ifnet *bridge_rtlookup(struct bridge_softc *,
+    struct ether_addr *, struct ifnet *, int, u_int8_t, struct mbuf *);
+unsigned int bridge_rtlookup(struct ifnet *,
     struct ether_addr *, struct mbuf *);
 void   bridge_rtflush(struct bridge_softc *, int);
 void   bridge_rtage(void *);
@@ -529,6 +525,7 @@ void        bridge_flushrule(struct bridge_ifli
 
 void   bridge_fragment(struct ifnet *, struct ifnet *, struct ether_header *,
     struct mbuf *);
+struct bridge_iflist *bridge_getbif(struct ifnet *);
 
 #endif /* _KERNEL */
 #endif /* _NET_IF_BRIDGE_H_ */
Index: net/if_switch.c
===================================================================
RCS file: /cvs/src/sys/net/if_switch.c,v
retrieving revision 1.25
diff -u -p -r1.25 if_switch.c
--- net/if_switch.c     28 Dec 2018 14:32:47 -0000      1.25
+++ net/if_switch.c     4 Apr 2019 19:58:21 -0000
@@ -492,7 +492,7 @@ switch_port_add(struct switch_softc *sc,
        if ((ifs = ifunit(req->ifbr_ifsname)) == NULL)
                return (ENOENT);
 
-       if (ifs->if_bridgeport != NULL)
+       if (ifs->if_bridgeidx != 0)
                return (EBUSY);
 
        if (ifs->if_switchport != NULL) {
Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.98
diff -u -p -r1.98 if_var.h
--- net/if_var.h        22 Apr 2019 03:26:16 -0000      1.98
+++ net/if_var.h        23 Apr 2019 15:23:08 -0000
@@ -131,8 +131,8 @@ struct ifnet {                              /* and the 
entries */
        void    (*if_rtrequest)(struct ifnet *, int, struct rtentry *);
        char    if_xname[IFNAMSIZ];     /* [I] external name (name + unit) */
        int     if_pcount;              /* [k] # of promiscuous listeners */
+       unsigned int if_bridgeidx;      /* [k] used by bridge ports */
        caddr_t if_bpf;                 /* packet filter structure */
-       caddr_t if_bridgeport;          /* used by bridge ports */
        caddr_t if_switchport;          /* used by switch ports */
        caddr_t if_mcast;               /* used by multicast code */
        caddr_t if_mcast6;              /* used by IPv6 multicast code */
Index: net/if_vxlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vxlan.c,v
retrieving revision 1.71
diff -u -p -r1.71 if_vxlan.c
--- net/if_vxlan.c      23 Apr 2019 10:53:45 -0000      1.71
+++ net/if_vxlan.c      23 Apr 2019 15:23:08 -0000
@@ -711,7 +711,7 @@ vxlan_lookup(struct mbuf *m, struct udph
 
 #if NBRIDGE > 0
        /* Store the tunnel src/dst IP and vni for the bridge or switch */
-       if ((ifp->if_bridgeport != NULL || ifp->if_switchport != NULL) &&
+       if ((ifp->if_bridgeidx != 0 || ifp->if_switchport != NULL) &&
            srcsa->sa_family != AF_UNSPEC &&
            ((brtag = bridge_tunneltag(m)) != NULL)) {
                memcpy(&brtag->brtag_peer.sa, srcsa, srcsa->sa_len);
Index: net80211/ieee80211_node.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v
retrieving revision 1.163
diff -u -p -r1.163 ieee80211_node.c
--- net80211/ieee80211_node.c   15 Mar 2019 11:05:29 -0000      1.163
+++ net80211/ieee80211_node.c   4 Apr 2019 19:58:21 -0000
@@ -2478,10 +2478,10 @@ ieee80211_node_join(struct ieee80211com 
 
 #if NBRIDGE > 0
        /*
-        * If the parent interface is a bridgeport, learn
+        * If the parent interface is a bridge port, learn
         * the node's address dynamically on this interface.
         */
-       if (ic->ic_if.if_bridgeport != NULL)
+       if (ic->ic_if.if_bridgeidx != 0)
                bridge_update(&ic->ic_if,
                    (struct ether_addr *)ni->ni_macaddr, 0);
 #endif
@@ -2635,10 +2635,10 @@ ieee80211_node_leave(struct ieee80211com
 
 #if NBRIDGE > 0
        /*
-        * If the parent interface is a bridgeport, delete
+        * If the parent interface is a bridge port, delete
         * any dynamically learned address for this node.
         */
-       if (ic->ic_if.if_bridgeport != NULL)
+       if (ic->ic_if.if_bridgeidx != 0)
                bridge_update(&ic->ic_if,
                    (struct ether_addr *)ni->ni_macaddr, 1);
 #endif
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.353
diff -u -p -r1.353 ip_output.c
--- netinet/ip_output.c 18 Jan 2019 20:46:03 -0000      1.353
+++ netinet/ip_output.c 4 Apr 2019 19:58:21 -0000
@@ -460,7 +460,7 @@ sendit:
        if (ntohs(ip->ip_len) <= mtu) {
                ip->ip_sum = 0;
                if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-                   (ifp->if_bridgeport == NULL))
+                   (ifp->if_bridgeidx == 0))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
                        ipstat_inc(ips_outswcsum);
@@ -719,7 +719,7 @@ ip_fragment(struct mbuf *m, struct ifnet
                mhip->ip_sum = 0;
                if ((ifp != NULL) &&
                    (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-                   (ifp->if_bridgeport == NULL))
+                   (ifp->if_bridgeidx == 0))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
                        ipstat_inc(ips_outswcsum);
@@ -740,7 +740,7 @@ ip_fragment(struct mbuf *m, struct ifnet
        ip->ip_sum = 0;
        if ((ifp != NULL) &&
            (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-           (ifp->if_bridgeport == NULL))
+           (ifp->if_bridgeidx == 0))
                m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
        else {
                ipstat_inc(ips_outswcsum);
@@ -1806,14 +1806,14 @@ in_proto_cksum_out(struct mbuf *m, struc
 
        if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
-                   ip->ip_hl != 5 || ifp->if_bridgeport != NULL) {
+                   ip->ip_hl != 5 || ifp->if_bridgeidx != 0) {
                        tcpstat_inc(tcps_outswcsum);
                        in_delayed_cksum(m);
                        m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
                }
        } else if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
-                   ip->ip_hl != 5 || ifp->if_bridgeport != NULL) {
+                   ip->ip_hl != 5 || ifp->if_bridgeidx != 0) {
                        udpstat_inc(udps_outswcsum);
                        in_delayed_cksum(m);
                        m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_OUT; /* Clear */
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.242
diff -u -p -r1.242 ip6_output.c
--- netinet6/ip6_output.c       23 Apr 2019 11:01:54 -0000      1.242
+++ netinet6/ip6_output.c       23 Apr 2019 15:23:08 -0000
@@ -2708,7 +2708,7 @@ in6_proto_cksum_out(struct mbuf *m, stru
        if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv6) ||
                    ip6->ip6_nxt != IPPROTO_TCP ||
-                   ifp->if_bridgeport != NULL) {
+                   ifp->if_bridgeidx != 0) {
                        tcpstat_inc(tcps_outswcsum);
                        in6_delayed_cksum(m, IPPROTO_TCP);
                        m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
@@ -2716,7 +2716,7 @@ in6_proto_cksum_out(struct mbuf *m, stru
        } else if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_UDPv6) ||
                    ip6->ip6_nxt != IPPROTO_UDP ||
-                   ifp->if_bridgeport != NULL) {
+                   ifp->if_bridgeidx != 0) {
                        udpstat_inc(udps_outswcsum);
                        in6_delayed_cksum(m, IPPROTO_UDP);
                        m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_OUT; /* Clear */

Reply via email to