Source-Changes-HG archive

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

[src/trunk]: src/sys/net ipsecif(4) can use fixed SP reqid based on ifindex, ...



details:   https://anonhg.NetBSD.org/src/rev/de209010fe2b
branches:  trunk
changeset: 371233:de209010fe2b
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Fri Sep 30 07:36:36 2022 +0000

description:
ipsecif(4) can use fixed SP reqid based on ifindex, that can reduce number of reqid.

If we want to use fixed SP reqid for ipsecif(4), set
net.ipsecif.use_fixed_reqid=1  Default(=0) is the same as before.
net.ipsecif.use_fixed_reqid can be changed only if there is no ipsecif(4) yet.

If we want to change the range of ipseif(4) SP reqid,
set net.ipsecif.reqid_base and net.ipsecif.reqid_last.
These can also be changed only if there is no ipsecif(4) yet.

diffstat:

 sys/net/if_ipsec.c |  215 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 193 insertions(+), 22 deletions(-)

diffs (truncated from 337 to 300 lines):

diff -r 5fff7358465b -r de209010fe2b sys/net/if_ipsec.c
--- a/sys/net/if_ipsec.c        Fri Sep 30 06:39:54 2022 +0000
+++ b/sys/net/if_ipsec.c        Fri Sep 30 07:36:36 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ipsec.c,v 1.31 2021/10/11 05:13:11 knakahara Exp $  */
+/*     $NetBSD: if_ipsec.c,v 1.32 2022/09/30 07:36:36 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.31 2021/10/11 05:13:11 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.32 2022/09/30 07:36:36 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -110,7 +110,7 @@
     struct sockaddr *, int);
 static inline size_t if_ipsec_set_sadb_x_policy(struct sadb_x_policy *,
     struct sadb_x_ipsecrequest *, uint16_t, uint8_t, uint32_t, uint8_t,
-    struct sockaddr *, struct sockaddr *);
+    struct sockaddr *, struct sockaddr *, uint16_t);
 static inline void if_ipsec_set_sadb_msg(struct sadb_msg *, uint16_t, uint8_t);
 static inline void if_ipsec_set_sadb_msg_add(struct sadb_msg *, uint16_t);
 static inline void if_ipsec_set_sadb_msg_del(struct sadb_msg *, uint16_t);
@@ -118,7 +118,7 @@
 static int if_ipsec_share_sp(struct ipsec_variant *);
 static int if_ipsec_unshare_sp(struct ipsec_variant *);
 static inline struct secpolicy *if_ipsec_add_sp0(struct sockaddr *,
-    in_port_t, struct sockaddr *, in_port_t, int, int, int, u_int);
+    in_port_t, struct sockaddr *, in_port_t, int, int, int, u_int, uint16_t);
 static inline int if_ipsec_del_sp0(struct secpolicy *);
 static int if_ipsec_add_sp(struct ipsec_variant *,
     struct sockaddr *, in_port_t, struct sockaddr *, in_port_t);
@@ -140,8 +140,17 @@
 /* This list is used in ioctl context only. */
 static struct {
        LIST_HEAD(ipsec_sclist, ipsec_softc) list;
+       bool use_fixed_reqid;
+#define REQID_BASE_DEFAULT     0x2000
+#define REQID_LAST_DEFAULT     0x2fff
+       u_int16_t reqid_base;
+       u_int16_t reqid_last;
        kmutex_t lock;
-} ipsec_softcs __cacheline_aligned;
+} ipsec_softcs __cacheline_aligned = {
+       .use_fixed_reqid = false,
+       .reqid_base = REQID_BASE_DEFAULT,
+       .reqid_last = REQID_LAST_DEFAULT,
+};
 
 struct psref_class *iv_psref_class __read_mostly;
 
@@ -153,6 +162,14 @@
 
 static pktq_rps_hash_func_t if_ipsec_pktq_rps_hash_p;
 
+enum {
+       REQID_INDEX_IPV4IN = 0,
+       REQID_INDEX_IPV4OUT,
+       REQID_INDEX_IPV6IN,
+       REQID_INDEX_IPV6OUT,
+       REQID_INDEX_NUM,
+};
+
 #ifdef INET6
 static int
 sysctl_if_ipsec_pmtu_global(SYSCTLFN_ARGS)
@@ -205,6 +222,84 @@
 }
 #endif
 
