|
| 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