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