Skip to contentSkip to conversation

netfilter: Add the capability to offload flowtable in XDP layer

PATCH Superseded Lorenzo Bianconi 4 participants 12 messages May 18, 2024 – May 21, 2024

Subsystems (7)

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v2 cover netfilter: Add the capability to offload flowtable in XDP layer

Introduce bpf_xdp_flow_offload_lookup kfunc in order to perform the lookup of a given flowtable entry based on the fib tuple of incoming traffic.
bpf_xdp_flow_offload_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 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 (3):
netfilter: add bpf_xdp_flow_offload_lookup kfunc samples/bpf: Add bpf sample to offload flowtable traffic to xdp selftests/bpf: Add selftest for bpf_xdp_flow_offload_lookup kfunc

 include/net/netfilter/nf_flow_table.h         |  12 +
 net/netfilter/Makefile                        |   5 +
 net/netfilter/nf_flow_table_bpf.c             |  94 +++
 net/netfilter/nf_flow_table_inet.c            |   2 +-
 net/netfilter/nf_flow_table_offload.c         | 161 ++++-
 samples/bpf/Makefile                          |   7 +-
 samples/bpf/xdp_flowtable_offload.bpf.c       | 591 ++++++++++++++++++
 samples/bpf/xdp_flowtable_offload_user.c      | 128 ++++
 tools/testing/selftests/bpf/Makefile          |  10 +-
 tools/testing/selftests/bpf/config            |   4 +
 .../selftests/bpf/progs/xdp_flowtable.c       | 141 +++++
 .../selftests/bpf/test_xdp_flowtable.sh       | 112 ++++
 tools/testing/selftests/bpf/xdp_flowtable.c   | 142 +++++
 13 files changed, 1403 insertions(+), 6 deletions(-)
 create mode 100644 net/netfilter/nf_flow_table_bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload.bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload_user.c
 create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.c
 create mode 100755 tools/testing/selftests/bpf/test_xdp_flowtable.sh
 create mode 100644 tools/testing/selftests/bpf/xdp_flowtable.c
Signature · 1 line
2.45.1
#1 lore raw

PATCH v2 1/4 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 |   2 +
 net/netfilter/nf_flow_table_offload.c | 161 +++++++++++++++++++++++++-
 2 files changed, 161 insertions(+), 2 deletions(-)
include/net/netfilter/nf_flow_table.h +2 -0
index 9abb7ee40d72f..0bbe6ea8e0651 100644
@@ -305,6 +305,8 @@ struct flow_ports {
 	__be16 source, dest;
 };
 
+struct nf_flowtable *nf_flowtable_by_dev(const struct net_device *dev);
+
 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/nf_flow_table_offload.c +159 -2

186 lines not on this page · raw message

Signature · 1 line
2.45.1
#2 lore raw

PATCH v2 2/4 netfilter: add bpf_xdp_flow_offload_lookup kfunc

In reply to Lorenzo Bianconi

Introduce bpf_xdp_flow_offload_lookup kfunc in order to perform the lookup of a given flowtable entry based on a fib tuple of incoming traffic.
bpf_xdp_flow_offload_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     | 94 +++++++++++++++++++++++++++
 net/netfilter/nf_flow_table_inet.c    |  2 +-
 4 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 net/netfilter/nf_flow_table_bpf.c
include/net/netfilter/nf_flow_table.h +10 -0
index 0bbe6ea8e0651..085660cbcd3f2 100644
@@ -312,6 +312,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_offload_register_bpf(void);
+#else
+static inline int nf_flow_offload_register_bpf(void)
+{
+	return 0;
+}
+#endif
+
 #define MODULE_ALIAS_NF_FLOWTABLE(family)	\
 	MODULE_ALIAS("nf-flowtable-" __stringify(family))
 
net/netfilter/Makefile +5 -0
index 614815a3ed738..18b09cec92024 100644
@@ -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-$(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 +94 -0

94 lines not on this page · raw message

net/netfilter/nf_flow_table_inet.c +1 -1
index 6eef15648b7b0..6175f7556919d 100644
@@ -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_offload_register_bpf();
 }
 
 static void __exit nf_flow_inet_module_exit(void)
Signature · 1 line
2.45.1
maintainer Acked-by on v2 2/4
#3 lore raw

Re: [PATCH bpf-next v2 2/4] netfilter: add bpf_xdp_flow_offload_lookup kfunc

