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;
}