Diff below uses a mutex to serialize accesses to the hash table. It doesn't guarantee that pointers returned by a lookup on this table are still valid. This will be addressed in a later diff.
I also annotated Immutable fields ([I]) in the bridge_softc structure. Ok? Index: net/bridgectl.c =================================================================== RCS file: /cvs/src/sys/net/bridgectl.c,v retrieving revision 1.13 diff -u -p -r1.13 bridgectl.c --- net/bridgectl.c 12 Dec 2018 14:19:15 -0000 1.13 +++ net/bridgectl.c 13 Feb 2019 13:41:17 -0000 @@ -102,7 +102,9 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon bparam->ifbrp_csize = sc->sc_brtmax; break; case SIOCBRDGSCACHE: + mtx_enter(&sc->sc_mtx); sc->sc_brtmax = bparam->ifbrp_csize; + mtx_leave(&sc->sc_mtx); break; case SIOCBRDGSTO: if (bparam->ifbrp_ctime < 0 || @@ -195,6 +197,7 @@ bridge_rtupdate(struct bridge_softc *sc, } h = bridge_hash(sc, ea); + mtx_enter(&sc->sc_mtx); p = LIST_FIRST(&sc->sc_rts[h]); if (p == NULL) { if (sc->sc_brtcnt >= sc->sc_brtmax) @@ -285,26 +288,31 @@ bridge_rtupdate(struct bridge_softc *sc, done: ifp = NULL; want: + mtx_leave(&sc->sc_mtx); return (ifp); } struct bridge_rtnode * bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea) { - struct bridge_rtnode *p; + struct bridge_rtnode *p = NULL; u_int32_t h; int dir; h = bridge_hash(sc, ea); + mtx_enter(&sc->sc_mtx); LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)); if (dir == 0) - return (p); - if (dir > 0) - goto fail; + break; + if (dir > 0) { + p = NULL; + break; + } } -fail: - return (NULL); + mtx_leave(&sc->sc_mtx); + + return (p); } u_int32_t @@ -324,8 +332,7 @@ bridge_rtage(void *vsc) struct bridge_rtnode *n, *p; int i; - KERNEL_ASSERT_LOCKED(); - + mtx_enter(&sc->sc_mtx); for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { n = LIST_FIRST(&sc->sc_rts[i]); while (n != NULL) { @@ -346,6 +353,7 @@ bridge_rtage(void *vsc) } } } + mtx_leave(&sc->sc_mtx); if (sc->sc_brttimeout != 0) timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout); @@ -373,6 +381,7 @@ bridge_rtagenode(struct ifnet *ifp, int if (age == 0) bridge_rtdelete(sc, ifp, 1); else { + mtx_enter(&sc->sc_mtx); for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { LIST_FOREACH(n, &sc->sc_rts[i], brt_next) { /* Cap the expiry time to 'age' */ @@ -382,6 +391,7 @@ bridge_rtagenode(struct ifnet *ifp, int n->brt_age = time_uptime + age; } } + mtx_leave(&sc->sc_mtx); } } @@ -394,6 +404,7 @@ bridge_rtflush(struct bridge_softc *sc, int i; struct bridge_rtnode *p, *n; + mtx_enter(&sc->sc_mtx); for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { n = LIST_FIRST(&sc->sc_rts[i]); while (n != NULL) { @@ -408,6 +419,7 @@ bridge_rtflush(struct bridge_softc *sc, n = LIST_NEXT(n, brt_next); } } + mtx_leave(&sc->sc_mtx); } /* @@ -420,14 +432,17 @@ bridge_rtdaddr(struct bridge_softc *sc, struct bridge_rtnode *p; h = bridge_hash(sc, ea); + mtx_enter(&sc->sc_mtx); LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) { LIST_REMOVE(p, brt_next); sc->sc_brtcnt--; + mtx_leave(&sc->sc_mtx); free(p, M_DEVBUF, sizeof *p); return (0); } } + mtx_leave(&sc->sc_mtx); return (ENOENT); } @@ -445,6 +460,7 @@ bridge_rtdelete(struct bridge_softc *sc, * Loop through all of the hash buckets and traverse each * chain looking for routes to this interface. */ + mtx_enter(&sc->sc_mtx); for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { n = LIST_FIRST(&sc->sc_rts[i]); while (n != NULL) { @@ -466,6 +482,7 @@ bridge_rtdelete(struct bridge_softc *sc, n = p; } } + mtx_leave(&sc->sc_mtx); } /* @@ -479,10 +496,12 @@ bridge_rtfind(struct bridge_softc *sc, s u_int32_t i = 0, total = 0; int k, error = 0; + mtx_enter(&sc->sc_mtx); for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { LIST_FOREACH(n, &sc->sc_rts[k], brt_next) total++; } + mtx_leave(&sc->sc_mtx); if (baconf->ifbac_len == 0) { i = total; @@ -493,6 +512,7 @@ bridge_rtfind(struct bridge_softc *sc, s if (bareqs == NULL) goto done; + mtx_enter(&sc->sc_mtx); for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { LIST_FOREACH(n, &sc->sc_rts[k], brt_next) { if (baconf->ifbac_len < (i + 1) * sizeof(*bareqs)) @@ -511,6 +531,7 @@ bridge_rtfind(struct bridge_softc *sc, s i++; } } + mtx_leave(&sc->sc_mtx); error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs)); done: Index: net/if_bridge.c =================================================================== RCS file: /cvs/src/sys/net/if_bridge.c,v retrieving revision 1.319 diff -u -p -r1.319 if_bridge.c --- net/if_bridge.c 29 Jan 2019 17:47:35 -0000 1.319 +++ net/if_bridge.c 13 Feb 2019 13:48:36 -0000 @@ -174,6 +174,7 @@ bridge_clone_create(struct if_clone *ifc timeout_set(&sc->sc_brtimeout, bridge_rtage, sc); SLIST_INIT(&sc->sc_iflist); SLIST_INIT(&sc->sc_spanlist); + mtx_init(&sc->sc_mtx, IPL_MPFLOOR); for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) LIST_INIT(&sc->sc_rts[i]); arc4random_buf(&sc->sc_hashkey, sizeof(sc->sc_hashkey)); Index: net/if_bridge.h =================================================================== RCS file: /cvs/src/sys/net/if_bridge.h,v retrieving revision 1.60 diff -u -p -r1.60 if_bridge.h --- net/if_bridge.h 29 Jan 2019 17:47:35 -0000 1.60 +++ net/if_bridge.h 13 Feb 2019 13:41:17 -0000 @@ -242,6 +242,9 @@ struct ifbrlconf { }; #ifdef _KERNEL + +#include <sys/mutex.h> + /* STP port flags */ #define BSTP_PORT_CANMIGRATE 0x0001 #define BSTP_PORT_NEWINFO 0x0002 @@ -464,19 +467,25 @@ struct bridge_rtnode { #define BRIDGE_RTABLE_MASK (BRIDGE_RTABLE_SIZE - 1) /* + * Locks used to protect struct members in this file: + * I immutable after creation + * m per-softc mutex + */ +/* * Software state for each bridge */ struct bridge_softc { struct ifnet sc_if; /* the interface */ - u_int32_t sc_brtmax; /* max # addresses */ - u_int32_t sc_brtcnt; /* current # addrs */ + uint32_t sc_brtmax; /* [m] max # addresses */ + uint32_t sc_brtcnt; /* [m] current # addrs */ int sc_brttimeout; /* timeout ticks */ - u_int64_t sc_hashkey[2]; /* siphash key */ + 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 */ - LIST_HEAD(, bridge_rtnode) sc_rts[BRIDGE_RTABLE_SIZE]; /* hash table */ + struct mutex sc_mtx; /* mutex */ + LIST_HEAD(, bridge_rtnode) sc_rts[BRIDGE_RTABLE_SIZE]; /* [m] hash table */ }; extern const u_int8_t bstp_etheraddr[];