Netdev List
 help / color / mirror / Atom feed
From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
To: netdev@vger.kernel.org
Cc: magnus.karlsson@intel.com, stfomichev@gmail.com, kuba@kernel.org,
	pabeni@redhat.com, tushar.vyavahare@intel.com,
	kerneljasonxing@gmail.com, bjorn@kernel.org,
	Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Subject: [PATCH net-next 4/4] selftests: net: move xdp_hw_metadata from selftests/bpf
Date: Thu,  5 Nov 2026 14:41:17 +0100	[thread overview]
Message-ID: <20261105134117.977655-5-maciej.fijalkowski@intel.com> (raw)
In-Reply-To: <20261105134117.977655-1-maciej.fijalkowski@intel.com>

Move xdp_hw_metadata and its XDP program to selftests/net, next to the
AF_XDP library in net/lib/xsk that the tool is built from.

The tool used test_progs and network_helpers only for start_server(),
two checksum helpers and strscpy(). Open the UDP socket with a local
helper, copy csum_tcpudp_magic() and csum_ipv6_magic(), and fill
ifr_name with snprintf(). Build the XDP program against the uapi
headers rather than vmlinux.h: mirror struct vlan_hdr and enum
xdp_rss_hash_type, and cast to void * in the bound checks.

Build the tool only when bpftool works, and install it without running
it, as it needs a NIC and a peer that sends it traffic. Copy
xdp_metadata.h rather than move it, as the xdp_metadata test in
test_progs still uses it. Update xsk-tx-metadata.rst and the XDP entry
of MAINTAINERS.

Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 Documentation/networking/xsk-tx-metadata.rst  |  2 +-
 MAINTAINERS                                   |  1 +
 tools/testing/selftests/bpf/.gitignore        |  1 -
 tools/testing/selftests/bpf/Makefile          |  8 --
 tools/testing/selftests/net/.gitignore        |  2 +
 tools/testing/selftests/net/Makefile          | 18 +++++
 .../xdp_hw_metadata.bpf.c}                    | 35 +++++---
 .../selftests/{bpf => net}/xdp_hw_metadata.c  | 81 +++++++++++++++++--
 tools/testing/selftests/net/xdp_metadata.h    | 67 +++++++++++++++
 9 files changed, 188 insertions(+), 27 deletions(-)
 rename tools/testing/selftests/{bpf/progs/xdp_hw_metadata.c => net/xdp_hw_metadata.bpf.c} (75%)
 rename tools/testing/selftests/{bpf => net}/xdp_hw_metadata.c (92%)
 create mode 100644 tools/testing/selftests/net/xdp_metadata.h

diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst
index f240930ca1df..ac15e5fddc6b 100644
--- a/Documentation/networking/xsk-tx-metadata.rst
+++ b/Documentation/networking/xsk-tx-metadata.rst
@@ -144,6 +144,6 @@ See ``tools/net/ynl/samples/netdev.c`` on how to query this information.
 Example
 =======
 
-See ``tools/testing/selftests/bpf/xdp_hw_metadata.c`` for an example
+See ``tools/testing/selftests/net/xdp_hw_metadata.c`` for an example
 program that handles TX metadata. Also see https://github.com/fomichev/xskgen
 for a more bare-bones example.
