Module Name: src
Committed By: ryo
Date: Mon Jan 16 09:28:41 UTC 2017
Modified Files:
src/sys/kern: init_main.c
src/sys/net: pfil.c pfil.h
src/sys/rump/net/lib/libnet: net_component.c
Log Message:
Make pfil(9) MP-safe (applying psref(9))
To generate a diff of this commit:
cvs rdiff -u -r1.489 -r1.490 src/sys/kern/init_main.c
cvs rdiff -u -r1.31 -r1.32 src/sys/net/pfil.c
cvs rdiff -u -r1.32 -r1.33 src/sys/net/pfil.h
cvs rdiff -u -r1.6 -r1.7 src/sys/rump/net/lib/libnet/net_component.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.489 src/sys/kern/init_main.c:1.490
--- src/sys/kern/init_main.c:1.489 Thu Jan 5 03:22:20 2017
+++ src/sys/kern/init_main.c Mon Jan 16 09:28:40 2017
@@ -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 @@ extern void *_binary_splash_image_end;
#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 @@ main(void)
kern_cprng = cprng_strong_create("kernel", IPL_VM,
CPRNG_INIT_ANY|CPRNG_REKEY_ANY);
+ /* Initialize pfil */
+ pfil_init();
+
/* Initialize interfaces. */
ifinit1();
Index: src/sys/net/pfil.c
diff -u src/sys/net/pfil.c:1.31 src/sys/net/pfil.c:1.32
--- src/sys/net/pfil.c:1.31 Thu Jan 12 17:19:17 2017
+++ src/sys/net/pfil.c Mon Jan 16 09:28:40 2017
@@ -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 {
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 const int pfil_flag_cases[] = {
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 @@ pfil_head_create(int type, void *key)
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 @@ void
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 @@ pfil_head_get(int type, void *key)
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 @@ pfil_hook_get(int dir, pfil_head_t *ph)
}
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 @@ pfil_list_add(pfil_list_t *phlist, pfil_
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 @@ pfil_add_hook(pfil_func_t func, void *ar
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 @@ pfil_add_hook(pfil_func_t func, void *ar
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) {
+ if ((last = &newlist->hooks[nhooks - 1]) != pfh) {
memcpy(pfh, last, sizeof(pfil_hook_t));
}
- phlist->nhooks--;
+ newlist->nhooks--;
+
+ /* 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;
}
+ mutex_exit(&pfil_mtx);
return ENOENT;
}
@@ -259,13 +352,13 @@ pfil_remove_hook(pfil_func_t func, void
for (u_int i = 0; i < __arraycount(pfil_flag_cases); i++) {
const int fcase = pfil_flag_cases[i];
- pfil_list_t *pflist;
+ pfil_listset_t *pflistset;
if ((flags & fcase) == 0) {
continue;
}
- pflist = pfil_hook_get(fcase, ph);
- (void)pfil_list_remove(pflist, (pfil_polyfunc_t)func, arg);
+ pflistset = pfil_hook_get(fcase, ph);
+ (void)pfil_list_remove(pflistset, (pfil_polyfunc_t)func, arg);
}
return 0;
}
@@ -273,11 +366,11 @@ pfil_remove_hook(pfil_func_t func, void
int
pfil_remove_ihook(pfil_ifunc_t func, void *arg, int flags, pfil_head_t *ph)
{
- pfil_list_t *pflist;
+ pfil_listset_t *pflistset;
KASSERT(flags == PFIL_IFADDR || flags == PFIL_IFNET);
- pflist = pfil_hook_get(flags, ph);
- (void)pfil_list_remove(pflist, (pfil_polyfunc_t)func, arg);
+ pflistset = pfil_hook_get(flags, ph);
+ (void)pfil_list_remove(pflistset, (pfil_polyfunc_t)func, arg);
return 0;
}
@@ -288,14 +381,22 @@ int
pfil_run_hooks(pfil_head_t *ph, struct mbuf **mp, ifnet_t *ifp, int dir)
{
struct mbuf *m = mp ? *mp : NULL;
+ pfil_listset_t *phlistset;
pfil_list_t *phlist;
+ struct psref psref;
+ int s;
int ret = 0;
KASSERT(dir == PFIL_IN || dir == PFIL_OUT);
- if (__predict_false((phlist = pfil_hook_get(dir, ph)) == NULL)) {
+ if (__predict_false((phlistset = pfil_hook_get(dir, ph)) == NULL)) {
return ret;
}
+ s = pserialize_read_enter();
+ phlist = phlistset->active;
+ membar_datadep_consumer();
+ psref_acquire(&psref, &phlist->psref, pfil_psref_class);
+ pserialize_read_exit(s);
for (u_int i = 0; i < phlist->nhooks; i++) {
pfil_hook_t *pfh = &phlist->hooks[i];
pfil_func_t func = (pfil_func_t)pfh->pfil_func;
@@ -304,6 +405,7 @@ pfil_run_hooks(pfil_head_t *ph, struct m
if (m == NULL || ret)
break;
}
+ psref_release(&psref, &phlist->psref, pfil_psref_class);
if (mp) {
*mp = m;
@@ -311,26 +413,34 @@ pfil_run_hooks(pfil_head_t *ph, struct m
return ret;
}
-void
-pfil_run_addrhooks(pfil_head_t *ph, u_long cmd, struct ifaddr *ifa)
+static void
+pfil_run_arg(pfil_listset_t *phlistset, u_long cmd, void *arg)
{
- pfil_list_t *phlist = &ph->ph_ifaddr;
+ pfil_list_t *phlist;
+ struct psref psref;
+ int s;
+ s = pserialize_read_enter();
+ phlist = phlistset->active;
+ membar_datadep_consumer();
+ psref_acquire(&psref, &phlist->psref, pfil_psref_class);
+ pserialize_read_exit(s);
for (u_int i = 0; i < phlist->nhooks; i++) {
pfil_hook_t *pfh = &phlist->hooks[i];
pfil_ifunc_t func = (pfil_ifunc_t)pfh->pfil_func;
- (*func)(pfh->pfil_arg, cmd, (void *)ifa);
+ (*func)(pfh->pfil_arg, cmd, arg);
}
+ psref_release(&psref, &phlist->psref, pfil_psref_class);
}
void
-pfil_run_ifhooks(pfil_head_t *ph, u_long cmd, struct ifnet *ifp)
+pfil_run_addrhooks(pfil_head_t *ph, u_long cmd, struct ifaddr *ifa)
{
- pfil_list_t *phlist = &ph->ph_ifevent;
+ pfil_run_arg(&ph->ph_ifaddr, cmd, ifa);
+}
- for (u_int i = 0; i < phlist->nhooks; i++) {
- pfil_hook_t *pfh = &phlist->hooks[i];
- pfil_ifunc_t func = (pfil_ifunc_t)pfh->pfil_func;
- (*func)(pfh->pfil_arg, cmd, (void *)ifp);
- }
+void
+pfil_run_ifhooks(pfil_head_t *ph, u_long cmd, struct ifnet *ifp)
+{
+ pfil_run_arg(&ph->ph_ifevent, cmd, ifp);
}
Index: src/sys/net/pfil.h
diff -u src/sys/net/pfil.h:1.32 src/sys/net/pfil.h:1.33
--- src/sys/net/pfil.h:1.32 Mon Dec 26 23:21:49 2016
+++ src/sys/net/pfil.h Mon Jan 16 09:28:40 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: pfil.h,v 1.32 2016/12/26 23:21:49 christos Exp $ */
+/* $NetBSD: pfil.h,v 1.33 2017/01/16 09:28:40 ryo Exp $ */
/*
* Copyright (c) 1996 Matthew R. Green
@@ -59,6 +59,7 @@ typedef struct pfil_head pfil_head_t;
#ifdef _KERNEL
+void pfil_init(void);
int pfil_run_hooks(pfil_head_t *, struct mbuf **, struct ifnet *, int);
void pfil_run_addrhooks(pfil_head_t *, unsigned long, struct ifaddr *);
void pfil_run_ifhooks(pfil_head_t *, unsigned long, struct ifnet *);
Index: src/sys/rump/net/lib/libnet/net_component.c
diff -u src/sys/rump/net/lib/libnet/net_component.c:1.6 src/sys/rump/net/lib/libnet/net_component.c:1.7
--- src/sys/rump/net/lib/libnet/net_component.c:1.6 Wed Aug 10 10:09:42 2016
+++ src/sys/rump/net/lib/libnet/net_component.c Mon Jan 16 09:28:40 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: net_component.c,v 1.6 2016/08/10 10:09:42 kre Exp $ */
+/* $NetBSD: net_component.c,v 1.7 2017/01/16 09:28:40 ryo Exp $ */
/*
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: net_component.c,v 1.6 2016/08/10 10:09:42 kre Exp $");
+__KERNEL_RCSID(0, "$NetBSD: net_component.c,v 1.7 2017/01/16 09:28:40 ryo Exp $");
#include <sys/param.h>
#include <sys/domain.h>
@@ -42,7 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: net_componen
RUMP_COMPONENT(RUMP_COMPONENT_NET)
{
-
+ pfil_init();
ifinit1();
ifinit();
lltableinit();