Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Major NPF improvements (merge from upstream):



details:   https://anonhg.NetBSD.org/src/rev/7cbb91bf7dd2
branches:  trunk
changeset: 972569:7cbb91bf7dd2
user:      rmind <rmind%NetBSD.org@localhost>
date:      Sat May 30 14:16:56 2020 +0000

description:
Major NPF improvements (merge from upstream):

- Switch to the C11-style atomic primitives using atomic_loadstore(9).

- npfkern: introduce the 'state.key.interface' and 'state.key.direction'
  settings.  Users can now choose whether the connection state should be
  strictly per-interface or global at the configuration level.  Keep NAT
  logic to be always per-interface, though.

- npfkern: rewrite the G/C worker logic and make it self-tuning.

- npfkern and libnpf: multiple bug fixes; add param exporting; introduce
  more parameters.  Remove npf_nvlist_{copyin,copyout}() functions and
  refactor npfctl_load_nvlist() with others; add npfctl_run_op() to have
  a single entry point for operations.  Introduce npf_flow_t and clean up
  some code.

- npfctl: lots of fixes for the 'npfctl show' logic; make 'npfctl list'
  more informative; misc usability improvements and more user-friendly
  error messages.

- Amend and improve the manual pages.

diffstat:

 lib/libnpf/libnpf.3                              |   16 +-
 lib/libnpf/npf.c                                 |  405 +++++++++---
 lib/libnpf/npf.h                                 |    3 +-
 sys/net/npf/files.npf                            |    3 +-
 sys/net/npf/npf.c                                |   34 +-
 sys/net/npf/npf.h                                |   17 +-
 sys/net/npf/npf_alg.c                            |  103 ++-
 sys/net/npf/npf_alg_icmp.c                       |   21 +-
 sys/net/npf/npf_conf.c                           |   48 +-
 sys/net/npf/npf_conn.c                           |  337 ++++++----
 sys/net/npf/npf_conn.h                           |   37 +-
 sys/net/npf/npf_conndb.c                         |   96 ++-
 sys/net/npf/npf_connkey.c                        |  226 +++++-
 sys/net/npf/npf_ctl.c                            |  504 ++++++---------
 sys/net/npf/npf_ext_log.c                        |   45 +-
 sys/net/npf/npf_ext_normalize.c                  |   46 +-
 sys/net/npf/npf_ext_rndblock.c                   |   55 +-
 sys/net/npf/npf_handler.c                        |   47 +-
 sys/net/npf/npf_if.c                             |   21 +-
 sys/net/npf/npf_ifaddr.c                         |    6 +-
 sys/net/npf/npf_impl.h                           |   68 +-
 sys/net/npf/npf_inet.c                           |    8 +-
 sys/net/npf/npf_mbuf.c                           |   37 +-
 sys/net/npf/npf_nat.c                            |  249 ++++++--
 sys/net/npf/npf_os.c                             |   91 +-
 sys/net/npf/npf_params.c                         |   53 +-
 sys/net/npf/npf_portmap.c                        |   28 +-
 sys/net/npf/npf_rproc.c                          |   19 +-
 sys/net/npf/npf_ruleset.c                        |   84 +-
 sys/net/npf/npf_sendpkt.c                        |    4 +-
 sys/net/npf/npf_state.c                          |   22 +-
 sys/net/npf/npf_state_tcp.c                      |   15 +-
 sys/net/npf/npf_tableset.c                       |   18 +-
 sys/net/npf/npf_worker.c                         |  316 ++++++---
 sys/net/npf/npfkern.h                            |   42 +-
 usr.sbin/npf/npf-params.7                        |   54 +-
 usr.sbin/npf/npfctl/Makefile                     |    6 +-
 usr.sbin/npf/npfctl/npf.conf.5                   |   54 +-
 usr.sbin/npf/npfctl/npf_bpf_comp.c               |  150 +++-
 usr.sbin/npf/npfctl/npf_build.c                  |  269 +++++---
 usr.sbin/npf/npfctl/npf_cmd.c                    |  540 +++++++++++++++++
 usr.sbin/npf/npfctl/npf_parse.y                  |  131 ++-
 usr.sbin/npf/npfctl/npf_scan.l                   |    8 +-
 usr.sbin/npf/npfctl/npf_show.c                   |  396 ++++++++----
 usr.sbin/npf/npfctl/npf_var.c                    |  120 +--
 usr.sbin/npf/npfctl/npf_var.h                    |   12 +-
 usr.sbin/npf/npfctl/npfctl.8                     |   38 +-
 usr.sbin/npf/npfctl/npfctl.c                     |  705 +++++-----------------
 usr.sbin/npf/npfctl/npfctl.h                     |   38 +-
 usr.sbin/npf/npftest/libnpftest/Makefile         |    4 +-
 usr.sbin/npf/npftest/libnpftest/npf_conn_test.c  |  173 -----
 usr.sbin/npf/npftest/libnpftest/npf_gc_test.c    |  267 ++++++++
 usr.sbin/npf/npftest/libnpftest/npf_mbuf_subr.c  |    6 +-
 usr.sbin/npf/npftest/libnpftest/npf_nat_test.c   |    9 +-
 usr.sbin/npf/npftest/libnpftest/npf_state_test.c |    3 +-
 usr.sbin/npf/npftest/libnpftest/npf_test.h       |    8 +-
 usr.sbin/npf/npftest/libnpftest/npf_test_subr.c  |   52 +-
 usr.sbin/npf/npftest/npftest.c                   |   10 +-
 usr.sbin/npf/npftest/npftest.conf                |    5 +-
 usr.sbin/npf/npftest/npftest.h                   |    6 +-
 60 files changed, 3771 insertions(+), 2417 deletions(-)