Quoted 10 lines · Lorenzo Bianconi

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

---

Though I think it might have been better to have an opts parameter for extensibility (and have opts->error for now to aid debugging when NULL is returned),
but I won't insist (it's not a big deal, as there's only two things that can go wrong: the tuple->family is unsupported or the lookup fails).

#4 lore raw

Re: [PATCH bpf-next v2 2/4] netfilter: add bpf_xdp_flow_offload_lookup kfunc

In reply to Lorenzo Bianconi
Quoted 131 lines · Lorenzo Bianconi

Introduce bpf_xdp_flow_offload_lookup kfunc in order to perform the lookup of a given flowtable entry based on a fib tuple of incoming traffic.
bpf_xdp_flow_offload_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     | 94 +++++++++++++++++++++++++++
 net/netfilter/nf_flow_table_inet.c    |  2 +-
 4 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 net/netfilter/nf_flow_table_bpf.c
include/net/netfilter/nf_flow_table.h +10 -0
index 0bbe6ea8e0651..085660cbcd3f2 100644
@@ -312,6 +312,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_offload_register_bpf(void);
+#else
+static inline int nf_flow_offload_register_bpf(void)
+{
+       return 0;
+}
+#endif
+
 #define MODULE_ALIAS_NF_FLOWTABLE(family)      \
        MODULE_ALIAS("nf-flowtable-" __stringify(family))
 
net/netfilter/Makefile +5 -0
index 614815a3ed738..18b09cec92024 100644
@@ -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-$(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 +71 -0
new file mode 100644
index 0000000000000..f999ed9712796
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Unstable Flow Table Helpers for XDP hook
+ *
+ * These are called from the XDP programs.
+ * Note that it is allowed to break compatibility for these functions since
+ * the interface they are exposed through to BPF programs is explicitly
+ * unstable.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <net/netfilter/nf_flow_table.h>
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <net/xdp.h>
+
+__diag_push();
+__diag_ignore_all("-Wmissing-prototypes",
+                 "Global functions as their definitions will be in nf_flow_table BTF");
+
+static struct flow_offload_tuple_rhash *
+bpf_xdp_flow_offload_tuple_lookup(struct net_device *dev,
+                                 struct flow_offload_tuple *tuple,
+                                 __be16 proto)
+{
+       struct flow_offload_tuple_rhash *tuplehash;
+       struct nf_flowtable *flow_table;
+       struct flow_offload *flow;
+
+       flow_table = nf_flowtable_by_dev(dev);
+       if (!flow_table)
+               return NULL;
+
+       tuplehash = flow_offload_lookup(flow_table, tuple);
+       if (!tuplehash)
+               return NULL;
+
+       flow = container_of(tuplehash, struct flow_offload,
+                           tuplehash[tuplehash->tuple.dir]);
+       flow_offload_refresh(flow_table, flow, false);
+
+       return tuplehash;
+}
+
+__bpf_kfunc struct flow_offload_tuple_rhash *
+bpf_xdp_flow_offload_lookup(struct xdp_md *ctx,
+                           struct bpf_fib_lookup *fib_tuple)
+{
+       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,
+       };
+       __be16 proto;
+
+       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:

net/netfilter/nf_flow_table_bpf.c line 81

Quoted 10 lines
net/netfilter/nf_flow_table_bpf.c new file +10 -0
+               return NULL;
+       }
+
+       return bpf_xdp_flow_offload_tuple_lookup(xdp->rxq->dev, &tuple, proto);
+}
+
+__diag_pop()
+
+BTF_KFUNCS_START(nf_ft_kfunc_set)
+BTF_ID_FLAGS(func, bpf_xdp_flow_offload_lookup)

I think it needs to be KF_RET_NULL.
And most likely KF_TRUSTED_ARGS as well.

Also the "offload" doesn't fit in the name.
The existing code calls it "offload", because it's actually pushing the rules to HW (if I understand the code), but here it's just a lookup from xdp.
So call it
bpf_xdp_flow_lookup() ?

Though "flow" is a bit too generic here.
nf_flow maybe?

