Add support for CDB based NPF tables. trunk
authorrmind <rmind@NetBSD.org>
Thu, 06 Feb 2014 02:51:28 +0000
branchtrunk
changeset 224439 5b013bae54b0
parent 224438 968632609cae
child 224440 3793cb67fa5b
Add support for CDB based NPF tables.
lib/libnpf/npf.c
lib/libnpf/npf.h
sys/net/npf/npf.h
sys/net/npf/npf_ctl.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_tableset.c
usr.sbin/npf/npfctl/npf.conf.5
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npftest/libnpftest/npf_table_test.c
usr.sbin/npf/npftest/libnpftest/npf_test.h
usr.sbin/npf/npftest/npftest.c
usr.sbin/npf/npftest/npftest.h
--- a/lib/libnpf/npf.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/lib/libnpf/npf.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf.c,v 1.25 2014/02/03 02:21:52 rmind Exp $	*/
+/*	$NetBSD: npf.c,v 1.26 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.25 2014/02/03 02:21:52 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.26 2014/02/06 02:51:28 rmind Exp $");
 
 #include <sys/types.h>
 #include <netinet/in_systm.h>
@@ -961,6 +961,20 @@
 	return 0;
 }
 
+int
+npf_table_setdata(nl_table_t *tl, const void *blob, size_t len)
+{
+	prop_dictionary_t tldict = tl->ntl_dict;
+	prop_data_t bobj;
+
+	if ((bobj = prop_data_create_data(blob, len)) == NULL) {
+		return ENOMEM;
+	}
+	prop_dictionary_set(tldict, "data", bobj);
+	prop_object_release(bobj);
+	return 0;
+}
+
 static bool
 _npf_table_exists_p(nl_config_t *ncf, const char *name)
 {
--- a/lib/libnpf/npf.h	Wed Feb 05 23:10:41 2014 +0000
+++ b/lib/libnpf/npf.h	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.22 2014/02/03 02:21:52 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.23 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -111,6 +111,7 @@
 nl_table_t *	npf_table_create(const char *, u_int, int);
 int		npf_table_add_entry(nl_table_t *, int,
 		    const npf_addr_t *, const npf_netmask_t);
+int		npf_table_setdata(nl_table_t *, const void *, size_t);
 int		npf_table_insert(nl_config_t *, nl_table_t *);
 void		npf_table_destroy(nl_table_t *);
 
--- a/sys/net/npf/npf.h	Wed Feb 05 23:10:41 2014 +0000
+++ b/sys/net/npf/npf.h	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.34 2013/12/06 01:33:37 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.35 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -239,6 +239,7 @@
 /* Table types. */
 #define	NPF_TABLE_HASH			1
 #define	NPF_TABLE_TREE			2
+#define	NPF_TABLE_CDB			3
 
 #define	NPF_TABLE_MAXNAMELEN		32
 
--- a/sys/net/npf/npf_ctl.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/sys/net/npf/npf_ctl.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $	*/
+/*	$NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -77,6 +77,34 @@
 }
 
 static int __noinline
+npf_mk_table_entries(npf_table_t *t, prop_array_t entries)
+{
+	prop_object_iterator_t eit;
+	prop_dictionary_t ent;
+	int error = 0;
+
+	/* Fill all the entries. */
+	eit = prop_array_iterator(entries);
+	while ((ent = prop_object_iterator_next(eit)) != NULL) {
+		const npf_addr_t *addr;
+		npf_netmask_t mask;
+		int alen;
+
+		/* Get address and mask.  Add a table entry. */
+		prop_object_t obj = prop_dictionary_get(ent, "addr");
+		addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
+		prop_dictionary_get_uint8(ent, "mask", &mask);
+		alen = prop_data_size(obj);
+
+		error = npf_table_insert(t, alen, addr, mask);
+		if (error)
+			break;
+	}
+	prop_object_iterator_release(eit);
+	return error;
+}
+
+static int __noinline
 npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
     prop_dictionary_t errdict)
 {
@@ -92,9 +120,6 @@
 
 	it = prop_array_iterator(tables);
 	while ((tbldict = prop_object_iterator_next(it)) != NULL) {
-		prop_dictionary_t ent;
-		prop_object_iterator_t eit;
-		prop_array_t entries;
 		const char *name;
 		npf_table_t *t;
 		u_int tid;
@@ -121,8 +146,25 @@
 			break;
 		}
 
+		/* Get the entries or binary data. */
+		prop_array_t entries = prop_dictionary_get(tbldict, "entries");
+		if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
+			NPF_ERR_DEBUG(errdict);
+			error = EINVAL;
+			break;
+		}
+		prop_object_t obj = prop_dictionary_get(tbldict, "data");
+		void *blob = prop_data_data(obj);
+		size_t size = prop_data_size(obj);
+
+		if (type == NPF_TABLE_CDB && (blob == NULL || size == 0)) {
+			NPF_ERR_DEBUG(errdict);
+			error = EINVAL;
+			break;
+		}
+
 		/* Create and insert the table. */
