Sync NPF with the version on github: backport standalone NPF changes, trunk
authorchristos <christos@NetBSD.org>
Mon, 26 Dec 2016 23:05:05 +0000
branchtrunk
changeset 247110 424e704ddb9d
parent 247109 775bc28909b0
child 247111 aebef087c6b8
Sync NPF with the version on github: backport standalone NPF changes, which allow us to create and run separate NPF instances. Minor fixes. (from rmind@)
lib/libnpf/npf.c
lib/libnpf/npf.h
sys/compat/netbsd32/netbsd32_ioctl.c
sys/compat/netbsd32/netbsd32_ioctl.h
sys/net/npf/files.npf
sys/net/npf/if_npflog.c
sys/net/npf/npf.c
sys/net/npf/npf.h
sys/net/npf/npf_alg.c
sys/net/npf/npf_alg_icmp.c
sys/net/npf/npf_bpf.c
sys/net/npf/npf_conf.c
sys/net/npf/npf_conn.c
sys/net/npf/npf_conn.h
sys/net/npf/npf_conndb.c
sys/net/npf/npf_ctl.c
sys/net/npf/npf_ext_log.c
sys/net/npf/npf_ext_normalize.c
sys/net/npf/npf_ext_rndblock.c
sys/net/npf/npf_handler.c
sys/net/npf/npf_if.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_inet.c
sys/net/npf/npf_mbuf.c
sys/net/npf/npf_nat.c
sys/net/npf/npf_os.c
sys/net/npf/npf_rproc.c
sys/net/npf/npf_ruleset.c
sys/net/npf/npf_sendpkt.c
sys/net/npf/npf_state.c
sys/net/npf/npf_state_tcp.c
sys/net/npf/npf_tableset.c
sys/net/npf/npf_worker.c
sys/net/npf/npfkern.h
sys/rump/net/lib/libnpf/Makefile
usr.sbin/npf/npfctl/npf_bpf_comp.c
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_data.c
usr.sbin/npf/npfctl/npf_show.c
usr.sbin/npf/npfctl/npfctl.c
usr.sbin/npf/npfctl/npfctl.h
usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c
usr.sbin/npf/npftest/libnpftest/npf_mbuf_subr.c
usr.sbin/npf/npftest/libnpftest/npf_nat_test.c
usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c
usr.sbin/npf/npftest/libnpftest/npf_perf_test.c
usr.sbin/npf/npftest/libnpftest/npf_rule_test.c
usr.sbin/npf/npftest/libnpftest/npf_state_test.c
usr.sbin/npf/npftest/libnpftest/npf_table_test.c
usr.sbin/npf/npftest/libnpftest/npf_test.h
usr.sbin/npf/npftest/libnpftest/npf_test_subr.c
usr.sbin/npf/npftest/npfstream.c
usr.sbin/npf/npftest/npftest.c
usr.sbin/npf/npftest/npftest.h
--- a/lib/libnpf/npf.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/lib/libnpf/npf.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.39 2016/12/10 21:04:12 christos Exp $	*/
+/*	$NetBSD: npf.c,v 1.40 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2015 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.39 2016/12/10 21:04:12 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.40 2016/12/26 23:05:05 christos Exp $");
 
 #include <sys/types.h>
 #include <netinet/in_systm.h>
@@ -95,8 +95,6 @@
 	prop_dictionary_t	ncf_err;
 	prop_dictionary_t	ncf_debug;
 
-	/* Custom file to externalise property-list. */
-	const char *		ncf_plist;
 	bool			ncf_flush;
 };
 
@@ -143,7 +141,7 @@
 		return false;
 	}
 }
-		
+
 /*
  * CONFIGURATION INTERFACE.
  */
@@ -162,31 +160,26 @@
 	ncf->ncf_rproc_list = prop_array_create();
 	ncf->ncf_table_list = prop_array_create();
 	ncf->ncf_nat_list = prop_array_create();
-
-	ncf->ncf_plist = NULL;
 	ncf->ncf_flush = false;
-
 	return ncf;
 }
 
-int
-npf_config_submit(nl_config_t *ncf, int fd)
+static prop_dictionary_t
+_npf_build_config(nl_config_t *ncf)
 {
-	const char *plist = ncf->ncf_plist;
 	prop_dictionary_t npf_dict;
 	prop_array_t rlset;
-	int error = 0;
 
 	npf_dict = prop_dictionary_create();
 	if (npf_dict == NULL) {
-		return ENOMEM;
+		return NULL;
 	}
 	prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION);
 
 	rlset = _npf_ruleset_transform(ncf->ncf_rules_list);
 	if (rlset == NULL) {
 		prop_object_release(npf_dict);
-		return ENOMEM;
+		return NULL;
 	}
 	prop_object_release(ncf->ncf_rules_list);
 	ncf->ncf_rules_list = rlset;
@@ -204,26 +197,44 @@
 	if (ncf->ncf_debug) {
 		prop_dictionary_set(npf_dict, "debug", ncf->ncf_debug);
 	}
+	return npf_dict;
+}
 
-	if (plist) {
-		if (!prop_dictionary_externalize_to_file(npf_dict, plist)) {
-			error = errno;
-		}
+int
+npf_config_submit(nl_config_t *ncf, int fd, npf_error_t *errinfo)
+{
+#if !defined(_NPF_STANDALONE)
+	prop_dictionary_t npf_dict;
+	int error = 0;
+
+	npf_dict = _npf_build_config(ncf);
+	if (!npf_dict) {
+		return ENOMEM;
+	}
+	error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
+	    IOC_NPF_LOAD, &ncf->ncf_err);
+	if (error) {
 		prop_object_release(npf_dict);
+		assert(ncf->ncf_err == NULL);
 		return error;
 	}
-	if (fd) {
-		error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
-		    IOC_NPF_LOAD, &ncf->ncf_err);
-		if (error) {
-			prop_object_release(npf_dict);
-			assert(ncf->ncf_err == NULL);
-			return error;
-		}
-		prop_dictionary_get_int32(ncf->ncf_err, "errno", &error);
+	prop_dictionary_get_int32(ncf->ncf_err, "errno", &error);
+	if (error) {
+		memset(errinfo, 0, sizeof(*errinfo));
+
+		prop_dictionary_get_int64(ncf->ncf_err, "id",
+		    &errinfo->id);
+		prop_dictionary_get_cstring(ncf->ncf_err,
+		    "source-file", &errinfo->source_file);
+		prop_dictionary_get_uint32(ncf->ncf_err,
+		    "source-line", &errinfo->source_line);
 	}
 	prop_object_release(npf_dict);
 	return error;
+#else
+	(void)ncf; (void)fd;
+	return ENOTSUP;
+#endif
 }
 
 static nl_config_t *
@@ -246,13 +257,17 @@
 }
 
 nl_config_t *
-npf_config_retrieve(int fd, bool *active, bool *loaded)
+npf_config_retrieve(int fd)
 {
 	prop_dictionary_t npf_dict;
 	nl_config_t *ncf;
 	int error;
 
+#ifdef _NPF_STANDALONE
+	error = ENOTSUP;
+#else
 	error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SAVE, &npf_dict);
+#endif
 	if (error) {
 		return NULL;
 	}
@@ -261,30 +276,35 @@
 		prop_object_release(npf_dict);
 		return NULL;
 	}
-	prop_dictionary_get_bool(npf_dict, "active", active);
-	*loaded = (ncf->ncf_rules_list != NULL);
 	return ncf;
 }
 
-int
-npf_config_export(const nl_config_t *ncf, const char *path)
+void *
+npf_config_export(nl_config_t *ncf, size_t *length)
 {
 	prop_dictionary_t npf_dict = ncf->ncf_dict;
-	int error = 0;
+	void *blob;
 
-	if (!prop_dictionary_externalize_to_file(npf_dict, path)) {
-		error = errno;
+	if (!npf_dict && (npf_dict = _npf_build_config(ncf)) == NULL) {
+		errno = ENOMEM;
+		return NULL;
 	}
-	return error;
+	if ((blob = prop_dictionary_externalize(npf_dict)) == NULL) {
+		prop_object_release(npf_dict);
+		return NULL;
+	}
+	prop_object_release(npf_dict);
+	*length = strlen(blob);
+	return blob;
 }
 
 nl_config_t *
-npf_config_import(const char *path)
+npf_config_import(const void *blob, size_t len __unused)
 {
 	prop_dictionary_t npf_dict;
 	nl_config_t *ncf;
 
-	npf_dict = prop_dictionary_internalize_from_file(path);
+	npf_dict = prop_dictionary_internalize(blob);
 	if (!npf_dict) {
 		return NULL;
 	}
@@ -300,6 +320,7 @@
 npf_config_flush(int fd)
 {
 	nl_config_t *ncf;
+	npf_error_t errinfo;
 	int error;
 
 	ncf = npf_config_create();
@@ -307,24 +328,33 @@
 		return ENOMEM;
 	}
 	ncf->ncf_flush = true;
-	error = npf_config_submit(ncf, fd);
+	error = npf_config_submit(ncf, fd, &errinfo);
 	npf_config_destroy(ncf);
 	return error;
 }
 
-void
-_npf_config_error(nl_config_t *ncf, nl_error_t *ne)
+bool
+npf_config_active_p(nl_config_t *ncf)
+{
+	bool active = false;
+	prop_dictionary_get_bool(ncf->ncf_dict, "active", &active);
+	return active;
+}
+
+bool
+npf_config_loaded_p(nl_config_t *ncf)
 {
-	memset(ne, 0, sizeof(*ne));
-	prop_dictionary_get_int32(ncf->ncf_err, "id", &ne->ne_id);
-	prop_dictionary_get_cstring(ncf->ncf_err,
-	    "source-file", &ne->ne_source_file);
-	prop_dictionary_get_uint32(ncf->ncf_err,
-	    "source-line", &ne->ne_source_line);
-	prop_dictionary_get_int32(ncf->ncf_err,
-	    "code-error", &ne->ne_ncode_error);
-	prop_dictionary_get_int32(ncf->ncf_err,
-	    "code-errat", &ne->ne_ncode_errat);
+	return ncf->ncf_rules_list != NULL;
+}
+
+void *
+npf_config_build(nl_config_t *ncf)
+{
+	if (!ncf->ncf_dict && !(ncf->ncf_dict = _npf_build_config(ncf))) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	return (void *)ncf->ncf_dict;
 }
 
 void
@@ -346,12 +376,6 @@
 	free(ncf);
 }
 
-void
-_npf_config_setsubmit(nl_config_t *ncf, const char *plist_file)
-{
-	ncf->ncf_plist = plist_file;
-}
-
 static bool
 _npf_prop_array_lookup(prop_array_t array, const char *key, const char *name)
 {
@@ -382,7 +406,11 @@
 
 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD);
+#ifdef _NPF_STANDALONE
+	error = ENOTSUP;
+#else
 	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
+#endif
 	if (!error) {
 		prop_dictionary_get_uint64(ret, "id", id);
 	}
@@ -401,7 +429,11 @@
 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMOVE);
 	prop_dictionary_set_uint64(rldict, "id", id);
+#ifdef _NPF_STANDALONE
+	return ENOTSUP;
+#else
 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
+#endif
 }
 
 int
@@ -425,7 +457,11 @@
 	prop_dictionary_set(rldict, "key", keyobj);
 	prop_object_release(keyobj);
 
+#ifdef _NPF_STANDALONE
+	return ENOTSUP;
+#else
 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
+#endif
 }
 
 int
@@ -439,7 +475,11 @@
 	}
 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_FLUSH);
+#ifdef _NPF_STANDALONE
+	return ENOTSUP;
+#else
 	return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE);
+#endif
 }
 
 /*
@@ -610,7 +650,7 @@
 }
 
 int
-npf_rule_setprio(nl_rule_t *rl, pri_t pri)
+npf_rule_setprio(nl_rule_t *rl, int pri)
 {
 	prop_dictionary_t rldict = rl->nrl_dict;
 
@@ -664,6 +704,7 @@
 		rlset = ncf->ncf_rules_list;
 	}
 	prop_array_add(rlset, rldict);
+	prop_object_release(rldict);
 	return 0;
 }
 
@@ -764,7 +805,7 @@
 	uint64_t id = 0;
 
 	(void)prop_dictionary_get_uint64(rldict, "id", &id);
-	return id;
+	return (unsigned)id;
 }
 
 const void *
@@ -790,7 +831,11 @@
 	}
 	prop_dictionary_set_cstring(rldict, "ruleset-name", rname);
 	prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST);
+#ifdef _NPF_STANDALONE
+	error = ENOTSUP;
+#else
 	error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret);
+#endif
 	if (!error) {
 		prop_array_t rules;
 
@@ -860,6 +905,7 @@
 	}
 	prop_dictionary_set_cstring(extdict, "name", ext->nxt_name);
 	prop_array_add(extcalls, extdict);
+	prop_object_release(extdict);
 	return 0;
 }
 
@@ -882,6 +928,7 @@
 		return EEXIST;
 	}
 	prop_array_add(ncf->ncf_rproc_list, rpdict);
+	prop_object_release(rpdict);
 	return 0;
 }
 
@@ -953,12 +1000,13 @@
 }
 
 int
-npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, pri_t pri __unused)
+npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, int pri __unused)
 {
 	prop_dictionary_t rldict = nt->nrl_dict;
 
 	prop_dictionary_set_int32(rldict, "prio", NPF_PRI_LAST);
 	prop_array_add(ncf->ncf_nat_list, rldict);
+	prop_object_release(rldict);
 	return 0;
 }
 
@@ -1044,7 +1092,7 @@
 		return NULL;
 	}
 	prop_dictionary_set_cstring(tldict, "name", name);
-	prop_dictionary_set_uint32(tldict, "id", id);
+	prop_dictionary_set_uint64(tldict, "id", (uint64_t)id);
 	prop_dictionary_set_int32(tldict, "type", type);
 
 	tblents = prop_array_create();
@@ -1129,6 +1177,7 @@
 		return EEXIST;
 	}
 	prop_array_add(ncf->ncf_table_list, tldict);
+	prop_object_release(tldict);
 	return 0;
 }
 
@@ -1154,10 +1203,10 @@
 npf_table_getid(nl_table_t *tl)
 {
 	prop_dictionary_t tldict = tl->ntl_dict;
-	unsigned id = (unsigned)-1;
+	uint64_t id = (uint64_t)-1;
 
-	prop_dictionary_get_uint32(tldict, "id", &id);
-	return id;
+	prop_dictionary_get_uint64(tldict, "id", &id);
+	return (unsigned)id;
 }
 
 const char *
@@ -1282,8 +1331,12 @@
 
 	prop_object_release(conn_res);
 
+#if !defined(_NPF_STANDALONE)
 	error = prop_dictionary_sendrecv_ioctl(conn_dict, fd,
 	    IOC_NPF_CONN_LOOKUP, &conn_res);
+#else
+	error = ENOTSUP;
+#endif
 	if (error != 0)
 		goto out;
 
--- a/lib/libnpf/npf.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/lib/libnpf/npf.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.30 2016/12/10 21:04:12 christos Exp $	*/
+/*	$NetBSD: npf.h,v 1.31 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
@@ -58,14 +58,6 @@
 
 #ifdef _NPF_PRIVATE
 
-typedef struct {
-	int		ne_id;
-	char *		ne_source_file;
-	u_int		ne_source_line;
-	int		ne_ncode_error;
-	int		ne_ncode_errat;
-} nl_error_t;
-
 typedef void (*nl_rule_callback_t)(nl_rule_t *, unsigned);
 typedef void (*nl_table_callback_t)(unsigned, int);
 
@@ -75,12 +67,14 @@
 
 nl_config_t *	npf_config_create(void);
 void		npf_config_destroy(nl_config_t *);
-
-int		npf_config_submit(nl_config_t *, int);
-nl_config_t *	npf_config_retrieve(int, bool *, bool *);
-nl_config_t *	npf_config_import(const char *);
-int		npf_config_export(const nl_config_t *, const char *);
+int		npf_config_submit(nl_config_t *, int, npf_error_t *);
+nl_config_t *	npf_config_retrieve(int);
 int		npf_config_flush(int);
+nl_config_t *	npf_config_import(const void *, size_t);
+void *		npf_config_export(nl_config_t *, size_t *);
+bool		npf_config_active_p(nl_config_t *);
+bool		npf_config_loaded_p(nl_config_t *);
+void *		npf_config_build(nl_config_t *);
 
 int		npf_ruleset_add(int, const char *, nl_rule_t *, uint64_t *);
 int		npf_ruleset_remove(int, const char *, uint64_t);
@@ -94,7 +88,7 @@
 
 nl_rule_t *	npf_rule_create(const char *, uint32_t, const char *);
 int		npf_rule_setcode(nl_rule_t *, int, const void *, size_t);
-int		npf_rule_setprio(nl_rule_t *, pri_t);
+int		npf_rule_setprio(nl_rule_t *, int);
 int		npf_rule_setproc(nl_rule_t *, const char *);
 int		npf_rule_setkey(nl_rule_t *, const void *, size_t);
 int		npf_rule_setinfo(nl_rule_t *, const void *, size_t);
@@ -110,7 +104,7 @@
 
 nl_nat_t *	npf_nat_create(int, u_int, const char *,
 		    int, npf_addr_t *, npf_netmask_t, in_port_t);
-int		npf_nat_insert(nl_config_t *, nl_nat_t *, pri_t);
+int		npf_nat_insert(nl_config_t *, nl_nat_t *, int);
 int		npf_nat_lookup(int, int, npf_addr_t *[2], in_port_t [2], int, int);
 
 nl_table_t *	npf_table_create(const char *, u_int, int);
@@ -149,8 +143,6 @@
 nl_rproc_t *	npf_rproc_iterate(nl_config_t *);
 const char *	npf_rproc_getname(nl_rproc_t *);
 
-void		_npf_config_error(nl_config_t *, nl_error_t *);
-void		_npf_config_setsubmit(nl_config_t *, const char *);
 int		_npf_ruleset_list(int, const char *, nl_config_t *);
 void		_npf_debug_addif(nl_config_t *, const char *);
 
--- a/sys/compat/netbsd32/netbsd32_ioctl.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/compat/netbsd32/netbsd32_ioctl.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_ioctl.c,v 1.87 2016/11/21 03:50:50 rin Exp $	*/
+/*	$NetBSD: netbsd32_ioctl.c,v 1.88 2016/12/26 23:05:06 christos Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.87 2016/11/21 03:50:50 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.88 2016/12/26 23:05:06 christos Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ntp.h"
@@ -472,9 +472,7 @@
 	case NPF_CMD_TABLE_LOOKUP:
 	case NPF_CMD_TABLE_ADD:
 	case NPF_CMD_TABLE_REMOVE:
-		p->nct_data.ent.alen = s32p->nct_data.ent.alen;
-		p->nct_data.ent.addr = s32p->nct_data.ent.addr;
-		p->nct_data.ent.mask = s32p->nct_data.ent.mask;
+		p->nct_data.ent = s32p->nct_data.ent;
 		break;
 	case NPF_CMD_TABLE_LIST:
 		p->nct_data.buf.buf = NETBSD32PTR64(s32p->nct_data.buf.buf);
@@ -896,9 +894,7 @@
 	case NPF_CMD_TABLE_LOOKUP:
 	case NPF_CMD_TABLE_ADD:
 	case NPF_CMD_TABLE_REMOVE:
-		s32p->nct_data.ent.alen = p->nct_data.ent.alen;
-		s32p->nct_data.ent.addr = p->nct_data.ent.addr;
-		s32p->nct_data.ent.mask = p->nct_data.ent.mask;
+		s32p->nct_data.ent = p->nct_data.ent;
 		break;
 	case NPF_CMD_TABLE_LIST:
 		NETBSD32PTR32(s32p->nct_data.buf.buf, p->nct_data.buf.buf);
--- a/sys/compat/netbsd32/netbsd32_ioctl.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/compat/netbsd32/netbsd32_ioctl.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_ioctl.h,v 1.55 2016/11/12 16:06:04 mlelstv Exp $	*/
+/*	$NetBSD: netbsd32_ioctl.h,v 1.56 2016/12/26 23:05:06 christos Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -575,15 +575,7 @@
 #define	KIOCGSYMBOL32	_IOWR('l', 5, struct netbsd32_ksyms_gsymbol)
 #endif /* KIOCGSYMBOL */
 
-/* From net/npf/npf.h */
-typedef struct in6_addr		netbsd32_npf_addr_t;
-typedef uint8_t			netbsd32_npf_netmask_t;
-
-typedef struct netbsd32_npf_ioctl_ent {
-	int			alen;
-	netbsd32_npf_addr_t	addr;
-	netbsd32_npf_netmask_t	mask;
-} netbsd32_npf_ioctl_ent_t;
+#include <net/npf/npf.h>
 
 typedef struct netbsd32_npf_ioctl_buf {
 	netbsd32_voidp		buf;
@@ -594,7 +586,7 @@
 	int			nct_cmd;
 	netbsd32_charp		nct_name;
 	union {
-		netbsd32_npf_ioctl_ent_t ent;
+		npf_ioctl_ent_t ent;
 		netbsd32_npf_ioctl_buf_t buf;
 	} nct_data;
 } netbsd32_npf_ioctl_table_t;
--- a/sys/net/npf/files.npf	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/files.npf	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.npf,v 1.18 2016/12/09 02:40:38 christos Exp $
+# $NetBSD: files.npf,v 1.19 2016/12/26 23:05:06 christos Exp $
 #
 # Public Domain.
 #
@@ -11,6 +11,7 @@
 
 # Core
 file	net/npf/npf.c				npf
+file	net/npf/npf_os.c			npf
 file	net/npf/npf_conf.c			npf
 file	net/npf/npf_ctl.c			npf
 file	net/npf/npf_handler.c			npf
--- a/sys/net/npf/if_npflog.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/if_npflog.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_npflog.c,v 1.3 2013/03/13 13:15:47 christos Exp $	*/
+/*	$NetBSD: if_npflog.c,v 1.4 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF logging extension.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_npflog.c,v 1.3 2013/03/13 13:15:47 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_npflog.c,v 1.4 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/module.h>
@@ -49,6 +50,9 @@
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/bpf.h>
+#endif
+
+#include "npf_impl.h"
 
 MODULE(MODULE_CLASS_DRIVER, if_npflog, NULL);
 
--- a/sys/net/npf/npf.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.32 2016/12/10 05:41:10 christos Exp $	*/
+/*	$NetBSD: npf.c,v 1.33 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -33,249 +33,113 @@
  * NPF main: dynamic load/initialisation and unload routines.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.32 2016/12/10 05:41:10 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.33 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
-#include <sys/atomic.h>
 #include <sys/conf.h>
-#include <sys/kauth.h>
 #include <sys/kmem.h>
-#include <sys/lwp.h>
-#include <sys/module.h>
 #include <sys/percpu.h>
-#include <sys/rwlock.h>
-#include <sys/socketvar.h>
-#include <sys/sysctl.h>
-#include <sys/uio.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
 
-#ifndef _MODULE
-#include "opt_modular.h"
-#endif
-
-#include "ioconf.h"
-
-/*
- * Module and device structures.
- */
-#ifndef _MODULE
-/*
- * Modular kernels load drivers too early, and we need percpu to be inited
- * So we make this misc; a better way would be to have early boot and late
- * boot drivers.
- */
-MODULE(MODULE_CLASS_MISC, npf, NULL);
-#else
-/* This module autoloads via /dev/npf so it needs to be a driver */
-MODULE(MODULE_CLASS_DRIVER, npf, NULL);
-#endif
-
-static int	npf_fini(void);
-static int	npf_dev_open(dev_t, int, int, lwp_t *);
-static int	npf_dev_close(dev_t, int, int, lwp_t *);
-static int	npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *);
-static int	npf_dev_poll(dev_t, int, lwp_t *);
-static int	npf_dev_read(dev_t, struct uio *, int);
-
-static int	npfctl_stats(void *);
-
-static percpu_t *		npf_stats_percpu	__read_mostly;
-static struct sysctllog *	npf_sysctl		__read_mostly;
+__read_mostly static npf_t *	npf_kernel_ctx = NULL;
 
-const struct cdevsw npf_cdevsw = {
-	.d_open = npf_dev_open,
-	.d_close = npf_dev_close,
-	.d_read = npf_dev_read,
-	.d_write = nowrite,
-	.d_ioctl = npf_dev_ioctl,
-	.d_stop = nostop,
-	.d_tty = notty,
-	.d_poll = npf_dev_poll,
-	.d_mmap = nommap,
-	.d_kqfilter = nokqfilter,
-	.d_discard = nodiscard,
-	.d_flag = D_OTHER | D_MPSAFE
-};
-
-static int
-npf_init(void)
+__dso_public int
+npf_sysinit(unsigned nworkers)
 {
-	KASSERT(npf_stats_percpu == NULL);
-
-	npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE);
-	npf_sysctl = NULL;
-
 	npf_bpf_sysinit();
-	npf_worker_sysinit();
 	npf_tableset_sysinit();
-	npf_conn_sysinit();
 	npf_nat_sysinit();
-	npf_alg_sysinit();
-	npf_ext_sysinit();
-
-	/* Load empty configuration. */
-	npf_pfil_register(true);
-	npf_config_init();
+	return npf_worker_sysinit(nworkers);
+}
 
-#ifdef _MODULE
-	devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
-
-	/* Attach /dev/npf device. */
-	int error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
-	if (error) {
-		/* It will call devsw_detach(), which is safe. */
-		(void)npf_fini();
-	}
-	return error;
-#else
-	return 0;
-#endif
+__dso_public void
+npf_sysfini(void)
+{
+	npf_worker_sysfini();
+	npf_nat_sysfini();
+	npf_tableset_sysfini();
+	npf_bpf_sysfini();
 }
 
-static int
-npf_fini(void)
+__dso_public npf_t *
+npf_create(int flags, const npf_mbufops_t *mbufops, const npf_ifops_t *ifops)
 {
-	/* At first, detach device and remove pfil hooks. */
-#ifdef _MODULE
-	devsw_detach(NULL, &npf_cdevsw);
-#endif
-	npf_pfil_unregister(true);
-	npf_config_fini();
+	npf_t *npf;
+
+	npf = kmem_zalloc(sizeof(npf_t), KM_SLEEP);
+	npf->qsbr = pserialize_create();
+	if (!npf->qsbr) {
+		kmem_free(npf, sizeof(npf_t));
+		return NULL;
+	}
+	npf->stats_percpu = percpu_alloc(NPF_STATS_SIZE);
+	npf->mbufops = mbufops;
+
+	npf_ifmap_init(npf, ifops);
+	npf_conn_init(npf, flags);
+	npf_alg_init(npf);
+	npf_ext_init(npf);
+
+	/* Load an empty configuration. */
+	npf_config_init(npf);
+	return npf;
+}
+
+__dso_public void
+npf_destroy(npf_t *npf)
+{
+	/*
+	 * Destroy the current configuration.  Note: at this point all
+	 * handlers must be deactivated; we will drain any processing.
+	 */
+	npf_config_fini(npf);
 
 	/* Finally, safe to destroy the subsystems. */
-	npf_ext_sysfini();
-	npf_alg_sysfini();
-	npf_nat_sysfini();
-	npf_conn_sysfini();
-	npf_tableset_sysfini();
-	npf_bpf_sysfini();
+	npf_ext_fini(npf);
+	npf_alg_fini(npf);
+	npf_conn_fini(npf);
+	npf_ifmap_fini(npf);
 
-	/* Note: worker is the last. */
-	npf_worker_sysfini();
-
-	if (npf_sysctl) {
-		sysctl_teardown(&npf_sysctl);
-	}
-	percpu_free(npf_stats_percpu, NPF_STATS_SIZE);
-
-	return 0;
+	pserialize_destroy(npf->qsbr);
+	percpu_free(npf->stats_percpu, NPF_STATS_SIZE);
+	kmem_free(npf, sizeof(npf_t));
 }
 
-/*
- * Module interface.
- */
-static int
-npf_modcmd(modcmd_t cmd, void *arg)
+__dso_public int
+npf_load(npf_t *npf, void *ref, npf_error_t *err)
 {
+	return npfctl_load(npf, 0, ref);
+}
 
-	switch (cmd) {
-	case MODULE_CMD_INIT:
-		return npf_init();
-	case MODULE_CMD_FINI:
-		return npf_fini();
-	case MODULE_CMD_AUTOUNLOAD:
-		if (npf_autounload_p()) {
-			return EBUSY;
-		}
-		break;
-	default:
-		return ENOTTY;
-	}
-	return 0;
+__dso_public void
+npf_gc(npf_t *npf)
+{
+	npf_conn_worker(npf);
+}
+
+__dso_public void
+npf_thread_register(npf_t *npf)
+{
+	pserialize_register(npf->qsbr);
 }
 
 void
-npfattach(int nunits)
-{
-	/* Nothing */
-}
-
-static int
-npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l)
+npf_setkernctx(npf_t *npf)
 {
-
-	/* Available only for super-user. */
-	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
-	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
-		return EPERM;
-	}
-	return 0;
-}
-
-static int
-npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l)
-{
-
-	return 0;
+	npf_kernel_ctx = npf;
 }
 
-static int
-npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
+npf_t *
+npf_getkernctx(void)
 {
-	int error;
-
-	/* Available only for super-user. */
-	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
-	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
-		return EPERM;
-	}
-
-	switch (cmd) {
-	case IOC_NPF_TABLE:
-		error = npfctl_table(data);
-		break;
-	case IOC_NPF_RULE:
-		error = npfctl_rule(cmd, data);
-		break;
-	case IOC_NPF_STATS:
-		error = npfctl_stats(data);
-		break;
-	case IOC_NPF_SAVE:
-		error = npfctl_save(cmd, data);
-		break;
-	case IOC_NPF_SWITCH:
-		error = npfctl_switch(data);
-		break;
-	case IOC_NPF_LOAD:
-		error = npfctl_load(cmd, data);
-		break;
-	case IOC_NPF_CONN_LOOKUP:
-		error = npfctl_conn_lookup(cmd, data);
-		break;
-	case IOC_NPF_VERSION:
-		*(int *)data = NPF_VERSION;
-		error = 0;
-		break;
-	default:
-		error = ENOTTY;
-		break;
-	}
-	return error;
-}
-
-static int
-npf_dev_poll(dev_t dev, int events, lwp_t *l)
-{
-
-	return ENOTSUP;
-}
-
-static int
-npf_dev_read(dev_t dev, struct uio *uio, int flag)
-{
-
-	return ENOTSUP;
-}
-
-bool
-npf_autounload_p(void)
-{
-	return !npf_pfil_registered_p() && npf_default_pass();
+	return npf_kernel_ctx;
 }
 
 /*
@@ -283,44 +147,37 @@
  */
 
 void
-npf_stats_inc(npf_stats_t st)
+npf_stats_inc(npf_t *npf, npf_stats_t st)
 {
-	uint64_t *stats = percpu_getref(npf_stats_percpu);
+	uint64_t *stats = percpu_getref(npf->stats_percpu);
 	stats[st]++;
-	percpu_putref(npf_stats_percpu);
+	percpu_putref(npf->stats_percpu);
 }
 
 void