Quoted 29 lines
net/netfilter/nf_flow_table_bpf.c new file +13 -0
+BTF_KFUNCS_END(nf_ft_kfunc_set)
+
+static const struct btf_kfunc_id_set nf_flow_offload_kfunc_set = {
+       .owner = THIS_MODULE,
+       .set   = &nf_ft_kfunc_set,
+};
+
+int nf_flow_offload_register_bpf(void)
+{
+       return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
+                                        &nf_flow_offload_kfunc_set);
+}
+EXPORT_SYMBOL_GPL(nf_flow_offload_register_bpf);
net/netfilter/nf_flow_table_inet.c +1 -2
index 6eef15648b7b0..6175f7556919d 100644
@@ -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_offload_register_bpf();
 }
 
 static void __exit nf_flow_inet_module_exit(void)
--

2.45.1

#5 lore raw

Re: [PATCH bpf-next v2 2/4] netfilter: add bpf_xdp_flow_offload_lookup kfunc

Quoted 1 line · Lorenzo Bianconi

[...]

Quoted 3 lines

I think it needs to be KF_RET_NULL.
And most likely KF_TRUSTED_ARGS as well.

ack, I will fix it in v2.

Quoted 7 lines

Also the "offload" doesn't fit in the name.
The existing code calls it "offload", because it's actually pushing the rules to HW (if I understand the code), but here it's just a lookup from xdp.
So call it
bpf_xdp_flow_lookup() ?

ack fine, I do not have a strong opinion on it. I will fix it in v2.

Quoted 3 lines

Though "flow" is a bit too generic here.
nf_flow maybe?

ack, I will fix it in v2.

Regards,
Lorenzo

Quoted 30 lines
Quoted 30 lines
net/netfilter/nf_flow_table_bpf.c new file +13 -0
+BTF_KFUNCS_END(nf_ft_kfunc_set)
+
+static const struct btf_kfunc_id_set nf_flow_offload_kfunc_set = {
+       .owner = THIS_MODULE,
+       .set   = &nf_ft_kfunc_set,
+};
+
+int nf_flow_offload_register_bpf(void)
+{
+       return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
+                                        &nf_flow_offload_kfunc_set);
+}
+EXPORT_SYMBOL_GPL(nf_flow_offload_register_bpf);
net/netfilter/nf_flow_table_inet.c +1 -2
index 6eef15648b7b0..6175f7556919d 100644
@@ -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_offload_register_bpf();
 }
 
 static void __exit nf_flow_inet_module_exit(void)
--

2.45.1

#6 lore raw

PATCH v2 3/4 samples/bpf: Add bpf sample to offload flowtable traffic to xdp

In reply to Lorenzo Bianconi

Introduce xdp_flowtable_offload bpf sample to offload sw flowtable logic in xdp layer if hw flowtable is not available or does not support a specific kind of traffic.

---
 samples/bpf/Makefile                     |   7 +-
 samples/bpf/xdp_flowtable_offload.bpf.c  | 591 +++++++++++++++++++++++
 samples/bpf/xdp_flowtable_offload_user.c | 128 +++++
 3 files changed, 725 insertions(+), 1 deletion(-)
 create mode 100644 samples/bpf/xdp_flowtable_offload.bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload_user.c
samples/bpf/Makefile +6 -1
index 9aa027b144df6..a3d089ca224d5 100644
@@ -46,6 +46,7 @@ tprogs-y += xdp_fwd
 tprogs-y += task_fd_query
 tprogs-y += ibumad
 tprogs-y += hbm
+tprogs-y += xdp_flowtable_offload
 
 # Libbpf dependencies
 LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
@@ -98,6 +99,7 @@ ibumad-objs := ibumad_user.o
 hbm-objs := hbm.o $(CGROUP_HELPERS)
 
 xdp_router_ipv4-objs := xdp_router_ipv4_user.o $(XDP_SAMPLE)
+xdp_flowtable_offload-objs := xdp_flowtable_offload_user.o $(XDP_SAMPLE)
 
 # Tell kbuild to always build the programs
 always-y := $(tprogs-y)
@@ -306,6 +308,7 @@ $(obj)/$(TRACE_HELPERS) $(obj)/$(CGROUP_HELPERS) $(obj)/$(XDP_SAMPLE): | libbpf_
 .PHONY: libbpf_hdrs
 
 $(obj)/xdp_router_ipv4_user.o: $(obj)/xdp_router_ipv4.skel.h
