- NPF connection tracking: rework synchronisation on tracking disable/enable trunk
authorrmind <rmind@NetBSD.org>
Sun, 02 Jun 2013 02:20:04 +0000
branchtrunk
changeset 218871 b7d4d5622a14
parent 218870 bf2350ca6539
child 218872 94b6039fec37
- NPF connection tracking: rework synchronisation on tracking disable/enable points and document it. Split the worker thread into a separate module with an interface, so it could be re-used for other tasks. - Replace ALG list with arrays and thus hit fewer cache lines. - Misc bug fixes.
sys/modules/npf/Makefile
sys/net/npf/files.npf
sys/net/npf/npf.c
sys/net/npf/npf_alg.c
sys/net/npf/npf_alg_icmp.c
sys/net/npf/npf_ctl.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_inet.c
sys/net/npf/npf_nat.c
sys/net/npf/npf_session.c
sys/net/npf/npf_worker.c
sys/rump/net/lib/libnpf/Makefile
--- a/sys/modules/npf/Makefile	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/modules/npf/Makefile	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.12 2013/02/09 03:35:33 rmind Exp $
+# $NetBSD: Makefile,v 1.13 2013/06/02 02:20:05 rmind Exp $
 
 .include "../Makefile.inc"
 
@@ -10,7 +10,7 @@
 SRCS+=		npf_inet.c npf_instr.c npf_mbuf.c npf_nat.c
 SRCS+=		npf_processor.c npf_ruleset.c npf_rproc.c npf_sendpkt.c
 SRCS+=		npf_session.c npf_state.c npf_state_tcp.c
-SRCS+=		npf_tableset.c npf_tableset_ptree.c
+SRCS+=		npf_tableset.c npf_tableset_ptree.c npf_worker.c
 
 CPPFLAGS+=	-DINET6
 
--- a/sys/net/npf/files.npf	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/files.npf	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.npf,v 1.12 2013/03/12 20:47:48 christos Exp $
+# $NetBSD: files.npf,v 1.13 2013/06/02 02:20:04 rmind Exp $
 #
 # Public Domain.
 #
@@ -28,6 +28,7 @@
 file	net/npf/npf_nat.c			npf
 file	net/npf/npf_alg.c			npf
 file	net/npf/npf_sendpkt.c			npf
+file	net/npf/npf_worker.c			npf
 
 # Built-in extensions.
 file	net/npf/npf_ext_log.c			npf
--- a/sys/net/npf/npf.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.15 2013/02/09 03:35:31 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.16 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.15 2013/02/09 03:35:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.16 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -88,6 +88,7 @@
 	npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE);
 	npf_sysctl = NULL;
 
+	npf_worker_sysinit();
 	npf_tableset_sysinit();
 	npf_session_sysinit();
 	npf_nat_sysinit();
@@ -129,6 +130,9 @@
 	npf_session_sysfini();
 	npf_tableset_sysfini();
 
+	/* Note: worker is the last. */
+	npf_worker_sysfini();
+
 	if (npf_sysctl) {
 		sysctl_teardown(&npf_sysctl);
 	}
--- a/sys/net/npf/npf_alg.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_alg.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_alg.c,v 1.8 2013/03/20 00:29:47 christos Exp $	*/
+/*	$NetBSD: npf_alg.c,v 1.9 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -30,11 +30,11 @@
  */
 
 /*
- * NPF interface for application level gateways (ALGs).
+ * NPF interface for the Application Level Gateways (ALGs).
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.8 2013/03/20 00:29:47 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.9 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -47,67 +47,63 @@
 
 #include "npf_impl.h"
 
-/* NAT ALG structure for registration. */
+/*
+ * NAT ALG description structure.  For more compact use of cache,
+ * the functions are separated in their own arrays.  The number of
+ * ALGs is expected to be very small.
+ */
+
 struct npf_alg {
-	LIST_ENTRY(npf_alg)	na_entry;
-	const char *		na_name;
-	npf_alg_t *		na_bptr;
-	npf_alg_func_t		na_match_func;
-	npf_alg_func_t		na_tr_func;
-	npf_alg_sfunc_t		na_se_func;
+	const char *	na_name;
+	u_int		na_slot;
 };
 