-		t = npf_table_create(name, tid, type, 1024);	/* XXX */
+		t = npf_table_create(name, tid, type, blob, size);
 		if (t == NULL) {
 			NPF_ERR_DEBUG(errdict);
 			error = ENOMEM;
@@ -131,32 +173,10 @@
 		error = npf_tableset_insert(tblset, t);
 		KASSERT(error == 0);
 
-		/* Entries. */
-		entries = prop_dictionary_get(tbldict, "entries");
-		if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
+		if ((error = npf_mk_table_entries(t, entries)) != 0) {
 			NPF_ERR_DEBUG(errdict);
-			error = EINVAL;
 			break;
 		}
-		eit = prop_array_iterator(entries);
-		while ((ent = prop_object_iterator_next(eit)) != NULL) {
-			const npf_addr_t *addr;
-			npf_netmask_t mask;
-			int alen;
-
-			/* Get address and mask.  Add a table entry. */
-			prop_object_t obj = prop_dictionary_get(ent, "addr");
-			addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
-			prop_dictionary_get_uint8(ent, "mask", &mask);
-			alen = prop_data_size(obj);
-
-			error = npf_table_insert(t, alen, addr, mask);
-			if (error)
-				break;
-		}
-		prop_object_iterator_release(eit);
-		if (error)
-			break;
 	}
 	prop_object_iterator_release(it);
 	/*
--- a/sys/net/npf/npf_impl.h	Wed Feb 05 23:10:41 2014 +0000
+++ b/sys/net/npf/npf_impl.h	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.45 2013/12/06 01:33:37 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.46 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -229,7 +229,7 @@
 void		npf_tableset_reload(npf_tableset_t *, npf_tableset_t *);
 void		npf_tableset_syncdict(const npf_tableset_t *, prop_dictionary_t);
 
-npf_table_t *	npf_table_create(const char *, u_int, int, size_t);
+npf_table_t *	npf_table_create(const char *, u_int, int, void *, size_t);
 void		npf_table_destroy(npf_table_t *);
 
 int		npf_table_check(npf_tableset_t *, const char *, u_int, int);
--- a/sys/net/npf/npf_tableset.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/sys/net/npf/npf_tableset.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_tableset.c,v 1.20 2013/11/22 00:25:51 rmind Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.21 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -41,14 +41,16 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.20 2013/11/22 00:25:51 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.21 2014/02/06 02:51:28 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <sys/atomic.h>
 #include <sys/hash.h>
+#include <sys/cdbr.h>
 #include <sys/kmem.h>
+#include <sys/malloc.h>
 #include <sys/pool.h>
 #include <sys/queue.h>
 #include <sys/rwlock.h>
@@ -59,9 +61,9 @@
 
 typedef struct npf_tblent {
 	union {
-		LIST_ENTRY(npf_tblent) hashq;
-		pt_node_t	node;
-	} te_entry;
+		LIST_ENTRY(npf_tblent) te_hashent;
+		pt_node_t	te_node;
+	} /* C11 */;
 	int			te_alen;
 	npf_addr_t		te_addr;
 } npf_tblent_t;
