NPF: add support for specifying the interfaces before they are attached. trunk
authorrmind <rmind@NetBSD.org>
Fri, 08 Nov 2013 00:38:26 +0000
branchtrunk
changeset 222297 8d404eb06bc4
parent 222296 d2d6aa16f1cd
child 222298 027aeed7b8ff
NPF: add support for specifying the interfaces before they are attached. If an interface is or gets detached, all associated rules and connections will be deactivated (it might be useful to have an option to invalidate the associated connections). Once the interface is reattached they will become active. Bump NPF_VERSION.
lib/libnpf/npf.3
lib/libnpf/npf.c
lib/libnpf/npf.h
sys/modules/npf/Makefile
sys/net/npf/files.npf
sys/net/npf/npf.c
sys/net/npf/npf.h
sys/net/npf/npf_conf.c
sys/net/npf/npf_ctl.c
sys/net/npf/npf_handler.c
sys/net/npf/npf_if.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_mbuf.c
sys/net/npf/npf_ruleset.c
sys/net/npf/npf_session.c
sys/rump/net/lib/libnpf/Makefile
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_data.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_show.c
usr.sbin/npf/npfctl/npfctl.h
usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c
usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c
usr.sbin/npf/npftest/libnpftest/npf_state_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.3	Thu Nov 07 21:45:04 2013 +0000
+++ b/lib/libnpf/npf.3	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-.\"	$NetBSD: npf.3,v 1.9 2013/09/19 17:29:06 rmind Exp $
+.\"	$NetBSD: npf.3,v 1.10 2013/11/08 00:38:27 rmind Exp $
 .\"
 .\" Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd September 19, 2013
+.Dd November 7, 2013
 .Dt NPF 3
 .Os
 .Sh NAME
@@ -48,7 +48,7 @@
 .Fn npf_config_flush "int fd"
 .\" ---
 .Ft nl_rule_t *
-.Fn npf_rule_create "char *name" "uint32_t attr" "u_int if_idx"
+.Fn npf_rule_create "char *name" "uint32_t attr" "const char *ifname"
 .Ft int
 .Fn npf_rule_setcode "nl_rule_t *rl" "int type" "const void *code" "size_t len"
 .Ft int
@@ -72,7 +72,7 @@
 .Fn npf_rproc_insert "nl_config_t *ncf" "nl_rproc_t *rp"
 .\" ---
 .Ft nl_nat_t *
-.Fn npf_nat_create "int type" "u_int flags" "u_int if_idx" \
+.Fn npf_nat_create "int type" "u_int flags" "const char *ifname" \
 "npf_addr_t *addr" "int af" "in_port_t port"
 .Ft int
 .Fn npf_nat_insert "nl_config_t *ncf" "nl_nat_t *nt" "pri_t pri"
@@ -114,7 +114,7 @@
 .\" ---
 .Ss Rule interface
 .Bl -tag -width 4n
-.It Fn npf_rule_create "name" "attr" "if_idx"
+.It Fn npf_rule_create "name" "attr" "ifname"
 Create a rule with a given name, attribute and priorty.
 Name can be
 .Dv NULL ,
@@ -143,11 +143,9 @@
 .El
 .Pp
 Interface is specified by
-.Fa if_idx ,
-which is a numeral representation of an
-interface, given by
-.Xr if_nametoindex 3 .
-Zero indicates any interface.
+.Fa ifname ,
+which is a string.
+NULL indicates any interface.
 .\" ---
 .It Fn npf_rule_setcode "rl" "type" "code" "len"
 Assign compiled code for the rule specified by
@@ -217,7 +215,7 @@
 .\" -----
 .Ss Translation interface
 .Bl -tag -width 4n
-.It Fn npf_nat_create "type" "flags" "if_idx" "addr" "af" "port"
+.It Fn npf_nat_create "type" "flags" "ifname" "addr" "af" "port"
 Create a NAT translation policy of a specified type.
 There are two types:
 .Bl -tag -width "NPF_NAT_PORTMAP "
--- a/lib/libnpf/npf.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/lib/libnpf/npf.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.21 2013/09/19 01:49:07 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.22 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.21 2013/09/19 01:49:07 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.22 2013/11/08 00:38:27 rmind Exp $");
 
 #include <sys/types.h>
 #include <netinet/in_systm.h>
@@ -437,7 +437,7 @@
  */
 
 nl_rule_t *
-npf_rule_create(const char *name, uint32_t attr, u_int if_idx)
+npf_rule_create(const char *name, uint32_t attr, const char *ifname)
 {
 	prop_dictionary_t rldict;
 	nl_rule_t *rl;
@@ -456,8 +456,8 @@
 	}
 	prop_dictionary_set_uint32(rldict, "attributes", attr);
 
-	if (if_idx) {
-		prop_dictionary_set_uint32(rldict, "interface", if_idx);
+	if (ifname) {
+		prop_dictionary_set_cstring(rldict, "interface", ifname);
 	}
 	rl->nrl_dict = rldict;
 	return rl;
@@ -631,14 +631,14 @@
 	return attr;
 }
 
-unsigned
+const char *
 npf_rule_getinterface(nl_rule_t *rl)
 {
 	prop_dictionary_t rldict = rl->nrl_dict;
-	unsigned if_idx = 0;
+	const char *ifname = NULL;
 
-	prop_dictionary_get_uint32(rldict, "interface", &if_idx);
-	return if_idx;
+	prop_dictionary_get_cstring_nocopy(rldict, "interface", &ifname);
+	return ifname;
 }
 
 const void *
@@ -801,7 +801,7 @@
  */
 
 nl_nat_t *
