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
next prev 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