Source-Changes-HG archive

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

[src/trunk]: src/sys Make pfil(9) MP-safe (applying psref(9))



details:   https://anonhg.NetBSD.org/src/rev/5371bcb20df1
branches:  trunk
changeset: 350680:5371bcb20df1
user:      ryo <ryo%NetBSD.org@localhost>
date:      Mon Jan 16 09:28:40 2017 +0000

description:
Make pfil(9) MP-safe (applying psref(9))

diffstat:

 sys/kern/init_main.c                    |    8 +-
 sys/net/pfil.c                          |  210 ++++++++++++++++++++++++-------
 sys/net/pfil.h                          |    3 +-
 sys/rump/net/lib/libnet/net_component.c |    6 +-
 4 files changed, 171 insertions(+), 56 deletions(-)

diffs (truncated from 478 to 300 lines):

diff -r 079b02362985 -r 5371bcb20df1 sys/kern/init_main.c
--- a/sys/kern/init_main.c      Mon Jan 16 08:26:30 2017 +0000
+++ b/sys/kern/init_main.c      Mon Jan 16 09:28:40 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: init_main.c,v 1.489 2017/01/05 03:22:20 pgoyette Exp $ */
+/*     $NetBSD: init_main.c,v 1.490 2017/01/16 09:28:40 ryo Exp $      */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.489 2017/01/05 03:22:20 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.490 2017/01/16 09:28:40 ryo Exp $");
 
 #include "opt_ddb.h"
 #include "opt_inet.h"
@@ -215,6 +215,7 @@
 
 #include <net/bpf.h>
 #include <net/if.h>
+#include <net/pfil.h>
 #include <net/raw_cb.h>
 #include <net/if_llatbl.h>
 
@@ -479,6 +480,9 @@
        kern_cprng = cprng_strong_create("kernel", IPL_VM,
                                         CPRNG_INIT_ANY|CPRNG_REKEY_ANY);
 
+       /* Initialize pfil */
+       pfil_init();
+
        /* Initialize interfaces. */
        ifinit1();
 
diff -r 079b02362985 -r 5371bcb20df1 sys/net/pfil.c
--- a/sys/net/pfil.c    Mon Jan 16 08:26:30 2017 +0000
+++ b/sys/net/pfil.c    Mon Jan 16 09:28:40 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pfil.c,v 1.31 2017/01/12 17:19:17 ryo Exp $    */
+/*     $NetBSD: pfil.c,v 1.32 2017/01/16 09:28:40 ryo Exp $    */
 
 /*
  * Copyright (c) 2013 Mindaugas Rasiukevicius <rmind at NetBSD org>
@@ -28,12 +28,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pfil.c,v 1.31 2017/01/12 17:19:17 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pfil.c,v 1.32 2017/01/16 09:28:40 ryo Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/queue.h>
 #include <sys/kmem.h>
+#include <sys/psref.h>
 
 #include <net/if.h>
 #include <net/pfil.h>
@@ -51,16 +52,22 @@
 typedef struct {
        pfil_hook_t     hooks[MAX_HOOKS];
        u_int           nhooks;
+       struct psref_target psref;
 } pfil_list_t;
 
+typedef struct {
+       pfil_list_t     *active;        /* lists[0] or lists[1] */
+       pfil_list_t     lists[2];
+} pfil_listset_t;
+
 CTASSERT(PFIL_IN == 1);
 CTASSERT(PFIL_OUT == 2);
 
 struct pfil_head {
-       pfil_list_t     ph_in;
-       pfil_list_t     ph_out;
-       pfil_list_t     ph_ifaddr;
-       pfil_list_t     ph_ifevent;
+       pfil_listset_t  ph_in;
+       pfil_listset_t  ph_out;
+       pfil_listset_t  ph_ifaddr;
+       pfil_listset_t  ph_ifevent;
        int             ph_type;
        void *          ph_key;
        LIST_ENTRY(pfil_head) ph_list;
@@ -73,6 +80,25 @@
 static LIST_HEAD(, pfil_head) pfil_head_list __read_mostly =
     LIST_HEAD_INITIALIZER(&pfil_head_list);
 
+static kmutex_t pfil_mtx __cacheline_aligned;
+static struct psref_class *pfil_psref_class __read_mostly;
+static pserialize_t pfil_psz;
+
+void
+pfil_init(void)
+{
+       mutex_init(&pfil_mtx, MUTEX_DEFAULT, IPL_NONE);
+       pfil_psz = pserialize_create();
+       pfil_psref_class = psref_class_create("pfil", IPL_SOFTNET);
+}
+
+static inline void
+pfil_listset_init(pfil_listset_t *pflistset)
+{
+       pflistset->active = &pflistset->lists[0];
+       psref_target_init(&pflistset->active->psref, pfil_psref_class);
+}
+
 /*
  * pfil_head_create: create and register a packet filter head.
  */
@@ -88,6 +114,11 @@
        ph->ph_type = type;
        ph->ph_key = key;
 
+       pfil_listset_init(&ph->ph_in);
+       pfil_listset_init(&ph->ph_out);
+       pfil_listset_init(&ph->ph_ifaddr);
+       pfil_listset_init(&ph->ph_ifevent);
+
        LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list);
        return ph;
 }
