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 :)

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.578
diff -u -p -r1.578 if.c
--- net/if.c    19 Apr 2019 07:38:02 -0000      1.578
+++ net/if.c    19 Apr 2019 20:45:20 -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
@@ -1162,7 +1160,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     16 Apr 2019 18:42:52 -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,26 @@ bridge_output(struct ifnet *ifp, struct 
                            BRL_ACTION_BLOCK)
                                continue;
 
-                       error = bridge_ifenqueue(&sc->sc_if, dst_if, mc);
-                       if (error)
-                               continue;
+                       bridge_ifenqueue(brifp, dst_if, mc);
                }
+               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);
+       if_put(dst_if);
+out:
+       if_put(brifp);
+       return (error);
 }
 
 /*
@@ -853,12 +879,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 +894,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 +932,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;
                }
@@ -952,10 +980,6 @@ bridgeintr_frame(struct bridge_softc *sc
                return;
        }
 
-       if (bridge_filterrule(&bif->bif_brlin, &eh, m) == BRL_ACTION_BLOCK) {
-               m_freem(m);
-               return;
-       }
        m = bridge_ip(&sc->sc_if, BRIDGE_IN, src_if, &eh, m);
        if (m == NULL)
                return;
@@ -963,42 +987,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 ((dst_if->if_flags & IFF_RUNNING) == 0)
+               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 +1031,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 +1078,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 +1089,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 +1101,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,32 +1134,17 @@ 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;
                }
-
-               /*
-                * No need to process frames for ifs in the discarding state
-                */
-               if ((bif->bif_flags & IFBIF_STP) &&
-                   (bif->bif_state == BSTP_IFSTATE_DISCARDING))
-                       goto reenqueue;
-
-               mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
-               if (mc == NULL)
-                       goto reenqueue;
-
-               bridge_ifinput(ifp, mc);
-
-               bridgeintr_frame(sc, ifp, m);
-               return;
        }
 
+       if (bridge_filterrule(&bif->bif_brlin, eh, m) == BRL_ACTION_BLOCK)
+               goto bad;
+
        /*
         * No need to queue frames for ifs in the discarding state
         */
@@ -1138,6 +1152,14 @@ bridge_process(struct ifnet *ifp, struct
            (bif->bif_state == BSTP_IFSTATE_DISCARDING))
                goto reenqueue;
 
+       if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+               mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
+               if (mc != NULL)
+                       bridgeintr_frame(brifp, ifp, mc);
+
+               goto reenqueue;
+       }
+
        /*
         * Unicast, make sure it's not for us.
         */
@@ -1150,30 +1172,27 @@ bridge_process(struct ifnet *ifp, struct
                                bridge_rtupdate(sc,
                                    (struct ether_addr *)&eh->ether_shost,
                                    ifp, 0, IFBAF_DYNAMIC, m);
-                       if (bridge_filterrule(&bif0->bif_brlin, eh, m) ==
-                           BRL_ACTION_BLOCK) {
-                               m_freem(m);
-                               return;
-                       }
-
                        /* 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 +1209,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 +1320,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 +1340,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 +1961,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.97
diff -u -p -r1.97 if_var.h
--- net/if_var.h        19 Apr 2019 07:38:02 -0000      1.97
+++ net/if_var.h        19 Apr 2019 20:45:20 -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.70
diff -u -p -r1.70 if_vxlan.c
--- net/if_vxlan.c      3 Dec 2018 17:25:22 -0000       1.70
+++ net/if_vxlan.c      4 Apr 2019 19:58:21 -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.241
diff -u -p -r1.241 ip6_output.c
--- netinet6/ip6_output.c       3 Dec 2018 17:25:22 -0000       1.241
+++ netinet6/ip6_output.c       4 Apr 2019 19:58:21 -0000
@@ -2704,7 +2704,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 */
@@ -2712,7 +2712,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