selftests/xsk: add xdp populate metadata test
authorTushar Vyavahare <tushar.vyavahare@intel.com>
Mon, 20 Mar 2023 10:27:05 +0000 (15:57 +0530)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 22 Mar 2023 16:14:07 +0000 (09:14 -0700)
Add a new test in copy-mode for testing the copying of metadata from the
buffer in kernel-space to user-space. This is accomplished by adding a
new XDP program and using the bss map to store a counter that is written
to the metadata field. This counter is incremented for every packet so
that the number becomes unique and should be the same as the payload. It
is store in the bss so the value can be reset between runs.

The XDP program populates the metadata and the userspace program checks
the value stored in the metadata field against the payload using the new
is_metadata_correct() function. To turn this verification on or off, add
a new parameter (use_metadata) to the ifobject structure.

Signed-off-by: Tushar Vyavahare <tushar.vyavahare@intel.com>
Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Link: https://lore.kernel.org/r/20230320102705.306187-1-tushar.vyavahare@intel.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/xsk_xdp_progs.c
tools/testing/selftests/bpf/xsk_xdp_metadata.h [new file with mode: 0644]
tools/testing/selftests/bpf/xskxceiver.c
tools/testing/selftests/bpf/xskxceiver.h

index 744a01d0e57d469dc59ae01988b780297b296b16..a630c95c74716de0b795c2dd594aa70f35e0bc9b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/bpf.h>
 #include <bpf/bpf_helpers.h>
+#include "xsk_xdp_metadata.h"
 
 struct {
        __uint(type, BPF_MAP_TYPE_XSKMAP);
@@ -12,6 +13,7 @@ struct {
 } xsk SEC(".maps");
 
 static unsigned int idx;
+int count = 0;
 
 SEC("xdp") int xsk_def_prog(struct xdp_md *xdp)
 {
@@ -27,4 +29,27 @@ SEC("xdp") int xsk_xdp_drop(struct xdp_md *xdp)
        return bpf_redirect_map(&xsk, 0, XDP_DROP);
 }
 
+SEC("xdp") int xsk_xdp_populate_metadata(struct xdp_md *xdp)
+{
+       void *data, *data_meta;
+       struct xdp_info *meta;
+       int err;
+
+       /* Reserve enough for all custom metadata. */
+       err = bpf_xdp_adjust_meta(xdp, -(int)sizeof(struct xdp_info));
+       if (err)
+               return XDP_DROP;
+
+       data = (void *)(long)xdp->data;
+       data_meta = (void *)(long)xdp->data_meta;
+
+       if (data_meta + sizeof(struct xdp_info) > data)
+               return XDP_DROP;
+
+       meta = data_meta;
+       meta->count = count++;
+
+       return bpf_redirect_map(&xsk, 0, XDP_DROP);
+}
+
 char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/xsk_xdp_metadata.h b/tools/testing/selftests/bpf/xsk_xdp_metadata.h
new file mode 100644 (file)
index 0000000..943133d
--- /dev/null
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+struct xdp_info {
+       __u64 count;
+} __attribute__((aligned(32)));
index a17655107a94c4ba00988b3abdfd0fe79e028bb3..b65e0645b0cd1d6e60aba180fb4acd41f7da1f85 100644 (file)
 #include <bpf/bpf.h>
 #include <linux/filter.h>
 #include "../kselftest.h"
+#include "xsk_xdp_metadata.h"
 
 static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62";
 static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61";
@@ -464,6 +465,7 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
                ifobj->use_fill_ring = true;
                ifobj->release_rx = true;
                ifobj->validation_func = NULL;
+               ifobj->use_metadata = false;
 
                if (i == 0) {
                        ifobj->rx_on = false;
@@ -798,6 +800,20 @@ static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt
        return false;
 }
 
+static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr)
+{
+       void *data = xsk_umem__get_data(buffer, addr);
+       struct xdp_info *meta = data - sizeof(struct xdp_info);
+
+       if (meta->count != pkt->payload) {
+               ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n",
+                              __func__, pkt->payload, meta->count);
+               return false;
+       }
+
+       return true;
+}
+
 static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len)
 {
        void *data = xsk_umem__get_data(buffer, addr);
@@ -959,7 +975,8 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds)
                        addr = xsk_umem__add_offset_to_addr(addr);
 
                        if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len) ||
-                           !is_offset_correct(umem, pkt_stream, addr, pkt->addr))
+                           !is_offset_correct(umem, pkt_stream, addr, pkt->addr) ||
+                           (ifobj->use_metadata && !is_metadata_correct(pkt, umem->buffer, addr)))
                                return TEST_FAILURE;
 
                        if (ifobj->use_fill_ring)
@@ -1686,6 +1703,30 @@ static void testapp_xdp_drop(struct test_spec *test)
        testapp_validate_traffic(test);
 }
 
+static void testapp_xdp_metadata_count(struct test_spec *test)
+{
+       struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs;
+       struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs;
+       struct bpf_map *data_map;
+       int count = 0;
+       int key = 0;
+
+       test_spec_set_name(test, "XDP_METADATA_COUNT");
+       test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_populate_metadata,
+                              skel_tx->progs.xsk_xdp_populate_metadata,
+                              skel_rx->maps.xsk, skel_tx->maps.xsk);
+       test->ifobj_rx->use_metadata = true;
+
+       data_map = bpf_object__find_map_by_name(skel_rx->obj, "xsk_xdp_.bss");
+       if (!data_map || !bpf_map__is_internal(data_map))
+               exit_with_error(ENOMEM);
+
+       if (bpf_map_update_elem(bpf_map__fd(data_map), &key, &count, BPF_ANY))
+               exit_with_error(errno);
+
+       testapp_validate_traffic(test);
+}
+
 static void testapp_poll_txq_tmout(struct test_spec *test)
 {
        test_spec_set_name(test, "POLL_TXQ_FULL");
@@ -1835,6 +1876,9 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_
        case TEST_TYPE_XDP_DROP_HALF:
                testapp_xdp_drop(test);
                break;
+       case TEST_TYPE_XDP_METADATA_COUNT:
+               testapp_xdp_metadata_count(test);
+               break;
        default:
                break;
        }
index 3e8ec7d8ec32ae6257a259e1b1fac089a2e6d8ac..bdb4efedf3a92394723d83950f30a6ac12d67770 100644 (file)
@@ -88,6 +88,7 @@ enum test_type {
        TEST_TYPE_STATS_FILL_EMPTY,
        TEST_TYPE_BPF_RES,
        TEST_TYPE_XDP_DROP_HALF,
+       TEST_TYPE_XDP_METADATA_COUNT,
        TEST_TYPE_MAX
 };
 
@@ -158,6 +159,7 @@ struct ifobject {
        bool use_fill_ring;
        bool release_rx;
        bool shared_umem;
+       bool use_metadata;
        u8 dst_mac[ETH_ALEN];
        u8 src_mac[ETH_ALEN];
 };