-npf_nat_create(int type, u_int flags, u_int if_idx,
+npf_nat_create(int type, u_int flags, const char *ifname,
     npf_addr_t *addr, int af, in_port_t port)
 {
 	nl_rule_t *rl;
@@ -822,7 +822,7 @@
 	    (type == NPF_NATOUT ? NPF_RULE_OUT : NPF_RULE_IN);
 
 	/* Create a rule for NAT policy.  Next, will add translation data. */
-	rl = npf_rule_create(NULL, attr, if_idx);
+	rl = npf_rule_create(NULL, attr, ifname);
 	if (rl == NULL) {
 		return NULL;
 	}
@@ -1123,49 +1123,18 @@
 }
 
 void
-_npf_debug_addif(nl_config_t *ncf, struct ifaddrs *ifa, u_int if_idx)
+_npf_debug_addif(nl_config_t *ncf, const char *ifname)
 {
 	prop_dictionary_t ifdict, dbg = _npf_debug_initonce(ncf);
 	prop_array_t iflist = prop_dictionary_get(dbg, "interfaces");
+	u_int if_idx = if_nametoindex(ifname);
 
-	if (_npf_prop_array_lookup(iflist, "name", ifa->ifa_name)) {
+	if (_npf_prop_array_lookup(iflist, "name", ifname)) {
 		return;
 	}
-
 	ifdict = prop_dictionary_create();
-	prop_dictionary_set_cstring(ifdict, "name", ifa->ifa_name);
-	prop_dictionary_set_uint32(ifdict, "flags", ifa->ifa_flags);
-	if (!if_idx) {
-		if_idx = if_nametoindex(ifa->ifa_name);
-	}
-	prop_dictionary_set_uint32(ifdict, "idx", if_idx);
-
-	const struct sockaddr *sa = ifa->ifa_addr;
-	npf_addr_t addr;
-	size_t alen = 0;
-
-	switch (sa ? sa->sa_family : -1) {
-	case AF_INET: {
-		const struct sockaddr_in *sin = (const void *)sa;
-		alen = sizeof(sin->sin_addr);
-		memcpy(&addr, &sin->sin_addr, alen);
-		break;
-	}
-	case AF_INET6: {
-		const struct sockaddr_in6 *sin6 = (const void *)sa;
-		alen = sizeof(sin6->sin6_addr);
-		memcpy(&addr, &sin6->sin6_addr, alen);
-		break;
-	}
-	default:
-		break;
-	}
-
-	if (alen) {
-		prop_data_t addrdata = prop_data_create_data(&addr, alen);
-		prop_dictionary_set(ifdict, "addr", addrdata);
-		prop_object_release(addrdata);
-	}
+	prop_dictionary_set_cstring(ifdict, "name", ifname);
+	prop_dictionary_set_uint32(ifdict, "index", if_idx);
 	prop_array_add(iflist, ifdict);
 	prop_object_release(ifdict);
 }
--- a/lib/libnpf/npf.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/lib/libnpf/npf.h	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.18 2013/09/19 01:49:07 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.19 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -88,7 +88,7 @@
 void		npf_ext_param_u32(nl_ext_t *, const char *, uint32_t);
 void		npf_ext_param_bool(nl_ext_t *, const char *, bool);
 
-nl_rule_t *	npf_rule_create(const char *, uint32_t, u_int);
+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_setproc(nl_rule_t *, const char *);
@@ -104,7 +104,8 @@
 bool		npf_rproc_exists_p(nl_config_t *, const char *);
 int		npf_rproc_insert(nl_config_t *, nl_rproc_t *);
 
-nl_nat_t *	npf_nat_create(int, u_int, u_int, npf_addr_t *, int, in_port_t);
+nl_nat_t *	npf_nat_create(int, u_int, const char *,
+		    npf_addr_t *, int, in_port_t);
 int		npf_nat_insert(nl_config_t *, nl_nat_t *, pri_t);
 
 nl_table_t *	npf_table_create(u_int, int);
@@ -124,7 +125,7 @@
 nl_rule_t *	npf_rule_iterate(nl_config_t *, unsigned *);
 const char *	npf_rule_getname(nl_rule_t *);
 uint32_t	npf_rule_getattr(nl_rule_t *);
-unsigned	npf_rule_getinterface(nl_rule_t *);
+const char *	npf_rule_getinterface(nl_rule_t *);
 const void *	npf_rule_getinfo(nl_rule_t *, size_t *);
 const char *	npf_rule_getproc(nl_rule_t *);
 
@@ -142,7 +143,7 @@
 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 *, struct ifaddrs *, u_int);
+void		_npf_debug_addif(nl_config_t *, const char *);
 
 /* The ALG interface is experimental */
 int 		_npf_alg_load(nl_config_t *, const char *);
--- a/sys/modules/npf/Makefile	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/modules/npf/Makefile	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.15 2013/09/19 01:49:07 rmind Exp $
+# $NetBSD: Makefile,v 1.16 2013/11/08 00:38:26 rmind Exp $
 #
 # Public Domain.
 #
@@ -9,10 +9,11 @@
 
 KMOD=		npf
 
-SRCS=		npf.c npf_alg.c npf_conf.c npf_ctl.c npf_handler.c npf_bpf.c
-SRCS+=		npf_inet.c npf_mbuf.c npf_nat.c npf_ruleset.c npf_rproc.c
-SRCS+=		npf_sendpkt.c npf_session.c npf_state.c npf_state_tcp.c
-SRCS+=		npf_tableset.c npf_tableset_ptree.c npf_worker.c
+SRCS=		npf.c npf_alg.c npf_conf.c npf_ctl.c npf_handler.c
+SRCS+=		npf_bpf.c npf_if.c npf_inet.c npf_mbuf.c npf_nat.c
+SRCS+=		npf_ruleset.c npf_rproc.c npf_sendpkt.c npf_session.c
+SRCS+=		npf_state.c npf_state_tcp.c npf_tableset.c
+SRCS+=		npf_tableset_ptree.c npf_worker.c
 
 CPPFLAGS+=	-DINET6
 
--- a/sys/net/npf/files.npf	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/files.npf	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.npf,v 1.15 2013/09/19 01:49:07 rmind Exp $
+# $NetBSD: files.npf,v 1.16 2013/11/08 00:38:26 rmind Exp $
 #
 # Public Domain.
 #
@@ -20,6 +20,7 @@
 file	net/npf/npf_rproc.c			npf
 file	net/npf/npf_tableset.c			npf
 file	net/npf/npf_tableset_ptree.c		npf
+file	net/npf/npf_if.c			npf
 file	net/npf/npf_inet.c			npf
 file	net/npf/npf_session.c			npf
 file	net/npf/npf_state.c			npf
--- a/sys/net/npf/npf.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.c,v 1.17 2013/09/19 01:04:46 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.18 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.17 2013/09/19 01:04:46 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.18 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -97,6 +97,7 @@
 	npf_ext_sysinit();
 
 	/* Load empty configuration. */
+	npf_pfil_register(true);
 	npf_config_init();
 
 #ifdef _MODULE
@@ -117,7 +118,7 @@
 #ifdef _MODULE
 	devsw_detach(NULL, &npf_cdevsw);
 #endif
-	npf_pfil_unregister();
+	npf_pfil_unregister(true);
 
 	/* Flush all sessions, destroy configuration (ruleset, etc). */
 	npf_session_tracking(false);
--- a/sys/net/npf/npf.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf.h	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.31 2013/09/19 01:04:46 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.32 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 
-#define	NPF_VERSION		10
+#define	NPF_VERSION		11
 
 /*
  * Public declarations and definitions.
@@ -143,6 +143,7 @@
 	struct mbuf *	nb_mbuf;
 	void *		nb_nptr;
 	const ifnet_t *	nb_ifp;
+	unsigned	nb_ifid;
 	int		nb_flags;
 } nbuf_t;
 
--- a/sys/net/npf/npf_conf.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_conf.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_conf.c,v 1.2 2013/02/10 23:47:37 rmind Exp $	*/
+/*	$NetBSD: npf_conf.c,v 1.3 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.2 2013/02/10 23:47:37 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.3 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -108,6 +108,11 @@
 void
 npf_config_fini(void)
 {
+	mutex_enter(&npf_config_lock);
+	pserialize_perform(npf_config_psz);
+	npf_ifmap_flush();
+	mutex_exit(&npf_config_lock);
+
 	npf_config_destroy(npf_config);
 	pserialize_destroy(npf_config_psz);
 	mutex_destroy(&npf_config_lock);
@@ -151,12 +156,16 @@
 	npf_config = nc;
 	if (onc == NULL) {
 		/* Initial load, done. */
+		npf_ifmap_flush();
 		mutex_exit(&npf_config_lock);
 		return;
 	}
 
 	/* Synchronise: drain all references. */
 	pserialize_perform(npf_config_psz);
+	if (flush) {
+		npf_ifmap_flush();
+	}
 	mutex_exit(&npf_config_lock);
 
 	/* Finally, it is safe to destroy the old config. */
