Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/net Use pserialize for rtlist in bridge
details: https://anonhg.NetBSD.org/src/rev/44d1d6917934
branches: trunk
changeset: 335474:44d1d6917934
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Thu Jan 08 10:47:44 2015 +0000
description:
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.
diffstat:
sys/net/if_bridge.c | 418 ++++++++++++++++++++++++++++++++++--------------
sys/net/if_bridgevar.h | 13 +-
2 files changed, 307 insertions(+), 124 deletions(-)
diffs (truncated from 673 to 300 lines):
diff -r e85c02789de4 -r 44d1d6917934 sys/net/if_bridge.c
--- a/sys/net/if_bridge.c Thu Jan 08 10:38:08 2015 +0000
+++ b/sys/net/if_bridge.c Thu Jan 08 10:47:44 2015 +0000
@@ -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 @@
#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 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 @@
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 @@
{
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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;
- }
-
- /*
- * 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;
+ BRIDGE_RT_RENTER(s);
+ brt = bridge_rtnode_lookup(sc, dst);
+
+ 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;
}
}
-
- 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);
+
+ if (brt == NULL) {
+ int r;
+
+ r = bridge_rtalloc(sc, dst, &brt);
+ if (r != 0)
+ return r;
+ goto again;
}
-out:
- mutex_exit(sc->sc_rtlist_lock);
-
- return error;
+ return 0;
}
/*
@@ -2050,18 +2119,92 @@
{
struct bridge_rtnode *brt;
struct ifnet *ifs = NULL;
-
- mutex_enter(sc->sc_rtlist_lock);
-
+ int s;
+
+ 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;
Home |
Main Index |
Thread Index |
Old Index