[Devel] [PATCH hci-8.1 v4 2/3] selftests/bpf: xsk: take the fragment limit from the kernel's BTF

Konstantin Khorenko khorenko at virtuozzo.com
Tue Oct 27 21:15:20 MSK 2026


From: Eva Kurchatova <eva.kurchatova at virtuozzo.com>

too_many_frags sends a packet with as many fragments as the kernel
takes, then one that goes past the limit, and expects only the first to
arrive. xskxceiver reads the limit from the max_skb_frags sysctl, which
has two problems:

- AF_XDP does not use the sysctl: xsk_build_skb() checks the
  compile-time MAX_SKB_FRAGS. The sysctl only equals it by default, so
  on a host where it is lowered the test expects the wrong limit.
- The sysctl exists in the initial network namespace only. A run in any
  other namespace finds no file and falls back to 17, wrong for a kernel
  built with another CONFIG_MAX_SKB_FRAGS.

Take the limit from the kernel's BTF as the element count of
skb_shared_info's frags array: it is MAX_SKB_FRAGS itself and readable
from any namespace. The sysctl stays as a fallback for a kernel without
BTF.

https://virtuozzo.atlassian.net/browse/VSTOR-150731

Feature: fix selftests
Signed-off-by: Eva Kurchatova <eva.kurchatova at virtuozzo.com>
Reviewed-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 tools/testing/selftests/bpf/xskxceiver.c | 39 +++++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c
index 11f047b8af752..a4a0b4e2516ca 100644
--- a/tools/testing/selftests/bpf/xskxceiver.c
+++ b/tools/testing/selftests/bpf/xskxceiver.c
@@ -103,6 +103,7 @@
 #include "xsk.h"
 #include "xskxceiver.h"
 #include <bpf/bpf.h>
+#include <bpf/btf.h>
 #include <linux/filter.h>
 #include "../kselftest.h"
 #include "xsk_xdp_common.h"
@@ -325,12 +326,48 @@ static bool ifobj_zc_avail(struct ifobject *ifobject)
 	return zc_avail;
 }
 
+/* AF_XDP checks MAX_SKB_FRAGS, which the sysctl only follows by default */
+static unsigned int btf_max_skb_frags(void)
+{
+	unsigned int max_skb_frags = 0;
+	const struct btf_member *m;
+	const struct btf_type *t;
+	struct btf *btf;
+	int id, i;
+
+	btf = btf__load_vmlinux_btf();
+	if (!btf)
+		return 0;
+
+	id = btf__find_by_name_kind(btf, "skb_shared_info", BTF_KIND_STRUCT);
+	if (id < 0)
+		goto out;
+
+	t = btf__type_by_id(btf, id);
+	m = btf_members(t);
+	for (i = 0; i < btf_vlen(t); i++, m++) {
+		if (strcmp(btf__name_by_offset(btf, m->name_off), "frags"))
+			continue;
+		t = btf__type_by_id(btf, m->type);
+		if (btf_is_array(t))
+			max_skb_frags = btf_array(t)->nelems;
+		break;
+	}
+out:
+	btf__free(btf);
+	return max_skb_frags;
+}
+
 #define MAX_SKB_FRAGS_PATH "/proc/sys/net/core/max_skb_frags"
 static unsigned int get_max_skb_frags(void)
 {
-	unsigned int max_skb_frags = 0;
+	unsigned int max_skb_frags = btf_max_skb_frags();
 	FILE *file;
 
+	if (max_skb_frags)
+		return max_skb_frags;
+
+	ksft_print_msg("No MAX_SKB_FRAGS in the kernel's BTF, reading %s\n", MAX_SKB_FRAGS_PATH);
 	file = fopen(MAX_SKB_FRAGS_PATH, "r");
 	if (!file) {
 		ksft_print_msg("Error opening %s\n", MAX_SKB_FRAGS_PATH);

-- 
2.43.0



More information about the Devel mailing list