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); 122