From: Arthur Fabre <afabre@xxxxxxxxxxxxxx> Doesn't test interop with the "data_meta" area yet, or error cases. Signed-off-by: Arthur Fabre <afabre@xxxxxxxxxxxxxx> --- .../testing/selftests/bpf/prog_tests/xdp_traits.c | 35 ++++++++ .../testing/selftests/bpf/progs/test_xdp_traits.c | 94 ++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_traits.c b/tools/testing/selftests/bpf/prog_tests/xdp_traits.c new file mode 100644 index 0000000000000000000000000000000000000000..4175b28d45e91e82435e646e5edd783980d5fe70 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/xdp_traits.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include <network_helpers.h> + +static void _test_xdp_traits(void) +{ + const char *file = "./test_xdp_traits.bpf.o"; + struct bpf_object *obj; + int err, prog_fd; + char buf[128]; + + 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, + ); + + err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); + if (!ASSERT_OK(err, "test_xdp_traits")) + return; + + err = bpf_prog_test_run_opts(prog_fd, &topts); + ASSERT_OK(err, "prog_run"); + ASSERT_EQ(topts.retval, XDP_PASS, "retval"); + + bpf_object__close(obj); +} + +void test_xdp_traits(void) +{ + if (test__start_subtest("xdp_traits")) + _test_xdp_traits(); +} diff --git a/tools/testing/selftests/bpf/progs/test_xdp_traits.c b/tools/testing/selftests/bpf/progs/test_xdp_traits.c new file mode 100644 index 0000000000000000000000000000000000000000..79e0b0dedb5c05792579861975e8caf290f5f42b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_traits.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <errno.h> + +extern int bpf_xdp_trait_set(const struct xdp_md *xdp, __u64 key, + const void *val, __u64 val__sz, + __u64 flags) __ksym; +extern int bpf_xdp_trait_get(const struct xdp_md *xdp, __u64 key, void *val, + __u64 val__sz) __ksym; +extern int bpf_xdp_trait_del(const struct xdp_md *xdp, __u64 key) __ksym; + +SEC("xdp") +int _xdp_traits(struct xdp_md *xdp) +{ + int ret; + __u16 val, got, want; + + // No keys to start. + for (int i = 0; i < 64; i++) { + ret = bpf_xdp_trait_get(xdp, i, &val, sizeof(val)); + if (ret != -ENOENT) { + bpf_printk("get(%d) ret %d", i, ret); + return XDP_DROP; + } + } + + // Set 64 2 byte KVs. + for (int i = 0; i < 64; i++) { + val = i << 8 | i; + ret = bpf_xdp_trait_set(xdp, i, &val, sizeof(val), 0); + if (ret < 0) { + bpf_printk("set(%d) ret %d\n", i, ret); + return XDP_DROP; + } + bpf_printk("set(%d, 0x%04x)\n", i, val); + } + + // Check we can get the 64 2 byte KVs back out. + for (int i = 0; i < 64; i++) { + ret = bpf_xdp_trait_get(xdp, i, &got, sizeof(got)); + if (ret != 2) { + bpf_printk("get(%d) ret %d", i, ret); + return XDP_DROP; + } + want = (i << 8) | i; + if (got != want) { + bpf_printk("get(%d) got 0x%04x want 0x%04x\n", i, got, + want); + return XDP_DROP; + } + bpf_printk("get(%d) 0x%04x\n", i, got); + } + + // Overwrite all 64 2 byte KVs. + for (int i = 0; i < 64; i++) { + val = i << 9 | i << 1; + ret = bpf_xdp_trait_set(xdp, i, &val, sizeof(val), 0); + if (ret < 0) { + bpf_printk("set(%d) ret %d\n", i, ret); + return XDP_DROP; + } + bpf_printk("set(%d, 0x%04x)\n", i, val); + } + + // Delete all the even KVs. + for (int i = 0; i < 64; i += 2) { + ret = bpf_xdp_trait_del(xdp, i); + if (ret < 0) { + bpf_printk("del(%d) ret %d\n", i, ret); + return XDP_DROP; + } + } + + // Read out all the odd KVs again. + for (int i = 1; i < 63; i += 2) { + ret = bpf_xdp_trait_get(xdp, i, &got, sizeof(got)); + if (ret != 2) { + bpf_printk("get(%d) ret %d", i, ret); + return XDP_DROP; + } + want = (i << 9) | i << 1; + if (got != want) { + bpf_printk("get(%d) got 0x%04x want 0x%04x\n", i, got, + want); + return XDP_DROP; + } + bpf_printk("get(%d) 0x%04x\n", i, got); + } + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; -- 2.43.0