diff options
author | Toke Høiland-Jørgensen <toke@redhat.com> | 2021-11-05 16:23:43 +0100 |
---|---|---|
committer | Toke Høiland-Jørgensen <toke@redhat.com> | 2022-03-14 10:37:21 +0100 |
commit | a043a41b1a69e5d034c8bdc1cdcce2f3df28a833 (patch) | |
tree | 4948bc8ec6e26c1ec01a64bf8d0530bbe0511ba2 | |
parent | a53af000639a42b53f17470ddda7e76cb661fe91 (diff) | |
download | linux-xdp-queueing-03.tar.gz |
selftests/bpf: Add test for XDP queueing through PIFO mapsxdp-queueing-03
This adds a selftest that uses bpf_prog_run() of an XDP program that puts
packets into a PIFO map, and then pulls them back out again through
bpf_prog_run() of a dequeue program.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-rw-r--r-- | tools/testing/selftests/bpf/prog_tests/xdp_pifo_test_run.c | 69 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/progs/test_xdp_pifo.c | 67 |
2 files changed, 136 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_pifo_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_pifo_test_run.c new file mode 100644 index 00000000000000..76d0e4b236201a --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/xdp_pifo_test_run.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include <network_helpers.h> +#include "test_xdp_pifo.skel.h" + +static void run_xdp_prog(int prog_fd, void *data, size_t data_size) +{ + struct xdp_md ctx_in = {}; + DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_in = data, + .data_size_in = data_size, + .ctx_in = &ctx_in, + .ctx_size_in = sizeof(ctx_in), + .repeat = 3, + .flags = BPF_F_TEST_XDP_LIVE_FRAMES, + ); + int err; + + ctx_in.data_end = ctx_in.data + sizeof(pkt_v4); + err = bpf_prog_test_run_opts(prog_fd, &opts); + ASSERT_OK(err, "bpf_prog_test_run(valid)"); +} + +static void run_dequeue_prog(int prog_fd, int exp_proto) +{ + struct ipv4_packet data_out; + DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_out = &data_out, + .data_size_out = sizeof(data_out), + .repeat = 1, + ); + int err; + + err = bpf_prog_test_run_opts(prog_fd, &opts); + ASSERT_OK(err, "bpf_prog_test_run(valid)"); + ASSERT_EQ(opts.retval, exp_proto == -1 ? 0 : 1, "valid-retval"); + if (exp_proto >= 0) { + ASSERT_EQ(opts.data_size_out, sizeof(pkt_v4), "valid-datasize"); + ASSERT_EQ(data_out.eth.h_proto, exp_proto, "valid-pkt"); + } else { + ASSERT_EQ(opts.data_size_out, 0, "no-pkt-returned"); + } +} + +void test_xdp_pifo(void) +{ + struct test_xdp_pifo *skel = NULL; + struct ipv4_packet data; + int xdp_prog_fd, dequeue_prog_fd; + + skel = test_xdp_pifo__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel")) + return; + + xdp_prog_fd = bpf_program__fd(skel->progs.xdp_pifo); + dequeue_prog_fd = bpf_program__fd(skel->progs.dequeue_pifo); + data = pkt_v4; + + run_xdp_prog(xdp_prog_fd, &data, sizeof(data)); + + /* kernel program queues packets with prio 2, 1, 0 (in that order), we + * should get back 0 and 1, and 2 should get dropped on dequeue + */ + run_dequeue_prog(dequeue_prog_fd, 0); + run_dequeue_prog(dequeue_prog_fd, 1); + run_dequeue_prog(dequeue_prog_fd, -1); + + test_xdp_pifo__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_xdp_pifo.c b/tools/testing/selftests/bpf/progs/test_xdp_pifo.c new file mode 100644 index 00000000000000..086b17c374ac83 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_pifo.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "linux/bpf.h" +#include <linux/bpf.h> +#include <linux/if_ether.h> +#include <bpf/bpf_helpers.h> + +struct { + __uint(type, BPF_MAP_TYPE_PIFO); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); + __uint(max_entries, 1024); +} pifo_map SEC(".maps"); + +__u16 prio = 3; +__u16 exp_prio = 0; + +SEC("xdp") +int xdp_pifo(struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + void *data_end = (void *)(long)xdp->data_end; + struct ethhdr *eth = data; + + if (eth + 1 > data_end) + return XDP_DROP; + + /* We write the priority into the ethernet proto field so userspace can + * pick it back out and confirm that it's correct + */ + eth->h_proto = --prio; + return bpf_redirect_map(&pifo_map, prio, 0); +} + +__u16 pkt_count = 0; + +SEC("dequeue") +void *dequeue_pifo(struct dequeue_ctx *ctx) +{ + __u64 prio = 0, pkt_prio = 0; + void *data, *data_end; + struct xdp_md *pkt; + struct ethhdr *eth; + + pkt = (void *)bpf_packet_dequeue(ctx, &pifo_map, 0, &prio); + if (!pkt) + return NULL; + + data = (void *)(long)pkt->data; + data_end = (void *)(long)pkt->data_end; + eth = data; + + if (eth + 1 <= data_end) + pkt_prio = eth->h_proto; + + if (prio != exp_prio++ || pkt_prio != prio) { + bpf_packet_drop(ctx, pkt); + return NULL; + } + + if (++pkt_count > 2) { + bpf_packet_drop(ctx, pkt); + pkt = NULL; + } + return pkt; +} + +char _license[] SEC("license") = "GPL"; |