Skip to content

Commit 62fdd17

Browse files
committed
Merge tag 'ipsec-next-2024-07-13' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2024-07-13 1) Support sending NAT keepalives in ESP in UDP states. Userspace IKE daemon had to do this before, but the kernel can better keep track of it. From Eyal Birger. 2) Support IPsec crypto offload for IPv6 ESP and IPv4 UDP-encapsulated ESP data paths. Currently, IPsec crypto offload is enabled for GRO code path only. This patchset support UDP encapsulation for the non GRO path. From Mike Yu. * tag 'ipsec-next-2024-07-13' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next: xfrm: Support crypto offload for outbound IPv4 UDP-encapsulated ESP packet xfrm: Support crypto offload for inbound IPv4 UDP-encapsulated ESP packet xfrm: Allow UDP encapsulation in crypto offload control path xfrm: Support crypto offload for inbound IPv6 ESP packets not in GRO path xfrm: support sending NAT keepalives in ESP in UDP states ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents ecb1e1d + d5b60c6 commit 62fdd17

File tree

16 files changed

+393
-10
lines changed

16 files changed

+393
-10
lines changed

include/net/ipv6_stubs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <net/flow.h>
1010
#include <net/neighbour.h>
1111
#include <net/sock.h>
12+
#include <net/ipv6.h>
1213

1314
/* structs from net/ip6_fib.h */
1415
struct fib6_info;
@@ -72,6 +73,8 @@ struct ipv6_stub {
7273
int (*output)(struct net *, struct sock *, struct sk_buff *));
7374
struct net_device *(*ipv6_dev_find)(struct net *net, const struct in6_addr *addr,
7475
struct net_device *dev);
76+
int (*ip6_xmit)(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
77+
__u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority);
7578
};
7679
extern const struct ipv6_stub *ipv6_stub __read_mostly;
7780

include/net/netns/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct netns_xfrm {
8383

8484
spinlock_t xfrm_policy_lock;
8585
struct mutex xfrm_cfg_mutex;
86+
struct delayed_work nat_keepalive_work;
8687
};
8788

8889
#endif

include/net/xfrm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ struct xfrm_state {
229229
struct xfrm_encap_tmpl *encap;
230230
struct sock __rcu *encap_sk;
231231

232+
/* NAT keepalive */
233+
u32 nat_keepalive_interval; /* seconds */
234+
time64_t nat_keepalive_expiration;
235+
232236
/* Data for care-of address */
233237
xfrm_address_t *coaddr;
234238

@@ -2203,4 +2207,10 @@ static inline int register_xfrm_state_bpf(void)
22032207
}
22042208
#endif
22052209

2210+
int xfrm_nat_keepalive_init(unsigned short family);
2211+
void xfrm_nat_keepalive_fini(unsigned short family);
2212+
int xfrm_nat_keepalive_net_init(struct net *net);
2213+
int xfrm_nat_keepalive_net_fini(struct net *net);
2214+
void xfrm_nat_keepalive_state_updated(struct xfrm_state *x);
2215+
22062216
#endif /* _NET_XFRM_H */