@@ -70,12 +72,23 @@
 
 struct npf_table {
 	/*
-	 * The storage type can be: a) hash b) tree.
+	 * The storage type can be: a) hash b) tree c) cdb.
 	 * There are separate trees for IPv4 and IPv6.
 	 */
-	struct npf_hashl *	t_hashl;
-	u_long			t_hashmask;
-	pt_tree_t		t_tree[2];
+	union {
+		struct {
+			struct npf_hashl *t_hashl;
+			u_long		t_hashmask;
+		};
+		struct {
+			pt_tree_t	t_tree[2];
+		};
+		struct {
+			void *		t_blob;
+			size_t		t_bsize;
+			struct cdbr *	t_cdb;
+		};
+	} /* C11 */;
 
 	/*
 	 * Table ID, type and lock.  The ID may change during the
@@ -237,7 +250,7 @@
 		KASSERT(npf_config_locked_p());
 		ot->t_id = tid;
 
-		/* Destroy the new table (we hold only reference). */
+		/* Destroy the new table (we hold the only reference). */
 		t->t_refcnt--;
 		npf_table_destroy(t);
 	}
@@ -284,7 +297,7 @@
 	 * Lookup the hash table and check for duplicates.
 	 * Note: mask is ignored for the hash storage.
 	 */
-	LIST_FOREACH(ent, htbl, te_entry.hashq) {
+	LIST_FOREACH(ent, htbl, te_hashent) {
 		if (ent->te_alen != alen) {
 			continue;
 		}
@@ -303,7 +316,7 @@
 		npf_tblent_t *ent;
 
 		while ((ent = LIST_FIRST(&t->t_hashl[n])) != NULL) {
-			LIST_REMOVE(ent, te_entry.hashq);
+			LIST_REMOVE(ent, te_hashent);
 			pool_cache_put(tblent_cache, ent);
 		}
 	}
@@ -324,7 +337,8 @@
  * npf_table_create: create table with a specified ID.
  */
 npf_table_t *
-npf_table_create(const char *name, u_int tid, int type, size_t hsize)
+npf_table_create(const char *name, u_int tid, int type,
+    void *blob, size_t size)
 {
 	npf_table_t *t;
 
@@ -335,20 +349,31 @@
 	case NPF_TABLE_TREE:
 		ptree_init(&t->t_tree[0], &npf_table_ptree_ops,
 		    (void *)(sizeof(struct in_addr) / sizeof(uint32_t)),
-		    offsetof(npf_tblent_t, te_entry.node),
+		    offsetof(npf_tblent_t, te_node),
 		    offsetof(npf_tblent_t, te_addr));
 		ptree_init(&t->t_tree[1], &npf_table_ptree_ops,
 		    (void *)(sizeof(struct in6_addr) / sizeof(uint32_t)),
-		    offsetof(npf_tblent_t, te_entry.node),
+		    offsetof(npf_tblent_t, te_node),
 		    offsetof(npf_tblent_t, te_addr));
 		break;
 	case NPF_TABLE_HASH:
-		t->t_hashl = hashinit(hsize, HASH_LIST, true, &t->t_hashmask);
+		t->t_hashl = hashinit(1024, HASH_LIST, true, &t->t_hashmask);
 		if (t->t_hashl == NULL) {
 			kmem_free(t, sizeof(npf_table_t));
 			return NULL;
 		}
 		break;
+	case NPF_TABLE_CDB:
+		t->t_blob = blob;
+		t->t_bsize = size;
+		t->t_cdb = cdbr_open_mem(blob, size, CDBR_DEFAULT, NULL, NULL);
+		if (t->t_cdb == NULL) {
+			kmem_free(t, sizeof(npf_table_t));
+			free(blob, M_TEMP);
+			return NULL;
+		}
+		t->t_nitems = cdbr_entries(t->t_cdb);
+		break;
 	default:
 		KASSERT(false);
 	}
@@ -376,6 +401,10 @@
 		table_tree_destroy(&t->t_tree[0]);
 		table_tree_destroy(&t->t_tree[1]);
 		break;
+	case NPF_TABLE_CDB:
+		cdbr_close(t->t_cdb);
+		free(t->t_blob, M_TEMP);
+		break;
 	default:
 		KASSERT(false);
 	}
@@ -395,7 +424,12 @@
 	if (ts->ts_map[tid] != NULL) {
 		return EEXIST;
 	}
