Skip to contentSkip to conversation

Fix xdp_adjust_frags_tail_grow selftest on powerpc

PATCH Applied Saket Kumar Bhaskar 2 participants 6 messages Mar 5, 2025 – Mar 20, 2025

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

v2 cover Fix xdp_adjust_frags_tail_grow selftest on powerpc

For platforms on powerpc architecture with a default page size greater than 4096, there was an inconsistency in fragment size calculation. This caused the BPF selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow to fail on powerpc.

The issue occurred because the fragment buffer size in bpf_prog_test_run_xdp() was set to 4096, while the actual data size in the fragment within the shared skb was checked against PAGE_SIZE (65536 on powerpc) in min_t, causing it to exceed 4096 and be set accordingly. This discrepancy led to an overflow when bpf_xdp_frags_increase_tail() checked for tailroom, as skb_frag_size(frag) could be greater than rxq->frag_size (when PAGE_SIZE > 4096).

This change fixes:

1. test_run by getting the correct arch dependent PAGE_SIZE.
2. selftest by caculating tailroom and getting correct PAGE_SIZE.

Changes:
v1 -> v2:
* Address comments from Alexander
* Use dynamic page size, cacheline size and size of struct skb_shared_info to calculate parameters.
* Fixed both test_run and selftest.

v1: https://lore.kernel.org/all/[email protected]/

Saket Kumar Bhaskar (2):
bpf, test_run: Replace hardcoded page size with dynamic PAGE_SIZE in
test_run
selftests/bpf: Refactor xdp_adjust_tail selftest with dynamic sizing

 .../bpf/prog_tests/xdp_adjust_tail.c          | 160 +++++++++++++-----
 .../bpf/progs/test_xdp_adjust_tail_grow.c     |  41 +++--
 2 files changed, 149 insertions(+), 52 deletions(-)
Signature · 1 line
2.43.5
#1 lore raw

PATCH v2 1/2 bpf, test_run: Replace hardcoded page size with dynamic PAGE_SIZE in test_run

Replace fixed value 4096 with PAGE_SIZE for calculating the max_data_sz in bpf_prog_test_run_xdp, which allows for a more accurate determination of max_data_sz, considering different default page sizes across different architectures.

---
 net/bpf/test_run.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bpf/test_run.c +1 -1
index 7cb192cbd65f..c0d5bbf20098 100644
@@ -1249,7 +1249,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
 		headroom -= ctx->data;
 	}
 
