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