-static LIST_HEAD(, npf_alg)	nat_alg_list	__cacheline_aligned;
-static kmutex_t			nat_alg_lock	__cacheline_aligned;
-static pserialize_t		nat_alg_psz	__cacheline_aligned;
+#define	NPF_MAX_ALGS	8
+
+/* List of ALGs and the count. */
+static pserialize_t	alg_psz			__cacheline_aligned;
+static npf_alg_t	alg_list[NPF_MAX_ALGS]	__read_mostly;
+static u_int		alg_count		__read_mostly;
+
+/* Session, matching and translation functions. */
+static npf_alg_sfunc_t	alg_sfunc[NPF_MAX_ALGS]	__read_mostly;
+static npf_alg_func_t	alg_mfunc[NPF_MAX_ALGS]	__read_mostly;
+static npf_alg_func_t	alg_tfunc[NPF_MAX_ALGS]	__read_mostly;
+
+static const char	alg_prefix[] = "npf_alg_";
+#define	NPF_EXT_PREFLEN	(sizeof(alg_prefix) - 1)
 
 void
 npf_alg_sysinit(void)
 {
+	alg_psz = pserialize_create();
+	memset(&alg_list, 0, sizeof(alg_list));
+	alg_count = 0;
 
-	mutex_init(&nat_alg_lock, MUTEX_DEFAULT, IPL_NONE);
-	nat_alg_psz = pserialize_create();
-	LIST_INIT(&nat_alg_list);
+	memset(&alg_mfunc, 0, sizeof(alg_mfunc));
+	memset(&alg_tfunc, 0, sizeof(alg_tfunc));
+	memset(&alg_sfunc, 0, sizeof(alg_sfunc));
 }
 
 void
 npf_alg_sysfini(void)
 {
-
-	KASSERT(LIST_EMPTY(&nat_alg_list));
-	pserialize_destroy(nat_alg_psz);
-	mutex_destroy(&nat_alg_lock);
+	pserialize_destroy(alg_psz);
 }
 
-static const char npf_alg_prefix[] = "npf_alg_";
-#define NPF_EXT_PREFLEN (sizeof(npf_alg_prefix) - 1)
-
 static npf_alg_t *
-npf_alg_lookup(const char *name, bool autoload)
+npf_alg_lookup(const char *name)
 {
-	npf_alg_t *alg;
-	char modname[64 + NPF_EXT_PREFLEN];
-	int error;
-
-	KASSERT(mutex_owned(&nat_alg_lock));
-
-again:
-	LIST_FOREACH(alg, &nat_alg_list, na_entry)
-		if (strcmp(alg->na_name, name) == 0)
-			break;
+	KASSERT(npf_config_locked_p());
 
-	if (alg != NULL || !autoload)
-		return alg;
+	for (u_int i = 0; i < alg_count; i++) {
+		npf_alg_t *alg = &alg_list[i];
+		const char *aname = alg->na_name;
 
-	mutex_exit(&nat_alg_lock);
-	autoload = false;
-	snprintf(modname, sizeof(modname), "%s%s", npf_alg_prefix, name);
-	error = module_autoload(modname, MODULE_CLASS_MISC);
-	mutex_enter(&nat_alg_lock);
-
-	if (error)
-		return NULL;
-	goto again;
+		if (aname && strcmp(aname, name) == 0)
+			return alg;
+	}
+	return NULL;
 }
 
 npf_alg_t *
@@ -115,9 +111,19 @@
 {
 	npf_alg_t *alg;
 
-	mutex_enter(&nat_alg_lock);
-	alg = npf_alg_lookup(name, true);
-	mutex_exit(&nat_alg_lock);
+	npf_config_enter();
+	if ((alg = npf_alg_lookup(name)) == NULL) {
+		char modname[NPF_EXT_PREFLEN + 64];
+		snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name);
+		npf_config_exit();
+
+		if (module_autoload(modname, MODULE_CLASS_MISC) != 0) {
+			return NULL;
+		}
+		npf_config_enter();
+		alg = npf_alg_lookup(name);
+	}
+	npf_config_exit();
 	return alg;
 }
 
