1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Unstable Conntrack Helpers for XDP and TC-BPF hook
4 * These are called from the XDP and SCHED_CLS BPF programs. Note that it is
5 * allowed to break compatibility for these functions since the interface they
6 * are exposed through to BPF programs is explicitly unstable.
10 #include <linux/btf.h>
11 #include <linux/types.h>
12 #include <linux/btf_ids.h>
13 #include <linux/net_namespace.h>
14 #include <net/netfilter/nf_conntrack.h>
15 #include <net/netfilter/nf_conntrack_bpf.h>
16 #include <net/netfilter/nf_conntrack_core.h>
18 /* bpf_ct_opts - Options for CT lookup helpers
21 * @netns_id - Specify the network namespace for lookup
23 * BPF_F_CURRENT_NETNS (-1)
24 * Use namespace associated with ctx (xdp_md, __sk_buff)
26 * Network Namespace ID
27 * @error - Out parameter, set for any errors encountered
29 * -EINVAL - Passed NULL for bpf_tuple pointer
30 * -EINVAL - opts->reserved is not 0
31 * -EINVAL - netns_id is less than -1
32 * -EINVAL - opts__sz isn't NF_BPF_CT_OPTS_SZ (12)
33 * -EPROTO - l4proto isn't one of IPPROTO_TCP or IPPROTO_UDP
34 * -ENONET - No network namespace found for netns_id
35 * -ENOENT - Conntrack lookup could not find entry for tuple
36 * -EAFNOSUPPORT - tuple__sz isn't one of sizeof(tuple->ipv4)
37 * or sizeof(tuple->ipv6)
38 * @l4proto - Layer 4 protocol
40 * IPPROTO_TCP, IPPROTO_UDP
41 * @dir: - connection tracking tuple direction.
42 * @reserved - Reserved member, will be reused for more options in future
55 NF_BPF_CT_OPTS_SZ = 12,
58 static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,
59 struct bpf_sock_tuple *bpf_tuple,
60 u32 tuple_len, u8 protonum,
61 s32 netns_id, u8 *dir)
63 struct nf_conntrack_tuple_hash *hash;
64 struct nf_conntrack_tuple tuple;
67 if (unlikely(protonum != IPPROTO_TCP && protonum != IPPROTO_UDP))
68 return ERR_PTR(-EPROTO);
69 if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
70 return ERR_PTR(-EINVAL);
72 memset(&tuple, 0, sizeof(tuple));
74 case sizeof(bpf_tuple->ipv4):
75 tuple.src.l3num = AF_INET;
76 tuple.src.u3.ip = bpf_tuple->ipv4.saddr;
77 tuple.src.u.tcp.port = bpf_tuple->ipv4.sport;
78 tuple.dst.u3.ip = bpf_tuple->ipv4.daddr;
79 tuple.dst.u.tcp.port = bpf_tuple->ipv4.dport;
81 case sizeof(bpf_tuple->ipv6):
82 tuple.src.l3num = AF_INET6;
83 memcpy(tuple.src.u3.ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr));
84 tuple.src.u.tcp.port = bpf_tuple->ipv6.sport;
85 memcpy(tuple.dst.u3.ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr));
86 tuple.dst.u.tcp.port = bpf_tuple->ipv6.dport;
89 return ERR_PTR(-EAFNOSUPPORT);
92 tuple.dst.protonum = protonum;
95 net = get_net_ns_by_id(net, netns_id);
97 return ERR_PTR(-ENONET);
100 hash = nf_conntrack_find_get(net, &nf_ct_zone_dflt, &tuple);
104 return ERR_PTR(-ENOENT);
106 ct = nf_ct_tuplehash_to_ctrack(hash);
108 *dir = NF_CT_DIRECTION(hash);
114 __diag_ignore_all("-Wmissing-prototypes",
115 "Global functions as their definitions will be in nf_conntrack BTF");
117 /* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a
121 * @xdp_ctx - Pointer to ctx (xdp_md) in XDP program
123 * @bpf_tuple - Pointer to memory representing the tuple to look up
125 * @tuple__sz - Length of the tuple structure
126 * Must be one of sizeof(bpf_tuple->ipv4) or
127 * sizeof(bpf_tuple->ipv6)
128 * @opts - Additional options for lookup (documented above)
130 * @opts__sz - Length of the bpf_ct_opts structure
131 * Must be NF_BPF_CT_OPTS_SZ (12)
134 bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
135 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
137 struct xdp_buff *ctx = (struct xdp_buff *)xdp_ctx;
138 struct net *caller_net;
139 struct nf_conn *nfct;
141 BUILD_BUG_ON(sizeof(struct bpf_ct_opts) != NF_BPF_CT_OPTS_SZ);
145 if (!bpf_tuple || opts->reserved[0] || opts->reserved[1] ||
146 opts__sz != NF_BPF_CT_OPTS_SZ) {
147 opts->error = -EINVAL;
150 caller_net = dev_net(ctx->rxq->dev);
151 nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts->l4proto,
152 opts->netns_id, &opts->dir);
154 opts->error = PTR_ERR(nfct);
160 /* bpf_skb_ct_lookup - Lookup CT entry for the given tuple, and acquire a
164 * @skb_ctx - Pointer to ctx (__sk_buff) in TC program
166 * @bpf_tuple - Pointer to memory representing the tuple to look up
168 * @tuple__sz - Length of the tuple structure
169 * Must be one of sizeof(bpf_tuple->ipv4) or
170 * sizeof(bpf_tuple->ipv6)
171 * @opts - Additional options for lookup (documented above)
173 * @opts__sz - Length of the bpf_ct_opts structure
174 * Must be NF_BPF_CT_OPTS_SZ (12)
177 bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
178 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
180 struct sk_buff *skb = (struct sk_buff *)skb_ctx;
181 struct net *caller_net;
182 struct nf_conn *nfct;
184 BUILD_BUG_ON(sizeof(struct bpf_ct_opts) != NF_BPF_CT_OPTS_SZ);
188 if (!bpf_tuple || opts->reserved[0] || opts->reserved[1] ||
189 opts__sz != NF_BPF_CT_OPTS_SZ) {
190 opts->error = -EINVAL;
193 caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
194 nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts->l4proto,
195 opts->netns_id, &opts->dir);
197 opts->error = PTR_ERR(nfct);
203 /* bpf_ct_release - Release acquired nf_conn object
205 * This must be invoked for referenced PTR_TO_BTF_ID, and the verifier rejects
206 * the program if any references remain in the program in all of the explored
210 * @nf_conn - Pointer to referenced nf_conn object, obtained using
211 * bpf_xdp_ct_lookup or bpf_skb_ct_lookup.
213 void bpf_ct_release(struct nf_conn *nfct)
222 BTF_SET_START(nf_ct_xdp_check_kfunc_ids)
223 BTF_ID(func, bpf_xdp_ct_lookup)
224 BTF_ID(func, bpf_ct_release)
225 BTF_SET_END(nf_ct_xdp_check_kfunc_ids)
227 BTF_SET_START(nf_ct_tc_check_kfunc_ids)
228 BTF_ID(func, bpf_skb_ct_lookup)
229 BTF_ID(func, bpf_ct_release)
230 BTF_SET_END(nf_ct_tc_check_kfunc_ids)
232 BTF_SET_START(nf_ct_acquire_kfunc_ids)
233 BTF_ID(func, bpf_xdp_ct_lookup)
234 BTF_ID(func, bpf_skb_ct_lookup)
235 BTF_SET_END(nf_ct_acquire_kfunc_ids)
237 BTF_SET_START(nf_ct_release_kfunc_ids)
238 BTF_ID(func, bpf_ct_release)
239 BTF_SET_END(nf_ct_release_kfunc_ids)
241 /* Both sets are identical */
242 #define nf_ct_ret_null_kfunc_ids nf_ct_acquire_kfunc_ids
244 static const struct btf_kfunc_id_set nf_conntrack_xdp_kfunc_set = {
245 .owner = THIS_MODULE,
246 .check_set = &nf_ct_xdp_check_kfunc_ids,
247 .acquire_set = &nf_ct_acquire_kfunc_ids,
248 .release_set = &nf_ct_release_kfunc_ids,
249 .ret_null_set = &nf_ct_ret_null_kfunc_ids,
252 static const struct btf_kfunc_id_set nf_conntrack_tc_kfunc_set = {
253 .owner = THIS_MODULE,
254 .check_set = &nf_ct_tc_check_kfunc_ids,
255 .acquire_set = &nf_ct_acquire_kfunc_ids,
256 .release_set = &nf_ct_release_kfunc_ids,
257 .ret_null_set = &nf_ct_ret_null_kfunc_ids,
260 int register_nf_conntrack_bpf(void)
264 ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &nf_conntrack_xdp_kfunc_set);
265 return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &nf_conntrack_tc_kfunc_set);