--- a/sys/net/npf/npf_ctl.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_ctl.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ctl.c,v 1.30 2013/10/27 16:22:08 rmind Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.31 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.30 2013/10/27 16:22:08 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.31 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -67,10 +67,10 @@
 
 	if (onoff) {
 		/* Enable: add pfil hooks. */
-		error = npf_pfil_register();
+		error = npf_pfil_register(false);
 	} else {
 		/* Disable: remove pfil hooks. */
-		npf_pfil_unregister();
+		npf_pfil_unregister(false);
 		error = 0;
 	}
 	return error;
--- a/sys/net/npf/npf_handler.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_handler.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_handler.c,v 1.27 2013/06/29 21:06:58 rmind Exp $	*/
+/*	$NetBSD: npf_handler.c,v 1.28 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -31,10 +31,12 @@
 
 /*
  * NPF packet handler.
+ *
+ * Note: pfil(9) hooks are currently locked by softnet_lock and kernel-lock.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.27 2013/06/29 21:06:58 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.28 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -53,10 +55,7 @@
 
 #include "npf_impl.h"
 
-/*
- * If npf_ph_if != NULL, pfil hooks are registered.  If NULL, not registered.
- * Used to check the state.  Locked by: softnet_lock + KERNEL_LOCK (XXX).
- */
+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;
@@ -71,7 +70,18 @@
 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;
 }
 
@@ -294,35 +304,43 @@
  * npf_pfil_register: register pfil(9) hooks.
  */
 int