diff --git a/MAINTAINERS b/MAINTAINERS
index 12e444f1f7a6..2123857f3365 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -30418,6 +30418,7 @@ F:	net/core/xdp.c
 F:	samples/bpf/xdp*
 F:	tools/testing/selftests/bpf/*/*xdp*
 F:	tools/testing/selftests/bpf/*xdp*
+F:	tools/testing/selftests/net/*xdp*
 K:	(?:\b|_)xdp(?:\b|_)
 
 XDP SOCKETS (AF_XDP)
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index cd098c0271ef..e318a38035d2 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -38,7 +38,6 @@ test_cpp
 *.tmp
 xdp_redirect_multi
 xdp_synproxy
-xdp_hw_metadata
 xdp_features
 verification_cert.h
 *.BTF
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 203f2cedaf77..2d46e47bab60 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -56,7 +56,6 @@ TEST_GEN_PROGS_EXTENDED = \
 	test_cpp \
 	veristat \
 	xdp_features \
-	xdp_hw_metadata \
 	xdp_synproxy
 
 TEST_GEN_FILES += $(TEST_KMODS) liburandom_read.so urandom_read sign-file uprobe_multi
@@ -568,13 +567,6 @@ $(OUTPUT)/test_verifier: test_verifier.c verifier/tests.h $(BPFOBJ) | $(OUTPUT)
 	$(call msg,BINARY,,$@)
 	$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
 
-$(OUTPUT)/xdp_hw_metadata: xdp_hw_metadata.c ../net/lib/xsk/xsk.c network_helpers.c \
-			   $(TOOLSDIR)/lib/find_bit.c xdp_metadata.h \
-			   ../net/lib/xsk/xsk.h network_helpers.h test_progs.h bpf_util.h \
-			   $(OUTPUT)/xdp_hw_metadata.skel.h $(BPFOBJ) | $(OUTPUT)
-	$(call msg,BINARY,,$@)
-	$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
-
 $(OUTPUT)/xdp_features: xdp_features.c network_helpers.c xdp_features.h \
 			   network_helpers.h \
 			   test_progs.h bpf_util.h $(OUTPUT)/xdp_features.skel.h \
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 21412510ac26..0bd88b48a53c 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -60,3 +60,5 @@ udp_splice_checksum
 udpgso
 udpgso_bench_rx
 udpgso_bench_tx
+xdp_hw_metadata
+xdp_hw_metadata.skel.h
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 7dba412401ea..9925360a9a98 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -226,6 +226,15 @@ TEST_GEN_PROGS += $(YNL_GEN_PROGS)
 
 TEST_GEN_FILES += $(patsubst %.c,%.o,$(wildcard *.bpf.c))
 
+# xdp_hw_metadata needs a working bpftool to generate its skeleton
+BPFTOOL ?= bpftool
+HAS_BPFTOOL := $(shell $(BPFTOOL) version >/dev/null 2>&1 && echo y)
+ifeq ($(HAS_BPFTOOL),y)
+TEST_GEN_FILES += xdp_hw_metadata
+else
+$(warning excluding xdp_hw_metadata, bpftool not installed or not working)
+endif
+
 TEST_INCLUDES := forwarding/lib.sh
 
 include ../lib.mk
@@ -249,3 +258,12 @@ $(OUTPUT)/bind_bhash: LDLIBS += -lpthread
 $(OUTPUT)/io_uring_zerocopy_tx: CFLAGS += -I../../../include/
 
 include bpf.mk
+
+# Reference tool for checking XDP RX/TX metadata on real HW, built with
+# the AF_XDP library of net/lib/xsk.
+$(OUTPUT)/xdp_hw_metadata: xdp_hw_metadata.c xdp_metadata.h lib/xsk/xsk.c \
+			   lib/xsk/xsk.h $(OUTPUT)/xdp_hw_metadata.skel.h $(BPFOBJ)
+	$(call msg,CC,,$@)
+	$(Q)$(CC) -I$(top_srcdir)/tools/include $(CFLAGS) -I$(OUTPUT) \
+		-I$(SCRATCH_DIR)/include \
+		$(filter %.c,$^) $(BPFOBJ) $(LDLIBS) -lelf -lz -o $@
diff --git a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c b/tools/testing/selftests/net/xdp_hw_metadata.bpf.c
similarity index 75%
rename from tools/testing/selftests/bpf/progs/xdp_hw_metadata.c
rename to tools/testing/selftests/net/xdp_hw_metadata.bpf.c
index 330ece2eabdb..a183436646b1 100644
--- a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c
+++ b/tools/testing/selftests/net/xdp_hw_metadata.bpf.c
@@ -1,10 +1,23 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include <vmlinux.h>
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
 #include "xdp_metadata.h"
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_endian.h>
 
+/* Mirror of struct vlan_hdr from include/linux/if_vlan.h, which is not
+ * part of the UAPI headers.
+ */
+struct vlan_hdr {
+	__be16 h_vlan_TCI;
+	__be16 h_vlan_encapsulated_proto;
+};
+
 struct {
 	__uint(type, BPF_MAP_TYPE_XSKMAP);
 	__uint(max_entries, 256);
@@ -39,25 +52,29 @@ int rx(struct xdp_md *ctx)
 	data_end = (void *)(long)ctx->data_end;
 	eth = data;
 
-	if (eth + 1 < data_end && (eth->h_proto == bpf_htons(ETH_P_8021AD) ||
-				   eth->h_proto == bpf_htons(ETH_P_8021Q)))
+	if ((void *)(eth + 1) < data_end &&
+	    (eth->h_proto == bpf_htons(ETH_P_8021AD) ||
+	     eth->h_proto == bpf_htons(ETH_P_8021Q)))
 		eth = (void *)eth + sizeof(struct vlan_hdr);
 
-	if (eth + 1 < data_end && eth->h_proto == bpf_htons(ETH_P_8021Q))
+	if ((void *)(eth + 1) < data_end &&
+	    eth->h_proto == bpf_htons(ETH_P_8021Q))
 		eth = (void *)eth + sizeof(struct vlan_hdr);
 
-	if (eth + 1 < data_end) {
+	if ((void *)(eth + 1) < data_end) {
 		if (eth->h_proto == bpf_htons(ETH_P_IP)) {
 			iph = (void *)(eth + 1);
-			if (iph + 1 < data_end && iph->protocol == IPPROTO_UDP)
+			if ((void *)(iph + 1) < data_end &&
+			    iph->protocol == IPPROTO_UDP)
 				udp = (void *)(iph + 1);
 		}
 		if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
 			ip6h = (void *)(eth + 1);
-			if (ip6h + 1 < data_end && ip6h->nexthdr == IPPROTO_UDP)
+			if ((void *)(ip6h + 1) < data_end &&
+			    ip6h->nexthdr == IPPROTO_UDP)
 				udp = (void *)(ip6h + 1);
 		}
-		if (udp && udp + 1 > data_end)
+		if (udp && (void *)(udp + 1) > data_end)
 			udp = NULL;
 	}
 
@@ -82,7 +99,7 @@ int rx(struct xdp_md *ctx)
 	data_meta = (void *)(long)ctx->data_meta;
 	meta = data_meta;
 
-	if (meta + 1 > data) {
+	if ((void *)(meta + 1) > data) {
 		__sync_add_and_fetch(&pkts_fail, 1);
 		return XDP_PASS;
 	}
diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/net/xdp_hw_metadata.c
similarity index 92%
rename from tools/testing/selftests/bpf/xdp_hw_metadata.c
rename to tools/testing/selftests/net/xdp_hw_metadata.c
index ab3f5fc56e86..6db928f1ffdc 100644
--- a/tools/testing/selftests/bpf/xdp_hw_metadata.c
+++ b/tools/testing/selftests/net/xdp_hw_metadata.c
@@ -16,11 +16,11 @@
  * - TX launch time HW offload is requested for transmission
  */
 
-#include <test_progs.h>
-#include <network_helpers.h>
 #include "xdp_hw_metadata.skel.h"
-#include "xsk.h"
+#include "lib/xsk/xsk.h"
 
+#include <bpf/bpf.h>
+#include <errno.h>
 #include <error.h>
 #include <linux/kernel.h>
 #include <linux/bits.h>
@@ -47,6 +47,9 @@
 #include <linux/ethtool.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <signal.h>
 
 #include "xdp_metadata.h"
 
@@ -87,7 +90,69 @@ int launch_time_queue;
 	system(command);					\
 })
 