+static int
+sysctl_if_ipsec_use_fixed_reqid(SYSCTLFN_ARGS)
+{
+       bool fixed;
+       int error;
+       struct sysctlnode node = *rnode;
+
+       mutex_enter(&ipsec_softcs.lock);
+       fixed = ipsec_softcs.use_fixed_reqid;
+       node.sysctl_data = &fixed;
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error || newp == NULL) {
+               mutex_exit(&ipsec_softcs.lock);
+               return error;
+       }
+
+       if (!LIST_EMPTY(&ipsec_softcs.list)) {
+               mutex_exit(&ipsec_softcs.lock);
+               return EBUSY;
+       }
+       ipsec_softcs.use_fixed_reqid = fixed;
+       mutex_exit(&ipsec_softcs.lock);
+
+       return 0;
+}
+
+static int
+sysctl_if_ipsec_reqid_base(SYSCTLFN_ARGS)
+{
+       int base;
+       int error;
+       struct sysctlnode node = *rnode;
+
+       mutex_enter(&ipsec_softcs.lock);
+       base = ipsec_softcs.reqid_base;
+       node.sysctl_data = &base;
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error || newp == NULL) {
+               mutex_exit(&ipsec_softcs.lock);
+               return error;
+       }
+
+       if (!LIST_EMPTY(&ipsec_softcs.list)) {
+               mutex_exit(&ipsec_softcs.lock);
+               return EBUSY;
+       }
+       ipsec_softcs.reqid_base = base;
+       mutex_exit(&ipsec_softcs.lock);
+
+       return 0;
+}
+
+static int
+sysctl_if_ipsec_reqid_last(SYSCTLFN_ARGS)
+{
+       int last;
+       int error;
+       struct sysctlnode node = *rnode;
+
+       mutex_enter(&ipsec_softcs.lock);
+       last = ipsec_softcs.reqid_last;
+       node.sysctl_data = &last;
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error || newp == NULL) {
+               mutex_exit(&ipsec_softcs.lock);
+               return error;
+       }
+
+       if (!LIST_EMPTY(&ipsec_softcs.list)) {
+               mutex_exit(&ipsec_softcs.lock);
+               return EBUSY;
+       }
+       ipsec_softcs.reqid_last = last;
+       mutex_exit(&ipsec_softcs.lock);
+
+       return 0;
+}
+
 static void
 if_ipsec_sysctl_setup(void)
 {
@@ -260,6 +355,26 @@
            sysctl_pktq_rps_hash_handler, 0, (void *)&if_ipsec_pktq_rps_hash_p,
            PKTQ_RPS_HASH_NAME_LEN,
            CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(&if_ipsec_sysctl, 0, &node, NULL,
+           CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+           CTLTYPE_BOOL, "use_fixed_reqid",
+           SYSCTL_DESCR("use fixed reqid for SP"),
+           sysctl_if_ipsec_use_fixed_reqid, 0, NULL, 0,
+           CTL_CREATE, CTL_EOL);
+       sysctl_createv(&if_ipsec_sysctl, 0, &node, NULL,
+           CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+           CTLTYPE_INT, "reqid_base",
+           SYSCTL_DESCR("base value of fixed reqid"),
+           sysctl_if_ipsec_reqid_base, 0, NULL, 0,
+           CTL_CREATE, CTL_EOL);
+       sysctl_createv(&if_ipsec_sysctl, 0, &node, NULL,
+           CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+           CTLTYPE_INT, "reqid_last",
+           SYSCTL_DESCR("last value of fixed reqid"),
+           sysctl_if_ipsec_reqid_last, 0, NULL, 0,
+           CTL_CREATE, CTL_EOL);
+
 }
 
 static void
@@ -1575,7 +1690,7 @@
 static inline size_t
 if_ipsec_set_sadb_x_policy(struct sadb_x_policy *xpl,
     struct sadb_x_ipsecrequest *xisr, uint16_t policy, uint8_t dir, uint32_t id,
-    uint8_t level, struct sockaddr *src, struct sockaddr *dst)
+    uint8_t level, struct sockaddr *src, struct sockaddr *dst, uint16_t reqid)
 {
        size_t size;
 
@@ -1604,7 +1719,7 @@
                xisr->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
                xisr->sadb_x_ipsecrequest_level = level;
                if (level == IPSEC_LEVEL_UNIQUE)
-                       xisr->sadb_x_ipsecrequest_reqid = key_newreqid();
+                       xisr->sadb_x_ipsecrequest_reqid = reqid;
                else
                        xisr->sadb_x_ipsecrequest_reqid = 0;
        }
@@ -1675,10 +1790,47 @@
        return error;
 }
 