@@ -129,23 +135,37 @@
     npf_alg_sfunc_t sfunc)
 {
 	npf_alg_t *alg;
+	u_int i;
 
-	alg = kmem_zalloc(sizeof(npf_alg_t), KM_SLEEP);
-	alg->na_name = name;
-	alg->na_bptr = alg;
-	alg->na_match_func = mfunc;
-	alg->na_tr_func = tfunc;
-	alg->na_se_func = sfunc;
-
-	mutex_enter(&nat_alg_lock);
-	if (npf_alg_lookup(name, false) != NULL) {
-		mutex_exit(&nat_alg_lock);
-		kmem_free(alg, sizeof(npf_alg_t));
+	npf_config_enter();
+	if (npf_alg_lookup(name) != NULL) {
+		npf_config_exit();
 		return NULL;
 	}
-	LIST_INSERT_HEAD(&nat_alg_list, alg, na_entry);
-	mutex_exit(&nat_alg_lock);
 
+	/* Find a spare slot. */
+	for (i = 0; i < NPF_MAX_ALGS; i++) {
+		alg = &alg_list[i];
+		if (alg->na_name == NULL) {
+			break;
+		}
+	}
+	if (i == NPF_MAX_ALGS) {
+		npf_config_exit();
+		return NULL;
+	}
+
+	/* Register the ALG. */
+	alg->na_name = name;
+	alg->na_slot = i;
+
+	/* Assign the functions. */
+	alg_mfunc[i] = mfunc;
+	alg_tfunc[i] = tfunc;
+	alg_sfunc[i] = sfunc;
+
+	alg_count = MAX(alg_count, i + 1);
+	npf_config_exit();
 	return alg;
 }
 
@@ -155,16 +175,20 @@
 int
 npf_alg_unregister(npf_alg_t *alg)
 {
-	mutex_enter(&nat_alg_lock);
-	LIST_REMOVE(alg, na_entry);
-	pserialize_perform(nat_alg_psz);
-	mutex_exit(&nat_alg_lock);
+	u_int i = alg->na_slot;
 
+	/* Deactivate the functions first. */
 	npf_config_enter();
+	alg_mfunc[i] = NULL;
+	alg_tfunc[i] = NULL;
+	alg_sfunc[i] = NULL;
+	pserialize_perform(alg_psz);
+
+	/* Finally, unregister the ALG. */
 	npf_ruleset_freealg(npf_config_natset(), alg);
+	alg->na_name = NULL;
 	npf_config_exit();
 
-	kmem_free(alg, sizeof(npf_alg_t));
 	return 0;
 }
 
@@ -174,13 +198,12 @@
 bool
 npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
 {
-	npf_alg_t *alg;
 	bool match = false;
 	int s;
 
 	s = pserialize_read_enter();
-	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
-		npf_alg_func_t func = alg->na_match_func;
+	for (u_int i = 0; i < alg_count; i++) {
+		npf_alg_func_t func = alg_mfunc[i];
 
 		if (func && func(npc, nbuf, nt, di)) {
 			match = true;
@@ -197,15 +220,14 @@
 void
 npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, int di)
 {
-	npf_alg_t *alg;
 	int s;
 
 	s = pserialize_read_enter();
-	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
+	for (u_int i = 0; i < alg_count; i++) {
 		npf_alg_func_t func;
 
-		if ((func = alg->na_tr_func) != NULL) {
-			(func)(npc, nbuf, nt, di);
+		if ((func = alg_tfunc[i]) != NULL) {
+			func(npc, nbuf, nt, di);
 		}
 	}
 	pserialize_read_exit(s);
@@ -215,12 +237,11 @@
 npf_alg_session(npf_cache_t *npc, nbuf_t *nbuf, int di)
 {
 	npf_session_t *se = NULL;
-	npf_alg_t *alg;
 	int s;
 
 	s = pserialize_read_enter();
-	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
-		npf_alg_sfunc_t func = alg->na_se_func;
+	for (u_int i = 0; i < alg_count; i++) {
+		npf_alg_sfunc_t func = alg_sfunc[i];
 
 		if (func && (se = func(npc, nbuf, di)) != NULL) {
 			break;
--- a/sys/net/npf/npf_alg_icmp.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_alg_icmp.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg_icmp.c,v 1.16 2013/03/20 00:29:47 christos Exp $	*/
+/*	$NetBSD: npf_alg_icmp.c,v 1.17 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -34,11 +34,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.16 2013/03/20 00:29:47 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.17 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/module.h>
-#include <sys/pool.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
@@ -78,17 +77,14 @@
 static int
 npf_alg_icmp_init(void)
 {
-
 	alg_icmp = npf_alg_register("icmp", npfa_icmp_match,
 	    npfa_icmp_nat, npfa_icmp_session);
-	KASSERT(alg_icmp != NULL);
-	return 0;
+	return alg_icmp ? 0 : ENOMEM;
 }
 
 static int
 npf_alg_icmp_fini(void)
 {
-
 	KASSERT(alg_icmp != NULL);
 	return npf_alg_unregister(alg_icmp);
 }
@@ -96,7 +92,6 @@
 static int
 npf_alg_icmp_modcmd(modcmd_t cmd, void *arg)
 {
-
 	switch (cmd) {
 	case MODULE_CMD_INIT:
 		return npf_alg_icmp_init();
--- a/sys/net/npf/npf_ctl.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_ctl.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ctl.c,v 1.25 2013/05/19 20:45:34 rmind Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.26 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.25 2013/05/19 20:45:34 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.26 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -743,36 +743,36 @@
 
 	/* Create a session hash table. */
 	sehasht = sess_htable_create();
-	if (sehasht == NULL) {
-		prop_object_release(selist);
-		return ENOMEM;
-	}
 
 	/*
 	 * Iterate through and construct each session.  Note: acquire the
 	 * config lock as we access NAT policies during the restore.
 	 */
 	error = 0;
+	it = prop_array_iterator(selist);
+
 	npf_config_enter();
-	it = prop_array_iterator(selist);
 	while ((sedict = prop_object_iterator_next(it)) != NULL) {
 		/* Session - dictionary. */
 		if (prop_object_type(sedict) != PROP_TYPE_DICTIONARY) {
 			error = EINVAL;
-			goto fail;
+			break;
 		}
 		/* Construct and insert real session structure. */
 		error = npf_session_restore(sehasht, sedict);
 		if (error) {
-			goto fail;
+			break;
 		}
 	}
-	sess_htable_reload(sehasht);
-fail:
 	npf_config_exit();
+
 	prop_object_iterator_release(it);
 	prop_object_release(selist);
-	if (error) {
+
+	if (!error) {
+		/* Finally, load the new table. */
+		npf_session_load(sehasht);
+	} else {
 		/* Destroy session table. */
 		sess_htable_destroy(sehasht);
 	}
--- a/sys/net/npf/npf_impl.h	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_impl.h	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.30 2013/05/19 20:45:34 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.31 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -96,6 +96,7 @@
 
 typedef bool (*npf_alg_func_t)(npf_cache_t *, nbuf_t *, npf_nat_t *, int);
 typedef npf_session_t *(*npf_alg_sfunc_t)(npf_cache_t *, nbuf_t *, int);
+typedef void (*npf_workfunc_t)(void);
 
 #define	NPF_NCODE_LIMIT		1024
 #define	NPF_TABLE_SLOTS		32
@@ -143,6 +144,12 @@
 prop_dictionary_t npf_config_dict(void);
 bool		npf_default_pass(void);
 
+int		npf_worker_sysinit(void);
+void		npf_worker_sysfini(void);
+void		npf_worker_signal(void);
+void		npf_worker_register(npf_workfunc_t);
+void		npf_worker_unregister(npf_workfunc_t);
+
 void		npflogattach(int);
 void		npflogdetach(void);
 int		npfctl_switch(void *);
@@ -272,11 +279,10 @@
 /* Session handling interface. */
 void		npf_session_sysinit(void);
 void		npf_session_sysfini(void);
-int		npf_session_tracking(bool);
+void		npf_session_tracking(bool);
 
 npf_sehash_t *	sess_htable_create(void);
 void		sess_htable_destroy(npf_sehash_t *);
-void		sess_htable_reload(npf_sehash_t *);
 
 npf_session_t *	npf_session_lookup(const npf_cache_t *, const nbuf_t *,
 		    const int, bool *);
@@ -289,6 +295,7 @@
 int		npf_session_setnat(npf_session_t *, npf_nat_t *, const int);
 npf_nat_t *	npf_session_retnat(npf_session_t *, const int, bool *);
 
+void		npf_session_load(npf_sehash_t *);
 int		npf_session_save(prop_array_t, prop_array_t);
 int		npf_session_restore(npf_sehash_t *, prop_dictionary_t);
 
--- a/sys/net/npf/npf_inet.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_inet.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_inet.c,v 1.21 2013/02/09 03:35:32 rmind Exp $	*/
+/*	$NetBSD: npf_inet.c,v 1.22 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 /*
- * Various procotol related helper routines.
+ * Various protocol related helper routines.
  *
  * This layer manipulates npf_cache_t structure i.e. caches requested headers
  * and stores which information was cached in the information bit field.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.21 2013/02/09 03:35:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.22 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
--- a/sys/net/npf/npf_nat.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_nat.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat.c,v 1.19 2013/02/09 03:35:32 rmind Exp $	*/
+/*	$NetBSD: npf_nat.c,v 1.20 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.19 2013/02/09 03:35:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.20 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -260,7 +260,8 @@
 	}
 	mutex_exit(&np->n_lock);
 
-	/* All references should be going away. */
+	/* Kick the worker - all references should be going away. */
+	npf_worker_signal();
 	while (np->n_refcnt) {
 		kpause("npfgcnat", false, 1, NULL);
 	}
@@ -827,7 +828,10 @@
 		return NULL;
 	}
 
-	/* Match if there is an existing NAT policy. */
+	/*
+	 * Match if there is an existing NAT policy.  Will acquire the
+	 * reference on it if further operations are successful.
+	 */
 	KASSERT(npf_config_locked_p());
 	rl = npf_ruleset_matchnat(npf_config_natset(), __UNCONST(onp));
 	if (rl == NULL) {
@@ -840,6 +844,7 @@
 	if (!npf_nat_takeport(np, ntraw->nt_tport)) {
 		return NULL;
 	}
+	atomic_inc_uint(&np->n_refcnt);
 
 	/* Create and return NAT entry for association. */
 	nt = pool_cache_get(nat_cache, PR_WAITOK);
--- a/sys/net/npf/npf_session.c	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/net/npf/npf_session.c	Sun Jun 02 02:20:04 2013 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_session.c,v 1.23 2013/03/18 00:17:20 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.24 2013/06/02 02:20:04 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -65,22 +65,34 @@
  *	and should be released by the caller.  Reference guarantees that the
  *	session will not be destroyed, although it may be expired.
  *
- * Querying ALGs
+ * Synchronisation
  *
- *	Application-level gateways (ALGs) can inspect the packet and
- *	determine whether the packet matches an ALG case.  An ALG may
- *	also lookup a session using different identifiers and return.
- *	the packet cache (npf_cache_t) representing the IDs.
+ *	Session hash table is accessed in a lock-less manner by the main
+ *	operations: npf_session_inspect() and npf_session_establish().
+ *	Since they are always called from a software interrupt, the hash
+ *	table is protected using passive serialisation.  The main place
+ *	which can destroy the hash table is npf_session_reload().  It has
+ *	to synchronise with other readers and writers using sess_lock,
+ *	primarily the G/C thread.
+ *
+ * ALG support
+ *
+ *	Application-level gateways (ALGs) can override generic session
+ *	inspection (npf_alg_session() in npf_session_inspect() function)
+ *	by performing their own lookup using different identifiers.
+ *	Recursive call to npf_session_inspect() is not allowed, they
+ *	ought to use npf_session_lookup() for this purpose.
  *
  * Lock order
  *
- *	[ sess_lock -> ]
- *		npf_sehash_t::sh_lock ->
- *			npf_state_t::nst_lock
+ *	sess_lock ->
+ *		[ npf_config_lock -> ]
+ *			npf_sehash_t::sh_lock ->
+ *				npf_state_t::nst_lock
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.23 2013/03/18 00:17:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.24 2013/06/02 02:20:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -180,60 +192,53 @@
  * Session tracking state: disabled (off), enabled (on) or flush request.
  */
 enum { SESS_TRACKING_OFF, SESS_TRACKING_ON, SESS_TRACKING_FLUSH };
-static int			sess_tracking	__cacheline_aligned;
+static volatile int		sess_tracking	__cacheline_aligned;
 
-/* Session hash table, lock and session cache. */
+/* Session hash table, session cache and the lock. */
 static npf_sehash_t *		sess_hashtbl	__read_mostly;
 static pool_cache_t		sess_cache	__read_mostly;
-
-static kmutex_t			sess_lock;
-static kcondvar_t		sess_cv;
-static lwp_t *			sess_gc_lwp;
+static kmutex_t			sess_lock	__cacheline_aligned;
+static kcondvar_t		sess_cv		__cacheline_aligned;
+static struct npf_sesslist	sess_gc_list	__cacheline_aligned;
 
-#define	SESS_GC_INTERVAL	5		/* 5 sec */
-
-static void	sess_tracking_stop(void);
+static void	npf_session_worker(void);
 static void	npf_session_destroy(npf_session_t *);
-static void	npf_session_worker(void *) __dead;
 
 /*
  * npf_session_sys{init,fini}: initialise/destroy session handling structures.
  *
- * Session table and G/C thread are initialised when session tracking gets
- * actually enabled via npf_session_tracking() interface.
+ * Session table is initialised when session tracking gets enabled via
+ * npf_session_tracking() interface.
  */
 
 void
 npf_session_sysinit(void)
 {
-
 	sess_cache = pool_cache_init(sizeof(npf_session_t), coherency_unit,
 	    0, 0, "npfsespl", NULL, IPL_NET, NULL, NULL, NULL);
 	mutex_init(&sess_lock, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&sess_cv, "npfgccv");
+	cv_init(&sess_cv, "npfsecv");
+	sess_tracking = SESS_TRACKING_OFF;
+	LIST_INIT(&sess_gc_list);
 	sess_hashtbl = NULL;
-	sess_gc_lwp = NULL;
 
-	sess_tracking = SESS_TRACKING_OFF;
+	npf_worker_register(npf_session_worker);
 }
 
 void
 npf_session_sysfini(void)
 {
-
 	/* Disable tracking, flush all sessions. */
 	npf_session_tracking(false);
-	KASSERT(sess_tracking == SESS_TRACKING_OFF);
-	KASSERT(sess_gc_lwp == NULL);
+	npf_worker_unregister(npf_session_worker);
 
-	/* Sessions might have been restored while the tracking is off. */
-	if (sess_hashtbl) {
-		sess_htable_destroy(sess_hashtbl);
-	}
+	KASSERT(sess_tracking == SESS_TRACKING_OFF);
+	KASSERT(LIST_EMPTY(&sess_gc_list));
+	KASSERT(sess_hashtbl == NULL);
 
 	pool_cache_destroy(sess_cache);
+	mutex_destroy(&sess_lock);
 	cv_destroy(&sess_cv);
-	mutex_destroy(&sess_lock);
 }
 
 /*
@@ -314,142 +319,96 @@
 npf_sehash_t *
 sess_htable_create(void)
 {
-	npf_sehash_t *stbl, *sh;
-	u_int i;
+	npf_sehash_t *tbl;
 
-	stbl = kmem_zalloc(SESS_HASH_BUCKETS * sizeof(*sh), KM_SLEEP);
-	if (stbl == NULL) {
-		return NULL;
-	}
-	for (i = 0; i < SESS_HASH_BUCKETS; i++) {
-		sh = &stbl[i];
+	tbl = kmem_zalloc(SESS_HASH_BUCKETS * sizeof(npf_sehash_t), KM_SLEEP);
+	for (u_int i = 0; i < SESS_HASH_BUCKETS; i++) {
+		npf_sehash_t *sh = &tbl[i];
+
 		LIST_INIT(&sh->sh_list);
 		rb_tree_init(&sh->sh_tree, &sess_rbtree_ops);
 		rw_init(&sh->sh_lock);
 		sh->sh_count = 0;
 	}
-	return stbl;
+	return tbl;
 }
 
 void
-sess_htable_destroy(npf_sehash_t *stbl)
+sess_htable_destroy(npf_sehash_t *tbl)
 {
-	npf_sehash_t *sh;
-	u_int i;
+	for (u_int i = 0; i < SESS_HASH_BUCKETS; i++) {
+		npf_sehash_t *sh = &tbl[i];
 
-	for (i = 0; i < SESS_HASH_BUCKETS; i++) {
-		sh = &stbl[i];
 		KASSERT(sh->sh_count == 0);
 		KASSERT(LIST_EMPTY(&sh->sh_list));
 		KASSERT(!rb_tree_iterate(&sh->sh_tree, NULL, RB_DIR_LEFT));
 		rw_destroy(&sh->sh_lock);
 	}
-	kmem_free(stbl, SESS_HASH_BUCKETS * sizeof(*sh));
+	kmem_free(tbl, SESS_HASH_BUCKETS * sizeof(npf_sehash_t));
 }
 
-void
-sess_htable_reload(npf_sehash_t *stbl)
+/*
+ * npf_session_reload: perform reload by flushing the current hash table
+ * of the sessions and replacing with the new one or just destroying.
+ *
+ * Key routine synchronising with all other readers and writers.
+ */
+static void
+npf_session_reload(npf_sehash_t *newtbl, int tracking)
 {
-	npf_sehash_t *oldstbl;
+	npf_sehash_t *oldtbl;
 
-	/* Flush all existing entries. */
+	/* Must synchronise with G/C thread and session saving/restoring. */
 	mutex_enter(&sess_lock);
-	if (sess_gc_lwp) {
-		sess_tracking = SESS_TRACKING_FLUSH;
-		cv_broadcast(&sess_cv);
-	}
 	while (sess_tracking == SESS_TRACKING_FLUSH) {
 		cv_wait(&sess_cv, &sess_lock);
 	}
 
-	/* Set a new session table. */
-	oldstbl = sess_hashtbl;
-	sess_hashtbl = stbl;
-	mutex_exit(&sess_lock);
-
-	/* Destroy the old table. */
-	if (oldstbl) {
-		sess_htable_destroy(oldstbl);
-	}
-}
+	/*
+	 * Set the flush status.  It disables session inspection as well as
+	 * creation.  There may be some operations in-flight, drain them.
+	 */
+	npf_config_enter();
+	sess_tracking = SESS_TRACKING_FLUSH;
+	npf_config_sync();
+	npf_config_exit();
 
-/*
- * Session tracking routines.  Note: manages tracking structures.
- */
-
-static int
-sess_tracking_start(void)
-{
-	npf_sehash_t *nstbl;
-
-	nstbl = sess_htable_create();
-	if (nstbl == NULL) {
-		return ENOMEM;
+	/* Notify the worker to G/C all sessions. */
+	npf_worker_signal();
+	while (sess_tracking == SESS_TRACKING_FLUSH) {
+		cv_wait(&sess_cv, &sess_lock);
 	}
 
-	/* Note: should be visible before thread start. */
-	mutex_enter(&sess_lock);
-	if (sess_tracking != SESS_TRACKING_OFF) {
-		mutex_exit(&sess_lock);
-		sess_htable_destroy(nstbl);
-		return EEXIST;
-	}
-	sess_hashtbl = nstbl;
-	sess_tracking = SESS_TRACKING_ON;
-	mutex_exit(&sess_lock);
-
-	if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
-	    npf_session_worker, NULL, &sess_gc_lwp, "npfgc")) {
-		sess_tracking_stop();
-		return ENOMEM;
-	}
-	return 0;
-}
+	/* Install the new hash table, make it visible. */
+	oldtbl = atomic_swap_ptr(&sess_hashtbl, newtbl);
+	membar_sync();
+	sess_tracking = tracking;
 
-static void
-sess_tracking_stop(void)
-{
-	npf_sehash_t *stbl;
-
-	mutex_enter(&sess_lock);
-	if (sess_tracking == SESS_TRACKING_OFF) {
-		mutex_exit(&sess_lock);
-		return;
+	/* Done.  Destroy the old table, if any. */
+	mutex_exit(&sess_lock);
+	if (oldtbl) {
+		sess_htable_destroy(oldtbl);
 	}
-
-	/* Notify G/C thread to flush all sessions. */
-	sess_tracking = SESS_TRACKING_OFF;
-	cv_broadcast(&sess_cv);
-
-	/* Wait for the exit. */
-	while (sess_gc_lwp != NULL) {
-		cv_wait(&sess_cv, &sess_lock);
-	}
-	stbl = sess_hashtbl;
-	sess_hashtbl = NULL;
-	mutex_exit(&sess_lock);
-
-	sess_htable_destroy(stbl);
-	pool_cache_invalidate(sess_cache);
 }
 
 /*
  * npf_session_tracking: enable/disable session tracking.
  */
-int
+void
 npf_session_tracking(bool track)
 {
-
 	if (sess_tracking == SESS_TRACKING_OFF && track) {
 		/* Disabled -> Enable. */
-		return sess_tracking_start();
+		npf_sehash_t *newtbl = sess_htable_create();
+		npf_session_reload(newtbl, SESS_TRACKING_ON);
+		return;
 	}
 	if (sess_tracking == SESS_TRACKING_ON && !track) {
 		/* Enabled -> Disable. */
-		sess_tracking_stop();
-		return 0;
+		npf_session_reload(NULL, SESS_TRACKING_OFF);
+		pool_cache_invalidate(sess_cache);
+		return;
 	}
-	return 0;
 }
 
 static bool
@@ -459,7 +418,7 @@
 	 * Check if session tracking is on.  Also, if layer 3 and 4 are not
 	 * cached - protocol is not supported or packet is invalid.
 	 */
-	if (sess_tracking == SESS_TRACKING_OFF) {
+	if (sess_tracking != SESS_TRACKING_ON) {
 		return false;
 	}
 	if (!npf_iscached(npc, NPC_IP46) || !npf_iscached(npc, NPC_LAYER4)) {
@@ -929,14 +888,14 @@
 npf_session_gc(struct npf_sesslist *gc_list, bool flushall)
 {
 	struct timespec tsnow;
-	npf_sentry_t *sen, *nsen;
-	npf_session_t *se;
 	u_int i;
 
+	KASSERT(mutex_owned(&sess_lock));
 	getnanouptime(&tsnow);
 
 	/* Scan each session entry in the hash table. */
 	for (i = 0; i < SESS_HASH_BUCKETS; i++) {
+		npf_sentry_t *sen, *nsen;
 		npf_sehash_t *sh;
 
 		sh = &sess_hashtbl[i];
@@ -947,6 +906,8 @@
 		/* For each (left -> right) ... */
 		sen = rb_tree_iterate(&sh->sh_tree, NULL, RB_DIR_LEFT);
 		while (sen != NULL) {
+			npf_session_t *se;
+
 			/* Get session, pre-iterate, skip if not expired. */
 			se = sen->se_backptr;
 			nsen = rb_tree_iterate(&sh->sh_tree, sen, RB_DIR_RIGHT);
@@ -981,15 +942,33 @@
 }
 
 /*
- * npf_session_freelist: destroy all sessions, which have no references,
- * in the given G/C list.  Return true, if the list is empty.
+ * npf_session_worker: G/C to run from a worker thread.
  */
 static void
-npf_session_freelist(struct npf_sesslist *gc_list)
+npf_session_worker(void)
 {
 	npf_session_t *se, *nse;
 
-	se = LIST_FIRST(gc_list);
+	/*
+	 * Garbage collect expired sessions.
+	 */
+	mutex_enter(&sess_lock);
+	if (sess_hashtbl) {
+		bool flush = (sess_tracking != SESS_TRACKING_ON);
+		npf_session_gc(&sess_gc_list, flush);
+	}
+	if (sess_tracking == SESS_TRACKING_FLUSH) {
+		/* Flush was requested - indicate we are done. */
+		sess_tracking = SESS_TRACKING_OFF;
+		cv_broadcast(&sess_cv);
+	}
+	mutex_exit(&sess_lock);
+again:
+	/*
+	 * Destroy all sessions in the G/C list.
+	 * May need to wait for the references to drain.
+	 */
+	se = LIST_FIRST(&sess_gc_list);
 	while (se != NULL) {
 		nse = LIST_NEXT(se, s_list);
 		if (se->s_refcnt == 0) {
@@ -999,48 +978,17 @@
 		}
 		se = nse;
 	}
+	if (!LIST_EMPTY(&sess_gc_list)) {
+		kpause("npfcongc", false, 1, NULL);
+		goto again;
+	}
 }
 
-/*
- * npf_session_worker: G/C worker thread.
- */
-static void
-npf_session_worker(void *arg)
+void
+npf_session_load(npf_sehash_t *newtbl)
 {
-	struct npf_sesslist gc_list;
-	bool flushreq = false;
-
-	LIST_INIT(&gc_list);
-	do {
-		/* Periodically wake up, unless get notified. */
-		mutex_enter(&sess_lock);
-		(void)cv_timedwait(&sess_cv, &sess_lock, SESS_GC_INTERVAL);
-		flushreq = (sess_tracking != SESS_TRACKING_ON);
-		npf_session_gc(&gc_list, flushreq);
-		if (sess_tracking == SESS_TRACKING_FLUSH) {
-			/* Flush was requested - on again, notify waiter. */
-			sess_tracking = SESS_TRACKING_ON;
-			cv_broadcast(&sess_cv);
-		}
-		mutex_exit(&sess_lock);
-
-		npf_session_freelist(&gc_list);
-
-	} while (sess_tracking != SESS_TRACKING_OFF);
-
-	/* Wait for any referenced sessions to be released. */
-	while (!LIST_EMPTY(&gc_list)) {
-		kpause("npfgcfr", false, 1, NULL);
-		npf_session_freelist(&gc_list);
-	}
-
-	/* Notify that we are done. */
-	mutex_enter(&sess_lock);
-	sess_gc_lwp = NULL;
-	cv_broadcast(&sess_cv);
-	mutex_exit(&sess_lock);
-
-	kthread_exit(0);
+	KASSERT(newtbl != NULL);
+	npf_session_reload(newtbl, SESS_TRACKING_ON);
 }
 
 /*
@@ -1054,18 +1002,16 @@
 	npf_session_t *se;
 	int error = 0, i;
 
-	/* If not tracking - empty. */
+	/*
+	 * If not tracking - empty.  Note: must acquire sess_lock to
+	 * prevent from hash table destruction as well as expiring or
+	 * removing of sessions by the G/C thread.
+	 */
 	mutex_enter(&sess_lock);
-	if (sess_tracking == SESS_TRACKING_OFF) {
+	if (sess_tracking != SESS_TRACKING_ON) {
 		mutex_exit(&sess_lock);
 		return 0;
 	}
-
-	/*
-	 * Note: hold the session lock to prevent G/C thread from session
-	 * expiring and removing.  Therefore, no need to exclusively lock
-	 * the entire hash table.
-	 */
 	for (i = 0; i < SESS_HASH_BUCKETS; i++) {
 		sh = &sess_hashtbl[i];
 		if (sh->sh_count == 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_worker.c	Sun Jun 02 02:20:04 2013 +0000
@@ -0,0 +1,161 @@
+/*	$NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $	*/
+
+/*-
+ * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+
+#include "npf_impl.h"
+
+#define	NPF_MAX_WORKS		4
+#define	WORKER_INTERVAL		mstohz(5 * 1000)
+
+static kmutex_t		worker_lock;
+static kcondvar_t	worker_cv;
+static kcondvar_t	worker_event_cv;
+static lwp_t *		worker_lwp;
+static uint64_t		worker_loop;
+
+static npf_workfunc_t	work_funcs[NPF_MAX_WORKS];
+
+static void	npf_worker(void *) __dead;
+
+int
+npf_worker_sysinit(void)
+{
+	mutex_init(&worker_lock, MUTEX_DEFAULT, IPL_SOFTNET);
+	cv_init(&worker_cv, "npfgccv");
+	cv_init(&worker_event_cv, "npfevcv");
+	worker_lwp = (lwp_t *)0xdeadbabe;
+	worker_loop = 1;
+
+	if (kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
+	    npf_worker, NULL, &worker_lwp, "npfgc")) {
+		return ENOMEM;
+	}
+	return 0;
+}
+
+void
+npf_worker_sysfini(void)
+{
+	lwp_t *l = worker_lwp;
+
+	/* Notify the worker and wait for the exit. */
+	mutex_enter(&worker_lock);
+	worker_lwp = NULL;
+	cv_broadcast(&worker_cv);
+	mutex_exit(&worker_lock);
+	kthread_join(l);
+
+	/* LWP has exited, destroy the structures. */
+	cv_destroy(&worker_cv);
+	cv_destroy(&worker_event_cv);
+	mutex_destroy(&worker_lock);
+}
+
+void
+npf_worker_signal(void)
+{
+	mutex_enter(&worker_lock);
+	cv_signal(&worker_cv);
+	mutex_exit(&worker_lock);
+}
+
+static bool
+npf_worker_testset(npf_workfunc_t find, npf_workfunc_t set)
+{
+	for (u_int i = 0; i < NPF_MAX_WORKS; i++) {
+		if (work_funcs[i] == find) {
+			work_funcs[i] = set;
+			return true;
+		}
+	}
+	return false;
+}
+
+void
+npf_worker_register(npf_workfunc_t func)
+{
+	mutex_enter(&worker_lock);
+	npf_worker_testset(NULL, func);
+	mutex_exit(&worker_lock);
+}
+
+void
+npf_worker_unregister(npf_workfunc_t func)
+{
+	uint64_t l = worker_loop;
+
+	mutex_enter(&worker_lock);
+	npf_worker_testset(func, NULL);
+	while (worker_loop == l) {
+		cv_signal(&worker_cv);
+		cv_wait(&worker_event_cv, &worker_lock);
+	}
+	mutex_exit(&worker_lock);
+}
+
+static void
+npf_worker(void *arg)
+{
+	for (;;) {
+		const bool finish = (worker_lwp == NULL);
+		u_int i = NPF_MAX_WORKS;
+		npf_workfunc_t work;
+
+		/* Run the jobs. */
+		while (i--) {
+			if ((work = work_funcs[i]) != NULL) {
+				work();
+			}
+		}
+
+		/* Exit if requested and all jobs are done. */
+		if (finish) {
+			break;
+		}
+
+		/* Sleep and periodically wake up, unless we get notified. */
+		mutex_enter(&worker_lock);
+		worker_loop++;
+		cv_broadcast(&worker_event_cv);
+		cv_timedwait(&worker_cv, &worker_lock, WORKER_INTERVAL);
+		mutex_exit(&worker_lock);
+	}
+	kthread_exit(0);
+}
--- a/sys/rump/net/lib/libnpf/Makefile	Sat Jun 01 21:21:36 2013 +0000
+++ b/sys/rump/net/lib/libnpf/Makefile	Sun Jun 02 02:20:04 2013 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.6 2013/03/12 21:12:47 christos Exp $
+#	$NetBSD: Makefile,v 1.7 2013/06/02 02:20:04 rmind Exp $
 #
 # Public Domain.
 #
@@ -11,7 +11,7 @@
 SRCS+=	npf_inet.c npf_instr.c npf_mbuf.c npf_nat.c
 SRCS+=	npf_processor.c npf_ruleset.c npf_rproc.c npf_sendpkt.c
 SRCS+=	npf_session.c npf_state.c npf_state_tcp.c
-SRCS+=	npf_tableset.c npf_tableset_ptree.c
+SRCS+=	npf_tableset.c npf_tableset_ptree.c npf_worker.c
 SRCS+=	if_npflog.c
 
 SRCS+=	npf_alg_icmp.c