-	if (type != NPF_TABLE_TREE && type != NPF_TABLE_HASH) {
+	switch (type) {
+	case NPF_TABLE_TREE:
+	case NPF_TABLE_HASH:
+	case NPF_TABLE_CDB:
+		break;
+	default:
 		return EINVAL;
 	}
 	if (strlen(name) >= NPF_TABLE_MAXNAMELEN) {
@@ -463,7 +497,7 @@
 			break;
 		}
 		if (!table_hash_lookup(t, addr, alen, &htbl)) {
-			LIST_INSERT_HEAD(htbl, ent, te_entry.hashq);
+			LIST_INSERT_HEAD(htbl, ent, te_hashent);
 			t->t_nitems++;
 		} else {
 			error = EEXIST;
@@ -488,6 +522,9 @@
 		}
 		break;
 	}
+	case NPF_TABLE_CDB:
+		error = EINVAL;
+		break;
 	default:
 		KASSERT(false);
 	}
@@ -507,8 +544,8 @@
     const npf_addr_t *addr, const npf_netmask_t mask)
 {
 	const u_int aidx = NPF_ADDRLEN2TREE(alen);
-	npf_tblent_t *ent;
-	int error;
+	npf_tblent_t *ent = NULL;
+	int error = ENOENT;
 
 	error = table_cidr_check(aidx, addr, mask);
 	if (error) {
@@ -522,7 +559,7 @@
 
 		ent = table_hash_lookup(t, addr, alen, &htbl);
 		if (__predict_true(ent != NULL)) {
-			LIST_REMOVE(ent, te_entry.hashq);
+			LIST_REMOVE(ent, te_hashent);
 			t->t_nitems--;
 		}
 		break;
@@ -537,17 +574,19 @@
 		}
 		break;
 	}
+	case NPF_TABLE_CDB:
+		error = EINVAL;
+		break;
 	default:
 		KASSERT(false);
 		ent = NULL;
 	}
 	rw_exit(&t->t_lock);
 
