Module Name:    src
Committed By:   rmind
Date:           Wed Aug 21 21:45:47 UTC 2019

Modified Files:
        src/lib/libnpf: libnpf.3 npf.c npf.h
        src/sys/net/npf: npf.h npf_ctl.c npf_impl.h npf_os.c npf_tableset.c

Log Message:
npfkern/libnpf: Add support for the table replace/swap operation.
Contributed by Timshel Knoll-Miller.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/lib/libnpf/libnpf.3
cvs rdiff -u -r1.46 -r1.47 src/lib/libnpf/npf.c
cvs rdiff -u -r1.36 -r1.37 src/lib/libnpf/npf.h
cvs rdiff -u -r1.60 -r1.61 src/sys/net/npf/npf.h
cvs rdiff -u -r1.55 -r1.56 src/sys/net/npf/npf_ctl.c
cvs rdiff -u -r1.76 -r1.77 src/sys/net/npf/npf_impl.h
cvs rdiff -u -r1.14 -r1.15 src/sys/net/npf/npf_os.c
cvs rdiff -u -r1.33 -r1.34 src/sys/net/npf/npf_tableset.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libnpf/libnpf.3
diff -u src/lib/libnpf/libnpf.3:1.9 src/lib/libnpf/libnpf.3:1.10
--- src/lib/libnpf/libnpf.3:1.9	Tue Jul 23 14:18:20 2019
+++ src/lib/libnpf/libnpf.3	Wed Aug 21 21:45:47 2019
@@ -1,4 +1,4 @@
-.\"	$NetBSD: libnpf.3,v 1.9 2019/07/23 14:18:20 wiz Exp $
+.\"	$NetBSD: libnpf.3,v 1.10 2019/08/21 21:45:47 rmind Exp $
 .\"
 .\" Copyright (c) 2011-2019 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 April 14, 2019
+.Dd August 21, 2019
 .Dt LIBNPF 3
 .Os
 .Sh NAME
@@ -41,7 +41,7 @@
 .Ft nl_config_t *
 .Fn npf_config_create "void"
 .Ft int
-.Fn npf_config_submit "nl_config_t *ncf" "int fd" "nl_error_t *errinfo"
+.Fn npf_config_submit "nl_config_t *ncf" "int fd" "npf_error_t *errinfo"
 .Ft nl_config_t *
 .Fn npf_config_retrieve "int fd"
 .Ft int
@@ -104,6 +104,8 @@
 "const npf_addr_t *addr" "const npf_netmask_t mask"
 .Ft int
 .Fn npf_table_insert "nl_config_t *ncf" "nl_table_t *tl"
+.Ft int
+.Fn npf_table_replace "int fd" "nl_table_t *tl" "npf_error_t *errinfo"
 .Ft void
 .Fn npf_table_destroy "nl_table_t *tl"
 .\" -----
@@ -347,7 +349,9 @@ for IPv4 or
 for IPv6 address.
 Additionally,
 .Fa mask
-may be specified to indicate the translation network.
+may be specified to indicate the translation network;
+otherwise, it should be set to
+.Dv NPF_NO_NETMASK .
 In such case, a custom algorithm may need to be specified using the
 .Fn npf_nat_setalgo
 function.
@@ -423,11 +427,25 @@ must be either
 for IPv4 or
 .Dv AF_INET6
 for IPv6 address.
+If there is no mask, then
+.Fa mask
+should be set to
+.Dv NPF_NO_NETMASK .
+.\" ---
 .It Fn npf_table_insert "ncf" "tl"
 Add the table to the configuration object.
 This routine performs a check for duplicate table IDs.
 The table must not be referenced after insertion.
 .\" ---
+.It Fn npf_table_replace "fd" "tl" "errinfo"
+Submit the table object, specified by
+.Fa tl ,
+to the kernel, to replace the existing table with the
+corresponding table name and ID.
+On failure, the error information is written into the structure
+specified by
+.Fa errinfo .
+.\" ---
 .It Fn npf_table_destroy "tl"
 Destroy the specified table.
 .El