-	max_data_sz = 4096 - headroom - tailroom;
+	max_data_sz = PAGE_SIZE - headroom - tailroom;
 	if (size > max_data_sz) {
 		/* disallow live data mode for jumbo frames */
 		if (do_live)
Signature · 1 line
2.43.5
#2 lore raw

PATCH v2 2/2 selftests/bpf: Refactor xdp_adjust_tail selftest with dynamic sizing

In reply to Saket Kumar Bhaskar

The xdp_adjust_tail/xdp_adjust_frags_tail_grow selftest fails on powerpc architecture platforms with a default page size greater than 4096 because the page size, tailroom and buffer size are hardcoded.

To resolve this issue, these parameters are now collected dynamically in the test driver code and communicated to the BPF program using a map:

1. Page size and cache line size are obtained using sysconf.
2. The size of struct skb_shared_info is determined using BTF.

---
 .../bpf/prog_tests/xdp_adjust_tail.c          | 160 +++++++++++++-----
 .../bpf/progs/test_xdp_adjust_tail_grow.c     |  41 +++--
 2 files changed, 149 insertions(+), 52 deletions(-)
tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c +119 -41
index b2b2d85dbb1b..2d1fafa9738e 100644
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <test_progs.h>
+#include <bpf/btf.h>
 #include <network_helpers.h>
 
 static void test_xdp_adjust_tail_shrink(void)
@@ -41,21 +42,47 @@ static void test_xdp_adjust_tail_grow(void)
 {
 	const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
 	struct bpf_object *obj;
-	char buf[4096]; /* avoid segfault: large buf to hold grow results */
+	struct btf *btf;
+	__u8 *buf;
 	__u32 expect_sz;
-	int err, prog_fd;
-	LIBBPF_OPTS(bpf_test_run_opts, topts,
-		.data_in = &pkt_v4,
-		.data_size_in = sizeof(pkt_v4),
-		.data_out = buf,
-		.data_size_out = sizeof(buf),
-		.repeat = 1,
-	);
+	int err, prog_fd, id, shinfo_size, map_fd;
+	int key = 0;
+	int page_size = sysconf(_SC_PAGESIZE);
+	int cache_linesize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
 
 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
 	if (!ASSERT_OK(err, "test_xdp_adjust_tail_grow"))
 		return;
 
+	btf = btf__load_vmlinux_btf();
+	if (libbpf_get_error(btf))
+		return;
+
+	id = btf__find_by_name(btf, "skb_shared_info");
+	if (id < 0)
+		goto out;
+
+	shinfo_size = btf__resolve_size(btf, id);
+
+	map_fd = bpf_find_map(__func__, obj, "size");
+	if (map_fd < 0)
+		goto out;
+
+	bpf_map_update_elem(map_fd, &key, &shinfo_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &page_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &cache_linesize, BPF_ANY);
+
+	buf = malloc(page_size);
+
+	topts.data_in = &pkt_v4;
+	topts.data_size_in = sizeof(pkt_v4);
+	topts.data_out = buf;
+	topts.data_size_out = page_size;
+	topts.repeat = 1;
 	err = bpf_prog_test_run_opts(prog_fd, &topts);
 	ASSERT_OK(err, "ipv4");
 	ASSERT_EQ(topts.retval, XDP_DROP, "ipv4 retval");
@@ -63,45 +90,65 @@ static void test_xdp_adjust_tail_grow(void)
 	expect_sz = sizeof(pkt_v6) + 40; /* Test grow with 40 bytes */
 	topts.data_in = &pkt_v6;
 	topts.data_size_in = sizeof(pkt_v6);
-	topts.data_size_out = sizeof(buf);
+	topts.data_size_out = page_size;
 	err = bpf_prog_test_run_opts(prog_fd, &topts);
 	ASSERT_OK(err, "ipv6");
 	ASSERT_EQ(topts.retval, XDP_TX, "ipv6 retval");
 	ASSERT_EQ(topts.data_size_out, expect_sz, "ipv6 size");
 
+out:
 	bpf_object__close(obj);
+	btf__free(btf);
 }
 
 static void test_xdp_adjust_tail_grow2(void)
 {
 	const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
-	char buf[4096]; /* avoid segfault: large buf to hold grow results */
+	__u8 *buf;
 	struct bpf_object *obj;
+	struct btf *btf;
 	int err, cnt, i;
-	int max_grow, prog_fd;
-	/* SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) */
-#if defined(__s390x__)
-	int tailroom = 512;
-#elif defined(__powerpc__)
-	int tailroom = 384;
-#else
-	int tailroom = 320;
-#endif
-
-	LIBBPF_OPTS(bpf_test_run_opts, tattr,
-		.repeat		= 1,
-		.data_in	= &buf,
-		.data_out	= &buf,
-		.data_size_in	= 0, /* Per test */
-		.data_size_out	= 0, /* Per test */
-	);
+	int max_grow, prog_fd, id, shinfo_size, map_fd, tailroom;
+	int key = 0;
+	int page_size = sysconf(_SC_PAGESIZE);
+	int cache_linesize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+
+	LIBBPF_OPTS(bpf_test_run_opts, tattr);
 
 	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
 	if (!ASSERT_OK(err, "test_xdp_adjust_tail_grow"))
 		return;
 
+	btf = btf__load_vmlinux_btf();
+	if (libbpf_get_error(btf))
+		return;
+
+	id = btf__find_by_name(btf, "skb_shared_info");
+	if (id < 0)
+		goto out;
+
+	shinfo_size = btf__resolve_size(btf, id);
+
+	/* SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) */
+	tailroom = __ALIGN_KERNEL(shinfo_size, cache_linesize);
+
+	map_fd = bpf_find_map(__func__, obj, "size");
+	if (map_fd < 0)
+		goto out;
+
+	bpf_map_update_elem(map_fd, &key, &shinfo_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &page_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &cache_linesize, BPF_ANY);
+
+	buf = malloc(page_size);
+
 	/* Test case-64 */
-	memset(buf, 1, sizeof(buf));
+	memset(buf, 1, page_size);
+	tattr.repeat = 1;
+	tattr.data_in = buf;
+	tattr.data_out = buf;
 	tattr.data_size_in  =  64; /* Determine test case via pkt size */
 	tattr.data_size_out = 128; /* Limit copy_size */
 	/* Kernel side alloc packet memory area that is zero init */
@@ -120,25 +167,30 @@ static void test_xdp_adjust_tail_grow2(void)
 	ASSERT_EQ(buf[191], 1, "case-64-data buf[191]");
 
 	/* Test case-128 */
-	memset(buf, 2, sizeof(buf));
+	memset(buf, 2, page_size);
+	tattr.repeat = 1;
+	tattr.data_in = buf;
+	tattr.data_out = buf;
 	tattr.data_size_in  = 128; /* Determine test case via pkt size */
-	tattr.data_size_out = sizeof(buf);   /* Copy everything */
+	tattr.data_size_out = page_size;   /* Copy everything */
 	err = bpf_prog_test_run_opts(prog_fd, &tattr);
 
-	max_grow = 4096 - XDP_PACKET_HEADROOM -	tailroom; /* 3520 */
+	max_grow = page_size - XDP_PACKET_HEADROOM - tailroom; /* 3520 */
 	ASSERT_OK(err, "case-128");
 	ASSERT_EQ(tattr.retval, XDP_TX, "case-128 retval");
 	ASSERT_EQ(tattr.data_size_out, max_grow, "case-128 data_size_out"); /* Expect max grow */
 
 	/* Extra checks for data content: Count grow size, will contain zeros */
-	for (i = 0, cnt = 0; i < sizeof(buf); i++) {
+	for (i = 0, cnt = 0; i < page_size; i++) {
 		if (buf[i] == 0)
 			cnt++;
 	}
 	ASSERT_EQ(cnt, max_grow - tattr.data_size_in, "case-128-data cnt"); /* Grow increase */
 	ASSERT_EQ(tattr.data_size_out, max_grow, "case-128-data data_size_out"); /* Total grow */
 
+out:
 	bpf_object__close(obj);
+	btf__free(btf);
 }
 
 static void test_xdp_adjust_frags_tail_shrink(void)
@@ -149,6 +201,7 @@ static void test_xdp_adjust_frags_tail_shrink(void)
 	struct bpf_object *obj;
 	int err, prog_fd;
 	__u8 *buf;
+
 	LIBBPF_OPTS(bpf_test_run_opts, topts);
 
 	/* For the individual test cases, the first byte in the packet
@@ -214,26 +267,50 @@ static void test_xdp_adjust_frags_tail_grow(void)
 	__u32 exp_size;
 	struct bpf_program *prog;
 	struct bpf_object *obj;
-	int err, i, prog_fd;
+	struct btf *btf;
+	int err, i, prog_fd, id, shinfo_size, map_fd;
+	int key = 0;
+	int page_size = sysconf(_SC_PAGESIZE);
+	int cache_linesize = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
 	__u8 *buf;
+
 	LIBBPF_OPTS(bpf_test_run_opts, topts);
 
 	obj = bpf_object__open(file);
 	if (libbpf_get_error(obj))
 		return;
 
+	btf = btf__load_vmlinux_btf();
+	if (libbpf_get_error(btf))
+		return;
+
 	prog = bpf_object__next_program(obj, NULL);
 	if (bpf_object__load(obj))
 		goto out;
 
 	prog_fd = bpf_program__fd(prog);
 
-	buf = malloc(16384);
-	if (!ASSERT_OK_PTR(buf, "alloc buf 16Kb"))
+	id = btf__find_by_name(btf, "skb_shared_info");
+	if (id < 0)
+		goto out;
+
+	shinfo_size = btf__resolve_size(btf, id);
+	map_fd = bpf_find_map(__func__, obj, "size");
+	if (map_fd < 0)
+		goto out;
+
+	bpf_map_update_elem(map_fd, &key, &shinfo_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &page_size, BPF_ANY);
+	key++;
+	bpf_map_update_elem(map_fd, &key, &cache_linesize, BPF_ANY);
+
+	buf = malloc(4 * page_size);
+	if (!ASSERT_OK_PTR(buf, "alloc buf (4 x page size)Kb"))
 		goto out;
 
 	/* Test case add 10 bytes to last frag */
-	memset(buf, 1, 16384);
+	memset(buf, 1, 4 * page_size);
 	exp_size = 9000 + 10;
 
 	topts.data_in = buf;
@@ -256,12 +333,12 @@ static void test_xdp_adjust_frags_tail_grow(void)
 		ASSERT_EQ(buf[i], 1, "9Kb+10b-untouched");
 
 	/* Test a too large grow */
-	memset(buf, 1, 16384);
-	exp_size = 9001;
+	memset(buf, 1, 4 * page_size);
+	exp_size = 2 * page_size + 1;
 
 	topts.data_in = topts.data_out = buf;
-	topts.data_size_in = 9001;
-	topts.data_size_out = 16384;
+	topts.data_size_in = 2 * page_size + 1;
+	topts.data_size_out = 4 * page_size;
 	err = bpf_prog_test_run_opts(prog_fd, &topts);
 
 	ASSERT_OK(err, "9Kb+10b");
@@ -271,6 +348,7 @@ static void test_xdp_adjust_frags_tail_grow(void)
 	free(buf);
 out:
 	bpf_object__close(obj);
+	btf__free(btf);
 }
 
 void test_xdp_adjust_tail(void)
tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c +30 -11

66 lines not on this page · raw message

Signature · 1 line
2.43.5
Tested-by on the v2 series Applied
#3 lore raw
In reply to Saket Kumar Bhaskar
Quoted 27 lines · Saket Kumar Bhaskar

For platforms on powerpc architecture with a default page size greater than 4096, there was an inconsistency in fragment size calculation. This caused the BPF selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow to fail on powerpc.

The issue occurred because the fragment buffer size in bpf_prog_test_run_xdp() was set to 4096, while the actual data size in the fragment within the shared skb was checked against PAGE_SIZE (65536 on powerpc) in min_t, causing it to exceed 4096 and be set accordingly. This discrepancy led to an overflow when bpf_xdp_frags_increase_tail() checked for tailroom, as skb_frag_size(frag) could be greater than rxq->frag_size (when PAGE_SIZE > 4096).

This change fixes:

1. test_run by getting the correct arch dependent PAGE_SIZE.
2. selftest by caculating tailroom and getting correct PAGE_SIZE.

Changes:
v1 -> v2:
* Address comments from Alexander
* Use dynamic page size, cacheline size and size of struct skb_shared_info to calculate parameters.
* Fixed both test_run and selftest.

v1: https://lore.kernel.org/all/[email protected]/

Quoted 9 lines

Saket Kumar Bhaskar (2):
bpf, test_run: Replace hardcoded page size with dynamic PAGE_SIZE in
test_run
selftests/bpf: Refactor xdp_adjust_tail selftest with dynamic sizing

  .../bpf/prog_tests/xdp_adjust_tail.c          | 160 +++++++++++++-----
  .../bpf/progs/test_xdp_adjust_tail_grow.c     |  41 +++--
  2 files changed, 149 insertions(+), 52 deletions(-)

Applied the patch series on the bpf-next and patch works as expected.

With Out the Patch:

test_xdp_adjust_frags_tail_grow:PASS:9Kb+10b 0 nsec test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b retval unexpected 9Kb+10b retval: actual 3 != expected 1 test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b size unexpected 9Kb+10b size: actual 13097 != expected 9001 #583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:FAIL
#583     xdp_adjust_tail:FAIL
Summary: 0/4 PASSED, 0 SKIPPED, 1 FAILED

With Patch:

# ./test_progs -t xdp_adjust_tail
#583/1   xdp_adjust_tail/xdp_adjust_tail_shrink:OK
#583/2   xdp_adjust_tail/xdp_adjust_tail_grow:OK
#583/3   xdp_adjust_tail/xdp_adjust_tail_grow2:OK
#583/4   xdp_adjust_tail/xdp_adjust_frags_tail_shrink:OK
#583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:OK
#583     xdp_adjust_tail:OK
Summary: 1/5 PASSED, 0 SKIPPED, 0 FAILED

Please add below tag to all the patches in series.

Regards,

Venkat.

#4 lore raw
Quoted 65 lines · Venkat Rao Bagalkote
Quoted 27 lines · Saket Kumar Bhaskar

For platforms on powerpc architecture with a default page size greater than 4096, there was an inconsistency in fragment size calculation. This caused the BPF selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow to fail on powerpc.

The issue occurred because the fragment buffer size in bpf_prog_test_run_xdp() was set to 4096, while the actual data size in the fragment within the shared skb was checked against PAGE_SIZE (65536 on powerpc) in min_t, causing it to exceed 4096 and be set accordingly. This discrepancy led to an overflow when bpf_xdp_frags_increase_tail() checked for tailroom, as skb_frag_size(frag) could be greater than rxq->frag_size (when PAGE_SIZE > 4096).

This change fixes:

1. test_run by getting the correct arch dependent PAGE_SIZE.
2. selftest by caculating tailroom and getting correct PAGE_SIZE.

Changes:
v1 -> v2:
* Address comments from Alexander
* Use dynamic page size, cacheline size and size of struct skb_shared_info to calculate parameters.
* Fixed both test_run and selftest.

v1: https://lore.kernel.org/all/[email protected]/

Quoted 9 lines

Saket Kumar Bhaskar (2):
bpf, test_run: Replace hardcoded page size with dynamic PAGE_SIZE in
test_run
selftests/bpf: Refactor xdp_adjust_tail selftest with dynamic sizing

  .../bpf/prog_tests/xdp_adjust_tail.c          | 160 +++++++++++++-----
  .../bpf/progs/test_xdp_adjust_tail_grow.c     |  41 +++--
  2 files changed, 149 insertions(+), 52 deletions(-)

Applied the patch series on the bpf-next and patch works as expected.

With Out the Patch:

test_xdp_adjust_frags_tail_grow:PASS:9Kb+10b 0 nsec test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b retval unexpected 9Kb+10b
retval: actual 3 != expected 1 test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b size unexpected 9Kb+10b size:
actual 13097 != expected 9001
#583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:FAIL
#583     xdp_adjust_tail:FAIL
Summary: 0/4 PASSED, 0 SKIPPED, 1 FAILED

With Patch:

# ./test_progs -t xdp_adjust_tail
#583/1   xdp_adjust_tail/xdp_adjust_tail_shrink:OK
#583/2   xdp_adjust_tail/xdp_adjust_tail_grow:OK
#583/3   xdp_adjust_tail/xdp_adjust_tail_grow2:OK
#583/4   xdp_adjust_tail/xdp_adjust_frags_tail_shrink:OK
#583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:OK
#583     xdp_adjust_tail:OK
Summary: 1/5 PASSED, 0 SKIPPED, 0 FAILED
Quoted 9 lines

Please add below tag to all the patches in series.

Regards,

Venkat.

Thanks for testing this Venkat.

Regards,
Saket

#5 lore raw
In reply to Venkat Rao Bagalkote

Gentle Ping...

Hi Alexander and other net bpf guys, it would be great if you could share your feedback whenever you have a moment. Please do let me know if there's any additional change needed.

Thanks,
Saket

Quoted 74 lines · Venkat Rao Bagalkote
Quoted 27 lines · Saket Kumar Bhaskar

For platforms on powerpc architecture with a default page size greater than 4096, there was an inconsistency in fragment size calculation. This caused the BPF selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow to fail on powerpc.

The issue occurred because the fragment buffer size in bpf_prog_test_run_xdp() was set to 4096, while the actual data size in the fragment within the shared skb was checked against PAGE_SIZE (65536 on powerpc) in min_t, causing it to exceed 4096 and be set accordingly. This discrepancy led to an overflow when bpf_xdp_frags_increase_tail() checked for tailroom, as skb_frag_size(frag) could be greater than rxq->frag_size (when PAGE_SIZE > 4096).

This change fixes:

1. test_run by getting the correct arch dependent PAGE_SIZE.
2. selftest by caculating tailroom and getting correct PAGE_SIZE.

Changes:
v1 -> v2:
* Address comments from Alexander
* Use dynamic page size, cacheline size and size of struct skb_shared_info to calculate parameters.
* Fixed both test_run and selftest.

v1: https://lore.kernel.org/all/[email protected]/

Quoted 9 lines

Saket Kumar Bhaskar (2):
bpf, test_run: Replace hardcoded page size with dynamic PAGE_SIZE in
test_run
selftests/bpf: Refactor xdp_adjust_tail selftest with dynamic sizing

  .../bpf/prog_tests/xdp_adjust_tail.c          | 160 +++++++++++++-----
  .../bpf/progs/test_xdp_adjust_tail_grow.c     |  41 +++--
  2 files changed, 149 insertions(+), 52 deletions(-)

Applied the patch series on the bpf-next and patch works as expected.

With Out the Patch:

test_xdp_adjust_frags_tail_grow:PASS:9Kb+10b 0 nsec test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b retval unexpected 9Kb+10b
retval: actual 3 != expected 1 test_xdp_adjust_frags_tail_grow:FAIL:9Kb+10b size unexpected 9Kb+10b size:
actual 13097 != expected 9001
#583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:FAIL
#583     xdp_adjust_tail:FAIL
Summary: 0/4 PASSED, 0 SKIPPED, 1 FAILED

With Patch:

# ./test_progs -t xdp_adjust_tail
#583/1   xdp_adjust_tail/xdp_adjust_tail_shrink:OK
#583/2   xdp_adjust_tail/xdp_adjust_tail_grow:OK
#583/3   xdp_adjust_tail/xdp_adjust_tail_grow2:OK
#583/4   xdp_adjust_tail/xdp_adjust_frags_tail_shrink:OK
#583/5   xdp_adjust_tail/xdp_adjust_frags_tail_grow:OK
#583     xdp_adjust_tail:OK
Summary: 1/5 PASSED, 0 SKIPPED, 0 FAILED

Please add below tag to all the patches in series.

Regards,

Venkat.