diffs (truncated from 11286 to 300 lines):

diff -r 20b28ddd1c41 -r 7cbb91bf7dd2 lib/libnpf/libnpf.3
--- a/lib/libnpf/libnpf.3       Sat May 30 14:15:43 2020 +0000
+++ b/lib/libnpf/libnpf.3       Sat May 30 14:16:56 2020 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: libnpf.3,v 1.11 2019/09/30 00:37:11 rmind Exp $
+.\"    $NetBSD: libnpf.3,v 1.12 2020/05/30 14:16:56 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 August 25, 2019
+.Dd May 30, 2020
 .Dt LIBNPF 3
 .Os
 .Sh NAME
@@ -187,13 +187,12 @@
 .It Dv NPF_RULE_STATEFUL
 Create a state (session) on match, track the connection and pass the
 backwards stream (the returning packets) without the ruleset inspection.
-The state is uniquely identified by a 5-tuple (source and destination
-IP addresses, port numbers and an interface identifier).
+The state is uniquely identified by an n-tuple key.
 .It Dv NPF_RULE_GSTATEFUL
-Exclude the interface identifier from the state key i.e. use a 4-tuple.
+Exclude the interface identifier from the state key (n-tuple).
 This makes the state global with respect to the network interfaces.
-The state is also picked for packets travelling different direction than
-originally.
+The state is also picked for packets travelling in different direction
+than originally.
 .It Dv NPF_RULE_RETRST
 Return TCP RST packet in a case of packet block.
 .It Dv NPF_RULE_RETICMP
@@ -281,7 +280,8 @@
 is
 .Dv NULL ,
 then insert into the main ruleset.
-The rule must not be referenced after insertion.
+The rule will be consumed (the relevant resourced will be freed) and it
+must not be referenced after insertion.
 .\" ---
 .It Fn npf_rule_exists_p "ncf" "name"
 Check whether the rule with a given name is already in the configuration.