Index: src/lib/libnpf/npf.c
diff -u src/lib/libnpf/npf.c:1.46 src/lib/libnpf/npf.c:1.47
--- src/lib/libnpf/npf.c:1.46	Tue Jul 23 00:52:01 2019
+++ src/lib/libnpf/npf.c	Wed Aug 21 21:45:47 2019
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.46 2019/07/23 00:52:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.47 2019/08/21 21:45:47 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/mman.h>
@@ -203,6 +203,30 @@ _npf_rules_process(nl_config_t *ncf, nvl
 }
 
 /*
+ * _npf_extract_error: check the error number field and extract the
+ * error details into the npf_error_t structure.
+ */
+static int
+_npf_extract_error(nvlist_t *resp, npf_error_t *errinfo)
+{
+	int error;
+
+	error = dnvlist_get_number(resp, "errno", 0);
+	if (error && errinfo) {
+		memset(errinfo, 0, sizeof(npf_error_t));
+
+		errinfo->id = dnvlist_get_number(resp, "id", 0);
+		errinfo->error_msg =
+		    dnvlist_take_string(resp, "error-msg", NULL);
+		errinfo->source_file =
+		    dnvlist_take_string(resp, "source-file", NULL);
+		errinfo->source_line =
+		    dnvlist_take_number(resp, "source-line", 0);
+	}
+	return error;
+}
+
+/*
  * CONFIGURATION INTERFACE.
  */
 
@@ -233,17 +257,7 @@ npf_config_submit(nl_config_t *ncf, int 
 		assert(errnv == NULL);
 		return errno;
 	}
-	error = dnvlist_get_number(errnv, "errno", 0);
-	if (error && errinfo) {
-		memset(errinfo, 0, sizeof(npf_error_t));
-		errinfo->id = dnvlist_get_number(errnv, "id", 0);
-		errinfo->error_msg =
-		    dnvlist_take_string(errnv, "error-msg", NULL);
-		errinfo->source_file =
-		    dnvlist_take_string(errnv, "source-file", NULL);
-		errinfo->source_line =
-		    dnvlist_take_number(errnv, "source-line", 0);
-	}
+	error = _npf_extract_error(errnv, errinfo);
 	nvlist_destroy(errnv);
 	return error;
 }
@@ -949,7 +963,7 @@ npf_table_add_entry(nl_table_t *tl, int 
 }
 
 static inline int
