1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Unstable Conntrack Helpers for XDP and TC-BPF hook 3 * 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. 7 */ 8 9 #include <linux/bpf.h> 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> 17 18 /* bpf_ct_opts - Options for CT lookup helpers 19 * 20 * Members: 21 * @netns_id - Specify the network namespace for lookup 22 * Values: 23 * BPF_F_CURRENT_NETNS (-1) 24 * Use namespace associated with ctx (xdp_md, __sk_buff) 25 * [0, S32_MAX] 26 * Network Namespace ID 27 * @error - Out parameter, set for any errors encountered 28 * Values: 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 39 * Values: 40 * IPPROTO_TCP, IPPROTO_UDP 41 * @reserved - Reserved member, will be reused for more options in future 42 * Values: 43 * 0 44 */ 45 struct bpf_ct_opts { 46 s32 netns_id; 47 s32 error; 48 u8 l4proto; 49 u8 reserved[3]; 50 }; 51 52 enum { 53 NF_BPF_CT_OPTS_SZ = 12, 54 }; 55 56 static struct nf_conn *__bpf_nf_ct_lookup(struct net *net, 57 struct bpf_sock_tuple *bpf_tuple, 58 u32 tuple_len, u8 protonum, 59 s32 netns_id) 60 { 61 struct nf_conntrack_tuple_hash *hash; 62 struct nf_conntrack_tuple tuple; 63 64 if (unlikely(protonum != IPPROTO_TCP && protonum != IPPROTO_UDP)) 65 return ERR_PTR(-EPROTO); 66 if (unlikely(netns_id < BPF_F_CURRENT_NETNS)) 67 return ERR_PTR(-EINVAL); 68 69 memset(&tuple, 0, sizeof(tuple)); 70 switch (tuple_len) { 71 case sizeof(bpf_tuple->ipv4): 72 tuple.src.l3num = AF_INET; 73 tuple.src.u3.ip = bpf_tuple->ipv4.saddr; 74 tuple.src.u.tcp.port = bpf_tuple->ipv4.sport; 75 tuple.dst.u3.ip = bpf_tuple->ipv4.daddr; 76 tuple.dst.u.tcp.port = bpf_tuple->ipv4.dport; 77 break; 78 case sizeof(bpf_tuple->ipv6): 79 tuple.src.l3num = AF_INET6; 80 memcpy(tuple.src.u3.ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr)); 81 tuple.src.u.tcp.port = bpf_tuple->ipv6.sport; 82 memcpy(tuple.dst.u3.ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr)); 83 tuple.dst.u.tcp.port = bpf_tuple->ipv6.dport; 84 break; 85 default: 86 return ERR_PTR(-EAFNOSUPPORT); 87 } 88 89 tuple.dst.protonum = protonum; 90 91 if (netns_id >= 0) { 92 net = get_net_ns_by_id(net, netns_id); 93 if (unlikely(!net)) 94 return ERR_PTR(-ENONET); 95 } 96 97 hash = nf_conntrack_find_get(net, &nf_ct_zone_dflt, &tuple); 98 if (netns_id >= 0) 99 put_net(net); 100 if (!hash) 101 return ERR_PTR(-ENOENT); 102 return nf_ct_tuplehash_to_ctrack(hash); 103 } 104 105 __diag_push(); 106 __diag_ignore_all("-Wmissing-prototypes", 107 "Global functions as their definitions will be in nf_conntrack BTF"); 108 109 /* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a 110 * reference to it 111 * 112 * Parameters: 113 * @xdp_ctx - Pointer to ctx (xdp_md) in XDP program 114 * Cannot be NULL 115 * @bpf_tuple - Pointer to memory representing the tuple to look up 116 * Cannot be NULL 117 * @tuple__sz - Length of the tuple structure 118 * Must be one of sizeof(bpf_tuple->ipv4) or 119 * sizeof(bpf_tuple->ipv6) 120 * @opts - Additional options for lookup (documented above) 121 * Cannot be NULL 122 * @opts__sz - Length of the bpf_ct_opts structure 123 * Must be NF_BPF_CT_OPTS_SZ (12) 124 */ 125 struct nf_conn * 126 bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple, 127 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz) 128 { 129 struct xdp_buff *ctx = (struct xdp_buff *)xdp_ctx; 130 struct net *caller_net; 131 struct nf_conn *nfct; 132 133 BUILD_BUG_ON(sizeof(struct bpf_ct_opts) != NF_BPF_CT_OPTS_SZ); 134 135 if (!opts) 136 return NULL; 137 if (!bpf_tuple || opts->reserved[0] || opts->reserved[1] || 138 opts->reserved[2] || opts__sz != NF_BPF_CT_OPTS_SZ) { 139 opts->error = -EINVAL; 140 return NULL; 141 } 142 caller_net = dev_net(ctx->rxq->dev); 143 nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts->l4proto, 144 opts->netns_id); 145 if (IS_ERR(nfct)) { 146 opts->error = PTR_ERR(nfct); 147 return NULL; 148 } 149 return nfct; 150 } 151 152 /* bpf_skb_ct_lookup - Lookup CT entry for the given tuple, and acquire a 153 * reference to it 154 * 155 * Parameters: 156 * @skb_ctx - Pointer to ctx (__sk_buff) in TC program 157 * Cannot be NULL 158 * @bpf_tuple - Pointer to memory representing the tuple to look up 159 * Cannot be NULL 160 * @tuple__sz - Length of the tuple structure 161 * Must be one of sizeof(bpf_tuple->ipv4) or 162 * sizeof(bpf_tuple->ipv6) 163 * @opts - Additional options for lookup (documented above) 164 * Cannot be NULL 165 * @opts__sz - Length of the bpf_ct_opts structure 166 * Must be NF_BPF_CT_OPTS_SZ (12) 167 */ 168 struct nf_conn * 169 bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple, 170 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz) 171 { 172 struct sk_buff *skb = (struct sk_buff *)skb_ctx; 173 struct net *caller_net; 174 struct nf_conn *nfct; 175 176 BUILD_BUG_ON(sizeof(struct bpf_ct_opts) != NF_BPF_CT_OPTS_SZ); 177 178 if (!opts) 179 return NULL; 180 if (!bpf_tuple || opts->reserved[0] || opts->reserved[1] || 181 opts->reserved[2] || opts__sz != NF_BPF_CT_OPTS_SZ) { 182 opts->error = -EINVAL; 183 return NULL; 184 } 185 caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk); 186 nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts->l4proto, 187 opts->netns_id); 188 if (IS_ERR(nfct)) { 189 opts->error = PTR_ERR(nfct); 190 return NULL; 191 } 192 return nfct; 193 } 194 195 /* bpf_ct_release - Release acquired nf_conn object 196 * 197 * This must be invoked for referenced PTR_TO_BTF_ID, and the verifier rejects 198 * the program if any references remain in the program in all of the explored 199 * states. 200 * 201 * Parameters: 202 * @nf_conn - Pointer to referenced nf_conn object, obtained using 203 * bpf_xdp_ct_lookup or bpf_skb_ct_lookup. 204 */ 205 void bpf_ct_release(struct nf_conn *nfct) 206 { 207 if (!nfct) 208 return; 209 nf_ct_put(nfct); 210 } 211 212 __diag_pop() 213 214 BTF_SET_START(nf_ct_xdp_check_kfunc_ids) 215 BTF_ID(func, bpf_xdp_ct_lookup) 216 BTF_ID(func, bpf_ct_release) 217 BTF_SET_END(nf_ct_xdp_check_kfunc_ids) 218 219 BTF_SET_START(nf_ct_tc_check_kfunc_ids) 220 BTF_ID(func, bpf_skb_ct_lookup) 221 BTF_ID(func, bpf_ct_release) 222 BTF_SET_END(nf_ct_tc_check_kfunc_ids) 223 224 BTF_SET_START(nf_ct_acquire_kfunc_ids) 225 BTF_ID(func, bpf_xdp_ct_lookup) 226 BTF_ID(func, bpf_skb_ct_lookup) 227 BTF_SET_END(nf_ct_acquire_kfunc_ids) 228 229 BTF_SET_START(nf_ct_release_kfunc_ids) 230 BTF_ID(func, bpf_ct_release) 231 BTF_SET_END(nf_ct_release_kfunc_ids) 232 233 /* Both sets are identical */ 234 #define nf_ct_ret_null_kfunc_ids nf_ct_acquire_kfunc_ids 235 236 static const struct btf_kfunc_id_set nf_conntrack_xdp_kfunc_set = { 237 .owner = THIS_MODULE, 238 .check_set = &nf_ct_xdp_check_kfunc_ids, 239 .acquire_set = &nf_ct_acquire_kfunc_ids, 240 .release_set = &nf_ct_release_kfunc_ids, 241 .ret_null_set = &nf_ct_ret_null_kfunc_ids, 242 }; 243 244 static const struct btf_kfunc_id_set nf_conntrack_tc_kfunc_set = { 245 .owner = THIS_MODULE, 246 .check_set = &nf_ct_tc_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, 250 }; 251 252 int register_nf_conntrack_bpf(void) 253 { 254 int ret; 255 256 ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &nf_conntrack_xdp_kfunc_set); 257 return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &nf_conntrack_tc_kfunc_set); 258 } 259