Skip to content

Commit 8f0ec8c

Browse files
danobiAlexei Starovoitov
authored andcommitted
bpf: xfrm: Add bpf_xdp_get_xfrm_state() kfunc
This commit adds an unstable kfunc helper to access internal xfrm_state associated with an SA. This is intended to be used for the upcoming IPsec pcpu work to assign special pcpu SAs to a particular CPU. In other words: for custom software RSS. That being said, the function that this kfunc wraps is fairly generic and used for a lot of xfrm tasks. I'm sure people will find uses elsewhere over time. This commit also adds a corresponding bpf_xdp_xfrm_state_release() kfunc to release the refcnt acquired by bpf_xdp_get_xfrm_state(). The verifier will require that all acquired xfrm_state's are released. Co-developed-by: Antony Antony <[email protected]> Signed-off-by: Antony Antony <[email protected]> Acked-by: Steffen Klassert <[email protected]> Signed-off-by: Daniel Xu <[email protected]> Link: https://lore.kernel.org/r/a29699c42f5fad456b875c98dd11c6afc3ffb707.1702593901.git.dxu@dxuuu.xyz Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 56925f3 commit 8f0ec8c

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

include/net/xfrm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,4 +2190,13 @@ static inline int register_xfrm_interface_bpf(void)
21902190

21912191
#endif
21922192

2193+
#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF)
2194+
int register_xfrm_state_bpf(void);
2195+
#else
2196+
static inline int register_xfrm_state_bpf(void)
2197+
{
2198+
return 0;
2199+
}
2200+
#endif
2201+
21932202
#endif /* _NET_XFRM_H */

net/xfrm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ obj-$(CONFIG_XFRM_USER_COMPAT) += xfrm_compat.o
2121
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
2222
obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o
2323
obj-$(CONFIG_XFRM_ESPINTCP) += espintcp.o
24+
obj-$(CONFIG_DEBUG_INFO_BTF) += xfrm_state_bpf.o

net/xfrm/xfrm_policy.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4218,6 +4218,8 @@ void __init xfrm_init(void)
42184218
#ifdef CONFIG_XFRM_ESPINTCP
42194219
espintcp_init();
42204220
#endif
4221+
4222+
register_xfrm_state_bpf();
42214223
}
42224224

42234225
#ifdef CONFIG_AUDITSYSCALL