+$(obj)/xdp_flowtable_offload_user.o: $(obj)/xdp_flowtable_offload.skel.h
 
 $(obj)/tracex5.bpf.o: $(obj)/syscall_nrs.h
 $(obj)/hbm_out_kern.o: $(src)/hbm.h $(src)/hbm_kern.h
@@ -361,6 +364,7 @@ endef
 CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
 
 $(obj)/xdp_router_ipv4.bpf.o: $(obj)/xdp_sample.bpf.o
+$(obj)/xdp_flowtable_offload.bpf.o: $(obj)/xdp_sample.bpf.o
 
 $(obj)/%.bpf.o: $(src)/%.bpf.c $(obj)/vmlinux.h $(src)/xdp_sample.bpf.h $(src)/xdp_sample_shared.h
 	@echo "  CLANG-BPF " $@
@@ -370,10 +374,11 @@ $(obj)/%.bpf.o: $(src)/%.bpf.c $(obj)/vmlinux.h $(src)/xdp_sample.bpf.h $(src)/x
 		-I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \
 		-c $(filter %.bpf.c,$^) -o $@
 
-LINKED_SKELS := xdp_router_ipv4.skel.h
+LINKED_SKELS := xdp_router_ipv4.skel.h xdp_flowtable_offload.skel.h
 clean-files += $(LINKED_SKELS)
 
 xdp_router_ipv4.skel.h-deps := xdp_router_ipv4.bpf.o xdp_sample.bpf.o
+xdp_flowtable_offload.skel.h-deps := xdp_flowtable_offload.bpf.o xdp_sample.bpf.o
 
 LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.bpf.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))
 
samples/bpf/xdp_flowtable_offload.bpf.c new file +591 -0

591 lines not on this page · raw message

samples/bpf/xdp_flowtable_offload_user.c new file +128 -0

128 lines not on this page · raw message

Signature · 1 line
2.45.1
#7 lore raw

Re: [PATCH bpf-next v2 3/4] samples/bpf: Add bpf sample to offload flowtable traffic to xdp

Quoted 5 lines · Lorenzo Bianconi

Introduce xdp_flowtable_offload bpf sample to offload sw flowtable logic in xdp layer if hw flowtable is not available or does not support a specific kind of traffic.

Quoted 8 lines
---
 samples/bpf/Makefile                     |   7 +-
 samples/bpf/xdp_flowtable_offload.bpf.c  | 591 +++++++++++++++++++++++
 samples/bpf/xdp_flowtable_offload_user.c | 128 +++++
 3 files changed, 725 insertions(+), 1 deletion(-)
 create mode 100644 samples/bpf/xdp_flowtable_offload.bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload_user.c

I feel this sample code is dead on arrival.
Make selftest more real if you want people to use it as an example, but samples dir is just a dumping ground.
We shouldn't be adding anything to it.

#8 lore raw

Re: [PATCH bpf-next v2 3/4] samples/bpf: Add bpf sample to offload flowtable traffic to xdp

Quoted 15 lines · Alexei Starovoitov
Quoted 5 lines · Lorenzo Bianconi

Introduce xdp_flowtable_offload bpf sample to offload sw flowtable logic in xdp layer if hw flowtable is not available or does not support a specific kind of traffic.

Quoted 8 lines
---
 samples/bpf/Makefile                     |   7 +-
 samples/bpf/xdp_flowtable_offload.bpf.c  | 591 +++++++++++++++++++++++
 samples/bpf/xdp_flowtable_offload_user.c | 128 +++++
 3 files changed, 725 insertions(+), 1 deletion(-)
 create mode 100644 samples/bpf/xdp_flowtable_offload.bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload_user.c
Quoted 4 lines

I feel this sample code is dead on arrival.
Make selftest more real if you want people to use it as an example, but samples dir is just a dumping ground.
We shouldn't be adding anything to it.

Agreed. We can integrate a working sample into xdp-tools instead :)

-Toke

#9 lore raw

Re: [PATCH bpf-next v2 3/4] samples/bpf: Add bpf sample to offload flowtable traffic to xdp

Quoted 17 lines
Quoted 15 lines · Alexei Starovoitov
Quoted 13 lines · Lorenzo Bianconi

Introduce xdp_flowtable_offload bpf sample to offload sw flowtable logic in xdp layer if hw flowtable is not available or does not support a specific kind of traffic.

