Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net vlan(4) MP-ify. contributed by s-yamaguchi@IIJ, thanks.



details:   https://anonhg.NetBSD.org/src/rev/1243c8c39fcf
branches:  trunk
changeset: 824496:1243c8c39fcf
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Wed Jun 07 03:53:11 2017 +0000

description:
vlan(4) MP-ify. contributed by s-yamaguchi@IIJ, thanks.

XXX Pull-ups needed for netbsd-8 branch

diffstat:

 sys/net/if_vlan.c    |  840 ++++++++++++++++++++++++++++++++++++++++++++------
 sys/net/if_vlanvar.h |   33 +-
 2 files changed, 758 insertions(+), 115 deletions(-)

diffs (truncated from 1315 to 300 lines):

diff -r d2fc6aaa0f23 -r 1243c8c39fcf sys/net/if_vlan.c
--- a/sys/net/if_vlan.c Wed Jun 07 03:32:39 2017 +0000
+++ b/sys/net/if_vlan.c Wed Jun 07 03:53:11 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_vlan.c,v 1.97 2017/05/29 02:55:49 ozaki-r Exp $     */
+/*     $NetBSD: if_vlan.c,v 1.98 2017/06/07 03:53:11 knakahara Exp $   */
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.97 2017/05/29 02:55:49 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.98 2017/06/07 03:53:11 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -86,6 +86,7 @@
 #endif
 
 #include <sys/param.h>
+#include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/queue.h>
@@ -95,6 +96,12 @@
 #include <sys/proc.h>
 #include <sys/kauth.h>
 #include <sys/mutex.h>
+#include <sys/kmem.h>
+#include <sys/cpu.h>
+#include <sys/pserialize.h>
+#include <sys/psref.h>
+#include <sys/pslist.h>
+#include <sys/atomic.h>
 #include <sys/device.h>
 #include <sys/module.h>
 
@@ -116,6 +123,10 @@
 
 #include "ioconf.h"
 
+#ifdef NET_MPSAFE
+#define VLAN_MPSAFE            1
+#endif
+
 struct vlan_mc_entry {
        LIST_ENTRY(vlan_mc_entry)       mc_entries;
        /*
@@ -131,21 +142,33 @@
 
 #define        mc_enm          mc_u.mcu_enm
 
+
+struct ifvlan_linkmib {
+       struct ifvlan *ifvm_ifvlan;
+       const struct vlan_multisw *ifvm_msw;
+       int     ifvm_encaplen;  /* encapsulation length */
+       int     ifvm_mtufudge;  /* MTU fudged by this much */
+       int     ifvm_mintu;     /* min transmission unit */
+       uint16_t ifvm_proto;    /* encapsulation ethertype */
+       uint16_t ifvm_tag;      /* tag to apply on packets */
+       struct ifnet *ifvm_p;           /* parent interface of this vlan */
+
+       struct psref_target ifvm_psref;
+};
+
 struct ifvlan {
        union {
                struct ethercom ifvu_ec;
        } ifv_u;
-       struct ifnet *ifv_p;    /* parent interface of this vlan */
-       struct ifv_linkmib {
-               const struct vlan_multisw *ifvm_msw;
-               int     ifvm_encaplen;  /* encapsulation length */
-               int     ifvm_mtufudge;  /* MTU fudged by this much */
-               int     ifvm_mintu;     /* min transmission unit */
-               uint16_t ifvm_proto;    /* encapsulation ethertype */
-               uint16_t ifvm_tag;      /* tag to apply on packets */
-       } ifv_mib;
+       struct ifvlan_linkmib *ifv_mib; /*
+                                        * reader must use vlan_getref_linkmib()
+                                        * instead of direct dereference
+                                        */
+       kmutex_t ifv_lock;              /* writer lock for ifv_mib */
+
        LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
        LIST_ENTRY(ifvlan) ifv_list;
+       struct pslist_entry ifv_hash;
        int ifv_flags;
 };
 
@@ -179,15 +202,47 @@
 
 static int     vlan_clone_create(struct if_clone *, int);
 static int     vlan_clone_destroy(struct ifnet *);
-static int     vlan_config(struct ifvlan *, struct ifnet *);
+static int     vlan_config(struct ifvlan *, struct ifnet *,
+    uint16_t);
 static int     vlan_ioctl(struct ifnet *, u_long, void *);
 static void    vlan_start(struct ifnet *);
+static int     vlan_transmit(struct ifnet *, struct mbuf *);
 static void    vlan_unconfig(struct ifnet *);
+static int     vlan_unconfig_locked(struct ifvlan *,
+    struct ifvlan_linkmib *);
+static void    vlan_hash_init(void);
+static int     vlan_hash_fini(void);
+static struct ifvlan_linkmib*  vlan_getref_linkmib(struct ifvlan *,
+    struct psref *);
+static void    vlan_putref_linkmib(struct ifvlan_linkmib *,
+    struct psref *);
+static void    vlan_linkmib_update(struct ifvlan *,
+    struct ifvlan_linkmib *);
+static struct ifvlan_linkmib*  vlan_lookup_tag_psref(struct ifnet *,
+    uint16_t, struct psref *);
+static int     tag_hash_func(uint16_t, u_long);
 
-/* XXX This should be a hash table with the tag as the basis of the key. */
-static LIST_HEAD(, ifvlan) ifv_list;
+LIST_HEAD(vlan_ifvlist, ifvlan);
+static struct {
+       kmutex_t lock;
+       struct vlan_ifvlist list;
+} ifv_list __cacheline_aligned;
+
 