-	if (ent == NULL) {
-		return ENOENT;
+	if (ent) {
+		pool_cache_put(tblent_cache, ent);
 	}
-	pool_cache_put(tblent_cache, ent);
-	return 0;
+	return error;
 }
 
 /*
@@ -558,34 +597,43 @@
 npf_table_lookup(npf_table_t *t, const int alen, const npf_addr_t *addr)
 {
 	const u_int aidx = NPF_ADDRLEN2TREE(alen);
-	npf_tblent_t *ent;
+	struct npf_hashl *htbl;
+	const void *data;
+	size_t dlen;
+	bool found;
 
 	if (__predict_false(aidx > 1)) {
 		return EINVAL;
 	}
 
-	rw_enter(&t->t_lock, RW_READER);
 	switch (t->t_type) {
-	case NPF_TABLE_HASH: {
-		struct npf_hashl *htbl;
-		ent = table_hash_lookup(t, addr, alen, &htbl);
+	case NPF_TABLE_HASH:
+		rw_enter(&t->t_lock, RW_READER);
+		found = table_hash_lookup(t, addr, alen, &htbl) != NULL;
+		rw_exit(&t->t_lock);
 		break;
-	}
-	case NPF_TABLE_TREE: {
-		ent = ptree_find_node(&t->t_tree[aidx], addr);
+	case NPF_TABLE_TREE:
+		rw_enter(&t->t_lock, RW_READER);
+		found = ptree_find_node(&t->t_tree[aidx], addr) != NULL;
+		rw_exit(&t->t_lock);
 		break;
-	}
+	case NPF_TABLE_CDB:
+		if (cdbr_find(t->t_cdb, addr, alen, &data, &dlen) == 0) {
+			found = dlen == alen && memcmp(addr, data, dlen) == 0;
+		} else {
+			found = false;
+		}
+		break;
 	default:
 		KASSERT(false);
-		ent = NULL;
+		found = false;
 	}
-	rw_exit(&t->t_lock);
 
-	return ent ? 0 : ENOENT;
+	return found ? 0 : ENOENT;
 }
 
 static int
-table_ent_copyout(npf_tblent_t *ent, npf_netmask_t mask,
+table_ent_copyout(const npf_addr_t *addr, const int alen, npf_netmask_t mask,
     void *ubuf, size_t len, size_t *off)
 {
 	void *ubufp = (uint8_t *)ubuf + *off;
@@ -594,14 +642,33 @@
 	if ((*off += sizeof(npf_ioctl_ent_t)) > len) {
 		return ENOMEM;
 	}
-	uent.alen = ent->te_alen;
-	memcpy(&uent.addr, &ent->te_addr, sizeof(npf_addr_t));
+	uent.alen = alen;
+	memcpy(&uent.addr, addr, sizeof(npf_addr_t));
 	uent.mask = mask;
 
 	return copyout(&uent, ubufp, sizeof(npf_ioctl_ent_t));
 }
 
 static int
+table_hash_list(const npf_table_t *t, void *ubuf, size_t len)
+{
+	size_t off = 0;
+	int error = 0;
+
+	for (unsigned n = 0; n <= t->t_hashmask; n++) {
+		npf_tblent_t *ent;
+
+		LIST_FOREACH(ent, &t->t_hashl[n], te_hashent) {
+			error = table_ent_copyout(&ent->te_addr,
+			    ent->te_alen, 0, ubuf, len, &off);
+			if (error)
+				break;
+		}
+	}
+	return error;
+}
+
+static int
 table_tree_list(pt_tree_t *tree, npf_netmask_t maxmask, void *ubuf,
     size_t len, size_t *off)
 {
@@ -614,7 +681,26 @@
 		if (!ptree_mask_node_p(tree, ent, &blen)) {
 			blen = maxmask;
 		}
-		error = table_ent_copyout(ent, blen, ubuf, len, off);
+		error = table_ent_copyout(&ent->te_addr, ent->te_alen,
+		    blen, ubuf, len, off);
+		if (error)
+			break;
+	}
+	return error;
+}
+
+static int
+table_cdb_list(npf_table_t *t, void *ubuf, size_t len)
+{
+	size_t off = 0, dlen;
+	const void *data;
+	int error = 0;
+
+	for (size_t i = 0; i < t->t_nitems; i++) {
+		if (cdbr_get(t->t_cdb, i, &data, &dlen) != 0) {
+			return EINVAL;
+		}
+		error = table_ent_copyout(data, dlen, 0, ubuf, len, &off);
 		if (error)
 			break;
 	}
@@ -633,14 +719,7 @@
 	rw_enter(&t->t_lock, RW_READER);
 	switch (t->t_type) {
 	case NPF_TABLE_HASH:
-		for (unsigned n = 0; n <= t->t_hashmask; n++) {
-			npf_tblent_t *ent;
-
-			LIST_FOREACH(ent, &t->t_hashl[n], te_entry.hashq)
-				if ((error = table_ent_copyout(ent, 0, ubuf,
-				    len, &off)) != 0)
-					break;
-		}
+		error = table_hash_list(t, ubuf, len);
 		break;
 	case NPF_TABLE_TREE:
 		error = table_tree_list(&t->t_tree[0], 32, ubuf, len, &off);
@@ -648,6 +727,9 @@
 			break;
 		error = table_tree_list(&t->t_tree[1], 128, ubuf, len, &off);
 		break;
+	case NPF_TABLE_CDB:
+		error = table_cdb_list(t, ubuf, len);
+		break;
 	default:
 		KASSERT(false);
 	}
@@ -662,6 +744,8 @@
 int
 npf_table_flush(npf_table_t *t)
 {
+	int error = 0;
+
 	rw_enter(&t->t_lock, RW_WRITER);
 	switch (t->t_type) {
 	case NPF_TABLE_HASH:
@@ -673,9 +757,12 @@
 		table_tree_destroy(&t->t_tree[1]);
 		t->t_nitems = 0;
 		break;
+	case NPF_TABLE_CDB:
+		error = EINVAL;
+		break;
 	default:
 		KASSERT(false);
 	}
 	rw_exit(&t->t_lock);
-	return 0;
+	return error;
 }
--- a/usr.sbin/npf/npfctl/npf.conf.5	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf.conf.5	Thu Feb 06 02:51:28 2014 +0000
@@ -1,6 +1,6 @@
-.\"    $NetBSD: npf.conf.5,v 1.35 2013/11/19 00:28:41 rmind Exp $
+.\"    $NetBSD: npf.conf.5,v 1.36 2014/02/06 02:51:28 rmind Exp $
 .\"
-.\" Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\"
 .\" This material is based upon work partially supported by The
@@ -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 November 18, 2013
+.Dd February 6, 2014
 .Dt NPF.CONF 5
 .Os
 .Sh NAME
@@ -85,7 +85,7 @@
 table <black> type hash dynamic
 .Pp
 .Ed
-Currently, tables support two storage types: "hash" or "tree".
+Currently, tables support two storage types: "hash", "tree" or "cdb".
 They can also be "dynamic" or static i.e. loaded from the specified file.
 .Pp
 The file should contain a list of IP addresses and/or networks in the form of:
@@ -94,7 +94,8 @@
 10.1.1.1
 .Ed
 .Pp
-Tables of type "hash" can only contain IP addresses.
+Tables of type "hash" and "cdb" can only contain IP addresses.
+Also, the latter can only be static.
 .Ss Interfaces
 Interfaces can be specified as the values of the variables:
 .Pp
@@ -223,7 +224,7 @@
 ; Table definition.  Table ID shall be numeric.  Path is in the double quotes.
 
 table-id	= \*[Lt]table-name\*[Gt]
-table-def	= "table" table-id "type" ( "hash" | "tree" )
+table-def	= "table" table-id "type" ( "hash" | "tree" | "cdb" )
 		  ( "dynamic" | "file" path )
 
 ; Mapping for address translation.
--- a/usr.sbin/npf/npfctl/npf_build.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,7 +1,7 @@
-/*	$NetBSD: npf_build.c,v 1.32 2014/02/03 02:21:52 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.33 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -34,19 +34,22 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.32 2014/02/03 02:21:52 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.33 2014/02/06 02:51:28 rmind Exp $");
 
 #include <sys/types.h>
-#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
 
 #include <stdlib.h>
 #include <inttypes.h>
 #include <string.h>
 #include <ctype.h>
+#include <unistd.h>
 #include <errno.h>
 #include <err.h>
 
 #include <pcap/pcap.h>
+#include <cdbw.h>
 
 #include "npfctl.h"
 
@@ -635,11 +638,15 @@
 static void
 npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname)
 {
+	struct cdbw *cdbw;
 	char *buf = NULL;
 	int l = 0;
 	FILE *fp;
 	size_t n;
 
+	if (type == NPF_TABLE_CDB && (cdbw = cdbw_open()) == NULL) {
+		err(EXIT_FAILURE, "cdbw_open");
+	}
 	fp = fopen(fname, "r");
 	if (fp == NULL) {
 		err(EXIT_FAILURE, "open '%s'", fname);
@@ -656,18 +663,56 @@
 			errx(EXIT_FAILURE,
 			    "%s:%d: invalid table entry", fname, l);
 		}
-		if (type == NPF_TABLE_HASH && fam.fam_mask != NPF_NO_NETMASK) {
-			errx(EXIT_FAILURE,
-			    "%s:%d: mask used with the hash table", fname, l);
+		if (type != NPF_TABLE_TREE && fam.fam_mask != NPF_NO_NETMASK) {
+			errx(EXIT_FAILURE, "%s:%d: mask used with the "
+			    "non-tree table", fname, l);
 		}
 
-		/* Create and add a table entry. */
-		npf_table_add_entry(tl, fam.fam_family,
-		    &fam.fam_addr, fam.fam_mask);
+		/*
+		 * Create and add a table entry.
+		 */
+		if (type == NPF_TABLE_CDB) {
+			const npf_addr_t *addr = &fam.fam_addr;
+			if (cdbw_put(cdbw, addr, alen, addr, alen) == -1) {
+				err(EXIT_FAILURE, "cdbw_put");
+			}
+		} else {
+			npf_table_add_entry(tl, fam.fam_family,
+			    &fam.fam_addr, fam.fam_mask);
+		}
 	}
 	if (buf != NULL) {
 		free(buf);
 	}
