Module Name:    src
Committed By:   knakahara
Date:           Fri Sep 30 07:36:36 UTC 2022

Modified Files:
        src/sys/net: if_ipsec.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.32 src/sys/net/if_ipsec.c

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

Modified files:

Index: src/sys/net/if_ipsec.c
diff -u src/sys/net/if_ipsec.c:1.31 src/sys/net/if_ipsec.c:1.32
--- src/sys/net/if_ipsec.c:1.31	Mon Oct 11 05:13:11 2021
+++ src/sys/net/if_ipsec.c	Fri Sep 30 07:36:36 2022
@@ -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 @@ static inline size_t if_ipsec_set_sadb_d
     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 inline void if_ipsec_set_sadb_msg
 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 @@ static int if_ipsec_set_addr_port(struct
 /* 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 struct sysctllog *if_ipsec_sysctl
 
 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 @@ sysctl_if_ipsec_pmtu_perif(SYSCTLFN_ARGS
 }
 #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 @@ if_ipsec_sysctl_setup(void)
 	    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 @@ if_ipsec_set_sadb_dst(struct sadb_addres
 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 @@ if_ipsec_set_sadb_x_policy(struct sadb_x
 		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 @@ if_ipsec_set_addr_port(struct sockaddr *
 	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 @@ if_ipsec_add_sp0(struct sockaddr *src, i
 	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 @@ if_ipsec_add_sp(struct ipsec_variant *va
 {
 	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 @@ if_ipsec_add_sp(struct ipsec_variant *va
 	else
 		v6policy = IPSEC_POLICY_DISCARD;
 
+	error = if_ipsec_get_reqids(var, reqids);
+	if (error)
+		goto fail;
+
 	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)
+	    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_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)
+	    IPSEC_DIR_OUTBOUND, IPPROTO_IPIP, level, IPSEC_POLICY_IPSEC,
+	    reqids[REQID_INDEX_IPV4OUT]);
+	if (IV_SP_OUT(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)
+	    IPSEC_DIR_INBOUND, IPPROTO_IPV6, level, v6policy,
+	    reqids[REQID_INDEX_IPV6IN]);
+	if (IV_SP_IN6(var) == NULL) {
+		error = EEXIST;
 		goto fail;
+	}
 	IV_SP_OUT6(var) = if_ipsec_add_sp0(src, sport, dst, dport,
-	    IPSEC_DIR_OUTBOUND, IPPROTO_IPV6, level, v6policy);
-	if (IV_SP_OUT6(var) == NULL)
+	    IPSEC_DIR_OUTBOUND, IPPROTO_IPV6, level, v6policy,
+	    reqids[REQID_INDEX_IPV6OUT]);
+	if (IV_SP_OUT6(var) == NULL) {
+		error = EEXIST;
 		goto fail;
+	}
 
 	return 0;
 
@@ -1805,7 +1976,7 @@ fail:
 		IV_SP_IN(var) = NULL;
 	}
 
-	return EEXIST;
+	return error;
 }
 
 static int
@@ -1826,7 +1997,7 @@ if_ipsec_del_sp0(struct secpolicy *sp)
 
 	MGETHDR(m, M_WAIT, MT_DATA);
 
-	size = if_ipsec_set_sadb_x_policy(&xpl, NULL, 0, 0, sp->id, 0, NULL, NULL);
+	size = if_ipsec_set_sadb_x_policy(&xpl, NULL, 0, 0, sp->id, 0, NULL, NULL, 0);
 	ext_msg_len += PFKEY_UNIT64(size);
 
 	if_ipsec_set_sadb_msg_del(&msg, ext_msg_len);

Reply via email to