812 lines
18 KiB
Diff
812 lines
18 KiB
Diff
Index: sys/net/if_bridge.c
|
|
===================================================================
|
|
--- sys/net/if_bridge.c (revision 360985)
|
|
+++ sys/net/if_bridge.c (working copy)
|
|
@@ -165,6 +165,9 @@
|
|
#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
|
|
#endif
|
|
|
|
+#define NET_EPOCH_ASSERT() MPASS(in_epoch(net_epoch_preempt))
|
|
+#define NET_EPOCH_CALL(f, c) epoch_call(net_epoch_preempt, (c), (f))
|
|
+
|
|
/*
|
|
* List of capabilities to possibly mask on the member interface.
|
|
*/
|
|
@@ -188,6 +191,7 @@
|
|
uint32_t bif_addrmax; /* max # of addresses */
|
|
uint32_t bif_addrcnt; /* cur. # of addresses */
|
|
uint32_t bif_addrexceeded;/* # of address violations */
|
|
+ struct epoch_context bif_epoch_ctx;
|
|
};
|
|
|
|
/*
|
|
@@ -201,6 +205,8 @@
|
|
uint8_t brt_flags; /* address flags */
|
|
uint8_t brt_addr[ETHER_ADDR_LEN];
|
|
uint16_t brt_vlan; /* vlan id */
|
|
+ struct vnet *brt_vnet;
|
|
+ struct epoch_context brt_epoch_ctx;
|
|
};
|
|
#define brt_ifp brt_dst->bif_ifp
|
|
|
|
@@ -211,13 +217,10 @@
|
|
struct ifnet *sc_ifp; /* make this an interface */
|
|
LIST_ENTRY(bridge_softc) sc_list;
|
|
struct mtx sc_mtx;
|
|
- struct cv sc_cv;
|
|
uint32_t sc_brtmax; /* max # of addresses */
|
|
uint32_t sc_brtcnt; /* cur. # of addresses */
|
|
uint32_t sc_brttimeout; /* rt timeout in seconds */
|
|
struct callout sc_brcallout; /* bridge callout */
|
|
- uint32_t sc_iflist_ref; /* refcount for sc_iflist */
|
|
- uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */
|
|
LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */
|
|
LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */
|
|
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
|
|
@@ -227,6 +230,7 @@
|
|
uint32_t sc_brtexceeded; /* # of cache drops */
|
|
struct ifnet *sc_ifaddr; /* member mac copied from */
|
|
struct ether_addr sc_defaddr; /* Default MAC address */
|
|
+ struct epoch_context sc_epoch_ctx;
|
|
};
|
|
|
|
VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx);
|
|
@@ -546,6 +550,10 @@
|
|
if_clone_detach(V_bridge_cloner);
|
|
V_bridge_cloner = NULL;
|
|
BRIDGE_LIST_LOCK_DESTROY();
|
|
+
|
|
+ /* Callbacks may use UMA zone. */
|
|
+ epoch_drain_callbacks(net_epoch_preempt);
|
|
+
|
|
uma_zdestroy(V_bridge_rtnode_zone);
|
|
}
|
|
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
|
|
@@ -708,6 +716,17 @@
|
|
return (0);
|
|
}
|
|
|
|
+static void
|
|
+bridge_clone_destroy_cb(struct epoch_context *ctx)
|
|
+{
|
|
+ struct bridge_softc *sc;
|
|
+
|
|
+ sc = __containerof(ctx, struct bridge_softc, sc_epoch_ctx);
|
|
+
|
|
+ BRIDGE_LOCK_DESTROY(sc);
|
|
+ free(sc, M_DEVBUF);
|
|
+}
|
|
+
|
|
/*
|
|
* bridge_clone_destroy:
|
|
*
|
|
@@ -718,7 +737,9 @@
|
|
{
|
|
struct bridge_softc *sc = ifp->if_softc;
|
|
struct bridge_iflist *bif;
|
|
+ struct epoch_tracker et;
|
|
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
BRIDGE_LOCK(sc);
|
|
|
|
bridge_stop(ifp, 1);
|
|
@@ -743,11 +764,12 @@
|
|
BRIDGE_LIST_UNLOCK();
|
|
|
|
bstp_detach(&sc->sc_stp);
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
+
|
|
ether_ifdetach(ifp);
|
|
if_free(ifp);
|
|
|
|
- BRIDGE_LOCK_DESTROY(sc);
|
|
- free(sc, M_DEVBUF);
|
|
+ NET_EPOCH_CALL(bridge_clone_destroy_cb, &sc->sc_epoch_ctx);
|
|
}
|
|
|
|
/*
|
|
@@ -773,7 +795,10 @@
|
|
struct ifdrv *ifd = (struct ifdrv *) data;
|
|
const struct bridge_control *bc;
|
|
int error = 0;
|
|
+ struct epoch_tracker et;
|
|
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
+
|
|
switch (cmd) {
|
|
|
|
case SIOCADDMULTI:
|
|
@@ -882,6 +907,8 @@
|
|
break;
|
|
}
|
|
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
+
|
|
return (error);
|
|
}
|
|
|
|
@@ -896,6 +923,8 @@
|
|
struct bridge_iflist *bif;
|
|
int enabled, mask;
|
|
|
|
+ BRIDGE_LOCK_ASSERT(sc);
|
|
+
|
|
/* Initial bitmask of capabilities to test */
|
|
mask = BRIDGE_IFCAPS_MASK;
|
|
|
|
@@ -904,7 +933,6 @@
|
|
mask &= bif->bif_savedcaps;
|
|
}
|
|
|
|
- BRIDGE_XLOCK(sc);
|
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
|
enabled = bif->bif_ifp->if_capenable;
|
|
enabled &= ~BRIDGE_IFCAPS_STRIP;
|
|
@@ -915,8 +943,6 @@
|
|
bridge_set_ifcap(sc, bif, enabled);
|
|
BRIDGE_LOCK(sc);
|
|
}
|
|
- BRIDGE_XDROP(sc);
|
|
-
|
|
}
|
|
|
|
static void
|
|
@@ -957,7 +983,7 @@
|
|
struct bridge_iflist *bif;
|
|
struct ifnet *ifp;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
|
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
|
ifp = bif->bif_ifp;
|
|
@@ -978,7 +1004,7 @@
|
|
{
|
|
struct bridge_iflist *bif;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
|
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
|
if (bif->bif_ifp == member_ifp)
|
|
@@ -988,6 +1014,16 @@
|
|
return (NULL);
|
|
}
|
|
|
|
+static void
|
|
+bridge_delete_member_cb(struct epoch_context *ctx)
|
|
+{
|
|
+ struct bridge_iflist *bif;
|
|
+
|
|
+ bif = __containerof(ctx, struct bridge_iflist, bif_epoch_ctx);
|
|
+
|
|
+ free(bif, M_DEVBUF);
|
|
+}
|
|
+
|
|
/*
|
|
* bridge_delete_member:
|
|
*
|
|
@@ -1006,9 +1042,7 @@
|
|
bstp_disable(&bif->bif_stp);
|
|
|
|
ifs->if_bridge = NULL;
|
|
- BRIDGE_XLOCK(sc);
|
|
LIST_REMOVE(bif, bif_next);
|
|
- BRIDGE_XDROP(sc);
|
|
|
|
/*
|
|
* If removing the interface that gave the bridge its mac address, set
|
|
@@ -1066,7 +1100,8 @@
|
|
}
|
|
bstp_destroy(&bif->bif_stp); /* prepare to free */
|
|
BRIDGE_LOCK(sc);
|
|
- free(bif, M_DEVBUF);
|
|
+
|
|
+ NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx);
|
|
}
|
|
|
|
/*
|
|
@@ -1083,7 +1118,8 @@
|
|
("%s: not a span interface", __func__));
|
|
|
|
LIST_REMOVE(bif, bif_next);
|
|
- free(bif, M_DEVBUF);
|
|
+
|
|
+ NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx);
|
|
}
|
|
|
|
static int
|
|
@@ -1139,7 +1175,6 @@
|
|
* If any, remove all inet6 addresses from the member
|
|
* interfaces.
|
|
*/
|
|
- BRIDGE_XLOCK(sc);
|
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
|
if (in6ifa_llaonifp(bif->bif_ifp)) {
|
|
BRIDGE_UNLOCK(sc);
|
|
@@ -1152,7 +1187,6 @@
|
|
bif->bif_ifp->if_xname);
|
|
}
|
|
}
|
|
- BRIDGE_XDROP(sc);
|
|
if (in6ifa_llaonifp(ifs)) {
|
|
BRIDGE_UNLOCK(sc);
|
|
in6_ifdetach(ifs);
|
|
@@ -1466,12 +1500,17 @@
|
|
struct bridge_iflist *bif;
|
|
int error;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
bif = bridge_lookup_member(sc, req->ifba_ifsname);
|
|
if (bif == NULL)
|
|
return (ENOENT);
|
|
|
|
+ /* bridge_rtupdate() may acquire the lock. */
|
|
+ BRIDGE_UNLOCK(sc);
|
|
error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
|
|
req->ifba_flags);
|
|
+ BRIDGE_LOCK(sc);
|
|
|
|
return (error);
|
|
}
|
|
@@ -1810,6 +1849,7 @@
|
|
{
|
|
struct bridge_softc *sc = ifp->if_bridge;
|
|
struct bridge_iflist *bif;
|
|
+ struct epoch_tracker et;
|
|
|
|
if (ifp->if_flags & IFF_RENAMING)
|
|
return;
|
|
@@ -1820,6 +1860,7 @@
|
|
*/
|
|
return;
|
|
}
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
/* Check if the interface is a bridge member */
|
|
if (sc != NULL) {
|
|
BRIDGE_LOCK(sc);
|
|
@@ -1829,6 +1870,7 @@
|
|
bridge_delete_member(sc, bif, 1);
|
|
|
|
BRIDGE_UNLOCK(sc);
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
return;
|
|
}
|
|
|
|
@@ -1845,6 +1887,7 @@
|
|
BRIDGE_UNLOCK(sc);
|
|
}
|
|
BRIDGE_LIST_UNLOCK();
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
}
|
|
|
|
/*
|
|
@@ -1881,6 +1924,7 @@
|
|
{
|
|
struct bridge_softc *sc = ifp->if_softc;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
|
|
@@ -2004,6 +2048,8 @@
|
|
struct bridge_softc *sc;
|
|
uint16_t vlan;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
if (m->m_len < ETHER_HDR_LEN) {
|
|
m = m_pullup(m, ETHER_HDR_LEN);
|
|
if (m == NULL)
|
|
@@ -2014,8 +2060,6 @@
|
|
sc = ifp->if_bridge;
|
|
vlan = VLANTAGOF(m);
|
|
|
|
- BRIDGE_LOCK(sc);
|
|
-
|
|
/*
|
|
* If bridge is down, but the original output interface is up,
|
|
* go ahead and send out that interface. Otherwise, the packet
|
|
@@ -2037,16 +2081,10 @@
|
|
if (dst_if == NULL) {
|
|
struct bridge_iflist *bif;
|
|
struct mbuf *mc;
|
|
- int error = 0, used = 0;
|
|
+ int used = 0;
|
|
|
|
bridge_span(sc, m);
|
|
|
|
- BRIDGE_LOCK2REF(sc, error);
|
|
- if (error) {
|
|
- m_freem(m);
|
|
- return (0);
|
|
- }
|
|
-
|
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
|
dst_if = bif->bif_ifp;
|
|
|
|
@@ -2080,7 +2118,6 @@
|
|
}
|
|
if (used == 0)
|
|
m_freem(m);
|
|
- BRIDGE_UNREF(sc);
|
|
return (0);
|
|
}
|
|
|
|
@@ -2092,11 +2129,9 @@
|
|
bridge_span(sc, m);
|
|
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
|
m_freem(m);
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (0);
|
|
}
|
|
|
|
- BRIDGE_UNLOCK(sc);
|
|
bridge_enqueue(sc, dst_if, m);
|
|
return (0);
|
|
}
|
|
@@ -2121,10 +2156,8 @@
|
|
|
|
eh = mtod(m, struct ether_header *);
|
|
|
|
- BRIDGE_LOCK(sc);
|
|
if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) &&
|
|
(dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1)) != NULL) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
error = bridge_enqueue(sc, dst_if, m);
|
|
} else
|
|
bridge_broadcast(sc, ifp, m, 0);
|
|
@@ -2158,6 +2191,8 @@
|
|
uint8_t *dst;
|
|
int error;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
src_if = m->m_pkthdr.rcvif;
|
|
ifp = sc->sc_ifp;
|
|
|
|
@@ -2236,12 +2271,10 @@
|
|
|| PFIL_HOOKED(&V_inet6_pfil_hook)
|
|
#endif
|
|
) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
|
|
return;
|
|
if (m == NULL)
|
|
return;
|
|
- BRIDGE_LOCK(sc);
|
|
}
|
|
|
|
if (dst_if == NULL) {
|
|
@@ -2269,8 +2302,6 @@
|
|
dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
|
|
goto drop;
|
|
|
|
- BRIDGE_UNLOCK(sc);
|
|
-
|
|
if (PFIL_HOOKED(&V_inet_pfil_hook)
|
|
#ifdef INET6
|
|
|| PFIL_HOOKED(&V_inet6_pfil_hook)
|
|
@@ -2286,7 +2317,6 @@
|
|
return;
|
|
|
|
drop:
|
|
- BRIDGE_UNLOCK(sc);
|
|
m_freem(m);
|
|
}
|
|
|
|
@@ -2307,6 +2337,8 @@
|
|
uint16_t vlan;
|
|
int error;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
|
|
return (m);
|
|
|
|
@@ -2327,10 +2359,8 @@
|
|
m_freem(m);
|
|
return (NULL);
|
|
}
|
|
- BRIDGE_LOCK(sc);
|
|
bif = bridge_lookup_member_if(sc, ifp);
|
|
if (bif == NULL) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (m);
|
|
}
|
|
|
|
@@ -2343,13 +2373,11 @@
|
|
if (memcmp(eh->ether_dhost, bstp_etheraddr,
|
|
ETHER_ADDR_LEN) == 0) {
|
|
bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (NULL);
|
|
}
|
|
|
|
if ((bif->bif_flags & IFBIF_STP) &&
|
|
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (m);
|
|
}
|
|
|
|
@@ -2360,7 +2388,6 @@
|
|
*/
|
|
mc = m_dup(m, M_NOWAIT);
|
|
if (mc == NULL) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (m);
|
|
}
|
|
|
|
@@ -2392,7 +2419,6 @@
|
|
|
|
if ((bif->bif_flags & IFBIF_STP) &&
|
|
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
return (m);
|
|
}
|
|
|
|
@@ -2432,7 +2458,6 @@
|
|
OR_PFIL_HOOKED_INET6)) { \
|
|
if (bridge_pfil(&m, NULL, ifp, \
|
|
PFIL_IN) != 0 || m == NULL) { \
|
|
- BRIDGE_UNLOCK(sc); \
|
|
return (NULL); \
|
|
} \
|
|
eh = mtod(m, struct ether_header *); \
|
|
@@ -2442,13 +2467,11 @@
|
|
error = bridge_rtupdate(sc, eh->ether_shost, \
|
|
vlan, bif, 0, IFBAF_DYNAMIC); \
|
|
if (error && bif->bif_addrmax) { \
|
|
- BRIDGE_UNLOCK(sc); \
|
|
m_freem(m); \
|
|
return (NULL); \
|
|
} \
|
|
} \
|
|
m->m_pkthdr.rcvif = iface; \
|
|
- BRIDGE_UNLOCK(sc); \
|
|
return (m); \
|
|
} \
|
|
\
|
|
@@ -2456,7 +2479,6 @@
|
|
if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \
|
|
OR_CARP_CHECK_WE_ARE_SRC((iface)) \
|
|
) { \
|
|
- BRIDGE_UNLOCK(sc); \
|
|
m_freem(m); \
|
|
return (NULL); \
|
|
}
|
|
@@ -2507,16 +2529,12 @@
|
|
struct bridge_iflist *dbif, *sbif;
|
|
struct mbuf *mc;
|
|
struct ifnet *dst_if;
|
|
- int error = 0, used = 0, i;
|
|
+ int used = 0, i;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
sbif = bridge_lookup_member_if(sc, src_if);
|
|
|
|
- BRIDGE_LOCK2REF(sc, error);
|
|
- if (error) {
|
|
- m_freem(m);
|
|
- return;
|
|
- }
|
|
-
|
|
/* Filter on the bridge interface before broadcasting */
|
|
if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
|
|
#ifdef INET6
|
|
@@ -2524,9 +2542,9 @@
|
|
#endif
|
|
)) {
|
|
if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0)
|
|
- goto out;
|
|
+ return;
|
|
if (m == NULL)
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
|
|
LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) {
|
|
@@ -2589,9 +2607,6 @@
|
|
}
|
|
if (used == 0)
|
|
m_freem(m);
|
|
-
|
|
-out:
|
|
- BRIDGE_UNREF(sc);
|
|
}
|
|
|
|
/*
|
|
@@ -2607,6 +2622,8 @@
|
|
struct ifnet *dst_if;
|
|
struct mbuf *mc;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
if (LIST_EMPTY(&sc->sc_spanlist))
|
|
return;
|
|
|
|
@@ -2638,7 +2655,8 @@
|
|
struct bridge_rtnode *brt;
|
|
int error;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
+ BRIDGE_UNLOCK_ASSERT(sc);
|
|
|
|
/* Check the source address is valid and not multicast. */
|
|
if (ETHER_IS_MULTICAST(dst) ||
|
|
@@ -2655,13 +2673,24 @@
|
|
* update it, otherwise create a new one.
|
|
*/
|
|
if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) {
|
|
+ BRIDGE_LOCK(sc);
|
|
+
|
|
+ /* Check again, now that we have the lock. There could have
|
|
+ * been a race and we only want to insert this once. */
|
|
+ if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) != NULL) {
|
|
+ BRIDGE_UNLOCK(sc);
|
|
+ return (0);
|
|
+ }
|
|
+
|
|
if (sc->sc_brtcnt >= sc->sc_brtmax) {
|
|
sc->sc_brtexceeded++;
|
|
+ BRIDGE_UNLOCK(sc);
|
|
return (ENOSPC);
|
|
}
|
|
/* Check per interface address limits (if enabled) */
|
|
if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) {
|
|
bif->bif_addrexceeded++;
|
|
+ BRIDGE_UNLOCK(sc);
|
|
return (ENOSPC);
|
|
}
|
|
|
|
@@ -2671,8 +2700,11 @@
|
|
* address.
|
|
*/
|
|
brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
|
|
- if (brt == NULL)
|
|
+ if (brt == NULL) {
|
|
+ BRIDGE_UNLOCK(sc);
|
|
return (ENOMEM);
|
|
+ }
|
|
+ brt->brt_vnet = curvnet;
|
|
|
|
if (bif->bif_flags & IFBIF_STICKY)
|
|
brt->brt_flags = IFBAF_STICKY;
|
|
@@ -2684,17 +2716,22 @@
|
|
|
|
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
|
|
uma_zfree(V_bridge_rtnode_zone, brt);
|
|
+ BRIDGE_UNLOCK(sc);
|
|
return (error);
|
|
}
|
|
brt->brt_dst = bif;
|
|
bif->bif_addrcnt++;
|
|
+
|
|
+ BRIDGE_UNLOCK(sc);
|
|
}
|
|
|
|
if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
|
|
brt->brt_dst != bif) {
|
|
+ BRIDGE_LOCK(sc);
|
|
brt->brt_dst->bif_addrcnt--;
|
|
brt->brt_dst = bif;
|
|
brt->brt_dst->bif_addrcnt++;
|
|
+ BRIDGE_UNLOCK(sc);
|
|
}
|
|
|
|
if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
|
|
@@ -2715,7 +2752,7 @@
|
|
{
|
|
struct bridge_rtnode *brt;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
|
|
if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL)
|
|
return (NULL);
|
|
@@ -2735,6 +2772,7 @@
|
|
{
|
|
struct bridge_rtnode *brt, *nbrt;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
/* Make sure we actually need to do this. */
|
|
@@ -2764,7 +2802,9 @@
|
|
bridge_timer(void *arg)
|
|
{
|
|
struct bridge_softc *sc = arg;
|
|
+ struct epoch_tracker et;
|
|
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
/* Destruction of rtnodes requires a proper vnet context */
|
|
@@ -2775,6 +2815,7 @@
|
|
callout_reset(&sc->sc_brcallout,
|
|
bridge_rtable_prune_period * hz, bridge_timer, sc);
|
|
CURVNET_RESTORE();
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
}
|
|
|
|
/*
|
|
@@ -2787,6 +2828,7 @@
|
|
{
|
|
struct bridge_rtnode *brt, *nbrt;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
|
|
@@ -2807,6 +2849,7 @@
|
|
{
|
|
struct bridge_rtnode *brt, *nbrt;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
|
|
@@ -2826,6 +2869,7 @@
|
|
struct bridge_rtnode *brt;
|
|
int found = 0;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
/*
|
|
@@ -2850,6 +2894,7 @@
|
|
{
|
|
struct bridge_rtnode *brt, *nbrt;
|
|
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
|
|
@@ -2954,7 +2999,7 @@
|
|
uint32_t hash;
|
|
int dir;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
|
|
hash = bridge_rthash(sc, addr);
|
|
LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
|
|
@@ -3017,6 +3062,18 @@
|
|
return (0);
|
|
}
|
|
|
|
+static void
|
|
+bridge_rtnode_destroy_cb(struct epoch_context *ctx)
|
|
+{
|
|
+ struct bridge_rtnode *brt;
|
|
+
|
|
+ brt = __containerof(ctx, struct bridge_rtnode, brt_epoch_ctx);
|
|
+
|
|
+ CURVNET_SET(brt->brt_vnet);
|
|
+ uma_zfree(V_bridge_rtnode_zone, brt);
|
|
+ CURVNET_RESTORE();
|
|
+}
|
|
+
|
|
/*
|
|
* bridge_rtnode_destroy:
|
|
*
|
|
@@ -3025,6 +3082,7 @@
|
|
static void
|
|
bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
|
|
{
|
|
+ NET_EPOCH_ASSERT();
|
|
BRIDGE_LOCK_ASSERT(sc);
|
|
|
|
LIST_REMOVE(brt, brt_hash);
|
|
@@ -3032,7 +3090,8 @@
|
|
LIST_REMOVE(brt, brt_list);
|
|
sc->sc_brtcnt--;
|
|
brt->brt_dst->bif_addrcnt--;
|
|
- uma_zfree(V_bridge_rtnode_zone, brt);
|
|
+
|
|
+ NET_EPOCH_CALL(bridge_rtnode_destroy_cb, &brt->brt_epoch_ctx);
|
|
}
|
|
|
|
/*
|
|
@@ -3045,7 +3104,9 @@
|
|
{
|
|
struct bridge_softc *sc = ifp->if_bridge;
|
|
struct bridge_rtnode *brt;
|
|
+ struct epoch_tracker et;
|
|
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
CURVNET_SET(ifp->if_vnet);
|
|
BRIDGE_LOCK(sc);
|
|
|
|
@@ -3066,6 +3127,7 @@
|
|
}
|
|
BRIDGE_UNLOCK(sc);
|
|
CURVNET_RESTORE();
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
}
|
|
|
|
/*
|
|
@@ -3577,17 +3639,20 @@
|
|
{
|
|
struct bridge_softc *sc = ifp->if_bridge;
|
|
struct bridge_iflist *bif;
|
|
+ struct epoch_tracker et;
|
|
|
|
- BRIDGE_LOCK(sc);
|
|
+ NET_EPOCH_ENTER_ET(et);
|
|
+
|
|
bif = bridge_lookup_member_if(sc, ifp);
|
|
if (bif == NULL) {
|
|
- BRIDGE_UNLOCK(sc);
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
return;
|
|
}
|
|
bridge_linkcheck(sc);
|
|
- BRIDGE_UNLOCK(sc);
|
|
|
|
bstp_linkstate(&bif->bif_stp);
|
|
+
|
|
+ NET_EPOCH_EXIT_ET(et);
|
|
}
|
|
|
|
static void
|
|
@@ -3596,7 +3661,8 @@
|
|
struct bridge_iflist *bif;
|
|
int new_link, hasls;
|
|
|
|
- BRIDGE_LOCK_ASSERT(sc);
|
|
+ NET_EPOCH_ASSERT();
|
|
+
|
|
new_link = LINK_STATE_DOWN;
|
|
hasls = 0;
|
|
/* Our link is considered up if at least one of our ports is active */
|
|
Index: sys/net/if_bridgevar.h
|
|
===================================================================
|
|
--- sys/net/if_bridgevar.h (revision 360985)
|
|
+++ sys/net/if_bridgevar.h (working copy)
|
|
@@ -273,41 +273,14 @@
|
|
|
|
#define BRIDGE_LOCK_INIT(_sc) do { \
|
|
mtx_init(&(_sc)->sc_mtx, "if_bridge", NULL, MTX_DEF); \
|
|
- cv_init(&(_sc)->sc_cv, "if_bridge_cv"); \
|
|
} while (0)
|
|
#define BRIDGE_LOCK_DESTROY(_sc) do { \
|
|
mtx_destroy(&(_sc)->sc_mtx); \
|
|
- cv_destroy(&(_sc)->sc_cv); \
|
|
} while (0)
|
|
#define BRIDGE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
|
|
#define BRIDGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
|
|
#define BRIDGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
|
|
#define BRIDGE_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
|
|
-#define BRIDGE_LOCK2REF(_sc, _err) do { \
|
|
- mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
|
|
- if ((_sc)->sc_iflist_xcnt > 0) \
|
|
- (_err) = EBUSY; \
|
|
- else \
|
|
- (_sc)->sc_iflist_ref++; \
|
|
- mtx_unlock(&(_sc)->sc_mtx); \
|
|
-} while (0)
|
|
-#define BRIDGE_UNREF(_sc) do { \
|
|
- mtx_lock(&(_sc)->sc_mtx); \
|
|
- (_sc)->sc_iflist_ref--; \
|
|
- if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) \
|
|
- cv_broadcast(&(_sc)->sc_cv); \
|
|
- mtx_unlock(&(_sc)->sc_mtx); \
|
|
-} while (0)
|
|
-#define BRIDGE_XLOCK(_sc) do { \
|
|
- mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
|
|
- (_sc)->sc_iflist_xcnt++; \
|
|
- while ((_sc)->sc_iflist_ref > 0) \
|
|
- cv_wait(&(_sc)->sc_cv, &(_sc)->sc_mtx); \
|
|
-} while (0)
|
|
-#define BRIDGE_XDROP(_sc) do { \
|
|
- mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
|
|
- (_sc)->sc_iflist_xcnt--; \
|
|
-} while (0)
|
|
|
|
#define BRIDGE_INPUT(_ifp, _m) do { \
|
|
KASSERT((_ifp)->if_bridge_input != NULL, \
|