@@ -3302,6 +3302,9 @@ F: support/testing/tests/package/test_python_xmodem.py
F: support/testing/tests/toolchain/test_external_arm.py
F: toolchain/
+N: Théo Lebrun <theo.lebrun@bootlin.com>
+F: package/xdp-tools/
+
N: Timo Ketola <timo.ketola@exertus.fi>
F: package/fbgrab/
@@ -159,6 +159,7 @@ menu "Debugging, profiling and benchmark"
source "package/valgrind/Config.in"
source "package/vmtouch/Config.in"
source "package/whetstone/Config.in"
+ source "package/xdp-tools/Config.in"
endmenu
menu "Development tools"
new file mode 100644
@@ -0,0 +1,116 @@
+From cb61380442b407cff5c6e3ee7df2204df75bf540 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= <theo.lebrun@bootlin.com>
+Date: Thu, 27 Aug 2026 16:52:46 +0200
+Subject: [PATCH] lib: build BPF objects freestanding
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BPF objects target the arch-independent BPF ISA but get access to the
+arch-specific target sysroot in BPF_CFLAGS. This causes trouble.
+
+Issues are:
+
+ - Arch-specific kernel UAPI headers provide <asm/byteorder.h> which can
+ be broken. MIPS version uses __MIPSEB__/__MIPSEL__ for endianess
+ detection and #error out if both are undefined. ARM64
+ does #ifdef __AARCH64EB__ #else ..., meaning we fallback silently to
+ little-endian. Luckily everyone does LE on ARM64.
+
+ - Arch-specific kernel UAPI headers provide <asm/bitsperlong.h> which
+ can be broken in similar ways. MIPS defines __BITS_PER_LONG using
+ _MIPS_SZLONG, which is undefined. Again, a known working architecture
+ has a silent fallback: x86 picks 32 or 64 based on if __x86_64__ is
+ defined.
+
+ - `-nostdlibinc` is needed to ensure our host clang isn't falling back
+ to host headers, which might work by accident.
+
+We get close to the same setup as the kernel BPF selftests. They however
+do not introduce generic asm/*.h, they prefer a list of -D macros.
+
+Upstream: Not submitted
+Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
+---
+ headers/asm/bitsperlong.h | 13 +++++++++++++
+ headers/asm/byteorder.h | 16 ++++++++++++++++
+ lib/defines.mk | 5 ++++-
+ lib/libxdp/tests/Makefile | 1 +
+ 4 files changed, 34 insertions(+), 1 deletion(-)
+ create mode 100644 headers/asm/bitsperlong.h
+ create mode 100644 headers/asm/byteorder.h
+
+diff --git a/headers/asm/bitsperlong.h b/headers/asm/bitsperlong.h
+new file mode 100644
+index 0000000..fa4c240
+--- /dev/null
++++ b/headers/asm/bitsperlong.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++/*
++ * Arch-neutral bitsperlong for the BPF targets (bpfel/bpfeb), shadowing
++ * the arch-specific asm/bitsperlong.h copies which select their value
++ * with compiler backend macros a -target bpf compile never defines
++ * (_MIPS_SZLONG, __x86_64__, ...).
++ */
++#ifndef __ASM_BITSPERLONG_H
++#define __ASM_BITSPERLONG_H
++
++#include <asm-generic/bitsperlong.h>
++
++#endif /* __ASM_BITSPERLONG_H */
+diff --git a/headers/asm/byteorder.h b/headers/asm/byteorder.h
+new file mode 100644
+index 0000000..3fd92b8
+--- /dev/null
++++ b/headers/asm/byteorder.h
+@@ -0,0 +1,16 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++/*
++ * Arch-neutral byteorder for the BPF targets (bpfel/bpfeb), shadowing
++ * the arch-specific asm/byteorder.h copies which select their flavour
++ * with compiler backend macros a -target bpf compile never defines.
++ */
++#ifndef _ASM_BYTEORDER_H
++#define _ASM_BYTEORDER_H
++
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++#include <linux/byteorder/little_endian.h>
++#else
++#include <linux/byteorder/big_endian.h>
++#endif
++
++#endif /* _ASM_BYTEORDER_H */
+diff --git a/lib/defines.mk b/lib/defines.mk
+index 411a97e..b14e5cc 100644
+--- a/lib/defines.mk
++++ b/lib/defines.mk
+@@ -43,7 +43,10 @@ endif
+ DEFINES += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+
+ CFLAGS += -std=gnu11 -Wextra -Werror $(DEFINES) $(ARCH_INCLUDES)
+-BPF_CFLAGS += $(DEFINES) $(filter -ffile-prefix-map=%,$(CFLAGS)) $(filter -I%,$(CFLAGS)) $(ARCH_INCLUDES)
++BPF_CFLAGS += $(DEFINES) $(filter -ffile-prefix-map=%,$(CFLAGS)) \
++ -nostdlibinc \
++ $(subst -I,-isystem ,$(filter-out -I$(HEADER_DIR) -I$(LIB_DIR)/util,$(filter -I%,$(CFLAGS)))) \
++ $(ARCH_INCLUDES)
+
+ CONFIGMK := $(LIB_DIR)/../config.mk
+ LIBMK := Makefile $(CONFIGMK) $(LIB_DIR)/defines.mk $(LIB_DIR)/common.mk $(LIB_DIR)/../version.mk
+diff --git a/lib/libxdp/tests/Makefile b/lib/libxdp/tests/Makefile
+index 29f0292..e3e6d7a 100644
+--- a/lib/libxdp/tests/Makefile
++++ b/lib/libxdp/tests/Makefile
+@@ -47,6 +47,7 @@ endif
+ LIBXDP_SOURCES := $(wildcard $(LIBXDP_DIR)/*.[ch] $(LIBXDP_DIR)/*.in)
+
+ CFLAGS += -I$(HEADER_DIR)
++BPF_CFLAGS += -I$(HEADER_DIR)
+
+ BPF_HEADERS := $(wildcard $(HEADER_DIR)/bpf/*.h) $(wildcard $(HEADER_DIR)/xdp/*.h)
+
+--
+Théo Lebrun, Bootlin
+Embedded Linux and Kernel engineering
+https://bootlin.com
+
new file mode 100644
@@ -0,0 +1,64 @@
+From 3ed00b9c9764d49bc78a44acdcfb2402780eb498 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= <theo.lebrun@bootlin.com>
+Date: Fri, 28 Aug 2026 09:30:14 +0200
+Subject: [PATCH] lib/testing: support busybox mktemp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The test suite uses GNU-only mktemp options that BusyBox mktemp does not
+support:
+
+ mktemp: unrecognized option '--suffix=.xdptest'
+
+Fix both mktemp callers (test_runner.sh & test-libxdp.sh) by avoiding
+GNU-isms and using only busybox supported flags. This allows running
+the test suite using busybox, somewhat.
+
+Upstream: Not submitted
+Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
+---
+ lib/libxdp/tests/test-libxdp.sh | 4 ++--
+ lib/testing/test_runner.sh | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/lib/libxdp/tests/test-libxdp.sh b/lib/libxdp/tests/test-libxdp.sh
+index 50352f3..141395e 100644
+--- a/lib/libxdp/tests/test-libxdp.sh
++++ b/lib/libxdp/tests/test-libxdp.sh
+@@ -15,7 +15,7 @@ test_link_so()
+ {
+ [ -n "${CC:-}" ] || return $SKIPPED_TEST
+
+- TMPDIR=$(mktemp --tmpdir -d libxdp-test.XXXXXX)
++ TMPDIR=$(mktemp -d -t libxdp-test.XXXXXX)
+ cat >$TMPDIR/libxdptest.c <<EOF
+ #include <xdp/libxdp.h>
+ int main(int argc, char **argv) {
+@@ -34,7 +34,7 @@ test_link_a()
+ {
+ [ -n "${CC:-}" ] || return $SKIPPED_TEST
+
+- TMPDIR=$(mktemp --tmpdir -d libxdp-test.XXXXXX)
++ TMPDIR=$(mktemp -d -t libxdp-test.XXXXXX)
+ cat >$TMPDIR/libxdptest.c <<EOF
+ #include <xdp/libxdp.h>
+ int main(int argc, char **argv) {
+diff --git a/lib/testing/test_runner.sh b/lib/testing/test_runner.sh
+index 0220c32..d9b0f8b 100755
+--- a/lib/testing/test_runner.sh
++++ b/lib/testing/test_runner.sh
+@@ -293,7 +293,7 @@ check_prereq()
+ die "This script needs root permissions to run."
+ fi
+
+- STATEDIR="$(mktemp -d --tmpdir=${TMPDIR:-/tmp} --suffix=.xdptest)"
++ STATEDIR="$(mktemp -d -p "${TMPDIR:-/tmp}" xdptest.XXXXXX)"
+ if [ $? -ne 0 ]; then
+ die "Unable to create state dir in $TMPDIR"
+ fi
+--
+Théo Lebrun, Bootlin
+Embedded Linux and Kernel engineering
+https://bootlin.com
+
new file mode 100644
@@ -0,0 +1,55 @@
+config BR2_PACKAGE_XDP_TOOLS
+ bool "xdp-tools"
+ depends on BR2_USE_WCHAR # elfutils
+ depends on !BR2_STATIC_LIBS # elfutils, libbpf
+ depends on BR2_TOOLCHAIN_HAS_THREADS # elfutils
+ depends on BR2_TOOLCHAIN_HAS_SYNC_4 # libbpf
+ depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_5_0
+ select BR2_PACKAGE_HOST_LLVM_BPF
+ select BR2_PACKAGE_ELFUTILS
+ select BR2_PACKAGE_LIBBPF
+ select BR2_PACKAGE_ZLIB
+ select BR2_PACKAGE_LIBPCAP
+ help
+ xdp-tools: the XDP utility programs and the libxdp
+ library that build on top of libbpf.
+
+ Programs are: xdp-bench, xdp-dump, xdp-filter,
+ xdp-forward, xdp-loader, xdp-monitor, xdp-trafficgen.
+ Quite a few BPF programs are compiled using host-clang.
+
+ https://github.com/xdp-project/xdp-tools
+
+if BR2_PACKAGE_XDP_TOOLS
+
+config BR2_PACKAGE_XDP_TOOLS_INSTALL_TESTS
+ bool "install test suite"
+ depends on BR2_INSTALL_LIBSTDCPP # wireshark
+ select BR2_PACKAGE_BASH
+ select BR2_PACKAGE_BUSYBOX_SHOW_OTHERS # bash
+ select BR2_PACKAGE_ETHTOOL
+ select BR2_PACKAGE_IPROUTE2 # tc
+ select BR2_PACKAGE_TCPDUMP
+ select BR2_PACKAGE_WIRESHARK # tshark, capinfos
+ select BR2_PACKAGE_NFTABLES # nft
+ select BR2_PACKAGE_SOCAT
+ select BR2_PACKAGE_NDISC6
+ select BR2_PACKAGE_NDISC6_NDISC6 # ndisc6 tool
+ help
+ Install the xdp-tools test suite (binaries, BPF
+ objects and test_runner.sh) under /usr/share/xdp-tools/
+ which can be ran on the target as root.
+
+ The runner has a list of required tools: capinfos ethtool
+ ip ping sed tc tcpdump timeout tshark nft socat ndisc6 arping.
+
+comment "xdp-tools test suite needs a toolchain w/ C++ support"
+ depends on !BR2_INSTALL_LIBSTDCPP
+
+endif
+
+comment "xdp-tools needs a toolchain w/ wchar, dynamic library, threads, sync, headers >= 5.0"
+ depends on !BR2_USE_WCHAR || BR2_STATIC_LIBS \
+ || !BR2_TOOLCHAIN_HAS_THREADS \
+ || !BR2_TOOLCHAIN_HAS_SYNC_4 \
+ || !BR2_TOOLCHAIN_HEADERS_AT_LEAST_5_0
new file mode 100644
@@ -0,0 +1,59 @@
+From f92cac6cf76705fe476f6288c8041390cabdf136 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= <theo.lebrun@bootlin.com>
+Date: Thu, 6 Aug 2026 14:01:17 +0200
+Subject: [PATCH] libxdp: embed BPF objects with assembler rather than partial
+ linking
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+To embed BPF programs, libxdp uses the linker in partial link mode, with
+a binary input. For some obscure reason, on MIPS, `ld -b binary`
+generates an object with generic default ABI (e_flags mips3,
+no .MIPS.abiflags and no .MIPS.options section) instead of the
+toolchain ABI (mips64r6 n64 for example).
+
+The partial linking therefore succeeds, but then the next link step
+rightfully fails linking objects of different ABI (even though one
+contains 0 target code).
+
+ ld: failed to merge target specific data of file libxdp.a(xdp-dispatcher.embed.o)
+
+Calling the linker indirectly (through the gcc command) or directly
+makes no difference, and I couldn't find flags to generate the right
+ABI (and those flags would be ABI specific anyway).
+
+Instead, avoid the linker and use the assembler with .incbin which
+generates an object with a reasonable header. What is not reasonable,
+is the assembler incantation required.
+
+One note on the .note.GNU-stack section: it replaces
+the -Wl,-z,noexecstack which marks the object non-exec-stack.
+
+Upstream: Not submitted
+Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
+---
+ lib/libxdp/Makefile | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/lib/libxdp/Makefile b/lib/libxdp/Makefile
+index 7ea7e7e..279da81 100644
+--- a/lib/libxdp/Makefile
++++ b/lib/libxdp/Makefile
+@@ -134,8 +134,9 @@ $(TEMPLATED_SOURCES): %.c: %.c.in Makefile
+ $(QUIET_M4)$(M4) $(DEFINES) $< > $@ || ( ret=$$?; rm -f $@; exit $$ret )
+
+ $(EMBEDDED_XDP_OBJS): %.embed.o: %.o
+- $(QUIET_CC)$(CC) -r -nostdlib -Wl,-z,noexecstack,--format=binary $(LDFLAGS) -o $@ $<
+- $(Q)$(OBJCOPY) --rename-section .data=.rodata,alloc,load,readonly,data,contents $@
++ $(Q)b=$$(printf '%s' '$(notdir $<)'|tr -c 'A-Za-z0-9' '_'); printf '.section .rodata,"a"\n.globl _binary_%s_start\n.globl _binary_%s_end\n.globl _binary_%s_size\n_binary_%s_start:\n.incbin "%s"\n_binary_%s_end:\n.set _binary_%s_size, _binary_%s_end - _binary_%s_start\n.section .note.GNU-stack\n' $$b $$b $$b $$b '$<' $$b $$b $$b $$b > $@.S
++ $(QUIET_CC)$(CC) -c $@.S -o $@
++ $(Q)rm -f $@.S
+
+ $(XDP_OBJS): %.o: %.c $(BPF_HEADERS) $(LIBMK)
+ $(QUIET_CLANG)$(CLANG) -target $(BPF_TARGET) $(BPF_CFLAGS) -O2 -c -g -o $@ $<
+--
+Théo Lebrun, Bootlin
+Embedded Linux and Kernel engineering
+https://bootlin.com
+
new file mode 100644
@@ -0,0 +1,3 @@
+all:
+install:
+clean:
new file mode 100644
@@ -0,0 +1,8 @@
+# Hashes from: https://github.com/xdp-project/xdp-tools/releases
+sha256 b4c30d10147e71059c118aea17f415fd986b709c4600201f85fef0b6f4c8cb47 xdp-tools-1.6.3.tar.gz
+
+# Locally computed:
+sha256 734d0b7377af175d51c5ae07c061037862eb8d0d5a335544cfef9861c1895a2a LICENSE
+sha256 aaf32cd2d7cbb2af7ddeb3108e87436d36dbdb080e85cf839defa4b36bc830c5 LICENSES/GPL-2.0
+sha256 0b9a4febcdee6de55872501d5c1a8f5d8b0d1650cd4d5351995ceb22e889f8ca LICENSES/LGPL-2.1
+sha256 6313108c23efffa36948f8b2cff1560a5935373b527b0e1a837cc77e6ed1bacd LICENSES/BSD-2-Clause
new file mode 100644
@@ -0,0 +1,79 @@
+################################################################################
+#
+# xdp-tools
+#
+################################################################################
+
+XDP_TOOLS_VERSION = 1.6.3
+XDP_TOOLS_SITE = https://github.com/xdp-project/xdp-tools/releases/download/v$(XDP_TOOLS_VERSION)
+XDP_TOOLS_LICENSE = GPL-2.0, LGPL-2.1, BSD-2-Clause
+XDP_TOOLS_LICENSE_FILES = LICENSE LICENSES/GPL-2.0 LICENSES/LGPL-2.1 LICENSES/BSD-2-Clause
+XDP_TOOLS_DEPENDENCIES = host-clang host-bpftool host-m4 host-pkgconf \
+ libbpf elfutils zlib libpcap
+XDP_TOOLS_INSTALL_STAGING = YES
+
+# Avoid bin-arch triggering on eBPF objects.
+XDP_TOOLS_BIN_ARCH_EXCLUDE = /usr/lib/bpf
+
+# FORCE_SYSTEM_LIBBPF is to avoid xdp-tools compiling a vendored libbpf.
+# Use clang.br_real (avoid clang wrapper) which injects target-specific flags.
+XDP_TOOLS_CONF_ENV = \
+ FORCE_SYSTEM_LIBBPF=1 \
+ CLANG="$(HOST_DIR)/bin/clang.br_real" \
+ BPF_TARGET=$(if $(filter BIG,$(BR2_ENDIAN)),bpfeb,bpfel) \
+ BPFTOOL="$(HOST_DIR)/sbin/bpftool" \
+ M4="$(HOST_DIR)/bin/m4" \
+ EMACS= \
+ PKG_CONFIG="$(PKG_CONFIG_HOST_BINARY)" \
+ PKG_CONFIG_SYSROOT_DIR="$(STAGING_DIR)" \
+ PKG_CONFIG_LIBDIR="$(STAGING_DIR)/usr/lib/pkgconfig:$(STAGING_DIR)/usr/share/pkgconfig"
+
+# Tests are unconditionally built and installed; skip them by pointing TEST_DIR
+# at a stub directory containing a no-op Makefile.
+# PRODUCTION=1 is to drop -DDEBUG mode.
+XDP_TOOLS_MAKE_OPTS = PREFIX=/usr V=1 PRODUCTION=1 \
+ $(if $(BR2_PACKAGE_XDP_TOOLS_INSTALL_TESTS),,TEST_DIR=$(abspath $(XDP_TOOLS_PKGDIR)/no-tests))
+
+# The target linker generates default MIPS ABI flags instead the toolchain ones
+# when doing partial linking. Workaround by using the assembler instead.
+ifeq ($(BR2_mips)$(BR2_mipsel)$(BR2_mips64)$(BR2_mips64el),y)
+define XDP_TOOLS_APPLY_MIPS_PATCHES
+ $(APPLY_PATCHES) $(@D) $(XDP_TOOLS_PKGDIR)/mips \*.patch
+endef
+XDP_TOOLS_POST_PATCH_HOOKS += XDP_TOOLS_APPLY_MIPS_PATCHES
+endif
+
+define XDP_TOOLS_CONFIGURE_CMDS
+ cd $(@D) && \
+ $(TARGET_CONFIGURE_OPTS) \
+ $(XDP_TOOLS_CONF_ENV) \
+ ./configure
+endef
+
+define XDP_TOOLS_BUILD_CMDS
+ $(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) \
+ $(XDP_TOOLS_CONF_ENV) \
+ $(MAKE) -C $(@D) $(XDP_TOOLS_MAKE_OPTS) all
+endef
+
+define XDP_TOOLS_INSTALL_STAGING_CMDS
+ $(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) \
+ $(MAKE) -C $(@D) $(XDP_TOOLS_MAKE_OPTS) \
+ DESTDIR=$(STAGING_DIR) libxdp_install
+endef
+
+define XDP_TOOLS_INSTALL_TARGET_CMDS
+ $(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) \
+ $(MAKE) -C $(@D) $(XDP_TOOLS_MAKE_OPTS) \
+ DESTDIR=$(TARGET_DIR) MAN_FILES= libxdp_install install
+endef
+
+# The test script uses timeout(1) and unshare(1). Enable them if using busybox.
+ifneq ($(BR2_PACKAGE_XDP_TOOLS_INSTALL_TESTS),)
+define XDP_TOOLS_BUSYBOX_CONFIG_FIXUPS
+ $(call KCONFIG_ENABLE_OPT,CONFIG_TIMEOUT)
+ $(call KCONFIG_ENABLE_OPT,CONFIG_UNSHARE)
+endef
+endif
+
+$(eval $(generic-package))
xdp-tools 1.6.3 bundles libxdp and seven associated tools. libxdp has a preference for linking against a vendored libbpf, but we force it to use our packaged libbpf instead. BPF objects are built by host-clang and put on the target /usr/lib/bpf/. Building them requires three patches: (1) Compile BPF objects freestanding. We provide vendored <asm/{byteorder,bitsperlong}.h> to avoid arch-specific ones. Also ensure we do not retrieve the clang system includes, as we do not use the clang wrapper. (2) Allow running tests on a busybox target, avoiding GNU mktemp flags. (3) Partial linking appears broken on MIPS toolchain. Fix by avoiding the linker and using .incbin from the assembler instead. Patch is only applied on MIPS. Also note that tests can be compiled and installed on the target using a Kconfig entry. That has a large list of dependencies however. Built and tested on BR2_mips_64r6, little endian. Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com> --- DEVELOPERS | 3 + package/Config.in | 1 + .../0001-lib-build-BPF-objects-freestanding.patch | 116 +++++++++++++++++++++ .../0002-lib-testing-support-busybox-mktemp.patch | 64 ++++++++++++ package/xdp-tools/Config.in | 55 ++++++++++ ...d-BPF-objects-with-assembler-rather-than-.patch | 59 +++++++++++ package/xdp-tools/no-tests/Makefile | 3 + package/xdp-tools/xdp-tools.hash | 8 ++ package/xdp-tools/xdp-tools.mk | 79 ++++++++++++++ 9 files changed, 388 insertions(+)