---
 samples/bpf/Makefile                     |   7 +-
 samples/bpf/xdp_flowtable_offload.bpf.c  | 591 +++++++++++++++++++++++
 samples/bpf/xdp_flowtable_offload_user.c | 128 +++++
 3 files changed, 725 insertions(+), 1 deletion(-)
 create mode 100644 samples/bpf/xdp_flowtable_offload.bpf.c
 create mode 100644 samples/bpf/xdp_flowtable_offload_user.c
Quoted 6 lines
Quoted 4 lines

I feel this sample code is dead on arrival.
Make selftest more real if you want people to use it as an example, but samples dir is just a dumping ground.
We shouldn't be adding anything to it.

Agreed. We can integrate a working sample into xdp-tools instead :)

ack fine, I can post a patch for xdp-tools.

Regards,
Lorenzo

Quoted 3 lines

-Toke

#10 lore raw

PATCH v2 4/4 selftests/bpf: Add selftest for bpf_xdp_flow_offload_lookup kfunc

In reply to Lorenzo Bianconi

Introduce e2e selftest for bpf_xdp_flow_offload_lookup kfunc through xdp_flowtable utility.

---
 tools/testing/selftests/bpf/Makefile          |  10 +-
 tools/testing/selftests/bpf/config            |   4 +
 .../selftests/bpf/progs/xdp_flowtable.c       | 141 +++++++++++++++++
 .../selftests/bpf/test_xdp_flowtable.sh       | 112 ++++++++++++++
 tools/testing/selftests/bpf/xdp_flowtable.c   | 142 ++++++++++++++++++
 5 files changed, 407 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.c
 create mode 100755 tools/testing/selftests/bpf/test_xdp_flowtable.sh
 create mode 100644 tools/testing/selftests/bpf/xdp_flowtable.c
tools/testing/selftests/bpf/Makefile +8 -2
index e0b3887b3d2df..7361c429bed62 100644
@@ -133,7 +133,8 @@ TEST_PROGS := test_kmod.sh \
 	test_bpftool_metadata.sh \
 	test_doc_build.sh \
 	test_xsk.sh \
-	test_xdp_features.sh
+	test_xdp_features.sh \
+	test_xdp_flowtable.sh
 
 TEST_PROGS_EXTENDED := with_addr.sh \
 	with_tunnels.sh ima_setup.sh verify_sig_setup.sh \
@@ -144,7 +145,7 @@ TEST_GEN_PROGS_EXTENDED = test_skb_cgroup_id_user \
 	flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
 	test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
 	xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \
-	xdp_features bpf_test_no_cfi.ko
+	xdp_features bpf_test_no_cfi.ko xdp_flowtable
 
 TEST_GEN_FILES += liburandom_read.so urandom_read sign-file uprobe_multi
 
@@ -476,6 +477,7 @@ test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
 xsk_xdp_progs.skel.h-deps := xsk_xdp_progs.bpf.o
 xdp_hw_metadata.skel.h-deps := xdp_hw_metadata.bpf.o
 xdp_features.skel.h-deps := xdp_features.bpf.o
+xdp_flowtable.skel.h-deps := xdp_flowtable.bpf.o
 
 LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))
 
@@ -710,6 +712,10 @@ $(OUTPUT)/xdp_features: xdp_features.c $(OUTPUT)/network_helpers.o $(OUTPUT)/xdp
 	$(call msg,BINARY,,$@)
 	$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
 
+$(OUTPUT)/xdp_flowtable: xdp_flowtable.c $(OUTPUT)/xdp_flowtable.skel.h | $(OUTPUT)
+	$(call msg,BINARY,,$@)
+	$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
+
 # Make sure we are able to include and link libbpf against c++.
 $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
 	$(call msg,CXX,,$@)
tools/testing/selftests/bpf/config +4 -0
index eeabd798bc3ae..1a9aea01145f7 100644
@@ -82,6 +82,10 @@ CONFIG_NF_CONNTRACK=y
 CONFIG_NF_CONNTRACK_MARK=y
 CONFIG_NF_DEFRAG_IPV4=y
 CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_TABLES=y
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NF_FLOW_TABLE=y
+CONFIG_NF_FLOW_TABLE_INET=y
 CONFIG_NF_NAT=y
 CONFIG_RC_CORE=y
 CONFIG_SECURITY=y
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +141 -0

141 lines not on this page · raw message