-npf_pfil_register(void)
+npf_pfil_register(bool init)
 {
-	int error;
+	int error = 0;
 
 	mutex_enter(softnet_lock);
 	KERNEL_LOCK(1, NULL);
 
-	/* Check if pfil hooks are not already registered. */
-	if (npf_ph_if) {
-		error = EEXIST;
-		goto fail;
+	/* 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;
 	}
 
-	/* Capture point of any activity in interfaces and IP layer. */
-	npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
+	/* 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_if || (!npf_ph_inet && !npf_ph_inet6)) {
-		npf_ph_if = NULL;
+	if (!npf_ph_inet && !npf_ph_inet6) {
 		error = ENOENT;
-		goto fail;
+		goto out;
 	}
 
-	/* Interface re-config or attach/detach hook. */
-	error = pfil_add_hook(npf_ifhook, NULL,
-	    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
-	KASSERT(error == 0);
-
-	/* Packet IN/OUT handler on all interfaces and IP layer. */
+	/* Packet IN/OUT handlers for IP layer. */
 	if (npf_ph_inet) {
 		error = pfil_add_hook(npf_packet_handler, NULL,
 		    PFIL_ALL, npf_ph_inet);
@@ -333,7 +351,8 @@
 		    PFIL_ALL, npf_ph_inet6);
 		KASSERT(error == 0);
 	}
-fail:
+	pfil_registered = true;
+out:
 	KERNEL_UNLOCK_ONE(NULL);
 	mutex_exit(softnet_lock);
 
@@ -344,13 +363,12 @@
  * npf_pfil_unregister: unregister pfil(9) hooks.
  */
 void
-npf_pfil_unregister(void)
+npf_pfil_unregister(bool fini)
 {
-
 	mutex_enter(softnet_lock);
 	KERNEL_LOCK(1, NULL);
 
-	if (npf_ph_if) {
+	if (fini && npf_ph_if) {
 		(void)pfil_remove_hook(npf_ifhook, NULL,
 		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
 	}
@@ -362,8 +380,7 @@
 		(void)pfil_remove_hook(npf_packet_handler, NULL,
 		    PFIL_ALL, npf_ph_inet6);
 	}
-
-	npf_ph_if = NULL;
+	pfil_registered = false;
 
 	KERNEL_UNLOCK_ONE(NULL);
 	mutex_exit(softnet_lock);
@@ -372,5 +389,5 @@
 bool
 npf_pfil_registered_p(void)
 {
-	return npf_ph_if != NULL;
+	return pfil_registered;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_if.c	Fri Nov 08 00:38:26 2013 +0000
@@ -0,0 +1,177 @@
+/*	$NetBSD: npf_if.c,v 1.1 2013/11/08 00:38:26 rmind Exp $	*/
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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 network interface handling module.
+ *
+ * NPF uses its own interface IDs (npf-if-id).  When NPF configuration is
+ * (re)loaded, each required interface name is registered and a matching
+ * network interface gets an ID assigned.  If an interface is not present,
+ * it gets an ID on attach.  Any other interfaces get INACTIVE_ID.
+ *
+ * The IDs are mapped synchronously based on interface events which are
+ * monitored using pfil(9) hooks.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.1 2013/11/08 00:38:26 rmind 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/kmem.h>
+
+#include <net/if.h>
+
+#include "npf_impl.h"
+
+#define	INACTIVE_ID	((u_int)-1)
+
+typedef struct {
+	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;
+
+/*
+ * NOTE: IDs start from 1.  Zero is reseved for "no interface" and
+ * (unsigned)-1 for "inactive interface".  Therefore, an interface
+ * can have either INACTIVE_ID or non-zero ID.
+ */
+
+static u_int
+npf_ifmap_new(void)
+{
+	KASSERT(npf_config_locked_p());
+
+	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) {
+		printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n");
+		return INACTIVE_ID;
+	}
+	return ++npf_ifmap_cnt;
+}
+
+static u_int
+npf_ifmap_lookup(const char *ifname)
+{
+	KASSERT(npf_config_locked_p());
+
+	for (u_int i = 0; i < npf_ifmap_cnt; i++) {
+		npf_ifmap_t *nim = &npf_ifmap[i];
+
+		if (nim->n_ifname && strcmp(nim->n_ifname, ifname) == 0)
+			return i + 1;
+	}
+	return INACTIVE_ID;
+}
+
+u_int
+npf_ifmap_register(const char *ifname)
+{
+	npf_ifmap_t *nim;
+	ifnet_t *ifp;
+	u_int i;
+
+	npf_config_enter();
+	if ((i = npf_ifmap_lookup(ifname)) != INACTIVE_ID) {
+		goto out;
+	}
+	if ((i = npf_ifmap_new()) == INACTIVE_ID) {
+		i = INACTIVE_ID;
+		goto out;
+	}
+	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;
+	}
+	KERNEL_UNLOCK_ONE(NULL);
+out:
+	npf_config_exit();
+	return i;
+}
+
+void
+npf_ifmap_flush(void)
+{
+	ifnet_t *ifp;
+
+	KASSERT(npf_config_locked_p());
+
+	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_FOREACH(ifp) {
+		ifp->if_pf_kif = (void *)(uintptr_t)INACTIVE_ID;
+	}
+	KERNEL_UNLOCK_ONE(NULL);
+}
+
+u_int
+npf_ifmap_id(const ifnet_t *ifp)
+{
+	const u_int i = (uintptr_t)ifp->if_pf_kif;
+
+	KASSERT(i == INACTIVE_ID || (i > 0 && i <= npf_ifmap_cnt));
+	return i;
+}
+
+void
+npf_ifmap_attach(ifnet_t *ifp)
+{
+	npf_config_enter();
+	ifp->if_pf_kif = (void *)(uintptr_t)npf_ifmap_lookup(ifp->if_xname);
+	npf_config_exit();
+}
+
+void
+npf_ifmap_detach(ifnet_t *ifp)
+{
+	npf_config_enter();
+	ifp->if_pf_kif = (void *)(uintptr_t)INACTIVE_ID; /* diagnostic */
+	npf_config_exit();
+}
--- a/sys/net/npf/npf_impl.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_impl.h	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.36 2013/11/04 22:17:21 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.37 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -103,6 +103,7 @@
 /* Some artificial limits. */
 #define	NPF_TABLE_SLOTS		32
 #define	NPF_MAX_RULES		(1024 * 1024)
+#define	NPF_MAX_IFMAP		64
 
 /*
  * SESSION STATE STRUCTURES
@@ -166,9 +167,15 @@
 void		npf_stats_inc(npf_stats_t);
 void		npf_stats_dec(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_id(const ifnet_t *);
+
 /* Packet filter hooks. */
-int		npf_pfil_register(void);
-void		npf_pfil_unregister(void);
+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);
 
--- a/sys/net/npf/npf_mbuf.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_mbuf.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_mbuf.c,v 1.11 2013/02/19 23:57:37 rmind Exp $	*/
+/*	$NetBSD: npf_mbuf.c,v 1.12 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.11 2013/02/19 23:57:37 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.12 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -51,11 +51,13 @@
 void
 nbuf_init(nbuf_t *nbuf, struct mbuf *m, const ifnet_t *ifp)
 {
+	u_int ifid = npf_ifmap_id(ifp);
+
 	KASSERT((m->m_flags & M_PKTHDR) != 0);
-	KASSERT(ifp != NULL);
 
 	nbuf->nb_mbuf0 = m;
 	nbuf->nb_ifp = ifp;
+	nbuf->nb_ifid =  ifid;
 	nbuf_reset(nbuf);
 }
 
--- a/sys/net/npf/npf_ruleset.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_ruleset.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ruleset.c,v 1.25 2013/09/19 01:49:07 rmind Exp $	*/
+/*	$NetBSD: npf_ruleset.c,v 1.26 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.25 2013/09/19 01:49:07 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.26 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -520,7 +520,15 @@
 	/* Attributes, priority and interface ID (optional). */
 	prop_dictionary_get_uint32(rldict, "attributes", &rl->r_attr);
 	prop_dictionary_get_int32(rldict, "priority", &rl->r_priority);
-	prop_dictionary_get_uint32(rldict, "interface", &rl->r_ifid);
+
+	if (prop_dictionary_get_cstring_nocopy(rldict, "interface", &rname)) {
+		if ((rl->r_ifid = npf_ifmap_register(rname)) == 0) {
+			kmem_free(rl, sizeof(npf_rule_t));
+			return NULL;
+		}
+	} else {
+		rl->r_ifid = 0;
+	}
 
 	/* Get the skip-to index.  No need to validate it. */
 	prop_dictionary_get_uint32(rldict, "skip-to", &rl->r_skip_to);
@@ -661,10 +669,8 @@
 npf_rule_inspect(npf_cache_t *npc, nbuf_t *nbuf, const npf_rule_t *rl,
     const int di_mask, const int layer)
 {
-	const ifnet_t *ifp = nbuf->nb_ifp;
-
 	/* Match the interface. */
-	if (rl->r_ifid && rl->r_ifid != ifp->if_index) {
+	if (rl->r_ifid && rl->r_ifid != nbuf->nb_ifid) {
 		return false;
 	}
 
--- a/sys/net/npf/npf_session.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/net/npf/npf_session.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_session.c,v 1.26 2013/10/29 16:39:10 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.27 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -92,7 +92,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.26 2013/10/29 16:39:10 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.27 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -150,7 +150,7 @@
 	/* Protocol and interface (common IDs). */
 	struct npf_secomid {
 		uint16_t	proto;
-		uint16_t	if_idx;
+		uint16_t	ifid;
 	} s_common_id;
 	/* Flags and the protocol state. */
 	u_int			s_flags;
@@ -312,7 +312,7 @@
 	const int sz = sen->se_alen;
 	uint32_t hash, mix[2];
 
-	mix[0] = (scid->proto ^ scid->if_idx) << 16;
+	mix[0] = (scid->proto ^ scid->ifid) << 16;
 	mix[0] |= sen->se_src_id ^ sen->se_dst_id;
 	mix[1] = npf_addr_sum(sz, &sen->se_src_addr, &sen->se_dst_addr);
 	hash = murmurhash2(mix, sizeof(mix), sess_hash_seed);
@@ -486,7 +486,6 @@
     const int di, bool *forw)
 {
 	const u_int proto = npc->npc_proto;
-	const ifnet_t *ifp = nbuf->nb_ifp;
 	npf_sentry_t senkey, *sen;
 	npf_session_t *se;
 	npf_sehash_t *sh;
@@ -506,7 +505,7 @@
 	 */
 	npf_secomid_t scid;
 	memset(&scid, 0, sizeof(npf_secomid_t));
-	scid = (npf_secomid_t){ .proto = proto, .if_idx = ifp->if_index };
+	scid = (npf_secomid_t){ .proto = proto, .ifid = nbuf->nb_ifid };
 	senkey.se_common_id = &scid;
 
 	/*
@@ -527,7 +526,7 @@
 	}
 	se = sen->se_backptr;
 	KASSERT(se->s_common_id.proto == proto);
-	KASSERT(se->s_common_id.if_idx == ifp->if_index);
+	KASSERT(se->s_common_id.ifid == nbuf->nb_ifid);
 	flags = se->s_flags;
 
 	/* Check if session is active and not expired. */
@@ -604,7 +603,6 @@
 npf_session_t *
 npf_session_establish(npf_cache_t *npc, nbuf_t *nbuf, const int di)
 {
-	const ifnet_t *ifp = nbuf->nb_ifp;
 	npf_sentry_t *fw, *bk;
 	npf_sehash_t *sh;
 	npf_session_t *se;
@@ -646,7 +644,7 @@
 	/* Protocol and interface. */
 	memset(&se->s_common_id, 0, sizeof(npf_secomid_t));
 	se->s_common_id.proto = npc->npc_proto;
-	se->s_common_id.if_idx = ifp->if_index;
+	se->s_common_id.ifid = nbuf->nb_ifid;
 
 	/* Setup "forwards" entry. */
 	if (!npf_session_fillent(npc, fw)) {
--- a/sys/rump/net/lib/libnpf/Makefile	Thu Nov 07 21:45:04 2013 +0000
+++ b/sys/rump/net/lib/libnpf/Makefile	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.8 2013/09/19 01:49:07 rmind Exp $
+#	$NetBSD: Makefile,v 1.9 2013/11/08 00:38:27 rmind Exp $
 #
 # Public Domain.
 #
@@ -7,11 +7,11 @@
 
 LIB=	rumpnet_npf
 
-SRCS=	npf.c npf_alg.c npf_conf.c npf_ctl.c npf_handler.c npf_bpf.c 
-SRCS+=	npf_inet.c npf_mbuf.c npf_nat.c npf_ruleset.c npf_rproc.c 
-SRCS+=	npf_sendpkt.c npf_session.c npf_state.c npf_state_tcp.c
-SRCS+=	npf_tableset.c npf_tableset_ptree.c npf_worker.c
-SRCS+=	if_npflog.c
+SRCS=	npf.c npf_alg.c npf_conf.c npf_ctl.c npf_handler.c
+SRCS+=	npf_bpf.c npf_if.c npf_inet.c npf_mbuf.c npf_nat.c
+SRCS+=	npf_ruleset.c npf_rproc.c npf_sendpkt.c npf_session.c
+SRCS+=	npf_state.c npf_state_tcp.c npf_tableset.c
+SRCS+=	npf_tableset_ptree.c npf_worker.c if_npflog.c
 
 SRCS+=	npf_alg_icmp.c
 
--- a/usr.sbin/npf/npfctl/npf_build.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.27 2013/09/20 03:03:52 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.28 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.27 2013/09/20 03:03:52 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.28 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -109,22 +109,17 @@
 	return the_rule;
 }
 
-unsigned long
+bool
 npfctl_debug_addif(const char *ifname)
 {
-	char tname[] = "npftest";
+	const char tname[] = "npftest";
 	const size_t tnamelen = sizeof(tname) - 1;
 
-	if (!npf_debug || strncmp(ifname, tname, tnamelen) != 0) {
-		return 0;
+	if (npf_debug) {
+		_npf_debug_addif(npf_conf, ifname);
+		return strncmp(ifname, tname, tnamelen) == 0;
 	}
-	struct ifaddrs ifa = {
-		.ifa_name = __UNCONST(ifname),
-		.ifa_flags = 0
-	};
-	unsigned long if_idx = atol(ifname + tnamelen) + 1;
-	_npf_debug_addif(npf_conf, &ifa, if_idx);
-	return if_idx;
+	return 0;
 }
 
 bool
@@ -417,7 +412,7 @@
 }
 
 void
-npfctl_build_maprset(const char *name, int attr, u_int if_idx)
+npfctl_build_maprset(const char *name, int attr, const char *ifname)
 {
 	const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT);
 	nl_rule_t *rl;
@@ -428,7 +423,7 @@
 	}
 	/* Allow only "in/out" attributes. */
 	attr = NPF_RULE_GROUP | NPF_RULE_GROUP | (attr & attr_di);
-	rl = npf_rule_create(name, attr, if_idx);
+	rl = npf_rule_create(name, attr, ifname);
 	npf_nat_insert(npf_conf, rl, NPF_PRI_LAST);
 }
 
@@ -437,7 +432,7 @@
  * update the current group pointer and increase the nesting level.
  */
 void
-npfctl_build_group(const char *name, int attr, u_int if_idx, bool def)
+npfctl_build_group(const char *name, int attr, const char *ifname, bool def)
 {
 	const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT);
 	nl_rule_t *rl;
@@ -446,7 +441,7 @@
 		attr |= attr_di;
 	}
 
-	rl = npf_rule_create(name, attr | NPF_RULE_GROUP, if_idx);
+	rl = npf_rule_create(name, attr | NPF_RULE_GROUP, ifname);
 	npf_rule_setprio(rl, NPF_PRI_LAST);
 	if (def) {
 		if (defgroup) {
@@ -480,7 +475,7 @@
  * if any, and insert into the ruleset of current group, or set the rule.
  */
 void
-npfctl_build_rule(uint32_t attr, u_int if_idx, sa_family_t family,
+npfctl_build_rule(uint32_t attr, const char *ifname, sa_family_t family,
     const opt_proto_t *op, const filt_opts_t *fopts,
     const char *pcap_filter, const char *rproc)
 {
@@ -488,7 +483,7 @@
 
 	attr |= (npf_conf ? 0 : NPF_RULE_DYNAMIC);
 
-	rl = npf_rule_create(NULL, attr, if_idx);
+	rl = npf_rule_create(NULL, attr, ifname);
 	if (pcap_filter) {
 		npfctl_build_pcap(rl, pcap_filter);
 	} else {
@@ -519,7 +514,7 @@
  * type with a given filter options.
  */
 static void
-npfctl_build_nat(int type, u_int if_idx, sa_family_t family,
+npfctl_build_nat(int type, const char *ifname, sa_family_t family,
     const addr_port_t *ap, const filt_opts_t *fopts, bool binat)
 {
 	const opt_proto_t op = { .op_proto = -1, .op_opts = NULL };
@@ -545,7 +540,7 @@
 		 */
 		nat = npf_nat_create(NPF_NATOUT, !binat ?
 		    (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0,
-		    if_idx, &am->fam_addr, am->fam_family, 0);
+		    ifname, &am->fam_addr, am->fam_family, 0);
 		break;
 	case NPF_NATIN:
 		/*
@@ -560,7 +555,7 @@
 			port = npfctl_get_singleport(ap->ap_portrange);
 		}
 		nat = npf_nat_create(NPF_NATIN, !binat ? NPF_NAT_PORTS : 0,
-		    if_idx, &am->fam_addr, am->fam_family, port);
+		    ifname, &am->fam_addr, am->fam_family, port);
 		break;
 	default:
 		assert(false);
@@ -574,8 +569,9 @@
  * npfctl_build_natseg: validate and create NAT policies.
  */
 void
-npfctl_build_natseg(int sd, int type, u_int if_idx, const addr_port_t *ap1,
-    const addr_port_t *ap2, const filt_opts_t *fopts)
+npfctl_build_natseg(int sd, int type, const char *ifname,
+    const addr_port_t *ap1, const addr_port_t *ap2,
+    const filt_opts_t *fopts)
 {
 	sa_family_t af = AF_INET;
 	filt_opts_t imfopts;
@@ -585,7 +581,7 @@
 		yyerror("static NAT is not yet supported");
 	}
 	assert(sd == NPFCTL_NAT_DYNAMIC);
-	assert(if_idx != 0);
+	assert(ifname != NULL);
 
 	/*
 	 * Bi-directional NAT is a combination of inbound NAT and outbound
@@ -607,12 +603,12 @@
 	if (type & NPF_NATIN) {
 		memset(&imfopts, 0, sizeof(filt_opts_t));
 		memcpy(&imfopts.fo_to, ap2, sizeof(addr_port_t));
-		npfctl_build_nat(NPF_NATIN, if_idx, af, ap1, fopts, binat);
+		npfctl_build_nat(NPF_NATIN, ifname, af, ap1, fopts, binat);
 	}
 	if (type & NPF_NATOUT) {
 		memset(&imfopts, 0, sizeof(filt_opts_t));
 		memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t));
-		npfctl_build_nat(NPF_NATOUT, if_idx, af, ap2, fopts, binat);
+		npfctl_build_nat(NPF_NATOUT, ifname, af, ap2, fopts, binat);
 	}
 }
 
--- a/usr.sbin/npf/npfctl/npf_data.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_data.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_data.c,v 1.20 2013/09/19 01:04:45 rmind Exp $	*/
+/*	$NetBSD: npf_data.c,v 1.21 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_data.c,v 1.20 2013/09/19 01:04:45 rmind Exp $");
+__RCSID("$NetBSD: npf_data.c,v 1.21 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/null.h>
@@ -47,7 +47,9 @@
 #include <net/if.h>
 
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
+#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <ifaddrs.h>
@@ -57,14 +59,48 @@
 
 static struct ifaddrs *		ifs_list = NULL;
 
-unsigned long
+void
+npfctl_note_interface(const char *ifname)
+{
+	unsigned long if_idx = if_nametoindex(ifname);
+	bool testif = npfctl_debug_addif(ifname);
+	const char *p = ifname;
+
+	/* If such interface exists or if it is a test interface - done. */
+	if (if_idx || testif) {
+		return;
+	}
+
+	/*
+	 * Minimum sanity check.  The interface name shall be non-empty
+	 * string shorter than IFNAMSIZ and alphanumeric only.
+	 */
+	if (*p == '\0') {
+		goto invalid;
+	}
+	while (*p) {
+		const size_t len = (ptrdiff_t)p - (ptrdiff_t)ifname;
+
+		if (!isalnum((unsigned char)*p) || len > IFNAMSIZ) {
+invalid:		yyerror("illegitimate interface name '%s'", ifname);
+		}
+		p++;
+	}
+
+	/* Throw a warning, so that the user could double check. */
+	warnx("warning - unknown interface '%s'", ifname);
+}
+
+static unsigned long
 npfctl_find_ifindex(const char *ifname)
 {
 	unsigned long if_idx = if_nametoindex(ifname);
+	bool testif = npfctl_debug_addif(ifname);
 
 	if (!if_idx) {
-		if ((if_idx = npfctl_debug_addif(ifname)) != 0) {
-			return if_idx;
+		if (testif) {
+			static u_int dummy_if_idx = (1 << 15);
+			return ++dummy_if_idx;
 		}
 		yyerror("unknown interface '%s'", ifname);
 	}
@@ -284,6 +320,7 @@
 	}
 
 	vpa = npfvar_create(".ifaddrs");
+	ifna.ifna_name = estrdup(ifname);
 	ifna.ifna_addrs = vpa;
 	ifna.ifna_index = npfctl_find_ifindex(ifname);
 	assert(ifna.ifna_index != 0);
--- a/usr.sbin/npf/npfctl/npf_parse.y	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.26 2013/09/20 03:03:52 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.27 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -156,9 +156,8 @@
 %token	<str>		VAR_ID
 
 %type	<str>		addr, some_name, list_elem, table_store, string
-%type	<str>		proc_param_val, opt_apply
-%type	<num>		ifindex, port, opt_final, on_ifindex, number
-%type	<num>		afamily, opt_family
+%type	<str>		proc_param_val, opt_apply, ifname, on_ifname
+%type	<num>		port, opt_final, number, afamily, opt_family
 %type	<num>		block_or_pass, rule_dir, group_dir, block_opts
 %type	<num>		opt_stateful, icmp_type, table_type, map_sd, map_type
 %type	<var>		ifnet, addr_or_ifnet, port_range, icmp_type_and_code
@@ -306,17 +305,17 @@
 	;
 
 map
-	: MAP ifindex map_sd mapseg map_type mapseg PASS filt_opts
+	: MAP ifname map_sd mapseg map_type mapseg PASS filt_opts
 	{
 		npfctl_build_natseg($3, $5, $2, &$4, &$6, &$8);
 	}
-	| MAP ifindex map_sd mapseg map_type mapseg
+	| MAP ifname map_sd mapseg map_type mapseg
 	{
 		npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
 	}
 	| MAP RULESET group_opts
 	{
-		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifnum);
+		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname);
 	}
 	;
 
@@ -389,7 +388,7 @@
 	{
 		/* Build a group.  Increases the nesting level. */
 		npfctl_build_group($2.rg_name, $2.rg_attr,
-		    $2.rg_ifnum, $2.rg_default);
+		    $2.rg_ifname, $2.rg_default);
 	}
 	  ruleset_block
 	{
@@ -403,7 +402,7 @@
 	{
 		/* Ruleset is a dynamic group. */
 		npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
-		    $2.rg_ifnum, $2.rg_default);
+		    $2.rg_ifname, $2.rg_default);
 		npfctl_build_group_end();
 	}
 	;
@@ -419,12 +418,12 @@
 		memset(&$$, 0, sizeof(rule_group_t));
 		$$.rg_default = true;
 	}
-	| STRING group_dir on_ifindex
+	| STRING group_dir on_ifname
 	{
 		memset(&$$, 0, sizeof(rule_group_t));
 		$$.rg_name = $1;
 		$$.rg_attr = $2;
-		$$.rg_ifnum = $3;
+		$$.rg_ifname = $3;
 	}
 	;
 
@@ -445,13 +444,13 @@
 	;
 
 rule
-	: block_or_pass opt_stateful rule_dir opt_final on_ifindex
+	: block_or_pass opt_stateful rule_dir opt_final on_ifname
 	  opt_family opt_proto all_or_filt_opts opt_apply
 	{
 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
 		    $6, &$7, &$8, NULL, $9);
 	}
-	| block_or_pass opt_stateful rule_dir opt_final on_ifindex
+	| block_or_pass opt_stateful rule_dir opt_final on_ifname
 	  PCAP_FILTER STRING opt_apply
 	{
 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
@@ -475,9 +474,9 @@
 	|			{ $$ = 0; }
 	;
 
-on_ifindex
-	: ON ifindex		{ $$ = $2; }
-	|			{ $$ = 0; }
+on_ifname
+	: ON ifname		{ $$ = $2; }
+	|			{ $$ = NULL; }
 	;
 
 afamily
@@ -758,15 +757,17 @@
 	}
 	;
 
-ifindex
+ifname
 	: some_name
 	{
-		$$ = npfctl_find_ifindex($1);
+		npfctl_note_interface($1);
+		$$ = $1;
 	}
 	| ifnet
 	{
 		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
-		$$ = ifna->ifna_index;
+		npfctl_note_interface(ifna->ifna_name);
+		$$ = ifna->ifna_name;
 	}
 	| VAR_ID
 	{
@@ -777,11 +778,11 @@
 		switch (type) {
 		case NPFVAR_STRING:
 		case NPFVAR_IDENTIFIER:
-			$$ = npfctl_find_ifindex(npfvar_expand_string(vp));
+			$$ = npfvar_expand_string(vp);
 			break;
 		case NPFVAR_INTERFACE:
 			ifna = npfvar_get_data(vp, type, 0);
-			$$ = ifna->ifna_index;
+			$$ = ifna->ifna_name;
 			break;
 		case -1:
 			yyerror("undefined variable '%s' for interface", $1);
@@ -791,6 +792,7 @@
 			    $1, npfvar_type(type));
 			break;
 		}
+		npfctl_note_interface($$);
 	}
 	;
 
--- a/usr.sbin/npf/npfctl/npf_show.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_show.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_show.c,v 1.2 2013/09/20 03:03:52 rmind Exp $	*/
+/*	$NetBSD: npf_show.c,v 1.3 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_show.c,v 1.2 2013/09/20 03:03:52 rmind Exp $");
+__RCSID("$NetBSD: npf_show.c,v 1.3 2013/11/08 00:38:26 rmind Exp $");
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -319,8 +319,7 @@
 npfctl_print_rule(npf_conf_info_t *ctx, nl_rule_t *rl)
 {
 	const uint32_t attr = npf_rule_getattr(rl);
-	const char *rproc, *name;
-	u_int if_idx;
+	const char *rproc, *ifname, *name;
 
 	/* Rule attributes/flags. */
 	for (u_int i = 0; i < __arraycount(attr_keyword_map); i++) {
@@ -333,9 +332,7 @@
 			fprintf(ctx->fp, "%s ", ak->val);
 		}
 	}
-	if ((if_idx = npf_rule_getinterface(rl)) != 0) {
-		char ifnamebuf[IFNAMSIZ], *ifname;
-		ifname = if_indextoname(if_idx, ifnamebuf);
+	if ((ifname = npf_rule_getinterface(rl)) != NULL) {
 		fprintf(ctx->fp, "on %s ", ifname);
 	}
 
@@ -360,14 +357,14 @@
 {
 	nl_rule_t *rl = (nl_nat_t *)nt;
 	const char *ifname, *seg1, *seg2, *arrow;
-	char *seg, ifnamebuf[IFNAMSIZ];
-	size_t if_idx, alen;
 	npf_addr_t addr;
 	in_port_t port;
+	size_t alen;
+	char *seg;
 
 	/* Get the interface. */
-	if_idx = npf_rule_getinterface(rl);
-	ifname = if_indextoname(if_idx, ifnamebuf);
+	ifname = npf_rule_getinterface(rl);
+	assert(ifname != NULL);
 
 	/* Get the translation address (and port, if used). */
 	npf_nat_getmap(nt, &addr, &alen, &port);
--- a/usr.sbin/npf/npfctl/npfctl.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.33 2013/09/20 03:03:52 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.34 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -58,6 +58,7 @@
 } fam_addr_mask_t;
 
 typedef struct ifnet_addr {
+	char *		ifna_name;
 	unsigned long	ifna_index;
 	sa_family_t	ifna_family;
 	npfvar_t *	ifna_filter;
@@ -87,7 +88,7 @@
 typedef struct rule_group {
 	const char *	rg_name;
 	uint32_t	rg_attr;
-	u_int		rg_ifnum;
+	const char *	rg_ifname;
 	bool		rg_default;
 } rule_group_t;
 
@@ -110,12 +111,12 @@
 
 void		npfctl_print_error(const nl_error_t *);
 char *		npfctl_print_addrmask(int, const npf_addr_t *, npf_netmask_t);
+void		npfctl_note_interface(const char *);
 bool		npfctl_table_exists_p(const char *);
 int		npfctl_protono(const char *);
 in_port_t	npfctl_portno(const char *);
 uint8_t		npfctl_icmpcode(int, uint8_t, const char *);
 uint8_t		npfctl_icmptype(int, const char *);
-unsigned long   npfctl_find_ifindex(const char *);
 npfvar_t *	npfctl_parse_ifnet(const char *, const int);
 npfvar_t *	npfctl_parse_tcpflag(const char *);
 npfvar_t *	npfctl_parse_table_id(const char *);
@@ -181,18 +182,19 @@
 int		npfctl_ruleset_show(int, const char *);
 
 nl_rule_t *	npfctl_rule_ref(void);
-unsigned long	npfctl_debug_addif(const char *);
+bool		npfctl_debug_addif(const char *);
 
 void		npfctl_build_alg(const char *);
 void		npfctl_build_rproc(const char *, npfvar_t *);
-void		npfctl_build_group(const char *, int, u_int, bool);
+void		npfctl_build_group(const char *, int, const char *, bool);
 void		npfctl_build_group_end(void);
-void		npfctl_build_rule(uint32_t, u_int, sa_family_t,
+void		npfctl_build_rule(uint32_t, const char *, sa_family_t,
 		    const opt_proto_t *, const filt_opts_t *,
 		    const char *, const char *);
-void		npfctl_build_natseg(int, int, u_int, const addr_port_t *,
-		    const addr_port_t *, const filt_opts_t *);
-void		npfctl_build_maprset(const char *, int, u_int);
+void		npfctl_build_natseg(int, int, const char *,
+		    const addr_port_t *, const addr_port_t *,
+		    const filt_opts_t *);
+void		npfctl_build_maprset(const char *, int, const char *);
 void		npfctl_build_table(const char *, u_int, const char *);
 
 #endif
--- a/usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_bpf_test.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_bpf_test.c,v 1.1 2013/09/19 01:04:45 rmind Exp $	*/
+/*	$NetBSD: npf_bpf_test.c,v 1.2 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -59,8 +59,8 @@
 static int
 test_bpf_code(const void *code)
 {
+	ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
 	npf_cache_t npc = { .npc_info = 0 };
-	const void *dummy_ifp = (void *)0xdeadbeef;
 	struct mbuf *m;
 	nbuf_t nbuf;
 	int ret;
--- a/usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_nbuf_test.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nbuf_test.c,v 1.4 2013/01/20 18:45:57 rmind Exp $	*/
+/*	$NetBSD: npf_nbuf_test.c,v 1.5 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*
  * NPF nbuf interface test.
@@ -30,7 +30,7 @@
 static char *
 parse_nbuf_chain(struct mbuf *m)
 {
-	const void *dummy_ifp = (void *)0xdeadbeef;
+	ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
 	char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP);
 	nbuf_t nbuf;
 	void *nptr;
--- a/usr.sbin/npf/npftest/libnpftest/npf_state_test.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_state_test.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_state_test.c,v 1.4 2012/12/24 19:05:49 rmind Exp $	*/
+/*	$NetBSD: npf_state_test.c,v 1.5 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*
  * NPF state tracking test.
@@ -133,6 +133,7 @@
 static bool
 process_packet(const int i, npf_state_t *nst, bool *snew)
 {
+	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 };
 	nbuf_t nbuf;
@@ -144,7 +145,6 @@
 		return true;
 	}
 
-	const void *dummy_ifp = (void *)0xdeadbeef;
 	nbuf_init(&nbuf, construct_packet(p), dummy_ifp);
 	ret = npf_cache_all(&npc, &nbuf);
 	KASSERT((ret & NPC_IPFRAG) == 0);
--- a/usr.sbin/npf/npftest/libnpftest/npf_test.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_test.h	Fri Nov 08 00:38:26 2013 +0000
@@ -27,6 +27,7 @@
 /* Test interfaces and IP addresses. */
 #define	IFNAME_EXT	"npftest0"
 #define	IFNAME_INT	"npftest1"
+#define	IFNAME_TEST	"npftest2"
 
 #define	LOCAL_IP1	"10.1.1.1"
 #define	LOCAL_IP2	"10.1.1.2"
@@ -40,10 +41,10 @@
 
 void		npf_test_init(void);
 int		npf_test_load(const void *);
-unsigned	npf_test_addif(const char *, unsigned, bool);
-unsigned	npf_test_getif(const char *);
+ifnet_t *	npf_test_addif(const char *, bool, bool);
+ifnet_t *	npf_test_getif(const char *);
 
-int		npf_test_statetrack(const void *, size_t, unsigned,
+int		npf_test_statetrack(const void *, size_t, ifnet_t *,
 		    bool, int64_t *);
 void		npf_test_conc(bool, unsigned);
 
--- a/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_test_subr.c,v 1.5 2013/09/24 02:04:21 rmind Exp $	*/
+/*	$NetBSD: npf_test_subr.c,v 1.6 2013/11/08 00:38:27 rmind Exp $	*/
 
 /*
  * NPF initialisation and handler routines.
@@ -33,30 +33,37 @@
 	return npfctl_reload(0, npf_dict);
 }
 
-unsigned
-npf_test_addif(const char *ifname, unsigned if_idx, bool verbose)
+ifnet_t *
+npf_test_addif(const char *ifname, bool reg, bool verbose)
 {
 	ifnet_t *ifp = if_alloc(IFT_OTHER);
 
 	/*
 	 * This is a "fake" interface with explicitly set index.
+	 * Note: test modules may not setup pfil(9) hooks and if_attach()
+	 * may not trigger npf_ifmap_attach(), so we call it manually.
 	 */
 	strlcpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
-	if (verbose) {
-		printf("+ Interface %s\n", ifp->if_xname);
+	ifp->if_dlt = DLT_NULL;
+	ifp->if_index = 0;
+	if_attach(ifp);
+	if_alloc_sadl(ifp);
+
+	npf_ifmap_attach(ifp);
+	if (reg) {
+		npf_ifmap_register(ifname);
 	}
-	ifp->if_dlt = DLT_NULL;
-	if_attach(ifp);
-	ifp->if_index = if_idx;
-	if_alloc_sadl(ifp);
-	return if_idx;
+
+	if (verbose) {
+		printf("+ Interface %s\n", ifname);
+	}
+	return ifp;
 }
 
-unsigned
+ifnet_t *
 npf_test_getif(const char *ifname)
 {
-	ifnet_t *ifp = ifunit(ifname);
-	return ifp ? ifp->if_index : 0;
+	return ifunit(ifname);
 }
 
 /*
@@ -72,15 +79,14 @@
 }
 
 int
-npf_test_statetrack(const void *data, size_t len, unsigned idx,
+npf_test_statetrack(const void *data, size_t len, ifnet_t *ifp,
     bool forw, int64_t *result)
 {
-	ifnet_t ifp = { .if_index = idx };
 	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(NULL, &m, ifp, forw ? PFIL_OUT : PFIL_IN);
 	if (error) {
 		assert(m == NULL);
 		return error;
--- a/usr.sbin/npf/npftest/npfstream.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/npfstream.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfstream.c,v 1.5 2013/09/24 02:04:21 rmind Exp $	*/
+/*	$NetBSD: npfstream.c,v 1.6 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*
  * NPF stream processor.
@@ -33,7 +33,7 @@
 static int		rcv_packet_no = 0;
 
 static void
-process_tcpip(const void *data, size_t len, FILE *fp, unsigned idx)
+process_tcpip(const void *data, size_t len, FILE *fp, ifnet_t *ifp)
 {
 	const struct ether_header *eth = data;
 	const struct ip *ip;
@@ -71,7 +71,7 @@
 	memset(result, 0, sizeof(result));
 
 	len = ntohs(ip->ip_len);
-	error = rumpns_npf_test_statetrack(ip, len, idx, forw, result);
+	error = rumpns_npf_test_statetrack(ip, len, ifp, forw, result);
 
 	fprintf(fp, "%s%2x %5d %3d %11u %11u %11u %11u %12" PRIxPTR,
 	    forw ? ">" : "<", (th->th_flags & (TH_SYN | TH_ACK | TH_FIN)),
@@ -85,7 +85,7 @@
 }
 
 int
-process_stream(const char *input, const char *output, unsigned idx)
+process_stream(const char *input, const char *output, ifnet_t *ifp)
 {
 	pcap_t *pcap;
 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
@@ -111,7 +111,7 @@
 		if (phdr->len != phdr->caplen) {
 			warnx("process_stream: truncated packet");
 		}
-		process_tcpip(data, phdr->caplen, fp, idx);
+		process_tcpip(data, phdr->caplen, fp, ifp);
 	}
 	pcap_close(pcap);
 	fclose(fp);
--- a/usr.sbin/npf/npftest/npftest.c	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/npftest.c	Fri Nov 08 00:38:26 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npftest.c,v 1.12 2013/09/24 02:44:20 rmind Exp $	*/
+/*	$NetBSD: npftest.c,v 1.13 2013/11/08 00:38:26 rmind Exp $	*/
 
 /*
  * NPF testing framework.
@@ -75,19 +75,15 @@
 static void
 load_npf_config_ifs(prop_dictionary_t dbg_dict)
 {
+	prop_array_t iflist = prop_dictionary_get(dbg_dict, "interfaces");
+	prop_object_iterator_t it = prop_array_iterator(iflist);
 	prop_dictionary_t ifdict;
-	prop_object_iterator_t it;
-	prop_array_t iflist;
 
-	iflist = prop_dictionary_get(dbg_dict, "interfaces");
-	it = prop_array_iterator(iflist);
 	while ((ifdict = prop_object_iterator_next(it)) != NULL) {
-		const char *ifname;
-		unsigned if_idx;
+		const char *ifname = NULL;
 
 		prop_dictionary_get_cstring_nocopy(ifdict, "name", &ifname);
-		prop_dictionary_get_uint32(ifdict, "idx", &if_idx);
-		(void)rumpns_npf_test_addif(ifname, if_idx, verbose);
+		(void)rumpns_npf_test_addif(ifname, true, verbose);
 	}
 	prop_object_iterator_release(it);
 }
@@ -140,7 +136,8 @@
 	bool test, ok, fail, tname_matched;
 	char *benchmark, *config, *interface, *stream, *testname;
 	unsigned nthreads = 0;
-	int idx = -1, ch;
+	ifnet_t *ifp = NULL;
+	int ch;
 
 	benchmark = NULL;
 	test = false;
@@ -224,7 +221,7 @@
 	if (config) {
 		load_npf_config(config);
 	}
-	if (interface && (idx = rumpns_npf_test_getif(interface)) == 0) {
+	if (interface && (ifp = rumpns_npf_test_getif(interface)) == 0) {
 		errx(EXIT_FAILURE, "failed to find the interface");
 	}
 
@@ -272,7 +269,7 @@
 	}
 
 	if (stream) {
-		process_stream(stream, NULL, idx);
+		process_stream(stream, NULL, ifp);
 	}
 
 	if (benchmark) {
--- a/usr.sbin/npf/npftest/npftest.h	Thu Nov 07 21:45:04 2013 +0000
+++ b/usr.sbin/npf/npftest/npftest.h	Fri Nov 08 00:38:26 2013 +0000
@@ -10,13 +10,15 @@
 #include <inttypes.h>
 #include <stdbool.h>
 
+#include <net/if.h>
+
 void		rumpns_npf_test_init(void);
 int		rumpns_npf_test_load(const void *);
-unsigned	rumpns_npf_test_addif(const char *, unsigned, bool);
-unsigned	rumpns_npf_test_getif(const char *);
+ifnet_t *	rumpns_npf_test_addif(const char *, bool, bool);
+ifnet_t *	rumpns_npf_test_getif(const char *);
 
 int		rumpns_npf_test_statetrack(const void *, size_t,
-		    unsigned, bool, int64_t *);
+		    ifnet_t *, bool, int64_t *);
 void		rumpns_npf_test_conc(bool, unsigned);
 
 bool		rumpns_npf_nbuf_test(bool);
@@ -27,6 +29,6 @@
 bool		rumpns_npf_rule_test(bool);
 bool		rumpns_npf_nat_test(bool);
 
-int		process_stream(const char *, const char *, unsigned);
+int		process_stream(const char *, const char *, ifnet_t *);
 
 #endif