Skip to content

Commit f531d13

Browse files
ebirgerklassert
authored andcommitted
xfrm: support sending NAT keepalives in ESP in UDP states
Add the ability to send out RFC-3948 NAT keepalives from the xfrm stack. To use, Userspace sets an XFRM_NAT_KEEPALIVE_INTERVAL integer property when creating XFRM outbound states which denotes the number of seconds between keepalive messages. Keepalive messages are sent from a per net delayed work which iterates over the xfrm states. The logic is guarded by the xfrm state spinlock due to the xfrm state walk iterator. Possible future enhancements: - Adding counters to keep track of sent keepalives. - deduplicate NAT keepalives between states sharing the same nat keepalive parameters. - provisioning hardware offloads for devices capable of implementing this. - revise xfrm state list to use an rcu list in order to avoid running this under spinlock. Suggested-by: Paul Wouters <[email protected]> Tested-by: Paul Wouters <[email protected]> Tested-by: Antony Antony <[email protected]> Signed-off-by: Eyal Birger <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 5233a55 commit f531d13

File tree

12 files changed

+361
-3
lines changed

12 files changed

+361
-3
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/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
@@ -284,8 +284,14 @@ int __init xfrm6_init(void)
284284
ret = register_pernet_subsys(&xfrm6_net_ops);
285285
if (ret)
286286
goto out_protocol;
287+
288+
ret = xfrm_nat_keepalive_init(AF_INET6);
289+
if (ret)
290+
goto out_nat_keepalive;
287291
out:
288292
return ret;
293+
out_nat_keepalive:
294+
unregister_pernet_subsys(&xfrm6_net_ops);
289295
out_protocol:
290296
xfrm6_protocol_fini();
291297
out_state:
@@ -297,6 +303,7 @@ int __init xfrm6_init(void)
297303

298304
void xfrm6_fini(void)
299305
{
306+
xfrm_nat_keepalive_fini(AF_INET6);
300307
unregister_pernet_subsys(&xfrm6_net_ops);
301308
xfrm6_protocol_fini();
302309
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)