include/uapi/linux/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ enum xfrm_attr_type_t {
321321
XFRMA_IF_ID, /* __u32 */
322322
XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */
323323
XFRMA_SA_DIR, /* __u8 */
324+
XFRMA_NAT_KEEPALIVE_INTERVAL, /* __u32 in seconds for NAT keepalive */
324325
__XFRMA_MAX
325326

326327
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */

net/ipv4/esp4.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
349349
{
350350
struct udphdr *uh;
351351
unsigned int len;
352+
struct xfrm_offload *xo = xfrm_offload(skb);
352353

353354
len = skb->len + esp->tailen - skb_transport_offset(skb);
354355
if (len + sizeof(struct iphdr) > IP_MAX_MTU)
@@ -360,7 +361,12 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
360361
uh->len = htons(len);
361362
uh->check = 0;
362363

363-
*skb_mac_header(skb) = IPPROTO_UDP;
364+
/* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload
365+
* data path, which means that esp_output_udp_encap is called outside of the XFRM stack.
366+
* In this case, the mac header doesn't point to the IPv4 protocol field, so don't set it.
367+
*/
368+
if (!xo || encap_type != UDP_ENCAP_ESPINUDP)
369+
*skb_mac_header(skb) = IPPROTO_UDP;
364370

365371
return (struct ip_esp_hdr *)(uh + 1);
366372
}

net/ipv4/esp4_offload.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
264264
struct esp_info esp;
265265
bool hw_offload = true;
266266
__u32 seq;
267+
int encap_type = 0;
267268

268269
esp.inplace = true;
269270

@@ -296,8 +297,10 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
296297

297298
esp.esph = ip_esp_hdr(skb);
298299

300+
if (x->encap)
301+
encap_type = x->encap->encap_type;
299302

300-
if (!hw_offload || !skb_is_gso(skb)) {
303+
if (!hw_offload || !skb_is_gso(skb) || (hw_offload && encap_type == UDP_ENCAP_ESPINUDP)) {
301304
esp.nfrags = esp_output_head(x, skb, &esp);
302305
if (esp.nfrags < 0)
303306
return esp.nfrags;
@@ -324,6 +327,18 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
324327

325328
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
326329

330+
if (hw_offload && encap_type == UDP_ENCAP_ESPINUDP) {
331+
/* In the XFRM stack, the encapsulation protocol is set to iphdr->protocol by
332+
* setting *skb_mac_header(skb) (see esp_output_udp_encap()) where skb->mac_header
333+
* points to iphdr->protocol (see xfrm4_tunnel_encap_add()).
334+
* However, in esp_xmit(), skb->mac_header doesn't point to iphdr->protocol.
335+
* Therefore, the protocol field needs to be corrected.
336+
*/
337+
ip_hdr(skb)->protocol = IPPROTO_UDP;
338+
339+
esph->seq_no = htonl(seq);
340+
}
341+
327342
ip_hdr(skb)->tot_len = htons(skb->len);
328343
ip_send_check(ip_hdr(skb));
329344

net/ipv6/af_inet6.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
10601060
.nd_tbl = &nd_tbl,
10611061
.ipv6_fragment = ip6_fragment,
10621062
.ipv6_dev_find = ipv6_dev_find,
1063+
.ip6_xmit = ip6_xmit,
10631064
};
10641065

10651066
static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {

net/ipv6/xfrm6_policy.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,14 @@ int __init xfrm6_init(void)
290290
ret = register_pernet_subsys(&xfrm6_net_ops);
291291
if (ret)
292292
goto out_protocol;
293+
294+
ret = xfrm_nat_keepalive_init(AF_INET6);
295+
if (ret)
296+
goto out_nat_keepalive;
293297
out:
294298
return ret;
299+
out_nat_keepalive:
300+
unregister_pernet_subsys(&xfrm6_net_ops);
295301
out_protocol:
296302
xfrm6_protocol_fini();
297303
out_state:
@@ -303,6 +309,7 @@ int __init xfrm6_init(void)
303309

304310
void xfrm6_fini(void)
305311
{
312+
xfrm_nat_keepalive_fini(AF_INET6);
306313
unregister_pernet_subsys(&xfrm6_net_ops);
307314
xfrm6_protocol_fini();
308315
xfrm6_policy_fini();

net/xfrm/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ endif
1313

1414
obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
1515
xfrm_input.o xfrm_output.o \
16-
xfrm_sysctl.o xfrm_replay.o xfrm_device.o
16+
xfrm_sysctl.o xfrm_replay.o xfrm_device.o \
17+
xfrm_nat_keepalive.o
1718
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
1819
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
1920
obj-$(CONFIG_XFRM_USER) += xfrm_user.o

net/xfrm/xfrm_compat.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
131131
[XFRMA_IF_ID] = { .type = NLA_U32 },
132132
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
133133
[XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT),
134+
[XFRMA_NAT_KEEPALIVE_INTERVAL] = { .type = NLA_U32 },
134135
};
135136

136137
static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
@@ -280,9 +281,10 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
280281
case XFRMA_IF_ID:
281282
case XFRMA_MTIMER_THRESH:
282283
case XFRMA_SA_DIR:
284+
case XFRMA_NAT_KEEPALIVE_INTERVAL:
283285
return xfrm_nla_cpy(dst, src, nla_len(src));
284286
default:
285-
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
287+
BUILD_BUG_ON(XFRMA_MAX != XFRMA_NAT_KEEPALIVE_INTERVAL);
286288
pr_warn_once("unsupported nla_type %d\n", src->nla_type);
287289
return -EOPNOTSUPP;
288290
}
@@ -437,7 +439,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
437439
int err;
438440

439441
if (type > XFRMA_MAX) {
440-
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
442+
BUILD_BUG_ON(XFRMA_MAX != XFRMA_NAT_KEEPALIVE_INTERVAL);
441443
NL_SET_ERR_MSG(extack, "Bad attribute");
442444
return -EOPNOTSUPP;
443445
}

0 commit comments

Comments
 (0)