]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: Fix an issue in bpf_prog_test_run_xdp when page size greater than 4K
authorYonghong Song <yonghong.song@linux.dev>
Thu, 12 Jun 2025 03:50:32 +0000 (20:50 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 13 Jun 2025 02:07:51 +0000 (19:07 -0700)
The bpf selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow failed on
arm64 with 64KB page:
   xdp_adjust_tail/xdp_adjust_frags_tail_grow:FAIL

In bpf_prog_test_run_xdp(), the xdp->frame_sz is set to 4K, but later on
when constructing frags, with 64K page size, the frag data_len could
be more than 4K. This will cause problems in bpf_xdp_frags_increase_tail().

To fix the failure, the xdp->frame_sz is set to be PAGE_SIZE so kernel
can test different page size properly. With the kernel change, the user
space and bpf prog needs adjustment. Currently, the MAX_SKB_FRAGS default
value is 17, so for 4K page, the maximum packet size will be less than 68K.
To test 64K page, a bigger maximum packet size than 68K is desired. So two
different functions are implemented for subtest xdp_adjust_frags_tail_grow.
Depending on different page size, different data input/output sizes are used
to adapt with different page size.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20250612035032.2207498-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
net/bpf/test_run.c
tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c

index aaf13a7d58eda25d52b88e1b457be0350af9ceea..9728dbd4c66c5105a7833e19c6db9df67818126a 100644 (file)
@@ -1255,7 +1255,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)
index e361129402a1e67188f4fd625afa61eba5634fce..43264347e7d7736061ae6bb91f86f2ad194ea399 100644 (file)
@@ -37,21 +37,26 @@ static void test_xdp_adjust_tail_shrink(void)
        bpf_object__close(obj);
 }
 
-static void test_xdp_adjust_tail_grow(void)
+static void test_xdp_adjust_tail_grow(bool is_64k_pagesize)
 {
        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 */
+       char buf[8192]; /* avoid segfault: large buf to hold grow results */
        __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,
        );
 
+       /* topts.data_size_in as a special signal to bpf prog */
+       if (is_64k_pagesize)
+               topts.data_size_in = sizeof(pkt_v4) - 1;
+       else
+               topts.data_size_in = sizeof(pkt_v4);
+
        err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
        if (!ASSERT_OK(err, "test_xdp_adjust_tail_grow"))
                return;
@@ -208,7 +213,7 @@ out:
        bpf_object__close(obj);
 }
 
-static void test_xdp_adjust_frags_tail_grow(void)
+static void test_xdp_adjust_frags_tail_grow_4k(void)
 {
        const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
        __u32 exp_size;
@@ -279,16 +284,93 @@ out:
        bpf_object__close(obj);
 }
 
+static void test_xdp_adjust_frags_tail_grow_64k(void)
+{
+       const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
+       __u32 exp_size;
+       struct bpf_program *prog;
+       struct bpf_object *obj;
+       int err, i, prog_fd;
+       __u8 *buf;
+       LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+       obj = bpf_object__open(file);
+       if (libbpf_get_error(obj))
+               return;
+
+       prog = bpf_object__next_program(obj, NULL);
+       if (bpf_object__load(obj))
+               goto out;
+
+       prog_fd = bpf_program__fd(prog);
+
+       buf = malloc(262144);
+       if (!ASSERT_OK_PTR(buf, "alloc buf 256Kb"))
+               goto out;
+
+       /* Test case add 10 bytes to last frag */
+       memset(buf, 1, 262144);
+       exp_size = 90000 + 10;
+
+       topts.data_in = buf;
+       topts.data_out = buf;
+       topts.data_size_in = 90000;
+       topts.data_size_out = 262144;
+       err = bpf_prog_test_run_opts(prog_fd, &topts);
+
+       ASSERT_OK(err, "90Kb+10b");
+       ASSERT_EQ(topts.retval, XDP_TX, "90Kb+10b retval");
+       ASSERT_EQ(topts.data_size_out, exp_size, "90Kb+10b size");
+
+       for (i = 0; i < 90000; i++) {
+               if (buf[i] != 1)
+                       ASSERT_EQ(buf[i], 1, "90Kb+10b-old");
+       }
+
+       for (i = 90000; i < 90010; i++) {
+               if (buf[i] != 0)
+                       ASSERT_EQ(buf[i], 0, "90Kb+10b-new");
+       }
+
+       for (i = 90010; i < 262144; i++) {
+               if (buf[i] != 1)
+                       ASSERT_EQ(buf[i], 1, "90Kb+10b-untouched");
+       }
+
+       /* Test a too large grow */
+       memset(buf, 1, 262144);
+       exp_size = 90001;
+
+       topts.data_in = topts.data_out = buf;
+       topts.data_size_in = 90001;
+       topts.data_size_out = 262144;
+       err = bpf_prog_test_run_opts(prog_fd, &topts);
+
+       ASSERT_OK(err, "90Kb+10b");
+       ASSERT_EQ(topts.retval, XDP_DROP, "90Kb+10b retval");
+       ASSERT_EQ(topts.data_size_out, exp_size, "90Kb+10b size");
+
+       free(buf);
+out:
+       bpf_object__close(obj);
+}
+
 void test_xdp_adjust_tail(void)
 {
+       int page_size = getpagesize();
+
        if (test__start_subtest("xdp_adjust_tail_shrink"))
                test_xdp_adjust_tail_shrink();
        if (test__start_subtest("xdp_adjust_tail_grow"))
-               test_xdp_adjust_tail_grow();
+               test_xdp_adjust_tail_grow(page_size == 65536);
        if (test__start_subtest("xdp_adjust_tail_grow2"))
                test_xdp_adjust_tail_grow2();
        if (test__start_subtest("xdp_adjust_frags_tail_shrink"))
                test_xdp_adjust_frags_tail_shrink();
-       if (test__start_subtest("xdp_adjust_frags_tail_grow"))
-               test_xdp_adjust_frags_tail_grow();
+       if (test__start_subtest("xdp_adjust_frags_tail_grow")) {
+               if (page_size == 65536)
+                       test_xdp_adjust_frags_tail_grow_64k();
+               else
+                       test_xdp_adjust_frags_tail_grow_4k();
+       }
 }
index dc74d8cf9e3f5be3ac48b9c3cf5855f15b6a298e..5904f45cfbc4f945a27d907451fe40a221d999b5 100644 (file)
@@ -19,7 +19,9 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)
        /* Data length determine test case */
 
        if (data_len == 54) { /* sizeof(pkt_v4) */
-               offset = 4096; /* test too large offset */
+               offset = 4096; /* test too large offset, 4k page size */
+       } else if (data_len == 53) { /* sizeof(pkt_v4) - 1 */
+               offset = 65536; /* test too large offset, 64k page size */
        } else if (data_len == 74) { /* sizeof(pkt_v6) */
                offset = 40;
        } else if (data_len == 64) {
@@ -31,6 +33,10 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)
                offset = 10;
        } else if (data_len == 9001) {
                offset = 4096;
+       } else if (data_len == 90000) {
+               offset = 10; /* test a small offset, 64k page size */
+       } else if (data_len == 90001) {
+               offset = 65536; /* test too large offset, 64k page size */
        } else {
                return XDP_ABORTED; /* No matching test */
        }