-void test__fail(void) { /* for network_helpers.c */ }
+static __u16 csum_fold(__u32 csum)
+{
+	csum = (csum & 0xffff) + (csum >> 16);
+	csum = (csum & 0xffff) + (csum >> 16);
+
+	return (__u16)~csum;
+}
+
+static __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
+				 __u8 proto, __wsum csum)
+{
+	__u64 s = csum;
+
+	s += (__u32)saddr;
+	s += (__u32)daddr;
+	s += htons(proto + len);
+	s = (s & 0xffffffff) + (s >> 32);
+	s = (s & 0xffffffff) + (s >> 32);
+
+	return csum_fold((__u32)s);
+}
+
+static __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+			       const struct in6_addr *daddr, __u32 len,
+			       __u8 proto, __wsum csum)
+{
+	__u64 s = csum;
+	int i;
+
+	for (i = 0; i < 4; i++)
+		s += (__u32)saddr->s6_addr32[i];
+	for (i = 0; i < 4; i++)
+		s += (__u32)daddr->s6_addr32[i];
+	s += htons(proto + len);
+	s = (s & 0xffffffff) + (s >> 32);
+	s = (s & 0xffffffff) + (s >> 32);
+
+	return csum_fold((__u32)s);
+}
+
+static int open_udp_server(__u16 port)
+{
+	struct sockaddr_in6 addr = {
+		.sin6_family = AF_INET6,
+		.sin6_port = htons(port),
+		.sin6_addr = IN6ADDR_ANY_INIT,
+	};
+	struct timeval timeo = { .tv_sec = 1 };
+	int fd;
+
+	fd = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (fd < 0)
+		return -1;
+
+	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)) ||
+	    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)) ||
+	    bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
 
 static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id)
 {
@@ -550,7 +615,7 @@ static int rxq_num(const char *ifname)
 	struct ifreq ifr = {
 		.ifr_data = (void *)&ch,
 	};
-	strscpy(ifr.ifr_name, ifname);
+	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname);
 	int fd, ret;
 
 	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