@@ -99,6 +130,12 @@
 pfil_head_destroy(pfil_head_t *pfh)
 {
        LIST_REMOVE(pfh, ph_list);
+
+       psref_target_destroy(&pfh->ph_in.active->psref, pfil_psref_class);
+       psref_target_destroy(&pfh->ph_out.active->psref, pfil_psref_class);
+       psref_target_destroy(&pfh->ph_ifaddr.active->psref, pfil_psref_class);
+       psref_target_destroy(&pfh->ph_ifevent.active->psref, pfil_psref_class);
+
        kmem_free(pfh, sizeof(pfil_head_t));
 }
 
@@ -117,7 +154,7 @@
        return ph;
 }
 
-static pfil_list_t *
+static pfil_listset_t *
 pfil_hook_get(int dir, pfil_head_t *ph)
 {
        switch (dir) {
@@ -134,24 +171,44 @@
 }
 
 static int
-pfil_list_add(pfil_list_t *phlist, pfil_polyfunc_t func, void *arg, int flags)
+pfil_list_add(pfil_listset_t *phlistset, pfil_polyfunc_t func, void *arg,
+              int flags)
 {
-       const u_int nhooks = phlist->nhooks;
+       u_int nhooks;
+       pfil_list_t *newlist, *oldlist;
        pfil_hook_t *pfh;
 
+       mutex_enter(&pfil_mtx);
+
        /* Check if we have a free slot. */
+       nhooks = phlistset->active->nhooks;
        if (nhooks == MAX_HOOKS) {
+               mutex_exit(&pfil_mtx);
                return ENOSPC;
        }
        KASSERT(nhooks < MAX_HOOKS);
 
+       if (phlistset->active == &phlistset->lists[0]) {
+               oldlist = &phlistset->lists[0];
+               newlist = &phlistset->lists[1];
+       } else{
+               oldlist = &phlistset->lists[1];
+               newlist = &phlistset->lists[0];
+       }
+
        /* Make sure the hook is not already added. */
        for (u_int i = 0; i < nhooks; i++) {
-               pfh = &phlist->hooks[i];
-               if (pfh->pfil_func == func && pfh->pfil_arg == arg)
+               pfh = &oldlist->hooks[i];
+               if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
+                       mutex_exit(&pfil_mtx);
                        return EEXIST;
+               }
        }
 
+       /* create new pfil_list_t copied from old */
+       memcpy(newlist, oldlist, sizeof(pfil_list_t));
+       psref_target_init(&newlist->psref, pfil_psref_class);
+
        /*
         * Finally, add the hook.  Note: for PFIL_IN we insert the hooks in
         * reverse order of the PFIL_OUT so that the same path is followed
@@ -160,15 +217,25 @@
        if (flags & PFIL_IN) {
                /* XXX: May want to revisit this later; */
                size_t len = sizeof(pfil_hook_t) * nhooks;
-               pfh = &phlist->hooks[0];
-               memmove(&phlist->hooks[1], pfh, len);
+               pfh = &newlist->hooks[0];
+               memmove(&newlist->hooks[1], pfh, len);
        } else {
-               pfh = &phlist->hooks[nhooks];
+               pfh = &newlist->hooks[nhooks];
        }
