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 */