diff mbox series

[ipsec-next,v5,08/17] xfrm: iptfs: add new iptfs xfrm mode impl

Message ID 20240714202246.1573817-9-chopps@chopps.org (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series Add IP-TFS mode to xfrm | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Christian Hopps July 14, 2024, 8:22 p.m. UTC
From: Christian Hopps <chopps@labn.net>

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 <chopps@labn.net>
---
 net/xfrm/Makefile     |   1 +
 net/xfrm/xfrm_iptfs.c | 206 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 207 insertions(+)
 create mode 100644 net/xfrm/xfrm_iptfs.c

Comments

Simon Horman July 15, 2024, 12:39 p.m. UTC | #1
On Sun, Jul 14, 2024 at 04:22:36PM -0400, Christian Hopps wrote:
> From: Christian Hopps <chopps@labn.net>
> 
> 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 <chopps@labn.net>
> ---
>  net/xfrm/Makefile     |   1 +
>  net/xfrm/xfrm_iptfs.c | 206 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 207 insertions(+)
>  create mode 100644 net/xfrm/xfrm_iptfs.c
> 
> diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
> index 512e0b2f8514..5a1787587cb3 100644
> --- a/net/xfrm/Makefile
> +++ b/net/xfrm/Makefile
> @@ -21,5 +21,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.o
> diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c
> new file mode 100644
> index 000000000000..414035a7a208
> --- /dev/null
> +++ b/net/xfrm/xfrm_iptfs.c
> @@ -0,0 +1,206 @@
> +// 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
> + */

Hi Christian,

Please consider including a "Return:" or "Returns:" section
in the Kernel doc for functions that return values.

Likewise elsewhere in this patchset.

Flagged by: ./scripts/kernel-doc -none -Wall

> +static u32 iptfs_get_inner_mtu(struct xfrm_state *x, int outer_mtu)

...
Christian Hopps July 18, 2024, 5:56 a.m. UTC | #2
Simon Horman via Devel <devel@linux-ipsec.org> writes:

> On Sun, Jul 14, 2024 at 04:22:36PM -0400, Christian Hopps wrote:
>> From: Christian Hopps <chopps@labn.net>
>>
>> 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 <chopps@labn.net>
>> ---
>>  net/xfrm/Makefile     |   1 +
>>  net/xfrm/xfrm_iptfs.c | 206 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 207 insertions(+)
>>  create mode 100644 net/xfrm/xfrm_iptfs.c
>>
>> diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
>> index 512e0b2f8514..5a1787587cb3 100644
>> --- a/net/xfrm/Makefile
>> +++ b/net/xfrm/Makefile
>> @@ -21,5 +21,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.o
>> diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c
>> new file mode 100644
>> index 000000000000..414035a7a208
>> --- /dev/null
>> +++ b/net/xfrm/xfrm_iptfs.c
>> @@ -0,0 +1,206 @@
>> +// 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
>> + */
>
> Hi Christian,
>
> Please consider including a "Return:" or "Returns:" section
> in the Kernel doc for functions that return values.
>
> Likewise elsewhere in this patchset.
>
> Flagged by: ./scripts/kernel-doc -none -Wall
>
>> +static u32 iptfs_get_inner_mtu(struct xfrm_state *x, int outer_mtu)
>
> ...

I've updated all the doc comments to include "Return:"s.

Thanks!
Chris.
Florian Westphal July 19, 2024, 6:16 a.m. UTC | #3
Christian Hopps via Devel <devel@linux-ipsec.org> wrote:
> +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;

Missing kfree on err?

> +	xtfs = kzalloc(sizeof(*xtfs), GFP_KERNEL);
> +	if (!xtfs)
> +		return -ENOMEM;
> +
> +	err = __iptfs_init_state(x, xtfs);
> +	if (err)
> +		return err;

Likewise.
Christian Hopps July 20, 2024, 12:30 a.m. UTC | #4
Florian Westphal <fw@strlen.de> writes:

> Christian Hopps via Devel <devel@linux-ipsec.org> wrote:
>> +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;
>
> Missing kfree on err?
>
>> +	xtfs = kzalloc(sizeof(*xtfs), GFP_KERNEL);
>> +	if (!xtfs)
>> +		return -ENOMEM;
>> +
>> +	err = __iptfs_init_state(x, xtfs);
>> +	if (err)
>> +		return err;
>
> Likewise.

These originally counted on the fact that the xfrm state is cleaned up on error; however, a later code change did indeed allow for the leak -- added kfree's as suggested.

Thanks,
Chris.
Sabrina Dubroca July 25, 2024, 1:33 p.m. UTC | #5
2024-07-14, 16:22:36 -0400, Christian Hopps wrote:
> +struct xfrm_iptfs_config {
> +	u32 pkt_size;	    /* outer_packet_size or 0 */

Please convert this to kdoc.

> +};
> +
> +struct xfrm_iptfs_data {
> +	struct xfrm_iptfs_config cfg;
> +
> +	/* Ingress User Input */
> +	struct xfrm_state *x;	    /* owning state */

And this too.

> +	u32 payload_mtu;	    /* max payload size */
> +};


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

BTW, I wrote that this was leaking xtfs in my previous review, back in
March :/
Christian Hopps July 25, 2024, 2:56 p.m. UTC | #6
Sabrina Dubroca <sd@queasysnail.net> writes:

> 2024-07-14, 16:22:36 -0400, Christian Hopps wrote:
>> +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;
>
> BTW, I wrote that this was leaking xtfs in my previous review, back in
> March :/


You did indeed -- that was the review you asked for the commit split. I've marked unread that previous email now so I can go over it again and verify I didn't miss anything else.

Thanks,
Chris.
Christian Hopps July 31, 2024, 4:29 p.m. UTC | #7
Sabrina Dubroca <sd@queasysnail.net> writes:

> 2024-07-14, 16:22:36 -0400, Christian Hopps wrote:
>> +struct xfrm_iptfs_config {
>> +	u32 pkt_size;	    /* outer_packet_size or 0 */
>
> Please convert this to kdoc.

Done.

>> +};
>> +
>> +struct xfrm_iptfs_data {
>> +	struct xfrm_iptfs_config cfg;
>> +
>> +	/* Ingress User Input */
>> +	struct xfrm_state *x;	    /* owning state */
>
> And this too.

Done.

>> +	u32 payload_mtu;	    /* max payload size */
>> +};
>
>
>> +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;
>
> BTW, I wrote that this was leaking xtfs in my previous review, back in
> March :/

I went back through your earlier review again. The next patch set adds the queue flush/cleanup on state delete, and uses a new MIB direction independent MIB counter for failed skb alloc -- which you identified as well.

Thanks,
Chris.
diff mbox series

Patch

diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
index 512e0b2f8514..5a1787587cb3 100644
--- a/net/xfrm/Makefile
+++ b/net/xfrm/Makefile
@@ -21,5 +21,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.o
diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c
new file mode 100644
index 000000000000..414035a7a208
--- /dev/null
+++ b/net/xfrm/xfrm_iptfs.c
@@ -0,0 +1,206 @@ 
+// 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;
+
+	if (x->dir == XFRM_SA_DIR_OUT)
+		l += nla_total_size(sizeof(xc->pkt_size));
+
+	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 = 0;
+
+	if (x->dir == XFRM_SA_DIR_OUT)
+		ret = nla_put_u32(skb, XFRMA_IPTFS_PKT_SIZE, xc->pkt_size);
+
+	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");
+MODULE_DESCRIPTION("IP-TFS support for xfrm ipsec tunnels");