Re: [devel-ipsec] [PATCH ipsec-next v2 08/17] xfrm: iptfs: add new iptfs xfrm mode impl
From: Antony Antony <hidden>
Date: 2024-06-03 17:15:20
Hi Chris, On Mon, May 20, 2024 at 05:42:46PM -0400, Christian Hopps via Devel wrote:
quoted hunk ↗ jump to hunk
From: Christian Hopps <redacted> Add a new xfrm mode implementing AggFrag/IP-TFS from RFC9347. This utilizes the new xfrm_mode_cbs to implement demand-driven IP-TFS functionality. This functionality can be used to increase bandwidth utilization through small packet aggregation, as well as help solve PMTU issues through it's efficient use of fragmentation. Link: https://www.rfc-editor.org/rfc/rfc9347.txt Multiple commits follow to build the functionality into xfrm_iptfs.c Signed-off-by: Christian Hopps <redacted> --- net/xfrm/Makefile | 1 + net/xfrm/xfrm_iptfs.c | 225 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 net/xfrm/xfrm_iptfs.cdiff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 547cec77ba03..cd6520d4d777 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile@@ -20,5 +20,6 @@ obj-$(CONFIG_XFRM_USER) += xfrm_user.o obj-$(CONFIG_XFRM_USER_COMPAT) += xfrm_compat.o obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o +obj-$(CONFIG_XFRM_IPTFS) += xfrm_iptfs.o obj-$(CONFIG_XFRM_ESPINTCP) += espintcp.o obj-$(CONFIG_DEBUG_INFO_BTF) += xfrm_state_bpf.odiff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c new file mode 100644 index 000000000000..e7b5546e1f6a --- /dev/null +++ b/net/xfrm/xfrm_iptfs.c@@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* xfrm_iptfs: IPTFS encapsulation support + * + * April 21 2022, Christian Hopps <chopps@labn.net> + * + * Copyright (c) 2022, LabN Consulting, L.L.C. + * + */ + +#include <linux/kernel.h> +#include <linux/icmpv6.h> +#include <net/gro.h> +#include <net/icmp.h> +#include <net/ip6_route.h> +#include <net/inet_ecn.h> +#include <net/xfrm.h> + +#include <crypto/aead.h> + +#include "xfrm_inout.h" + +struct xfrm_iptfs_config { + u32 pkt_size; /* outer_packet_size or 0 */ +}; + +struct xfrm_iptfs_data { + struct xfrm_iptfs_config cfg; + + /* Ingress User Input */ + struct xfrm_state *x; /* owning state */ + u32 payload_mtu; /* max payload size */ +}; + +/* ========================== */ +/* State Management Functions */ +/* ========================== */ + +/** + * iptfs_get_inner_mtu() - return inner MTU with no fragmentation. + * @x: xfrm state. + * @outer_mtu: the outer mtu + */ +static u32 iptfs_get_inner_mtu(struct xfrm_state *x, int outer_mtu) +{ + struct crypto_aead *aead; + u32 blksize; + + aead = x->data; + blksize = ALIGN(crypto_aead_blocksize(aead), 4); + return ((outer_mtu - x->props.header_len - crypto_aead_authsize(aead)) & + ~(blksize - 1)) - 2; +} + +/** + * iptfs_user_init() - initialize the SA with IPTFS options from netlink. + * @net: the net data + * @x: xfrm state + * @attrs: netlink attributes + * @extack: extack return data + */ +static int iptfs_user_init(struct net *net, struct xfrm_state *x, + struct nlattr **attrs, + struct netlink_ext_ack *extack) +{ + struct xfrm_iptfs_data *xtfs = x->mode_data; + struct xfrm_iptfs_config *xc; + + xc = &xtfs->cfg; + + if (attrs[XFRMA_IPTFS_PKT_SIZE]) { + xc->pkt_size = nla_get_u32(attrs[XFRMA_IPTFS_PKT_SIZE]); + if (!xc->pkt_size) { + xtfs->payload_mtu = 0; + } else if (xc->pkt_size > x->props.header_len) { + xtfs->payload_mtu = xc->pkt_size - x->props.header_len; + } else { + NL_SET_ERR_MSG(extack, + "Packet size must be 0 or greater than IPTFS/ESP header length"); + return -EINVAL; + } + } + return 0; +} + +static unsigned int iptfs_sa_len(const struct xfrm_state *x) +{ + struct xfrm_iptfs_data *xtfs = x->mode_data; + struct xfrm_iptfs_config *xc = &xtfs->cfg; + unsigned int l = 0; + + l += nla_total_size(0); + l += nla_total_size(sizeof(u16)); + l += nla_total_size(sizeof(xc->pkt_size)); + l += nla_total_size(sizeof(u32)); + l += nla_total_size(sizeof(u32)); /* drop time usec */ + l += nla_total_size(sizeof(u32)); /* init delay usec */ + + return l; +} + +static int iptfs_copy_to_user(struct xfrm_state *x, struct sk_buff *skb) +{ + struct xfrm_iptfs_data *xtfs = x->mode_data; + struct xfrm_iptfs_config *xc = &xtfs->cfg; + int ret; + + ret = nla_put_flag(skb, XFRMA_IPTFS_DONT_FRAG); + if (ret) + return ret; + ret = nla_put_u16(skb, XFRMA_IPTFS_REORDER_WINDOW, 0); + if (ret) + return ret; + ret = nla_put_u32(skb, XFRMA_IPTFS_PKT_SIZE, xc->pkt_size); + if (ret) + return ret; + ret = nla_put_u32(skb, XFRMA_IPTFS_MAX_QSIZE, 0); + if (ret) + return ret; + + ret = nla_put_u32(skb, XFRMA_IPTFS_DROP_TIME, 0); + if (ret) + return ret; + + ret = nla_put_u32(skb, XFRMA_IPTFS_INIT_DELAY, 0);
Why copy all attributes? Only copy the ones relevant to the SA direction. Also adjust in iptfs_sa_len().
+
+ return ret;
+}
+
+static int __iptfs_init_state(struct xfrm_state *x,
+ struct xfrm_iptfs_data *xtfs)
+{
+ /* Modify type (esp) adjustment values */
+
+ if (x->props.family == AF_INET)
+ x->props.header_len += sizeof(struct iphdr) + sizeof(struct ip_iptfs_hdr);
+ else if (x->props.family == AF_INET6)
+ x->props.header_len += sizeof(struct ipv6hdr) + sizeof(struct ip_iptfs_hdr);
+ x->props.enc_hdr_len = sizeof(struct ip_iptfs_hdr);
+
+ /* Always have a module reference if x->mode_data is set */
+ if (!try_module_get(x->mode_cbs->owner))
+ return -EINVAL;
+
+ x->mode_data = xtfs;
+ xtfs->x = x;
+
+ return 0;
+}
+
+static int iptfs_clone(struct xfrm_state *x, struct xfrm_state *orig)
+{
+ struct xfrm_iptfs_data *xtfs;
+ int err;
+
+ xtfs = kmemdup(orig->mode_data, sizeof(*xtfs), GFP_KERNEL);
+ if (!xtfs)
+ return -ENOMEM;
+
+ err = __iptfs_init_state(x, xtfs);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int iptfs_create_state(struct xfrm_state *x)
+{
+ struct xfrm_iptfs_data *xtfs;
+ int err;
+
+ xtfs = kzalloc(sizeof(*xtfs), GFP_KERNEL);
+ if (!xtfs)
+ return -ENOMEM;
+
+ err = __iptfs_init_state(x, xtfs);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void iptfs_delete_state(struct xfrm_state *x)
+{
+ struct xfrm_iptfs_data *xtfs = x->mode_data;
+
+ if (!xtfs)
+ return;
+
+ kfree_sensitive(xtfs);
+
+ module_put(x->mode_cbs->owner);
+}
+
+static const struct xfrm_mode_cbs iptfs_mode_cbs = {
+ .owner = THIS_MODULE,
+ .create_state = iptfs_create_state,
+ .delete_state = iptfs_delete_state,
+ .user_init = iptfs_user_init,
+ .copy_to_user = iptfs_copy_to_user,
+ .sa_len = iptfs_sa_len,
+ .clone = iptfs_clone,
+ .get_inner_mtu = iptfs_get_inner_mtu,
+};
+
+static int __init xfrm_iptfs_init(void)
+{
+ int err;
+
+ pr_info("xfrm_iptfs: IPsec IP-TFS tunnel mode module\n");
+
+ err = xfrm_register_mode_cbs(XFRM_MODE_IPTFS, &iptfs_mode_cbs);
+ if (err < 0)
+ pr_info("%s: can't register IP-TFS\n", __func__);
+
+ return err;
+}
+
+static void __exit xfrm_iptfs_fini(void)
+{
+ xfrm_unregister_mode_cbs(XFRM_MODE_IPTFS);
+}
+
+module_init(xfrm_iptfs_init);
+module_exit(xfrm_iptfs_fini);
+MODULE_LICENSE("GPL");
--
2.45.1
--
Devel mailing list
Devel@linux-ipsec.org
https://linux-ipsec.org/mailman/listinfo/devel