netfilter: Add the capability to offload flowtable in XDP layer
Subsystems (7)
v5 cover netfilter: Add the capability to offload flowtable in XDP layer
Introduce bpf_xdp_flow_lookup kfunc in order to perform the lookup of a given flowtable entry based on the fib tuple of incoming traffic. bpf_xdp_flow_lookup can be used as building block to offload in XDP the sw flowtable processing when the hw support is not available.
This series has been tested running the xdp_flowtable_offload eBPF program on an ixgbe 10Gbps NIC (eno2) in order to XDP_REDIRECT the TCP traffic to a veth pair (veth0-veth1) based on the content of the nf_flowtable as soon as the TCP connection is in the established state:
[tcp client] (eno1) == LAN == (eno2) xdp_flowtable_offload [XDP_REDIRECT] --> veth0 == veth1 [tcp server]
table inet filter {
flowtable ft {
hook ingress priority filter
devices = { eno2, veth0 }
}
chain forward {
type filter hook forward priority filter
meta l4proto { tcp, udp } flow add @ft
}
}- sw flowtable [1 TCP stream, T = 300s]: ~ 6.2 Gbps
- xdp flowtable [1 TCP stream, T = 300s]: ~ 7.6 Gbps
- sw flowtable [3 TCP stream, T = 300s]: ~ 7.7 Gbps
- xdp flowtable [3 TCP stream, T = 300s]: ~ 8.8 Gbps
Changes since v4:
- add missing BPF_NO_KFUNC_PROTOTYPES macro to selftest
Changes since v3:
- move flowtable map utilities in nf_flow_table_xdp.c
Changes since v2:
- introduce bpf_flowtable_opts struct in bpf_xdp_flow_lookup signature
- get rid of xdp_flowtable_offload bpf sample
- get rid of test_xdp_flowtable.sh for selftest and rely on prog_tests instead
- rename bpf_xdp_flow_offload_lookup in bpf_xdp_flow_lookup Changes since v1:
- return NULL in bpf_xdp_flow_offload_lookup kfunc in case of error
- take into account kfunc registration possible failures
Changes since RFC:
- fix compilation error if BTF is not enabled
Florian Westphal (1):
netfilter: nf_tables: add flowtable map for xdp offload
Lorenzo Bianconi (2):
netfilter: add bpf_xdp_flow_lookup kfunc selftests/bpf: Add selftest for bpf_xdp_flow_lookup kfunc
include/net/netfilter/nf_flow_table.h | 18 ++ net/netfilter/Makefile | 7 +- net/netfilter/nf_flow_table_bpf.c | 117 ++++++++++++ net/netfilter/nf_flow_table_inet.c | 2 +- net/netfilter/nf_flow_table_offload.c | 6 +- net/netfilter/nf_flow_table_xdp.c | 163 +++++++++++++++++ tools/testing/selftests/bpf/config | 13 ++ .../selftests/bpf/prog_tests/xdp_flowtable.c | 168 ++++++++++++++++++ .../selftests/bpf/progs/xdp_flowtable.c | 146 +++++++++++++++ 9 files changed, 636 insertions(+), 4 deletions(-) create mode 100644 net/netfilter/nf_flow_table_bpf.c create mode 100644 net/netfilter/nf_flow_table_xdp.c create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.c
Signature · 1 line
2.45.1
PATCH v5 1/3 netfilter: nf_tables: add flowtable map for xdp offload
From: Florian Westphal <[email protected]>
This adds a small internal mapping table so that a new bpf (xdp) kfunc can perform lookups in a flowtable.
As-is, xdp program has access to the device pointer, but no way to do a lookup in a flowtable -- there is no way to obtain the needed struct without questionable stunts.
This allows to obtain an nf_flowtable pointer given a net_device structure.
In order to keep backward compatibility, the infrastructure allows the user to add a given device to multiple flowtables, but it will always return the first added mapping performing the lookup since it assumes the right configuration is 1:1 mapping between flowtables and net_devices.
--- include/net/netfilter/nf_flow_table.h | 8 ++ net/netfilter/Makefile | 2 +- net/netfilter/nf_flow_table_offload.c | 6 +- net/netfilter/nf_flow_table_xdp.c | 163 ++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 net/netfilter/nf_flow_table_xdp.c
include/net/netfilter/nf_flow_table.h +8 -0
@@ -305,6 +305,14 @@ struct flow_ports {__be16 source, dest; }; +struct nf_flowtable *nf_flowtable_by_dev (const struct net_device *dev); +int nf_flow_offload_xdp_setup (struct nf_flowtable *flowtable, +struct net_device *dev, +enum flow_block_command cmd); +void nf_flow_offload_xdp_cancel (struct nf_flowtable *flowtable, +struct net_device *dev, +enum flow_block_command cmd); +unsigned int nf_flow_offload_ip_hook (void *priv,struct sk_buff *skb,const struct nf_hook_state *state); unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
net/netfilter/Makefile +1 -1
@@ -142,7 +142,7 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o # flow table infrastructure obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ - nf_flow_table_offload.o + nf_flow_table_offload.o nf_flow_table_xdp.o nf_flow_table-$(CONFIG_NF_FLOW_TABLE_PROCFS) += nf_flow_table_procfs.o obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
net/netfilter/nf_flow_table_offload.c +4 -2
@@ -1192,7 +1192,7 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,int err;if (!nf_flowtable_hw_offload (flowtable)) -return 0 ; +return nf_flow_offload_xdp_setup (flowtable, dev, cmd);if (dev->netdev_ops->ndo_setup_tc) err = nf_flow_table_offload_cmd(&bo, flowtable, dev, cmd,
@@ -1200,8 +1200,10 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,else err =nf_flow_table_indr_offload_cmd (&bo, flowtable, dev, cmd, &extack); -if (err <0 ) +if (err <0 ) { +nf_flow_offload_xdp_cancel (flowtable, dev, cmd);return err; + }return nf_flow_table_block_setup (flowtable, &bo, cmd); }
net/netfilter/nf_flow_table_xdp.c new file +163 -0
163 lines not on this page · raw message
Signature · 1 line
2.45.1
Daniel Borkmann
maintainerRe: [PATCH v5 bpf-next 1/3] netfilter: nf_tables: add flowtable map for xdp offload
On 6/14/24 5:40 PM, Lorenzo Bianconi wrote:
[...]
Quoted 98 lines
net/netfilter/nf_flow_table_offload.c +4
-2@@ -1192,7 +1192,7 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,int err;if (!nf_flowtable_hw_offload (flowtable)) -return 0 ; +return nf_flow_offload_xdp_setup (flowtable, dev, cmd);if (dev->netdev_ops->ndo_setup_tc) err = nf_flow_table_offload_cmd(&bo, flowtable, dev, cmd,@@ -1200,8 +1200,10 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,else err =nf_flow_table_indr_offload_cmd (&bo, flowtable, dev, cmd, &extack); -if (err <0 ) +if (err <0 ) { +nf_flow_offload_xdp_cancel (flowtable, dev, cmd);return err; + }return nf_flow_table_block_setup (flowtable, &bo, cmd); }net/netfilter/nf_flow_table_xdp.c new file +67
-0@@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netfilter.h> +#include <linux/rhashtable.h> +#include <linux/netdevice.h> +#include <net/flow_offload.h> +#include <net/netfilter/nf_flow_table.h> + +struct flow_offload_xdp_ft { +struct list_head head; +struct nf_flowtable *ft; +struct rcu_head rcuhead; +}; + +struct flow_offload_xdp { +struct hlist_node hnode; +unsigned long net_device_addr; +struct list_head head; +}; + +#define NF_XDP_HT_BITS 4 +static DEFINE_HASHTABLE(nf_xdp_hashtable, NF_XDP_HT_BITS); +static DEFINE_MUTEX (nf_xdp_hashtable_lock); + +/* caller must hold rcu read lock */ +struct nf_flowtable *nf_flowtable_by_dev (const struct net_device *dev) +{ +unsigned long key = (unsigned long )dev; +struct flow_offload_xdp *iter; + +hash_for_each_possible_rcu (nf_xdp_hashtable, iter, hnode, key) { +if (key == iter->net_device_addr) { +struct flow_offload_xdp_ft *ft_elem; + +/* The user is supposed to insert a given net_device +* just into a single nf_flowtable so we always return +* the first element here. +*/ + ft_elem =list_first_or_null_rcu (&iter->head, + struct flow_offload_xdp_ft, + head); +return ft_elem ? ft_elem->ft :NULL ; + } + } + +return NULL ; +} + +static int nf_flowtable_by_dev_insert (struct nf_flowtable *ft, +const struct net_device *dev) +{ +struct flow_offload_xdp *iter, *elem =NULL ; +unsigned long key = (unsigned long )dev; +struct flow_offload_xdp_ft *ft_elem; + + ft_elem =kzalloc (sizeof (*ft_elem),GFP_KERNEL_ACCOUNT ); +if (!ft_elem) +return -ENOMEM ; + + ft_elem->ft = ft; + +mutex_lock (&nf_xdp_hashtable_lock); + +hash_for_each_possible (nf_xdp_hashtable, iter, hnode, key) { +if (key == iter->net_device_addr) { + elem = iter;
net/netfilter/nf_flow_table_xdp.c line 77
Quoted 10 lines
net/netfilter/nf_flow_table_xdp.c new file +10
-0+break ; + } + } + +if (!elem) { + elem =kzalloc (sizeof (*elem),GFP_KERNEL_ACCOUNT ); +if (!elem) + goto err_unlock; + + elem->net_device_addr = key;
Looks good, as I understand (but just to double check) if a device goes away then upper layers in the nf flowtable code will trigger the nf_flowtable_by_dev_remove() based on the device pointer to clean this up again from nf_xdp_hashtable.
Quoted 15 lines
net/netfilter/nf_flow_table_xdp.c new file +15
-0+INIT_LIST_HEAD (&elem->head); +hash_add_rcu (nf_xdp_hashtable, &elem->hnode, key); + } +list_add_tail_rcu (&ft_elem->head, &elem->head); + +mutex_unlock (&nf_xdp_hashtable_lock); + +return 0 ; + +err_unlock: +mutex_unlock (&nf_xdp_hashtable_lock); +kfree (ft_elem); + +return -ENOMEM ; +}
Re: [PATCH v5 bpf-next 1/3] netfilter: nf_tables: add flowtable map for xdp offload
Quoted 103 lines · Lorenzo Bianconi
[...]
Quoted 101 lines
net/netfilter/nf_flow_table_offload.c +4
-2@@ -1192,7 +1192,7 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,int err;if (!nf_flowtable_hw_offload (flowtable)) -return 0 ; +return nf_flow_offload_xdp_setup (flowtable, dev, cmd);if (dev->netdev_ops->ndo_setup_tc) err = nf_flow_table_offload_cmd(&bo, flowtable, dev, cmd,@@ -1200,8 +1200,10 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,else err =nf_flow_table_indr_offload_cmd (&bo, flowtable, dev, cmd, &extack); -if (err <0 ) +if (err <0 ) { +nf_flow_offload_xdp_cancel (flowtable, dev, cmd);return err; + }return nf_flow_table_block_setup (flowtable, &bo, cmd); }net/netfilter/nf_flow_table_xdp.c new file +73
-0@@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netfilter.h> +#include <linux/rhashtable.h> +#include <linux/netdevice.h> +#include <net/flow_offload.h> +#include <net/netfilter/nf_flow_table.h> + +struct flow_offload_xdp_ft { +struct list_head head; +struct nf_flowtable *ft; +struct rcu_head rcuhead; +}; + +struct flow_offload_xdp { +struct hlist_node hnode; +unsigned long net_device_addr; +struct list_head head; +}; + +#define NF_XDP_HT_BITS 4 +static DEFINE_HASHTABLE(nf_xdp_hashtable, NF_XDP_HT_BITS); +static DEFINE_MUTEX (nf_xdp_hashtable_lock); + +/* caller must hold rcu read lock */ +struct nf_flowtable *nf_flowtable_by_dev (const struct net_device *dev) +{ +unsigned long key = (unsigned long )dev; +struct flow_offload_xdp *iter; + +hash_for_each_possible_rcu (nf_xdp_hashtable, iter, hnode, key) { +if (key == iter->net_device_addr) { +struct flow_offload_xdp_ft *ft_elem; + +/* The user is supposed to insert a given net_device +* just into a single nf_flowtable so we always return +* the first element here. +*/ + ft_elem =list_first_or_null_rcu (&iter->head, + struct flow_offload_xdp_ft, + head); +return ft_elem ? ft_elem->ft :NULL ; + } + } + +return NULL ; +} + +static int nf_flowtable_by_dev_insert (struct nf_flowtable *ft, +const struct net_device *dev) +{ +struct flow_offload_xdp *iter, *elem =NULL ; +unsigned long key = (unsigned long )dev; +struct flow_offload_xdp_ft *ft_elem; + + ft_elem =kzalloc (sizeof (*ft_elem),GFP_KERNEL_ACCOUNT ); +if (!ft_elem) +return -ENOMEM ; + + ft_elem->ft = ft; + +mutex_lock (&nf_xdp_hashtable_lock); + +hash_for_each_possible (nf_xdp_hashtable, iter, hnode, key) { +if (key == iter->net_device_addr) { + elem = iter; +break ; + } + } + +if (!elem) { + elem =kzalloc (sizeof (*elem),GFP_KERNEL_ACCOUNT );
Quoted 8 lines
net/netfilter/nf_flow_table_xdp.c line 77
Quoted 4 lines
net/netfilter/nf_flow_table_xdp.c new file +4
-0+if (!elem) + goto err_unlock; + + elem->net_device_addr = key;Looks good, as I understand (but just to double check) if a device goes away then upper layers in the nf flowtable code will trigger the
nf_flowtable_by_dev_remove()based on the device pointer to clean this up again fromnf_xdp_hashtable.
yep, correct. Core nft infrastructure runs nf_flow_offload_xdp_setup() with cmd set to FLOW_BLOCK_UNBIND (so we run nf_flowtable_by_dev_remove()) when the net_device is removed.
Regards,
Lorenzo
Quoted 16 lines
Quoted 16 lines
net/netfilter/nf_flow_table_xdp.c new file +15
-0+INIT_LIST_HEAD (&elem->head); +hash_add_rcu (nf_xdp_hashtable, &elem->hnode, key); + } +list_add_tail_rcu (&ft_elem->head, &elem->head); + +mutex_unlock (&nf_xdp_hashtable_lock); + +return 0 ; + +err_unlock: +mutex_unlock (&nf_xdp_hashtable_lock); +kfree (ft_elem); + +return -ENOMEM ; +}
PATCH v5 2/3 netfilter: add bpf_xdp_flow_lookup kfunc
In reply to Lorenzo BianconiIntroduce 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.
--- include/net/netfilter/nf_flow_table.h | 10 +++ net/netfilter/Makefile | 5 ++ net/netfilter/nf_flow_table_bpf.c | 117 ++++++++++++++++++++++++++ net/netfilter/nf_flow_table_inet.c | 2 +- 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 net/netfilter/nf_flow_table_bpf.c
include/net/netfilter/nf_flow_table.h +10 -0
@@ -318,6 +318,16 @@ unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,unsigned int nf_flow_offload_ipv6_hook (void *priv,struct sk_buff *skb,const struct nf_hook_state *state); +#if (IS_BUILTIN (CONFIG_NF_FLOW_TABLE ) &&IS_ENABLED (CONFIG_DEBUG_INFO_BTF )) || \ + (IS_MODULE (CONFIG_NF_FLOW_TABLE ) &&IS_ENABLED (CONFIG_DEBUG_INFO_BTF_MODULES )) +extern int nf_flow_register_bpf (void ); +#else +static inline int nf_flow_register_bpf (void ) +{ +return 0 ; +} +#endif +#define MODULE_ALIAS_NF_FLOWTABLE (family) \ MODULE_ALIAS("nf-flowtable-" __stringify(family))
net/netfilter/Makefile +5 -0
@@ -144,6 +144,11 @@ obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ nf_flow_table_offload.o nf_flow_table_xdp.o nf_flow_table-$(CONFIG_NF_FLOW_TABLE_PROCFS) += nf_flow_table_procfs.o +ifeq ($(CONFIG_NF_FLOW_TABLE),m) +nf_flow_table-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_flow_table_bpf.o +else ifeq ($(CONFIG_NF_FLOW_TABLE),y) +nf_flow_table-$(CONFIG_DEBUG_INFO_BTF) += nf_flow_table_bpf.o +endif obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
net/netfilter/nf_flow_table_bpf.c new file +117 -0
117 lines not on this page · raw message
net/netfilter/nf_flow_table_inet.c +1 -1
@@ -98,7 +98,7 @@ static int __init nf_flow_inet_module_init(void)nft_register_flowtable_type (&flowtable_ipv6);nft_register_flowtable_type (&flowtable_inet); -return 0 ; +return nf_flow_register_bpf (); } static void __exit nf_flow_inet_module_exit(void)
Signature · 1 line
2.45.1
Daniel Borkmann
maintainerRe: [PATCH v5 bpf-next 2/3] netfilter: add bpf_xdp_flow_lookup kfunc
On 6/14/24 5:40 PM, Lorenzo Bianconi wrote:
[...]
net/netfilter/nf_flow_table_bpf.c line 31
Quoted 7 lines
net/netfilter/nf_flow_table_bpf.c new file +7
-0+enum { +NF_BPF_FLOWTABLE_OPTS_SZ =4 , +}; + +__diag_push (); +__diag_ignore_all ("-Wmissing-prototypes" , +"Global functions as their definitions will be in nf_flow_table BTF" );
nit: __bpf_kfunc_start_defs();
Quoted 59 lines
net/netfilter/nf_flow_table_bpf.c new file +59
-0+static struct flow_offload_tuple_rhash * +bpf_xdp_flow_tuple_lookup (struct net_device *dev, +struct flow_offload_tuple *tuple,__be16 proto) +{ +struct flow_offload_tuple_rhash *tuplehash; +struct nf_flowtable *nf_flow_table; +struct flow_offload *nf_flow; + + nf_flow_table =nf_flowtable_by_dev (dev); +if (!nf_flow_table) +return ERR_PTR (-ENOENT ); + + tuplehash =flow_offload_lookup (nf_flow_table, tuple); +if (!tuplehash) +return ERR_PTR (-ENOENT ); + + nf_flow = container_of(tuplehash, struct flow_offload, + tuplehash[tuplehash->tuple.dir]); +flow_offload_refresh (nf_flow_table, nf_flow, false); + +return tuplehash; +} + +__bpf_kfunc struct flow_offload_tuple_rhash * +bpf_xdp_flow_lookup (struct xdp_md *ctx,struct bpf_fib_lookup *fib_tuple, +struct bpf_flowtable_opts *opts,u32 opts_len) +{ +struct xdp_buff *xdp = (struct xdp_buff *)ctx; +struct flow_offload_tuple tuple = { + .iifidx = fib_tuple->ifindex, + .l3proto = fib_tuple->family, + .l4proto = fib_tuple->l4_protocol, + .src_port = fib_tuple->sport, + .dst_port = fib_tuple->dport, + }; +struct flow_offload_tuple_rhash *tuplehash; +__be16 proto; + +if (opts_len !=NF_BPF_FLOWTABLE_OPTS_SZ ) { + opts->error = -EINVAL ; +return NULL ; + } + +switch (fib_tuple->family) { +case AF_INET : + tuple.src_v4.s_addr = fib_tuple->ipv4_src; + tuple.dst_v4.s_addr = fib_tuple->ipv4_dst; + proto =htons (ETH_P_IP ); +break ; +case AF_INET6 : + tuple.src_v6 = *(struct in6_addr *)&fib_tuple->ipv6_src; + tuple.dst_v6 = *(struct in6_addr *)&fib_tuple->ipv6_dst; + proto =htons (ETH_P_IPV6 ); +break ; +default : + opts->error = -EAFNOSUPPORT ; +return NULL ; + } +
net/netfilter/nf_flow_table_bpf.c line 101
Quoted 10 lines
net/netfilter/nf_flow_table_bpf.c new file +10
-0+ tuplehash =bpf_xdp_flow_tuple_lookup (xdp->rxq->dev, &tuple, proto); +if (IS_ERR (tuplehash)) { + opts->error =PTR_ERR (tuplehash); +return NULL ; + } + +return tuplehash; +} + +__diag_pop ()
__bpf_kfunc_end_defs();
Otherwise LGTM!
Re: [PATCH v5 bpf-next 2/3] netfilter: add bpf_xdp_flow_lookup kfunc
Quoted 11 lines · Lorenzo Bianconi
[...]
net/netfilter/nf_flow_table_bpf.c line 31
Quoted 7 lines
net/netfilter/nf_flow_table_bpf.c new file +7
-0+enum { +NF_BPF_FLOWTABLE_OPTS_SZ =4 , +}; + +__diag_push (); +__diag_ignore_all ("-Wmissing-prototypes" , +"Global functions as their definitions will be in nf_flow_table BTF" );nit:
__bpf_kfunc_start_defs();
ack, I will fix it in v6.
Quoted 64 lines
Quoted 64 lines
net/netfilter/nf_flow_table_bpf.c new file +63
-0+static struct flow_offload_tuple_rhash * +bpf_xdp_flow_tuple_lookup (struct net_device *dev, +struct flow_offload_tuple *tuple,__be16 proto) +{ +struct flow_offload_tuple_rhash *tuplehash; +struct nf_flowtable *nf_flow_table; +struct flow_offload *nf_flow; + + nf_flow_table =nf_flowtable_by_dev (dev); +if (!nf_flow_table) +return ERR_PTR (-ENOENT ); + + tuplehash =flow_offload_lookup (nf_flow_table, tuple); +if (!tuplehash) +return ERR_PTR (-ENOENT ); + + nf_flow = container_of(tuplehash, struct flow_offload, + tuplehash[tuplehash->tuple.dir]); +flow_offload_refresh (nf_flow_table, nf_flow, false); + +return tuplehash; +} + +__bpf_kfunc struct flow_offload_tuple_rhash * +bpf_xdp_flow_lookup (struct xdp_md *ctx,struct bpf_fib_lookup *fib_tuple, +struct bpf_flowtable_opts *opts,u32 opts_len) +{ +struct xdp_buff *xdp = (struct xdp_buff *)ctx; +struct flow_offload_tuple tuple = { + .iifidx = fib_tuple->ifindex, + .l3proto = fib_tuple->family, + .l4proto = fib_tuple->l4_protocol, + .src_port = fib_tuple->sport, + .dst_port = fib_tuple->dport, + }; +struct flow_offload_tuple_rhash *tuplehash; +__be16 proto; + +if (opts_len !=NF_BPF_FLOWTABLE_OPTS_SZ ) { + opts->error = -EINVAL ; +return NULL ; + } + +switch (fib_tuple->family) { +case AF_INET : + tuple.src_v4.s_addr = fib_tuple->ipv4_src; + tuple.dst_v4.s_addr = fib_tuple->ipv4_dst; + proto =htons (ETH_P_IP ); +break ; +case AF_INET6 : + tuple.src_v6 = *(struct in6_addr *)&fib_tuple->ipv6_src; + tuple.dst_v6 = *(struct in6_addr *)&fib_tuple->ipv6_dst; + proto =htons (ETH_P_IPV6 ); +break ; +default : + opts->error = -EAFNOSUPPORT ; +return NULL ; + } + + tuplehash =bpf_xdp_flow_tuple_lookup (xdp->rxq->dev, &tuple, proto); +if (IS_ERR (tuplehash)) { + opts->error =PTR_ERR (tuplehash); +return NULL ;
Quoted 8 lines
net/netfilter/nf_flow_table_bpf.c line 101
Quoted 6 lines
net/netfilter/nf_flow_table_bpf.c new file +6
-0+ } + +return tuplehash; +} + +__diag_pop ()
__bpf_kfunc_end_defs();
ack, I will fix it in v6.
Regards,
Lorenzo
Quoted 2 lines
Otherwise LGTM!
PATCH v5 3/3 selftests/bpf: Add selftest for bpf_xdp_flow_lookup kfunc
In reply to Lorenzo BianconiIntroduce e2e selftest for bpf_xdp_flow_lookup kfunc through xdp_flowtable utility.
--- tools/testing/selftests/bpf/config | 13 ++ .../selftests/bpf/prog_tests/xdp_flowtable.c | 168 ++++++++++++++++++ .../selftests/bpf/progs/xdp_flowtable.c | 146 +++++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.c
tools/testing/selftests/bpf/config +13 -0
@@ -83,6 +83,19 @@ CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_ZONES=y CONFIG_NF_DEFRAG_IPV4=y CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_TABLES=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NETFILTER_INGRESS=y +CONFIG_NF_FLOW_TABLE=y +CONFIG_NF_FLOW_TABLE_INET=y +CONFIG_NETFILTER_NETLINK=y +CONFIG_NFT_FLOW_OFFLOAD=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y CONFIG_NF_NAT=y CONFIG_RC_CORE=y CONFIG_SECURITY=y
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +168 -0
168 lines not on this page · raw message
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +146 -0
146 lines not on this page · raw message
Signature · 1 line
2.45.1
Daniel Borkmann
maintainerRe: [PATCH v5 bpf-next 3/3] selftests/bpf: Add selftest for bpf_xdp_flow_lookup kfunc
On 6/14/24 5:40 PM, Lorenzo Bianconi wrote:
[...]
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c line 75
Quoted 12 lines
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +12
-0+void test_xdp_flowtable (void ) +{ +struct xdp_flowtable *skel =NULL ; +struct nstoken *tok =NULL ; +int iifindex, stats_fd; +__u32 value, key =0 ; +struct bpf_link *link; + +if (SYS_NOFAIL ("nft -v" )) { +fprintf (stdout,"Missing required nft tool\n" ); +test__skip (); +return ;
Bit unfortunate that upstream CI skips the test case at the moment:
#542/2 xdp_devmap_attach/DEVMAP with frags programs in entries:OK #542/3 xdp_devmap_attach/Verifier check of DEVMAP programs:OK #542 xdp_devmap_attach:OK #543 xdp_do_redirect:OK #544 xdp_flowtable:SKIP
[...]
Quoted 13 lines
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +7
-0+out: +xdp_flowtable__destroy (skel); +if (tok) +close_netns (tok); +SYS_NOFAIL ("ip netns del " TX_NETNS_NAME ); +SYS_NOFAIL ("ip netns del " RX_NETNS_NAME ); +}tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +0
-0
tools/testing/selftests/bpf/progs/xdp_flowtable.c line 7
Quoted 7 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +7
-0@@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +#define BPF_NO_KFUNC_PROTOTYPES +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_endian.h> + +#define MAX_ERRNO 4095
nit: unused?
Quoted 22 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +22
-0+#define ETH_P_IP 0x0800 +#define ETH_P_IPV6 0x86dd +#define IP_MF 0x2000/* "More Fragments" */ +#define IP_OFFSET 0x1fff/* "Fragment Offset" */ +#define AF_INET 2 +#define AF_INET6 10 + +struct bpf_flowtable_opts___local { +s32 error; +}; + +struct flow_offload_tuple_rhash * +bpf_xdp_flow_lookup (struct xdp_md *,struct bpf_fib_lookup *, +struct bpf_flowtable_opts___local *,u32 ) __ksym; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 1); +} stats SEC(".maps"); +
[...]
Re: [PATCH v5 bpf-next 3/3] selftests/bpf: Add selftest for bpf_xdp_flow_lookup kfunc
Quoted 16 lines · Lorenzo Bianconi
[...]
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c line 75
Quoted 12 lines
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +12
-0+void test_xdp_flowtable (void ) +{ +struct xdp_flowtable *skel =NULL ; +struct nstoken *tok =NULL ; +int iifindex, stats_fd; +__u32 value, key =0 ; +struct bpf_link *link; + +if (SYS_NOFAIL ("nft -v" )) { +fprintf (stdout,"Missing required nft tool\n" ); +test__skip (); +return ;Bit unfortunate that upstream CI skips the test case at the moment:
yep, we are missing nft utility there.
Quoted 22 lines
#542/2 xdp_devmap_attach/DEVMAP with frags programs in entries:OK #542/3 xdp_devmap_attach/Verifier check of DEVMAP programs:OK #542 xdp_devmap_attach:OK #543 xdp_do_redirect:OK #544 xdp_flowtable:SKIP[...]
Quoted 14 lines
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +7
-0+out: +xdp_flowtable__destroy (skel); +if (tok) +close_netns (tok); +SYS_NOFAIL ("ip netns del " TX_NETNS_NAME ); +SYS_NOFAIL ("ip netns del " RX_NETNS_NAME ); +}tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +1
-0@@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0
Quoted 8 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c line 7
Quoted 6 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +6
-0+#define BPF_NO_KFUNC_PROTOTYPES +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_endian.h> + +#define MAX_ERRNO 4095nit: unused?
ack, I will remove it in v6.
Regards,
Lorenzo
Quoted 24 lines
Quoted 23 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +22
-0+#define ETH_P_IP 0x0800 +#define ETH_P_IPV6 0x86dd +#define IP_MF 0x2000/* "More Fragments" */ +#define IP_OFFSET 0x1fff/* "Fragment Offset" */ +#define AF_INET 2 +#define AF_INET6 10 + +struct bpf_flowtable_opts___local { +s32 error; +}; + +struct flow_offload_tuple_rhash * +bpf_xdp_flow_lookup (struct xdp_md *,struct bpf_fib_lookup *, +struct bpf_flowtable_opts___local *,u32 ) __ksym; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 1); +} stats SEC(".maps"); +[...]
Daniel Borkmann
maintainerRe: [PATCH v5 bpf-next 3/3] selftests/bpf: Add selftest for bpf_xdp_flow_lookup kfunc
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines · Lorenzo Bianconi
[...]
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c line 75
Quoted 12 lines
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c new file +12
-0+void test_xdp_flowtable (void ) +{ +struct xdp_flowtable *skel =NULL ; +struct nstoken *tok =NULL ; +int iifindex, stats_fd; +__u32 value, key =0 ; +struct bpf_link *link; + +if (SYS_NOFAIL ("nft -v" )) { +fprintf (stdout,"Missing required nft tool\n" ); +test__skip (); +return ;Bit unfortunate that upstream CI skips the test case at the moment:
Quoted 1 line
yep, we are missing nft utility there.
Ok, not a blocker imho, but if you could work with Manu to get this enabled in the CI, that would be great so that the test can actually run.
Thanks,
Daniel
Quoted 29 lines
Introduce
bpf_xdp_flow_lookupkfunc in order to perform the lookup of a given flowtable entry based on the fib tuple of incoming traffic.bpf_xdp_flow_lookupcan be used as building block to offload in XDP the sw flowtable processing when the hw support is not available.This series has been tested running the
xdp_flowtable_offloadeBPF program on an ixgbe 10Gbps NIC (eno2) in order toXDP_REDIRECTthe TCP traffic to a veth pair (veth0-veth1) based on the content of thenf_flowtableas soon as the TCP connection is in the established state:[tcp client] (eno1) == LAN == (eno2)
xdp_flowtable_offload[XDP_REDIRECT] --> veth0 == veth1 [tcp server]table inet filter { flowtable ft { hook ingress priority filter devices = { eno2, veth0 } } chain forward { type filter hook forward priority filter meta l4proto { tcp, udp } flow add @ft } }(quoted diff) +0
-4- sw flowtable [1 TCP stream, T = 300s]: ~ 6.2 Gbps - xdp flowtable [1 TCP stream, T = 300s]: ~ 7.6 Gbps - sw flowtable [3 TCP stream, T = 300s]: ~ 7.7 Gbps - xdp flowtable [3 TCP stream, T = 300s]: ~ 8.8 Gbps
Quoted 14 lines
Changes since v4:
- add missingBPF_NO_KFUNC_PROTOTYPESmacro to selftest
Changes since v3:
- move flowtable map utilities innf_flow_table_xdp.c
Changes since v2:
- introducebpf_flowtable_optsstruct inbpf_xdp_flow_lookupsignature
- get rid ofxdp_flowtable_offloadbpf sample
- get rid oftest_xdp_flowtable.shfor selftest and rely onprog_testsinstead
- renamebpf_xdp_flow_offload_lookupinbpf_xdp_flow_lookupChanges since v1:
- return NULL inbpf_xdp_flow_offload_lookupkfunc in case of error
- take into account kfunc registration possible failures
Changes since RFC:
- fix compilation error if BTF is not enabled
Hi all,
Looking at patchwork this series is marked as 'Archived' even if the eBPF bits have been acked by Alexei while netfilter ones have been acked by Pablo. Am I missing something? Do I need to repost?
Regards,
Lorenzo
Quoted 28 lines
Florian Westphal (1):
netfilter:nf_tables: add flowtable map for xdp offloadLorenzo Bianconi (2):
netfilter: addbpf_xdp_flow_lookupkfunc selftests/bpf: Add selftest forbpf_xdp_flow_lookupkfuncinclude/net/netfilter/nf_flow_table.h | 18 ++ net/netfilter/Makefile | 7 +- net/netfilter/nf_flow_table_bpf.c | 117 ++++++++++++ net/netfilter/nf_flow_table_inet.c | 2 +- net/netfilter/nf_flow_table_offload.c | 6 +- net/netfilter/nf_flow_table_xdp.c | 163 +++++++++++++++++ tools/testing/selftests/bpf/config | 13 ++ .../selftests/bpf/prog_tests/xdp_flowtable.c | 168 ++++++++++++++++++ .../selftests/bpf/progs/xdp_flowtable.c | 146 +++++++++++++++ 9 files changed, 636 insertions(+), 4 deletions(-) create mode 100644 net/netfilter/nf_flow_table_bpf.c create mode 100644 net/netfilter/nf_flow_table_xdp.c create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.cSignature · 1 line
2.45.1