diff -r 20b28ddd1c41 -r 7cbb91bf7dd2 lib/libnpf/npf.c
--- a/lib/libnpf/npf.c  Sat May 30 14:15:43 2020 +0000
+++ b/lib/libnpf/npf.c  Sat May 30 14:16:56 2020 +0000
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2010-2019 The NetBSD Foundation, Inc.
+ * Copyright (c) 2010-2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This material is based upon work partially supported by The
@@ -28,11 +28,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.48 2019/09/30 00:37:11 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.49 2020/05/30 14:16:56 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#if !defined(_NPF_STANDALONE)
+#include <sys/ioctl.h>
+#endif
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <net/if.h>
@@ -227,6 +230,94 @@
 }
 
 /*
+ * npf_xfer_fd: transfer the given request and receive a response.
+ *
+ * => Sets the 'operation' key on the 'req' dictionary.
+ * => On success: returns 0 and valid nvlist in 'resp'.
+ * => On failure: returns an error number.
+ */
+static int
+_npf_xfer_fd(int fd, unsigned long cmd, nvlist_t *req, nvlist_t **resp)
+{
+       struct stat st;
+       int kernver;
+
+       /*
+        * Set the NPF version and operation.
+        */
+       if (!nvlist_exists(req, "version")) {
+               nvlist_add_number(req, "version", NPF_VERSION);
+       }
+       nvlist_add_number(req, "operation", cmd);
+
+       /*
+        * Determine the type of file descriptor:
+        * - If socket, then perform nvlist_send()/nvlist_recv().
+        * - If a character device, then use ioctl.
+        */
+       if (fstat(fd, &st) == -1) {
+               goto err;
+       }
+       switch (st.st_mode & S_IFMT) {
+#if !defined(__NetBSD__)
+       case S_IFSOCK:
+               if (nvlist_send(fd, req) == -1) {
+                       goto err;
+               }
+               if (resp && (*resp = nvlist_recv(fd, 0)) == NULL) {
+                       goto err;
+               }
+               break;
+#endif
+#if !defined(_NPF_STANDALONE)
+       case S_IFBLK:
+       case S_IFCHR:
+               if (ioctl(fd, IOC_NPF_VERSION, &kernver) == -1) {
+                       goto err;
+               }
+               if (kernver != NPF_VERSION) {
+                       errno = EPROGMISMATCH;
+                       goto err;
+               }
+               if (nvlist_xfer_ioctl(fd, cmd, req, resp) == -1) {
+                       goto err;
+               }
+               break;
+#else
+               (void)kernver;
+#endif
+       default:
+               errno = ENOTSUP;
+               goto err;
+       }
+       return 0;
+err:
+       return errno ? errno : EIO;
+}
+
+/*
+ * npf_xfer_fd_errno: same as npf_xfer_fd(), but:
+ *
+ * => After successful retrieval of the response, inspects it, extracts
+ *    the 'errno' value (if any) and returns it.
+ * => Destroys the response.
+ */
+static int
+_npf_xfer_fd_errno(int fd, unsigned long cmd, nvlist_t *req)
+{
+       nvlist_t *resp;
+       int error;
+
+       error = _npf_xfer_fd(fd, cmd, req, &resp);
+       if (error) {
+               return error;
+       }
+       error = _npf_extract_error(resp, NULL);
+       nvlist_destroy(resp);
+       return error;
+}
+
+/*
  * CONFIGURATION INTERFACE.
  */
 
