Skip to content

Commit

Permalink
xfrm: support sending NAT keepalives in ESP in UDP states
Browse files Browse the repository at this point in the history
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 <paul@nohats.ca>
Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
Signed-off-by: NipaLocal <nipa@local>
  • Loading branch information
ebirger authored and NipaLocal committed Dec 11, 2023
1 parent 0e1c441 commit 7028b7a
Show file tree
Hide file tree
Showing 12 changed files with 356 additions and 4 deletions.
3 changes: 3 additions & 0 deletions include/net/ipv6_stubs.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <net/flow.h>
#include <net/neighbour.h>
#include <net/sock.h>
#include <net/ipv6.h>

/* structs from net/ip6_fib.h */
struct fib6_info;
Expand Down Expand Up @@ -72,6 +73,8 @@ struct ipv6_stub {
int (*output)(struct net *, struct sock *, struct sk_buff *));
struct net_device *(*ipv6_dev_find)(struct net *net, const struct in6_addr *addr,
struct net_device *dev);
int (*ip6_xmit)(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
__u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority);
};
extern const struct ipv6_stub *ipv6_stub __read_mostly;

Expand Down
1 change: 1 addition & 0 deletions include/net/netns/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct netns_xfrm {

spinlock_t xfrm_policy_lock;
struct mutex xfrm_cfg_mutex;
struct delayed_work nat_keepalive_work;
};

#endif
10 changes: 10 additions & 0 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ struct xfrm_state {
struct xfrm_encap_tmpl *encap;
struct sock __rcu *encap_sk;

/* NAT keepalive */
u32 nat_keepalive_interval; /* seconds */
time64_t nat_keepalive_expiration;

/* Data for care-of address */
xfrm_address_t *coaddr;

Expand Down Expand Up @@ -2190,4 +2194,10 @@ static inline int register_xfrm_interface_bpf(void)

#endif

int xfrm_nat_keepalive_init(unsigned short family);
void xfrm_nat_keepalive_fini(unsigned short family);
int xfrm_nat_keepalive_net_init(struct net *net);
int xfrm_nat_keepalive_net_fini(struct net *net);
void xfrm_nat_keepalive_state_updated(struct xfrm_state *x);

#endif /* _NET_XFRM_H */
1 change: 1 addition & 0 deletions include/uapi/linux/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ enum xfrm_attr_type_t {
XFRMA_SET_MARK_MASK, /* __u32 */
XFRMA_IF_ID, /* __u32 */
XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */
XFRMA_NAT_KEEPALIVE_INTERVAL, /* __u32 in seconds for NAT keepalive */
__XFRMA_MAX

#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
.nd_tbl = &nd_tbl,
.ipv6_fragment = ip6_fragment,
.ipv6_dev_find = ipv6_dev_find,
.ip6_xmit = ip6_xmit,
};

static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
Expand Down
7 changes: 7 additions & 0 deletions net/ipv6/xfrm6_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,14 @@ int __init xfrm6_init(void)
ret = register_pernet_subsys(&xfrm6_net_ops);
if (ret)
goto out_protocol;

ret = xfrm_nat_keepalive_init(AF_INET6);
if (ret)
goto out_nat_keepalive;
out:
return ret;
out_nat_keepalive:
unregister_pernet_subsys(&xfrm6_net_ops);
out_protocol:
xfrm6_protocol_fini();
out_state:
Expand All @@ -298,6 +304,7 @@ int __init xfrm6_init(void)

void xfrm6_fini(void)
{
xfrm_nat_keepalive_fini(AF_INET6);
unregister_pernet_subsys(&xfrm6_net_ops);
xfrm6_protocol_fini();
xfrm6_policy_fini();
Expand Down
3 changes: 2 additions & 1 deletion net/xfrm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ endif

obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
xfrm_input.o xfrm_output.o \
xfrm_sysctl.o xfrm_replay.o xfrm_device.o
xfrm_sysctl.o xfrm_replay.o xfrm_device.o \
xfrm_nat_keepalive.o
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
Expand Down
6 changes: 4 additions & 2 deletions net/xfrm/xfrm_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
[XFRMA_IF_ID] = { .type = NLA_U32 },
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
[XFRMA_NAT_KEEPALIVE_INTERVAL] = { .type = NLA_U32 },
};

static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
Expand Down Expand Up @@ -277,9 +278,10 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
case XFRMA_SET_MARK_MASK:
case XFRMA_IF_ID:
case XFRMA_MTIMER_THRESH:
case XFRMA_NAT_KEEPALIVE_INTERVAL:
return xfrm_nla_cpy(dst, src, nla_len(src));
default:
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
BUILD_BUG_ON(XFRMA_MAX != XFRMA_NAT_KEEPALIVE_INTERVAL);
pr_warn_once("unsupported nla_type %d\n", src->nla_type);
return -EOPNOTSUPP;
}
Expand Down Expand Up @@ -434,7 +436,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
int err;

if (type > XFRMA_MAX) {
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
BUILD_BUG_ON(XFRMA_MAX != XFRMA_NAT_KEEPALIVE_INTERVAL);
NL_SET_ERR_MSG(extack, "Bad attribute");
return -EOPNOTSUPP;
}
Expand Down
Loading

0 comments on commit 7028b7a

Please sign in to comment.