-npf_stats_dec(npf_stats_t st)
+npf_stats_dec(npf_t *npf, npf_stats_t st)
 {
-	uint64_t *stats = percpu_getref(npf_stats_percpu);
+	uint64_t *stats = percpu_getref(npf->stats_percpu);
 	stats[st]--;
-	percpu_putref(npf_stats_percpu);
+	percpu_putref(npf->stats_percpu);
 }
 
 static void
 npf_stats_collect(void *mem, void *arg, struct cpu_info *ci)
 {
 	uint64_t *percpu_stats = mem, *full_stats = arg;
-	int i;
 
-	for (i = 0; i < NPF_STATS_COUNT; i++) {
+	for (unsigned i = 0; i < NPF_STATS_COUNT; i++) {
 		full_stats[i] += percpu_stats[i];
 	}
 }
 
 /*
- * npfctl_stats: export collected statistics.
+ * npf_stats: export collected statistics.
  */
-static int
-npfctl_stats(void *data)
+__dso_public void
+npf_stats(npf_t *npf, uint64_t *buf)
 {
-	uint64_t *fullst, *uptr = *(uint64_t **)data;
-	int error;
-
-	fullst = kmem_zalloc(NPF_STATS_SIZE, KM_SLEEP);
-	percpu_foreach(npf_stats_percpu, npf_stats_collect, fullst);
-	error = copyout(fullst, uptr, NPF_STATS_SIZE);
-	kmem_free(fullst, NPF_STATS_SIZE);
-	return error;
+	memset(buf, 0, NPF_STATS_SIZE);
+	percpu_foreach(npf->stats_percpu, npf_stats_collect, buf);
 }
--- a/sys/net/npf/npf.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.51 2016/12/10 19:05:45 christos Exp $	*/
+/*	$NetBSD: npf.h,v 1.52 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -39,20 +39,29 @@
 #include <sys/param.h>
 #include <sys/types.h>
 
+#define	NPF_VERSION		18
+
+#if defined(_NPF_STANDALONE)
+#include "npf_stand.h"
+#else
 #include <sys/ioctl.h>
 #include <prop/proplib.h>
-
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
+#endif
 
-#define	NPF_VERSION		18
+struct npf;
+typedef struct npf npf_t;
 
 /*
- * Public declarations and definitions.
+ * Storage of address (both for IPv4 and IPv6) and netmask.
  */
+typedef union {
+	uint8_t			word8[16];
+	uint16_t		word16[8];
+	uint32_t		word32[4];
+} npf_addr_t;
 
-/* Storage of address (both for IPv4 and IPv6) and netmask */
-typedef struct in6_addr		npf_addr_t;
 typedef uint8_t			npf_netmask_t;
 
 #define	NPF_MAX_NETMASK		(128)
@@ -70,7 +79,11 @@
 /* The number of words used. */
 #define	NPF_BPF_NWORDS		3
 
-#if defined(_KERNEL)
+/*
+ * In-kernel declarations and definitions.
+ */
+
+#if defined(_KERNEL) || defined(_NPF_STANDALONE)
 
 #define	NPF_DECISION_BLOCK	0
 #define	NPF_DECISION_PASS	1
@@ -92,16 +105,11 @@
 
 #define	NBUF_DATAREF_RESET	0x01
 
-typedef struct {
-	struct mbuf *	nb_mbuf0;
-	struct mbuf *	nb_mbuf;
-	void *		nb_nptr;
-	const ifnet_t *	nb_ifp;
-	unsigned	nb_ifid;
-	int		nb_flags;
-} nbuf_t;
+struct mbuf;
+struct nbuf;
+typedef struct nbuf nbuf_t;
 
-void		nbuf_init(nbuf_t *, struct mbuf *, const ifnet_t *);
+void		nbuf_init(npf_t *, nbuf_t *, struct mbuf *, const ifnet_t *);
 void		nbuf_reset(nbuf_t *);
 struct mbuf *	nbuf_head_mbuf(nbuf_t *);
 
@@ -138,7 +146,8 @@
 #define	NPC_IP46	(NPC_IP4|NPC_IP6)
 
 typedef struct {
-	/* Information flags and the nbuf. */
+	/* NPF context, information flags and the nbuf. */
+	npf_t *			npc_ctx;
 	uint32_t		npc_info;
 	nbuf_t *		npc_nbuf;
 
@@ -186,8 +195,6 @@
 struct npf_rproc;
 typedef struct npf_rproc	npf_rproc_t;
 
-void		npf_rproc_assign(npf_rproc_t *, void *);
-
 typedef struct {
 	unsigned int	version;
 	void *		ctx;
@@ -196,8 +203,9 @@
 	bool		(*proc)(npf_cache_t *, void *, int *);
 } npf_ext_ops_t;
 
-void *		npf_ext_register(const char *, const npf_ext_ops_t *);
-int		npf_ext_unregister(void *);
+void *		npf_ext_register(npf_t *, const char *, const npf_ext_ops_t *);
+int		npf_ext_unregister(npf_t *, void *);
+void		npf_rproc_assign(npf_rproc_t *, void *);
 
 /*
  * Misc.
@@ -261,8 +269,6 @@
 
 /* XXX mbuf.h: just for now. */
 #define	PACKET_TAG_NPF			10
-
-/* Packet tags. */
 #define	NPF_NTAG_PASS			0x0001
 
 /*
@@ -320,6 +326,16 @@
 #define	IOC_NPF_CONN_LOOKUP	_IOWR('N', 108, struct plistref)
 
 /*
+ * NPF error report.
+ */
+
+typedef struct {
+	int64_t		id;
+	char *		source_file;
+	u_int		source_line;
+} npf_error_t;
+
+/*
  * Statistics counters.
  */
 
--- a/sys/net/npf/npf_alg.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_alg.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg.c,v 1.15 2014/08/11 23:48:01 rmind Exp $	*/
+/*	$NetBSD: npf_alg.c,v 1.16 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF interface for the Application Level Gateways (ALGs).
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.15 2014/08/11 23:48:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.16 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -44,6 +45,7 @@
 #include <sys/mutex.h>
 #include <net/pfil.h>
 #include <sys/module.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -58,39 +60,44 @@
 	u_int		na_slot;
 };
 
-/* 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;
+struct npf_algset {
+	/* List of ALGs and the count. */
+	npf_alg_t	alg_list[NPF_MAX_ALGS];
+	u_int		alg_count;
 
-/* Matching, inspection and translation functions. */
-static npfa_funcs_t	alg_funcs[NPF_MAX_ALGS]	__read_mostly;
+	/* Matching, inspection and translation functions. */
+	npfa_funcs_t	alg_funcs[NPF_MAX_ALGS];
+};
 
 static const char	alg_prefix[] = "npf_alg_";
 #define	NPF_EXT_PREFLEN	(sizeof(alg_prefix) - 1)
 
 void
-npf_alg_sysinit(void)
+npf_alg_init(npf_t *npf)
 {
-	alg_psz = pserialize_create();
-	memset(alg_list, 0, sizeof(alg_list));
-	memset(alg_funcs, 0, sizeof(alg_funcs));
-	alg_count = 0;
+	npf_algset_t *aset;
+
+	aset = kmem_zalloc(sizeof(npf_algset_t), KM_SLEEP);
+	npf->algset = aset;
 }
 
 void
-npf_alg_sysfini(void)
+npf_alg_fini(npf_t *npf)
 {
-	pserialize_destroy(alg_psz);
+	npf_algset_t *aset = npf->algset;
+
+	kmem_free(aset, sizeof(npf_algset_t));
 }
 
 static npf_alg_t *
-npf_alg_lookup(const char *name)
+npf_alg_lookup(npf_t *npf, const char *name)
 {
-	KASSERT(npf_config_locked_p());
+	npf_algset_t *aset = npf->algset;
 
-	for (u_int i = 0; i < alg_count; i++) {
-		npf_alg_t *alg = &alg_list[i];
+	KASSERT(npf_config_locked_p(npf));
+
+	for (u_int i = 0; i < aset->alg_count; i++) {
+		npf_alg_t *alg = &aset->alg_list[i];
 		const char *aname = alg->na_name;
 
 		if (aname && strcmp(aname, name) == 0)
@@ -100,23 +107,23 @@
 }
 
 npf_alg_t *
-npf_alg_construct(const char *name)
+npf_alg_construct(npf_t *npf, const char *name)
 {
 	npf_alg_t *alg;
 
-	npf_config_enter();
-	if ((alg = npf_alg_lookup(name)) == NULL) {
+	npf_config_enter(npf);
+	if ((alg = npf_alg_lookup(npf, name)) == NULL) {
 		char modname[NPF_EXT_PREFLEN + 64];
 		snprintf(modname, sizeof(modname), "%s%s", alg_prefix, name);
-		npf_config_exit();
+		npf_config_exit(npf);
 
 		if (module_autoload(modname, MODULE_CLASS_MISC) != 0) {
 			return NULL;
 		}
-		npf_config_enter();
-		alg = npf_alg_lookup(name);
+		npf_config_enter(npf);
+		alg = npf_alg_lookup(npf, name);
 	}
-	npf_config_exit();
+	npf_config_exit(npf);
 	return alg;
 }
 
@@ -124,26 +131,28 @@
  * npf_alg_register: register application-level gateway.
  */
 npf_alg_t *
-npf_alg_register(const char *name, const npfa_funcs_t *funcs)
+npf_alg_register(npf_t *npf, const char *name, const npfa_funcs_t *funcs)
 {
+	npf_algset_t *aset = npf->algset;
+	npfa_funcs_t *afuncs;
 	npf_alg_t *alg;
 	u_int i;
 
-	npf_config_enter();
-	if (npf_alg_lookup(name) != NULL) {
-		npf_config_exit();
+	npf_config_enter(npf);
+	if (npf_alg_lookup(npf, name) != NULL) {
+		npf_config_exit(npf);
 		return NULL;
 	}
 
 	/* Find a spare slot. */
 	for (i = 0; i < NPF_MAX_ALGS; i++) {
-		alg = &alg_list[i];
+		alg = &aset->alg_list[i];
 		if (alg->na_name == NULL) {
 			break;
 		}
 	}
 	if (i == NPF_MAX_ALGS) {
-		npf_config_exit();
+		npf_config_exit(npf);
 		return NULL;
 	}
 
@@ -152,12 +161,13 @@
 	alg->na_slot = i;
 
 	/* Assign the functions. */
-	alg_funcs[i].match = funcs->match;
-	alg_funcs[i].translate = funcs->translate;
-	alg_funcs[i].inspect = funcs->inspect;
+	afuncs = &aset->alg_funcs[i];
+	afuncs->match = funcs->match;
+	afuncs->translate = funcs->translate;
+	afuncs->inspect = funcs->inspect;
 
-	alg_count = MAX(alg_count, i + 1);
-	npf_config_exit();
+	aset->alg_count = MAX(aset->alg_count, i + 1);
+	npf_config_exit(npf);
 
 	return alg;
 }
@@ -166,21 +176,24 @@
  * npf_alg_unregister: unregister application-level gateway.
  */
 int
-npf_alg_unregister(npf_alg_t *alg)
+npf_alg_unregister(npf_t *npf, npf_alg_t *alg)
 {
+	npf_algset_t *aset = npf->algset;
 	u_int i = alg->na_slot;
+	npfa_funcs_t *afuncs;
 
 	/* Deactivate the functions first. */
-	npf_config_enter();
-	alg_funcs[i].match = NULL;
-	alg_funcs[i].translate = NULL;
-	alg_funcs[i].inspect = NULL;
-	pserialize_perform(alg_psz);
+	npf_config_enter(npf);
+	afuncs = &aset->alg_funcs[i];
+	afuncs->match = NULL;
+	afuncs->translate = NULL;
+	afuncs->inspect = NULL;
+	pserialize_perform(npf->qsbr);
 
 	/* Finally, unregister the ALG. */
-	npf_ruleset_freealg(npf_config_natset(), alg);
+	npf_ruleset_freealg(npf_config_natset(npf), alg);
 	alg->na_name = NULL;
-	npf_config_exit();
+	npf_config_exit(npf);
 
 	return 0;
 }
@@ -191,12 +204,13 @@
 bool
 npf_alg_match(npf_cache_t *npc, npf_nat_t *nt, int di)
 {
+	npf_algset_t *aset = npc->npc_ctx->algset;
 	bool match = false;
 	int s;
 
 	s = pserialize_read_enter();
-	for (u_int i = 0; i < alg_count; i++) {
-		const npfa_funcs_t *f = &alg_funcs[i];
+	for (u_int i = 0; i < aset->alg_count; i++) {
+		const npfa_funcs_t *f = &aset->alg_funcs[i];
 
 		if (f->match && f->match(npc, nt, di)) {
 			match = true;
@@ -213,11 +227,12 @@
 void
 npf_alg_exec(npf_cache_t *npc, npf_nat_t *nt, bool forw)
 {
+	npf_algset_t *aset = npc->npc_ctx->algset;
 	int s;
 
 	s = pserialize_read_enter();
-	for (u_int i = 0; i < alg_count; i++) {
-		const npfa_funcs_t *f = &alg_funcs[i];
+	for (u_int i = 0; i < aset->alg_count; i++) {
+		const npfa_funcs_t *f = &aset->alg_funcs[i];
 
 		if (f->translate) {
 			f->translate(npc, nt, forw);
@@ -229,12 +244,13 @@
 npf_conn_t *
 npf_alg_conn(npf_cache_t *npc, int di)
 {
+	npf_algset_t *aset = npc->npc_ctx->algset;
 	npf_conn_t *con = NULL;
 	int s;
 
 	s = pserialize_read_enter();
-	for (u_int i = 0; i < alg_count; i++) {
-		const npfa_funcs_t *f = &alg_funcs[i];
+	for (u_int i = 0; i < aset->alg_count; i++) {
+		const npfa_funcs_t *f = &aset->alg_funcs[i];
 
 		if (!f->inspect)
 			continue;
@@ -246,14 +262,15 @@
 }
 
 prop_array_t
-npf_alg_export(void)
+npf_alg_export(npf_t *npf)
 {
 	prop_array_t alglist = prop_array_create();
-
-	KASSERT(npf_config_locked_p());
+	npf_algset_t *aset = npf->algset;
 
-	for (u_int i = 0; i < alg_count; i++) {
-		const npf_alg_t *alg = &alg_list[i];
+	KASSERT(npf_config_locked_p(npf));
+
+	for (u_int i = 0; i < aset->alg_count; i++) {
+		const npf_alg_t *alg = &aset->alg_list[i];
 
 		if (alg->na_name == NULL) {
 			continue;
--- a/sys/net/npf/npf_alg_icmp.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_alg_icmp.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_alg_icmp.c,v 1.23 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_alg_icmp.c,v 1.24 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF ALG for ICMP and traceroute translations.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.23 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.24 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/module.h>
@@ -47,6 +48,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <net/pfil.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
@@ -216,6 +218,7 @@
 	if (!nbuf_advance(nbuf, npc->npc_hlen, 0)) {
 		return false;
 	}
+	enpc->npc_ctx = npc->npc_ctx;
 	enpc->npc_nbuf = nbuf;
 	enpc->npc_info = 0;
 
@@ -421,7 +424,7 @@
 		.translate	= npfa_icmp_nat,
 		.inspect	= npfa_icmp_conn,
 	};
-	alg_icmp = npf_alg_register("icmp", &icmp);
+	alg_icmp = npf_alg_register(npf_getkernctx(), "icmp", &icmp);
 	return alg_icmp ? 0 : ENOMEM;
 }
 
@@ -429,7 +432,7 @@
 npf_alg_icmp_fini(void)
 {
 	KASSERT(alg_icmp != NULL);
-	return npf_alg_unregister(alg_icmp);
+	return npf_alg_unregister(npf_getkernctx(), alg_icmp);
 }
 
 static int
--- a/sys/net/npf/npf_bpf.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_bpf.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_bpf.c,v 1.11 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_bpf.c,v 1.12 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF byte-code processing.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.11 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.12 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -42,10 +43,15 @@
 #include <sys/bitops.h>
 #include <sys/mbuf.h>
 #include <net/bpf.h>
+#endif
 
 #define NPF_BPFCOP
 #include "npf_impl.h"
 
+#if defined(_NPF_STANDALONE)
+#define	m_length(m)		(nbuf)->nb_mops->getchainlen(m)
+#endif
+
 /*
  * BPF context and the coprocessor.
  */
@@ -80,13 +86,19 @@
 void
 npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
 {
-	const struct mbuf *mbuf = nbuf_head_mbuf(npc->npc_nbuf);
+	nbuf_t *nbuf = npc->npc_nbuf;
+	const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
 	const size_t pktlen = m_length(mbuf);
 
 	/* Prepare the arguments for the BPF programs. */
+#ifdef _NPF_STANDALONE
+	args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
+	args->wirelen = args->buflen = pktlen;
+#else
 	args->pkt = (const uint8_t *)mbuf;
 	args->wirelen = pktlen;
 	args->buflen = 0;
+#endif
 	args->mem = M;
 	args->arg = npc;
 
@@ -164,7 +176,7 @@
 npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
 {
 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
-	npf_tableset_t *tblset = npf_config_tableset();
+	npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
 	const uint32_t tid = A & (SRC_FLAG_BIT - 1);
 	const npf_addr_t *addr;
 	npf_table_t *t;
--- a/sys/net/npf/npf_conf.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_conf.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_conf.c,v 1.9 2014/11/30 01:37:53 rmind Exp $	*/
+/*	$NetBSD: npf_conf.c,v 1.10 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -47,8 +47,9 @@
  *	necessary writer-side barrier of the passive serialisation.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.9 2014/11/30 01:37:53 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.10 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -57,39 +58,35 @@
 #include <sys/kmem.h>
 #include <sys/pserialize.h>
 #include <sys/mutex.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
 
-typedef struct {
+struct npf_config {
 	npf_ruleset_t *		n_rules;
 	npf_tableset_t *	n_tables;
 	npf_ruleset_t *		n_nat_rules;
 	npf_rprocset_t *	n_rprocs;
 	bool			n_default_pass;
-} npf_config_t;
-
-static npf_config_t *		npf_config		__cacheline_aligned;
-static kmutex_t			npf_config_lock		__cacheline_aligned;
-static pserialize_t		npf_config_psz		__cacheline_aligned;
+};
 
 void
-npf_config_init(void)
+npf_config_init(npf_t *npf)
 {
 	npf_ruleset_t *rlset, *nset;
 	npf_rprocset_t *rpset;
 	npf_tableset_t *tset;
 
-	mutex_init(&npf_config_lock, MUTEX_DEFAULT, IPL_SOFTNET);
-	npf_config_psz = pserialize_create();
+	mutex_init(&npf->config_lock, MUTEX_DEFAULT, IPL_SOFTNET);
 
 	/* Load the empty configuration. */
 	tset = npf_tableset_create(0);
 	rpset = npf_rprocset_create();
 	rlset = npf_ruleset_create(0);
 	nset = npf_ruleset_create(0);
-	npf_config_load(rlset, tset, nset, rpset, NULL, true);
-	KASSERT(npf_config != NULL);
+	npf_config_load(npf, rlset, tset, nset, rpset, NULL, true);
+	KASSERT(npf->config != NULL);
 }
 
 static void
@@ -103,21 +100,20 @@
 }
 
 void
-npf_config_fini(void)
+npf_config_fini(npf_t *npf)
 {
 	npf_conndb_t *cd = npf_conndb_create();
 
 	/* Flush the connections. */
-	mutex_enter(&npf_config_lock);
-	npf_conn_tracking(false);
-	pserialize_perform(npf_config_psz);
-	npf_conn_load(cd, false);
-	npf_ifmap_flush();
-	mutex_exit(&npf_config_lock);
+	mutex_enter(&npf->config_lock);
+	npf_conn_tracking(npf, false);
+	pserialize_perform(npf->qsbr);
+	npf_conn_load(npf, cd, false);
+	npf_ifmap_flush(npf);
+	mutex_exit(&npf->config_lock);
 
-	npf_config_destroy(npf_config);
-	pserialize_destroy(npf_config_psz);
-	mutex_destroy(&npf_config_lock);
+	npf_config_destroy(npf->config);
+	mutex_destroy(&npf->config_lock);
 }
 
 /*
@@ -125,7 +121,7 @@
  * Performs the necessary synchronisation and destroys the old config.
  */
 void
-npf_config_load(npf_ruleset_t *rset, npf_tableset_t *tset,
+npf_config_load(npf_t *npf, npf_ruleset_t *rset, npf_tableset_t *tset,
     npf_ruleset_t *nset, npf_rprocset_t *rpset,
     npf_conndb_t *conns, bool flush)
 {
@@ -144,23 +140,23 @@
 	 * - Scan and use existing dynamic tables, reload only static.
 	 * - Scan and use matching NAT policies to preserve the connections.
 	 */
-	mutex_enter(&npf_config_lock);
-	if ((onc = npf_config) != NULL) {
-		npf_ruleset_reload(rset, onc->n_rules, load);
-		npf_tableset_reload(tset, onc->n_tables);
-		npf_ruleset_reload(nset, onc->n_nat_rules, load);
+	mutex_enter(&npf->config_lock);
+	if ((onc = npf->config) != NULL) {
+		npf_ruleset_reload(npf, rset, onc->n_rules, load);
+		npf_tableset_reload(npf, tset, onc->n_tables);
+		npf_ruleset_reload(npf, nset, onc->n_nat_rules, load);
 	}
 
 	/*
 	 * Set the new config and release the lock.
 	 */
 	membar_sync();
-	npf_config = nc;
+	npf->config = nc;
 	if (onc == NULL) {
 		/* Initial load, done. */
-		npf_ifmap_flush();
-		npf_conn_load(conns, !flush);
-		mutex_exit(&npf_config_lock);
+		npf_ifmap_flush(npf);
+		npf_conn_load(npf, conns, !flush);
+		mutex_exit(&npf->config_lock);
 		return;
 	}
 
@@ -169,21 +165,21 @@
 	 * then disable the connection tracking for the grace period.
 	 */
 	if (flush || conns) {
-		npf_conn_tracking(false);
+		npf_conn_tracking(npf, false);
 	}
 
 	/* Synchronise: drain all references. */
-	pserialize_perform(npf_config_psz);
+	pserialize_perform(npf->qsbr);
 	if (flush) {
-		npf_ifmap_flush();
+		npf_ifmap_flush(npf);
 	}
 
 	/*
 	 * G/C the existing connections and, if passed, load the new ones.
 	 * If not flushing - enable the connection tracking.
 	 */
-	npf_conn_load(conns, !flush);
-	mutex_exit(&npf_config_lock);
+	npf_conn_load(npf, conns, !flush);
+	mutex_exit(&npf->config_lock);
 
 	/* Finally, it is safe to destroy the old config. */
 	npf_config_destroy(onc);
@@ -194,28 +190,28 @@
  */
 
 void
-npf_config_enter(void)
+npf_config_enter(npf_t *npf)
 {
-	mutex_enter(&npf_config_lock);
+	mutex_enter(&npf->config_lock);
 }
 
 void
-npf_config_exit(void)
+npf_config_exit(npf_t *npf)
 {
-	mutex_exit(&npf_config_lock);
+	mutex_exit(&npf->config_lock);
 }
 
 bool
-npf_config_locked_p(void)
+npf_config_locked_p(npf_t *npf)
 {
-	return mutex_owned(&npf_config_lock);
+	return mutex_owned(&npf->config_lock);
 }
 
 void
-npf_config_sync(void)
+npf_config_sync(npf_t *npf)
 {
-	KASSERT(npf_config_locked_p());
-	pserialize_perform(npf_config_psz);
+	KASSERT(npf_config_locked_p(npf));
+	pserialize_perform(npf->qsbr);
 }
 
 /*
@@ -239,31 +235,31 @@
  */
 
 npf_ruleset_t *
-npf_config_ruleset(void)
+npf_config_ruleset(npf_t *npf)
 {
-	return npf_config->n_rules;
+	return npf->config->n_rules;
 }
 
 npf_ruleset_t *
-npf_config_natset(void)
+npf_config_natset(npf_t *npf)
 {
-	return npf_config->n_nat_rules;
+	return npf->config->n_nat_rules;
 }
 
 npf_tableset_t *
-npf_config_tableset(void)
+npf_config_tableset(npf_t *npf)
 {
-	return npf_config->n_tables;
+	return npf->config->n_tables;
 }
 
 npf_rprocset_t *
-npf_config_rprocs(void)
+npf_config_rprocs(npf_t *npf)
 {
-	return npf_config->n_rprocs;
+	return npf->config->n_rprocs;
 }
 
 bool
-npf_default_pass(void)
+npf_default_pass(npf_t *npf)
 {
-	return npf_config->n_default_pass;
+	return npf->config->n_default_pass;
 }
--- a/sys/net/npf/npf_conn.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_conn.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_conn.c,v 1.21 2016/12/10 22:09:49 christos Exp $	*/
+/*	$NetBSD: npf_conn.c,v 1.22 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2014-2015 Mindaugas Rasiukevicius <rmind at netbsd org>
@@ -98,8 +98,9 @@
  *			npf_conn_t::c_lock
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.21 2016/12/10 22:09:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.22 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -116,6 +117,7 @@
 #include <sys/pool.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
+#endif
 
 #define __NPF_CONN_PRIVATE
 #include "npf_conn.h"
@@ -130,46 +132,38 @@
 #define	CONN_EXPIRE	0x010	/* explicitly expire */
 #define	CONN_REMOVED	0x020	/* "forw/back" entries removed */
 
-/*
- * Connection tracking state: disabled (off) or enabled (on).
- */
 enum { CONN_TRACKING_OFF, CONN_TRACKING_ON };
-static volatile int	conn_tracking	__cacheline_aligned;
 
-/* Connection tracking database, connection cache and the lock. */
-static npf_conndb_t *	conn_db		__read_mostly;
-static pool_cache_t	conn_cache	__read_mostly;
-static kmutex_t		conn_lock	__cacheline_aligned;
-
-static void	npf_conn_worker(void);
-static void	npf_conn_destroy(npf_conn_t *);
+static void	npf_conn_destroy(npf_t *, npf_conn_t *);
 
 /*
  * npf_conn_sys{init,fini}: initialise/destroy connection tracking.
  */
 
 void
-npf_conn_sysinit(void)
+npf_conn_init(npf_t *npf, int flags)
 {
-	conn_cache = pool_cache_init(sizeof(npf_conn_t), coherency_unit,
+	npf->conn_cache = pool_cache_init(sizeof(npf_conn_t), coherency_unit,
 	    0, 0, "npfconpl", NULL, IPL_NET, NULL, NULL, NULL);
-	mutex_init(&conn_lock, MUTEX_DEFAULT, IPL_NONE);
-	conn_tracking = CONN_TRACKING_OFF;
-	conn_db = npf_conndb_create();
+	mutex_init(&npf->conn_lock, MUTEX_DEFAULT, IPL_NONE);
+	npf->conn_tracking = CONN_TRACKING_OFF;
+	npf->conn_db = npf_conndb_create();
 
-	npf_worker_register(npf_conn_worker);
+	if ((flags & NPF_NO_GC) == 0) {
+		npf_worker_register(npf, npf_conn_worker);
+	}
 }
 
 void
-npf_conn_sysfini(void)
+npf_conn_fini(npf_t *npf)
 {
 	/* Note: the caller should have flushed the connections. */
-	KASSERT(conn_tracking == CONN_TRACKING_OFF);
-	npf_worker_unregister(npf_conn_worker);
+	KASSERT(npf->conn_tracking == CONN_TRACKING_OFF);
+	npf_worker_unregister(npf, npf_conn_worker);
 
-	npf_conndb_destroy(conn_db);
-	pool_cache_destroy(conn_cache);
-	mutex_destroy(&conn_lock);
+	npf_conndb_destroy(npf->conn_db);
+	pool_cache_destroy(npf->conn_cache);
+	mutex_destroy(&npf->conn_lock);
 }
 
 /*
@@ -180,37 +174,37 @@
  *    there are no connection database lookups or references in-flight.
  */
 void
-npf_conn_load(npf_conndb_t *ndb, bool track)
+npf_conn_load(npf_t *npf, npf_conndb_t *ndb, bool track)
 {
 	npf_conndb_t *odb = NULL;
 
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
 	/*
 	 * The connection database is in the quiescent state.
 	 * Prevent G/C thread from running and install a new database.
 	 */
-	mutex_enter(&conn_lock);
+	mutex_enter(&npf->conn_lock);
 	if (ndb) {
-		KASSERT(conn_tracking == CONN_TRACKING_OFF);
-		odb = conn_db;
-		conn_db = ndb;
+		KASSERT(npf->conn_tracking == CONN_TRACKING_OFF);
+		odb = npf->conn_db;
+		npf->conn_db = ndb;
 		membar_sync();
 	}
 	if (track) {
 		/* After this point lookups start flying in. */
-		conn_tracking = CONN_TRACKING_ON;
+		npf->conn_tracking = CONN_TRACKING_ON;
 	}
-	mutex_exit(&conn_lock);
+	mutex_exit(&npf->conn_lock);
 
 	if (odb) {
 		/*
 		 * Flush all, no sync since the caller did it for us.
 		 * Also, release the pool cache memory.
 		 */
-		npf_conn_gc(odb, true, false);
+		npf_conn_gc(npf, odb, true, false);
 		npf_conndb_destroy(odb);
-		pool_cache_invalidate(conn_cache);
+		pool_cache_invalidate(npf->conn_cache);
 	}
 }
 
@@ -218,20 +212,22 @@
  * npf_conn_tracking: enable/disable connection tracking.
  */
 void
-npf_conn_tracking(bool track)
+npf_conn_tracking(npf_t *npf, bool track)
 {
-	KASSERT(npf_config_locked_p());
-	conn_tracking = track ? CONN_TRACKING_ON : CONN_TRACKING_OFF;
+	KASSERT(npf_config_locked_p(npf));
+	npf->conn_tracking = track ? CONN_TRACKING_ON : CONN_TRACKING_OFF;
 }
 
 static inline bool
 npf_conn_trackable_p(const npf_cache_t *npc)
 {
+	const npf_t *npf = npc->npc_ctx;
+
 	/*
 	 * Check if connection tracking is on.  Also, if layer 3 and 4 are
 	 * not cached - protocol is not supported or packet is invalid.
 	 */
-	if (conn_tracking != CONN_TRACKING_ON) {
+	if (npf->conn_tracking != CONN_TRACKING_ON) {
 		return false;
 	}
 	if (!npf_iscached(npc, NPC_IP46) || !npf_iscached(npc, NPC_LAYER4)) {
@@ -242,10 +238,11 @@
 
 static uint32_t
 connkey_setkey(npf_connkey_t *key, uint16_t proto, const void *ipv,
-    const uint16_t *id, uint16_t alen, bool forw)
+    const uint16_t *id, unsigned alen, bool forw)
 {
 	uint32_t isrc, idst, *k = key->ck_key;
 	const npf_addr_t * const *ips = ipv;
+
 	if (__predict_true(forw)) {
 		isrc = NPF_SRC, idst = NPF_DST;
 	} else {
@@ -268,8 +265,8 @@
 	k[1] = ((uint32_t)id[isrc] << 16) | id[idst];
 
 	if (__predict_true(alen == sizeof(in_addr_t))) {
-		k[2] = ips[isrc]->s6_addr32[0];
-		k[3] = ips[idst]->s6_addr32[0];
+		k[2] = ips[isrc]->word32[0];
+		k[3] = ips[idst]->word32[0];
 		return 4 * sizeof(uint32_t);
 	} else {
 		const u_int nwords = alen >> 2;
@@ -309,12 +306,13 @@
 unsigned
 npf_conn_conkey(const npf_cache_t *npc, npf_connkey_t *key, const bool forw)
 {
-	const uint16_t alen = npc->npc_alen;
+	const u_int proto = npc->npc_proto;
+	const u_int alen = npc->npc_alen;
 	const struct tcphdr *th;
 	const struct udphdr *uh;
 	uint16_t id[2];
 
-	switch (npc->npc_proto) {
+	switch (proto) {
 	case IPPROTO_TCP:
 		KASSERT(npf_iscached(npc, NPC_TCP));
 		th = npc->npc_l4.tcp;
@@ -347,9 +345,7 @@
 		/* Unsupported protocol. */
 		return 0;
 	}
-
-	return connkey_setkey(key, npc->npc_proto, npc->npc_ips, id, alen,
-	    forw);
+	return connkey_setkey(key, proto, npc->npc_ips, id, alen, forw);
 }
 
 static __inline void
@@ -372,13 +368,22 @@
 	key->ck_key[1] = ((uint32_t)id << shift) | (oid & mask);
 }
 
+static inline void
+conn_update_atime(npf_conn_t *con)
+{
+	struct timespec tsnow;
+
+	getnanouptime(&tsnow);
+	con->c_atime = tsnow.tv_sec;
+}
+
 /*
  * npf_conn_ok: check if the connection is active, and has the right direction.
  */
 static bool
-npf_conn_ok(npf_conn_t *con, const int di, bool forw)
+npf_conn_ok(const npf_conn_t *con, const int di, bool forw)
 {
-	uint32_t flags = con->c_flags;
+	const uint32_t flags = con->c_flags;
 
 	/* Check if connection is active and not expired. */
 	bool ok = (flags & (CONN_ACTIVE | CONN_EXPIRE)) == CONN_ACTIVE;
@@ -387,7 +392,7 @@
 	}
 
 	/* Check if the direction is consistent */
-	bool pforw = (flags & PFIL_ALL) == di;
+	bool pforw = (flags & PFIL_ALL) == (unsigned)di;
 	if (__predict_false(forw != pforw)) {
 		return false;
 	}
@@ -402,6 +407,7 @@
 npf_conn_t *
 npf_conn_lookup(const npf_cache_t *npc, const int di, bool *forw)
 {
+	npf_t *npf = npc->npc_ctx;
 	const nbuf_t *nbuf = npc->npc_nbuf;
 	npf_conn_t *con;
 	npf_connkey_t key;
@@ -411,7 +417,7 @@
 	if (!npf_conn_conkey(npc, &key, true)) {
 		return NULL;
 	}
-	con = npf_conndb_lookup(conn_db, &key, forw);
+	con = npf_conndb_lookup(npf->conn_db, &key, forw);
 	if (con == NULL) {
 		return NULL;
 	}
@@ -434,7 +440,7 @@
 	}
 
 	/* Update the last activity time. */
-	getnanouptime(&con->c_atime);
+	conn_update_atime(con);
 	return con;
 }
 
@@ -479,7 +485,7 @@
 	/* If invalid state: let the rules deal with it. */
 	if (__predict_false(!ok)) {
 		npf_conn_release(con);
-		npf_stats_inc(NPF_STAT_INVALID_STATE);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_INVALID_STATE);
 		return NULL;
 	}
 
@@ -504,6 +510,7 @@
 npf_conn_t *
 npf_conn_establish(npf_cache_t *npc, int di, bool per_if)
 {
+	npf_t *npf = npc->npc_ctx;
 	const nbuf_t *nbuf = npc->npc_nbuf;
 	npf_conn_t *con;
 	int error = 0;
@@ -515,12 +522,13 @@
 	}
 
 	/* Allocate and initialise the new connection. */
-	con = pool_cache_get(conn_cache, PR_NOWAIT);
+	con = pool_cache_get(npf->conn_cache, PR_NOWAIT);
 	if (__predict_false(!con)) {
+		npf_worker_signal(npf);
 		return NULL;
 	}
 	NPF_PRINTF(("NPF: create conn %p\n", con));
-	npf_stats_inc(NPF_STAT_CONN_CREATE);
+	npf_stats_inc(npf, NPF_STAT_CONN_CREATE);
 
 	mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);
 	con->c_flags = (di & PFIL_ALL);
@@ -530,7 +538,7 @@
 
 	/* Initialize the protocol state. */
 	if (!npf_state_init(npc, &con->c_state)) {
-		npf_conn_destroy(con);
+		npf_conn_destroy(npf, con);
 		return NULL;
 	}
 
@@ -544,7 +552,7 @@
 	 */
 	if (!npf_conn_conkey(npc, fw, true) ||
 	    !npf_conn_conkey(npc, bk, false)) {
-		npf_conn_destroy(con);
+		npf_conn_destroy(npf, con);
 		return NULL;
 	}
 	fw->ck_backptr = bk->ck_backptr = con;
@@ -555,7 +563,7 @@
 	 * Set last activity time for a new connection and acquire
 	 * a reference for the caller before we make it visible.
 	 */
-	getnanouptime(&con->c_atime);
+	conn_update_atime(con);
 	con->c_refcnt = 1;
 
 	/*
@@ -564,13 +572,13 @@
 	 * the connection later.
 	 */
 	mutex_enter(&con->c_lock);
-	if (!npf_conndb_insert(conn_db, fw, con)) {
+	if (!npf_conndb_insert(npf->conn_db, fw, con)) {
 		error = EISCONN;
 		goto err;
 	}
-	if (!npf_conndb_insert(conn_db, bk, con)) {
+	if (!npf_conndb_insert(npf->conn_db, bk, con)) {
 		npf_conn_t *ret __diagused;
-		ret = npf_conndb_remove(conn_db, fw);
+		ret = npf_conndb_remove(npf->conn_db, fw);
 		KASSERT(ret == con);
 		error = EISCONN;
 		goto err;
@@ -584,20 +592,20 @@
 	if (error) {
 		atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);
 		atomic_dec_uint(&con->c_refcnt);
-		npf_stats_inc(NPF_STAT_RACE_CONN);
+		npf_stats_inc(npf, NPF_STAT_RACE_CONN);
 	} else {
 		NPF_PRINTF(("NPF: establish conn %p\n", con));
 	}
 
 	/* Finally, insert into the connection list. */
-	npf_conndb_enqueue(conn_db, con);
+	npf_conndb_enqueue(npf->conn_db, con);
 	mutex_exit(&con->c_lock);
 
 	return error ? NULL : con;
 }
 
 static void
-npf_conn_destroy(npf_conn_t *con)
+npf_conn_destroy(npf_t *npf, npf_conn_t *con)
 {
 	KASSERT(con->c_refcnt == 0);
 
@@ -615,8 +623,8 @@
 	mutex_destroy(&con->c_lock);
 
 	/* Free the structure, increase the counter. */
-	pool_cache_put(conn_cache, con);
-	npf_stats_inc(NPF_STAT_CONN_DESTROY);
+	pool_cache_put(npf->conn_cache, con);
+	npf_stats_inc(npf, NPF_STAT_CONN_DESTROY);
 	NPF_PRINTF(("NPF: conn %p destroyed\n", con));
 }
 
@@ -634,6 +642,7 @@
 		[NPF_NATOUT] = NPF_DST,
 		[NPF_NATIN] = NPF_SRC,
 	};
+	npf_t *npf = npc->npc_ctx;
 	npf_connkey_t key, *bk;
 	npf_conn_t *ret __diagused;
 	npf_addr_t *taddr;
@@ -663,12 +672,12 @@
 	if (__predict_false(con->c_nat != NULL)) {
 		/* Race with a duplicate packet. */
 		mutex_exit(&con->c_lock);
-		npf_stats_inc(NPF_STAT_RACE_NAT);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT);
 		return EISCONN;
 	}
 
 	/* Remove the "backwards" entry. */
-	ret = npf_conndb_remove(conn_db, &con->c_back_entry);
+	ret = npf_conndb_remove(npf->conn_db, &con->c_back_entry);
 	KASSERT(ret == con);
 
 	/* Set the source/destination IDs to the translation values. */
@@ -679,18 +688,18 @@
 	}
 
 	/* Finally, re-insert the "backwards" entry. */
-	if (!npf_conndb_insert(conn_db, bk, con)) {
+	if (!npf_conndb_insert(npf->conn_db, bk, con)) {
 		/*
 		 * Race: we have hit the duplicate, remove the "forwards"
 		 * entry and expire our connection; it is no longer valid.
 		 */
-		ret = npf_conndb_remove(conn_db, &con->c_forw_entry);
+		ret = npf_conndb_remove(npf->conn_db, &con->c_forw_entry);
 		KASSERT(ret == con);
 
 		atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);
 		mutex_exit(&con->c_lock);
 
-		npf_stats_inc(NPF_STAT_RACE_NAT);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT);
 		return EISCONN;
 	}
 
@@ -767,7 +776,7 @@
 npf_conn_getnat(npf_conn_t *con, const int di, bool *forw)
 {
 	KASSERT(con->c_refcnt > 0);
-	*forw = (con->c_flags & PFIL_ALL) == di;
+	*forw = (con->c_flags & PFIL_ALL) == (u_int)di;
 	return con->c_nat;
 }
 
@@ -775,17 +784,22 @@
  * npf_conn_expired: criterion to check if connection is expired.
  */
 static inline bool
-npf_conn_expired(const npf_conn_t *con, const struct timespec *tsnow)
+npf_conn_expired(const npf_conn_t *con, uint64_t tsnow)
 {
 	const int etime = npf_state_etime(&con->c_state, con->c_proto);
-	struct timespec tsdiff;
+	int elapsed;
 
 	if (__predict_false(con->c_flags & CONN_EXPIRE)) {
 		/* Explicitly marked to be expired. */
 		return true;
 	}
-	timespecsub(tsnow, &con->c_atime, &tsdiff);
-	return tsdiff.tv_sec > etime;
+
+	/*
+	 * Note: another thread may update 'atime' and it might
+	 * become greater than 'now'.
+	 */
+	elapsed = (int64_t)tsnow - con->c_atime;
+	return elapsed > etime;
 }
 
 /*
@@ -796,7 +810,7 @@
  * => If 'sync' is true, then perform passive serialisation.
  */
 void
-npf_conn_gc(npf_conndb_t *cd, bool flush, bool sync)
+npf_conn_gc(npf_t *npf, npf_conndb_t *cd, bool flush, bool sync)
 {
 	npf_conn_t *con, *prev, *gclist = NULL;
 	struct timespec tsnow;
@@ -812,7 +826,7 @@
 		npf_conn_t *next = con->c_next;
 
 		/* Expired?  Flushing all? */
-		if (!npf_conn_expired(con, &tsnow) && !flush) {
+		if (!npf_conn_expired(con, tsnow.tv_sec) && !flush) {
 			prev = con;
 			con = next;
 			continue;
@@ -848,11 +862,11 @@
 	 * Note: drop the conn_lock (see the lock order).
 	 */
 	if (sync) {
-		mutex_exit(&conn_lock);
+		mutex_exit(&npf->conn_lock);
 		if (gclist) {
-			npf_config_enter();
-			npf_config_sync();
-			npf_config_exit();
+			npf_config_enter(npf);
+			npf_config_sync(npf);
+			npf_config_exit(npf);
 		}
 	}
 
@@ -872,7 +886,7 @@
 			kpause("npfcongc", false, 1, NULL);
 			continue;
 		}
-		npf_conn_destroy(con);
+		npf_conn_destroy(npf, con);
 		con = next;
 	}
 }
@@ -880,12 +894,12 @@
 /*
  * npf_conn_worker: G/C to run from a worker thread.
  */
-static void
-npf_conn_worker(void)
+void
+npf_conn_worker(npf_t *npf)
 {
-	mutex_enter(&conn_lock);
+	mutex_enter(&npf->conn_lock);
 	/* Note: the conn_lock will be released (sync == true). */
-	npf_conn_gc(conn_db, false, true);
+	npf_conn_gc(npf, npf->conn_db, false, true);
 }
 
 /*
@@ -893,7 +907,7 @@
  * Note: this is expected to be an expensive operation.
  */
 int
-npf_conndb_export(prop_array_t conlist)
+npf_conndb_export(npf_t *npf, prop_array_t conlist)
 {
 	npf_conn_t *con, *prev;
 
@@ -901,26 +915,26 @@
 	 * Note: acquire conn_lock to prevent from the database
 	 * destruction and G/C thread.
 	 */
-	mutex_enter(&conn_lock);
-	if (conn_tracking != CONN_TRACKING_ON) {
-		mutex_exit(&conn_lock);
+	mutex_enter(&npf->conn_lock);
+	if (npf->conn_tracking != CONN_TRACKING_ON) {
+		mutex_exit(&npf->conn_lock);
 		return 0;
 	}
 	prev = NULL;
-	con = npf_conndb_getlist(conn_db);
+	con = npf_conndb_getlist(npf->conn_db);
 	while (con) {
 		npf_conn_t *next = con->c_next;
 		prop_dictionary_t cdict;
 
-		if ((cdict = npf_conn_export(con)) != NULL) {
+		if ((cdict = npf_conn_export(npf, con)) != NULL) {
 			prop_array_add(conlist, cdict);
 			prop_object_release(cdict);
 		}
 		prev = con;
 		con = next;
 	}
-	npf_conndb_settail(conn_db, prev);
-	mutex_exit(&conn_lock);
+	npf_conndb_settail(npf->conn_db, prev);
+	mutex_exit(&npf->conn_lock);
 	return 0;
 }
 
@@ -928,10 +942,11 @@
 npf_connkey_export(const npf_connkey_t *key)
 {
 	uint16_t id[2], alen, proto;
+	prop_dictionary_t kdict;
 	npf_addr_t ips[2];
 	prop_data_t d;
-	prop_dictionary_t kdict = prop_dictionary_create();
 
+	kdict = prop_dictionary_create();
 	connkey_getkey(key, &proto, ips, id, &alen);
 
 	prop_dictionary_set_uint16(kdict, "proto", proto);
@@ -952,7 +967,7 @@
  * npf_conn_export: serialise a single connection.
  */
 prop_dictionary_t
-npf_conn_export(const npf_conn_t *con)
+npf_conn_export(npf_t *npf, const npf_conn_t *con)
 {
 	prop_dictionary_t cdict, kdict;
 	prop_data_t d;
@@ -964,7 +979,7 @@
 	prop_dictionary_set_uint32(cdict, "flags", con->c_flags);
 	prop_dictionary_set_uint32(cdict, "proto", con->c_proto);
 	if (con->c_ifid) {
-		const char *ifname = npf_ifmap_getname(con->c_ifid);
+		const char *ifname = npf_ifmap_getname(npf, con->c_ifid);
 		prop_dictionary_set_cstring(cdict, "ifname", ifname);
 	}
 
@@ -986,10 +1001,9 @@
 static uint32_t
 npf_connkey_import(prop_dictionary_t kdict, npf_connkey_t *key)
 {
-	uint16_t proto;
 	prop_object_t sobj, dobj;
-	uint16_t id[2];
 	npf_addr_t const * ips[2];
+	uint16_t alen, proto, id[2];
 
 	if (!prop_dictionary_get_uint16(kdict, "proto", &proto))
 		return 0;
@@ -1008,7 +1022,7 @@
 	if ((ips[NPF_DST] = prop_data_data_nocopy(dobj)) == NULL)
 		return 0;
 
-	uint16_t alen = prop_data_size(sobj);
+	alen = prop_data_size(sobj);
 	if (alen != prop_data_size(dobj))
 		return 0;
 
@@ -1020,7 +1034,7 @@
  * directory and insert into the given database.
  */
 int
-npf_conn_import(npf_conndb_t *cd, prop_dictionary_t cdict,
+npf_conn_import(npf_t *npf, npf_conndb_t *cd, prop_dictionary_t cdict,
     npf_ruleset_t *natlist)
 {
 	npf_conn_t *con;
@@ -1030,18 +1044,18 @@
 	const void *d;
 
 	/* Allocate a connection and initialise it (clear first). */
-	con = pool_cache_get(conn_cache, PR_WAITOK);
+	con = pool_cache_get(npf->conn_cache, PR_WAITOK);
 	memset(con, 0, sizeof(npf_conn_t));
 	mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);
-	npf_stats_inc(NPF_STAT_CONN_CREATE);
+	npf_stats_inc(npf, NPF_STAT_CONN_CREATE);
 
 	prop_dictionary_get_uint32(cdict, "proto", &con->c_proto);
 	prop_dictionary_get_uint32(cdict, "flags", &con->c_flags);
 	con->c_flags &= PFIL_ALL | CONN_ACTIVE | CONN_PASS;
-	getnanouptime(&con->c_atime);
+	conn_update_atime(con);
 
 	if (prop_dictionary_get_cstring_nocopy(cdict, "ifname", &ifname) &&
-	    (con->c_ifid = npf_ifmap_register(ifname)) == 0) {
+	    (con->c_ifid = npf_ifmap_register(npf, ifname)) == 0) {
 		goto err;
 	}
 
@@ -1054,7 +1068,7 @@
 
 	/* Reconstruct NAT association, if any. */
 	if ((obj = prop_dictionary_get(cdict, "nat")) != NULL &&
-	    (con->c_nat = npf_nat_import(obj, natlist, con)) == NULL) {
+	    (con->c_nat = npf_nat_import(npf, obj, natlist, con)) == NULL) {
 		goto err;
 	}
 
@@ -1088,18 +1102,18 @@
 	npf_conndb_enqueue(cd, con);
 	return 0;
 err:
-	npf_conn_destroy(con);
+	npf_conn_destroy(npf, con);
 	return EINVAL;
 }
 
 int
-npf_conn_find(prop_dictionary_t idict, prop_dictionary_t *odict)
+npf_conn_find(npf_t *npf, prop_dictionary_t idict, prop_dictionary_t *odict)
 {
+	prop_dictionary_t kdict;
 	npf_connkey_t key;
 	npf_conn_t *con;
 	uint16_t dir;
 	bool forw;
-	prop_dictionary_t kdict;
 
 	if ((kdict = prop_dictionary_get(idict, "key")) == NULL)
 		return EINVAL;
@@ -1110,7 +1124,7 @@
 	if (!prop_dictionary_get_uint16(idict, "direction", &dir))
 		return EINVAL;
 
-	con = npf_conndb_lookup(conn_db, &key, &forw);
+	con = npf_conndb_lookup(npf->conn_db, &key, &forw);
 	if (con == NULL) {
 		return ESRCH;
 	}
@@ -1120,7 +1134,7 @@
 		return ESRCH;
 	}
 
-	*odict = npf_conn_export(con);
+	*odict = npf_conn_export(npf, con);
 	if (*odict == NULL) {
 		atomic_dec_uint(&con->c_refcnt);
 		return ENOSPC;
@@ -1139,16 +1153,15 @@
 	const uint32_t *fkey = con->c_forw_entry.ck_key;
 	const uint32_t *bkey = con->c_back_entry.ck_key;
 	const u_int proto = con->c_proto;
-	struct timespec tsnow, tsdiff;
+	struct timespec tspnow;
 	const void *src, *dst;
 	int etime;
 
-	getnanouptime(&tsnow);
-	timespecsub(&tsnow, &con->c_atime, &tsdiff);
+	getnanouptime(&tspnow);
 	etime = npf_state_etime(&con->c_state, proto);
 
-	printf("%p:\n\tproto %d flags 0x%x tsdiff %d etime %d\n",
-	    con, proto, con->c_flags, (int)tsdiff.tv_sec, etime);
+	printf("%p:\n\tproto %d flags 0x%x tsdiff %ld etime %d\n", con,
+	    proto, con->c_flags, (long)(tspnow.tv_sec - con->c_atime), etime);
 
 	src = &fkey[2], dst = &fkey[2 + (alen >> 2)];
 	printf("\tforw %s:%d", npf_addr_dump(src, alen), ntohs(fkey[1] >> 16));
--- a/sys/net/npf/npf_conn.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_conn.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_conn.h,v 1.10 2016/12/10 19:05:45 christos Exp $	*/
+/*	$NetBSD: npf_conn.h,v 1.11 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 #ifndef _NPF_CONN_H_
 #define _NPF_CONN_H_
 
-#if !defined(_KERNEL)
+#if !defined(_KERNEL) && !defined(_NPF_STANDALONE)
 #error "kernel-level header only"
 #endif
 
@@ -44,8 +44,6 @@
 
 #if defined(__NPF_CONN_PRIVATE)
 
-#include <sys/rbtree.h>
-
 /*
  * See npf_conn_conkey() function for the key layout description.
  */
@@ -89,7 +87,7 @@
 	kmutex_t		c_lock;
 	npf_state_t		c_state;
 	u_int			c_refcnt;
-	struct timespec		c_atime;
+	uint64_t		c_atime;
 };
 
 #endif
@@ -97,10 +95,10 @@
 /*
  * Connection tracking interface.
  */
-void		npf_conn_sysinit(void);
-void		npf_conn_sysfini(void);
-void		npf_conn_tracking(bool);
-void		npf_conn_load(npf_conndb_t *, bool);
+void		npf_conn_init(npf_t *, int);
+void		npf_conn_fini(npf_t *);
+void		npf_conn_tracking(npf_t *, bool);
+void		npf_conn_load(npf_t *, npf_conndb_t *, bool);
 
 unsigned	npf_conn_conkey(const npf_cache_t *, npf_connkey_t *, bool);
 npf_conn_t *	npf_conn_lookup(const npf_cache_t *, const int, bool *);
@@ -113,11 +111,12 @@
 int		npf_conn_setnat(const npf_cache_t *, npf_conn_t *,
 		    npf_nat_t *, u_int);
 npf_nat_t *	npf_conn_getnat(npf_conn_t *, const int, bool *);
-void		npf_conn_gc(npf_conndb_t *, bool, bool);
-int		npf_conn_import(npf_conndb_t *, prop_dictionary_t,
+void		npf_conn_gc(npf_t *, npf_conndb_t *, bool, bool);
+void		npf_conn_worker(npf_t *);
+int		npf_conn_import(npf_t *, npf_conndb_t *, prop_dictionary_t,
 		    npf_ruleset_t *);
-int		npf_conn_find(prop_dictionary_t, prop_dictionary_t *);
-prop_dictionary_t npf_conn_export(const npf_conn_t *);
+int		npf_conn_find(npf_t *, prop_dictionary_t, prop_dictionary_t *);
+prop_dictionary_t npf_conn_export(npf_t *, const npf_conn_t *);
 void		npf_conn_print(const npf_conn_t *);
 
 /*
@@ -130,13 +129,13 @@
 		    bool *);
 bool		npf_conndb_insert(npf_conndb_t *, npf_connkey_t *,
 		    npf_conn_t *);
-npf_conn_t *	npf_conndb_remove(npf_conndb_t *, const npf_connkey_t *);
+npf_conn_t *	npf_conndb_remove(npf_conndb_t *, npf_connkey_t *);
 
 void		npf_conndb_enqueue(npf_conndb_t *, npf_conn_t *);
 void		npf_conndb_dequeue(npf_conndb_t *, npf_conn_t *,
 		    npf_conn_t *);
 npf_conn_t *	npf_conndb_getlist(npf_conndb_t *);
 void		npf_conndb_settail(npf_conndb_t *, npf_conn_t *);
-int		npf_conndb_export(prop_array_t);
+int		npf_conndb_export(npf_t *, prop_array_t);
 
 #endif	/* _NPF_CONN_H_ */
--- a/sys/net/npf/npf_conndb.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_conndb.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_conndb.c,v 1.2 2014/07/23 01:25:34 rmind Exp $	*/
+/*	$NetBSD: npf_conndb.c,v 1.3 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF connection storage.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_conndb.c,v 1.2 2014/07/23 01:25:34 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_conndb.c,v 1.3 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -43,6 +44,7 @@
 #include <sys/cprng.h>
 #include <sys/hash.h>
 #include <sys/kmem.h>
+#endif
 
 #define __NPF_CONN_PRIVATE
 #include "npf_conn.h"
@@ -62,6 +64,7 @@
 	npf_conn_t *		cd_list;
 	npf_conn_t *		cd_tail;
 	uint32_t		cd_seed;
+	void *			cd_tree;
 	npf_hashbucket_t	cd_hashtbl[];
 };
 
@@ -138,6 +141,10 @@
 		KASSERT(!rb_tree_iterate(&hb->hb_tree, NULL, RB_DIR_LEFT));
 		rw_destroy(&hb->hb_lock);
 	}
+#ifdef USE_JUDY
+	Word_t bytes;
+	JHSFA(bytes, cd->cd_tree);
+#endif
 	kmem_free(cd, len);
 }
 
@@ -179,6 +186,15 @@
 bool
 npf_conndb_insert(npf_conndb_t *cd, npf_connkey_t *key, npf_conn_t *con)
 {
+#ifdef USE_JUDY
+	PWord_t pval;
+
+	JHSI(pval, cd->cd_tree, key, NPF_CONN_KEYLEN(key));
+	if (pval == PJERR || *pval != 0)
+		return false;
+	*pval = (uintptr_t)key;
+	return true;
+#else
 	npf_hashbucket_t *hb = conndb_hash_bucket(cd, key);
 	bool ok;
 
@@ -187,6 +203,7 @@
 	hb->hb_count += (u_int)ok;
 	rw_exit(&hb->hb_lock);
 	return ok;
+#endif
 }
 
 /*
@@ -194,8 +211,14 @@
  * it represents.
  */
 npf_conn_t *
-npf_conndb_remove(npf_conndb_t *cd, const npf_connkey_t *key)
+npf_conndb_remove(npf_conndb_t *cd, npf_connkey_t *key)
 {
+#ifdef USE_JUDY
+	PWord_t rc;
+
+	JHSD(rc, cd->cd_tree, key, NPF_CONN_KEYLEN(key));
+	return rc ? key->ck_backptr : NULL;
+#else
 	npf_hashbucket_t *hb = conndb_hash_bucket(cd, key);
 	npf_connkey_t *foundkey;
 	npf_conn_t *con;
@@ -210,6 +233,7 @@
 	}
 	rw_exit(&hb->hb_lock);
 	return con;
+#endif
 }
 
 /*
--- a/sys/net/npf/npf_ctl.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_ctl.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ctl.c,v 1.44 2016/12/10 05:41:10 christos Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.45 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -36,8 +36,9 @@
  * NPF proplib(9) dictionary consumer.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.44 2016/12/10 05:41:10 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.45 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -45,6 +46,7 @@
 #include <net/bpf.h>
 
 #include <prop/proplib.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
@@ -53,6 +55,7 @@
 	prop_dictionary_set_cstring_nocopy((e), "source-file", __FILE__); \
 	prop_dictionary_set_uint32((e), "source-line", __LINE__);
 
+#ifdef _KERNEL
 /*
  * npfctl_switch: enable or disable packet inspection.
  */
@@ -72,6 +75,7 @@
 	}
 	return error;
 }
+#endif
 
 static int __noinline
 npf_mk_table_entries(npf_table_t *t, prop_array_t entries)
@@ -121,7 +125,7 @@
 	while ((tbldict = prop_object_iterator_next(it)) != NULL) {
 		const char *name;
 		npf_table_t *t;
-		u_int tid;
+		uint64_t tid;
 		int type;
 
 		/* Table - dictionary. */
@@ -137,9 +141,9 @@
 			error = EINVAL;
 			break;
 		}
-		prop_dictionary_get_uint32(tbldict, "id", &tid);
+		prop_dictionary_get_uint64(tbldict, "id", &tid);
 		prop_dictionary_get_int32(tbldict, "type", &type);
-		error = npf_table_check(tblset, name, tid, type);
+		error = npf_table_check(tblset, name, (u_int)tid, type);
 		if (error) {
 			NPF_ERR_DEBUG(errdict);
 			break;
@@ -161,7 +165,7 @@
 		}
 
 		/* Create and insert the table. */
-		t = npf_table_create(name, tid, type, blob, size);
+		t = npf_table_create(name, (u_int)tid, type, blob, size);
 		if (t == NULL) {
 			NPF_ERR_DEBUG(errdict);
 			error = ENOMEM;
@@ -183,7 +187,7 @@
 }
 
 static npf_rproc_t *
-npf_mk_singlerproc(prop_dictionary_t rpdict)
+npf_mk_singlerproc(npf_t *npf, prop_dictionary_t rpdict)
 {
 	prop_object_iterator_t it;
 	prop_dictionary_t extdict;
@@ -204,8 +208,8 @@
 	while ((extdict = prop_object_iterator_next(it)) != NULL) {
 		const char *name;
 
-		if (!prop_dictionary_get_cstring_nocopy(extdict,
-		    "name", &name) || npf_ext_construct(name, rp, extdict)) {
+		if (!prop_dictionary_get_cstring_nocopy(extdict, "name",
+		    &name) || npf_ext_construct(npf, name, rp, extdict)) {
 			npf_rproc_release(rp);
 			rp = NULL;
 			break;
@@ -216,7 +220,7 @@
 }
 
 static int __noinline
-npf_mk_rprocs(npf_rprocset_t *rpset, prop_array_t rprocs,
+npf_mk_rprocs(npf_t *npf, npf_rprocset_t *rpset, prop_array_t rprocs,
     prop_dictionary_t errdict)
 {
 	prop_object_iterator_t it;
@@ -227,7 +231,7 @@
 	while ((rpdict = prop_object_iterator_next(it)) != NULL) {
 		npf_rproc_t *rp;
 
-		if ((rp = npf_mk_singlerproc(rpdict)) == NULL) {
+		if ((rp = npf_mk_singlerproc(npf, rpdict)) == NULL) {
 			NPF_ERR_DEBUG(errdict);
 			error = EINVAL;
 			break;
@@ -239,17 +243,17 @@
 }
 
 static npf_alg_t *
-npf_mk_singlealg(prop_dictionary_t aldict)
+npf_mk_singlealg(npf_t *npf, prop_dictionary_t aldict)
 {
 	const char *name;
 
 	if (!prop_dictionary_get_cstring_nocopy(aldict, "name", &name))
 		return NULL;
-	return npf_alg_construct(name);
+	return npf_alg_construct(npf, name);
 }
 
 static int __noinline
-npf_mk_algs(prop_array_t alglist, prop_dictionary_t errdict)
+npf_mk_algs(npf_t *npf, prop_array_t alglist, prop_dictionary_t errdict)
 {
 	prop_object_iterator_t it;
 	prop_dictionary_t nadict;
@@ -257,7 +261,7 @@
 
 	it = prop_array_iterator(alglist);
 	while ((nadict = prop_object_iterator_next(it)) != NULL) {
-		if (npf_mk_singlealg(nadict) == NULL) {
+		if (npf_mk_singlealg(npf, nadict) == NULL) {
 			NPF_ERR_DEBUG(errdict);
 			error = EINVAL;
 			break;
@@ -296,7 +300,7 @@
 }
 
 static int __noinline
-npf_mk_singlerule(prop_dictionary_t rldict, npf_rprocset_t *rpset,
+npf_mk_singlerule(npf_t *npf, prop_dictionary_t rldict, npf_rprocset_t *rpset,
     npf_rule_t **rlret, prop_dictionary_t errdict)
 {
 	npf_rule_t *rl;
@@ -309,7 +313,7 @@
 		NPF_ERR_DEBUG(errdict);
 		return EINVAL;
 	}
-	if ((rl = npf_rule_alloc(rldict)) == NULL) {
+	if ((rl = npf_rule_alloc(npf, rldict)) == NULL) {
 		NPF_ERR_DEBUG(errdict);
 		return EINVAL;
 	}
@@ -349,13 +353,13 @@
 err:
 	npf_rule_free(rl);
 	prop_dictionary_get_int32(rldict, "prio", &p); /* XXX */
-	prop_dictionary_set_int32(errdict, "id", p);
+	prop_dictionary_set_int64(errdict, "id", p);
 	return error;
 }
 
 static int __noinline
-npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules, npf_rprocset_t *rpset,
-    prop_dictionary_t errdict)
+npf_mk_rules(npf_t *npf, npf_ruleset_t *rlset, prop_array_t rules,
+    npf_rprocset_t *rpset, prop_dictionary_t errdict)
 {
 	prop_object_iterator_t it;
 	prop_dictionary_t rldict;
@@ -372,7 +376,7 @@
 		npf_rule_t *rl = NULL;
 
 		/* Generate a single rule. */
-		error = npf_mk_singlerule(rldict, rpset, &rl, errdict);
+		error = npf_mk_singlerule(npf, rldict, rpset, &rl, errdict);
 		if (error) {
 			break;
 		}
@@ -386,7 +390,7 @@
 }
 
 static int __noinline
-npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist,
+npf_mk_natlist(npf_t *npf, npf_ruleset_t *nset, prop_array_t natlist,
     prop_dictionary_t errdict)
 {
 	prop_object_iterator_t it;
@@ -416,7 +420,7 @@
 		 * NAT policies are standard rules, plus additional
 		 * information for translation.  Make a rule.
 		 */
-		error = npf_mk_singlerule(natdict, NULL, &rl, errdict);
+		error = npf_mk_singlerule(npf, natdict, NULL, &rl, errdict);
 		if (error) {
 			break;
 		}
@@ -429,7 +433,7 @@
 		}
 
 		/* Allocate a new NAT policy and assign to the rule. */
-		np = npf_nat_newpolicy(natdict, nset);
+		np = npf_nat_newpolicy(npf, natdict, nset);
 		if (np == NULL) {
 			NPF_ERR_DEBUG(errdict);
 			error = ENOMEM;
@@ -449,7 +453,7 @@
  * npf_mk_connlist: import a list of connections and load them.
  */
 static int __noinline
-npf_mk_connlist(prop_array_t conlist, npf_ruleset_t *natlist,
+npf_mk_connlist(npf_t *npf, prop_array_t conlist, npf_ruleset_t *natlist,
     npf_conndb_t **conndb, prop_dictionary_t errdict)
 {
 	prop_dictionary_t condict;
@@ -474,7 +478,7 @@
 			break;
 		}
 		/* Construct and insert the connection. */
-		error = npf_conn_import(cd, condict, natlist);
+		error = npf_conn_import(npf, cd, condict, natlist);
 		if (error) {
 			NPF_ERR_DEBUG(errdict);
 			break;
@@ -482,7 +486,7 @@
 	}
 	prop_object_iterator_release(it);
 	if (error) {
-		npf_conn_gc(cd, true, false);
+		npf_conn_gc(npf, cd, true, false);
 		npf_conndb_destroy(cd);
 	} else {
 		*conndb = cd;
@@ -495,7 +499,7 @@
  * tables, rules and atomically activate all them.
  */
 int
-npfctl_load(u_long cmd, void *data)
+npfctl_load(npf_t *npf, u_long cmd, void *data)
 {
 	struct plistref *pref = data;
 	prop_dictionary_t npf_dict, errdict;
@@ -511,7 +515,7 @@
 	int error;
 
 	/* Retrieve the dictionary. */
-#ifndef _NPF_TESTING
+#if !defined(_NPF_TESTING) && !defined(_NPF_STANDALONE)
 	error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict);
 	if (error)
 		return error;
@@ -529,7 +533,7 @@
 
 	/* ALGs. */
 	alglist = prop_dictionary_get(npf_dict, "algs");
-	error = npf_mk_algs(alglist, errdict);
+	error = npf_mk_algs(npf, alglist, errdict);
 	if (error) {
 		goto fail;
 	}
@@ -542,7 +546,7 @@
 	}
 
 	nset = npf_ruleset_create(nitems);
-	error = npf_mk_natlist(nset, natlist, errdict);
+	error = npf_mk_natlist(npf, nset, natlist, errdict);
 	if (error) {
 		goto fail;
 	}
@@ -566,7 +570,7 @@
 		goto fail;
 	}
 	rpset = npf_rprocset_create();
-	error = npf_mk_rprocs(rpset, rprocs, errdict);
+	error = npf_mk_rprocs(npf, rpset, rprocs, errdict);
 	if (error) {
 		goto fail;
 	}
@@ -579,14 +583,14 @@
 	}
 
 	rlset = npf_ruleset_create(nitems);
-	error = npf_mk_rules(rlset, rules, rpset, errdict);
+	error = npf_mk_rules(npf, rlset, rules, rpset, errdict);
 	if (error) {
 		goto fail;
 	}
 
 	/* Connections (if loading any). */
 	if ((conlist = prop_dictionary_get(npf_dict, "conn-list")) != NULL) {
-		error = npf_mk_connlist(conlist, nset, &conndb, errdict);
+		error = npf_mk_connlist(npf, conlist, nset, &conndb, errdict);
 		if (error) {
 			goto fail;
 		}
@@ -598,7 +602,7 @@
 	/*
 	 * Finally - perform the load.
 	 */
-	npf_config_load(rlset, tblset, nset, rpset, conndb, flush);
+	npf_config_load(npf, rlset, tblset, nset, rpset, conndb, flush);
 
 	/* Done.  Since data is consumed now, we shall not destroy it. */
 	tblset = NULL;
@@ -624,7 +628,7 @@
 	prop_object_release(npf_dict);
 
 	/* Error report. */
-#ifndef _NPF_TESTING
+#if !defined(_NPF_TESTING) && !defined(_NPF_STANDALONE)
 	prop_dictionary_set_int32(errdict, "errno", error);
 	prop_dictionary_copyout_ioctl(pref, cmd, errdict);
 	prop_object_release(errdict);
@@ -639,7 +643,7 @@
  * indicate whether the ruleset is currently active.
  */
 int
-npfctl_save(u_long cmd, void *data)
+npfctl_save(npf_t *npf, u_long cmd, void *data)
 {
 	struct plistref *pref = data;
 	prop_array_t rulelist, natlist, tables, rprocs, conlist;
@@ -655,28 +659,28 @@
 	/*
 	 * Serialise the connections and NAT policies.
 	 */
-	npf_config_enter();
-	error = npf_conndb_export(conlist);
+	npf_config_enter(npf);
+	error = npf_conndb_export(npf, conlist);
 	if (error) {
 		goto out;
 	}
-	error = npf_ruleset_export(npf_config_ruleset(), rulelist);
+	error = npf_ruleset_export(npf, npf_config_ruleset(npf), rulelist);
 	if (error) {
 		goto out;
 	}
-	error = npf_ruleset_export(npf_config_natset(), natlist);
+	error = npf_ruleset_export(npf, npf_config_natset(npf), natlist);
 	if (error) {
 		goto out;
 	}
-	error = npf_tableset_export(npf_config_tableset(), tables);
+	error = npf_tableset_export(npf, npf_config_tableset(npf), tables);
 	if (error) {
 		goto out;
 	}
-	error = npf_rprocset_export(npf_config_rprocs(), rprocs);
+	error = npf_rprocset_export(npf_config_rprocs(npf), rprocs);
 	if (error) {
 		goto out;
 	}
-	prop_array_t alglist = npf_alg_export();
+	prop_array_t alglist = npf_alg_export(npf);
 
 	npf_dict = prop_dictionary_create();
 	prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION);
@@ -686,10 +690,17 @@
 	prop_dictionary_set_and_rel(npf_dict, "tables", tables);
 	prop_dictionary_set_and_rel(npf_dict, "rprocs", rprocs);
 	prop_dictionary_set_and_rel(npf_dict, "conn-list", conlist);
+#if !defined(_NPF_STANDALONE)
 	prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p());
 	error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict);
+#else
+	prop_dictionary_set_bool(npf_dict, "active", true);
+	/* Userspace: just copy the pointer of the dictionary. */
+	CTASSERT(sizeof(prop_dictionary_t) == sizeof(void *));
+	memcpy(data, npf_dict, sizeof(void *));
+#endif
 out:
-	npf_config_exit();
+	npf_config_exit(npf);
 
 	if (!npf_dict) {
 		prop_object_release(rulelist);
@@ -698,7 +709,9 @@
 		prop_object_release(rprocs);
 		prop_object_release(conlist);
 	} else {
+#if !defined(_NPF_STANDALONE)
 		prop_object_release(npf_dict);
+#endif
 	}
 	return error;
 }
@@ -707,23 +720,31 @@
  * npfctl_conn_lookup: lookup a connection in the list of connections
  */
 int
-npfctl_conn_lookup(u_long cmd, void *data)
+npfctl_conn_lookup(npf_t *npf, u_long cmd, void *data)
 {
 	struct plistref *pref = data;
 	prop_dictionary_t conn_data, conn_result;
 	int error;
 
+#if !defined(_NPF_STANDALONE)
 	error = prop_dictionary_copyin_ioctl(pref, cmd, &conn_data);
 	if (error) {
 		return error;
 	}
-
-	error = npf_conn_find(conn_data, &conn_result);
+#else
+	conn_data = (prop_dictionary_t)pref;
+#endif
+	error = npf_conn_find(npf, conn_data, &conn_result);
 	if (error) {
 		goto out;
 	}
+#if !defined(_NPF_STANDALONE)
 	prop_dictionary_copyout_ioctl(pref, cmd, conn_result);
 	prop_object_release(conn_result);
+#else
+	CTASSERT(sizeof(prop_dictionary_t) == sizeof(void *));
+	memcpy(data, conn_result, sizeof(void *));
+#endif
 out:
 	prop_object_release(conn_data);
 	return error;
@@ -733,7 +754,7 @@
  * npfctl_rule: add or remove dynamic rules in the specified ruleset.
  */
 int
-npfctl_rule(u_long cmd, void *data)
+npfctl_rule(npf_t *npf, u_long cmd, void *data)
 {
 	struct plistref *pref = data;
 	prop_dictionary_t npf_rule, retdict = NULL;
@@ -741,12 +762,16 @@
 	npf_rule_t *rl = NULL;
 	const char *ruleset_name;
 	uint32_t rcmd = 0;
-	int error;
+	int error = 0;
 
+#if !defined(_NPF_STANDALONE)
 	error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_rule);
 	if (error) {
 		return error;
 	}
+#else
+	npf_rule = (prop_dictionary_t)pref;
+#endif
 	prop_dictionary_get_uint32(npf_rule, "command", &rcmd);
 	if (!prop_dictionary_get_cstring_nocopy(npf_rule,
 	    "ruleset-name", &ruleset_name)) {
@@ -756,14 +781,14 @@
 
 	if (rcmd == NPF_CMD_RULE_ADD) {
 		retdict = prop_dictionary_create();
-		if (npf_mk_singlerule(npf_rule, NULL, &rl, retdict) != 0) {
+		if (npf_mk_singlerule(npf, npf_rule, NULL, &rl, retdict) != 0) {
 			error = EINVAL;
 			goto out;
 		}
 	}
 
-	npf_config_enter();
-	rlset = npf_config_ruleset();
+	npf_config_enter(npf);
+	rlset = npf_config_ruleset(npf);
 
 	switch (rcmd) {
 	case NPF_CMD_RULE_ADD: {
@@ -798,7 +823,7 @@
 		break;
 	}
 	case NPF_CMD_RULE_LIST: {
-		retdict = npf_ruleset_list(rlset, ruleset_name);
+		retdict = npf_ruleset_list(npf, rlset, ruleset_name);
 		if (!retdict) {
 			error = ESRCH;
 		}
@@ -815,10 +840,10 @@
 
 	/* Destroy any removed rules. */
 	if (!error && rcmd != NPF_CMD_RULE_ADD && rcmd != NPF_CMD_RULE_LIST) {
-		npf_config_sync();
+		npf_config_sync(npf);
 		npf_ruleset_gc(rlset);
 	}
-	npf_config_exit();
+	npf_config_exit(npf);
 
 	if (rl) {
 		KASSERT(error);
@@ -827,8 +852,13 @@
 out:
 	if (retdict) {
 		prop_object_release(npf_rule);
+#if !defined(_NPF_STANDALONE)
 		prop_dictionary_copyout_ioctl(pref, cmd, retdict);
 		prop_object_release(retdict);
+#else
+		CTASSERT(sizeof(prop_dictionary_t) == sizeof(void *));
+		memcpy(data, npf_rule, sizeof(void *));
+#endif
 	}
 	return error;
 }
@@ -839,7 +869,7 @@
  * For maximum performance, interface is avoiding proplib(3)'s overhead.
  */
 int
-npfctl_table(void *data)
+npfctl_table(npf_t *npf, void *data)
 {
 	const npf_ioctl_table_t *nct = data;
 	char tname[NPF_TABLE_MAXNAMELEN];
@@ -853,7 +883,7 @@
 	}
 
 	s = npf_config_read_enter(); /* XXX */
-	ts = npf_config_tableset();
+	ts = npf_config_tableset(npf);
 	if ((t = npf_tableset_getbyname(ts, tname)) == NULL) {
 		npf_config_read_exit(s);
 		return EINVAL;
--- a/sys/net/npf/npf_ext_log.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_ext_log.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ext_log.c,v 1.9 2016/06/16 03:03:33 ozaki-r Exp $	*/
+/*	$NetBSD: npf_ext_log.c,v 1.10 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF logging extension.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ext_log.c,v 1.9 2016/06/16 03:03:33 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ext_log.c,v 1.10 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/module.h>
@@ -48,6 +49,7 @@
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/bpf.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -83,9 +85,9 @@
 {
 	struct mbuf *m = nbuf_head_mbuf(npc->npc_nbuf);
 	const npf_ext_log_t *log = meta;
+	struct psref psref;
 	ifnet_t *ifp;
 	int family;
-	struct psref psref;
 
 	/* Set the address family. */
 	if (npf_iscached(npc, NPC_IP4)) {
@@ -111,6 +113,7 @@
 	ifp->if_obytes += m->m_pkthdr.len;
 	bpf_mtap_af(ifp, family, m);
 	if_put(ifp, &psref);
+
 	KERNEL_UNLOCK_ONE(NULL);
 
 	return true;
@@ -129,6 +132,7 @@
 		.dtor		= npf_log_dtor,
 		.proc		= npf_log
 	};
+	npf_t *npf = npf_getkernctx();
 	int error;
 
 	switch (cmd) {
@@ -136,14 +140,14 @@
 		/*
 		 * Initialise the NPF logging extension.
 		 */
-		npf_ext_log_id = npf_ext_register("log", &npf_log_ops);
+		npf_ext_log_id = npf_ext_register(npf, "log", &npf_log_ops);
 		if (!npf_ext_log_id) {
 			return EEXIST;
 		}
 		break;
 
 	case MODULE_CMD_FINI:
-		error = npf_ext_unregister(npf_ext_log_id);
+		error = npf_ext_unregister(npf, npf_ext_log_id);
 		if (error) {
 			return error;
 		}
--- a/sys/net/npf/npf_ext_normalize.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_ext_normalize.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ext_normalize.c,v 1.3 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_ext_normalize.c,v 1.4 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -26,8 +26,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ext_normalize.c,v 1.3 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ext_normalize.c,v 1.4 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/module.h>
@@ -37,6 +38,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#endif
 
 #include "npf.h"
 #include "npf_impl.h"
@@ -196,6 +198,7 @@
 		.dtor		= npf_normalize_dtor,
 		.proc		= npf_normalize
 	};
+	npf_t *npf = npf_getkernctx();
 
 	switch (cmd) {
 	case MODULE_CMD_INIT:
@@ -204,12 +207,12 @@
 		 * extension and its calls.
 		 */
 		npf_ext_normalize_id =
-		    npf_ext_register("normalize", &npf_normalize_ops);
+		    npf_ext_register(npf, "normalize", &npf_normalize_ops);
 		return npf_ext_normalize_id ? 0 : EEXIST;
 
 	case MODULE_CMD_FINI:
 		/* Unregister the normalisation rule procedure. */
-		return npf_ext_unregister(npf_ext_normalize_id);
+		return npf_ext_unregister(npf, npf_ext_normalize_id);
 
 	case MODULE_CMD_AUTOUNLOAD:
 		return npf_autounload_p() ? 0 : EBUSY;
--- a/sys/net/npf/npf_ext_rndblock.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_ext_rndblock.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ext_rndblock.c,v 1.5 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_ext_rndblock.c,v 1.6 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -31,16 +31,18 @@
  * This is also a demo extension.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ext_rndblock.c,v 1.5 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ext_rndblock.c,v 1.6 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/cprng.h>
 #include <sys/atomic.h>
 #include <sys/module.h>
 #include <sys/kmem.h>
+#endif
 
-#include "npf.h"
+#include "npf_impl.h"
 
 /*
  * NPF extension module definition and the identifier.
@@ -146,6 +148,7 @@
 		.dtor		= npf_ext_rndblock_dtor,
 		.proc		= npf_ext_rndblock
 	};
+	npf_t *npf = npf_getkernctx();
 
 	switch (cmd) {
 	case MODULE_CMD_INIT:
@@ -154,7 +157,7 @@
 		 * "rndblock" extensions calls (constructor, destructor,
 		 * the processing * routine, etc).
 		 */
-		npf_ext_rndblock_id = npf_ext_register("rndblock",
+		npf_ext_rndblock_id = npf_ext_register(npf, "rndblock",
 		    &npf_rndblock_ops);
 		return npf_ext_rndblock_id ? 0 : EEXIST;
 
@@ -163,7 +166,7 @@
 		 * Unregister our rndblock extension.  NPF may return an
 		 * if there are references and it cannot drain them.
 		 */
-		return npf_ext_unregister(npf_ext_rndblock_id);
+		return npf_ext_unregister(npf, npf_ext_rndblock_id);
 
 	case MODULE_CMD_AUTOUNLOAD:
 		/* Allow auto-unload only if NPF permits it. */
--- a/sys/net/npf/npf_handler.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_handler.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_handler.c,v 1.34 2016/12/08 23:07:11 rmind Exp $	*/
+/*	$NetBSD: npf_handler.c,v 1.35 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -35,8 +35,9 @@
  * Note: pfil(9) hooks are currently locked by softnet_lock and kernel-lock.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.34 2016/12/08 23:07:11 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.35 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -52,42 +53,24 @@
 #include <netinet/ip_var.h>
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
 
-static bool		pfil_registered = false;
-static pfil_head_t *	npf_ph_if = NULL;
-static pfil_head_t *	npf_ph_inet = NULL;
-static pfil_head_t *	npf_ph_inet6 = NULL;
+#if defined(_NPF_STANDALONE)
+#define	m_freem(m)		npf->mbufops->free(m)
+#define	m_clear_flag(m,f)
+#else
+#define	m_clear_flag(m,f)	(m)->m_flags &= ~(f)
+#endif
 
 #ifndef INET6
 #define ip6_reass_packet(x, y)	ENOTSUP
 #endif
 
-/*
- * npf_ifhook: hook handling interface changes.
- */
 static int
-npf_ifhook(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
-{
-	u_long cmd = (u_long)mp;
-
-	if (di == PFIL_IFNET) {
-		switch (cmd) {
-		case PFIL_IFNET_ATTACH:
-			npf_ifmap_attach(ifp);
-			break;
-		case PFIL_IFNET_DETACH:
-			npf_ifmap_detach(ifp);
-			break;
-		}
-	}
-	return 0;
-}
-
-static int
-npf_reassembly(npf_cache_t *npc, struct mbuf **mp)
+npf_reassembly(npf_t *npf, npf_cache_t *npc, struct mbuf **mp)
 {
 	nbuf_t *nbuf = npc->npc_nbuf;
 	int error = EINVAL;
@@ -110,12 +93,12 @@
 		}
 	}
 	if (error) {
-		npf_stats_inc(NPF_STAT_REASSFAIL);
+		npf_stats_inc(npf, NPF_STAT_REASSFAIL);
 		return error;
 	}
 	if (*mp == NULL) {
 		/* More fragments should come. */
-		npf_stats_inc(NPF_STAT_FRAGMENTS);
+		npf_stats_inc(npf, NPF_STAT_FRAGMENTS);
 		return 0;
 	}
 
@@ -123,13 +106,13 @@
 	 * Reassembly is complete, we have the final packet.
 	 * Cache again, since layer 4 data is accessible now.
 	 */
-	nbuf_init(nbuf, *mp, nbuf->nb_ifp);
+	nbuf_init(npf, nbuf, *mp, nbuf->nb_ifp);
 	npc->npc_info = 0;
 
 	if (npf_cache_all(npc) & NPC_IPFRAG) {
 		return EINVAL;
 	}
-	npf_stats_inc(NPF_STAT_REASSEMBLY);
+	npf_stats_inc(npf, NPF_STAT_REASSEMBLY);
 	return 0;
 }
 
@@ -138,8 +121,8 @@
  *
  * Note: packet flow and inspection logic is in strict order.
  */
-int
-npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
+__dso_public int
+npf_packet_handler(npf_t *npf, struct mbuf **mp, ifnet_t *ifp, int di)
 {
 	nbuf_t nbuf;
 	npf_cache_t npc;
@@ -150,12 +133,16 @@
 	uint32_t ntag;
 	int decision;
 
+	/* QSBR checkpoint. */
+	pserialize_checkpoint(npf->qsbr);
+	KASSERT(ifp != NULL);
+
 	/*
 	 * Initialise packet information cache.
 	 * Note: it is enough to clear the info bits.
 	 */
-	KASSERT(ifp != NULL);
-	nbuf_init(&nbuf, *mp, ifp);
+	npc.npc_ctx = npf;
+	nbuf_init(npf, &nbuf, *mp, ifp);
 	npc.npc_nbuf = &nbuf;
 	npc.npc_info = 0;
 
@@ -169,7 +156,7 @@
 		/*
 		 * Pass to IPv4 or IPv6 reassembly mechanism.
 		 */
-		error = npf_reassembly(&npc, mp);
+		error = npf_reassembly(npf, &npc, mp);
 		if (error) {
 			con = NULL;
 			goto out;
@@ -191,7 +178,7 @@
 
 	/* If "passing" connection found - skip the ruleset inspection. */
 	if (con && npf_conn_pass(con, &rp)) {
-		npf_stats_inc(NPF_STAT_PASS_CONN);
+		npf_stats_inc(npf, NPF_STAT_PASS_CONN);
 		KASSERT(error == 0);
 		goto pass;
 	}
@@ -203,18 +190,18 @@
 
 	/* Acquire the lock, inspect the ruleset using this packet. */
 	int slock = npf_config_read_enter();
-	npf_ruleset_t *rlset = npf_config_ruleset();
+	npf_ruleset_t *rlset = npf_config_ruleset(npf);
 
 	rl = npf_ruleset_inspect(&npc, rlset, di, NPF_LAYER_3);
 	if (__predict_false(rl == NULL)) {
-		const bool pass = npf_default_pass();
+		const bool pass = npf_default_pass(npf);
 		npf_config_read_exit(slock);
 
 		if (pass) {
-			npf_stats_inc(NPF_STAT_PASS_DEFAULT);
+			npf_stats_inc(npf, NPF_STAT_PASS_DEFAULT);
 			goto pass;
 		}
-		npf_stats_inc(NPF_STAT_BLOCK_DEFAULT);
+		npf_stats_inc(npf, NPF_STAT_BLOCK_DEFAULT);
 		goto block;
 	}
 
@@ -230,10 +217,10 @@
 	npf_config_read_exit(slock);
 
 	if (error) {
-		npf_stats_inc(NPF_STAT_BLOCK_RULESET);
+		npf_stats_inc(npf, NPF_STAT_BLOCK_RULESET);
 		goto block;
 	}
-	npf_stats_inc(NPF_STAT_PASS_RULESET);
+	npf_stats_inc(npf, NPF_STAT_PASS_RULESET);
 
 	/*
 	 * Establish a "pass" connection, if required.  Just proceed if
@@ -293,7 +280,7 @@
 		 * XXX: Disable for now, it will be set accordingly later,
 		 * for optimisations (to reduce inspection).
 		 */
-		(*mp)->m_flags &= ~M_CANFASTFWD;
+		m_clear_flag(*mp, M_CANFASTFWD);
 		return 0;
 	}
 
@@ -311,100 +298,9 @@
 	}
 
 	if (*mp) {
+		/* Free the mbuf chain. */
 		m_freem(*mp);
 		*mp = NULL;
 	}
 	return error;
 }
-
-/*
- * npf_pfil_register: register pfil(9) hooks.
- */
-int
-npf_pfil_register(bool init)
-{
-	int error = 0;
-
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-
-	/* Init: interface re-config and attach/detach hook. */
-	if (!npf_ph_if) {
-		npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
-		if (!npf_ph_if) {
-			error = ENOENT;
-			goto out;
-		}
-		error = pfil_add_hook(npf_ifhook, NULL,
-		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
-		KASSERT(error == 0);
-	}
-	if (init) {
-		goto out;
-	}
-
-	/* Check if pfil hooks are not already registered. */
-	if (pfil_registered) {
-		error = EEXIST;
-		goto out;
-	}
-
-	/* Capture points of the activity in the IP layer. */
-	npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
-	npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
-	if (!npf_ph_inet && !npf_ph_inet6) {
-		error = ENOENT;
-		goto out;
-	}
-
-	/* Packet IN/OUT handlers for IP layer. */
-	if (npf_ph_inet) {
-		error = pfil_add_hook(npf_packet_handler, NULL,
-		    PFIL_ALL, npf_ph_inet);
-		KASSERT(error == 0);
-	}
-	if (npf_ph_inet6) {
-		error = pfil_add_hook(npf_packet_handler, NULL,
-		    PFIL_ALL, npf_ph_inet6);
-		KASSERT(error == 0);
-	}
-	pfil_registered = true;
-out:
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-
-	return error;
-}
-
-/*
- * npf_pfil_unregister: unregister pfil(9) hooks.
- */
-void
-npf_pfil_unregister(bool fini)
-{
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-
-	if (fini && npf_ph_if) {
-		(void)pfil_remove_hook(npf_ifhook, NULL,
-		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
-	}
-	if (npf_ph_inet) {
-		(void)pfil_remove_hook(npf_packet_handler, NULL,
-		    PFIL_ALL, npf_ph_inet);
-	}
-	if (npf_ph_inet6) {
-		(void)pfil_remove_hook(npf_packet_handler, NULL,
-		    PFIL_ALL, npf_ph_inet6);
-	}
-	pfil_registered = false;
-
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-}
-
-bool
-npf_pfil_registered_p(void)
-{
-	return pfil_registered;
-}
--- a/sys/net/npf/npf_if.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_if.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_if.c,v 1.6 2016/05/12 02:24:17 ozaki-r Exp $	*/
+/*	$NetBSD: npf_if.c,v 1.7 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -44,54 +44,65 @@
  * monitored using pfil(9) hooks.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.6 2016/05/12 02:24:17 ozaki-r Exp $");
-
-#ifdef _KERNEL_OPT
-#include "pf.h"
-#if NPF > 0
-#error "NPF and PF are mutually exclusive; please select one"
-#endif
-#endif
+__KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.7 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/kmem.h>
-
 #include <net/if.h>
+#endif
 
 #include "npf_impl.h"
 
-typedef struct {
+typedef struct npf_ifmap {
 	char		n_ifname[IFNAMSIZ];
 } npf_ifmap_t;
 
-static npf_ifmap_t	npf_ifmap[NPF_MAX_IFMAP]	__read_mostly;
-static u_int		npf_ifmap_cnt			__read_mostly;
+void
+npf_ifmap_init(npf_t *npf, const npf_ifops_t *ifops)
+{
+	const size_t nbytes = sizeof(npf_ifmap_t) * NPF_MAX_IFMAP;
+
+	KASSERT(ifops != NULL);
+	ifops->flush((void *)(uintptr_t)0);
+
+	npf->ifmap = kmem_zalloc(nbytes, KM_SLEEP);
+	npf->ifmap_cnt = 0;
+	npf->ifops = ifops;
+}
+
+void
+npf_ifmap_fini(npf_t *npf)
+{
+	const size_t nbytes = sizeof(npf_ifmap_t) * NPF_MAX_IFMAP;
+	kmem_free(npf->ifmap, nbytes);
+}
 
 static u_int
-npf_ifmap_new(void)
+npf_ifmap_new(npf_t *npf)
 {
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
-	for (u_int i = 0; i < npf_ifmap_cnt; i++)
-		if (npf_ifmap[i].n_ifname[0] == '\0')
+	for (u_int i = 0; i < npf->ifmap_cnt; i++)
+		if (npf->ifmap[i].n_ifname[0] == '\0')
 			return i + 1;
 
-	if (npf_ifmap_cnt == NPF_MAX_IFMAP) {
+	if (npf->ifmap_cnt == NPF_MAX_IFMAP) {
 		printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n");
 		return 0;
 	}
-	return ++npf_ifmap_cnt;
+	return ++npf->ifmap_cnt;
 }
 
 static u_int
-npf_ifmap_lookup(const char *ifname)
+npf_ifmap_lookup(npf_t *npf, const char *ifname)
 {
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
-	for (u_int i = 0; i < npf_ifmap_cnt; i++) {
-		npf_ifmap_t *nim = &npf_ifmap[i];
+	for (u_int i = 0; i < npf->ifmap_cnt; i++) {
+		npf_ifmap_t *nim = &npf->ifmap[i];
 
 		if (nim->n_ifname[0] && strcmp(nim->n_ifname, ifname) == 0)
 			return i + 1;
@@ -100,87 +111,80 @@
 }
 
 u_int
-npf_ifmap_register(const char *ifname)
+npf_ifmap_register(npf_t *npf, const char *ifname)
 {
 	npf_ifmap_t *nim;
 	ifnet_t *ifp;
 	u_int i;
 
-	npf_config_enter();
-	if ((i = npf_ifmap_lookup(ifname)) != 0) {
+	npf_config_enter(npf);
+	if ((i = npf_ifmap_lookup(npf, ifname)) != 0) {
 		goto out;
 	}
-	if ((i = npf_ifmap_new()) == 0) {
+	if ((i = npf_ifmap_new(npf)) == 0) {
 		goto out;
 	}
-	nim = &npf_ifmap[i - 1];
+	nim = &npf->ifmap[i - 1];
 	strlcpy(nim->n_ifname, ifname, IFNAMSIZ);
 
-	KERNEL_LOCK(1, NULL);
-	if ((ifp = ifunit(ifname)) != NULL) {
-		ifp->if_pf_kif = (void *)(uintptr_t)i;
+	if ((ifp = npf->ifops->lookup(ifname)) != NULL) {
+		npf->ifops->setmeta(ifp, (void *)(uintptr_t)i);
 	}
-	KERNEL_UNLOCK_ONE(NULL);
 out:
-	npf_config_exit();
+	npf_config_exit(npf);
 	return i;
 }
 
 void
-npf_ifmap_flush(void)
+npf_ifmap_flush(npf_t *npf)
 {
-	ifnet_t *ifp;
+	KASSERT(npf_config_locked_p(npf));
 
-	KASSERT(npf_config_locked_p());
-
-	for (u_int i = 0; i < npf_ifmap_cnt; i++) {
-		npf_ifmap[i].n_ifname[0] = '\0';
+	for (u_int i = 0; i < npf->ifmap_cnt; i++) {
+		npf->ifmap[i].n_ifname[0] = '\0';
 	}
-	npf_ifmap_cnt = 0;
-
-	KERNEL_LOCK(1, NULL);
-	IFNET_LOCK();
-	IFNET_WRITER_FOREACH(ifp) {
-		ifp->if_pf_kif = (void *)(uintptr_t)0;
-	}
-	IFNET_UNLOCK();
-	KERNEL_UNLOCK_ONE(NULL);
+	npf->ifmap_cnt = 0;
+	npf->ifops->flush((void *)(uintptr_t)0);
 }
 
 u_int
-npf_ifmap_getid(const ifnet_t *ifp)
+npf_ifmap_getid(npf_t *npf, const ifnet_t *ifp)
 {
-	const u_int i = (uintptr_t)ifp->if_pf_kif;
-	KASSERT(i <= npf_ifmap_cnt);
+	const u_int i = (uintptr_t)npf->ifops->getmeta(ifp);
+	KASSERT(i <= npf->ifmap_cnt);
 	return i;
 }
 
 const char *
-npf_ifmap_getname(const u_int id)
+npf_ifmap_getname(npf_t *npf, const u_int id)
 {
 	const char *ifname;
 
-	KASSERT(npf_config_locked_p());
-	KASSERT(id > 0 && id <= npf_ifmap_cnt);
+	KASSERT(npf_config_locked_p(npf));
+	KASSERT(id > 0 && id <= npf->ifmap_cnt);
 
-	ifname = npf_ifmap[id - 1].n_ifname;
+	ifname = npf->ifmap[id - 1].n_ifname;
 	KASSERT(ifname[0] != '\0');
 	return ifname;
 }
 
-void
-npf_ifmap_attach(ifnet_t *ifp)
+__dso_public void
+npf_ifmap_attach(npf_t *npf, ifnet_t *ifp)
 {
-	npf_config_enter();
-	ifp->if_pf_kif = (void *)(uintptr_t)npf_ifmap_lookup(ifp->if_xname);
-	npf_config_exit();
+	const npf_ifops_t *ifops = npf->ifops;
+	u_int i;
+
+	npf_config_enter(npf);
+	i = npf_ifmap_lookup(npf, ifops->getname(ifp));
+	ifops->setmeta(ifp, (void *)(uintptr_t)i);
+	npf_config_exit(npf);
 }
 
-void
-npf_ifmap_detach(ifnet_t *ifp)
+__dso_public void
+npf_ifmap_detach(npf_t *npf, ifnet_t *ifp)
 {
 	/* Diagnostic. */
-	npf_config_enter();
-	ifp->if_pf_kif = (void *)(uintptr_t)0;
-	npf_config_exit();
+	npf_config_enter(npf);
+	npf->ifops->setmeta(ifp, (void *)(uintptr_t)0);
+	npf_config_exit(npf);
 }
--- a/sys/net/npf/npf_impl.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_impl.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.63 2016/12/10 05:41:10 christos Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.64 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
 #ifndef _NPF_IMPL_H_
 #define _NPF_IMPL_H_
 
-#if !defined(_KERNEL)
+#if !defined(_KERNEL) && !defined(_NPF_STANDALONE)
 #error "Kernel-level header only"
 #endif
 
@@ -47,14 +47,18 @@
 #include "opt_inet6.h"
 #endif
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/rbtree.h>
 
 #include <net/bpf.h>
 #include <net/bpfjit.h>
 #include <net/if.h>
+#endif
 
 #include "npf.h"
+#include "npfkern.h"
 
 #ifdef _NPF_DEBUG
 #define	NPF_PRINTF(x)	printf x
@@ -71,6 +75,7 @@
 struct npf_rprocset;
 struct npf_nat;
 struct npf_conn;
+struct npf_config;
 
 typedef struct npf_ruleset	npf_ruleset_t;
 typedef struct npf_rule		npf_rule_t;
@@ -79,30 +84,35 @@
 typedef struct npf_alg		npf_alg_t;
 typedef struct npf_natpolicy	npf_natpolicy_t;
 typedef struct npf_conn		npf_conn_t;
+typedef struct npf_config	npf_config_t;
 
 struct npf_conndb;
 struct npf_table;
 struct npf_tableset;
+struct npf_algset;
+struct npf_ifmap;
 
 typedef struct npf_conndb	npf_conndb_t;
 typedef struct npf_table	npf_table_t;
 typedef struct npf_tableset	npf_tableset_t;
+typedef struct npf_algset	npf_algset_t;
 
 /*
  * DEFINITIONS.
  */
 
-typedef void (*npf_workfunc_t)(void);
+typedef void (*npf_workfunc_t)(npf_t *);
 
 /*
  * Some artificial limits.
  * Note: very unlikely to have many ALGs.
  */
 #define	NPF_MAX_RULES		(1024 * 1024)
-#define	NPF_MAX_ALGS		4
 #define	NPF_MAX_TABLES		128
 #define	NPF_MAX_RPROCS		128
 #define	NPF_MAX_IFMAP		64
+#define	NPF_MAX_ALGS		4
+#define	NPF_MAX_WORKS		4
 
 /*
  * CONNECTION STATE STRUCTURES
@@ -134,59 +144,113 @@
 } npfa_funcs_t;
 
 /*
+ * NBUF STRUCTURE.
+ */
+
+struct nbuf {
+	struct mbuf *	nb_mbuf0;
+	struct mbuf *	nb_mbuf;
+	void *		nb_nptr;
+	const ifnet_t *	nb_ifp;
+	unsigned	nb_ifid;
+	int		nb_flags;
+	const npf_mbufops_t *nb_mops;
+};
+
+/*
+ * NPF INSTANCE (CONTEXT) STRUCTURE AND AUXILIARY OPERATIONS.
+ */
+
+struct npf {
+	/* Active NPF configuration. */
+	kmutex_t		config_lock;
+	pserialize_t		qsbr;
+	npf_config_t *		config;
+
+	/* BPF byte-code context. */
+	bpf_ctx_t *		bpfctx;
+	const npf_mbufops_t *	mbufops;
+
+	/*
+	 * Connection tracking state: disabled (off) or enabled (on).
+	 * Connection tracking database, connection cache and the lock.
+	 */
+	volatile int		conn_tracking;
+	kmutex_t		conn_lock;
+	npf_conndb_t *		conn_db;
+	pool_cache_t		conn_cache;
+
+	/* ALGs. */
+	npf_algset_t *		algset;
+
+	/* Interface mapping. */
+	const npf_ifops_t *	ifops;
+	struct npf_ifmap *	ifmap;
+	unsigned		ifmap_cnt;
+
+	/* Associated worker thread. */
+	unsigned		worker_id;
+	void *			worker_entry;
+
+	/* List of extensions and its lock. */
+	LIST_HEAD(, npf_ext)	ext_list;
+	kmutex_t		ext_lock;
+
+	/* Statistics. */
+	percpu_t *		stats_percpu;
+};
+
+/*
  * INTERFACES.
  */
 
 /* NPF config, statistics, etc. */
-void		npf_config_init(void);
-void		npf_config_fini(void);
+void		npf_config_init(npf_t *);
+void		npf_config_fini(npf_t *);
 
-void		npf_config_enter(void);
-void		npf_config_exit(void);
-void		npf_config_sync(void);
-bool		npf_config_locked_p(void);
+void		npf_config_enter(npf_t *);
+void		npf_config_exit(npf_t *);
+void		npf_config_sync(npf_t *);
+bool		npf_config_locked_p(npf_t *);
 int		npf_config_read_enter(void);
-void		npf_config_read_exit(int);
+void		npf_config_read_exit(int s);
 
-void		npf_config_load(npf_ruleset_t *, npf_tableset_t *,
+void		npf_config_load(npf_t *, npf_ruleset_t *, npf_tableset_t *,
 		    npf_ruleset_t *, npf_rprocset_t *, npf_conndb_t *, bool);
-npf_ruleset_t *	npf_config_ruleset(void);
-npf_ruleset_t *	npf_config_natset(void);
-npf_tableset_t *npf_config_tableset(void);
-npf_rprocset_t *npf_config_rprocs(void);
-bool		npf_default_pass(void);
+npf_ruleset_t *	npf_config_ruleset(npf_t *npf);
+npf_ruleset_t *	npf_config_natset(npf_t *npf);
+npf_tableset_t *npf_config_tableset(npf_t *npf);
+npf_rprocset_t *npf_config_rprocs(npf_t *);
+bool		npf_default_pass(npf_t *);
 
-int		npf_worker_sysinit(void);
+int		npf_worker_sysinit(unsigned);
 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		npf_worker_signal(npf_t *);
+void		npf_worker_register(npf_t *, npf_workfunc_t);
+void		npf_worker_unregister(npf_t *, npf_workfunc_t);
 
-void		npflogattach(int);
-void		npflogdetach(void);
 int		npfctl_switch(void *);
 int		npfctl_reload(u_long, void *);
-int		npfctl_save(u_long, void *);
-int		npfctl_load(u_long, void *);
-int		npfctl_rule(u_long, void *);
-int		npfctl_conn_lookup(u_long, void *);
-int		npfctl_table(void *);
+int		npfctl_save(npf_t *, u_long, void *);
+int		npfctl_load(npf_t *, u_long, void *);
+int		npfctl_rule(npf_t *, u_long, void *);
+int		npfctl_conn_lookup(npf_t *, u_long, void *);
+int		npfctl_table(npf_t *, void *);
 
-void		npf_stats_inc(npf_stats_t);
-void		npf_stats_dec(npf_stats_t);
+void		npf_stats_inc(npf_t *, npf_stats_t);
+void		npf_stats_dec(npf_t *, npf_stats_t);
 
-u_int		npf_ifmap_register(const char *);
-void		npf_ifmap_flush(void);
-void		npf_ifmap_attach(ifnet_t *);
-void		npf_ifmap_detach(ifnet_t *);
-u_int		npf_ifmap_getid(const ifnet_t *);
-const char *	npf_ifmap_getname(const u_int);
+void		npf_ifmap_init(npf_t *, const npf_ifops_t *);
+void		npf_ifmap_fini(npf_t *);
+u_int		npf_ifmap_register(npf_t *, const char *);
+void		npf_ifmap_flush(npf_t *);
+u_int		npf_ifmap_getid(npf_t *, const ifnet_t *);
+const char *	npf_ifmap_getname(npf_t *, const u_int);
 
 /* Packet filter hooks. */
 int		npf_pfil_register(bool);
 void		npf_pfil_unregister(bool);
 bool		npf_pfil_registered_p(void);
-int		npf_packet_handler(void *, struct mbuf **, ifnet_t *, int);
 
 /* Protocol helpers. */
 int		npf_cache_all(npf_cache_t *);
@@ -233,8 +297,8 @@
 int		npf_tableset_insert(npf_tableset_t *, npf_table_t *);
 npf_table_t *	npf_tableset_getbyname(npf_tableset_t *, const char *);
 npf_table_t *	npf_tableset_getbyid(npf_tableset_t *, u_int);
-void		npf_tableset_reload(npf_tableset_t *, npf_tableset_t *);
-int		npf_tableset_export(const npf_tableset_t *, prop_array_t);
+void		npf_tableset_reload(npf_t *, npf_tableset_t *, npf_tableset_t *);
+int		npf_tableset_export(npf_t *, const npf_tableset_t *, prop_array_t);
 
 npf_table_t *	npf_table_create(const char *, u_int, int, void *, size_t);
 void		npf_table_destroy(npf_table_t *);
@@ -252,17 +316,18 @@
 npf_ruleset_t *	npf_ruleset_create(size_t);
 void		npf_ruleset_destroy(npf_ruleset_t *);
 void		npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
-void		npf_ruleset_reload(npf_ruleset_t *, npf_ruleset_t *, bool);
+void		npf_ruleset_reload(npf_t *, npf_ruleset_t *,
+		    npf_ruleset_t *, bool);
 npf_rule_t *	npf_ruleset_sharepm(npf_ruleset_t *, npf_natpolicy_t *);
 npf_natpolicy_t *npf_ruleset_findnat(npf_ruleset_t *, uint64_t);
 void		npf_ruleset_freealg(npf_ruleset_t *, npf_alg_t *);
-int		npf_ruleset_export(const npf_ruleset_t *, prop_array_t);
+int		npf_ruleset_export(npf_t *, const npf_ruleset_t *, prop_array_t);
 
 int		npf_ruleset_add(npf_ruleset_t *, const char *, npf_rule_t *);
 int		npf_ruleset_remove(npf_ruleset_t *, const char *, uint64_t);
 int		npf_ruleset_remkey(npf_ruleset_t *, const char *,
 		    const void *, size_t);
-prop_dictionary_t npf_ruleset_list(npf_ruleset_t *, const char *);
+prop_dictionary_t npf_ruleset_list(npf_t *, npf_ruleset_t *, const char *);
 int		npf_ruleset_flush(npf_ruleset_t *, const char *);
 void		npf_ruleset_gc(npf_ruleset_t *);
 
@@ -271,7 +336,7 @@
 int		npf_rule_conclude(const npf_rule_t *, int *);
 
 /* Rule interface. */
-npf_rule_t *	npf_rule_alloc(prop_dictionary_t);
+npf_rule_t *	npf_rule_alloc(npf_t *, prop_dictionary_t);
 void		npf_rule_setcode(npf_rule_t *, int, void *, size_t);
 void		npf_rule_setrproc(npf_rule_t *, npf_rproc_t *);
 void		npf_rule_free(npf_rule_t *);
@@ -280,9 +345,9 @@
 void		npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
 npf_rproc_t *	npf_rule_getrproc(const npf_rule_t *);
 
-void		npf_ext_sysinit(void);
-void		npf_ext_sysfini(void);
-int		npf_ext_construct(const char *,
+void		npf_ext_init(npf_t *);
+void		npf_ext_fini(npf_t *);
+int		npf_ext_construct(npf_t *, const char *,
 		    npf_rproc_t *, prop_dictionary_t);
 
 npf_rprocset_t *npf_rprocset_create(void);
@@ -308,7 +373,7 @@
 /* NAT. */
 void		npf_nat_sysinit(void);
 void		npf_nat_sysfini(void);
-npf_natpolicy_t *npf_nat_newpolicy(prop_dictionary_t, npf_ruleset_t *);
+npf_natpolicy_t *npf_nat_newpolicy(npf_t *, prop_dictionary_t, npf_ruleset_t *);
 int		npf_nat_policyexport(const npf_natpolicy_t *, prop_dictionary_t);
 void		npf_nat_freepolicy(npf_natpolicy_t *);
 bool		npf_nat_cmppolicy(npf_natpolicy_t *, npf_natpolicy_t *);
@@ -324,25 +389,34 @@
 void		npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t);
 
 void		npf_nat_export(prop_dictionary_t, npf_nat_t *);
-npf_nat_t *	npf_nat_import(prop_dictionary_t, npf_ruleset_t *,
+npf_nat_t *	npf_nat_import(npf_t *, prop_dictionary_t, npf_ruleset_t *,
 		    npf_conn_t *);
 
 /* ALG interface. */
-void		npf_alg_sysinit(void);
-void		npf_alg_sysfini(void);
-npf_alg_t *	npf_alg_register(const char *, const npfa_funcs_t *);
-int		npf_alg_unregister(npf_alg_t *);
-npf_alg_t *	npf_alg_construct(const char *);
+void		npf_alg_init(npf_t *);
+void		npf_alg_fini(npf_t *);
+npf_alg_t *	npf_alg_register(npf_t *, const char *, const npfa_funcs_t *);
+int		npf_alg_unregister(npf_t *, npf_alg_t *);
+npf_alg_t *	npf_alg_construct(npf_t *, const char *);
 bool		npf_alg_match(npf_cache_t *, npf_nat_t *, int);
 void		npf_alg_exec(npf_cache_t *, npf_nat_t *, bool);
 npf_conn_t *	npf_alg_conn(npf_cache_t *, int);
-prop_array_t	npf_alg_export(void);
+prop_array_t	npf_alg_export(npf_t *);
 
 /* Debugging routines. */
 const char *	npf_addr_dump(const npf_addr_t *, int);
 void		npf_state_dump(const npf_state_t *);
 void		npf_nat_dump(const npf_nat_t *);
-void		npf_ruleset_dump(const char *);
+void		npf_ruleset_dump(npf_t *, const char *);
 void		npf_state_setsampler(void (*)(npf_state_t *, bool));
 
+/* In-kernel routines. */
+void		npf_setkernctx(npf_t *);
+npf_t *		npf_getkernctx(void);
+
+#ifdef __NetBSD__
+#define	pserialize_register(x)
+#define	pserialize_checkpoint(x)
+#endif
+
 #endif	/* _NPF_IMPL_H_ */
--- a/sys/net/npf/npf_inet.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_inet.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_inet.c,v 1.35 2016/11/07 18:16:07 jnemeth Exp $	*/
+/*	$NetBSD: npf_inet.c,v 1.36 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -38,8 +38,9 @@
  * on rewrites (e.g. by translation routines).
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.35 2016/11/07 18:16:07 jnemeth Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.36 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -57,6 +58,7 @@
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -132,8 +134,8 @@
 	KASSERT(sz > 0 && a1 != NULL && a2 != NULL);
 
 	for (int i = 0; i < (sz >> 2); i++) {
-		mix ^= a1->s6_addr32[i];
-		mix ^= a2->s6_addr32[i];
+		mix ^= a1->word32[i];
+		mix ^= a2->word32[i];
 	}
 	return mix;
 }
@@ -163,7 +165,7 @@
 		} else {
 			wordmask = 0;
 		}
-		out->s6_addr32[i] = addr->s6_addr32[i] & wordmask;
+		out->word32[i] = addr->word32[i] & wordmask;
 	}
 }
 
@@ -655,9 +657,7 @@
 		}
 		break;
 	case IPPROTO_ICMP:
-#ifdef INET6
 	case IPPROTO_ICMPV6:
-#endif
 		KASSERT(npf_iscached(npc, NPC_ICMP));
 		/* Nothing. */
 		break;
@@ -671,7 +671,6 @@
  * IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296.
  */
 
-#ifdef INET6
 int
 npf_npt66_rwr(const npf_cache_t *npc, u_int which, const npf_addr_t *pref,
     npf_netmask_t len, uint16_t adj)
@@ -691,7 +690,7 @@
 		 * subnet if /48 or shorter.
 		 */
 		word = 3;
-		if (addr->s6_addr16[word] == 0xffff) {
+		if (addr->word16[word] == 0xffff) {
 			return EINVAL;
 		}
 	} else {
@@ -699,19 +698,19 @@
 		 * Also, all 0s or 1s in the host part are disallowed for
 		 * longer than /48 prefixes.
 		 */
-		if ((addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0) ||
-		    (addr->s6_addr32[2] == ~0U && addr->s6_addr32[3] == ~0U))
+		if ((addr->word32[2] == 0 && addr->word32[3] == 0) ||
+		    (addr->word32[2] == ~0U && addr->word32[3] == ~0U))
 			return EINVAL;
 
 		/* Determine the 16-bit word to adjust. */
 		for (word = 4; word < 8; word++)
-			if (addr->s6_addr16[word] != 0xffff)
+			if (addr->word16[word] != 0xffff)
 				break;
 	}
 
 	/* Rewrite the prefix. */
 	for (unsigned i = 0; i < preflen; i++) {
-		addr->s6_addr16[i] = pref->s6_addr16[i];
+		addr->word16[i] = pref->word16[i];
 	}
 
 	/*
@@ -722,14 +721,14 @@
 		const uint16_t wordmask = (1U << remnant) - 1;
 		const unsigned i = preflen;
 
-		addr->s6_addr16[i] = (pref->s6_addr16[i] & wordmask) |
-		    (addr->s6_addr16[i] & ~wordmask);
+		addr->word16[i] = (pref->word16[i] & wordmask) |
+		    (addr->word16[i] & ~wordmask);
 	}
 
 	/*
 	 * Performing 1's complement sum/difference.
 	 */
-	sum = addr->s6_addr16[word] + adj;
+	sum = addr->word16[word] + adj;
 	while (sum >> 16) {
 		sum = (sum >> 16) + (sum & 0xffff);
 	}
@@ -737,28 +736,21 @@
 		/* RFC 1071. */
 		sum = 0x0000;
 	}
-	addr->s6_addr16[word] = sum;
+	addr->word16[word] = sum;
 	return 0;
 }
-#endif
 
 #if defined(DDB) || defined(_NPF_TESTING)
 
 const char *
 npf_addr_dump(const npf_addr_t *addr, int alen)
 {
-#ifdef INET6
 	if (alen == sizeof(struct in_addr)) {
-#else
-		KASSERT(alen == sizeof(struct in_addr));
-#endif
 		struct in_addr ip;
 		memcpy(&ip, addr, alen);
 		return inet_ntoa(ip);
-#ifdef INET6
 	}
-	return ip6_sprintf(addr);
-#endif
+	return "[IPv6]";
 }
 
 #endif
--- a/sys/net/npf/npf_mbuf.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_mbuf.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_mbuf.c,v 1.17 2016/12/08 23:07:11 rmind Exp $	*/
+/*	$NetBSD: npf_mbuf.c,v 1.18 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -36,24 +36,41 @@
  * abstracted within this source.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.17 2016/12/08 23:07:11 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.18 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
+#endif
 
 #include "npf_impl.h"
 
+#if defined(_NPF_STANDALONE)
+#define	m_length(m)		(nbuf)->nb_mops->getchainlen(m)
+#define	m_buflen(m)		(nbuf)->nb_mops->getlen(m)
+#define	m_next_ptr(m)		(nbuf)->nb_mops->getnext(m)
+#define	m_ensure_contig(m,t)	(nbuf)->nb_mops->ensure_contig((m), (t))
+#define	m_makewritable(m,o,l,f)	(nbuf)->nb_mops->ensure_writable((m), (o+l))
+#define	mtod(m,t)		((t)((nbuf)->nb_mops->getdata(m)))
+#define	m_flags_p(m,f)		true
+#else
+#define	m_next_ptr(m)		(m)->m_next
+#define	m_buflen(m)		(m)->m_len
+#define	m_flags_p(m,f)		(((m)->m_flags & (f)) != 0)
+#endif
+
 #define	NBUF_ENSURE_ALIGN	(MAX(COHERENCY_UNIT, 64))
 #define	NBUF_ENSURE_MASK	(NBUF_ENSURE_ALIGN - 1)
 #define	NBUF_ENSURE_ROUNDUP(x)	(((x) + NBUF_ENSURE_ALIGN) & ~NBUF_ENSURE_MASK)
 
 void
-nbuf_init(nbuf_t *nbuf, struct mbuf *m, const ifnet_t *ifp)
+nbuf_init(npf_t *npf, nbuf_t *nbuf, struct mbuf *m, const ifnet_t *ifp)
 {
-	u_int ifid = npf_ifmap_getid(ifp);
+	u_int ifid = npf_ifmap_getid(npf, ifp);
 
-	KASSERT((m->m_flags & M_PKTHDR) != 0);
+	KASSERT(m_flags_p(m, M_PKTHDR));
+	nbuf->nb_mops = npf->mbufops;
 
 	nbuf->nb_mbuf0 = m;
 	nbuf->nb_ifp = ifp;
@@ -121,11 +138,11 @@
 
 	/* Offset with amount to advance. */
 	off = (uintptr_t)nbuf->nb_nptr - mtod(m, uintptr_t) + len;
-	wmark = m->m_len;
+	wmark = m_buflen(m);
 
 	/* Find the mbuf according to offset. */
 	while (__predict_false(wmark <= off)) {
-		m = m->m_next;
+		m = m_next_ptr(m);
 		if (__predict_false(m == NULL)) {
 			/*
 			 * If end of the chain, then the offset is
@@ -133,14 +150,14 @@
 			 */
 			return NULL;
 		}
-		wmark += m->m_len;
+		wmark += m_buflen(m);
 	}
 	KASSERT(off < m_length(nbuf->nb_mbuf0));
 
 	/* Offset in mbuf data. */
 	d = mtod(m, uint8_t *);
-	KASSERT(off >= (wmark - m->m_len));
-	d += (off - (wmark - m->m_len));
+	KASSERT(off >= (wmark - m_buflen(m)));
+	d += (off - (wmark - m_buflen(m)));
 
 	nbuf->nb_mbuf = m;
 	nbuf->nb_nptr = d;
@@ -165,17 +182,17 @@
 	const struct mbuf * const n = nbuf->nb_mbuf;
 	const size_t off = (uintptr_t)nbuf->nb_nptr - mtod(n, uintptr_t);
 
-	KASSERT(off <= n->m_len);
+	KASSERT(off <= m_buflen(n));
 
-	if (__predict_false(n->m_len < (off + len))) {
+	if (__predict_false(m_buflen(n) < (off + len))) {
 		struct mbuf *m = nbuf->nb_mbuf0;
 		const size_t foff = nbuf_offset(nbuf);
 		const size_t plen = m_length(m);
-		const size_t mlen = m->m_len;
+		const size_t mlen = m_buflen(m);
 		size_t target;
 		bool success;
 
-		npf_stats_inc(NPF_STAT_NBUF_NONCONTIG);
+		//npf_stats_inc(npf, NPF_STAT_NBUF_NONCONTIG);
 
 		/* Attempt to round-up to NBUF_ENSURE_ALIGN bytes. */
 		if ((target = NBUF_ENSURE_ROUNDUP(foff + len)) > plen) {
@@ -183,12 +200,12 @@
 		}
 
 		/* Rearrange the chain to be contiguous. */
-		KASSERT((m->m_flags & M_PKTHDR) != 0);
+		KASSERT(m_flags_p(m, M_PKTHDR));
 		success = m_ensure_contig(&m, target);
 		KASSERT(m != NULL);
 
 		/* If no change in the chain: return what we have. */
-		if (m == nbuf->nb_mbuf0 && m->m_len == mlen) {
+		if (m == nbuf->nb_mbuf0 && m_buflen(m) == mlen) {
 			return success ? nbuf->nb_nptr : NULL;
 		}
 
@@ -197,16 +214,16 @@
 		 * accordingly and indicate that the references to the data
 		 * might need a reset.
 		 */
-		KASSERT((m->m_flags & M_PKTHDR) != 0);
+		KASSERT(m_flags_p(m, M_PKTHDR));
 		nbuf->nb_mbuf0 = m;
 		nbuf->nb_mbuf = m;
 
-		KASSERT(foff < m->m_len && foff < m_length(m));
+		KASSERT(foff < m_buflen(m) && foff < m_length(m));
 		nbuf->nb_nptr = mtod(m, uint8_t *) + foff;
 		nbuf->nb_flags |= NBUF_DATAREF_RESET;
 
 		if (!success) {
-			npf_stats_inc(NPF_STAT_NBUF_CONTIG_FAIL);
+			//npf_stats_inc(npf, NPF_STAT_NBUF_CONTIG_FAIL);
 			return NULL;
 		}
 	}
@@ -232,7 +249,7 @@
 		return NULL;
 	}
 	if (head_buf) {
-		KASSERT((m->m_flags & M_PKTHDR) != 0);
+		KASSERT(m_flags_p(m, M_PKTHDR));
 		KASSERT(off < m_length(m));
 		nbuf->nb_mbuf0 = m;
 	}
@@ -245,13 +262,14 @@
 bool
 nbuf_cksum_barrier(nbuf_t *nbuf, int di)
 {
+#ifdef _KERNEL
 	struct mbuf *m;
 
 	if (di != PFIL_OUT) {
 		return false;
 	}
 	m = nbuf->nb_mbuf0;
-	KASSERT((m->m_flags & M_PKTHDR) != 0);
+	KASSERT(m_flags_p(m, M_PKTHDR));
 
 	if (m->m_pkthdr.csum_flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) {
 		in_delayed_cksum(m);
@@ -265,6 +283,9 @@
 		return true;
 	}
 #endif
+#else
+	(void)nbuf; (void)di;
+#endif
 	return false;
 }
 
@@ -276,11 +297,12 @@
 int
 nbuf_add_tag(nbuf_t *nbuf, uint32_t val)
 {
+#ifdef _KERNEL
 	struct mbuf *m = nbuf->nb_mbuf0;
 	struct m_tag *mt;
 	uint32_t *dat;
 
-	KASSERT((m->m_flags & M_PKTHDR) != 0);
+	KASSERT(m_flags_p(m, M_PKTHDR));
 
 	mt = m_tag_get(PACKET_TAG_NPF, sizeof(uint32_t), M_NOWAIT);
 	if (mt == NULL) {
@@ -290,6 +312,10 @@
 	*dat = val;
 	m_tag_prepend(m, mt);
 	return 0;
+#else
+	(void)nbuf; (void)val;
+	return ENOTSUP;
+#endif
 }
 
 /*
@@ -300,10 +326,11 @@
 int
 nbuf_find_tag(nbuf_t *nbuf, uint32_t *val)
 {
+#ifdef _KERNEL
 	struct mbuf *m = nbuf->nb_mbuf0;
 	struct m_tag *mt;
 
-	KASSERT((m->m_flags & M_PKTHDR) != 0);
+	KASSERT(m_flags_p(m, M_PKTHDR));
 
 	mt = m_tag_find(m, PACKET_TAG_NPF, NULL);
 	if (mt == NULL) {
@@ -311,4 +338,8 @@
 	}
 	*val = *(uint32_t *)(mt + 1);
 	return 0;
+#else
+	(void)nbuf; (void)val;
+	return ENOTSUP;
+#endif
 }
--- a/sys/net/npf/npf_nat.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_nat.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat.c,v 1.40 2016/03/18 10:09:46 mrg Exp $	*/
+/*	$NetBSD: npf_nat.c,v 1.41 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
@@ -70,8 +70,9 @@
  *	port map and NAT entry is destroyed when connection expires.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.40 2016/03/18 10:09:46 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.41 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -87,6 +88,7 @@
 
 #include <net/pfil.h>
 #include <netinet/in.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_conn.h"
@@ -113,6 +115,7 @@
  * NAT policy structure.
  */
 struct npf_natpolicy {
+	npf_t *			n_npfctx;
 	kmutex_t		n_lock;
 	LIST_HEAD(, npf_nat)	n_nat_list;
 	volatile u_int		n_refcnt;
@@ -191,13 +194,14 @@
  * => Shares portmap if policy is on existing translation address.
  */
 npf_natpolicy_t *
-npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *rset)
+npf_nat_newpolicy(npf_t *npf, prop_dictionary_t natdict, npf_ruleset_t *rset)
 {
 	npf_natpolicy_t *np;
 	prop_object_t obj;
 	npf_portmap_t *pm;
 
 	np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP);
+	np->n_npfctx = npf;
 
 	/* The translation type, flags and policy ID. */
 	prop_dictionary_get_int32(natdict, "type", &np->n_type);
@@ -311,7 +315,7 @@
 		mutex_exit(&np->n_lock);
 
 		/* Kick the worker - all references should be going away. */
-		npf_worker_signal();
+		npf_worker_signal(np->n_npfctx);
 		kpause("npfgcnat", false, 1, NULL);
 	}
 	KASSERT(LIST_EMPTY(&np->n_nat_list));
@@ -529,7 +533,7 @@
 npf_nat_inspect(npf_cache_t *npc, const int di)
 {
 	int slock = npf_config_read_enter();
-	npf_ruleset_t *rlset = npf_config_natset();
+	npf_ruleset_t *rlset = npf_config_natset(npc->npc_ctx);
 	npf_natpolicy_t *np;
 	npf_rule_t *rl;
 
@@ -561,7 +565,7 @@
 	if (nt == NULL){
 		return NULL;
 	}
-	npf_stats_inc(NPF_STAT_NAT_CREATE);
+	npf_stats_inc(npc->npc_ctx, NPF_STAT_NAT_CREATE);
 	nt->nt_natpolicy = np;
 	nt->nt_conn = con;
 	nt->nt_alg = NULL;
@@ -657,12 +661,10 @@
 	int error;
 
 	switch (np->n_algo) {
-#ifdef INET6
 	case NPF_ALGO_NPT66:
 		error = npf_npt66_rwr(npc, which, &np->n_taddr,
 		    np->n_tmask, np->n_npt66_adj);
 		break;
-#endif
 	default:
 		error = npf_napt_rwr(npc, which, &np->n_taddr, np->n_tport);
 		break;
@@ -829,15 +831,14 @@
 	if ((np->n_flags & NPF_NAT_PORTMAP) != 0 && nt->nt_tport) {
 		npf_nat_putport(np, nt->nt_tport);
 	}
+	npf_stats_inc(np->n_npfctx, NPF_STAT_NAT_DESTROY);
 
 	mutex_enter(&np->n_lock);
 	LIST_REMOVE(nt, nt_entry);
 	KASSERT(np->n_refcnt > 0);
 	atomic_dec_uint(&np->n_refcnt);
 	mutex_exit(&np->n_lock);
-
 	pool_cache_put(nat_cache, nt);
-	npf_stats_inc(NPF_STAT_NAT_DESTROY);
 }
 
 /*
@@ -863,8 +864,8 @@
  * npf_nat_import: find the NAT policy and unserialise the NAT entry.
  */
 npf_nat_t *
-npf_nat_import(prop_dictionary_t natdict, npf_ruleset_t *natlist,
-    npf_conn_t *con)
+npf_nat_import(npf_t *npf, prop_dictionary_t natdict,
+    npf_ruleset_t *natlist, npf_conn_t *con)
 {
 	npf_natpolicy_t *np;
 	npf_nat_t *nt;
@@ -894,7 +895,7 @@
 		pool_cache_put(nat_cache, nt);
 		return NULL;
 	}
-	npf_stats_inc(NPF_STAT_NAT_CREATE);
+	npf_stats_inc(npf, NPF_STAT_NAT_CREATE);
 
 	/*
 	 * Associate, take a reference and insert.  Unlocked since
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_os.c	Mon Dec 26 23:05:05 2016 +0000
@@ -0,0 +1,461 @@
+/*	$NetBSD: npf_os.c,v 1.1 2016/12/26 23:05:06 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2016 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.
+ */
+
+/*
+ * NPF main: dynamic load/initialisation and unload routines.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.1 2016/12/26 23:05:06 christos Exp $");
+
+#ifdef _KERNEL_OPT
+#include "pf.h"
+#if NPF > 0
+#error "NPF and PF are mutually exclusive; please select one"
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/conf.h>
+#include <sys/kauth.h>
+#include <sys/kmem.h>
+#include <sys/lwp.h>
+#include <sys/module.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+#endif
+
+#include "npf_impl.h"
+#include "npfkern.h"
+
+#ifdef _KERNEL
+#ifndef _MODULE
+#include "opt_modular.h"
+#endif
+#include "ioconf.h"
+#endif
+
+/*
+ * Module and device structures.
+ */
+#ifndef _MODULE
+/*
+ * Modular kernels load drivers too early, and we need percpu to be inited
+ * So we make this misc; a better way would be to have early boot and late
+ * boot drivers.
+ */
+MODULE(MODULE_CLASS_MISC, npf, NULL);
+#else
+/* This module autoloads via /dev/npf so it needs to be a driver */
+MODULE(MODULE_CLASS_DRIVER, npf, NULL);
+#endif
+
+static int	npf_dev_open(dev_t, int, int, lwp_t *);
+static int	npf_dev_close(dev_t, int, int, lwp_t *);
+static int	npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *);
+static int	npf_dev_poll(dev_t, int, lwp_t *);
+static int	npf_dev_read(dev_t, struct uio *, int);
+
+const struct cdevsw npf_cdevsw = {
+	.d_open = npf_dev_open,
+	.d_close = npf_dev_close,
+	.d_read = npf_dev_read,
+	.d_write = nowrite,
+	.d_ioctl = npf_dev_ioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = npf_dev_poll,
+	.d_mmap = nommap,
+	.d_kqfilter = nokqfilter,
+	.d_discard = nodiscard,
+	.d_flag = D_OTHER | D_MPSAFE
+};
+
+static const char *	npf_ifop_getname(ifnet_t *);
+static ifnet_t *	npf_ifop_lookup(const char *);
+static void		npf_ifop_flush(void *);
+static void *		npf_ifop_getmeta(const ifnet_t *);
+static void		npf_ifop_setmeta(ifnet_t *, void *);
+
+static const unsigned	nworkers = 1;
+
+static bool		pfil_registered = false;
+static pfil_head_t *	npf_ph_if = NULL;
+static pfil_head_t *	npf_ph_inet = NULL;
+static pfil_head_t *	npf_ph_inet6 = NULL;
+
+static const npf_ifops_t kern_ifops = {
+	.getname	= npf_ifop_getname,
+	.lookup		= npf_ifop_lookup,
+	.flush		= npf_ifop_flush,
+	.getmeta	= npf_ifop_getmeta,
+	.setmeta	= npf_ifop_setmeta,
+};
+
+static int
+npf_fini(void)
+{
+	npf_t *npf = npf_getkernctx();
+
+	/* At first, detach device and remove pfil hooks. */
+#ifdef _MODULE
+	devsw_detach(NULL, &npf_cdevsw);
+#endif
+	npf_pfil_unregister(true);
+	npf_destroy(npf);
+	npf_sysfini();
+	return 0;
+}
+
+static int
+npf_init(void)
+{
+	npf_t *npf;
+	int error = 0;
+
+	error = npf_sysinit(nworkers);
+	if (error)
+		return error;
+	npf = npf_create(0, NULL, &kern_ifops);
+	npf_setkernctx(npf);
+	npf_pfil_register(true);
+
+#ifdef _MODULE
+	devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
+
+	/* Attach /dev/npf device. */
+	error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
+	if (error) {
+		/* It will call devsw_detach(), which is safe. */
+		(void)npf_fini();
+	}
+#endif
+	return error;
+}
+
+
+/*
+ * Module interface.
+ */
+static int
+npf_modcmd(modcmd_t cmd, void *arg)
+{
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		return npf_init();
+	case MODULE_CMD_FINI:
+		return npf_fini();
+	case MODULE_CMD_AUTOUNLOAD:
+		if (npf_autounload_p()) {
+			return EBUSY;
+		}
+		break;
+	default:
+		return ENOTTY;
+	}
+	return 0;
+}
+
+void
+npfattach(int nunits)
+{
+	/* Nothing */
+}
+
+static int
+npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l)
+{
+
+	/* Available only for super-user. */
+	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
+	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
+		return EPERM;
+	}
+	return 0;
+}
+
+static int
+npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l)
+{
+	return 0;
+}
+
+static int
+npf_stats_export(npf_t *npf, void *data)
+{
+	uint64_t *fullst, *uptr = *(uint64_t **)data;
+	int error;
+
+	fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP);
+	npf_stats(npf, fullst); /* will zero the buffer */
+	error = copyout(fullst, uptr, NPF_STATS_SIZE);
+	kmem_free(fullst, NPF_STATS_SIZE);
+	return error;
+}
+
+static int
+npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
+{
+	npf_t *npf = npf_getkernctx();
+	int error;
+
+	/* Available only for super-user. */
+	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
+	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
+		return EPERM;
+	}
+
+	switch (cmd) {
+	case IOC_NPF_TABLE:
+		error = npfctl_table(npf, data);
+		break;
+	case IOC_NPF_RULE:
+		error = npfctl_rule(npf, cmd, data);
+		break;
+	case IOC_NPF_STATS:
+		error = npf_stats_export(npf, data);
+		break;
+	case IOC_NPF_SAVE:
+		error = npfctl_save(npf, cmd, data);
+		break;
+	case IOC_NPF_SWITCH:
+		error = npfctl_switch(data);
+		break;
+	case IOC_NPF_LOAD:
+		error = npfctl_load(npf, cmd, data);
+		break;
+	case IOC_NPF_CONN_LOOKUP:
+		error = npfctl_conn_lookup(npf, cmd, data);
+		break;
+	case IOC_NPF_VERSION:
+		*(int *)data = NPF_VERSION;
+		error = 0;
+		break;
+	default:
+		error = ENOTTY;
+		break;
+	}
+	return error;
+}
+
+static int
+npf_dev_poll(dev_t dev, int events, lwp_t *l)
+{
+	return ENOTSUP;
+}
+
+static int
+npf_dev_read(dev_t dev, struct uio *uio, int flag)
+{
+	return ENOTSUP;
+}
+
+bool
+npf_autounload_p(void)
+{
+	npf_t *npf = npf_getkernctx();
+	return !npf_pfil_registered_p() && npf_default_pass(npf);
+}
+
+/*
+ * Interface operations.
+ */
+
+static const char *
+npf_ifop_getname(ifnet_t *ifp)
+{
+	return ifp->if_xname;
+}
+
+static ifnet_t *
+npf_ifop_lookup(const char *name)
+{
+	return ifunit(name);
+}
+
+static void
+npf_ifop_flush(void *arg)
+{
+	ifnet_t *ifp;
+
+	KERNEL_LOCK(1, NULL);
+	IFNET_LOCK();
+	IFNET_WRITER_FOREACH(ifp) {
+		ifp->if_pf_kif = arg;
+	}
+	IFNET_UNLOCK();
+	KERNEL_UNLOCK_ONE(NULL);
+}
+
+static void *
+npf_ifop_getmeta(const ifnet_t *ifp)
+{
+	return ifp->if_pf_kif;
+}
+
+static void
+npf_ifop_setmeta(ifnet_t *ifp, void *arg)
+{
+	ifp->if_pf_kif = arg;
+}
+
+#ifdef _KERNEL
+
+/*
+ * Wrapper of the main packet handler to pass the kernel NPF context.
+ */
+static int
+npfkern_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
+{
+	npf_t *npf = npf_getkernctx();
+	return npf_packet_handler(npf, mp, ifp, di);
+}
+
+/*
+ * npf_ifhook: hook handling interface changes.
+ */
+static int
+npf_ifhook(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
+{
+	npf_t *npf = npf_getkernctx();
+	u_long cmd = (u_long)mp;
+
+	if (di == PFIL_IFNET) {
+		switch (cmd) {
+		case PFIL_IFNET_ATTACH:
+			npf_ifmap_attach(npf, ifp);
+			break;
+		case PFIL_IFNET_DETACH:
+			npf_ifmap_detach(npf, ifp);
+			break;
+		}
+	}
+	return 0;
+}
+
+/*
+ * npf_pfil_register: register pfil(9) hooks.
+ */
+int
+npf_pfil_register(bool init)
+{
+	npf_t *npf = npf_getkernctx();
+	int error = 0;
+
+	mutex_enter(softnet_lock);
+	KERNEL_LOCK(1, NULL);
+
+	/* Init: interface re-config and attach/detach hook. */
+	if (!npf_ph_if) {
+		npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
+		if (!npf_ph_if) {
+			error = ENOENT;
+			goto out;
+		}
+		error = pfil_add_hook(npf_ifhook, NULL,
+		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
+		KASSERT(error == 0);
+	}
+	if (init) {
+		goto out;
+	}
+
+	/* Check if pfil hooks are not already registered. */
+	if (pfil_registered) {
+		error = EEXIST;
+		goto out;
+	}
+
+	/* Capture points of the activity in the IP layer. */
+	npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
+	npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
+	if (!npf_ph_inet && !npf_ph_inet6) {
+		error = ENOENT;
+		goto out;
+	}
+
+	/* Packet IN/OUT handlers for IP layer. */
+	if (npf_ph_inet) {
+		error = pfil_add_hook(npfkern_packet_handler, npf,
+		    PFIL_ALL, npf_ph_inet);
+		KASSERT(error == 0);
+	}
+	if (npf_ph_inet6) {
+		error = pfil_add_hook(npfkern_packet_handler, npf,
+		    PFIL_ALL, npf_ph_inet6);
+		KASSERT(error == 0);
+	}
+	pfil_registered = true;
+out:
+	KERNEL_UNLOCK_ONE(NULL);
+	mutex_exit(softnet_lock);
+
+	return error;
+}
+
+/*
+ * npf_pfil_unregister: unregister pfil(9) hooks.
+ */
+void
+npf_pfil_unregister(bool fini)
+{
+	npf_t *npf = npf_getkernctx();
+
+	mutex_enter(softnet_lock);
+	KERNEL_LOCK(1, NULL);
+
+	if (fini && npf_ph_if) {
+		(void)pfil_remove_hook(npf_ifhook, NULL,
+		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
+	}
+	if (npf_ph_inet) {
+		(void)pfil_remove_hook(npfkern_packet_handler, npf,
+		    PFIL_ALL, npf_ph_inet);
+	}
+	if (npf_ph_inet6) {
+		(void)pfil_remove_hook(npfkern_packet_handler, npf,
+		    PFIL_ALL, npf_ph_inet6);
+	}
+	pfil_registered = false;
+
+	KERNEL_UNLOCK_ONE(NULL);
+	mutex_exit(softnet_lock);
+}
+
+bool
+npf_pfil_registered_p(void)
+{
+	return pfil_registered;
+}
+#endif
--- a/sys/net/npf/npf_rproc.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_rproc.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_rproc.c,v 1.13 2016/12/10 19:02:18 christos Exp $	*/
+/*	$NetBSD: npf_rproc.c,v 1.14 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -33,6 +33,7 @@
  * NPF extension and rule procedure interface.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD");
 
@@ -43,6 +44,7 @@
 #include <sys/kmem.h>
 #include <sys/mutex.h>
 #include <sys/module.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -77,21 +79,18 @@
 	LIST_ENTRY(npf_rproc)	rp_entry;
 };
 
-static LIST_HEAD(, npf_ext)	ext_list	__cacheline_aligned;
-static kmutex_t			ext_lock	__cacheline_aligned;
-
 void
-npf_ext_sysinit(void)
+npf_ext_init(npf_t *npf)
 {
-	mutex_init(&ext_lock, MUTEX_DEFAULT, IPL_NONE);
-	LIST_INIT(&ext_list);
+	mutex_init(&npf->ext_lock, MUTEX_DEFAULT, IPL_NONE);
+	LIST_INIT(&npf->ext_list);
 }
 
 void
-npf_ext_sysfini(void)
+npf_ext_fini(npf_t *npf)
 {
-	KASSERT(LIST_EMPTY(&ext_list));
-	mutex_destroy(&ext_lock);
+	KASSERT(LIST_EMPTY(&npf->ext_list));
+	mutex_destroy(&npf->ext_lock);
 }
 
 /*
@@ -102,27 +101,27 @@
 #define NPF_EXT_PREFLEN (sizeof(npf_ext_prefix) - 1)
 
 static npf_ext_t *
-npf_ext_lookup(const char *name, bool autoload)
+npf_ext_lookup(npf_t *npf, const char *name, bool autoload)
 {
 	npf_ext_t *ext;
 	char modname[RPROC_NAME_LEN + NPF_EXT_PREFLEN];
 	int error;
 
-	KASSERT(mutex_owned(&ext_lock));
+	KASSERT(mutex_owned(&npf->ext_lock));
 
 again:
-	LIST_FOREACH(ext, &ext_list, ext_entry)
+	LIST_FOREACH(ext, &npf->ext_list, ext_entry)
 		if (strcmp(ext->ext_callname, name) == 0)
 			break;
 
 	if (ext != NULL || !autoload)
 		return ext;
 
-	mutex_exit(&ext_lock);
+	mutex_exit(&npf->ext_lock);
 	autoload = false;
 	snprintf(modname, sizeof(modname), "%s%s", npf_ext_prefix, name);
 	error = module_autoload(modname, MODULE_CLASS_MISC);
-	mutex_enter(&ext_lock);
+	mutex_enter(&npf->ext_lock);
 
 	if (error)
 		return NULL;
@@ -130,7 +129,7 @@
 }
 
 void *
-npf_ext_register(const char *name, const npf_ext_ops_t *ops)
+npf_ext_register(npf_t *npf, const char *name, const npf_ext_ops_t *ops)
 {
 	npf_ext_t *ext;
 
@@ -138,20 +137,20 @@
 	strlcpy(ext->ext_callname, name, EXT_NAME_LEN);
 	ext->ext_ops = ops;
 
-	mutex_enter(&ext_lock);
-	if (npf_ext_lookup(name, false)) {
-		mutex_exit(&ext_lock);
+	mutex_enter(&npf->ext_lock);
+	if (npf_ext_lookup(npf, name, false)) {
+		mutex_exit(&npf->ext_lock);
 		kmem_free(ext, sizeof(npf_ext_t));
 		return NULL;
 	}
-	LIST_INSERT_HEAD(&ext_list, ext, ext_entry);
-	mutex_exit(&ext_lock);
+	LIST_INSERT_HEAD(&npf->ext_list, ext, ext_entry);
+	mutex_exit(&npf->ext_lock);
 
 	return (void *)ext;
 }
 
 int
-npf_ext_unregister(void *extid)
+npf_ext_unregister(npf_t *npf, void *extid)
 {
 	npf_ext_t *ext = extid;
 
@@ -162,21 +161,22 @@
 		return EBUSY;
 	}
 
-	mutex_enter(&ext_lock);
+	mutex_enter(&npf->ext_lock);
 	if (ext->ext_refcnt) {
-		mutex_exit(&ext_lock);
+		mutex_exit(&npf->ext_lock);
 		return EBUSY;
 	}
-	KASSERT(npf_ext_lookup(ext->ext_callname, false));
+	KASSERT(npf_ext_lookup(npf, ext->ext_callname, false));
 	LIST_REMOVE(ext, ext_entry);
-	mutex_exit(&ext_lock);
+	mutex_exit(&npf->ext_lock);
 
 	kmem_free(ext, sizeof(npf_ext_t));
 	return 0;
 }
 
 int
-npf_ext_construct(const char *name, npf_rproc_t *rp, prop_dictionary_t params)
+npf_ext_construct(npf_t *npf, const char *name,
+    npf_rproc_t *rp, prop_dictionary_t params)
 {
 	const npf_ext_ops_t *extops;
 	npf_ext_t *ext;
@@ -187,12 +187,12 @@
 		return ENOSPC;
 	}
 
-	mutex_enter(&ext_lock);
-	ext = npf_ext_lookup(name, true);
+	mutex_enter(&npf->ext_lock);
+	ext = npf_ext_lookup(npf, name, true);
 	if (ext) {
 		atomic_inc_uint(&ext->ext_refcnt);
 	}
-	mutex_exit(&ext_lock);
+	mutex_exit(&npf->ext_lock);
 
 	if (!ext) {
 		return ENOENT;
--- a/sys/net/npf/npf_ruleset.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_ruleset.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ruleset.c,v 1.42 2015/03/20 23:36:28 rmind Exp $	*/
+/*	$NetBSD: npf_ruleset.c,v 1.43 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2015 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF ruleset module.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.42 2015/03/20 23:36:28 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.43 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -49,6 +50,7 @@
 #include <net/bpfjit.h>
 #include <net/pfil.h>
 #include <net/if.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -121,7 +123,7 @@
 #define	SKIPTO_ADJ_FLAG		(1U << 31)
 #define	SKIPTO_MASK		(SKIPTO_ADJ_FLAG - 1)
 
-static int	npf_rule_export(const npf_ruleset_t *,
+static int	npf_rule_export(npf_t *, const npf_ruleset_t *,
     const npf_rule_t *, prop_dictionary_t);
 
 /*
@@ -173,6 +175,8 @@
 		npf_rule_free(rl);
 	}
 	KASSERT(LIST_EMPTY(&rlset->rs_dynamic));
+
+	npf_ruleset_gc(rlset);
 	KASSERT(LIST_EMPTY(&rlset->rs_gc));
 	kmem_free(rlset, len);
 }
@@ -208,8 +212,6 @@
 {
 	npf_rule_t *rl;
 
-	KASSERT(npf_config_locked_p());
-
 	LIST_FOREACH(rl, &rlset->rs_dynamic, r_dentry) {
 		KASSERT(NPF_DYNAMIC_GROUP_P(rl->r_attr));
 		if (strncmp(rl->r_name, name, NPF_RULE_MAXNAMELEN) == 0)
@@ -357,13 +359,13 @@
  * npf_ruleset_list: serialise and return the dynamic rules.
  */
 prop_dictionary_t
-npf_ruleset_list(npf_ruleset_t *rlset, const char *rname)
+npf_ruleset_list(npf_t *npf, npf_ruleset_t *rlset, const char *rname)
 {
 	prop_dictionary_t rgdict;
 	prop_array_t rules;
 	npf_rule_t *rg;
 
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
 	if ((rg = npf_ruleset_lookup(rlset, rname)) == NULL) {
 		return NULL;
@@ -383,7 +385,7 @@
 		KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr));
 
 		rldict = prop_dictionary_create();
-		if (npf_rule_export(rlset, rl, rldict)) {
+		if (npf_rule_export(npf, rlset, rl, rldict)) {
 			prop_object_release(rldict);
 			prop_object_release(rules);
 			return NULL;
@@ -445,13 +447,13 @@
  * npf_ruleset_export: serialise and return the static rules.
  */
 int
-npf_ruleset_export(const npf_ruleset_t *rlset, prop_array_t rules)
+npf_ruleset_export(npf_t *npf, const npf_ruleset_t *rlset, prop_array_t rules)
 {
 	const u_int nitems = rlset->rs_nitems;
 	int error = 0;
 	u_int n = 0;
 
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
 	while (n < nitems) {
 		const npf_rule_t *rl = rlset->rs_rules[n];
@@ -459,7 +461,7 @@
 		prop_dictionary_t rldict;
 
 		rldict = prop_dictionary_create();
-		if ((error = npf_rule_export(rlset, rl, rldict)) != 0) {
+		if ((error = npf_rule_export(npf, rlset, rl, rldict)) != 0) {
 			prop_object_release(rldict);
 			break;
 		}
@@ -481,12 +483,13 @@
  * => The active (old) ruleset should be exclusively locked.
  */
 void
-npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset, bool load)
+npf_ruleset_reload(npf_t *npf, npf_ruleset_t *newset,
+    npf_ruleset_t *oldset, bool load)
 {
 	npf_rule_t *rg, *rl;
 	uint64_t nid = 0;
 
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
 	/*
 	 * Scan the dynamic rules and share (migrate) if needed.
@@ -644,7 +647,7 @@
  * npf_rule_alloc: allocate a rule and initialise it.
  */
 npf_rule_t *
-npf_rule_alloc(prop_dictionary_t rldict)
+npf_rule_alloc(npf_t *npf, prop_dictionary_t rldict)
 {
 	npf_rule_t *rl;
 	const char *rname;
@@ -675,7 +678,7 @@
 
 	/* Interface name; register and get the npf-if-id. */
 	if (prop_dictionary_get_cstring_nocopy(rldict, "ifname", &rname)) {
-		if ((rl->r_ifid = npf_ifmap_register(rname)) == 0) {
+		if ((rl->r_ifid = npf_ifmap_register(npf, rname)) == 0) {
 			kmem_free(rl, sizeof(npf_rule_t));
 			return NULL;
 		}
@@ -703,8 +706,8 @@
 }
 
 static int
-npf_rule_export(const npf_ruleset_t *rlset, const npf_rule_t *rl,
-    prop_dictionary_t rldict)
+npf_rule_export(npf_t *npf, const npf_ruleset_t *rlset,
+    const npf_rule_t *rl, prop_dictionary_t rldict)
 {
 	u_int skip_to = 0;
 	prop_data_t d;
@@ -722,7 +725,7 @@
 	}
 
 	if (rl->r_ifid) {
-		const char *ifname = npf_ifmap_getname(rl->r_ifid);
+		const char *ifname = npf_ifmap_getname(npf, rl->r_ifid);
 		prop_dictionary_set_cstring(rldict, "ifname", ifname);
 	}
 	prop_dictionary_set_uint64(rldict, "id", rl->r_id);
@@ -914,9 +917,12 @@
 
 	/*
 	 * Prepare the external memory store and the arguments for
-	 * the BPF programs to be executed.
+	 * the BPF programs to be executed.  Reset mbuf before taking
+	 * any pointers for the BPF.
 	 */
 	uint32_t bc_words[NPF_BPF_NWORDS];
+
+	nbuf_reset(nbuf);
 	npf_bpf_prepare(npc, &bc_args, bc_words);
 
 	while (n < nitems) {
@@ -983,9 +989,9 @@
 #if defined(DDB) || defined(_NPF_TESTING)
 
 void
-npf_ruleset_dump(const char *name)
+npf_ruleset_dump(npf_t *npf, const char *name)
 {
-	npf_ruleset_t *rlset = npf_config_ruleset();
+	npf_ruleset_t *rlset = npf_config_ruleset(npf);
 	npf_rule_t *rg, *rl;
 
 	LIST_FOREACH(rg, &rlset->rs_dynamic, r_dentry) {
--- a/sys/net/npf/npf_sendpkt.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_sendpkt.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_sendpkt.c,v 1.15 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_sendpkt.c,v 1.16 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@@ -33,8 +33,9 @@
  * NPF module for packet construction routines.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.15 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.16 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -49,12 +50,19 @@
 #include <netinet/icmp6.h>
 #include <netinet6/ip6_var.h>
 #include <sys/mbuf.h>
+#endif
 
 #include "npf_impl.h"
 
 #define	DEFAULT_IP_TTL		(ip_defttl)
 
-#ifndef INET6
+#if defined(_NPF_STANDALONE)
+#define	m_gethdr(t, f)		npf->mbufops->alloc(0, 0)
+#define	m_freem(m)		npc->npc_ctx->mbufops->free(m)
+#define	mtod(m,t)		((t)((npf)->mbufops->getdata(m)))
+#endif
+
+#if !defined(INET6) || defined(_NPF_STANDALONE)
 #define	in6_cksum(...)		0
 #define	ip6_output(...)		0
 #define	icmp6_error(m, ...)	m_freem(m)
@@ -66,6 +74,7 @@
 static int
 npf_return_tcp(npf_cache_t *npc)
 {
+	npf_t *npf = npc->npc_ctx;
 	struct mbuf *m;
 	struct ip *ip = NULL;
 	struct ip6_hdr *ip6 = NULL;
@@ -97,10 +106,12 @@
 	if (m == NULL) {
 		return ENOMEM;
 	}
+#if !defined(_NPF_STANDALONE)
 	m->m_data += max_linkhdr;
 	m->m_len = len;
 	m->m_pkthdr.len = len;
-
+	(void)npf;
+#endif
 	if (npf_iscached(npc, NPC_IP4)) {
 		struct ip *oip = npc->npc_ip.v4;
 
--- a/sys/net/npf/npf_state.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_state.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_state.c,v 1.17 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_state.c,v 1.18 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -33,13 +33,14 @@
  * NPF state engine to track connection.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.17 2014/07/20 00:37:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.18 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-
 #include <sys/mutex.h>
+#endif
 
 #include "npf_impl.h"
 
--- a/sys/net/npf/npf_state_tcp.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_state_tcp.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_state_tcp.c,v 1.16 2014/07/25 20:07:32 rmind Exp $	*/
+/*	$NetBSD: npf_state_tcp.c,v 1.17 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2012 The NetBSD Foundation, Inc.
@@ -33,15 +33,16 @@
  * NPF TCP state engine for connection tracking.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.16 2014/07/25 20:07:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.17 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <netinet/in.h>
 #include <netinet/tcp.h>
-#include <netinet/tcp_seq.h>
+#endif
 
 #include "npf_impl.h"
 
@@ -93,6 +94,11 @@
 
 #define	NPF_TCP_MAXACKWIN	66000
 
+#define	SEQ_LT(a,b)		((int)((a)-(b)) < 0)
+#define	SEQ_LEQ(a,b)		((int)((a)-(b)) <= 0)
+#define	SEQ_GT(a,b)		((int)((a)-(b)) > 0)
+#define	SEQ_GEQ(a,b)		((int)((a)-(b)) >= 0)
+
 /*
  * List of TCP flag cases and conversion of flags to a case (index).
  */
@@ -406,13 +412,13 @@
 	 * that is, upper boundary for valid data (I).
 	 */
 	if (!SEQ_LEQ(end, fstate->nst_maxend)) {
-		npf_stats_inc(NPF_STAT_INVALID_STATE_TCP1);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_INVALID_STATE_TCP1);
 		return false;
 	}
 
 	/* Lower boundary (II), which is no more than one window back. */
 	if (!SEQ_GEQ(seq, fstate->nst_end - tstate->nst_maxwin)) {
-		npf_stats_inc(NPF_STAT_INVALID_STATE_TCP2);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_INVALID_STATE_TCP2);
 		return false;
 	}
 
@@ -423,7 +429,7 @@
 	ackskew = tstate->nst_end - ack;
 	if (ackskew < -NPF_TCP_MAXACKWIN ||
 	    ackskew > (NPF_TCP_MAXACKWIN << fstate->nst_wscale)) {
-		npf_stats_inc(NPF_STAT_INVALID_STATE_TCP3);
+		npf_stats_inc(npc->npc_ctx, NPF_STAT_INVALID_STATE_TCP3);
 		return false;
 	}
 
--- a/sys/net/npf/npf_tableset.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_tableset.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_tableset.c,v 1.24 2016/12/09 02:40:38 christos Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.25 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2016 The NetBSD Foundation, Inc.
@@ -40,8 +40,9 @@
  *	entries are protected by a read-write lock.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.24 2016/12/09 02:40:38 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.25 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -57,8 +58,10 @@
 #include <sys/systm.h>
 #include <sys/types.h>
 
+#include "lpm.h"
+#endif
+
 #include "npf_impl.h"
-#include "lpm.h"
 
 typedef struct npf_tblent {
 	LIST_ENTRY(npf_tblent)	te_listent;
@@ -213,7 +216,7 @@
  * => The caller is responsible for providing synchronisation.
  */
 void
-npf_tableset_reload(npf_tableset_t *nts, npf_tableset_t *ots)
+npf_tableset_reload(npf_t *npf, npf_tableset_t *nts, npf_tableset_t *ots)
 {
 	for (u_int tid = 0; tid < nts->ts_nitems; tid++) {
 		npf_table_t *t, *ot;
@@ -247,7 +250,7 @@
 		atomic_inc_uint(&ot->t_refcnt);
 		nts->ts_map[tid] = ot;
 
-		KASSERT(npf_config_locked_p());
+		KASSERT(npf_config_locked_p(npf));
 		ot->t_id = tid;
 
 		/* Destroy the new table (we hold the only reference). */
@@ -257,11 +260,11 @@
 }
 
 int
-npf_tableset_export(const npf_tableset_t *ts, prop_array_t tables)
+npf_tableset_export(npf_t *npf, const npf_tableset_t *ts, prop_array_t tables)
 {
 	const npf_table_t *t;
 
-	KASSERT(npf_config_locked_p());
+	KASSERT(npf_config_locked_p(npf));
 
 	for (u_int tid = 0; tid < ts->ts_nitems; tid++) {
 		if ((t = ts->ts_map[tid]) == NULL) {
@@ -340,19 +343,21 @@
 {
 	npf_table_t *t;
 
-	t = kmem_zalloc(sizeof(*t), KM_SLEEP);
+	t = kmem_zalloc(sizeof(npf_table_t), KM_SLEEP);
 	strlcpy(t->t_name, name, NPF_TABLE_MAXNAMELEN);
 
 	switch (type) {
 	case NPF_TABLE_TREE:
-		if ((t->t_lpm = lpm_create()) == NULL)
+		if ((t->t_lpm = lpm_create()) == NULL) {
 			goto out;
+		}
 		LIST_INIT(&t->t_list);
 		break;
 	case NPF_TABLE_HASH:
 		t->t_hashl = hashinit(1024, HASH_LIST, true, &t->t_hashmask);
-		if (t->t_hashl == NULL)
+		if (t->t_hashl == NULL) {
 			goto out;
+		}
 		break;
 	case NPF_TABLE_CDB:
 		t->t_blob = blob;
@@ -370,12 +375,10 @@
 	rw_init(&t->t_lock);
 	t->t_type = type;
 	t->t_id = tid;
-
 	return t;
 out:
-	kmem_free(t, sizeof(*t));
+	kmem_free(t, sizeof(npf_table_t));
 	return NULL;
-	
 }
 
 /*
@@ -403,7 +406,7 @@
 		KASSERT(false);
 	}
 	rw_destroy(&t->t_lock);
-	kmem_free(t, sizeof(*t));
+	kmem_free(t, sizeof(npf_table_t));
 }
 
 /*
@@ -609,7 +612,8 @@
 		break;
 	case NPF_TABLE_CDB:
 		if (cdbr_find(t->t_cdb, addr, alen, &data, &dlen) == 0) {
-			found = dlen == alen && memcmp(addr, data, dlen) == 0;
+			found = dlen == (u_int)alen &&
+			    memcmp(addr, data, dlen) == 0;
 		} else {
 			found = false;
 		}
--- a/sys/net/npf/npf_worker.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/net/npf/npf_worker.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $	*/
+/*	$NetBSD: npf_worker.c,v 1.2 2016/12/26 23:05:06 christos Exp $	*/
 
 /*-
- * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2015 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -29,43 +29,56 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.2 2016/12/26 23:05:06 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <sys/mutex.h>
+#include <sys/kmem.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
+#include <sys/cprng.h>
+#endif
 
 #include "npf_impl.h"
 
-#define	NPF_MAX_WORKS		4
-#define	WORKER_INTERVAL		mstohz(5 * 1000)
+typedef struct npf_worker {
+	kmutex_t		worker_lock;
+	kcondvar_t		worker_cv;
+	npf_workfunc_t		work_funcs[NPF_MAX_WORKS];
+	bool			worker_exit;
+	lwp_t *			worker_lwp;
+	npf_t *			instances;
+} npf_worker_t;
 
-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;
+#define	W_INTERVAL		mstohz(1 * 1000)
 
-static npf_workfunc_t	work_funcs[NPF_MAX_WORKS];
+static void			npf_worker(void *) __dead;
 
-static void	npf_worker(void *) __dead;
+static npf_worker_t *		npf_workers		__read_mostly;
+static unsigned			npf_worker_count	__read_mostly;
 
 int
-npf_worker_sysinit(void)
+npf_worker_sysinit(unsigned nworkers)
 {
-	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;
+	npf_workers = kmem_zalloc(sizeof(npf_worker_t) * nworkers, KM_SLEEP);
+	npf_worker_count = nworkers;
+
+	for (unsigned i = 0; i < nworkers; i++) {
+		npf_worker_t *wrk = &npf_workers[i];
 
-	if (kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
-	    npf_worker, NULL, &worker_lwp, "npfgc")) {
-		return ENOMEM;
+		mutex_init(&wrk->worker_lock, MUTEX_DEFAULT, IPL_SOFTNET);
+		cv_init(&wrk->worker_cv, "npfgccv");
+
+		if (kthread_create(PRI_NONE, KTHREAD_MPSAFE |
+		    KTHREAD_MUSTJOIN, NULL, npf_worker, wrk, &wrk->worker_lwp,
+			"npfgc-%u", i)) {
+			npf_worker_sysfini();
+			return ENOMEM;
+		}
 	}
 	return 0;
 }
@@ -73,35 +86,43 @@
 void
 npf_worker_sysfini(void)
 {
-	lwp_t *l = worker_lwp;
+	for (unsigned i = 0; i < npf_worker_count; i++) {
+		npf_worker_t *wrk = &npf_workers[i];
+
+		/* Notify the worker and wait for the exit. */
+		mutex_enter(&wrk->worker_lock);
+		wrk->worker_exit = true;
+		cv_broadcast(&wrk->worker_cv);
+		mutex_exit(&wrk->worker_lock);
 
-	/* 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);
+		if (wrk->worker_lwp) {
+			kthread_join(wrk->worker_lwp);
+		}
 
-	/* LWP has exited, destroy the structures. */
-	cv_destroy(&worker_cv);
-	cv_destroy(&worker_event_cv);
-	mutex_destroy(&worker_lock);
+		/* LWP has exited, destroy the structures. */
+		cv_destroy(&wrk->worker_cv);
+		mutex_destroy(&wrk->worker_lock);
+	}
+	kmem_free(npf_workers, sizeof(npf_worker_t) * npf_worker_count);
 }
 
 void
-npf_worker_signal(void)
+npf_worker_signal(npf_t *npf)
 {
-	mutex_enter(&worker_lock);
-	cv_signal(&worker_cv);
-	mutex_exit(&worker_lock);
+	const unsigned idx = npf->worker_id;
+	npf_worker_t *wrk = &npf_workers[idx];
+
+	mutex_enter(&wrk->worker_lock);
+	cv_signal(&wrk->worker_cv);
+	mutex_exit(&wrk->worker_lock);
 }
 
 static bool
-npf_worker_testset(npf_workfunc_t find, npf_workfunc_t set)
+npf_worker_testset(npf_worker_t *wrk, 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;
+		if (wrk->work_funcs[i] == find) {
+			wrk->work_funcs[i] = set;
 			return true;
 		}
 	}
@@ -109,53 +130,74 @@
 }
 
 void
-npf_worker_register(npf_workfunc_t func)
+npf_worker_register(npf_t *npf, npf_workfunc_t func)
 {
-	mutex_enter(&worker_lock);
-	npf_worker_testset(NULL, func);
-	mutex_exit(&worker_lock);
+	const unsigned idx = cprng_fast32() % npf_worker_count;
+	npf_worker_t *wrk = &npf_workers[idx];
+
+	mutex_enter(&wrk->worker_lock);
+
+	npf->worker_id = idx;
+	npf->worker_entry = wrk->instances;
+	wrk->instances = npf;
+
+	npf_worker_testset(wrk, NULL, func);
+	mutex_exit(&wrk->worker_lock);
 }
 
 void
-npf_worker_unregister(npf_workfunc_t func)
+npf_worker_unregister(npf_t *npf, npf_workfunc_t func)
 {
-	uint64_t l = worker_loop;
+	const unsigned idx = npf->worker_id;
+	npf_worker_t *wrk = &npf_workers[idx];
+	npf_t *instance;
 
-	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_enter(&wrk->worker_lock);
+	npf_worker_testset(wrk, func, NULL);
+	if ((instance = wrk->instances) == npf) {
+		wrk->instances = instance->worker_entry;
+	} else while (instance) {
+		if (instance->worker_entry == npf) {
+			instance->worker_entry = npf->worker_entry;
+			break;
+		}
+		instance = instance->worker_entry;
 	}
-	mutex_exit(&worker_lock);
+	mutex_exit(&wrk->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;
+	npf_worker_t *wrk = arg;
+
+	KASSERT(wrk != NULL);
+	KASSERT(!wrk->worker_exit);
+
+	while (!wrk->worker_exit) {
+		npf_t *npf;
 
-		/* Run the jobs. */
-		while (i--) {
-			if ((work = work_funcs[i]) != NULL) {
-				work();
+		npf = wrk->instances;
+		while (npf) {
+			u_int i = NPF_MAX_WORKS;
+			npf_workfunc_t work;
+
+			/* Run the jobs. */
+			while (i--) {
+				if ((work = wrk->work_funcs[i]) != NULL) {
+					work(npf);
+				}
 			}
+			/* Next .. */
+			npf = npf->worker_entry;
 		}
-
-		/* Exit if requested and all jobs are done. */
-		if (finish) {
+		if (wrk->worker_exit)
 			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);
+		mutex_enter(&wrk->worker_lock);
+		cv_timedwait(&wrk->worker_cv, &wrk->worker_lock, W_INTERVAL);
+		mutex_exit(&wrk->worker_lock);
 	}
 	kthread_exit(0);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npfkern.h	Mon Dec 26 23:05:05 2016 +0000
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2015 Mindaugas Rasiukevicius <rmind at netbsd org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef _NPFKERN_H_
+#define _NPFKERN_H_
+
+#ifndef _KERNEL
+#include <stdbool.h>
+#include <inttypes.h>
+#endif
+
+struct mbuf;
+struct ifnet;
+
+#if defined(_NPF_STANDALONE) || !defined(__NetBSD__)
+#define PFIL_IN		0x00000001	// incoming packet
+#define PFIL_OUT	0x00000002	// outgoing packet
+#endif
+
+#define	NPF_NO_GC	0x01
+
+typedef struct {
+	const char *	(*getname)(struct ifnet *);
+	struct ifnet *	(*lookup)(const char *);
+	void		(*flush)(void *);
+	void *		(*getmeta)(const struct ifnet *);
+	void		(*setmeta)(struct ifnet *, void *);
+} npf_ifops_t;
+
+typedef struct {
+	struct mbuf *	(*alloc)(int, int);
+	void		(*free)(struct mbuf *);
+	void *		(*getdata)(const struct mbuf *);
+	struct mbuf *	(*getnext)(struct mbuf *);
+	size_t		(*getlen)(const struct mbuf *);
+	size_t		(*getchainlen)(const struct mbuf *);
+	bool		(*ensure_contig)(struct mbuf **, size_t);
+	bool		(*ensure_writable)(struct mbuf **, size_t);
+} npf_mbufops_t;
+
+int	npf_sysinit(unsigned);
+void	npf_sysfini(void);
+
+npf_t *	npf_create(int, const npf_mbufops_t *, const npf_ifops_t *);
+int	npf_load(npf_t *, void *, npf_error_t *);
+void	npf_gc(npf_t *);
+void	npf_destroy(npf_t *);
+
+void	npf_thread_register(npf_t *);
+int	npf_packet_handler(npf_t *, struct mbuf **, struct ifnet *, int);
+void	npf_ifmap_attach(npf_t *, struct ifnet *);
+void	npf_ifmap_detach(npf_t *, struct ifnet *);
+void	npf_stats(npf_t *, uint64_t *);
+
+#endif
--- a/sys/rump/net/lib/libnpf/Makefile	Mon Dec 26 21:54:00 2016 +0000
+++ b/sys/rump/net/lib/libnpf/Makefile	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.18 2016/12/09 02:50:06 christos Exp $
+#	$NetBSD: Makefile,v 1.19 2016/12/26 23:05:05 christos Exp $
 #
 # Public Domain.
 #
@@ -15,7 +15,7 @@
 SRCS+=	npf_bpf.c npf_if.c npf_inet.c npf_mbuf.c npf_nat.c
 SRCS+=	npf_ruleset.c npf_conn.c npf_conndb.c npf_rproc.c 
 SRCS+=	npf_state.c npf_state_tcp.c npf_tableset.c
-SRCS+=	lpm.c npf_sendpkt.c npf_worker.c
+SRCS+=	lpm.c npf_sendpkt.c npf_worker.c npf_os.c
 
 SRCS+=	if_npflog.c
 
--- a/usr.sbin/npf/npfctl/npf_bpf_comp.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npf_bpf_comp.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_bpf_comp.c,v 1.8 2015/06/08 01:00:43 rmind Exp $	*/
+/*	$NetBSD: npf_bpf_comp.c,v 1.9 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_bpf_comp.c,v 1.8 2015/06/08 01:00:43 rmind Exp $");
+__RCSID("$NetBSD: npf_bpf_comp.c,v 1.9 2016/12/26 23:05:05 christos Exp $");
 
 #include <stdlib.h>
 #include <stdbool.h>
@@ -46,6 +46,7 @@
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
+#define	__FAVOR_BSD
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
 #include <netinet/udp.h>
@@ -103,6 +104,10 @@
 #define	ALLOC_MASK		(64 - 1)
 #define	ALLOC_ROUND(x)		(((x) + ALLOC_MASK) & ~ALLOC_MASK)
 
+#ifndef IPV6_VERSION
+#define	IPV6_VERSION		0x60
+#endif
+
 npf_bpf_t *
 npfctl_bpf_create(void)
 {
--- a/usr.sbin/npf/npfctl/npf_build.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.40 2015/06/08 01:00:43 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.41 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
@@ -34,11 +34,12 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.40 2015/06/08 01:00:43 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.41 2016/12/26 23:05:05 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#define	__FAVOR_BSD
 #include <netinet/tcp.h>
 
 #include <stdlib.h>
@@ -46,6 +47,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <errno.h>
 #include <err.h>
 
@@ -80,30 +82,47 @@
 int
 npfctl_config_send(int fd, const char *out)
 {
-	int error;
+	npf_error_t errinfo;
+	int error = 0;
 
-	if (out) {
-		_npf_config_setsubmit(npf_conf, out);
-		printf("\nSaving to %s\n", out);
-	}
 	if (!defgroup) {
 		errx(EXIT_FAILURE, "default group was not defined");
 	}
 	npf_rule_insert(npf_conf, NULL, defgroup);
-	error = npf_config_submit(npf_conf, fd);
+	if (out) {
+		printf("\nSaving to %s\n", out);
+		npfctl_config_save(npf_conf, out);
+	} else {
+		error = npf_config_submit(npf_conf, fd, &errinfo);
+	}
 	if (error == EEXIST) { /* XXX */
 		errx(EXIT_FAILURE, "(re)load failed: "
 		    "some table has a duplicate entry?");
 	}
 	if (error) {
-		nl_error_t ne;
-		_npf_config_error(npf_conf, &ne);
-		npfctl_print_error(&ne);
+		npfctl_print_error(&errinfo);
 	}
-	if (fd) {
-		npf_config_destroy(npf_conf);
+	npf_config_destroy(npf_conf);
+	return error;
+}
+
+void
+npfctl_config_save(nl_config_t *ncf, const char *outfile)
+{
+	void *blob;
+	size_t len;
+	int fd;
+
+	blob = npf_config_export(ncf, &len);
+	if (!blob)
+		err(EXIT_FAILURE, "npf_config_export");
+	if ((fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1)
+		err(EXIT_FAILURE, "could not open %s", outfile);
+	if (write(fd, blob, len) != (ssize_t)len) {
+		err(EXIT_FAILURE, "write to %s failed", outfile);
 	}
-	return error;
+	free(blob);
+	close(fd);
 }
 
 nl_config_t *
@@ -742,7 +761,9 @@
 		void *cdb;
 		int fd;
 
-		strlcpy(sfn, "/tmp/npfcdb.XXXXXX", sizeof(sfn));
+		strncpy(sfn, "/tmp/npfcdb.XXXXXX", sizeof(sfn));
+		sfn[sizeof(sfn) - 1] = '\0';
+
 		if ((fd = mkstemp(sfn)) == -1) {
 			err(EXIT_FAILURE, "mkstemp");
 		}
--- a/usr.sbin/npf/npfctl/npf_data.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npf_data.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_data.c,v 1.25 2014/02/13 03:34:40 rmind Exp $	*/
+/*	$NetBSD: npf_data.c,v 1.26 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -31,11 +31,10 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_data.c,v 1.25 2014/02/13 03:34:40 rmind Exp $");
+__RCSID("$NetBSD: npf_data.c,v 1.26 2016/12/26 23:05:05 christos Exp $");
 
 #include <sys/types.h>
 #include <sys/null.h>
-
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -43,6 +42,7 @@
 #include <netinet/ip_icmp.h>
 #define ICMP6_STRINGS
 #include <netinet/icmp6.h>
+#define	__FAVOR_BSD
 #include <netinet/tcp.h>
 #include <net/if.h>
 
@@ -176,8 +176,8 @@
 		return true;
 	}
 
-	ap = addr.s6_addr + (*mask / 8) - 1;
-	while (ap >= addr.s6_addr) {
+	ap = addr.word8 + (*mask / 8) - 1;
+	while (ap >= addr.word8) {
 		for (int j = 8; j > 0; j--) {
 			if (*ap & 1)
 				return true;
@@ -456,6 +456,7 @@
 uint8_t
 npfctl_icmptype(int proto, const char *type)
 {
+#ifdef __NetBSD__
 	uint8_t ul;
 
 	switch (proto) {
@@ -475,7 +476,7 @@
 	default:
 		assert(false);
 	}
-
+#endif
 	yyerror("unknown icmp-type %s", type);
 	return ~0;
 }
@@ -483,6 +484,7 @@
 uint8_t
 npfctl_icmpcode(int proto, uint8_t type, const char *code)
 {
+#ifdef __NetBSD__
 	const char * const *arr;
 
 	switch (proto) {
@@ -565,6 +567,7 @@
 		if (strcmp(arr[ul], code) == 0)
 			return ul;
 	}
+#endif
 	yyerror("unknown code %s for icmp-type %d", code, type);
 	return ~0;
 }
--- a/usr.sbin/npf/npfctl/npf_show.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npf_show.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_show.c,v 1.19 2015/06/03 23:36:05 rmind Exp $	*/
+/*	$NetBSD: npf_show.c,v 1.20 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -36,9 +36,10 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_show.c,v 1.19 2015/06/03 23:36:05 rmind Exp $");
+__RCSID("$NetBSD: npf_show.c,v 1.20 2016/12/26 23:05:05 christos Exp $");
 
 #include <sys/socket.h>
+#define	__FAVOR_BSD
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <net/if.h>
@@ -64,15 +65,19 @@
 	uint32_t	curmark;
 } npf_conf_info_t;
 
-static npf_conf_info_t	stdout_ctx = {
-	.fp = stdout,
-	.fpos = 0,
-	.flags = 0
-};
+static npf_conf_info_t	stdout_ctx;
 
 static void	print_indent(npf_conf_info_t *, u_int);
 static void	print_linesep(npf_conf_info_t *);
 
+void
+npfctl_show_init(void)
+{
+	stdout_ctx.fp = stdout;
+	stdout_ctx.fpos = 0;
+	stdout_ctx.flags = 0;
+}
+
 /*
  * Helper routines to print various pieces of information.
  */
@@ -488,15 +493,16 @@
 {
 	npf_conf_info_t *ctx = &stdout_ctx;
 	nl_config_t *ncf;
-	bool active, loaded;
+	bool loaded;
 
 	if (fd) {
-		ncf = npf_config_retrieve(fd, &active, &loaded);
+		ncf = npf_config_retrieve(fd);
 		if (ncf == NULL) {
 			return errno;
 		}
+		loaded = npf_config_loaded_p(ncf);
 		fprintf(ctx->fp, "# filtering:\t%s\n# config:\t%s\n",
-		    active ? "active" : "inactive",
+		    npf_config_active_p(ncf) ? "active" : "inactive",
 		    loaded ? "loaded" : "empty");
 		print_linesep(ctx);
 	} else {
--- a/usr.sbin/npf/npfctl/npfctl.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.c,v 1.47 2016/06/29 21:40:20 christos Exp $	*/
+/*	$NetBSD: npfctl.c,v 1.48 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -30,12 +30,16 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npfctl.c,v 1.47 2016/06/29 21:40:20 christos Exp $");
+__RCSID("$NetBSD: npfctl.c,v 1.48 2016/12/26 23:05:05 christos Exp $");
 
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/mman.h>
+#ifdef __NetBSD__
+#include <sha1.h>
+#include <sys/ioctl.h>
 #include <sys/module.h>
+#endif
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -44,7 +48,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
-#include <sha1.h>
+
+#include <arpa/inet.h>
+#include <openssl/sha.h>
 
 #include "npfctl.h"
 
@@ -209,49 +215,47 @@
 }
 
 void
-npfctl_print_error(const nl_error_t *ne)
+npfctl_print_error(const npf_error_t *ne)
 {
-	const char *srcfile = ne->ne_source_file;
+	const char *srcfile = ne->source_file;
 
 	if (srcfile) {
-		warnx("source %s line %d", srcfile, ne->ne_source_line);
+		warnx("source %s line %d", srcfile, ne->source_line);
 	}
-	if (ne->ne_id) {
-		warnx("object: %d", ne->ne_id);
+	if (ne->id) {
+		warnx("object: %" PRIi64, ne->id);
 	}
 }
 
 char *
 npfctl_print_addrmask(int alen, const npf_addr_t *addr, npf_netmask_t mask)
 {
+	const unsigned buflen = 64;
+	char *buf = ecalloc(1, buflen);
 	struct sockaddr_storage ss;
-	char *buf = ecalloc(1, 64);
-	int len;
+
+	memset(&ss, 0, sizeof(ss));
 
 	switch (alen) {
 	case 4: {
 		struct sockaddr_in *sin = (void *)&ss;
-		sin->sin_len = sizeof(*sin);
 		sin->sin_family = AF_INET;
-		sin->sin_port = 0;
 		memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
 		break;
 	}
 	case 16: {
 		struct sockaddr_in6 *sin6 = (void *)&ss;
-		sin6->sin6_len = sizeof(*sin6);
 		sin6->sin6_family = AF_INET6;
-		sin6->sin6_port = 0;
-		sin6->sin6_scope_id = 0;
 		memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
 		break;
 	}
 	default:
 		assert(false);
 	}
-	len = sockaddr_snprintf(buf, 64, "%a", (struct sockaddr *)&ss);
+	inet_ntop(ss.ss_family, (const void *)&ss, buf, buflen);
 	if (mask && mask != NPF_NO_NETMASK) {
-		snprintf(&buf[len], 64 - len, "/%u", mask);
+		const unsigned len = strlen(buf);
+		snprintf(&buf[len], buflen - len, "/%u", mask);
 	}
 	return buf;
 }
@@ -384,16 +388,18 @@
 	return rl;
 }
 
-static void
-SHA1(const uint8_t *d, unsigned int n, uint8_t *md)
+#ifdef __NetBSD__
+unsigned char *
+SHA1(const unsigned char *d, unsigned long l, unsigned char *md)
 {
-    SHA1_CTX c;
+	SHA1_CTX c;
 
-    SHA1Init(&c);
-    SHA1Update(&c, d, n);
-    SHA1Final(md, &c);
-    memset(&c, 0, sizeof(c));
+	SHA1Init(&c);
+	SHA1Update(&c, d, l);
+	SHA1Final(md, &c);
+	return md;
 }
+#endif
 
 static void
 npfctl_generate_key(nl_rule_t *rl, void *key)
@@ -404,9 +410,9 @@
 	if ((meta = npf_rule_export(rl, &len)) == NULL) {
 		errx(EXIT_FAILURE, "error generating rule key");
 	}
-	__CTASSERT(NPF_RULE_MAXKEYLEN >= SHA1_DIGEST_LENGTH);
+	__CTASSERT(NPF_RULE_MAXKEYLEN >= SHA_DIGEST_LENGTH);
 	memset(key, 0, NPF_RULE_MAXKEYLEN);
-	SHA1(meta, (unsigned int)len, key);
+	SHA1(meta, len, key);
 	free(meta);
 }
 
@@ -471,7 +477,7 @@
 		error = npf_ruleset_flush(fd, ruleset_name);
 		break;
 	default:
-		assert(false);
+		abort();
 	}
 
 	switch (error) {
@@ -502,6 +508,7 @@
 static void
 npfctl_preload_bpfjit(void)
 {
+#ifdef __NetBSD__
 	modctl_load_t args = {
 		.ml_filename = "bpfjit",
 		.ml_flags = MODCTL_NO_PROP,
@@ -521,39 +528,45 @@
 		warnx("To disable this warning `set bpf.jit off' in "
 		    "/etc/npf.conf");
 	}
-}
-
-static int
-npfctl_save(int fd)
-{
-	nl_config_t *ncf;
-	bool active, loaded;
-	int error;
-
-	ncf = npf_config_retrieve(fd, &active, &loaded);
-	if (ncf == NULL) {
-		return errno;
-	}
-	error = npf_config_export(ncf, NPF_DB_PATH);
-	npf_config_destroy(ncf);
-	return error;
+#endif
 }
 
 static int
 npfctl_load(int fd)
 {
 	nl_config_t *ncf;
+	npf_error_t errinfo;
+	struct stat sb;
+	size_t blen;
+	void *blob;
 	int error;
 
-	ncf = npf_config_import(NPF_DB_PATH);
+	/*
+	 * The file may change while reading - we are not handling this,
+	 * leaving this responsibility for the caller.
+	 */
+	if (stat(NPF_DB_PATH, &sb) == -1) {
+		err(EXIT_FAILURE, "stat");
+	}
+	if ((blen = sb.st_size) == 0) {
+		err(EXIT_FAILURE, "saved configuration file is empty");
+	}
+	if ((blob = mmap(NULL, blen, PROT_READ,
+	    MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+		err(EXIT_FAILURE, "mmap");
+	}
+	ncf = npf_config_import(blob, blen);
+	munmap(blob, blen);
 	if (ncf == NULL) {
 		return errno;
 	}
-	errno = error = npf_config_submit(ncf, fd);
+
+	/*
+	 * Configuration imported - submit it now.
+	 **/
+	errno = error = npf_config_submit(ncf, fd, &errinfo);
 	if (error) {
-		nl_error_t ne;
-		_npf_config_error(ncf, &ne);
-		npfctl_print_error(&ne);
+		npfctl_print_error(&errinfo);
 	}
 	npf_config_destroy(ncf);
 	return error;
@@ -563,6 +576,8 @@
 npfctl(int action, int argc, char **argv)
 {
 	int fd, ver, boolval, ret = 0;
+	nl_config_t *ncf;
+	const char *fun = "";
 
 	fd = open(NPF_DEV_PATH, O_RDONLY);
 	if (fd == -1) {
@@ -577,7 +592,6 @@
 		    "Hint: update userland?", NPF_VERSION, ver);
 	}
 
-	const char *fun = "";
 	switch (action) {
 	case NPFCTL_START:
 		boolval = true;
@@ -630,7 +644,13 @@
 		fun = "npfctl_config_load";
 		break;
 	case NPFCTL_SAVE:
-		fd = npfctl_save(fd);
+		ncf = npf_config_retrieve(fd);
+		if (ncf) {
+			npfctl_config_save(ncf, NPF_DB_PATH);
+			npf_config_destroy(ncf);
+		} else {
+			ret = errno;
+		}
 		fun = "npfctl_config_save";
 		break;
 	case NPFCTL_STATS:
@@ -652,6 +672,7 @@
 	if (argc < 2) {
 		usage();
 	}
+	npfctl_show_init();
 	cmd = argv[1];
 
 	if (strcmp(cmd, "debug") == 0) {
--- a/usr.sbin/npf/npfctl/npfctl.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.39 2014/12/26 22:44:54 christos Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.40 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -110,7 +110,7 @@
 void		npfctl_parse_file(const char *);
 void		npfctl_parse_string(const char *);
 
-void		npfctl_print_error(const nl_error_t *);
+void		npfctl_print_error(const npf_error_t *);
 char *		npfctl_print_addrmask(int, const npf_addr_t *, npf_netmask_t);
 void		npfctl_note_interface(const char *);
 unsigned	npfctl_table_getid(const char *);
@@ -182,6 +182,9 @@
 int		npfctl_config_send(int, const char *);
 nl_config_t *	npfctl_config_ref(void);
 int		npfctl_config_show(int);
+void		npfctl_config_save(nl_config_t *, const char *);
+
+void		npfctl_show_init(void);
 int		npfctl_ruleset_show(int, const char *);
 
 nl_rule_t *	npfctl_rule_ref(void);
@@ -200,4 +203,14 @@
 void		npfctl_build_maprset(const char *, int, const char *);
 void		npfctl_build_table(const char *, u_int, const char *);
 
+/*
+ * For the systems which do not define TH_ECE and TW_CRW.
+ */
+#ifndef TH_ECE
+#define	TH_ECE	  0x40
 #endif
+#ifndef TH_CWR
+#define	TH_CWR	  0x80
+#endif
+
+#endif
--- a/usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_bpf_test.c,v 1.7 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_bpf_test.c,v 1.8 2016/12/26 23:05:05 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -33,8 +33,10 @@
  * NPF test of BPF coprocessor.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/endian.h>
+#endif
 
 #define	NPF_BPFCOP
 #include "npf_impl.h"
@@ -62,7 +64,7 @@
 test_bpf_code(void *code, size_t size)
 {
 	ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
-	npf_cache_t npc = { .npc_info = 0 };
+	npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() };
 	uint32_t memstore[BPF_MEMWORDS];
 	bpf_args_t bc_args;
 	struct mbuf *m;
@@ -72,11 +74,14 @@
 
 	/* Layer 3 (IP + TCP). */
 	m = fill_packet(IPPROTO_TCP);
-	nbuf_init(&nbuf, m, dummy_ifp);
+	nbuf_init(npf_getkernctx(), &nbuf, m, dummy_ifp);
 	npc.npc_nbuf = &nbuf;
 	npf_cache_all(&npc);
-
+#ifdef _NPF_STANDALONE
+	bc_args.pkt = (const uint8_t *)nbuf_dataptr(&nbuf);
+#else
 	bc_args.pkt = (const uint8_t *)m;
+#endif
 	bc_args.buflen = m_length(m);
 	bc_args.wirelen = bc_args.buflen;
 	bc_args.mem = memstore;
--- a/usr.sbin/npf/npftest/libnpftest/npf_mbuf_subr.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_mbuf_subr.c	Mon Dec 26 23:05:05 2016 +0000
@@ -6,12 +6,108 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/kmem.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
 
+
+#if defined(_NPF_STANDALONE)
+struct mbuf *
+npfkern_m_get(int flags, int space)
+{
+	unsigned mlen = offsetof(struct mbuf, m_data0[space]);
+	struct mbuf *m;
+
+	m = calloc(1, sizeof(struct mbuf));
+	if (m) {
+		m->m_type = 1;
+		m->m_flags = flags;
+		m->m_data = m->m_data0;
+	}
+	return m;
+}
+#else
+struct mbuf *
+npfkern_m_get(int flags, int space)
+{
+	return m_get(flags, space);
+}
+#endif
+
+static void *
+npfkern_m_getdata(const struct mbuf *m)
+{
+	return m->m_data;
+}
+
+static struct mbuf *
+npfkern_m_next(struct mbuf *m)
+{
+	return m->m_next;
+}
+
+static size_t
+npfkern_m_buflen(const struct mbuf *m)
+{
+	return m->m_len;
+}
+
+size_t
+npfkern_m_length(const struct mbuf *m)
+{
+	const struct mbuf *m0;
+	unsigned pktlen = 0;
+
+	if ((m->m_flags & M_PKTHDR) != 0)
+		return m->m_pkthdr.len;
+	for (m0 = m; m0 != NULL; m0 = m0->m_next)
+		pktlen += m0->m_len;
+	return pktlen;
+}
+
+void
+npfkern_m_freem(struct mbuf *m)
+{
+#ifdef _NPF_STANDALONE
+	struct mbuf *n;
+
+	do {
+		n = m->m_next;
+		m->m_type = MT_FREE;
+		free(m);
+		m = n;
+	} while (m);
+#else
+	m_freem(m);
+#endif
+}
+
+static bool
+npfkern_m_ensure_contig(struct mbuf **m0, size_t len)
+{
+	struct mbuf *m1;
+	unsigned tlen;
+	char *dptr;
+
+	tlen = npfkern_m_length(*m0);
+	if ((m1 = npfkern_m_get(M_PKTHDR, tlen)) == NULL) {
+		return false;
+	}
+	m1->m_pkthdr.len = m1->m_len = tlen;
+	dptr = m1->m_data;
+	for (struct mbuf *m = *m0; m != NULL; m = m->m_next) {
+		memcpy(dptr, m->m_data, m->m_len);
+		dptr += m->m_len;
+	}
+	*m0 = m1;
+	return true;
+}
+
+
 struct mbuf *
 mbuf_getwithdata(const void *data, size_t len)
 {
@@ -159,3 +255,14 @@
 	m->m_len += addlen;
 	m_freem(m_orig);
 }
+
+const npf_mbufops_t npftest_mbufops = {
+	.alloc			= npfkern_m_get,
+	.free			= npfkern_m_freem,
+	.getdata		= npfkern_m_getdata,
+	.getnext		= npfkern_m_next,
+	.getlen			= npfkern_m_buflen,
+	.getchainlen		= npfkern_m_length,
+	.ensure_contig		= npfkern_m_ensure_contig,
+	.ensure_writable	= NULL,
+};
--- a/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat_test.c,v 1.9 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_nat_test.c,v 1.10 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF NAT test.
@@ -6,7 +6,9 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -154,7 +156,7 @@
 checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error)
 {
 	const struct test_case *t = &test_cases[i];
-	npf_cache_t npc = { .npc_info = 0 };
+	npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() };
 	const int af = t->af;
 	nbuf_t nbuf;
 
@@ -165,7 +167,7 @@
 		return error == t->ret;
 	}
 
-	nbuf_init(&nbuf, m, ifp);
+	nbuf_init(npf_getkernctx(), &nbuf, m, ifp);
 	npc.npc_nbuf = &nbuf;
 	if (!npf_cache_all(&npc)) {
 		printf("error: could not fetch the packet data");
@@ -234,9 +236,11 @@
 bool
 npf_nat_test(bool verbose)
 {
+	npf_t *npf = npf_getkernctx();
+
 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
 		const struct test_case *t = &test_cases[i];
-		ifnet_t *ifp = ifunit(t->ifname);
+		ifnet_t *ifp = npf_test_getif(t->ifname);
 		struct mbuf *m = fill_packet(t);
 		int error;
 		bool ret;
@@ -245,7 +249,7 @@
 			printf("Interface %s is not configured.\n", t->ifname);
 			return false;
 		}
-		error = npf_packet_handler(NULL, &m, ifp, t->di);
+		error = npf_packet_handler(npf, &m, ifp, t->di);
 		ret = checkresult(verbose, i, m, ifp, error);
 		if (m) {
 			m_freem(m);
--- a/usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nbuf_test.c,v 1.5 2013/11/08 00:38:27 rmind Exp $	*/
+/*	$NetBSD: npf_nbuf_test.c,v 1.6 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF nbuf interface test.
@@ -6,8 +6,10 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/kmem.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -36,7 +38,7 @@
 	void *nptr;
 	int n;
 
-	nbuf_init(&nbuf, m, dummy_ifp);
+	nbuf_init(npf_getkernctx(), &nbuf, m, dummy_ifp);
 
 	nptr = nbuf_advance(&nbuf, (random() % 16) + 1, (random() % 16) + 1);
 	mbuf_consistency_check(&nbuf);
--- a/usr.sbin/npf/npftest/libnpftest/npf_perf_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_perf_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_perf_test.c,v 1.4 2014/06/25 00:21:42 rmind Exp $	*/
+/*	$NetBSD: npf_perf_test.c,v 1.5 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF benchmarking.
@@ -6,12 +6,14 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/param.h>
 
 #include <sys/kernel.h>
 #include <sys/kmem.h>
 #include <sys/kthread.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -46,7 +48,8 @@
 __dead static void
 worker(void *arg)
 {
-	ifnet_t *ifp = ifunit(IFNAME_INT);
+	npf_t *npf = npf_getkernctx();
+	ifnet_t *ifp = npf_test_getif(IFNAME_INT);
 	unsigned int i = (uintptr_t)arg;
 	struct mbuf *m = fill_packet(i);
 	uint64_t n = 0;
@@ -56,7 +59,7 @@
 	while (!done) {
 		int error;
 
-		error = npf_packet_handler(NULL, &m, ifp, PFIL_OUT);
+		error = npf_packet_handler(npf, &m, ifp, PFIL_OUT);
 		KASSERT(error == 0);
 		n++;
 	}
@@ -80,15 +83,15 @@
 	l = kmem_zalloc(sizeof(lwp_t *) * nthreads, KM_SLEEP);
 
 	for (unsigned i = 0; i < nthreads; i++) {
-		const int flags = KTHREAD_MUSTJOIN | KTHREAD_MPSAFE;
-		error = kthread_create(PRI_NONE, flags, NULL,
-		    worker, (void *)(uintptr_t)i, &l[i], "npfperf");
+		error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN |
+		    KTHREAD_MPSAFE, NULL, worker, (void *)(uintptr_t)i,
+		    &l[i], "npfperf");
 		KASSERT(error == 0);
 	}
 
 	/* Let them spin! */
 	run = true;
-	kpause("perf", false, NSECS * hz, NULL);
+	kpause("perf", false, mstohz(NSECS * 1000), NULL);
 	done = true;
 
 	/* Wait until all threads exit and sum the counts. */
--- a/usr.sbin/npf/npftest/libnpftest/npf_rule_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_rule_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_rule_test.c,v 1.12 2014/08/10 19:09:43 rmind Exp $	*/
+/*	$NetBSD: npf_rule_test.c,v 1.13 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF ruleset test.
@@ -6,7 +6,9 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -74,17 +76,18 @@
 static int
 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di)
 {
-	npf_cache_t npc = { .npc_info = 0 };
+	npf_t *npf = npf_getkernctx();
+	npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf };
 	nbuf_t nbuf;
 	npf_rule_t *rl;
 	int retfl, error;
 
-	nbuf_init(&nbuf, m, ifp);
+	nbuf_init(npf, &nbuf, m, ifp);
 	npc.npc_nbuf = &nbuf;
 	npf_cache_all(&npc);
 
 	int slock = npf_config_read_enter();
-	rl = npf_ruleset_inspect(&npc, npf_config_ruleset(),
+	rl = npf_ruleset_inspect(&npc, npf_config_ruleset(npf),
 	    di, NPF_LAYER_3);
 	if (rl) {
 		error = npf_rule_conclude(rl, &retfl);
@@ -99,7 +102,7 @@
 npf_test_case(u_int i, bool verbose)
 {
 	const struct test_case *t = &test_cases[i];
-	ifnet_t *ifp = ifunit(t->ifname);
+	ifnet_t *ifp = npf_test_getif(t->ifname);
 	int error;
 
 	struct mbuf *m = fill_packet(t);
@@ -111,17 +114,19 @@
 static npf_rule_t *
 npf_blockall_rule(void)
 {
+	npf_t *npf = npf_getkernctx();
 	prop_dictionary_t rldict;
 
 	rldict = prop_dictionary_create();
 	prop_dictionary_set_uint32(rldict, "attr",
 	    NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
-	return npf_rule_alloc(rldict);
+	return npf_rule_alloc(npf, rldict);
 }
 
 bool
 npf_rule_test(bool verbose)
 {
+	npf_t *npf = npf_getkernctx();
 	npf_ruleset_t *rlset;
 	npf_rule_t *rl;
 	bool fail = false;
@@ -130,7 +135,7 @@
 
 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
 		const struct test_case *t = &test_cases[i];
-		ifnet_t *ifp = ifunit(t->ifname);
+		ifnet_t *ifp = npf_test_getif(t->ifname);
 		int serror;
 
 		if (ifp == NULL) {
@@ -140,7 +145,7 @@
 
 		struct mbuf *m = fill_packet(t);
 		error = npf_rule_raw_test(verbose, m, ifp, t->di);
-		serror = npf_packet_handler(NULL, &m, ifp, t->di);
+		serror = npf_packet_handler(npf, &m, ifp, t->di);
 
 		if (m) {
 			m_freem(m);
@@ -161,8 +166,8 @@
 	error = npf_test_case(0, verbose);
 	assert(error == RESULT_PASS);
 
-	npf_config_enter();
-	rlset = npf_config_ruleset();
+	npf_config_enter(npf);
+	rlset = npf_config_ruleset(npf);
 
 	rl = npf_blockall_rule();
 	error = npf_ruleset_add(rlset, "test-rules", rl);
@@ -175,7 +180,7 @@
 	error = npf_ruleset_remove(rlset, "test-rules", id);
 	fail |= error != 0;
 
-	npf_config_exit();
+	npf_config_exit(npf);
 
 	error = npf_test_case(0, verbose);
 	fail |= (error != RESULT_PASS);
--- a/usr.sbin/npf/npftest/libnpftest/npf_state_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_state_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_state_test.c,v 1.6 2014/07/20 00:37:41 rmind Exp $	*/
+/*	$NetBSD: npf_state_test.c,v 1.7 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF state tracking test.
@@ -6,8 +6,10 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/kmem.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -135,7 +137,7 @@
 {
 	ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
 	const tcp_meta_t *p = &packet_sequence[i];
-	npf_cache_t npc = { .npc_info = 0 };
+	npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() };
 	nbuf_t nbuf;
 	int ret;
 
@@ -145,7 +147,7 @@
 		return true;
 	}
 
-	nbuf_init(&nbuf, construct_packet(p), dummy_ifp);
+	nbuf_init(npf_getkernctx(), &nbuf, construct_packet(p), dummy_ifp);
 	npc.npc_nbuf = &nbuf;
 	ret = npf_cache_all(&npc);
 	KASSERT((ret & NPC_IPFRAG) == 0);
--- a/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_table_test.c,v 1.8 2014/02/06 02:51:28 rmind Exp $	*/
+/*	$NetBSD: npf_table_test.c,v 1.9 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF tableset test.
@@ -6,8 +6,16 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/malloc.h>
+#endif
+
+#ifdef __linux__
+#include <endian.h>
+#else
+#include <sys/endian.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -23,25 +31,36 @@
 	"10.0.0.2",
 };
 
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define	U16_TO_LE(x)	((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
+#else
+#define	U16_TO_LE(x)	(x)
+#endif
+
 static const uint16_t ip6_list[][8] = {
 	{
-	    htons(0xfe80), 0x0, 0x0, 0x0,
-	    htons(0x2a0), htons(0xc0ff), htons(0xfe10), htons(0x1234)
+	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
+	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff),
+	    U16_TO_LE(0xfe10), U16_TO_LE(0x1234)
 	},
 	{
-	    htons(0xfe80), 0x0, 0x0, 0x0,
-	    htons(0x2a0), htons(0xc0ff), 0x00, 0x0
+	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
+	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff), 0x00, 0x0
 	},
 	{
-	    htons(0xfe80), 0x0, 0x0, 0x0,
+	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
 	    0x0, 0x0, 0x0, 0x0
 	},
 	{
-	    htons(0xfe80), 0x0, 0x0, 0x0,
-	    htons(0x2a0), htons(0xc0ff), htons(0xfe10), htons(0x1230)
+	    U16_TO_LE(0xfe80), 0x0, 0x0, 0x0,
+	    U16_TO_LE(0x2a0), U16_TO_LE(0xc0ff),
+	    U16_TO_LE(0xfe10), U16_TO_LE(0x1230)
 	}
 };
 
+#define	check_ok(x)	\
+    ((x) ? true : (printf("fail at line %d\n", __LINE__), false))
+
 #define	HASH_TID		"hash-table"
 #define	TREE_TID		"tree-table"
 #define	CDB_TID			"cdb-table"
@@ -58,19 +77,19 @@
 		npf_table_t *t;
 		int error;
 
-		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+		addr->word32[0] = inet_addr(ip_list[i]);
 
 		t = npf_tableset_getbyname(tblset, HASH_TID);
 		error = npf_table_insert(t, alen, addr, nm);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 		error = npf_table_insert(t, alen, addr, nm);
-		fail |= !(error != 0);
+		fail |= !check_ok(error != 0);
 
 		t = npf_tableset_getbyname(tblset, TREE_TID);
 		error = npf_table_insert(t, alen, addr, nm);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 		error = npf_table_insert(t, alen, addr, nm);
-		fail |= !(error != 0);
+		fail |= !check_ok(error != 0);
 	}
 	return fail;
 }
@@ -88,23 +107,23 @@
 	u_int i;
 
 	tblset = npf_tableset_create(3);
-	fail |= !(tblset != NULL);
+	fail |= !check_ok(tblset != NULL);
 
 	/* Table ID 1, using hash table with 256 lists. */
 	t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, NULL, 256);
-	fail |= !(t1 != NULL);
+	fail |= !check_ok(t1 != NULL);
 	error = npf_tableset_insert(tblset, t1);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	/* Check for double-insert. */
 	error = npf_tableset_insert(tblset, t1);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	/* Table ID 2, using a prefix tree. */
 	t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, NULL, 0);
 	fail |= !(t2 != NULL);
 	error = npf_tableset_insert(tblset, t2);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	/* Table ID 3, using a CDB. */
 	cdb = malloc(size, M_TEMP, M_WAITOK);
@@ -113,46 +132,46 @@
 	t3 = npf_table_create(CDB_TID, 2, NPF_TABLE_CDB, cdb, size);
 	fail |= !(t3 != NULL);
 	error = npf_tableset_insert(tblset, t3);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	/* Attempt to match non-existing entries - should fail. */
-	addr->s6_addr32[0] = inet_addr(ip_list[0]);
+	addr->word32[0] = inet_addr(ip_list[0]);
 	alen = sizeof(struct in_addr);
 
 	t = npf_tableset_getbyname(tblset, HASH_TID);
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	t = npf_tableset_getbyname(tblset, TREE_TID);
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	/* Fill both tables with IP addresses. */
 	fail |= npf_table_test_fill4(tblset, addr);
 
 	/* Attempt to add duplicates - should fail. */
-	addr->s6_addr32[0] = inet_addr(ip_list[0]);
+	addr->word32[0] = inet_addr(ip_list[0]);
 	alen = sizeof(struct in_addr);
 
 	t = npf_tableset_getbyname(tblset, HASH_TID);
 	error = npf_table_insert(t, alen, addr, nm);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	t = npf_tableset_getbyname(tblset, TREE_TID);
 	error = npf_table_insert(t, alen, addr, nm);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	/* Match (validate) each IP entry. */
 	for (i = 0; i < __arraycount(ip_list); i++) {
-		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+		addr->word32[0] = inet_addr(ip_list[i]);
 
 		t = npf_tableset_getbyname(tblset, HASH_TID);
 		error = npf_table_lookup(t, alen, addr);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 
 		t = npf_tableset_getbyname(tblset, TREE_TID);
 		error = npf_table_lookup(t, alen, addr);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 	}
 
 	/* IPv6 addresses. */
@@ -161,19 +180,19 @@
 
 	t = npf_tableset_getbyname(tblset, HASH_TID);
 	error = npf_table_insert(t, alen, addr, nm);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 	error = npf_table_remove(t, alen, addr, nm);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	t = npf_tableset_getbyname(tblset, TREE_TID);
 	error = npf_table_insert(t, alen, addr, nm);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 	error = npf_table_remove(t, alen, addr, nm);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	/*
 	 * Masking: 96, 32, 127.
@@ -181,69 +200,69 @@
 
 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
 	error = npf_table_insert(t, alen, addr, 96);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	memcpy(addr, ip6_list[1], sizeof(ip6_list[1]));
 	error = npf_table_remove(t, alen, addr, 96);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 
 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
 	error = npf_table_insert(t, alen, addr, 32);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	memcpy(addr, ip6_list[2], sizeof(ip6_list[2]));
 	error = npf_table_remove(t, alen, addr, 32);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 
 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
 	error = npf_table_insert(t, alen, addr, 126);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	memcpy(addr, ip6_list[0], sizeof(ip6_list[0]));
 	error = npf_table_lookup(t, alen, addr);
-	fail |= !(error != 0);
+	fail |= !check_ok(error != 0);
 
 	memcpy(addr, ip6_list[3], sizeof(ip6_list[3]));
 	error = npf_table_remove(t, alen, addr, 126);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 
 	alen = sizeof(struct in_addr);
 
 	/* Remove all IPv4 entries. */
 	for (i = 0; i < __arraycount(ip_list); i++) {
-		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+		addr->word32[0] = inet_addr(ip_list[i]);
 
 		t = npf_tableset_getbyname(tblset, HASH_TID);
 		error = npf_table_remove(t, alen, addr, nm);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 
 		t = npf_tableset_getbyname(tblset, TREE_TID);
 		error = npf_table_remove(t, alen, addr, nm);
-		fail |= !(error == 0);
+		fail |= !check_ok(error == 0);
 	}
 
 	/* Test CDB. */
-	addr->s6_addr32[0] = inet_addr(ip_list[0]);
+	addr->word32[0] = inet_addr(ip_list[0]);
 	alen = sizeof(struct in_addr);
 	error = npf_table_lookup(t3, alen, addr);
-	fail |= !(error == 0);
+	fail |= !check_ok(error == 0);
 
 	for (i = 1; i < __arraycount(ip_list) - 1; i++) {
-		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+		addr->word32[0] = inet_addr(ip_list[i]);
 		alen = sizeof(struct in_addr);
 		error = npf_table_lookup(t3, alen, addr);
-		fail |= !(error != 0);
+		fail |= !check_ok(error != 0);
 	}
 
 	npf_tableset_destroy(tblset);
--- a/usr.sbin/npf/npftest/libnpftest/npf_test.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_test.h	Mon Dec 26 23:05:05 2016 +0000
@@ -7,6 +7,7 @@
 #ifndef _LIB_NPF_TEST_H_
 #define _LIB_NPF_TEST_H_
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/mbuf.h>
 
@@ -23,6 +24,7 @@
 #include <net/if.h>
 #include <net/if_ether.h>
 #include <net/ethertypes.h>
+#endif
 
 /* Test interfaces and IP addresses. */
 #define	IFNAME_EXT	"npftest0"
@@ -46,9 +48,46 @@
 #define	REMOTE_IP6	"2001:db8:fefe::1010"
 #define	EXPECTED_IP6	"2001:db8:1:d550::1234"
 
+#if defined(_NPF_STANDALONE)
+
+#define	MLEN		512
+
+struct mbuf {
+	unsigned	m_flags;
+	int		m_type;
+	unsigned	m_len;
+	void *		m_next;
+	struct {
+		int	len;
+	} m_pkthdr;
+	char *		m_data;
+	char		m_data0[MLEN];
+};
+
+
+#define	MT_FREE			0
+#define	M_UNWRITABLE(m, l)	false
+#define	M_NOWAIT		0x00001
+#define M_PKTHDR		0x00002
+
+#define	m_get(x, y)		npfkern_m_get(0, MLEN)
+#define	m_gethdr(x, y)		npfkern_m_get(M_PKTHDR, MLEN)
+#define	m_length(m)		npfkern_m_length(m)
+#define	m_freem(m)		npfkern_m_freem(m)
+#define	mtod(m, t)		((t)((m)->m_data))
+
+#endif
+
+const npf_mbufops_t	npftest_mbufops;
+
+struct mbuf *	npfkern_m_get(int, int);
+size_t		npfkern_m_length(const struct mbuf *);
+void		npfkern_m_freem(struct mbuf *);
+
 void		npf_test_init(int (*)(int, const char *, void *),
 		    const char *(*)(int, const void *, char *, socklen_t),
 		    long (*)(void));
+void		npf_test_fini(void);
 int		npf_test_load(const void *);
 ifnet_t *	npf_test_addif(const char *, bool, bool);
 ifnet_t *	npf_test_getif(const char *);
--- a/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_test_subr.c,v 1.11 2014/08/10 16:44:37 tls Exp $	*/
+/*	$NetBSD: npf_test_subr.c,v 1.12 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF initialisation and handler routines.
@@ -6,10 +6,12 @@
  * Public Domain.
  */
 
+#ifdef _KERNEL
 #include <sys/types.h>
 #include <sys/cprng.h>
 #include <net/if.h>
 #include <net/if_types.h>
+#endif
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -25,28 +27,72 @@
 
 static void		npf_state_sample(npf_state_t *, bool);
 
+#ifndef __NetBSD__
+/*
+ * Standalone NPF: we define the same struct ifnet members
+ * to reduce the npf_ifops_t implementation differences.
+ */
+struct ifnet {
+	char		if_xname[32];
+	void *		if_softc;
+	TAILQ_ENTRY(ifnet) if_list;
+};
+#endif
+
+static TAILQ_HEAD(, ifnet) npftest_ifnet_list =
+    TAILQ_HEAD_INITIALIZER(npftest_ifnet_list);
+
+static const char *	npftest_ifop_getname(ifnet_t *);
+static void		npftest_ifop_flush(void *);
+static void *		npftest_ifop_getmeta(const ifnet_t *);
+static void		npftest_ifop_setmeta(ifnet_t *, void *);
+
+static const npf_ifops_t npftest_ifops = {
+	.getname	= npftest_ifop_getname,
+	.lookup		= npf_test_getif,
+	.flush		= npftest_ifop_flush,
+	.getmeta	= npftest_ifop_getmeta,
+	.setmeta	= npftest_ifop_setmeta,
+};
+
 void
 npf_test_init(int (*pton_func)(int, const char *, void *),
     const char *(*ntop_func)(int, const void *, char *, socklen_t),
     long (*rndfunc)(void))
 {
+	npf_t *npf;
+
+	npf_sysinit(1);
+	npf = npf_create(0, &npftest_mbufops, &npftest_ifops);
+	npf_thread_register(npf);
+	npf_setkernctx(npf);
+
 	npf_state_setsampler(npf_state_sample);
 	_pton_func = pton_func;
 	_ntop_func = ntop_func;
 	_random_func = rndfunc;
 }
 
+void
+npf_test_fini(void)
+{
+	npf_t *npf = npf_getkernctx();
+	npf_destroy(npf);
+	npf_sysfini();
+}
+
 int
 npf_test_load(const void *xml)
 {
 	prop_dictionary_t npf_dict = prop_dictionary_internalize(xml);
-	return npfctl_load(0, npf_dict);
+	return npfctl_load(npf_getkernctx(), 0, npf_dict);
 }
 
 ifnet_t *
 npf_test_addif(const char *ifname, bool reg, bool verbose)
 {
-	ifnet_t *ifp = if_alloc(IFT_OTHER);
+	npf_t *npf = npf_getkernctx();
+	ifnet_t *ifp = malloc(sizeof(*ifp), M_TEST, M_WAITOK|M_ZERO);
 
 	/*
 	 * This is a "fake" interface with explicitly set index.
@@ -54,14 +100,11 @@
 	 * may not trigger npf_ifmap_attach(), so we call it manually.
 	 */
 	strlcpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
-	ifp->if_dlt = DLT_NULL;
-	ifp->if_index = 0;
-	if_attach(ifp);
-	if_alloc_sadl(ifp);
+	TAILQ_INSERT_TAIL(&npftest_ifnet_list, ifp, if_list);
 
-	npf_ifmap_attach(ifp);
+	npf_ifmap_attach(npf, ifp);
 	if (reg) {
-		npf_ifmap_register(ifname);
+		npf_ifmap_register(npf, ifname);
 	}
 
 	if (verbose) {
@@ -70,10 +113,43 @@
 	return ifp;
 }
 
+static const char *
+npftest_ifop_getname(ifnet_t *ifp)
+{
+	return ifp->if_xname;
+}
+
 ifnet_t *
 npf_test_getif(const char *ifname)
 {
-	return ifunit(ifname);
+	ifnet_t *ifp;
+
+	TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list) {
+		if (!strcmp(ifp->if_xname, ifname))
+			return ifp;
+	}
+	return NULL;
+}
+
+static void
+npftest_ifop_flush(void *arg)
+{
+	ifnet_t *ifp;
+
+	TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list)
+		ifp->if_softc = arg;
+}
+
+static void *
+npftest_ifop_getmeta(const ifnet_t *ifp)
+{
+	return ifp->if_softc;
+}
+
+static void
+npftest_ifop_setmeta(ifnet_t *ifp, void *arg)
+{
+	ifp->if_softc = arg;
 }
 
 /*
@@ -92,11 +168,12 @@
 npf_test_statetrack(const void *data, size_t len, ifnet_t *ifp,
     bool forw, int64_t *result)
 {
+	npf_t *npf = npf_getkernctx();
 	struct mbuf *m;
 	int i = 0, error;
 
 	m = mbuf_getwithdata(data, len);
-	error = npf_packet_handler(NULL, &m, ifp, forw ? PFIL_OUT : PFIL_IN);
+	error = npf_packet_handler(npf, &m, ifp, forw ? PFIL_OUT : PFIL_IN);
 	if (error) {
 		assert(m == NULL);
 		return error;
@@ -137,6 +214,7 @@
 	return _ntop_func(af, src, dst, size);
 }
 
+#ifdef _KERNEL
 /*
  * Need to override cprng_fast32() -- we need deterministic PRNG.
  */
@@ -145,3 +223,4 @@
 {
 	return (uint32_t)(_random_func ? _random_func() : random());
 }
+#endif
--- a/usr.sbin/npf/npftest/npfstream.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/npfstream.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfstream.c,v 1.6 2013/11/08 00:38:26 rmind Exp $	*/
+/*	$NetBSD: npfstream.c,v 1.7 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF stream processor.
@@ -16,6 +16,7 @@
 
 #include <arpa/inet.h>
 
+#if !defined(_NPF_STANDALONE)
 #include <net/if.h>
 #include <net/ethertypes.h>
 #include <net/if_ether.h>
@@ -25,6 +26,7 @@
 #include <netinet/tcp.h>
 
 #include <rump/rump.h>
+#endif
 
 #include "npftest.h"
 
--- a/usr.sbin/npf/npftest/npftest.c	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/npftest.c	Mon Dec 26 23:05:05 2016 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npftest.c,v 1.19 2016/01/25 12:24:41 pooka Exp $	*/
+/*	$NetBSD: npftest.c,v 1.20 2016/12/26 23:05:05 christos Exp $	*/
 
 /*
  * NPF testing framework.
@@ -16,6 +16,8 @@
 #include <err.h>
 
 #include <sys/mman.h>
+#include <sys/stat.h>
+#if !defined(_NPF_STANDALONE)
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <arpa/inet.h>
@@ -24,6 +26,7 @@
 
 #include <rump/rump.h>
 #include <rump/rump_syscalls.h>
+#endif
 
 #include <cdbw.h>
 
@@ -32,7 +35,7 @@
 static bool verbose, quiet;
 
 __dead static void
-usage(void)
+usage(const char *progname)
 {
 	printf("usage:\n"
 	    "  %s [ -q | -v ] [ -c <config> ] "
@@ -49,7 +52,7 @@
 	    "\t-L: list testnames and description for -T\n"
 	    "\t-q: quiet mode\n"
 	    "\t-v: verbose mode\n",
-	    getprogname(), getprogname(), getprogname());
+	    progname, progname, progname);
 	exit(EXIT_FAILURE);
 }
 
@@ -117,7 +120,7 @@
 	/* Pass the XML configuration for NPF kernel component to load. */
 	error = rumpns_npf_test_load(xml);
 	if (error) {
-		errx(EXIT_FAILURE, "npf_test_load: %s", strerror(error));
+		errx(EXIT_FAILURE, "npf_test_load: %s\n", strerror(error));
 	}
 	free(xml);
 
@@ -171,6 +174,27 @@
 	return cdb;
 }
 
+static void
+npf_kern_init(void)
+{
+#if !defined(_NPF_STANDALONE)
+	/* XXX rn_init */
+	extern int rumpns_max_keylen;
+	rumpns_max_keylen = 1;
+
+	rump_init();
+	rump_schedule();
+#endif
+}
+
+static void
+npf_kern_fini(void)
+{
+#if !defined(_NPF_STANDALONE)
+	rump_unschedule();
+#endif
+}
+
 int
 main(int argc, char **argv)
 {
@@ -226,14 +250,13 @@
 			/* Note: RUMP_NCPU must be high enough. */
 			if ((nthreads = atoi(optarg)) > 0 &&
 			    getenv("RUMP_NCPU") == NULL) {
-				char *val;
-				asprintf(&val, "%u", nthreads + 1);
-				setenv("RUMP_NCPU", val, 1);
-				free(val);
+				static char nthr[64];
+				sprintf(nthr, "%u", nthreads + 1);
+				setenv("RUMP_NCPU", nthr, 1);
 			}
 			break;
 		default:
-			usage();
+			usage(argv[0]);
 		}
 	}
 
@@ -243,20 +266,17 @@
 	 * config should be loaded.
 	 */
 	if ((benchmark != NULL) == test && (stream && !interface)) {
-		usage();
+		usage(argv[0]);
 	}
 	if (benchmark && (!config || !nthreads)) {
 		errx(EXIT_FAILURE, "missing config for the benchmark or "
 		    "invalid thread count");
 	}
 
-	/* XXX rn_init */
-	extern int rumpns_max_keylen;
-	rumpns_max_keylen = 1;
-
-	rump_init();
-	rump_schedule();
-
+	/*
+	 * Initialise the NPF kernel component.
+	 */
+	npf_kern_init();
 	rumpns_npf_test_init(inet_pton, inet_ntop, random);
 
 	if (config) {
@@ -308,6 +328,7 @@
 		}
 
 		if (!testname || strcmp("nat", testname) == 0) {
+			srandom(1);
 			ok = rumpns_npf_nat_test(verbose);
 			fail |= result("nat", ok);
 			tname_matched = true;
@@ -327,7 +348,8 @@
 		}
 	}
 
-	rump_unschedule();
+	rumpns_npf_test_fini();
+	npf_kern_fini();
 
 	if (testname && !tname_matched)
 		errx(EXIT_FAILURE, "test \"%s\" unknown", testname);
--- a/usr.sbin/npf/npftest/npftest.h	Mon Dec 26 21:54:00 2016 +0000
+++ b/usr.sbin/npf/npftest/npftest.h	Mon Dec 26 23:05:05 2016 +0000
@@ -10,11 +10,30 @@
 #include <inttypes.h>
 #include <stdbool.h>
 
+#if !defined(_NPF_STANDALONE)
 #include <net/if.h>
+#else
+#define	rumpns_npf_test_addif		npf_test_addif
+#define	rumpns_npf_test_load		npf_test_load
+#define	rumpns_npf_test_init		npf_test_init
+#define	rumpns_npf_test_fini		npf_test_fini
+#define	rumpns_npf_test_getif		npf_test_getif
+#define	rumpns_npf_nbuf_test		npf_nbuf_test
+#define	rumpns_npf_bpf_test		npf_bpf_test
+#define	rumpns_npf_table_test		npf_table_test
+#define	rumpns_npf_state_test		npf_state_test
+#define	rumpns_npf_rule_test		npf_rule_test
+#define	rumpns_npf_nat_test		npf_nat_test
+#define	rumpns_npf_test_conc		npf_test_conc
+#define	rumpns_npf_test_statetrack	npf_test_statetrack
+#endif
+
+#include "npf.h"
 
 void		rumpns_npf_test_init(int (*)(int, const char *, void *),
 		    const char *(*)(int, const void *, char *, socklen_t),
 		    long (*)(void));
+void		rumpns_npf_test_fini(void);
 int		rumpns_npf_test_load(const void *);
 ifnet_t *	rumpns_npf_test_addif(const char *, bool, bool);
 ifnet_t *	rumpns_npf_test_getif(const char *);