summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/xskxceiver.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/bpf/xskxceiver.c')
-rw-r--r--tools/testing/selftests/bpf/xskxceiver.c110
1 files changed, 98 insertions, 12 deletions
diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c
index a17655107a94..f144d0604ddf 100644
--- a/tools/testing/selftests/bpf/xskxceiver.c
+++ b/tools/testing/selftests/bpf/xskxceiver.c
@@ -69,6 +69,7 @@
*/
#define _GNU_SOURCE
+#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
@@ -76,6 +77,7 @@
#include <linux/if_link.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
+#include <linux/mman.h>
#include <linux/udp.h>
#include <arpa/inet.h>
#include <net/if.h>
@@ -103,6 +105,7 @@
#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 +467,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;
@@ -631,7 +635,6 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb
if (!pkt_stream)
exit_with_error(ENOMEM);
- pkt_stream->nb_pkts = nb_pkts;
for (i = 0; i < nb_pkts; i++) {
pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size,
pkt_len);
@@ -798,6 +801,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 +976,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)
@@ -1124,7 +1142,14 @@ static int validate_rx_dropped(struct ifobject *ifobject)
if (err)
return TEST_FAILURE;
- if (stats.rx_dropped == ifobject->pkt_stream->nb_pkts / 2)
+ /* The receiver calls getsockopt after receiving the last (valid)
+ * packet which is not the final packet sent in this test (valid and
+ * invalid packets are sent in alternating fashion with the final
+ * packet being invalid). Since the last packet may or may not have
+ * been dropped already, both outcomes must be allowed.
+ */
+ if (stats.rx_dropped == ifobject->pkt_stream->nb_pkts / 2 ||
+ stats.rx_dropped == ifobject->pkt_stream->nb_pkts / 2 - 1)
return TEST_PASS;
return TEST_FAILURE;
@@ -1266,7 +1291,7 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
int ret;
if (ifobject->umem->unaligned_mode)
- mmap_flags |= MAP_HUGETLB;
+ mmap_flags |= MAP_HUGETLB | MAP_HUGE_2MB;
if (ifobject->shared_umem)
umem_sz *= 2;
@@ -1355,6 +1380,11 @@ static void *worker_testapp_validate_rx(void *arg)
pthread_exit(NULL);
}
+static u64 ceil_u64(u64 a, u64 b)
+{
+ return (a + b - 1) / b;
+}
+
static void testapp_clean_xsk_umem(struct ifobject *ifobj)
{
u64 umem_sz = ifobj->umem->num_frames * ifobj->umem->frame_size;
@@ -1362,6 +1392,7 @@ static void testapp_clean_xsk_umem(struct ifobject *ifobj)
if (ifobj->shared_umem)
umem_sz *= 2;
+ umem_sz = ceil_u64(umem_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE;
xsk_umem__delete(ifobj->umem->umem);
munmap(ifobj->umem->buffer, umem_sz);
}
@@ -1595,14 +1626,15 @@ static void testapp_stats_fill_empty(struct test_spec *test)
/* Simple test */
static bool hugepages_present(struct ifobject *ifobject)
{
- const size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size;
+ size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size;
void *bufs;
bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0);
if (bufs == MAP_FAILED)
return false;
+ mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE;
munmap(bufs, mmap_sz);
return true;
}
@@ -1635,6 +1667,7 @@ static void testapp_single_pkt(struct test_spec *test)
static void testapp_invalid_desc(struct test_spec *test)
{
+ u64 umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size;
struct pkt pkts[] = {
/* Zero packet address allowed */
{0, PKT_SIZE, 0, true},
@@ -1644,10 +1677,12 @@ static void testapp_invalid_desc(struct test_spec *test)
{-2, PKT_SIZE, 0, false},
/* Packet too large */
{0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false},
+ /* Up to end of umem allowed */
+ {umem_size - PKT_SIZE, PKT_SIZE, 0, true},
/* After umem ends */
- {UMEM_SIZE, PKT_SIZE, 0, false},
+ {umem_size, PKT_SIZE, 0, false},
/* Straddle the end of umem */
- {UMEM_SIZE - PKT_SIZE / 2, PKT_SIZE, 0, false},
+ {umem_size - PKT_SIZE / 2, PKT_SIZE, 0, false},
/* Straddle a page boundrary */
{0x3000 - PKT_SIZE / 2, PKT_SIZE, 0, false},
/* Straddle a 2K boundrary */
@@ -1657,16 +1692,17 @@ static void testapp_invalid_desc(struct test_spec *test)
if (test->ifobj_tx->umem->unaligned_mode) {
/* Crossing a page boundrary allowed */
- pkts[6].valid = true;
+ pkts[7].valid = true;
}
if (test->ifobj_tx->umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) {
/* Crossing a 2K frame size boundrary not allowed */
- pkts[7].valid = false;
+ pkts[8].valid = false;
}
if (test->ifobj_tx->shared_umem) {
- pkts[4].addr += UMEM_SIZE;
- pkts[5].addr += UMEM_SIZE;
+ pkts[4].addr += umem_size;
+ pkts[5].addr += umem_size;
+ pkts[6].addr += umem_size;
}
pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
@@ -1686,6 +1722,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");
@@ -1825,6 +1885,29 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_
test->ifobj_rx->umem->unaligned_mode = true;
testapp_invalid_desc(test);
break;
+ case TEST_TYPE_UNALIGNED_INV_DESC_4K1_FRAME: {
+ u64 page_size, umem_size;
+
+ if (!hugepages_present(test->ifobj_tx)) {
+ ksft_test_result_skip("No 2M huge pages present.\n");
+ return;
+ }
+ test_spec_set_name(test, "UNALIGNED_INV_DESC_4K1_FRAME_SIZE");
+ /* Odd frame size so the UMEM doesn't end near a page boundary. */
+ test->ifobj_tx->umem->frame_size = 4001;
+ test->ifobj_rx->umem->frame_size = 4001;
+ test->ifobj_tx->umem->unaligned_mode = true;
+ test->ifobj_rx->umem->unaligned_mode = true;
+ /* This test exists to test descriptors that staddle the end of
+ * the UMEM but not a page.
+ */
+ page_size = sysconf(_SC_PAGESIZE);
+ umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size;
+ assert(umem_size % page_size > PKT_SIZE);
+ assert(umem_size % page_size < page_size - PKT_SIZE);
+ testapp_invalid_desc(test);
+ break;
+ }
case TEST_TYPE_UNALIGNED:
if (!testapp_unaligned(test))
return;
@@ -1835,6 +1918,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;
}