+
+	if (type == NPF_TABLE_CDB) {
+		struct stat sb;
+		char sfn[32];
+		void *cdb;
+		int fd;
+
+		strlcpy(sfn, "/tmp/npfcdb.XXXXXX", sizeof(sfn));
+		if ((fd = mkstemp(sfn)) == -1) {
+			err(EXIT_FAILURE, "mkstemp");
+		}
+		unlink(sfn);
+
+		if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) {
+			err(EXIT_FAILURE, "cdbw_output");
+		}
+		cdbw_close(cdbw);
+
+		if (fstat(fd, &sb) == -1) {
+			err(EXIT_FAILURE, "fstat");
+		}
+		if ((cdb = mmap(NULL, sb.st_size, PROT_READ,
+		    MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+			err(EXIT_FAILURE, "mmap");
+		}
+		npf_table_setdata(tl, cdb, sb.st_size);
+
+		close(fd);
+	}
 }
 
 /*
@@ -689,6 +734,8 @@
 
 	if (fname) {
 		npfctl_fill_table(tl, type, fname);
+	} else if (type == NPF_TABLE_CDB) {
+		errx(EXIT_FAILURE, "tables of cdb type must be static");
 	}
 }
 
--- a/usr.sbin/npf/npfctl/npf_parse.y	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.29 2013/11/19 00:28:41 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.30 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -91,6 +91,7 @@
 %token			ARROWLEFT
 %token			ARROWRIGHT
 %token			BLOCK
+%token			CDB
 %token			CURLY_CLOSE
 %token			CURLY_OPEN
 %token			CODE
@@ -278,6 +279,7 @@
 table_type
 	: HASH		{ $$ = NPF_TABLE_HASH; }
 	| TREE		{ $$ = NPF_TABLE_TREE; }
+	| CDB		{ $$ = NPF_TABLE_CDB; }
 	;
 
 table_store
--- a/usr.sbin/npf/npfctl/npf_scan.l	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.16 2013/11/19 00:28:41 rmind Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.17 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -91,6 +91,7 @@
 type			return TYPE;
 hash			return HASH;
 tree			return TREE;
+cdb			return CDB;
 static			return TSTATIC;
 dynamic			return TDYNAMIC;
 file			return TFILE;
--- a/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_table_test.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_table_test.c,v 1.7 2013/11/12 00:46:34 rmind Exp $	*/
+/*	$NetBSD: npf_table_test.c,v 1.8 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*
  * NPF tableset test.
@@ -7,6 +7,7 @@
  */
 
 #include <sys/types.h>
