Merge branch 'bpf-fix-a-few-test-failures-with-64k-page-size'

Yonghong Song says:

====================
bpf: Fix a few test failures with 64K page size

Changelog:
  v2 -> v3:
    - v2: https://lore.kernel.org/bpf/20250611171519.2033193-1-yonghong.song@linux.dev/
    - Add additional comments for xdp_adjust_tail test.
    - Use actual kernel page size to set new_len for Patch 2 tests.
  v1 -> v2:
    - v1: https://lore.kernel.org/bpf/20250608165534.1019914-1-yonghong.song@linux.dev/
    - For xdp_adjust_tail, let kernel test_run can handle various page sizes for xdp progs.
    - For two change_tail tests, make code easier to understand.
    - Resolved a new test failure (xdp_do_redirect).
====================

Link: https://patch.msgid.link/20250612035027.2207299-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2025-06-12 19:07:51 -07:00
commit 0e93df45c7
6 changed files with 122 additions and 20 deletions

View 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)

View 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();
}
}

View file

@ -66,16 +66,25 @@ static int attach_tc_prog(struct bpf_tc_hook *hook, int fd)
#else
#define MAX_PKT_SIZE 3408
#endif
#define PAGE_SIZE_4K 4096
#define PAGE_SIZE_64K 65536
static void test_max_pkt_size(int fd)
{
char data[MAX_PKT_SIZE + 1] = {};
char data[PAGE_SIZE_64K + 1] = {};
int err;
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
.data_in = &data,
.data_size_in = MAX_PKT_SIZE,
.flags = BPF_F_TEST_XDP_LIVE_FRAMES,
.repeat = 1,
);
if (getpagesize() == PAGE_SIZE_64K)
opts.data_size_in = MAX_PKT_SIZE + PAGE_SIZE_64K - PAGE_SIZE_4K;
else
opts.data_size_in = MAX_PKT_SIZE;
err = bpf_prog_test_run_opts(fd, &opts);
ASSERT_OK(err, "prog_run_max_size");

View file

@ -1,8 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 ByteDance */
#include <linux/bpf.h>
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE __PAGE_SIZE
#endif
#define BPF_SKB_MAX_LEN (PAGE_SIZE << 2)
struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__uint(max_entries, 1);
@ -31,7 +36,7 @@ int prog_skb_verdict(struct __sk_buff *skb)
change_tail_ret = bpf_skb_change_tail(skb, skb->len + 1, 0);
return SK_PASS;
} else if (data[0] == 'E') { /* Error */
change_tail_ret = bpf_skb_change_tail(skb, 65535, 0);
change_tail_ret = bpf_skb_change_tail(skb, BPF_SKB_MAX_LEN, 0);
return SK_PASS;
}
return SK_PASS;

View file

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/pkt_cls.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE __PAGE_SIZE
#endif
#define BPF_SKB_MAX_LEN (PAGE_SIZE << 2)
long change_tail_ret = 1;
@ -94,7 +94,7 @@ int change_tail(struct __sk_buff *skb)
bpf_skb_change_tail(skb, len, 0);
return TCX_PASS;
} else if (payload[0] == 'E') { /* Error */
change_tail_ret = bpf_skb_change_tail(skb, 65535, 0);
change_tail_ret = bpf_skb_change_tail(skb, BPF_SKB_MAX_LEN, 0);
return TCX_PASS;
} else if (payload[0] == 'Z') { /* Zero */
change_tail_ret = bpf_skb_change_tail(skb, 0, 0);

View 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 */
}