-_npf_table_build(nl_table_t *tl)
+_npf_table_build_const(nl_table_t *tl)
 {
 	struct cdbw *cdbw;
 	const nvlist_t * const *entries;
@@ -959,6 +973,10 @@ _npf_table_build(nl_table_t *tl)
 	struct stat sb;
 	char sfn[32];
 
+	if (dnvlist_get_number(tl->table_dict, "type", 0) != NPF_TABLE_CONST) {
+		return 0;
+	}
+
 	if (!nvlist_exists_nvlist_array(tl->table_dict, "entries")) {
 		return 0;
 	}
@@ -1050,10 +1068,8 @@ npf_table_insert(nl_config_t *ncf, nl_ta
 	if (_npf_dataset_lookup(ncf->ncf_dict, "tables", "name", name)) {
 		return EEXIST;
 	}
-	if (dnvlist_get_number(tl->table_dict, "type", 0) == NPF_TABLE_CONST) {
-		if ((error = _npf_table_build(tl)) != 0) {
-			return error;
-		}
+	if ((error = _npf_table_build_const(tl)) != 0) {
+		return error;
 	}
 	nvlist_append_nvlist_array(ncf->ncf_dict, "tables", tl->table_dict);
 	nvlist_destroy(tl->table_dict);
@@ -1061,6 +1077,27 @@ npf_table_insert(nl_config_t *ncf, nl_ta
 	return 0;
 }
 
+int
+npf_table_replace(int fd, nl_table_t *tl, npf_error_t *errinfo)
+{
+	nvlist_t *errnv = NULL;
+	int error;
+
+	/* Ensure const tables are built. */
+	if ((error = _npf_table_build_const(tl)) != 0) {
+		return error;
+	}
+
+	if (nvlist_xfer_ioctl(fd, IOC_NPF_TABLE_REPLACE,
+	    tl->table_dict, &errnv) == -1) {
+		assert(errnv == NULL);
+		return errno;
+	}
+	error = _npf_extract_error(errnv, errinfo);
+	nvlist_destroy(errnv);
+	return error;
+}
+
 nl_table_t *
 npf_table_iterate(nl_config_t *ncf, nl_iter_t *iter)
 {

Index: src/lib/libnpf/npf.h
diff -u src/lib/libnpf/npf.h:1.36 src/lib/libnpf/npf.h:1.37
--- src/lib/libnpf/npf.h:1.36	Tue Jul 23 00:52:01 2019
+++ src/lib/libnpf/npf.h	Wed Aug 21 21:45:47 2019
@@ -146,6 +146,8 @@ int		npf_table_add_entry(nl_table_t *, i
 int		npf_table_insert(nl_config_t *, nl_table_t *);
 void		npf_table_destroy(nl_table_t *);
 
+int		npf_table_replace(int, nl_table_t *, npf_error_t *);
+
 #ifdef _NPF_PRIVATE
 
 #include <ifaddrs.h>

Index: src/sys/net/npf/npf.h
diff -u src/sys/net/npf/npf.h:1.60 src/sys/net/npf/npf.h:1.61
--- src/sys/net/npf/npf.h:1.60	Tue Jul 23 00:52:01 2019
+++ src/sys/net/npf/npf.h	Wed Aug 21 21:45:47 2019
@@ -310,6 +310,7 @@ typedef struct npf_ioctl_table {
 #define	IOC_NPF_SAVE		_IOR('N', 105, nvlist_ref_t)
 #define	IOC_NPF_RULE		_IOWR('N', 107, nvlist_ref_t)
 #define	IOC_NPF_CONN_LOOKUP	_IOWR('N', 108, nvlist_ref_t)
+#define	IOC_NPF_TABLE_REPLACE	_IOWR('N', 109, nvlist_ref_t)
 
 /*
  * NPF error report.

Index: src/sys/net/npf/npf_ctl.c
diff -u src/sys/net/npf/npf_ctl.c:1.55 src/sys/net/npf/npf_ctl.c:1.56
--- src/sys/net/npf/npf_ctl.c:1.55	Sun Aug 11 20:26:33 2019
+++ src/sys/net/npf/npf_ctl.c	Wed Aug 21 21:45:47 2019
@@ -36,7 +36,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.55 2019/08/11 20:26:33 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.56 2019/08/21 21:45:47 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -178,6 +178,63 @@ npf_mk_table_entries(npf_table_t *t, con
 	return error;
 }
 
+/*
+ * npf_mk_table: create a table from provided nvlist.
+ */
+static int __noinline
+npf_mk_table(npf_t *npf, const nvlist_t *tbl_dict, nvlist_t *errdict,
+    npf_tableset_t *tblset, npf_table_t **tblp, bool replacing)
+{
+	npf_table_t *t;
+	const char *name;
+	const void *blob;
+	uint64_t tid;
+	size_t size;
+	int type;
+	int error = 0;
+
+	KASSERT(tblp != NULL);
+
+	/* Table name, ID and type.  Validate them. */
+	name = dnvlist_get_string(tbl_dict, "name", NULL);
+	if (!name) {
+		NPF_ERR_DEBUG(errdict);
+		error = EINVAL;
+		goto out;
+	}
+	tid = dnvlist_get_number(tbl_dict, "id", UINT64_MAX);
+	type = dnvlist_get_number(tbl_dict, "type", UINT64_MAX);
+	error = npf_table_check(tblset, name, tid, type, replacing);
+	if (error) {
+		NPF_ERR_DEBUG(errdict);
+		goto out;
+	}
+
+	/* Get the entries or binary data. */
+	blob = dnvlist_get_binary(tbl_dict, "data", &size, NULL, 0);
+	if (type == NPF_TABLE_CONST && (blob == NULL || size == 0)) {
+		NPF_ERR_DEBUG(errdict);
+		error = EINVAL;
+		goto out;
+	}
+
+	t = npf_table_create(name, (u_int)tid, type, blob, size);
+	if (t == NULL) {
+		NPF_ERR_DEBUG(errdict);
+		error = ENOMEM;
+		goto out;
+	}
+
+	if ((error = npf_mk_table_entries(t, tbl_dict, errdict)) != 0) {
+		npf_table_destroy(t);
+		goto out;
+	}
+
+	*tblp = t;
+out:
+	return error;
+}
+
 static int __noinline
 npf_mk_tables(npf_t *npf, nvlist_t *npf_dict, nvlist_t *errdict,
     npf_tableset_t **tblsetp)
@@ -200,49 +257,15 @@ npf_mk_tables(npf_t *npf, nvlist_t *npf_
 	tblset = npf_tableset_create(nitems);
 	for (unsigned i = 0; i < nitems; i++) {
 		const nvlist_t *table = tables[i];
-		const char *name;
-		const void *blob;
 		npf_table_t *t;
-		uint64_t tid;
-		size_t size;
-		int type;
 
-		/* Table name, ID and type.  Validate them. */
-		name = dnvlist_get_string(table, "name", NULL);
-		if (!name) {
-			NPF_ERR_DEBUG(errdict);
-			error = EINVAL;
-			break;
-		}
-		tid = dnvlist_get_number(table, "id", UINT64_MAX);
-		type = dnvlist_get_number(table, "type", UINT64_MAX);
-		error = npf_table_check(tblset, name, tid, type);
+		error = npf_mk_table(npf, table, errdict, tblset, &t, 0);
 		if (error) {
-			NPF_ERR_DEBUG(errdict);
-			break;
-		}
-
-		/* Get the entries or binary data. */
-		blob = dnvlist_get_binary(table, "data", &size, NULL, 0);
-		if (type == NPF_TABLE_CONST && (blob == NULL || size == 0)) {
-			NPF_ERR_DEBUG(errdict);
-			error = EINVAL;
 			break;
 		}
 
-		/* Create and insert the table. */
-		t = npf_table_create(name, (u_int)tid, type, blob, size);
-		if (t == NULL) {
-			NPF_ERR_DEBUG(errdict);
-			error = ENOMEM;
-			break;
-		}
 		error = npf_tableset_insert(tblset, t);
 		KASSERT(error == 0);
-
-		if ((error = npf_mk_table_entries(t, table, errdict)) != 0) {
-			break;
-		}
 	}
 	*tblsetp = tblset;
 	return error;
@@ -733,6 +756,63 @@ out:
 }
 
 /*
+ * npfctl_table_replace_nvlist: atomically replace a table's contents
+ * with the passed table data.
+ */
+static int __noinline
+npfctl_table_replace_nvlist(npf_t *npf, nvlist_t *npf_dict, nvlist_t *errdict)
+{
+	npf_table_t *tbl, *gc_tbl = NULL;
+	npf_tableset_t *tblset;
+	int error = 0;
+
+	npf_config_enter(npf);
+	tblset = npf_config_tableset(npf);
+
+	/* Get the entries or binary data. */
+	error = npf_mk_table(npf, npf_dict, errdict, tblset, &tbl, true);
+	if (error) {
+		goto err;
+	}
+
+	gc_tbl = npf_tableset_swap(tblset, tbl);
+	if (gc_tbl == NULL) {
+		error = EINVAL;
+		gc_tbl = tbl;
+		goto err;
+	}
+	npf_config_sync(npf);
+err:
+	npf_config_exit(npf);
+	if (gc_tbl) {
+		npf_table_destroy(gc_tbl);
+	}
+	return error;
+}
+
+int
+npfctl_table_replace(npf_t *npf, u_long cmd, void *data)
+{
+	nvlist_t *request, *response;
+	int error;
+
+	/*
+	 * Retrieve the configuration and check the version.
+	 * Construct a response with error reporting.
+	 */
+	error = npf_nvlist_copyin(npf, data, &request);
+	if (error) {
+		return error;
+	}
+	response = nvlist_create(0);
+	error = npfctl_table_replace_nvlist(npf, request, response);
+	nvlist_add_number(response, "errno", error);
+	error = npf_nvlist_copyout(npf, data, response);
+	nvlist_destroy(request);
+	return error;
+}
+
+/*
  * npfctl_conn_lookup: lookup a connection in the list of connections
  */
 int

Index: src/sys/net/npf/npf_impl.h
diff -u src/sys/net/npf/npf_impl.h:1.76 src/sys/net/npf/npf_impl.h:1.77
--- src/sys/net/npf/npf_impl.h:1.76	Sun Aug 11 20:26:34 2019
+++ src/sys/net/npf/npf_impl.h	Wed Aug 21 21:45:47 2019
@@ -292,6 +292,7 @@ int		npfctl_save(npf_t *, u_long, void *
 int		npfctl_load(npf_t *, u_long, void *);
 int		npfctl_rule(npf_t *, u_long, void *);
 int		npfctl_conn_lookup(npf_t *, u_long, void *);
+int		npfctl_table_replace(npf_t *, u_long, void *);
 int		npfctl_table(npf_t *, void *);
 
 void		npf_stats_inc(npf_t *, npf_stats_t);
@@ -379,7 +380,7 @@ npf_table_t *	npf_table_create(const cha
 void		npf_table_destroy(npf_table_t *);
 
 u_int		npf_table_getid(npf_table_t *);
-int		npf_table_check(npf_tableset_t *, const char *, uint64_t, uint64_t);
+int		npf_table_check(npf_tableset_t *, const char *, uint64_t, uint64_t, bool);
 int		npf_table_insert(npf_table_t *, const int,
 		    const npf_addr_t *, const npf_netmask_t);
 int		npf_table_remove(npf_table_t *, const int,

Index: src/sys/net/npf/npf_os.c
diff -u src/sys/net/npf/npf_os.c:1.14 src/sys/net/npf/npf_os.c:1.15
--- src/sys/net/npf/npf_os.c:1.14	Sun Aug 11 20:26:34 2019
+++ src/sys/net/npf/npf_os.c	Wed Aug 21 21:45:47 2019
@@ -33,7 +33,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.14 2019/08/11 20:26:34 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.15 2019/08/21 21:45:47 rmind Exp $");
 
 #ifdef _KERNEL_OPT
 #include "pf.h"
@@ -259,6 +259,9 @@ npf_dev_ioctl(dev_t dev, u_long cmd, voi
 	case IOC_NPF_CONN_LOOKUP:
 		error = npfctl_conn_lookup(npf, cmd, data);
 		break;
+	case IOC_NPF_TABLE_REPLACE:
+		error = npfctl_table_replace(npf, cmd, data);
+		break;
 	case IOC_NPF_VERSION:
 		*(int *)data = NPF_VERSION;
 		error = 0;

Index: src/sys/net/npf/npf_tableset.c
diff -u src/sys/net/npf/npf_tableset.c:1.33 src/sys/net/npf/npf_tableset.c:1.34
--- src/sys/net/npf/npf_tableset.c:1.33	Tue Jul 23 00:52:01 2019
+++ src/sys/net/npf/npf_tableset.c	Wed Aug 21 21:45:47 2019
@@ -46,7 +46,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.33 2019/07/23 00:52:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.34 2019/08/21 21:45:47 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -456,12 +456,15 @@ npf_table_getid(npf_table_t *t)
  * npf_table_check: validate the name, ID and type.
  */
 int
-npf_table_check(npf_tableset_t *ts, const char *name, uint64_t tid, uint64_t type)
+npf_table_check(npf_tableset_t *ts, const char *name, uint64_t tid,
+    uint64_t type, bool replacing)
 {
+	const npf_table_t *t;
+
 	if (tid >= ts->ts_nitems) {
 		return EINVAL;
 	}
-	if (ts->ts_map[tid] != NULL) {
+	if (!replacing && ts->ts_map[tid] != NULL) {
 		return EEXIST;
 	}
 	switch (type) {
@@ -476,8 +479,10 @@ npf_table_check(npf_tableset_t *ts, cons
 	if (strlen(name) >= NPF_TABLE_MAXNAMELEN) {
 		return ENAMETOOLONG;
 	}
-	if (npf_tableset_getbyname(ts, name)) {
-		return EEXIST;
+	if ((t = npf_tableset_getbyname(ts, name)) != NULL) {
+		if (!replacing || t->t_id != tid) {
+			return EEXIST;
+		}
 	}
 	return 0;
 }

Reply via email to