-       phlist->nhooks++;
+       newlist->nhooks++;
 
        pfh->pfil_func = func;
        pfh->pfil_arg  = arg;
+
+       /* switch from oldlist to newlist */
+       phlistset->active = newlist;
+       membar_producer();
+       pserialize_perform(pfil_psz);
+       mutex_exit(&pfil_mtx);
+
+       /* Wait for all readers */
+       psref_target_destroy(&oldlist->psref, pfil_psref_class);
+
        return 0;
 }
 
@@ -190,18 +257,18 @@
 
        for (u_int i = 0; i < __arraycount(pfil_flag_cases); i++) {
                const int fcase = pfil_flag_cases[i];
-               pfil_list_t *phlist;
+               pfil_listset_t *phlistset;
 
                if ((flags & fcase) == 0) {
                        continue;
                }
-               phlist = pfil_hook_get(fcase, ph);
-               error = pfil_list_add(phlist, (pfil_polyfunc_t)func, arg, flags);
-               if (error) {
+               phlistset = pfil_hook_get(fcase, ph);
+               error = pfil_list_add(phlistset, (pfil_polyfunc_t)func, arg,
+                   flags);
+               if (error && (error != EEXIST))
                        break;
-               }
        }
-       if (error) {
+       if (error && (error != EEXIST)) {
                pfil_remove_hook(func, arg, flags, ph);
        }
        return error;
@@ -217,35 +284,61 @@
 int
 pfil_add_ihook(pfil_ifunc_t func, void *arg, int flags, pfil_head_t *ph)
 {
-       pfil_list_t *phlist;
+       pfil_listset_t *phlistset;
 
        KASSERT(func != NULL);
        KASSERT(flags == PFIL_IFADDR || flags == PFIL_IFNET);
 
-       phlist = pfil_hook_get(flags, ph);
-       return pfil_list_add(phlist, (pfil_polyfunc_t)func, arg, flags);
+       phlistset = pfil_hook_get(flags, ph);
+       return pfil_list_add(phlistset, (pfil_polyfunc_t)func, arg, flags);
 }
 
 /*
  * pfil_list_remove: remove the hook from a specified list.
  */
 static int
-pfil_list_remove(pfil_list_t *phlist, pfil_polyfunc_t func, void *arg)
+pfil_list_remove(pfil_listset_t *phlistset, pfil_polyfunc_t func, void *arg)
 {
-       const u_int nhooks = phlist->nhooks;
+       u_int nhooks;
+       pfil_list_t *oldlist, *newlist;
+
+       mutex_enter(&pfil_mtx);
 
+       /* create new pfil_list_t copied from old */
+       if (phlistset->active == &phlistset->lists[0]) {
+               oldlist = &phlistset->lists[0];
+               newlist = &phlistset->lists[1];
+       } else{
+               oldlist = &phlistset->lists[1];
+               newlist = &phlistset->lists[0];
+       }
+       memcpy(newlist, oldlist, sizeof(*newlist));
+       psref_target_init(&newlist->psref, pfil_psref_class);
+
+       nhooks = newlist->nhooks;
        for (u_int i = 0; i < nhooks; i++) {
-               pfil_hook_t *last, *pfh = &phlist->hooks[i];
+               pfil_hook_t *last, *pfh = &newlist->hooks[i];
 
                if (pfh->pfil_func != func || pfh->pfil_arg != arg) {
                        continue;
                }
-               if ((last = &phlist->hooks[nhooks - 1]) != pfh) {



Home | Main Index | Thread Index | Old Index