+static int
+if_ipsec_get_reqids(struct ipsec_variant *var, u_int16_t reqids[REQID_INDEX_NUM])
+{
+       struct ipsec_softc *sc = var->iv_softc;
+       struct ifnet *ifp = &sc->ipsec_if;
+
+       mutex_enter(&ipsec_softcs.lock);
+       if (ipsec_softcs.use_fixed_reqid) {
+               u_int16_t reqid_base;
+
+               reqid_base = ipsec_softcs.reqid_base + ifp->if_index * 2;
+               if (reqid_base + 1 > ipsec_softcs.reqid_last) {
+                       log(LOG_ERR,
+                           "%s: invalid fixed reqid(%"PRIu16"), "
+                           "current range %"PRIu16" <= reqid <= %"PRIu16"\n",
+                           ifp->if_xname, reqid_base + 1,
+                           ipsec_softcs.reqid_base, ipsec_softcs.reqid_last);
+                       mutex_exit(&ipsec_softcs.lock);
+                       return ENOSPC;
+               }
+
+               /*
+                * Use same reqid both inbound and outbound to reduce reqid.
+                */
+               reqids[REQID_INDEX_IPV4IN] = reqid_base;
+               reqids[REQID_INDEX_IPV4OUT] = reqid_base;
+               reqids[REQID_INDEX_IPV6IN] = reqid_base + 1;
+               reqids[REQID_INDEX_IPV6OUT] = reqid_base + 1;
+       } else {
+               for (int i = 0; i < REQID_INDEX_NUM; i++)
+                       reqids[i] = key_newreqid();
+       }
+       mutex_exit(&ipsec_softcs.lock);
+
+       return 0;
+}
+
 static struct secpolicy *
 if_ipsec_add_sp0(struct sockaddr *src, in_port_t sport,
     struct sockaddr *dst, in_port_t dport,
-    int dir, int proto, int level, u_int policy)
+    int dir, int proto, int level, u_int policy, uint16_t reqid)
 {
        struct sadb_msg msg;
        struct sadb_address xsrc, xdst;
@@ -1701,7 +1853,8 @@
        ext_msg_len += PFKEY_UNIT64(size);
        size = if_ipsec_set_sadb_dst(&xdst, dst, proto);
        ext_msg_len += PFKEY_UNIT64(size);
-       size = if_ipsec_set_sadb_x_policy(&xpl, &xisr, policy, dir, 0, level, NULL, NULL);
+       size = if_ipsec_set_sadb_x_policy(&xpl, &xisr, policy, dir, 0, level,
+           NULL, NULL, reqid);
        ext_msg_len += PFKEY_UNIT64(size);
        if_ipsec_set_sadb_msg_add(&msg, ext_msg_len);
 
@@ -1746,7 +1899,9 @@
 {
        struct ipsec_softc *sc = var->iv_softc;
        int level;
+       int error;
        u_int v6policy;
+       u_int16_t reqids[REQID_INDEX_NUM];
 
        /*
         * must delete sp before add it.
@@ -1772,22 +1927,38 @@
        else
                v6policy = IPSEC_POLICY_DISCARD;
 
-       IV_SP_IN(var) = if_ipsec_add_sp0(dst, dport, src, sport,
-           IPSEC_DIR_INBOUND, IPPROTO_IPIP, level, IPSEC_POLICY_IPSEC);
-       if (IV_SP_IN(var) == NULL)
+       error = if_ipsec_get_reqids(var, reqids);
+       if (error)
                goto fail;
-       IV_SP_OUT(var) = if_ipsec_add_sp0(src, sport, dst, dport,
-           IPSEC_DIR_OUTBOUND, IPPROTO_IPIP, level, IPSEC_POLICY_IPSEC);
-       if (IV_SP_OUT(var) == NULL)
+
+       IV_SP_IN(var) = if_ipsec_add_sp0(dst, dport, src, sport,
+           IPSEC_DIR_INBOUND, IPPROTO_IPIP, level, IPSEC_POLICY_IPSEC,
+           reqids[REQID_INDEX_IPV4IN]);
+       if (IV_SP_IN(var) == NULL) {
+               error = EEXIST;
                goto fail;
-       IV_SP_IN6(var) = if_ipsec_add_sp0(dst, dport, src, sport,
-           IPSEC_DIR_INBOUND, IPPROTO_IPV6, level, v6policy);
-       if (IV_SP_IN6(var) == NULL)
+       }
+       IV_SP_OUT(var) = if_ipsec_add_sp0(src, sport, dst, dport,
+           IPSEC_DIR_OUTBOUND, IPPROTO_IPIP, level, IPSEC_POLICY_IPSEC,
+           reqids[REQID_INDEX_IPV4OUT]);
+       if (IV_SP_OUT(var) == NULL) {
+               error = EEXIST;
                goto fail;
+       }



Home | Main Index | Thread Index | Old Index