Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: Add bpf_xdp_flow_lookup kfunc

Introduce bpf_xdp_flow_lookup kfunc in order to perform the lookup
of a given flowtable entry based on a fib tuple of incoming traffic.
bpf_xdp_flow_lookup can be used as building block to offload in xdp
the processing of sw flowtable when hw flowtable is not available.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Link: https://lore.kernel.org/bpf/55d38a4e5856f6d1509d823ff4e98aaa6d356097.1719698275.git.lorenzo@kernel.org

authored by

Lorenzo Bianconi and committed by
Daniel Borkmann
391bb659 89cc8f1c

+137 -1
+10
include/net/netfilter/nf_flow_table.h
··· 315 315 unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, 316 316 const struct nf_hook_state *state); 317 317 318 + #if (IS_BUILTIN(CONFIG_NF_FLOW_TABLE) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \ 319 + (IS_MODULE(CONFIG_NF_FLOW_TABLE) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) 320 + extern int nf_flow_register_bpf(void); 321 + #else 322 + static inline int nf_flow_register_bpf(void) 323 + { 324 + return 0; 325 + } 326 + #endif 327 + 318 328 #define MODULE_ALIAS_NF_FLOWTABLE(family) \ 319 329 MODULE_ALIAS("nf-flowtable-" __stringify(family)) 320 330
+5
net/netfilter/Makefile
··· 144 144 nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ 145 145 nf_flow_table_offload.o nf_flow_table_xdp.o 146 146 nf_flow_table-$(CONFIG_NF_FLOW_TABLE_PROCFS) += nf_flow_table_procfs.o 147 + ifeq ($(CONFIG_NF_FLOW_TABLE),m) 148 + nf_flow_table-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_flow_table_bpf.o 149 + else ifeq ($(CONFIG_NF_FLOW_TABLE),y) 150 + nf_flow_table-$(CONFIG_DEBUG_INFO_BTF) += nf_flow_table_bpf.o 151 + endif 147 152 148 153 obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o 149 154
+121
net/netfilter/nf_flow_table_bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Unstable Flow Table Helpers for XDP hook 3 + * 4 + * These are called from the XDP programs. 5 + * Note that it is allowed to break compatibility for these functions since 6 + * the interface they are exposed through to BPF programs is explicitly 7 + * unstable. 8 + */ 9 + 10 + #include <linux/kernel.h> 11 + #include <linux/init.h> 12 + #include <linux/module.h> 13 + #include <net/netfilter/nf_flow_table.h> 14 + #include <linux/bpf.h> 15 + #include <linux/btf.h> 16 + #include <net/xdp.h> 17 + 18 + /* bpf_flowtable_opts - options for bpf flowtable helpers 19 + * @error: out parameter, set for any encountered error 20 + */ 21 + struct bpf_flowtable_opts { 22 + s32 error; 23 + }; 24 + 25 + enum { 26 + NF_BPF_FLOWTABLE_OPTS_SZ = 4, 27 + }; 28 + 29 + __diag_push(); 30 + __diag_ignore_all("-Wmissing-prototypes", 31 + "Global functions as their definitions will be in nf_flow_table BTF"); 32 + 33 + __bpf_kfunc_start_defs(); 34 + 35 + static struct flow_offload_tuple_rhash * 36 + bpf_xdp_flow_tuple_lookup(struct net_device *dev, 37 + struct flow_offload_tuple *tuple, __be16 proto) 38 + { 39 + struct flow_offload_tuple_rhash *tuplehash; 40 + struct nf_flowtable *nf_flow_table; 41 + struct flow_offload *nf_flow; 42 + 43 + nf_flow_table = nf_flowtable_by_dev(dev); 44 + if (!nf_flow_table) 45 + return ERR_PTR(-ENOENT); 46 + 47 + tuplehash = flow_offload_lookup(nf_flow_table, tuple); 48 + if (!tuplehash) 49 + return ERR_PTR(-ENOENT); 50 + 51 + nf_flow = container_of(tuplehash, struct flow_offload, 52 + tuplehash[tuplehash->tuple.dir]); 53 + flow_offload_refresh(nf_flow_table, nf_flow, false); 54 + 55 + return tuplehash; 56 + } 57 + 58 + __bpf_kfunc struct flow_offload_tuple_rhash * 59 + bpf_xdp_flow_lookup(struct xdp_md *ctx, struct bpf_fib_lookup *fib_tuple, 60 + struct bpf_flowtable_opts *opts, u32 opts_len) 61 + { 62 + struct xdp_buff *xdp = (struct xdp_buff *)ctx; 63 + struct flow_offload_tuple tuple = { 64 + .iifidx = fib_tuple->ifindex, 65 + .l3proto = fib_tuple->family, 66 + .l4proto = fib_tuple->l4_protocol, 67 + .src_port = fib_tuple->sport, 68 + .dst_port = fib_tuple->dport, 69 + }; 70 + struct flow_offload_tuple_rhash *tuplehash; 71 + __be16 proto; 72 + 73 + if (opts_len != NF_BPF_FLOWTABLE_OPTS_SZ) { 74 + opts->error = -EINVAL; 75 + return NULL; 76 + } 77 + 78 + switch (fib_tuple->family) { 79 + case AF_INET: 80 + tuple.src_v4.s_addr = fib_tuple->ipv4_src; 81 + tuple.dst_v4.s_addr = fib_tuple->ipv4_dst; 82 + proto = htons(ETH_P_IP); 83 + break; 84 + case AF_INET6: 85 + tuple.src_v6 = *(struct in6_addr *)&fib_tuple->ipv6_src; 86 + tuple.dst_v6 = *(struct in6_addr *)&fib_tuple->ipv6_dst; 87 + proto = htons(ETH_P_IPV6); 88 + break; 89 + default: 90 + opts->error = -EAFNOSUPPORT; 91 + return NULL; 92 + } 93 + 94 + tuplehash = bpf_xdp_flow_tuple_lookup(xdp->rxq->dev, &tuple, proto); 95 + if (IS_ERR(tuplehash)) { 96 + opts->error = PTR_ERR(tuplehash); 97 + return NULL; 98 + } 99 + 100 + return tuplehash; 101 + } 102 + 103 + __diag_pop() 104 + 105 + __bpf_kfunc_end_defs(); 106 + 107 + BTF_KFUNCS_START(nf_ft_kfunc_set) 108 + BTF_ID_FLAGS(func, bpf_xdp_flow_lookup, KF_TRUSTED_ARGS | KF_RET_NULL) 109 + BTF_KFUNCS_END(nf_ft_kfunc_set) 110 + 111 + static const struct btf_kfunc_id_set nf_flow_kfunc_set = { 112 + .owner = THIS_MODULE, 113 + .set = &nf_ft_kfunc_set, 114 + }; 115 + 116 + int nf_flow_register_bpf(void) 117 + { 118 + return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, 119 + &nf_flow_kfunc_set); 120 + } 121 + EXPORT_SYMBOL_GPL(nf_flow_register_bpf);
+1 -1
net/netfilter/nf_flow_table_inet.c
··· 98 98 nft_register_flowtable_type(&flowtable_ipv6); 99 99 nft_register_flowtable_type(&flowtable_inet); 100 100 101 - return 0; 101 + return nf_flow_register_bpf(); 102 102 } 103 103 104 104 static void __exit nf_flow_inet_module_exit(void)