Hi, tried it on a router with three bridges (etherip/vether over IPSec and vxlan/vlan) and it works, if you want dmesg/ifconfig output I'll send it to you.
Regards, S. Rudzio Am So., 21. Apr. 2019 um 21:47 Uhr schrieb Martin Pieuchot <[email protected]>: > > 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 */ >
