Skip to content

Commit 4b3faf6

Browse files
choppsv1klassert
authored andcommitted
xfrm: iptfs: add new iptfs xfrm mode impl
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 <[email protected]> Tested-by: Antony Antony <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent d1716d5 commit 4b3faf6

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

net/xfrm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ obj-$(CONFIG_XFRM_USER) += xfrm_user.o
2121
obj-$(CONFIG_XFRM_USER_COMPAT) += xfrm_compat.o
2222
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
2323
obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o
24+
obj-$(CONFIG_XFRM_IPTFS) += xfrm_iptfs.o
2425
obj-$(CONFIG_XFRM_ESPINTCP) += espintcp.o
2526
obj-$(CONFIG_DEBUG_INFO_BTF) += xfrm_state_bpf.o

net/xfrm/xfrm_iptfs.c

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* xfrm_iptfs: IPTFS encapsulation support
3+
*
4+
* April 21 2022, Christian Hopps <[email protected]>
5+
*
6+
* Copyright (c) 2022, LabN Consulting, L.L.C.
7+
*
8+
*/
9+
10+
#include <linux/kernel.h>
11+
#include <linux/icmpv6.h>
12+
#include <net/gro.h>
13+
#include <net/icmp.h>
14+
#include <net/ip6_route.h>
15+
#include <net/inet_ecn.h>
16+
#include <net/xfrm.h>
17+
18+
#include <crypto/aead.h>
19+
20+
#include "xfrm_inout.h"
21+
22+
/**
23+
* struct xfrm_iptfs_config - configuration for the IPTFS tunnel.
24+
* @pkt_size: size of the outer IP packet. 0 to use interface and MTU discovery,
25+
* otherwise the user specified value.
26+
*/
27+
struct xfrm_iptfs_config {
28+
u32 pkt_size; /* outer_packet_size or 0 */
29+
};
30+
31+
/**
32+
* struct xfrm_iptfs_data - mode specific xfrm state.
33+
* @cfg: IPTFS tunnel config.
34+
* @x: owning SA (xfrm_state).
35+
* @payload_mtu: max payload size.
36+
*/
37+
struct xfrm_iptfs_data {
38+
struct xfrm_iptfs_config cfg;
39+
40+
/* Ingress User Input */
41+
struct xfrm_state *x; /* owning state */
42+
u32 payload_mtu; /* max payload size */
43+
};
44+
45+
/* ========================== */
46+
/* State Management Functions */
47+
/* ========================== */
48+
49+
/**
50+
* iptfs_get_inner_mtu() - return inner MTU with no fragmentation.
51+
* @x: xfrm state.
52+
* @outer_mtu: the outer mtu
53+
*/
54+
static u32 iptfs_get_inner_mtu(struct xfrm_state *x, int outer_mtu)
55+
{
56+
struct crypto_aead *aead;
57+
u32 blksize;
58+
59+
aead = x->data;
60+
blksize = ALIGN(crypto_aead_blocksize(aead), 4);
61+
return ((outer_mtu - x->props.header_len - crypto_aead_authsize(aead)) &
62+
~(blksize - 1)) - 2;
63+
}
64+
65+
/**
66+
* iptfs_user_init() - initialize the SA with IPTFS options from netlink.
67+
* @net: the net data
68+
* @x: xfrm state
69+
* @attrs: netlink attributes
70+
* @extack: extack return data
71+
*
72+
* Return: 0 on success or a negative error code on failure
73+
*/
74+
static int iptfs_user_init(struct net *net, struct xfrm_state *x,
75+
struct nlattr **attrs,
76+
struct netlink_ext_ack *extack)
77+
{
78+
struct xfrm_iptfs_data *xtfs = x->mode_data;
79+
struct xfrm_iptfs_config *xc;
80+
81+
xc = &xtfs->cfg;
82+
83+
if (attrs[XFRMA_IPTFS_PKT_SIZE]) {
84+
xc->pkt_size = nla_get_u32(attrs[XFRMA_IPTFS_PKT_SIZE]);
85+
if (!xc->pkt_size) {
86+
xtfs->payload_mtu = 0;
87+
} else if (xc->pkt_size > x->props.header_len) {
88+
xtfs->payload_mtu = xc->pkt_size - x->props.header_len;
89+
} else {
90+
NL_SET_ERR_MSG(extack,
91+
"Packet size must be 0 or greater than IPTFS/ESP header length");
92+
return -EINVAL;
93+
}
94+
}
95+
return 0;
96+
}
97+
98+
static unsigned int iptfs_sa_len(const struct xfrm_state *x)
99+
{
100+
struct xfrm_iptfs_data *xtfs = x->mode_data;
101+
struct xfrm_iptfs_config *xc = &xtfs->cfg;
102+
unsigned int l = 0;
103+
104+
if (x->dir == XFRM_SA_DIR_OUT)
105+
l += nla_total_size(sizeof(xc->pkt_size));
106+
107+
return l;
108+
}
109+
110+
static int iptfs_copy_to_user(struct xfrm_state *x, struct sk_buff *skb)
111+
{
112+
struct xfrm_iptfs_data *xtfs = x->mode_data;
113+
struct xfrm_iptfs_config *xc = &xtfs->cfg;
114+
int ret = 0;
115+
116+
if (x->dir == XFRM_SA_DIR_OUT)
117+
ret = nla_put_u32(skb, XFRMA_IPTFS_PKT_SIZE, xc->pkt_size);
118+
119+
return ret;
120+
}
121+
122+
static void __iptfs_init_state(struct xfrm_state *x,
123+
struct xfrm_iptfs_data *xtfs)
124+
{
125+
/* Modify type (esp) adjustment values */
126+
127+
if (x->props.family == AF_INET)
128+
x->props.header_len += sizeof(struct iphdr) + sizeof(struct ip_iptfs_hdr);
129+
else if (x->props.family == AF_INET6)
130+
x->props.header_len += sizeof(struct ipv6hdr) + sizeof(struct ip_iptfs_hdr);
131+
x->props.enc_hdr_len = sizeof(struct ip_iptfs_hdr);
132+
133+
/* Always keep a module reference when x->mode_data is set */
134+
__module_get(x->mode_cbs->owner);
135+
136+
x->mode_data = xtfs;
137+
xtfs->x = x;
138+
}
139+
140+
static int iptfs_clone_state(struct xfrm_state *x, struct xfrm_state *orig)
141+
{
142+
struct xfrm_iptfs_data *xtfs;
143+
144+
xtfs = kmemdup(orig->mode_data, sizeof(*xtfs), GFP_KERNEL);
145+
if (!xtfs)
146+
return -ENOMEM;
147+
148+
x->mode_data = xtfs;
149+
xtfs->x = x;
150+
151+
return 0;
152+
}
153+
154+
static int iptfs_init_state(struct xfrm_state *x)
155+
{
156+
struct xfrm_iptfs_data *xtfs;
157+
158+
if (x->mode_data) {
159+
/* We have arrived here from xfrm_state_clone() */
160+
xtfs = x->mode_data;
161+
} else {
162+
xtfs = kzalloc(sizeof(*xtfs), GFP_KERNEL);
163+
if (!xtfs)
164+
return -ENOMEM;
165+
}
166+
167+
__iptfs_init_state(x, xtfs);
168+
169+
return 0;
170+
}
171+
172+
static void iptfs_destroy_state(struct xfrm_state *x)
173+
{
174+
struct xfrm_iptfs_data *xtfs = x->mode_data;
175+
176+
if (!xtfs)
177+
return;
178+
179+
kfree_sensitive(xtfs);
180+
181+
module_put(x->mode_cbs->owner);
182+
}
183+
184+
static const struct xfrm_mode_cbs iptfs_mode_cbs = {
185+
.owner = THIS_MODULE,
186+
.init_state = iptfs_init_state,
187+
.clone_state = iptfs_clone_state,
188+
.destroy_state = iptfs_destroy_state,
189+
.user_init = iptfs_user_init,
190+
.copy_to_user = iptfs_copy_to_user,
191+
.sa_len = iptfs_sa_len,
192+
.get_inner_mtu = iptfs_get_inner_mtu,
193+
};
194+
195+
static int __init xfrm_iptfs_init(void)
196+
{
197+
int err;
198+
199+
pr_info("xfrm_iptfs: IPsec IP-TFS tunnel mode module\n");
200+
201+
err = xfrm_register_mode_cbs(XFRM_MODE_IPTFS, &iptfs_mode_cbs);
202+
if (err < 0)
203+
pr_info("%s: can't register IP-TFS\n", __func__);
204+
205+
return err;
206+
}
207+
208+
static void __exit xfrm_iptfs_fini(void)
209+
{
210+
xfrm_unregister_mode_cbs(XFRM_MODE_IPTFS);
211+
}
212+
213+
module_init(xfrm_iptfs_init);
214+
module_exit(xfrm_iptfs_fini);
215+
MODULE_LICENSE("GPL");
216+
MODULE_DESCRIPTION("IP-TFS support for xfrm ipsec tunnels");

0 commit comments

Comments
 (0)