+#include <sys/malloc.h>
 
 #include "npf_impl.h"
 #include "npf_test.h"
@@ -43,6 +44,7 @@
 
 #define	HASH_TID		"hash-table"
 #define	TREE_TID		"tree-table"
+#define	CDB_TID			"cdb-table"
 
 static bool
 npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
@@ -74,21 +76,22 @@
 }
 
 bool
-npf_table_test(bool verbose)
+npf_table_test(bool verbose, void *blob, size_t size)
 {
 	npf_addr_t addr_storage, *addr = &addr_storage;
 	const int nm = NPF_NO_NETMASK;
+	npf_table_t *t, *t1, *t2, *t3;
 	npf_tableset_t *tblset;
-	npf_table_t *t, *t1, *t2;
 	int error, alen;
 	bool fail = false;
+	void *cdb;
 	u_int i;
 
-	tblset = npf_tableset_create(2);
+	tblset = npf_tableset_create(3);
 	fail |= !(tblset != NULL);
 
 	/* Table ID 1, using hash table with 256 lists. */
-	t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, 256);
+	t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, NULL, 256);
 	fail |= !(t1 != NULL);
 	error = npf_tableset_insert(tblset, t1);
 	fail |= !(error == 0);
@@ -98,11 +101,20 @@
 	fail |= !(error != 0);
 
 	/* Table ID 2, using a prefix tree. */
-	t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, 0);
+	t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, NULL, 0);
 	fail |= !(t2 != NULL);
 	error = npf_tableset_insert(tblset, t2);
 	fail |= !(error == 0);
 
+	/* Table ID 3, using a CDB. */
+	cdb = malloc(size, M_TEMP, M_WAITOK);
+	memcpy(cdb, blob, size);
+
+	t3 = npf_table_create(CDB_TID, 2, NPF_TABLE_CDB, cdb, size);
+	fail |= !(t3 != NULL);
+	error = npf_tableset_insert(tblset, t3);
+	fail |= !(error == 0);
+
 	/* Attempt to match non-existing entries - should fail. */
 	addr->s6_addr32[0] = inet_addr(ip_list[0]);
 	alen = sizeof(struct in_addr);
@@ -221,6 +233,19 @@
 		fail |= !(error == 0);
 	}
 
