Module Name: src
Committed By: ozaki-r
Date: Thu Jan 8 10:47:44 UTC 2015
Modified Files:
src/sys/net: if_bridge.c if_bridgevar.h
Log Message:
Use pserialize for rtlist in bridge
This change enables lockless accesses to bridge rtable lists.
See locking notes in a comment to know how pserialize and
mutexes are used. Some functions are rearranged to use
pserialize. A workqueue is introduced to use pserialize in
bridge_rtage via bridge_timer callout.
As usual, pserialize and mutexes are used only when NET_MPSAFE
on. On the other hand, the newly added workqueue is used
regardless of NET_MPSAFE on or off.
To generate a diff of this commit:
cvs rdiff -u -r1.96 -r1.97 src/sys/net/if_bridge.c
cvs rdiff -u -r1.21 -r1.22 src/sys/net/if_bridgevar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.96 src/sys/net/if_bridge.c:1.97
--- src/sys/net/if_bridge.c:1.96 Thu Jan 1 08:43:26 2015
+++ src/sys/net/if_bridge.c Thu Jan 8 10:47:44 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bridge.c,v 1.96 2015/01/01 08:43:26 ozaki-r Exp $ */
+/* $NetBSD: if_bridge.c,v 1.97 2015/01/08 10:47:44 ozaki-r Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.96 2015/01/01 08:43:26 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.97 2015/01/08 10:47:44 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_bridge_ipf.h"
@@ -175,9 +175,43 @@ __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,
#define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
#endif
+#define BRIDGE_RT_INTR_LOCK(_sc) mutex_enter((_sc)->sc_rtlist_intr_lock)
+#define BRIDGE_RT_INTR_UNLOCK(_sc) mutex_exit((_sc)->sc_rtlist_intr_lock)
+#define BRIDGE_RT_INTR_LOCKED(_sc) mutex_owned((_sc)->sc_rtlist_intr_lock)
+
+#define BRIDGE_RT_LOCK(_sc) if ((_sc)->sc_rtlist_lock) \
+ mutex_enter((_sc)->sc_rtlist_lock)
+#define BRIDGE_RT_UNLOCK(_sc) if ((_sc)->sc_rtlist_lock) \
+ mutex_exit((_sc)->sc_rtlist_lock)
+#define BRIDGE_RT_LOCKED(_sc) (!(_sc)->sc_rtlist_lock || \
+ mutex_owned((_sc)->sc_rtlist_lock))
+
+#define BRIDGE_RT_PSZ_PERFORM(_sc) \
+ if ((_sc)->sc_rtlist_psz != NULL) \
+ pserialize_perform((_sc)->sc_rtlist_psz);
+
+#ifdef BRIDGE_MPSAFE
+#define BRIDGE_RT_RENTER(__s) do { \
+ if (!cpu_intr_p()) \
+ __s = pserialize_read_enter(); \
+ else \
+ __s = splhigh(); \
+ } while (0)
+#define BRIDGE_RT_REXIT(__s) do { \
+ if (!cpu_intr_p()) \
+ pserialize_read_exit(__s); \
+ else \
+ splx(__s); \
+ } while (0)
+#else /* BRIDGE_MPSAFE */
+#define BRIDGE_RT_RENTER(__s) do { __s = 0; } while (0)
+#define BRIDGE_RT_REXIT(__s) do { (void)__s; } while (0)
+#endif /* BRIDGE_MPSAFE */
+
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
static struct pool bridge_rtnode_pool;
+static struct work bridge_rtage_wk;
void bridgeattach(int);
@@ -202,6 +236,7 @@ static int bridge_rtupdate(struct bridge
static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *);
static void bridge_rttrim(struct bridge_softc *);
static void bridge_rtage(struct bridge_softc *);
+static void bridge_rtage_work(struct work *, void *);
static void bridge_rtflush(struct bridge_softc *, int);
static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *);
static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp);
@@ -213,8 +248,9 @@ static struct bridge_rtnode *bridge_rtno
const uint8_t *);
static int bridge_rtnode_insert(struct bridge_softc *,
struct bridge_rtnode *);
-static void bridge_rtnode_destroy(struct bridge_softc *,
- struct bridge_rtnode *);
+static void bridge_rtnode_remove(struct bridge_softc *,
+ struct bridge_rtnode *);
+static void bridge_rtnode_destroy(struct bridge_rtnode *);
static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
const char *name);
@@ -348,6 +384,7 @@ bridge_clone_create(struct if_clone *ifc
{
struct bridge_softc *sc;
struct ifnet *ifp;
+ int error, flags;
sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
ifp = &sc->sc_if;
@@ -364,6 +401,16 @@ bridge_clone_create(struct if_clone *ifc
/* Initialize our routing table. */
bridge_rtable_init(sc);
+#ifdef BRIDGE_MPSAFE
+ flags = WQ_MPSAFE;
+#else
+ flags = 0;
+#endif
+ error = workqueue_create(&sc->sc_rtage_wq, "bridge_rtage",
+ bridge_rtage_work, sc, PRI_SOFTNET, IPL_SOFTNET, flags);
+ if (error)
+ panic("%s: workqueue_create %d\n", __func__, error);
+
callout_init(&sc->sc_brcallout, 0);
callout_init(&sc->sc_bstpcallout, 0);
@@ -454,6 +501,8 @@ bridge_clone_destroy(struct ifnet *ifp)
if (sc->sc_iflist_lock)
mutex_obj_free(sc->sc_iflist_lock);
+ workqueue_destroy(sc->sc_rtage_wq);
+
kmem_free(sc, sizeof(*sc));
return (0);
@@ -1077,7 +1126,7 @@ bridge_ioctl_rts(struct bridge_softc *sc
if (bac->ifbac_len == 0)
return (0);
- mutex_enter(sc->sc_rtlist_lock);
+ BRIDGE_RT_INTR_LOCK(sc);
len = bac->ifbac_len;
LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
@@ -1100,7 +1149,7 @@ bridge_ioctl_rts(struct bridge_softc *sc
len -= sizeof(bareq);
}
out:
- mutex_exit(sc->sc_rtlist_lock);
+ BRIDGE_RT_INTR_UNLOCK(sc);
bac->ifbac_len = sizeof(bareq) * count;
return (error);
@@ -1976,6 +2025,43 @@ next:
m_freem(m);
}
+static int
+bridge_rtalloc(struct bridge_softc *sc, const uint8_t *dst,
+ struct bridge_rtnode **brtp)
+{
+ struct bridge_rtnode *brt;
+ int error;
+
+ if (sc->sc_brtcnt >= sc->sc_brtmax)
+ return ENOSPC;
+
+ /*
+ * Allocate a new bridge forwarding node, and
+ * initialize the expiration time and Ethernet
+ * address.
+ */
+ brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT);
+ if (brt == NULL)
+ return ENOMEM;
+
+ memset(brt, 0, sizeof(*brt));
+ brt->brt_expire = time_uptime + sc->sc_brttimeout;
+ brt->brt_flags = IFBAF_DYNAMIC;
+ memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
+
+ BRIDGE_RT_INTR_LOCK(sc);
+ error = bridge_rtnode_insert(sc, brt);
+ BRIDGE_RT_INTR_UNLOCK(sc);
+
+ if (error != 0) {
+ pool_put(&bridge_rtnode_pool, brt);
+ return error;
+ }
+
+ *brtp = brt;
+ return 0;
+}
+
/*
* bridge_rtupdate:
*
@@ -1986,58 +2072,41 @@ bridge_rtupdate(struct bridge_softc *sc,
struct ifnet *dst_if, int setflags, uint8_t flags)
{
struct bridge_rtnode *brt;
- int error = 0;
-
- mutex_enter(sc->sc_rtlist_lock);
+ int s;
+again:
/*
* A route for this destination might already exist. If so,
* update it, otherwise create a new one.
*/
- if ((brt = bridge_rtnode_lookup(sc, dst)) == NULL) {
- if (sc->sc_brtcnt >= sc->sc_brtmax) {
- error = ENOSPC;
- goto out;
- }
+ BRIDGE_RT_RENTER(s);
+ brt = bridge_rtnode_lookup(sc, dst);
- /*
- * Allocate a new bridge forwarding node, and
- * initialize the expiration time and Ethernet
- * address.
- */
- brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT);
- if (brt == NULL) {
- error = ENOMEM;
- goto out;
- }
-
- memset(brt, 0, sizeof(*brt));
- brt->brt_expire = time_uptime + sc->sc_brttimeout;
- brt->brt_flags = IFBAF_DYNAMIC;
- memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
-
- if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
- pool_put(&bridge_rtnode_pool, brt);
- goto out;
+ if (brt != NULL) {
+ brt->brt_ifp = dst_if;
+ if (setflags) {
+ brt->brt_flags = flags;
+ if (flags & IFBAF_STATIC)
+ brt->brt_expire = 0;
+ else
+ brt->brt_expire = time_uptime + sc->sc_brttimeout;
+ } else {
+ if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
+ brt->brt_expire = time_uptime + sc->sc_brttimeout;
}
}
+ BRIDGE_RT_REXIT(s);
- brt->brt_ifp = dst_if;
- if (setflags) {
- brt->brt_flags = flags;
- if (flags & IFBAF_STATIC)
- brt->brt_expire = 0;
- else
- brt->brt_expire = time_uptime + sc->sc_brttimeout;
- } else {
- if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
- brt->brt_expire = time_uptime + sc->sc_brttimeout;
- }
+ if (brt == NULL) {
+ int r;
-out:
- mutex_exit(sc->sc_rtlist_lock);
+ r = bridge_rtalloc(sc, dst, &brt);
+ if (r != 0)
+ return r;
+ goto again;
+ }
- return error;
+ return 0;
}
/*
@@ -2050,18 +2119,92 @@ bridge_rtlookup(struct bridge_softc *sc,
{
struct bridge_rtnode *brt;
struct ifnet *ifs = NULL;
+ int s;
- mutex_enter(sc->sc_rtlist_lock);
-
+ BRIDGE_RT_RENTER(s);
brt = bridge_rtnode_lookup(sc, addr);
if (brt != NULL)
ifs = brt->brt_ifp;
-
- mutex_exit(sc->sc_rtlist_lock);
+ BRIDGE_RT_REXIT(s);
return ifs;
}
+typedef bool (*bridge_iterate_cb_t)
+ (struct bridge_softc *, struct bridge_rtnode *, bool *, void *);
+
+/*
+ * bridge_rtlist_iterate_remove:
+ *
+ * It iterates on sc->sc_rtlist and removes rtnodes of it which func
+ * callback judges to remove. Removals of rtnodes are done in a manner
+ * of pserialize. To this end, all kmem_* operations are placed out of
+ * mutexes.
+ */
+static void
+bridge_rtlist_iterate_remove(struct bridge_softc *sc, bridge_iterate_cb_t func, void *arg)
+{
+ struct bridge_rtnode *brt, *nbrt;
+ struct bridge_rtnode **brt_list;
+ int i, count;
+
+retry:
+ count = sc->sc_brtcnt;
+ if (count == 0)
+ return;
+ brt_list = kmem_alloc(sizeof(struct bridge_rtnode *) * count, KM_SLEEP);
+
+ BRIDGE_RT_LOCK(sc);
+ BRIDGE_RT_INTR_LOCK(sc);
+ if (__predict_false(sc->sc_brtcnt > count)) {
+ /* The rtnodes increased, we need more memory */
+ BRIDGE_RT_INTR_UNLOCK(sc);
+ BRIDGE_RT_UNLOCK(sc);
+ kmem_free(brt_list, sizeof(*brt_list) * count);
+ goto retry;
+ }
+
+ i = 0;
+ LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
+ bool need_break = false;
+ if (func(sc, brt, &need_break, arg)) {
+ bridge_rtnode_remove(sc, brt);
+ brt_list[i++] = brt;
+ }
+ if (need_break)
+ break;
+ }
+ BRIDGE_RT_INTR_UNLOCK(sc);
+
+ if (i > 0)
+ BRIDGE_RT_PSZ_PERFORM(sc);
+ BRIDGE_RT_UNLOCK(sc);
+
+ while (--i >= 0)
+ bridge_rtnode_destroy(brt_list[i]);
+
+ kmem_free(brt_list, sizeof(*brt_list) * count);
+}
+
+static bool
+bridge_rttrim0_cb(struct bridge_softc *sc, struct bridge_rtnode *brt,
+ bool *need_break, void *arg)
+{
+ if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
+ /* Take into account of the subsequent removal */
+ if ((sc->sc_brtcnt - 1) <= sc->sc_brtmax)
+ *need_break = true;
+ return true;
+ } else
+ return false;
+}
+
+static void
+bridge_rttrim0(struct bridge_softc *sc)
+{
+ bridge_rtlist_iterate_remove(sc, bridge_rttrim0_cb, NULL);
+}
+
/*
* bridge_rttrim:
*
@@ -2072,29 +2215,17 @@ bridge_rtlookup(struct bridge_softc *sc,
static void
bridge_rttrim(struct bridge_softc *sc)
{
- struct bridge_rtnode *brt, *nbrt;
-
- mutex_enter(sc->sc_rtlist_lock);
/* Make sure we actually need to do this. */
if (sc->sc_brtcnt <= sc->sc_brtmax)
- goto out;
+ return;
/* Force an aging cycle; this might trim enough addresses. */
bridge_rtage(sc);
if (sc->sc_brtcnt <= sc->sc_brtmax)
- goto out;
-
- LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
- if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
- bridge_rtnode_destroy(sc, brt);
- if (sc->sc_brtcnt <= sc->sc_brtmax)
- goto out;
- }
- }
+ return;
-out:
- mutex_exit(sc->sc_rtlist_lock);
+ bridge_rttrim0(sc);
return;
}
@@ -2109,15 +2240,32 @@ bridge_timer(void *arg)
{
struct bridge_softc *sc = arg;
- mutex_enter(sc->sc_rtlist_lock);
+ workqueue_enqueue(sc->sc_rtage_wq, &bridge_rtage_wk, NULL);
+}
+
+static void
+bridge_rtage_work(struct work *wk, void *arg)
+{
+ struct bridge_softc *sc = arg;
+
+ KASSERT(wk == &bridge_rtage_wk);
bridge_rtage(sc);
if (sc->sc_if.if_flags & IFF_RUNNING)
callout_reset(&sc->sc_brcallout,
bridge_rtable_prune_period * hz, bridge_timer, sc);
+}
- mutex_exit(sc->sc_rtlist_lock);
+static bool
+bridge_rtage_cb(struct bridge_softc *sc, struct bridge_rtnode *brt,
+ bool *need_break, void *arg)
+{
+ if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
+ time_uptime >= brt->brt_expire)
+ return true;
+ else
+ return false;
}
/*
@@ -2128,16 +2276,20 @@ bridge_timer(void *arg)
static void
bridge_rtage(struct bridge_softc *sc)
{
- struct bridge_rtnode *brt, *nbrt;
+ bridge_rtlist_iterate_remove(sc, bridge_rtage_cb, NULL);
+}
- KASSERT(mutex_owned(sc->sc_rtlist_lock));
- LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
- if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
- if (time_uptime >= brt->brt_expire)
- bridge_rtnode_destroy(sc, brt);
- }
- }
+static bool
+bridge_rtflush_cb(struct bridge_softc *sc, struct bridge_rtnode *brt,
+ bool *need_break, void *arg)
+{
+ int full = *(int*)arg;
+
+ if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
+ return true;
+ else
+ return false;
}
/*
@@ -2148,16 +2300,7 @@ bridge_rtage(struct bridge_softc *sc)
static void
bridge_rtflush(struct bridge_softc *sc, int full)
{
- struct bridge_rtnode *brt, *nbrt;
-
- mutex_enter(sc->sc_rtlist_lock);
-
- LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
- if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
- bridge_rtnode_destroy(sc, brt);
- }
-
- mutex_exit(sc->sc_rtlist_lock);
+ bridge_rtlist_iterate_remove(sc, bridge_rtflush_cb, &full);
}
/*
@@ -2169,21 +2312,22 @@ static int
bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr)
{
struct bridge_rtnode *brt;
- int error = 0;
-
- mutex_enter(sc->sc_rtlist_lock);
+ BRIDGE_RT_LOCK(sc);
+ BRIDGE_RT_INTR_LOCK(sc);
if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL) {
- error = ENOENT;
- goto out;
+ BRIDGE_RT_INTR_UNLOCK(sc);
+ BRIDGE_RT_UNLOCK(sc);
+ return ENOENT;
}
+ bridge_rtnode_remove(sc, brt);
+ BRIDGE_RT_INTR_UNLOCK(sc);
+ BRIDGE_RT_PSZ_PERFORM(sc);
+ BRIDGE_RT_UNLOCK(sc);
- bridge_rtnode_destroy(sc, brt);
+ bridge_rtnode_destroy(brt);
-out:
- mutex_exit(sc->sc_rtlist_lock);
-
- return error;
+ return 0;
}
/*
@@ -2196,14 +2340,23 @@ bridge_rtdelete(struct bridge_softc *sc,
{
struct bridge_rtnode *brt, *nbrt;
- mutex_enter(sc->sc_rtlist_lock);
-
+ BRIDGE_RT_LOCK(sc);
+ BRIDGE_RT_INTR_LOCK(sc);
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) {
if (brt->brt_ifp == ifp)
- bridge_rtnode_destroy(sc, brt);
+ break;
}
+ if (brt == NULL) {
+ BRIDGE_RT_INTR_UNLOCK(sc);
+ BRIDGE_RT_UNLOCK(sc);
+ return;
+ }
+ bridge_rtnode_remove(sc, brt);
+ BRIDGE_RT_INTR_UNLOCK(sc);
+ BRIDGE_RT_PSZ_PERFORM(sc);
+ BRIDGE_RT_UNLOCK(sc);
- mutex_exit(sc->sc_rtlist_lock);
+ bridge_rtnode_destroy(brt);
}
/*
@@ -2226,7 +2379,14 @@ bridge_rtable_init(struct bridge_softc *
LIST_INIT(&sc->sc_rtlist);
- sc->sc_rtlist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
+ sc->sc_rtlist_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
+#ifdef BRIDGE_MPSAFE
+ sc->sc_rtlist_psz = pserialize_create();
+ sc->sc_rtlist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
+#else
+ sc->sc_rtlist_psz = NULL;
+ sc->sc_rtlist_lock = NULL;
+#endif
}
/*
@@ -2239,8 +2399,12 @@ bridge_rtable_fini(struct bridge_softc *
{
kmem_free(sc->sc_rthash, sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE);
+ if (sc->sc_rtlist_intr_lock)
+ mutex_obj_free(sc->sc_rtlist_intr_lock);
if (sc->sc_rtlist_lock)
mutex_obj_free(sc->sc_rtlist_lock);
+ if (sc->sc_rtlist_psz)
+ pserialize_destroy(sc->sc_rtlist_psz);
}
/*
@@ -2291,8 +2455,6 @@ bridge_rtnode_lookup(struct bridge_softc
uint32_t hash;
int dir;
- KASSERT(mutex_owned(sc->sc_rtlist_lock));
-
hash = bridge_rthash(sc, addr);
LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
dir = memcmp(addr, brt->brt_addr, ETHER_ADDR_LEN);
@@ -2318,7 +2480,7 @@ bridge_rtnode_insert(struct bridge_softc
uint32_t hash;
int dir;
- KASSERT(mutex_owned(sc->sc_rtlist_lock));
+ KASSERT(BRIDGE_RT_INTR_LOCKED(sc));
hash = bridge_rthash(sc, brt->brt_addr);
@@ -2355,20 +2517,30 @@ bridge_rtnode_insert(struct bridge_softc
}
/*
- * bridge_rtnode_destroy:
+ * bridge_rtnode_remove:
*
- * Destroy a bridge rtnode.
+ * Remove a bridge rtnode from the rthash and the rtlist of a bridge.
*/
static void
-bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
+bridge_rtnode_remove(struct bridge_softc *sc, struct bridge_rtnode *brt)
{
- KASSERT(mutex_owned(sc->sc_rtlist_lock));
+ KASSERT(BRIDGE_RT_INTR_LOCKED(sc));
LIST_REMOVE(brt, brt_hash);
-
LIST_REMOVE(brt, brt_list);
sc->sc_brtcnt--;
+}
+
+/*
+ * bridge_rtnode_destroy:
+ *
+ * Destroy a bridge rtnode.
+ */
+static void
+bridge_rtnode_destroy(struct bridge_rtnode *brt)
+{
+
pool_put(&bridge_rtnode_pool, brt);
}
Index: src/sys/net/if_bridgevar.h
diff -u src/sys/net/if_bridgevar.h:1.21 src/sys/net/if_bridgevar.h:1.22
--- src/sys/net/if_bridgevar.h:1.21 Wed Dec 31 17:36:24 2014
+++ src/sys/net/if_bridgevar.h Thu Jan 8 10:47:44 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bridgevar.h,v 1.21 2014/12/31 17:36:24 ozaki-r Exp $ */
+/* $NetBSD: if_bridgevar.h,v 1.22 2015/01/08 10:47:44 ozaki-r Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -208,6 +208,7 @@ struct ifbrparam {
#ifdef _KERNEL
#include <sys/pserialize.h>
+#include <sys/workqueue.h>
#include <net/pktqueue.h>
@@ -311,7 +312,10 @@ struct bridge_softc {
kmutex_t *sc_iflist_lock;
LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
+ kmutex_t *sc_rtlist_intr_lock;
kmutex_t *sc_rtlist_lock;
+ pserialize_t sc_rtlist_psz;
+ struct workqueue *sc_rtage_wq;
uint32_t sc_rthash_key; /* key for hash */
uint32_t sc_filter_flags; /* ipf and flags */
pktqueue_t * sc_fwd_pktq;
@@ -387,6 +391,13 @@ void bridge_enqueue(struct bridge_softc
* - The mutex is also used for STP
* - Once we change to execute entire Layer 2 in softint context,
* we can get rid of sc_iflist_intr_lock
+ * - Updates of sc_rtlist are serialized by sc_rtlist_intr_lock (a spin mutex)
+ * - The sc_rtlist can be modified in HW interrupt context for now
+ * - sc_rtlist_lock (an adaptive mutex) is only for pserialize
+ * - Once we change to execute entire Layer 2 in softint context,
+ * we can get rid of sc_rtlist_intr_lock
+ * - A workqueue is used to run bridge_rtage in LWP context via bridge_timer callout
+ * - bridge_rtage uses pserialize that requires non-interrupt context
*/
#endif /* _KERNEL */
#endif /* !_NET_IF_BRIDGEVAR_H_ */