tools/testing/selftests/bpf/test_xdp_flowtable.sh new file +112 -0

112 lines not on this page · raw message

tools/testing/selftests/bpf/xdp_flowtable.c new file +142 -0

142 lines not on this page · raw message

Signature · 1 line
2.45.1
#11 lore raw

Re: [PATCH bpf-next v2 4/4] selftests/bpf: Add selftest for bpf_xdp_flow_offload_lookup kfunc

Quoted 96 lines · Lorenzo Bianconi

Introduce e2e selftest for bpf_xdp_flow_offload_lookup kfunc through xdp_flowtable utility.

---
 tools/testing/selftests/bpf/Makefile          |  10 +-
 tools/testing/selftests/bpf/config            |   4 +
 .../selftests/bpf/progs/xdp_flowtable.c       | 141 +++++++++++++++++
 .../selftests/bpf/test_xdp_flowtable.sh       | 112 ++++++++++++++
 tools/testing/selftests/bpf/xdp_flowtable.c   | 142 ++++++++++++++++++
 5 files changed, 407 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/xdp_flowtable.c
 create mode 100755 tools/testing/selftests/bpf/test_xdp_flowtable.sh
 create mode 100644 tools/testing/selftests/bpf/xdp_flowtable.c
tools/testing/selftests/bpf/Makefile +8 -2
index e0b3887b3d2df..7361c429bed62 100644
@@ -133,7 +133,8 @@ TEST_PROGS := test_kmod.sh \
        test_bpftool_metadata.sh \
        test_doc_build.sh \
        test_xsk.sh \
-       test_xdp_features.sh
+       test_xdp_features.sh \
+       test_xdp_flowtable.sh
 
 TEST_PROGS_EXTENDED := with_addr.sh \
        with_tunnels.sh ima_setup.sh verify_sig_setup.sh \
@@ -144,7 +145,7 @@ TEST_GEN_PROGS_EXTENDED = test_skb_cgroup_id_user \
        flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
        test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
        xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \
-       xdp_features bpf_test_no_cfi.ko
+       xdp_features bpf_test_no_cfi.ko xdp_flowtable
 
 TEST_GEN_FILES += liburandom_read.so urandom_read sign-file uprobe_multi
 
@@ -476,6 +477,7 @@ test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
 xsk_xdp_progs.skel.h-deps := xsk_xdp_progs.bpf.o
 xdp_hw_metadata.skel.h-deps := xdp_hw_metadata.bpf.o
 xdp_features.skel.h-deps := xdp_features.bpf.o
+xdp_flowtable.skel.h-deps := xdp_flowtable.bpf.o
 
 LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))
 
