Test that in case of linear region, we always are able to do DPA without any errors. Note how offset is clamped to range [0, 0xffff] and len is a constant. Ensure that helper vs DPA is detected and tested. Add a force_helper mode, that forces use of bpf_xdp_load_bytes and bpf_xdp_store_bytes instead of using bpf_packet_pointer, even for contiguous regions, to make sure that case keeps working. Also, we can take this opportunity to convert it to use BPF skeleton. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> --- .../bpf/prog_tests/xdp_adjust_frags.c | 46 +++++++++++++------ .../bpf/progs/test_xdp_update_frags.c | 46 +++++++++++++------ 2 files changed, 65 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c index 2f033da4cd45..cfb50a575b11 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c @@ -2,26 +2,24 @@ #include <test_progs.h> #include <network_helpers.h> -static void test_xdp_update_frags(void) +#include "test_xdp_update_frags.skel.h" + +static void test_xdp_update_frags(bool force_helper) { - const char *file = "./test_xdp_update_frags.o"; int err, prog_fd, max_skb_frags, buf_size, num; - struct bpf_program *prog; - struct bpf_object *obj; + LIBBPF_OPTS(bpf_test_run_opts, topts); + struct test_xdp_update_frags *skel; __u32 *offset; __u8 *buf; FILE *f; - LIBBPF_OPTS(bpf_test_run_opts, topts); - obj = bpf_object__open(file); - if (libbpf_get_error(obj)) + skel = test_xdp_update_frags__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_xdp_update_frags__open_and_load")) return; - prog = bpf_object__next_program(obj, NULL); - if (bpf_object__load(obj)) - return; + skel->bss->force_helper = force_helper; - prog_fd = bpf_program__fd(prog); + prog_fd = bpf_program__fd(skel->progs.xdp_adjust_frags); buf = malloc(128); if (!ASSERT_OK_PTR(buf, "alloc buf 128b")) @@ -45,6 +43,13 @@ static void test_xdp_update_frags(void) ASSERT_EQ(topts.retval, XDP_PASS, "xdp_update_frag retval"); ASSERT_EQ(buf[16], 0xbb, "xdp_update_frag buf[16]"); ASSERT_EQ(buf[31], 0xbb, "xdp_update_frag buf[31]"); + if (force_helper) { + ASSERT_EQ(skel->bss->used_dpa, false, "did not use DPA"); + ASSERT_EQ(skel->bss->used_helper, true, "used helper"); + } else { + ASSERT_EQ(skel->bss->used_dpa, true, "used DPA"); + ASSERT_EQ(skel->bss->used_helper, false, "did not use helper"); + } free(buf); @@ -70,6 +75,13 @@ static void test_xdp_update_frags(void) ASSERT_EQ(topts.retval, XDP_PASS, "xdp_update_frag retval"); ASSERT_EQ(buf[5000], 0xbb, "xdp_update_frag buf[5000]"); ASSERT_EQ(buf[5015], 0xbb, "xdp_update_frag buf[5015]"); + if (force_helper) { + ASSERT_EQ(skel->bss->used_dpa, false, "did not use DPA"); + ASSERT_EQ(skel->bss->used_helper, true, "used helper"); + } else { + ASSERT_EQ(skel->bss->used_dpa, true, "used DPA"); + ASSERT_EQ(skel->bss->used_helper, false, "did not use helper"); + } memset(buf, 0, 9000); offset = (__u32 *)buf; @@ -84,6 +96,8 @@ static void test_xdp_update_frags(void) ASSERT_EQ(topts.retval, XDP_PASS, "xdp_update_frag retval"); ASSERT_EQ(buf[3510], 0xbb, "xdp_update_frag buf[3510]"); ASSERT_EQ(buf[3525], 0xbb, "xdp_update_frag buf[3525]"); + ASSERT_EQ(skel->bss->used_dpa, false, "did not use DPA"); + ASSERT_EQ(skel->bss->used_helper, true, "used helper"); memset(buf, 0, 9000); offset = (__u32 *)buf; @@ -98,6 +112,8 @@ static void test_xdp_update_frags(void) ASSERT_EQ(topts.retval, XDP_PASS, "xdp_update_frag retval"); ASSERT_EQ(buf[7606], 0xbb, "xdp_update_frag buf[7606]"); ASSERT_EQ(buf[7621], 0xbb, "xdp_update_frag buf[7621]"); + ASSERT_EQ(skel->bss->used_dpa, false, "did not use DPA"); + ASSERT_EQ(skel->bss->used_helper, true, "used helper"); free(buf); @@ -136,11 +152,13 @@ static void test_xdp_update_frags(void) "unsupported buf size, possible non-default /proc/sys/net/core/max_skb_flags?"); free(buf); out: - bpf_object__close(obj); + test_xdp_update_frags__destroy(skel); } void test_xdp_adjust_frags(void) { - if (test__start_subtest("xdp_adjust_frags")) - test_xdp_update_frags(); + if (test__start_subtest("xdp_adjust_frags-force-nodpa")) + test_xdp_update_frags(true); + if (test__start_subtest("xdp_adjust_frags-dpa+memcpy")) + test_xdp_update_frags(false); } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_update_frags.c b/tools/testing/selftests/bpf/progs/test_xdp_update_frags.c index 2a3496d8e327..1ad5c45e06e0 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_update_frags.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_update_frags.c @@ -4,37 +4,57 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ -#include <linux/bpf.h> -#include <linux/if_ether.h> +#include <vmlinux.h> #include <bpf/bpf_helpers.h> int _version SEC("version") = 1; +bool force_helper; +bool used_dpa; +bool used_helper; + +#define XDP_LEN 16 + SEC("xdp.frags") int xdp_adjust_frags(struct xdp_md *xdp) { __u8 *data_end = (void *)(long)xdp->data_end; __u8 *data = (void *)(long)xdp->data; - __u8 val[16] = {}; + __u8 val[XDP_LEN] = {}; + __u8 *ptr = NULL; __u32 offset; int err; + used_dpa = false; + used_helper = false; + if (data + sizeof(__u32) > data_end) return XDP_DROP; offset = *(__u32 *)data; - err = bpf_xdp_load_bytes(xdp, offset, val, sizeof(val)); - if (err < 0) + offset &= 0xffff; + if (!force_helper) + ptr = bpf_packet_pointer(xdp, offset, XDP_LEN); + if (!ptr) { + used_helper = true; + err = bpf_xdp_load_bytes(xdp, offset, val, sizeof(val)); + if (err < 0) + return XDP_DROP; + ptr = val; + } else { + used_dpa = true; + } + + if (ptr[0] != 0xaa || ptr[15] != 0xaa) /* marker */ return XDP_DROP; - if (val[0] != 0xaa || val[15] != 0xaa) /* marker */ - return XDP_DROP; - - val[0] = 0xbb; /* update the marker */ - val[15] = 0xbb; - err = bpf_xdp_store_bytes(xdp, offset, val, sizeof(val)); - if (err < 0) - return XDP_DROP; + ptr[0] = 0xbb; /* update the marker */ + ptr[15] = 0xbb; + if (ptr == val) { + err = bpf_xdp_store_bytes(xdp, offset, val, sizeof(val)); + if (err < 0) + return XDP_DROP; + } return XDP_PASS; } -- 2.35.1