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();

Reply via email to