-static kmutex_t ifv_mtx __cacheline_aligned;
+#if !defined(VLAN_TAG_HASH_SIZE)
+#define VLAN_TAG_HASH_SIZE 32
+#endif
+static struct {
+       kmutex_t lock;
+       struct pslist_head *lists;
+       u_long mask;
+} ifv_hash __cacheline_aligned = {
+       .lists = NULL,
+       .mask = 0,
+};
+
+pserialize_t vlan_psz __read_mostly;
+static struct psref_class *ifvm_psref_class __read_mostly;
 
 struct if_clone vlan_cloner =
     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
@@ -208,10 +263,15 @@
 static void
 vlaninit(void)
 {
+       mutex_init(&ifv_list.lock, MUTEX_DEFAULT, IPL_NONE);
+       LIST_INIT(&ifv_list.list);
 
-       LIST_INIT(&ifv_list);
-       mutex_init(&ifv_mtx, MUTEX_DEFAULT, IPL_NONE);
+       mutex_init(&ifv_hash.lock, MUTEX_DEFAULT, IPL_NONE);
+       vlan_psz = pserialize_create();
+       ifvm_psref_class = psref_class_create("vlanlinkmib", IPL_SOFTNET);
        if_clone_attach(&vlan_cloner);
+
+       vlan_hash_init();
 }
 
 static int
@@ -219,15 +279,24 @@
 {
        int error = 0;
 
-       if (!LIST_EMPTY(&ifv_list))
-               error = EBUSY;
+       mutex_enter(&ifv_list.lock);
+       if (!LIST_EMPTY(&ifv_list.list)) {
+               mutex_exit(&ifv_list.lock);
+               return EBUSY;
+       }
+       mutex_exit(&ifv_list.lock);
 
-       if (error == 0) {
-               if_clone_detach(&vlan_cloner);
-               mutex_destroy(&ifv_mtx);
-       }
+       error = vlan_hash_fini();
+       if (error != 0)
+               return error;
 
-       return error;
+       if_clone_detach(&vlan_cloner);
+       psref_class_destroy(ifvm_psref_class);
+       pserialize_destroy(vlan_psz);
+       mutex_destroy(&ifv_hash.lock);
+       mutex_destroy(&ifv_list.lock);
+
+       return 0;
 }
 
 static void
@@ -252,20 +321,32 @@
 {
        struct ifvlan *ifv;
        struct ifnet *ifp;
-       int s;
+       struct ifvlan_linkmib *mib;
 
        ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK|M_ZERO);
+       mib = kmem_zalloc(sizeof(struct ifvlan_linkmib), KM_SLEEP);
        ifp = &ifv->ifv_if;
        LIST_INIT(&ifv->ifv_mc_listhead);
 
-       s = splnet();
-       LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
-       splx(s);
+       mib->ifvm_ifvlan = ifv;
+       mib->ifvm_p = NULL;
+       psref_target_init(&mib->ifvm_psref, ifvm_psref_class);
+
+       mutex_init(&ifv->ifv_lock, MUTEX_DEFAULT, IPL_NONE);
+       ifv->ifv_mib = mib;
+
+       mutex_enter(&ifv_list.lock);
+       LIST_INSERT_HEAD(&ifv_list.list, ifv, ifv_list);
+       mutex_exit(&ifv_list.lock);
 
        if_initname(ifp, ifc->ifc_name, unit);
        ifp->if_softc = ifv;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef VLAN_MPSAFE
+       ifp->if_extflags = IFEF_START_MPSAFE;
+#endif
        ifp->if_start = vlan_start;
+       ifp->if_transmit = vlan_transmit;
        ifp->if_ioctl = vlan_ioctl;
        IFQ_SET_READY(&ifp->if_snd);
 
@@ -280,47 +361,66 @@
 vlan_clone_destroy(struct ifnet *ifp)
 {
        struct ifvlan *ifv = ifp->if_softc;
-       int s;
 
-       s = splnet();
+       mutex_enter(&ifv_list.lock);
        LIST_REMOVE(ifv, ifv_list);
+       mutex_exit(&ifv_list.lock);
+
        vlan_unconfig(ifp);
        if_detach(ifp);
-       splx(s);
 
+       psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
+       kmem_free(ifv->ifv_mib, sizeof(struct ifvlan_linkmib));
+       mutex_destroy(&ifv->ifv_lock);
        free(ifv, M_DEVBUF);
 
        return (0);
 }
 
 /*
- * Configure a VLAN interface.  Must be called at splnet().
+ * Configure a VLAN interface.
  */
 static int
-vlan_config(struct ifvlan *ifv, struct ifnet *p)
+vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
 {
        struct ifnet *ifp = &ifv->ifv_if;
-       int error;
+       struct ifvlan_linkmib *nmib = NULL;
+       struct ifvlan_linkmib *omib = NULL;
+       struct psref_target *nmib_psref = NULL;
+       int error = 0;
+       int idx;
+       bool omib_cleanup = false;
+
+       nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
 
-       if (ifv->ifv_p != NULL)
-               return (EBUSY);
+       mutex_enter(&ifv->ifv_lock);
+       omib = ifv->ifv_mib;
+
+       if (omib->ifvm_p != NULL) {
+               error = EBUSY;
+               goto done;
+       }
+
+       *nmib = *omib;
+       nmib_psref = &nmib->ifvm_psref;
+
+       psref_target_init(nmib_psref, ifvm_psref_class);
 
        switch (p->if_type) {
        case IFT_ETHER:
            {
                struct ethercom *ec = (void *) p;
-
-               ifv->ifv_msw = &vlan_ether_multisw;
-               ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
-               ifv->ifv_mintu = ETHERMIN;
+               nmib->ifvm_msw = &vlan_ether_multisw;
+               nmib->ifvm_encaplen = ETHER_VLAN_ENCAP_LEN;
+               nmib->ifvm_mintu = ETHERMIN;



Home | Main Index | Thread Index | Old Index