@@ -571,7 +636,7 @@ static void hwtstamp_ioctl(int op, const char *ifname, struct hwtstamp_config *c
 	struct ifreq ifr = {
 		.ifr_data = (void *)cfg,
 	};
-	strscpy(ifr.ifr_name, ifname);
+	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname);
 	int fd, ret;
 
 	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
@@ -853,9 +918,9 @@ int main(int argc, char *argv[])
 		error(1, -ret, "xdp_hw_metadata__load");
 
 	printf("prepare skb endpoint...\n");
-	server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 9092, 1000);
+	server_fd = open_udp_server(9092);
 	if (server_fd < 0)
-		error(1, errno, "start_server");
+		error(1, errno, "open_udp_server");
 	timestamping_enable(server_fd,
 			    SOF_TIMESTAMPING_SOFTWARE |
 			    SOF_TIMESTAMPING_RAW_HARDWARE);
diff --git a/tools/testing/selftests/net/xdp_metadata.h b/tools/testing/selftests/net/xdp_metadata.h
new file mode 100644
index 000000000000..9371889f76d3
--- /dev/null
+++ b/tools/testing/selftests/net/xdp_metadata.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#pragma once
+
+#ifndef ETH_P_IP
+#define ETH_P_IP 0x0800
+#endif
+
+#ifndef ETH_P_IPV6
+#define ETH_P_IPV6 0x86DD
+#endif
+
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif
+
+#ifndef ETH_P_8021AD
+#define ETH_P_8021AD 0x88A8
+#endif
+
+#ifndef BIT
+#define BIT(nr)			(1 << (nr))
+#endif
+
+/* Non-existent checksum status */
+#define XDP_CHECKSUM_MAGIC	BIT(2)
+
+/* Mirror of enum xdp_rss_hash_type from include/net/xdp.h, which is not
+ * part of the UAPI headers.
+ */
+enum xdp_rss_hash_type {
+	XDP_RSS_L3_IPV4		= BIT(0),
+	XDP_RSS_L3_IPV6		= BIT(1),
+	XDP_RSS_L3_DYNHDR	= BIT(2),
+	XDP_RSS_L4		= BIT(3),
+	XDP_RSS_L4_TCP		= BIT(4),
+	XDP_RSS_L4_UDP		= BIT(5),
+	XDP_RSS_L4_SCTP		= BIT(6),
+	XDP_RSS_L4_IPSEC	= BIT(7),
+	XDP_RSS_L4_ICMP		= BIT(8),
+};
+
+enum xdp_meta_field {
+	XDP_META_FIELD_TS	= BIT(0),
+	XDP_META_FIELD_RSS	= BIT(1),
+	XDP_META_FIELD_VLAN_TAG	= BIT(2),
+};
+
+struct xdp_meta {
+	union {
+		__u64 rx_timestamp;
+		__s32 rx_timestamp_err;
+	};
+	__u64 xdp_timestamp;
+	__u32 rx_hash;
+	union {
+		__u32 rx_hash_type;
+		__s32 rx_hash_err;
+	};
+	union {
+		struct {
+			__be16 rx_vlan_proto;
+			__u16 rx_vlan_tci;
+		};
+		__s32 rx_vlan_tag_err;
+	};
+	enum xdp_meta_field hint_valid;
+};
-- 
2.43.0


  parent reply	other threads:[~2026-11-05 13:44 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 13:41 [PATCH net-next 0/4] selftests: move the AF_XDP test suite from bpf to net Maciej Fijalkowski
2026-11-05 13:41 ` [PATCH net-next 1/4] selftests/bpf: drop the test_progs AF_XDP wrapper Maciej Fijalkowski
2026-11-05 13:41 ` [PATCH net-next 2/4] selftests: net: add a generic rule for BPF skeletons Maciej Fijalkowski
2026-11-05 13:41 ` [PATCH net-next 3/4] selftests: xsk: move the AF_XDP test suite to selftests/net Maciej Fijalkowski
2026-11-05 13:41 ` Maciej Fijalkowski [this message]
2026-11-05 20:43 ` [PATCH net-next 0/4] selftests: move the AF_XDP test suite from bpf to net Stanislav Fomichev
2026-11-09 12:44   ` Maciej Fijalkowski
2026-11-09 16:52     ` Stanislav Fomichev
2026-11-09 19:12       ` Maciej Fijalkowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261105134117.977655-5-maciej.fijalkowski@intel.com \
    --to=maciej.fijalkowski@intel.com \
    --cc=bjorn@kernel.org \
    --cc=kerneljasonxing@gmail.com \
    --cc=kuba@kernel.org \
    --cc=magnus.karlsson@intel.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=stfomichev@gmail.com \
    --cc=tushar.vyavahare@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox