xref: /netbsd-src/sys/net/npf/npf_tableset.c (revision 5e72ca9101a1d443e82b0dc40ff8d3b4367868e9)
12e6f2099Srmind /*-
2dadc88e3Srmind  * Copyright (c) 2009-2019 The NetBSD Foundation, Inc.
32e6f2099Srmind  * All rights reserved.
42e6f2099Srmind  *
52e6f2099Srmind  * This material is based upon work partially supported by The
62e6f2099Srmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
72e6f2099Srmind  *
82e6f2099Srmind  * Redistribution and use in source and binary forms, with or without
92e6f2099Srmind  * modification, are permitted provided that the following conditions
102e6f2099Srmind  * are met:
112e6f2099Srmind  * 1. Redistributions of source code must retain the above copyright
122e6f2099Srmind  *    notice, this list of conditions and the following disclaimer.
132e6f2099Srmind  * 2. Redistributions in binary form must reproduce the above copyright
142e6f2099Srmind  *    notice, this list of conditions and the following disclaimer in the
152e6f2099Srmind  *    documentation and/or other materials provided with the distribution.
162e6f2099Srmind  *
172e6f2099Srmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182e6f2099Srmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192e6f2099Srmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202e6f2099Srmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212e6f2099Srmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222e6f2099Srmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232e6f2099Srmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242e6f2099Srmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252e6f2099Srmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262e6f2099Srmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272e6f2099Srmind  * POSSIBILITY OF SUCH DAMAGE.
282e6f2099Srmind  */
292e6f2099Srmind 
302e6f2099Srmind /*
31628e094cSrmind  * NPF tableset module.
322e6f2099Srmind  *
3364647e51Srmind  * Notes
3464647e51Srmind  *
3564647e51Srmind  *	The tableset is an array of tables.  After the creation, the array
3664647e51Srmind  *	is immutable.  The caller is responsible to synchronise the access
373d9a792dSrmind  *	to the tableset.
38dadc88e3Srmind  *
39dadc88e3Srmind  * Warning (not applicable for the userspace npfkern):
40dadc88e3Srmind  *
41dadc88e3Srmind  *	The thmap_put()/thmap_del() are not called from the interrupt
42b899bfd9Srmind  *	context and are protected by an IPL_NET mutex(9), therefore they
43b899bfd9Srmind  *	do not need SPL wrappers -- see the comment at the top of the
44b899bfd9Srmind  *	npf_conndb.c source file.
452e6f2099Srmind  */
462e6f2099Srmind 
47f75d79ebSchristos #ifdef _KERNEL
482e6f2099Srmind #include <sys/cdefs.h>
49*5e72ca91Sriastradh __KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.42 2023/02/24 11:03:01 riastradh Exp $");
502e6f2099Srmind 
512e6f2099Srmind #include <sys/param.h>
5215d58f91Srmind #include <sys/types.h>
532e6f2099Srmind 
542e6f2099Srmind #include <sys/atomic.h>
55ffcdc4afSrmind #include <sys/cdbr.h>
562e6f2099Srmind #include <sys/kmem.h>
572e6f2099Srmind #include <sys/pool.h>
582e6f2099Srmind #include <sys/queue.h>
5939013e66Srmind #include <sys/mutex.h>
603d9a792dSrmind #include <sys/thmap.h>
612e6f2099Srmind 
628f6d079fSchristos #include "lpm.h"
63f75d79ebSchristos #endif
64f75d79ebSchristos 
65f75d79ebSchristos #include "npf_impl.h"
662e6f2099Srmind 
6764647e51Srmind typedef struct npf_tblent {
688f6d079fSchristos 	LIST_ENTRY(npf_tblent)	te_listent;
698f6d079fSchristos 	uint16_t		te_preflen;
708f6d079fSchristos 	uint16_t		te_alen;
715a5d868dSzoltan 	npf_addr_t		te_addr;
7264647e51Srmind } npf_tblent_t;
732e6f2099Srmind 
743d9a792dSrmind #define	NPF_ADDRLEN2IDX(alen)	((alen) >> 4)
753d9a792dSrmind #define	NPF_ADDR_SLOTS		(2)
762e6f2099Srmind 
772e6f2099Srmind struct npf_table {
781e7342c1Srmind 	/*
793d9a792dSrmind 	 * The storage type can be: a) hashmap b) LPM c) cdb.
801e7342c1Srmind 	 * There are separate trees for IPv4 and IPv6.
811e7342c1Srmind 	 */
82ffcdc4afSrmind 	union {
83ffcdc4afSrmind 		struct {
843d9a792dSrmind 			thmap_t *	t_map;
853d9a792dSrmind 			LIST_HEAD(, npf_tblent) t_gc;
86ffcdc4afSrmind 		};
878f6d079fSchristos 		lpm_t *			t_lpm;
88ffcdc4afSrmind 		struct {
89ffcdc4afSrmind 			void *		t_blob;
90ffcdc4afSrmind 			size_t		t_bsize;
91ffcdc4afSrmind 			struct cdbr *	t_cdb;
92ffcdc4afSrmind 		};
933d9a792dSrmind 		struct {
943d9a792dSrmind 			npf_tblent_t **	t_elements[NPF_ADDR_SLOTS];
953d9a792dSrmind 			unsigned	t_allocated[NPF_ADDR_SLOTS];
963d9a792dSrmind 			unsigned	t_used[NPF_ADDR_SLOTS];
973d9a792dSrmind 		};
98ffcdc4afSrmind 	} /* C11 */;
993d9a792dSrmind 	LIST_HEAD(, npf_tblent)		t_list;
1003d9a792dSrmind 	unsigned			t_nitems;
1011e7342c1Srmind 
1021e7342c1Srmind 	/*
1031e7342c1Srmind 	 * Table ID, type and lock.  The ID may change during the
104976285b5Sriastradh 	 * config reload, it is protected by the npf_t::config_lock.
1051e7342c1Srmind 	 */
1061e7342c1Srmind 	int			t_type;
1073d9a792dSrmind 	unsigned		t_id;
10839013e66Srmind 	kmutex_t		t_lock;
1091e7342c1Srmind 
1103d9a792dSrmind 	/* Reference count and table name. */
1113d9a792dSrmind 	unsigned		t_refcnt;
1121e7342c1Srmind 	char			t_name[NPF_TABLE_MAXNAMELEN];
1132e6f2099Srmind };
1142e6f2099Srmind 
1151e7342c1Srmind struct npf_tableset {
1163d9a792dSrmind 	unsigned		ts_nitems;
1171e7342c1Srmind 	npf_table_t *		ts_map[];
1181e7342c1Srmind };
1191e7342c1Srmind 
1201e7342c1Srmind #define	NPF_TABLESET_SIZE(n)	\
1211e7342c1Srmind     (offsetof(npf_tableset_t, ts_map[n]) * sizeof(npf_table_t *))
1221e7342c1Srmind 
1233d9a792dSrmind #define	NPF_IFADDR_STEP		4
124a3b239f6Srmind 
125628e094cSrmind static pool_cache_t		tblent_cache	__read_mostly;
1262e6f2099Srmind 
1272e6f2099Srmind /*
1282e6f2099Srmind  * npf_table_sysinit: initialise tableset structures.
1292e6f2099Srmind  */
130628e094cSrmind void
npf_tableset_sysinit(void)1312e6f2099Srmind npf_tableset_sysinit(void)
1322e6f2099Srmind {
1333d9a792dSrmind 	tblent_cache = pool_cache_init(sizeof(npf_tblent_t), 0,
13463f44833Srmind 	    0, 0, "npftblpl", NULL, IPL_NONE, NULL, NULL, NULL);
1352e6f2099Srmind }
1362e6f2099Srmind 
1372e6f2099Srmind void
npf_tableset_sysfini(void)1382e6f2099Srmind npf_tableset_sysfini(void)
1392e6f2099Srmind {
1402e6f2099Srmind 	pool_cache_destroy(tblent_cache);
1412e6f2099Srmind }
1422e6f2099Srmind 
1432e6f2099Srmind npf_tableset_t *
npf_tableset_create(u_int nitems)1441e7342c1Srmind npf_tableset_create(u_int nitems)
1452e6f2099Srmind {
1461e7342c1Srmind 	npf_tableset_t *ts = kmem_zalloc(NPF_TABLESET_SIZE(nitems), KM_SLEEP);
1471e7342c1Srmind 	ts->ts_nitems = nitems;
1481e7342c1Srmind 	return ts;
1492e6f2099Srmind }
1502e6f2099Srmind 
1512e6f2099Srmind void
npf_tableset_destroy(npf_tableset_t * ts)1521e7342c1Srmind npf_tableset_destroy(npf_tableset_t *ts)
1532e6f2099Srmind {
1542e6f2099Srmind 	/*
1551e7342c1Srmind 	 * Destroy all tables (no references should be held, since the
1561e7342c1Srmind 	 * ruleset should be destroyed before).
1572e6f2099Srmind 	 */
1581e7342c1Srmind 	for (u_int tid = 0; tid < ts->ts_nitems; tid++) {
1591e7342c1Srmind 		npf_table_t *t = ts->ts_map[tid];
1601e7342c1Srmind 
161122a3e8aSriastradh 		if (t == NULL)
162122a3e8aSriastradh 			continue;
163ef3476fbSriastradh 		membar_release();
164122a3e8aSriastradh 		if (atomic_dec_uint_nv(&t->t_refcnt) > 0)
165122a3e8aSriastradh 			continue;
166ef3476fbSriastradh 		membar_acquire();
1672e6f2099Srmind 		npf_table_destroy(t);
1682e6f2099Srmind 	}
1691e7342c1Srmind 	kmem_free(ts, NPF_TABLESET_SIZE(ts->ts_nitems));
1702e6f2099Srmind }
1712e6f2099Srmind 
1722e6f2099Srmind /*
1732e6f2099Srmind  * npf_tableset_insert: insert the table into the specified tableset.
1742e6f2099Srmind  *
175a3b239f6Srmind  * => Returns 0 on success.  Fails and returns error if ID is already used.
1762e6f2099Srmind  */
1772e6f2099Srmind int
npf_tableset_insert(npf_tableset_t * ts,npf_table_t * t)1781e7342c1Srmind npf_tableset_insert(npf_tableset_t *ts, npf_table_t *t)
1792e6f2099Srmind {
1802e6f2099Srmind 	const u_int tid = t->t_id;
1812e6f2099Srmind 	int error;
1822e6f2099Srmind 
1831e7342c1Srmind 	KASSERT((u_int)tid < ts->ts_nitems);
1842e6f2099Srmind 
1851e7342c1Srmind 	if (ts->ts_map[tid] == NULL) {
1860e218254Srmind 		atomic_inc_uint(&t->t_refcnt);
1871e7342c1Srmind 		ts->ts_map[tid] = t;
1882e6f2099Srmind 		error = 0;
1892e6f2099Srmind 	} else {
1902e6f2099Srmind 		error = EEXIST;
1912e6f2099Srmind 	}
1922e6f2099Srmind 	return error;
1932e6f2099Srmind }
1942e6f2099Srmind 
1950b635e7cSrmind npf_table_t *
npf_tableset_swap(npf_tableset_t * ts,npf_table_t * newt)1960b635e7cSrmind npf_tableset_swap(npf_tableset_t *ts, npf_table_t *newt)
1970b635e7cSrmind {
1980b635e7cSrmind 	const u_int tid = newt->t_id;
1990b635e7cSrmind 	npf_table_t *oldt = ts->ts_map[tid];
2000b635e7cSrmind 
2010b635e7cSrmind 	KASSERT(tid < ts->ts_nitems);
2020b635e7cSrmind 	KASSERT(oldt->t_id == newt->t_id);
2030b635e7cSrmind 
2040b635e7cSrmind 	newt->t_refcnt = oldt->t_refcnt;
2050b635e7cSrmind 	oldt->t_refcnt = 0;
206b899bfd9Srmind 	membar_producer();
2070b635e7cSrmind 
2080b635e7cSrmind 	return atomic_swap_ptr(&ts->ts_map[tid], newt);
2090b635e7cSrmind }
2100b635e7cSrmind 
2112e6f2099Srmind /*
2121e7342c1Srmind  * npf_tableset_getbyname: look for a table in the set given the name.
2131e7342c1Srmind  */
2141e7342c1Srmind npf_table_t *
npf_tableset_getbyname(npf_tableset_t * ts,const char * name)2151e7342c1Srmind npf_tableset_getbyname(npf_tableset_t *ts, const char *name)
2161e7342c1Srmind {
2171e7342c1Srmind 	npf_table_t *t;
2181e7342c1Srmind 
2191e7342c1Srmind 	for (u_int tid = 0; tid < ts->ts_nitems; tid++) {
2201e7342c1Srmind 		if ((t = ts->ts_map[tid]) == NULL)
2211e7342c1Srmind 			continue;
2221e7342c1Srmind 		if (strcmp(name, t->t_name) == 0)
2231e7342c1Srmind 			return t;
2241e7342c1Srmind 	}
2251e7342c1Srmind 	return NULL;
2261e7342c1Srmind }
2271e7342c1Srmind 
2281e7342c1Srmind npf_table_t *
npf_tableset_getbyid(npf_tableset_t * ts,unsigned tid)229b899bfd9Srmind npf_tableset_getbyid(npf_tableset_t *ts, unsigned tid)
2301e7342c1Srmind {
2311e7342c1Srmind 	if (__predict_true(tid < ts->ts_nitems)) {
232b899bfd9Srmind 		return atomic_load_relaxed(&ts->ts_map[tid]);
2331e7342c1Srmind 	}
2341e7342c1Srmind 	return NULL;
2351e7342c1Srmind }
2361e7342c1Srmind 
2371e7342c1Srmind /*
23864647e51Srmind  * npf_tableset_reload: iterate all tables and if the new table is of the
23964647e51Srmind  * same type and has no items, then we preserve the old one and its entries.
24064647e51Srmind  *
24164647e51Srmind  * => The caller is responsible for providing synchronisation.
24264647e51Srmind  */
24364647e51Srmind void
npf_tableset_reload(npf_t * npf,npf_tableset_t * nts,npf_tableset_t * ots)244f75d79ebSchristos npf_tableset_reload(npf_t *npf, npf_tableset_t *nts, npf_tableset_t *ots)
24564647e51Srmind {
2461e7342c1Srmind 	for (u_int tid = 0; tid < nts->ts_nitems; tid++) {
2471e7342c1Srmind 		npf_table_t *t, *ot;
24864647e51Srmind 
2491e7342c1Srmind 		if ((t = nts->ts_map[tid]) == NULL) {
25064647e51Srmind 			continue;
25164647e51Srmind 		}
2521e7342c1Srmind 
2531e7342c1Srmind 		/* If our table has entries, just load it. */
2541e7342c1Srmind 		if (t->t_nitems) {
2551e7342c1Srmind 			continue;
2561e7342c1Srmind 		}
2571e7342c1Srmind 
2581e7342c1Srmind 		/* Look for a currently existing table with such name. */
2591e7342c1Srmind 		ot = npf_tableset_getbyname(ots, t->t_name);
2601e7342c1Srmind 		if (ot == NULL) {
2611e7342c1Srmind 			/* Not found: we have a new table. */
2621e7342c1Srmind 			continue;
2631e7342c1Srmind 		}
2641e7342c1Srmind 
2651e7342c1Srmind 		/* Found.  Did the type change? */
2661e7342c1Srmind 		if (t->t_type != ot->t_type) {
2671e7342c1Srmind 			/* Yes, load the new. */
26864647e51Srmind 			continue;
26964647e51Srmind 		}
2700e218254Srmind 
2710e218254Srmind 		/*
2721e7342c1Srmind 		 * Preserve the current table.  Acquire a reference since
2731e7342c1Srmind 		 * we are keeping it in the old table set.  Update its ID.
2740e218254Srmind 		 */
2750e218254Srmind 		atomic_inc_uint(&ot->t_refcnt);
2761e7342c1Srmind 		nts->ts_map[tid] = ot;
2770e218254Srmind 
278f75d79ebSchristos 		KASSERT(npf_config_locked_p(npf));
2791e7342c1Srmind 		ot->t_id = tid;
2801e7342c1Srmind 
281ffcdc4afSrmind 		/* Destroy the new table (we hold the only reference). */
2820e218254Srmind 		t->t_refcnt--;
28364647e51Srmind 		npf_table_destroy(t);
28464647e51Srmind 	}
28564647e51Srmind }
28664647e51Srmind 
2874f21ab88Srmind int
npf_tableset_export(npf_t * npf,const npf_tableset_t * ts,nvlist_t * nvl)288b899bfd9Srmind npf_tableset_export(npf_t *npf, const npf_tableset_t *ts, nvlist_t *nvl)
289805a41fbSrmind {
290805a41fbSrmind 	const npf_table_t *t;
291805a41fbSrmind 
292f75d79ebSchristos 	KASSERT(npf_config_locked_p(npf));
293805a41fbSrmind 
294805a41fbSrmind 	for (u_int tid = 0; tid < ts->ts_nitems; tid++) {
29539013e66Srmind 		nvlist_t *table;
29639013e66Srmind 
297805a41fbSrmind 		if ((t = ts->ts_map[tid]) == NULL) {
298805a41fbSrmind 			continue;
299805a41fbSrmind 		}
30039013e66Srmind 		table = nvlist_create(0);
30139013e66Srmind 		nvlist_add_string(table, "name", t->t_name);
30239013e66Srmind 		nvlist_add_number(table, "type", t->t_type);
30339013e66Srmind 		nvlist_add_number(table, "id", tid);
304805a41fbSrmind 
305b899bfd9Srmind 		nvlist_append_nvlist_array(nvl, "tables", table);
30639013e66Srmind 		nvlist_destroy(table);
307805a41fbSrmind 	}
3084f21ab88Srmind 	return 0;
309805a41fbSrmind }
310805a41fbSrmind 
31164647e51Srmind /*
312a3b239f6Srmind  * Few helper routines.
3132e6f2099Srmind  */
3142e6f2099Srmind 
315a3b239f6Srmind static void
table_ipset_flush(npf_table_t * t)3163d9a792dSrmind table_ipset_flush(npf_table_t *t)
317ce389782Srmind {
318ce389782Srmind 	npf_tblent_t *ent;
319ce389782Srmind 
3203d9a792dSrmind 	while ((ent = LIST_FIRST(&t->t_list)) != NULL) {
3213d9a792dSrmind 		thmap_del(t->t_map, &ent->te_addr, ent->te_alen);
3228f6d079fSchristos 		LIST_REMOVE(ent, te_listent);
323ce389782Srmind 		pool_cache_put(tblent_cache, ent);
324ce389782Srmind 	}
3253d9a792dSrmind 	t->t_nitems = 0;
326ce389782Srmind }
327ce389782Srmind 
328ce389782Srmind static void
table_tree_flush(npf_table_t * t)3298f6d079fSchristos table_tree_flush(npf_table_t *t)
3302e6f2099Srmind {
331a3b239f6Srmind 	npf_tblent_t *ent;
3322e6f2099Srmind 
3338f6d079fSchristos 	while ((ent = LIST_FIRST(&t->t_list)) != NULL) {
3348f6d079fSchristos 		LIST_REMOVE(ent, te_listent);
335a3b239f6Srmind 		pool_cache_put(tblent_cache, ent);
336a3b239f6Srmind 	}
3378f6d079fSchristos 	lpm_clear(t->t_lpm, NULL, NULL);
3383d9a792dSrmind 	t->t_nitems = 0;
3393d9a792dSrmind }
3403d9a792dSrmind 
3413d9a792dSrmind static void
table_ifaddr_flush(npf_table_t * t)3423d9a792dSrmind table_ifaddr_flush(npf_table_t *t)
3433d9a792dSrmind {
3443d9a792dSrmind 	npf_tblent_t *ent;
3453d9a792dSrmind 
3463d9a792dSrmind 	for (unsigned i = 0; i < NPF_ADDR_SLOTS; i++) {
3473d9a792dSrmind 		size_t len;
3483d9a792dSrmind 
3493d9a792dSrmind 		if (!t->t_allocated[i]) {
3503d9a792dSrmind 			KASSERT(t->t_elements[i] == NULL);
3513d9a792dSrmind 			continue;
3523d9a792dSrmind 		}
3533d9a792dSrmind 		len = t->t_allocated[i] * sizeof(npf_tblent_t *);
3543d9a792dSrmind 		kmem_free(t->t_elements[i], len);
3553d9a792dSrmind 		t->t_elements[i] = NULL;
3563d9a792dSrmind 		t->t_allocated[i] = 0;
3573d9a792dSrmind 		t->t_used[i] = 0;
3583d9a792dSrmind 	}
3593d9a792dSrmind 	while ((ent = LIST_FIRST(&t->t_list)) != NULL) {
3603d9a792dSrmind 		LIST_REMOVE(ent, te_listent);
3613d9a792dSrmind 		pool_cache_put(tblent_cache, ent);
3623d9a792dSrmind 	}
3633d9a792dSrmind 	t->t_nitems = 0;
3642e6f2099Srmind }
3652e6f2099Srmind 
3662e6f2099Srmind /*
3672e6f2099Srmind  * npf_table_create: create table with a specified ID.
3682e6f2099Srmind  */
3692e6f2099Srmind npf_table_t *
npf_table_create(const char * name,u_int tid,int type,const void * blob,size_t size)370ffcdc4afSrmind npf_table_create(const char *name, u_int tid, int type,
37139013e66Srmind     const void *blob, size_t size)
3722e6f2099Srmind {
3732e6f2099Srmind 	npf_table_t *t;
3742e6f2099Srmind 
375f75d79ebSchristos 	t = kmem_zalloc(sizeof(npf_table_t), KM_SLEEP);
3761e7342c1Srmind 	strlcpy(t->t_name, name, NPF_TABLE_MAXNAMELEN);
3771e7342c1Srmind 
3782e6f2099Srmind 	switch (type) {
3793d9a792dSrmind 	case NPF_TABLE_LPM:
380a80fb120Schristos 		t->t_lpm = lpm_create(KM_NOSLEEP);
3813d9a792dSrmind 		if (t->t_lpm == NULL) {
3828f6d079fSchristos 			goto out;
383f75d79ebSchristos 		}
3848f6d079fSchristos 		LIST_INIT(&t->t_list);
3852e6f2099Srmind 		break;
3863d9a792dSrmind 	case NPF_TABLE_IPSET:
3873d9a792dSrmind 		t->t_map = thmap_create(0, NULL, THMAP_NOCOPY);
3883d9a792dSrmind 		if (t->t_map == NULL) {
3898f6d079fSchristos 			goto out;
390f75d79ebSchristos 		}
3912e6f2099Srmind 		break;
3923d9a792dSrmind 	case NPF_TABLE_CONST:
39339013e66Srmind 		t->t_blob = kmem_alloc(size, KM_SLEEP);
39439013e66Srmind 		if (t->t_blob == NULL) {
39539013e66Srmind 			goto out;
39639013e66Srmind 		}
39739013e66Srmind 		memcpy(t->t_blob, blob, size);
398ffcdc4afSrmind 		t->t_bsize = size;
39939013e66Srmind 
40039013e66Srmind 		t->t_cdb = cdbr_open_mem(t->t_blob, size,
40139013e66Srmind 		    CDBR_DEFAULT, NULL, NULL);
402ffcdc4afSrmind 		if (t->t_cdb == NULL) {
40339013e66Srmind 			kmem_free(t->t_blob, t->t_bsize);
4048f6d079fSchristos 			goto out;
405ffcdc4afSrmind 		}
406ffcdc4afSrmind 		t->t_nitems = cdbr_entries(t->t_cdb);
407ffcdc4afSrmind 		break;
4083d9a792dSrmind 	case NPF_TABLE_IFADDR:
4093d9a792dSrmind 		break;
4102e6f2099Srmind 	default:
4112e6f2099Srmind 		KASSERT(false);
4122e6f2099Srmind 	}
413a80fb120Schristos 	mutex_init(&t->t_lock, MUTEX_DEFAULT, IPL_NET);
4142e6f2099Srmind 	t->t_type = type;
4152e6f2099Srmind 	t->t_id = tid;
4162e6f2099Srmind 	return t;
4178f6d079fSchristos out:
418f75d79ebSchristos 	kmem_free(t, sizeof(npf_table_t));
4198f6d079fSchristos 	return NULL;
4202e6f2099Srmind }
4212e6f2099Srmind 
4222e6f2099Srmind /*
4232e6f2099Srmind  * npf_table_destroy: free all table entries and table itself.
4242e6f2099Srmind  */
4252e6f2099Srmind void
npf_table_destroy(npf_table_t * t)4262e6f2099Srmind npf_table_destroy(npf_table_t *t)
4272e6f2099Srmind {
4280e218254Srmind 	KASSERT(t->t_refcnt == 0);
4292e6f2099Srmind 
4302e6f2099Srmind 	switch (t->t_type) {
4313d9a792dSrmind 	case NPF_TABLE_IPSET:
4323d9a792dSrmind 		table_ipset_flush(t);
4333d9a792dSrmind 		npf_table_gc(NULL, t);
4343d9a792dSrmind 		thmap_destroy(t->t_map);
4352e6f2099Srmind 		break;
4363d9a792dSrmind 	case NPF_TABLE_LPM:
4378f6d079fSchristos 		table_tree_flush(t);
4388f6d079fSchristos 		lpm_destroy(t->t_lpm);
4392e6f2099Srmind 		break;
4403d9a792dSrmind 	case NPF_TABLE_CONST:
441ffcdc4afSrmind 		cdbr_close(t->t_cdb);
44239013e66Srmind 		kmem_free(t->t_blob, t->t_bsize);
443ffcdc4afSrmind 		break;
4443d9a792dSrmind 	case NPF_TABLE_IFADDR:
4453d9a792dSrmind 		table_ifaddr_flush(t);
4463d9a792dSrmind 		break;
4472e6f2099Srmind 	default:
4482e6f2099Srmind 		KASSERT(false);
4492e6f2099Srmind 	}
45039013e66Srmind 	mutex_destroy(&t->t_lock);
451f75d79ebSchristos 	kmem_free(t, sizeof(npf_table_t));
4522e6f2099Srmind }
4532e6f2099Srmind 
4540b635e7cSrmind u_int
npf_table_getid(npf_table_t * t)4550b635e7cSrmind npf_table_getid(npf_table_t *t)
4560b635e7cSrmind {
4570b635e7cSrmind 	return t->t_id;
4580b635e7cSrmind }
4590b635e7cSrmind 
4602e6f2099Srmind /*
4611e7342c1Srmind  * npf_table_check: validate the name, ID and type.
462a3b239f6Srmind  */
4632e6f2099Srmind int
npf_table_check(npf_tableset_t * ts,const char * name,uint64_t tid,uint64_t type,bool replacing)4640e1944daSrmind npf_table_check(npf_tableset_t *ts, const char *name, uint64_t tid,
4650e1944daSrmind     uint64_t type, bool replacing)
4662e6f2099Srmind {
4670e1944daSrmind 	const npf_table_t *t;
4680e1944daSrmind 
46939013e66Srmind 	if (tid >= ts->ts_nitems) {
4702e6f2099Srmind 		return EINVAL;
4712e6f2099Srmind 	}
4720e1944daSrmind 	if (!replacing && ts->ts_map[tid] != NULL) {
4732e6f2099Srmind 		return EEXIST;
4742e6f2099Srmind 	}
475ffcdc4afSrmind 	switch (type) {
4763d9a792dSrmind 	case NPF_TABLE_LPM:
4773d9a792dSrmind 	case NPF_TABLE_IPSET:
4783d9a792dSrmind 	case NPF_TABLE_CONST:
4793d9a792dSrmind 	case NPF_TABLE_IFADDR:
480ffcdc4afSrmind 		break;
481ffcdc4afSrmind 	default:
4822e6f2099Srmind 		return EINVAL;
4832e6f2099Srmind 	}
4841e7342c1Srmind 	if (strlen(name) >= NPF_TABLE_MAXNAMELEN) {
4851e7342c1Srmind 		return ENAMETOOLONG;
4861e7342c1Srmind 	}
4870e1944daSrmind 	if ((t = npf_tableset_getbyname(ts, name)) != NULL) {
4880e1944daSrmind 		if (!replacing || t->t_id != tid) {
489805a41fbSrmind 			return EEXIST;
4901e7342c1Srmind 		}
4910e1944daSrmind 	}
4922e6f2099Srmind 	return 0;
4932e6f2099Srmind }
4942e6f2099Srmind 
495a3b239f6Srmind static int
table_ifaddr_insert(npf_table_t * t,const int alen,npf_tblent_t * ent)4963d9a792dSrmind table_ifaddr_insert(npf_table_t *t, const int alen, npf_tblent_t *ent)
4973d9a792dSrmind {
4983d9a792dSrmind 	const unsigned aidx = NPF_ADDRLEN2IDX(alen);
4993d9a792dSrmind 	const unsigned allocated = t->t_allocated[aidx];
5003d9a792dSrmind 	const unsigned used = t->t_used[aidx];
5013d9a792dSrmind 
5023d9a792dSrmind 	/*
5033d9a792dSrmind 	 * No need to check for duplicates.
5043d9a792dSrmind 	 */
5053d9a792dSrmind 	if (allocated <= used) {
5063d9a792dSrmind 		npf_tblent_t **old_elements = t->t_elements[aidx];
5073d9a792dSrmind 		npf_tblent_t **elements;
5083d9a792dSrmind 		size_t toalloc, newsize;
5093d9a792dSrmind 
5103d9a792dSrmind 		toalloc = roundup2(allocated + 1, NPF_IFADDR_STEP);
5113d9a792dSrmind 		newsize = toalloc * sizeof(npf_tblent_t *);
5123d9a792dSrmind 
513cd3ba776Schristos 		elements = kmem_zalloc(newsize, KM_NOSLEEP);
5145db0dcccSchristos 		if (elements == NULL) {
5155db0dcccSchristos 			return ENOMEM;
5165db0dcccSchristos 		}
5173d9a792dSrmind 		for (unsigned i = 0; i < used; i++) {
5183d9a792dSrmind 			elements[i] = old_elements[i];
5193d9a792dSrmind 		}
5203d9a792dSrmind 		if (allocated) {
5213d9a792dSrmind 			const size_t len = allocated * sizeof(npf_tblent_t *);
5223d9a792dSrmind 			KASSERT(old_elements != NULL);
5233d9a792dSrmind 			kmem_free(old_elements, len);
5243d9a792dSrmind 		}
5253d9a792dSrmind 		t->t_elements[aidx] = elements;
5263d9a792dSrmind 		t->t_allocated[aidx] = toalloc;
5273d9a792dSrmind 	}
5283d9a792dSrmind 	t->t_elements[aidx][used] = ent;
5293d9a792dSrmind 	t->t_used[aidx]++;
5305db0dcccSchristos 	return 0;
5313d9a792dSrmind }
5323d9a792dSrmind 
533a3b239f6Srmind /*
534a3b239f6Srmind  * npf_table_insert: add an IP CIDR entry into the table.
535a3b239f6Srmind  */
536a3b239f6Srmind int
npf_table_insert(npf_table_t * t,const int alen,const npf_addr_t * addr,const npf_netmask_t mask)5371e7342c1Srmind npf_table_insert(npf_table_t *t, const int alen,
538a3b239f6Srmind     const npf_addr_t *addr, const npf_netmask_t mask)
539a3b239f6Srmind {
540a3b239f6Srmind 	npf_tblent_t *ent;
541a3b239f6Srmind 	int error;
542a3b239f6Srmind 
543dadc88e3Srmind 	error = npf_netmask_check(alen, mask);
544a3b239f6Srmind 	if (error) {
545a3b239f6Srmind 		return error;
546a3b239f6Srmind 	}
54733b678d7Srmind 	ent = pool_cache_get(tblent_cache, PR_WAITOK);
548a3b239f6Srmind 	memcpy(&ent->te_addr, addr, alen);
549a3b239f6Srmind 	ent->te_alen = alen;
5503d9a792dSrmind 	ent->te_preflen = 0;
5512e6f2099Srmind 
552a3b239f6Srmind 	/*
553a3b239f6Srmind 	 * Insert the entry.  Return an error on duplicate.
554a3b239f6Srmind 	 */
55539013e66Srmind 	mutex_enter(&t->t_lock);
5562e6f2099Srmind 	switch (t->t_type) {
5573d9a792dSrmind 	case NPF_TABLE_IPSET:
558a3b239f6Srmind 		/*
5593d9a792dSrmind 		 * Hashmap supports only IPs.
5603d9a792dSrmind 		 *
5613d9a792dSrmind 		 * Note: the key must be already persistent, since we
5623d9a792dSrmind 		 * use THMAP_NOCOPY.
563a3b239f6Srmind 		 */
564a3b239f6Srmind 		if (mask != NPF_NO_NETMASK) {
565a3b239f6Srmind 			error = EINVAL;
56609cdfd6aSrmind 			break;
5675a5d868dSzoltan 		}
5683d9a792dSrmind 		if (thmap_put(t->t_map, &ent->te_addr, alen, ent) == ent) {
5693d9a792dSrmind 			LIST_INSERT_HEAD(&t->t_list, ent, te_listent);
57064647e51Srmind 			t->t_nitems++;
5712e6f2099Srmind 		} else {
5722e6f2099Srmind 			error = EEXIST;
5732e6f2099Srmind 		}
5742e6f2099Srmind 		break;
5753d9a792dSrmind 	case NPF_TABLE_LPM: {
5768f6d079fSchristos 		const unsigned preflen =
5778f6d079fSchristos 		    (mask == NPF_NO_NETMASK) ? (alen * 8) : mask;
5783d9a792dSrmind 		ent->te_preflen = preflen;
5793d9a792dSrmind 
5808f6d079fSchristos 		if (lpm_lookup(t->t_lpm, addr, alen) == NULL &&
5818f6d079fSchristos 		    lpm_insert(t->t_lpm, addr, alen, preflen, ent) == 0) {
5828f6d079fSchristos 			LIST_INSERT_HEAD(&t->t_list, ent, te_listent);
58364647e51Srmind 			t->t_nitems++;
58464647e51Srmind 			error = 0;
585a3b239f6Srmind 		} else {
58664647e51Srmind 			error = EEXIST;
587a3b239f6Srmind 		}
5882e6f2099Srmind 		break;
589a3b239f6Srmind 	}
5903d9a792dSrmind 	case NPF_TABLE_CONST:
591ffcdc4afSrmind 		error = EINVAL;
592ffcdc4afSrmind 		break;
5933d9a792dSrmind 	case NPF_TABLE_IFADDR:
5945db0dcccSchristos 		if ((error = table_ifaddr_insert(t, alen, ent)) != 0) {
5955db0dcccSchristos 			break;
5965db0dcccSchristos 		}
5973d9a792dSrmind 		LIST_INSERT_HEAD(&t->t_list, ent, te_listent);
5983d9a792dSrmind 		t->t_nitems++;
5993d9a792dSrmind 		break;
6002e6f2099Srmind 	default:
6012e6f2099Srmind 		KASSERT(false);
6022e6f2099Srmind 	}
60339013e66Srmind 	mutex_exit(&t->t_lock);
6042e6f2099Srmind 
605fad8b2d7Srmind 	if (error) {
60633b678d7Srmind 		pool_cache_put(tblent_cache, ent);
6072e6f2099Srmind 	}
6082e6f2099Srmind 	return error;
6092e6f2099Srmind }
6102e6f2099Srmind 
6112e6f2099Srmind /*
612a3b239f6Srmind  * npf_table_remove: remove the IP CIDR entry from the table.
6132e6f2099Srmind  */
6142e6f2099Srmind int
npf_table_remove(npf_table_t * t,const int alen,const npf_addr_t * addr,const npf_netmask_t mask)6151e7342c1Srmind npf_table_remove(npf_table_t *t, const int alen,
6165a5d868dSzoltan     const npf_addr_t *addr, const npf_netmask_t mask)
6172e6f2099Srmind {
618ffcdc4afSrmind 	npf_tblent_t *ent = NULL;
6193d9a792dSrmind 	int error;
6202e6f2099Srmind 
621dadc88e3Srmind 	error = npf_netmask_check(alen, mask);
622a3b239f6Srmind 	if (error) {
623a3b239f6Srmind 		return error;
624fad8b2d7Srmind 	}
62564647e51Srmind 
62639013e66Srmind 	mutex_enter(&t->t_lock);
6272e6f2099Srmind 	switch (t->t_type) {
6283d9a792dSrmind 	case NPF_TABLE_IPSET:
6293d9a792dSrmind 		ent = thmap_del(t->t_map, addr, alen);
63033b678d7Srmind 		if (__predict_true(ent != NULL)) {
6318f6d079fSchristos 			LIST_REMOVE(ent, te_listent);
6323d9a792dSrmind 			LIST_INSERT_HEAD(&t->t_gc, ent, te_listent);
6333d9a792dSrmind 			ent = NULL; // to be G/C'ed
63464647e51Srmind 			t->t_nitems--;
6353d9a792dSrmind 		} else {
6363d9a792dSrmind 			error = ENOENT;
6372e6f2099Srmind 		}
6382e6f2099Srmind 		break;
6393d9a792dSrmind 	case NPF_TABLE_LPM:
6408f6d079fSchristos 		ent = lpm_lookup(t->t_lpm, addr, alen);
64133b678d7Srmind 		if (__predict_true(ent != NULL)) {
6428f6d079fSchristos 			LIST_REMOVE(ent, te_listent);
6438f6d079fSchristos 			lpm_remove(t->t_lpm, &ent->te_addr,
6448f6d079fSchristos 			    ent->te_alen, ent->te_preflen);
64564647e51Srmind 			t->t_nitems--;
6463d9a792dSrmind 		} else {
6473d9a792dSrmind 			error = ENOENT;
6482e6f2099Srmind 		}
6492e6f2099Srmind 		break;
6503d9a792dSrmind 	case NPF_TABLE_CONST:
6513d9a792dSrmind 	case NPF_TABLE_IFADDR:
652ffcdc4afSrmind 		error = EINVAL;
653ffcdc4afSrmind 		break;
6542e6f2099Srmind 	default:
6552e6f2099Srmind 		KASSERT(false);
656a3b239f6Srmind 		ent = NULL;
6572e6f2099Srmind 	}
65839013e66Srmind 	mutex_exit(&t->t_lock);
6592e6f2099Srmind 
660ffcdc4afSrmind 	if (ent) {
66133b678d7Srmind 		pool_cache_put(tblent_cache, ent);
662ffcdc4afSrmind 	}
663ffcdc4afSrmind 	return error;
6642e6f2099Srmind }
6652e6f2099Srmind 
6662e6f2099Srmind /*
667a3b239f6Srmind  * npf_table_lookup: find the table according to ID, lookup and match
668a3b239f6Srmind  * the contents with the specified IP address.
6692e6f2099Srmind  */
6702e6f2099Srmind int
npf_table_lookup(npf_table_t * t,const int alen,const npf_addr_t * addr)6711e7342c1Srmind npf_table_lookup(npf_table_t *t, const int alen, const npf_addr_t *addr)
6722e6f2099Srmind {
673ffcdc4afSrmind 	const void *data;
674ffcdc4afSrmind 	size_t dlen;
675ffcdc4afSrmind 	bool found;
6763d9a792dSrmind 	int error;
6772e6f2099Srmind 
678dadc88e3Srmind 	error = npf_netmask_check(alen, NPF_NO_NETMASK);
6793d9a792dSrmind 	if (error) {
6803d9a792dSrmind 		return error;
681a3b239f6Srmind 	}
682a3b239f6Srmind 
6832e6f2099Srmind 	switch (t->t_type) {
6843d9a792dSrmind 	case NPF_TABLE_IPSET:
685b899bfd9Srmind 		/* Note: the caller is in the npf_config_read_enter(). */
6863d9a792dSrmind 		found = thmap_get(t->t_map, addr, alen) != NULL;
6872e6f2099Srmind 		break;
6883d9a792dSrmind 	case NPF_TABLE_LPM:
68939013e66Srmind 		mutex_enter(&t->t_lock);
6908f6d079fSchristos 		found = lpm_lookup(t->t_lpm, addr, alen) != NULL;
69139013e66Srmind 		mutex_exit(&t->t_lock);
692a3b239f6Srmind 		break;
6933d9a792dSrmind 	case NPF_TABLE_CONST:
694ffcdc4afSrmind 		if (cdbr_find(t->t_cdb, addr, alen, &data, &dlen) == 0) {
6953d9a792dSrmind 			found = dlen == (unsigned)alen &&
696f75d79ebSchristos 			    memcmp(addr, data, dlen) == 0;
697ffcdc4afSrmind 		} else {
698ffcdc4afSrmind 			found = false;
69933b678d7Srmind 		}
700ffcdc4afSrmind 		break;
7013d9a792dSrmind 	case NPF_TABLE_IFADDR: {
7023d9a792dSrmind 		const unsigned aidx = NPF_ADDRLEN2IDX(alen);
7033d9a792dSrmind 
7043d9a792dSrmind 		found = false;
7053d9a792dSrmind 		for (unsigned i = 0; i < t->t_used[aidx]; i++) {
7063d9a792dSrmind 			const npf_tblent_t *elm = t->t_elements[aidx][i];
7073d9a792dSrmind 
7083d9a792dSrmind 			KASSERT(elm->te_alen == alen);
7093d9a792dSrmind 
7103d9a792dSrmind 			if (memcmp(&elm->te_addr, addr, alen) == 0) {
7113d9a792dSrmind 				found = true;
7123d9a792dSrmind 				break;
7133d9a792dSrmind 			}
7143d9a792dSrmind 		}
7153d9a792dSrmind 		break;
7163d9a792dSrmind 	}
7172e6f2099Srmind 	default:
7182e6f2099Srmind 		KASSERT(false);
719ffcdc4afSrmind 		found = false;
7202e6f2099Srmind 	}
7212e6f2099Srmind 
722ffcdc4afSrmind 	return found ? 0 : ENOENT;
7232e6f2099Srmind }
72464647e51Srmind 
7253d9a792dSrmind npf_addr_t *
npf_table_getsome(npf_table_t * t,const int alen,unsigned idx)7263d9a792dSrmind npf_table_getsome(npf_table_t *t, const int alen, unsigned idx)
7273d9a792dSrmind {
7283d9a792dSrmind 	const unsigned aidx = NPF_ADDRLEN2IDX(alen);
7293d9a792dSrmind 	npf_tblent_t *elm;
7303d9a792dSrmind 	unsigned nitems;
7313d9a792dSrmind 
7323d9a792dSrmind 	KASSERT(t->t_type == NPF_TABLE_IFADDR);
7333d9a792dSrmind 	KASSERT(aidx < NPF_ADDR_SLOTS);
7343d9a792dSrmind 
7353d9a792dSrmind 	nitems = t->t_used[aidx];
7363d9a792dSrmind 	if (nitems == 0) {
7373d9a792dSrmind 		return NULL;
7383d9a792dSrmind 	}
7393d9a792dSrmind 
7403d9a792dSrmind 	/*
7413d9a792dSrmind 	 * No need to acquire the lock, since the table is immutable.
7423d9a792dSrmind 	 */
7433d9a792dSrmind 	elm = t->t_elements[aidx][idx % nitems];
7443d9a792dSrmind 	return &elm->te_addr;
7453d9a792dSrmind }
7463d9a792dSrmind 
74764647e51Srmind static int
table_ent_copyout(const npf_addr_t * addr,const int alen,npf_netmask_t mask,void * ubuf,size_t len,size_t * off)748ffcdc4afSrmind table_ent_copyout(const npf_addr_t *addr, const int alen, npf_netmask_t mask,
74964647e51Srmind     void *ubuf, size_t len, size_t *off)
75064647e51Srmind {
75164647e51Srmind 	void *ubufp = (uint8_t *)ubuf + *off;
75264647e51Srmind 	npf_ioctl_ent_t uent;
75364647e51Srmind 
75464647e51Srmind 	if ((*off += sizeof(npf_ioctl_ent_t)) > len) {
75564647e51Srmind 		return ENOMEM;
75664647e51Srmind 	}
757ffcdc4afSrmind 	uent.alen = alen;
758ffcdc4afSrmind 	memcpy(&uent.addr, addr, sizeof(npf_addr_t));
75964647e51Srmind 	uent.mask = mask;
76064647e51Srmind 
76164647e51Srmind 	return copyout(&uent, ubufp, sizeof(npf_ioctl_ent_t));
76264647e51Srmind }
76364647e51Srmind 
76464647e51Srmind static int
table_generic_list(npf_table_t * t,void * ubuf,size_t len)7652f9d5bcdSriastradh table_generic_list(npf_table_t *t, void *ubuf, size_t len)
76664647e51Srmind {
7678f6d079fSchristos 	npf_tblent_t *ent;
7688f6d079fSchristos 	size_t off = 0;
76964647e51Srmind 	int error = 0;
77064647e51Srmind 
7718f6d079fSchristos 	LIST_FOREACH(ent, &t->t_list, te_listent) {
7722f9d5bcdSriastradh 		mutex_exit(&t->t_lock);
7738f6d079fSchristos 		error = table_ent_copyout(&ent->te_addr,
7743d9a792dSrmind 		    ent->te_alen, ent->te_preflen, ubuf, len, &off);
7752f9d5bcdSriastradh 		mutex_enter(&t->t_lock);
776ffcdc4afSrmind 		if (error)
777ffcdc4afSrmind 			break;
778ffcdc4afSrmind 	}
779ffcdc4afSrmind 	return error;
780ffcdc4afSrmind }
781ffcdc4afSrmind 
782ffcdc4afSrmind static int
table_cdb_list(npf_table_t * t,void * ubuf,size_t len)783ffcdc4afSrmind table_cdb_list(npf_table_t *t, void *ubuf, size_t len)
784ffcdc4afSrmind {
785ffcdc4afSrmind 	size_t off = 0, dlen;
786ffcdc4afSrmind 	const void *data;
787ffcdc4afSrmind 	int error = 0;
788ffcdc4afSrmind 
789ffcdc4afSrmind 	for (size_t i = 0; i < t->t_nitems; i++) {
790ffcdc4afSrmind 		if (cdbr_get(t->t_cdb, i, &data, &dlen) != 0) {
791ffcdc4afSrmind 			return EINVAL;
792ffcdc4afSrmind 		}
793ffcdc4afSrmind 		error = table_ent_copyout(data, dlen, 0, ubuf, len, &off);
79464647e51Srmind 		if (error)
79564647e51Srmind 			break;
79664647e51Srmind 	}
79764647e51Srmind 	return error;
79864647e51Srmind }
79964647e51Srmind 
80064647e51Srmind /*
80164647e51Srmind  * npf_table_list: copy a list of all table entries into a userspace buffer.
80264647e51Srmind  */
80364647e51Srmind int
npf_table_list(npf_table_t * t,void * ubuf,size_t len)8041e7342c1Srmind npf_table_list(npf_table_t *t, void *ubuf, size_t len)
80564647e51Srmind {
80664647e51Srmind 	int error = 0;
80764647e51Srmind 
80839013e66Srmind 	mutex_enter(&t->t_lock);
80964647e51Srmind 	switch (t->t_type) {
8103d9a792dSrmind 	case NPF_TABLE_IPSET:
8113d9a792dSrmind 		error = table_generic_list(t, ubuf, len);
81264647e51Srmind 		break;
8133d9a792dSrmind 	case NPF_TABLE_LPM:
8143d9a792dSrmind 		error = table_generic_list(t, ubuf, len);
81564647e51Srmind 		break;
8163d9a792dSrmind 	case NPF_TABLE_CONST:
817ffcdc4afSrmind 		error = table_cdb_list(t, ubuf, len);
818ffcdc4afSrmind 		break;
8193d9a792dSrmind 	case NPF_TABLE_IFADDR:
8203d9a792dSrmind 		error = table_generic_list(t, ubuf, len);
8213d9a792dSrmind 		break;
82264647e51Srmind 	default:
82364647e51Srmind 		KASSERT(false);
82464647e51Srmind 	}
82539013e66Srmind 	mutex_exit(&t->t_lock);
82664647e51Srmind 
82764647e51Srmind 	return error;
82864647e51Srmind }
829ce389782Srmind 
830ce389782Srmind /*
831ce389782Srmind  * npf_table_flush: remove all table entries.
832ce389782Srmind  */
833ce389782Srmind int
npf_table_flush(npf_table_t * t)8341e7342c1Srmind npf_table_flush(npf_table_t *t)
835ce389782Srmind {
836ffcdc4afSrmind 	int error = 0;
837ffcdc4afSrmind 
83839013e66Srmind 	mutex_enter(&t->t_lock);
839ce389782Srmind 	switch (t->t_type) {
8403d9a792dSrmind 	case NPF_TABLE_IPSET:
8413d9a792dSrmind 		table_ipset_flush(t);
842ce389782Srmind 		break;
8433d9a792dSrmind 	case NPF_TABLE_LPM:
8448f6d079fSchristos 		table_tree_flush(t);
845ce389782Srmind 		break;
8463d9a792dSrmind 	case NPF_TABLE_CONST:
8473d9a792dSrmind 	case NPF_TABLE_IFADDR:
848ffcdc4afSrmind 		error = EINVAL;
849ffcdc4afSrmind 		break;
850ce389782Srmind 	default:
851ce389782Srmind 		KASSERT(false);
852ce389782Srmind 	}
85339013e66Srmind 	mutex_exit(&t->t_lock);
854ffcdc4afSrmind 	return error;
855ce389782Srmind }
8563d9a792dSrmind 
8573d9a792dSrmind void
npf_table_gc(npf_t * npf,npf_table_t * t)8583d9a792dSrmind npf_table_gc(npf_t *npf, npf_table_t *t)
8593d9a792dSrmind {
8603d9a792dSrmind 	npf_tblent_t *ent;
8613d9a792dSrmind 	void *ref;
8623d9a792dSrmind 
8633d9a792dSrmind 	if (t->t_type != NPF_TABLE_IPSET || LIST_EMPTY(&t->t_gc)) {
8643d9a792dSrmind 		return;
8653d9a792dSrmind 	}
8663d9a792dSrmind 
8673d9a792dSrmind 	ref = thmap_stage_gc(t->t_map);
8683d9a792dSrmind 	if (npf) {
8693d9a792dSrmind 		npf_config_locked_p(npf);
8703d9a792dSrmind 		npf_config_sync(npf);
8713d9a792dSrmind 	}
8723d9a792dSrmind 	thmap_gc(t->t_map, ref);
8733d9a792dSrmind 
8743d9a792dSrmind 	while ((ent = LIST_FIRST(&t->t_gc)) != NULL) {
8753d9a792dSrmind 		LIST_REMOVE(ent, te_listent);
8763d9a792dSrmind 		pool_cache_put(tblent_cache, ent);
8773d9a792dSrmind 	}
8783d9a792dSrmind }
879