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