@@ -710,6 +712,10 @@ $(OUTPUT)/xdp_features: xdp_features.c $(OUTPUT)/network_helpers.o $(OUTPUT)/xdp
        $(call msg,BINARY,,$@)
        $(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
 
+$(OUTPUT)/xdp_flowtable: xdp_flowtable.c $(OUTPUT)/xdp_flowtable.skel.h | $(OUTPUT)
+       $(call msg,BINARY,,$@)
+       $(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
+
 # Make sure we are able to include and link libbpf against c++.
 $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
        $(call msg,CXX,,$@)
tools/testing/selftests/bpf/config +4 -0
index eeabd798bc3ae..1a9aea01145f7 100644
@@ -82,6 +82,10 @@ CONFIG_NF_CONNTRACK=y
 CONFIG_NF_CONNTRACK_MARK=y
 CONFIG_NF_DEFRAG_IPV4=y
 CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_TABLES=y
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NF_FLOW_TABLE=y
+CONFIG_NF_FLOW_TABLE_INET=y
 CONFIG_NF_NAT=y
 CONFIG_RC_CORE=y
 CONFIG_SECURITY=y
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +17 -0
new file mode 100644
index 0000000000000..888ac87790f90
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#define MAX_ERRNO      4095
+
+#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 flow_offload_tuple_rhash *
+bpf_xdp_flow_offload_lookup(struct xdp_md *,
+                           struct bpf_fib_lookup *) __ksym;

tools/testing/selftests/bpf/progs/xdp_flowtable.c line 27

Quoted 10 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +10 -0
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __type(key, __u32);
+       __type(value, __u32);
+       __uint(max_entries, 1);
+} stats SEC(".maps");
+
+static __always_inline bool
+xdp_flowtable_offload_check_iphdr(struct iphdr *iph)

Please do not use __always_inline in bpf code.
It was needed 10 years ago. Not any more.

tools/testing/selftests/bpf/test_xdp_flowtable.sh

Quoted 119 lines
tools/testing/selftests/bpf/progs/xdp_flowtable.c new file +114 -0
+{
+       /* ip fragmented traffic */
+       if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET))
+               return false;
+
+       /* ip options */
+       if (iph->ihl * 4 != sizeof(*iph))
+               return false;
+
+       if (iph->ttl <= 1)
+               return false;
+
+       return true;
+}
+
+static __always_inline bool
+xdp_flowtable_offload_check_tcp_state(void *ports, void *data_end, u8 proto)
+{
+       if (proto == IPPROTO_TCP) {
+               struct tcphdr *tcph = ports;
+
+               if (tcph + 1 > data_end)
+                       return false;
+
+               if (tcph->fin || tcph->rst)
+                       return false;
+       }
+
+       return true;
+}
+
+SEC("xdp.frags")
+int xdp_flowtable_do_lookup(struct xdp_md *ctx)
+{
+       void *data_end = (void *)(long)ctx->data_end;
+       struct flow_offload_tuple_rhash *tuplehash;
+       struct bpf_fib_lookup tuple = {
+               .ifindex = ctx->ingress_ifindex,
+       };
+       void *data = (void *)(long)ctx->data;
+       struct ethhdr *eth = data;
+       struct flow_ports *ports;
+       __u32 *val, key = 0;
+
+       if (eth + 1 > data_end)
+               return XDP_DROP;
+
+       switch (eth->h_proto) {
+       case bpf_htons(ETH_P_IP): {
+               struct iphdr *iph = data + sizeof(*eth);
+
+               ports = (struct flow_ports *)(iph + 1);
+               if (ports + 1 > data_end)
+                       return XDP_PASS;
+
+               /* sanity check on ip header */
+               if (!xdp_flowtable_offload_check_iphdr(iph))
+                       return XDP_PASS;
+
+               if (!xdp_flowtable_offload_check_tcp_state(ports, data_end,
+                                                          iph->protocol))
+                       return XDP_PASS;
+
+               tuple.family            = AF_INET;
+               tuple.tos               = iph->tos;
+               tuple.l4_protocol       = iph->protocol;
+               tuple.tot_len           = bpf_ntohs(iph->tot_len);
+               tuple.ipv4_src          = iph->saddr;
+               tuple.ipv4_dst          = iph->daddr;
+               tuple.sport             = ports->source;
+               tuple.dport             = ports->dest;
+               break;
+       }
+       case bpf_htons(ETH_P_IPV6): {
+               struct in6_addr *src = (struct in6_addr *)tuple.ipv6_src;
+               struct in6_addr *dst = (struct in6_addr *)tuple.ipv6_dst;
+               struct ipv6hdr *ip6h = data + sizeof(*eth);
+
+               ports = (struct flow_ports *)(ip6h + 1);
+               if (ports + 1 > data_end)
+                       return XDP_PASS;
+
+               if (ip6h->hop_limit <= 1)
+                       return XDP_PASS;
+
+               if (!xdp_flowtable_offload_check_tcp_state(ports, data_end,
+                                                          ip6h->nexthdr))
+                       return XDP_PASS;
+
+               tuple.family            = AF_INET6;
+               tuple.l4_protocol       = ip6h->nexthdr;
+               tuple.tot_len           = bpf_ntohs(ip6h->payload_len);
+               *src                    = ip6h->saddr;
+               *dst                    = ip6h->daddr;
+               tuple.sport             = ports->source;
+               tuple.dport             = ports->dest;
+               break;
+       }
+       default:
+               return XDP_PASS;
+       }
+
+       tuplehash = bpf_xdp_flow_offload_lookup(ctx, &tuple);
+       if (!tuplehash)
+               return XDP_PASS;
+
+       val = bpf_map_lookup_elem(&stats, &key);
+       if (val)
+               __sync_add_and_fetch(val, 1);
+
+       return XDP_PASS;
+}
+
+char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/test_xdp_flowtable.sh new file +0 -0
new file mode 100755
index 0000000000000..1a8a40aebbdf1

Sorry shell scripts are not allowed.
Integrate it into test_progs.

pw-bot: cr