aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorToke Høiland-Jørgensen <toke@redhat.com>2021-11-05 16:23:43 +0100
committerToke Høiland-Jørgensen <toke@redhat.com>2022-03-14 10:37:21 +0100
commita043a41b1a69e5d034c8bdc1cdcce2f3df28a833 (patch)
tree4948bc8ec6e26c1ec01a64bf8d0530bbe0511ba2
parenta53af000639a42b53f17470ddda7e76cb661fe91 (diff)
downloadlinux-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.c69
-rw-r--r--tools/testing/selftests/bpf/progs/test_xdp_pifo.c67
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";