@@ -247,18 +338,18 @@
 int
 npf_config_submit(nl_config_t *ncf, int fd, npf_error_t *errinfo)
 {
-       nvlist_t *errnv = NULL;
+       nvlist_t *resp = NULL;
        int error;
 
        /* Ensure the config is built. */
        (void)npf_config_build(ncf);
 
-       if (nvlist_xfer_ioctl(fd, IOC_NPF_LOAD, ncf->ncf_dict, &errnv) == -1) {
-               assert(errnv == NULL);
-               return errno;
+       error = _npf_xfer_fd(fd, IOC_NPF_LOAD, ncf->ncf_dict, &resp);
+       if (error) {
+               return error;
        }
-       error = _npf_extract_error(errnv, errinfo);
-       nvlist_destroy(errnv);
+       error = _npf_extract_error(resp, errinfo);
+       nvlist_destroy(resp);
        return error;
 }
 
@@ -266,15 +357,24 @@
 npf_config_retrieve(int fd)
 {
        nl_config_t *ncf;
+       nvlist_t *req, *resp = NULL;
+       int error;
 
        ncf = calloc(1, sizeof(nl_config_t));
        if (!ncf) {
                return NULL;
        }
-       if (nvlist_recv_ioctl(fd, IOC_NPF_SAVE, &ncf->ncf_dict) == -1) {
+
+       req = nvlist_create(0);
+       error = _npf_xfer_fd(fd, IOC_NPF_SAVE, req, &resp);
+       nvlist_destroy(req);
+
+       if (error || _npf_extract_error(resp, NULL) != 0) {
+               nvlist_destroy(resp);
                free(ncf);
                return NULL;
        }
+       ncf->ncf_dict = resp;
        return ncf;
 }
 
@@ -332,7 +432,7 @@
        return nvlist_exists_nvlist_array(ncf->ncf_dict, "rules");
 }
 
-void *
+const void *
 npf_config_build(nl_config_t *ncf)
 {
        _npf_rules_process(ncf, ncf->ncf_dict, "__rules");
@@ -397,6 +497,43 @@
        return 0;
 }
 
+const char *
+npf_param_iterate(nl_config_t *ncf, nl_iter_t *iter, int *val, int *defval)
+{
+       void *cookie = (void *)(intptr_t)*iter;
+       const nvlist_t *params, *dparams;
+       const char *name;
+       int type;
+
+       assert(sizeof(nl_iter_t) >= sizeof(void *));
+
+       params = dnvlist_get_nvlist(ncf->ncf_dict, "params", NULL);
+       if (params == NULL) {
+               return NULL;
+       }
+skip:
+       if ((name = nvlist_next(params, &type, &cookie)) == NULL) {
+               *iter = NPF_ITER_BEGIN;
+               return NULL;
+       }
+       if (type != NV_TYPE_NUMBER) {
+               goto skip; // should never happen, though
+       }
+       if (defval) {
+               dparams = dnvlist_get_nvlist(ncf->ncf_dict,
+                   "params-defaults", NULL);
+               if (dparams == NULL) {
+                       errno = EINVAL;
+                       return NULL;
+               }
+               *defval = (int)nvlist_get_number(dparams, name);
+       }
+
+       *val = (int)nvlist_get_number(params, name);
+       *iter = (intptr_t)cookie;
+       return name;
+}
+
 /*
  * DYNAMIC RULESET INTERFACE.
  */
@@ -412,24 +549,26 @@
 npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
 {
        const bool natset = _npf_nat_ruleset_p(rname);
-       nvlist_t *rule_dict = rl->rule_dict;
-       nvlist_t *ret_dict;
+       nvlist_t *rule_nvl = rl->rule_dict, *resp;
+       int error;
 
-       nvlist_add_number(rule_dict, "attr",
-           NPF_RULE_DYNAMIC | nvlist_take_number(rule_dict, "attr"));
+       nvlist_add_number(rule_nvl, "attr",
+           NPF_RULE_DYNAMIC | nvlist_take_number(rule_nvl, "attr"));
 
-       if (natset && !dnvlist_get_bool(rule_dict, "nat-rule", false)) {
+       if (natset && !dnvlist_get_bool(rule_nvl, "nat-rule", false)) {
                errno = EINVAL;
                return errno;
        }
-       nvlist_add_string(rule_dict, "ruleset-name", rname);
-       nvlist_add_bool(rule_dict, "nat-ruleset", natset);
-       nvlist_add_number(rule_dict, "command", NPF_CMD_RULE_ADD);
+       nvlist_add_string(rule_nvl, "ruleset-name", rname);
+       nvlist_add_bool(rule_nvl, "nat-ruleset", natset);
+       nvlist_add_number(rule_nvl, "command", NPF_CMD_RULE_ADD);
 
-       if (nvlist_xfer_ioctl(fd, IOC_NPF_RULE, rule_dict, &ret_dict) == -1) {
-               return errno;
+       error = _npf_xfer_fd(fd, IOC_NPF_RULE, rule_nvl, &resp);



Home | Main Index | Thread Index | Old Index