+	/* Test CDB. */
+	addr->s6_addr32[0] = inet_addr(ip_list[0]);
+	alen = sizeof(struct in_addr);
+	error = npf_table_lookup(t3, alen, addr);
+	fail |= !(error == 0);
+
+	for (i = 1; i < __arraycount(ip_list) - 1; i++) {
+		addr->s6_addr32[0] = inet_addr(ip_list[i]);
+		alen = sizeof(struct in_addr);
+		error = npf_table_lookup(t3, alen, addr);
+		fail |= !(error != 0);
+	}
+
 	npf_tableset_destroy(tblset);
 
 	return !fail;
--- a/usr.sbin/npf/npftest/libnpftest/npf_test.h	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npftest/libnpftest/npf_test.h	Thu Feb 06 02:51:28 2014 +0000
@@ -57,7 +57,7 @@
 
 bool		npf_nbuf_test(bool);
 bool		npf_bpf_test(bool);
-bool		npf_table_test(bool);
+bool		npf_table_test(bool, void *, size_t);
 bool		npf_state_test(bool);
 
 bool		npf_rule_test(bool);
--- a/usr.sbin/npf/npftest/npftest.c	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npftest/npftest.c	Thu Feb 06 02:51:28 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npftest.c,v 1.15 2014/02/05 03:49:48 rmind Exp $	*/
+/*	$NetBSD: npftest.c,v 1.16 2014/02/06 02:51:28 rmind Exp $	*/
 
 /*
  * NPF testing framework.
@@ -15,6 +15,7 @@
 #include <fcntl.h>
 #include <err.h>
 
+#include <sys/mman.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <arpa/inet.h>
@@ -22,6 +23,8 @@
 #include <rump/rump.h>
 #include <rump/rump_syscalls.h>
 
+#include <cdbw.h>
+
 #include "npftest.h"
 
 static bool verbose, quiet;
@@ -121,6 +124,51 @@
 	}
 }
 
+static void *
+generate_test_cdb(size_t *size)
+{
+	in_addr_t addr;
+	struct cdbw *cdbw;
+	struct stat sb;
+	char sfn[32];
+	int alen, fd;
+	void *cdb;
+
+	if ((cdbw = cdbw_open()) == NULL) {
+		err(EXIT_FAILURE, "cdbw_open");
+	}
+	strlcpy(sfn, "/tmp/npftest_cdb.XXXXXX", sizeof(sfn));
+	if ((fd = mkstemp(sfn)) == -1) {
+		err(EXIT_FAILURE, "mkstemp");
+	}
+	unlink(sfn);
+
+	addr = inet_addr("192.168.1.1"), alen = sizeof(struct in_addr);
+	if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
+		err(EXIT_FAILURE, "cdbw_put");
+
+	addr = inet_addr("10.0.0.2"), alen = sizeof(struct in_addr);
+	if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
+		err(EXIT_FAILURE, "cdbw_put");
+
+	if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) {
+		err(EXIT_FAILURE, "cdbw_output");
+	}
+	cdbw_close(cdbw);
+
+	if (fstat(fd, &sb) == -1) {
+		err(EXIT_FAILURE, "fstat");
+	}
+	if ((cdb = mmap(NULL, sb.st_size, PROT_READ,
+	    MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+		err(EXIT_FAILURE, "mmap");
+	}
+	close(fd);
+
+	*size = sb.st_size;
+	return cdb;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -233,9 +281,14 @@
 		}
 
 		if (!testname || strcmp("table", testname) == 0) {
-			ok = rumpns_npf_table_test(verbose);
+			void *cdb;
+			size_t len;
+
+			cdb = generate_test_cdb(&len);
+			ok = rumpns_npf_table_test(verbose, cdb, len);
 			fail |= result("table", ok);
 			tname_matched = true;
+			munmap(cdb, len);
 		}
 
 		if (!testname || strcmp("state", testname) == 0) {
--- a/usr.sbin/npf/npftest/npftest.h	Wed Feb 05 23:10:41 2014 +0000
+++ b/usr.sbin/npf/npftest/npftest.h	Thu Feb 06 02:51:28 2014 +0000
@@ -23,7 +23,7 @@
 
 bool		rumpns_npf_nbuf_test(bool);
 bool		rumpns_npf_bpf_test(bool);
-bool		rumpns_npf_table_test(bool);
+bool		rumpns_npf_table_test(bool, void *, size_t);
 bool		rumpns_npf_state_test(bool);
 
 bool		rumpns_npf_rule_test(bool);