net/xfrm/xfrm_state_bpf.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Unstable XFRM state BPF helpers.
3+
*
4+
* Note that it is allowed to break compatibility for these functions since the
5+
* interface they are exposed through to BPF programs is explicitly unstable.
6+
*/
7+
8+
#include <linux/bpf.h>
9+
#include <linux/btf.h>
10+
#include <linux/btf_ids.h>
11+
#include <net/xdp.h>
12+
#include <net/xfrm.h>
13+
14+
/* bpf_xfrm_state_opts - Options for XFRM state lookup helpers
15+
*
16+
* Members:
17+
* @error - Out parameter, set for any errors encountered
18+
* Values:
19+
* -EINVAL - netns_id is less than -1
20+
* -EINVAL - opts__sz isn't BPF_XFRM_STATE_OPTS_SZ
21+
* -ENONET - No network namespace found for netns_id
22+
* -ENOENT - No xfrm_state found
23+
* @netns_id - Specify the network namespace for lookup
24+
* Values:
25+
* BPF_F_CURRENT_NETNS (-1)
26+
* Use namespace associated with ctx
27+
* [0, S32_MAX]
28+
* Network Namespace ID
29+
* @mark - XFRM mark to match on
30+
* @daddr - Destination address to match on
31+
* @spi - Security parameter index to match on
32+
* @proto - IP protocol to match on (eg. IPPROTO_ESP)
33+
* @family - Protocol family to match on (AF_INET/AF_INET6)
34+
*/
35+
struct bpf_xfrm_state_opts {
36+
s32 error;
37+
s32 netns_id;
38+
u32 mark;
39+
xfrm_address_t daddr;
40+
__be32 spi;
41+
u8 proto;
42+
u16 family;
43+
};
44+
45+
enum {
46+
BPF_XFRM_STATE_OPTS_SZ = sizeof(struct bpf_xfrm_state_opts),
47+
};
48+
49+
__bpf_kfunc_start_defs();
50+
51+
/* bpf_xdp_get_xfrm_state - Get XFRM state
52+
*
53+
* A `struct xfrm_state *`, if found, must be released with a corresponding
54+
* bpf_xdp_xfrm_state_release.
55+
*
56+
* Parameters:
57+
* @ctx - Pointer to ctx (xdp_md) in XDP program
58+
* Cannot be NULL
59+
* @opts - Options for lookup (documented above)
60+
* Cannot be NULL
61+
* @opts__sz - Length of the bpf_xfrm_state_opts structure
62+
* Must be BPF_XFRM_STATE_OPTS_SZ
63+
*/
64+
__bpf_kfunc struct xfrm_state *
65+
bpf_xdp_get_xfrm_state(struct xdp_md *ctx, struct bpf_xfrm_state_opts *opts, u32 opts__sz)
66+
{
67+
struct xdp_buff *xdp = (struct xdp_buff *)ctx;
68+
struct net *net = dev_net(xdp->rxq->dev);
69+
struct xfrm_state *x;
70+
71+
if (!opts || opts__sz < sizeof(opts->error))
72+
return NULL;
73+
74+
if (opts__sz != BPF_XFRM_STATE_OPTS_SZ) {
75+
opts->error = -EINVAL;
76+
return NULL;
77+
}
78+
79+
if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS)) {
80+
opts->error = -EINVAL;
81+
return NULL;
82+
}
83+
84+
if (opts->netns_id >= 0) {
85+
net = get_net_ns_by_id(net, opts->netns_id);
86+
if (unlikely(!net)) {
87+
opts->error = -ENONET;
88+
return NULL;
89+
}
90+
}
91+
92+
x = xfrm_state_lookup(net, opts->mark, &opts->daddr, opts->spi,
93+
opts->proto, opts->family);
94+
95+
if (opts->netns_id >= 0)
96+
put_net(net);
97+
if (!x)
98+
opts->error = -ENOENT;
99+
100+
return x;
101+
}
102+
103+
/* bpf_xdp_xfrm_state_release - Release acquired xfrm_state object
104+
*
105+
* This must be invoked for referenced PTR_TO_BTF_ID, and the verifier rejects
106+
* the program if any references remain in the program in all of the explored
107+
* states.
108+
*
109+
* Parameters:
110+
* @x - Pointer to referenced xfrm_state object, obtained using
111+
* bpf_xdp_get_xfrm_state.
112+
*/
113+
__bpf_kfunc void bpf_xdp_xfrm_state_release(struct xfrm_state *x)
114+
{
115+
xfrm_state_put(x);
116+
}
117+
118+
__bpf_kfunc_end_defs();
119+
120+
BTF_SET8_START(xfrm_state_kfunc_set)
121+
BTF_ID_FLAGS(func, bpf_xdp_get_xfrm_state, KF_RET_NULL | KF_ACQUIRE)
122+
BTF_ID_FLAGS(func, bpf_xdp_xfrm_state_release, KF_RELEASE)
123+
BTF_SET8_END(xfrm_state_kfunc_set)
124+
125+
static const struct btf_kfunc_id_set xfrm_state_xdp_kfunc_set = {
126+
.owner = THIS_MODULE,
127+
.set = &xfrm_state_kfunc_set,
128+
};
129+
130+
int __init register_xfrm_state_bpf(void)
131+
{
132+
return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
133+
&xfrm_state_xdp_kfunc_set);
134+
}

0 commit comments

Comments
 (0)