mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Merge branch 'selftests-bpf-integrate-test_xsk-c-to-test_progs-framework'
Bastien Curutchet says:
====================
selftests/bpf: Integrate test_xsk.c to test_progs framework
The test_xsk.sh script covers many AF_XDP use cases. The tests it runs
are defined in xksxceiver.c. Since this script is used to test real
hardware, the goal here is to leave it as it is, and only integrate the
tests that run on veth peers into the test_progs framework.
PATCH 1 extracts test_xsk[.c/.h] from xskxceiver[.c/.h] to make the
tests available to test_progs.
PATCH 2 to 7 fix small issues in the current test
PATCH 8 to 13 handle all errors to release resources instead of calling
exit() when any error occurs.
PATCH 14 isolates the tests that won't fit in the CI
PATCH 15 integrates the CI tests to the test_progs framework
Signed-off-by: Bastien Curutchet (eBPF Foundation) <bastien.curutchet@bootlin.com>
---
Changes in v7:
- Restore 'test_ns' prefix to allow parallel execution.
- PATCH 11: fix potential uninitialized variable spotted by AI.
- PACTH 12: fix potential resource leak spotted by AI
- Link to v6: https://lore.kernel.org/r/20251029-xsk-v6-0-5a63a64dff98@bootlin.com
Changes in v6:
- Setup veth peer once for each mode instead of once for each substest
- Rename the 'flaky' table 'skip-ci' table and move the automatically
skipped and the longest tests into it
- Link to v5: https://lore.kernel.org/r/20251016-xsk-v5-0-662c95eb8005@bootlin.com
Changes in v5:
- Rebase on latest bpf-next_base
- Move XDP_ADJUST_TAIL_SHRINK_MULTI_BUFF to the flaky table
- Add Maciej's reviewed-by
- Link to v4: https://lore.kernel.org/r/20250924-xsk-v4-0-20e57537b876@bootlin.com
Changes in v4:
- Fix test_xsk.sh's summary report.
- Merge PATCH 11 & 12 together, otherwise PATCH 11 fails to build.
- Split old PATCH 3 in two patches. The first one fixes
testapp_stats_rx_dropped(), the second one fixes
testapp_xdp_shared_umem(). The unecessary frees (in
testapp_stats_rx_full() and testapp_stats_fill_empty() are removed)
- Link to v3: https://lore.kernel.org/r/20250904-xsk-v3-0-ce382e331485@bootlin.com
Changes in v3:
- Rebase on latest bpf-next_base to integrate commit c9110e6f72 ("selftests/bpf:
Fix count write in testapp_xdp_metadata_copy()").
- Move XDP_METADATA_COPY_* tests from flaky-tests to nominal tests
- Link to v2: https://lore.kernel.org/r/20250902-xsk-v2-0-17c6345d5215@bootlin.com
Changes in v2:
- Rebase on the latest bpf-next_base and integrate the newly added tests
to the work (adjust_tail* and tx_queue_consumer tests)
- Re-order patches to split xkxceiver sooner.
- Fix the bug reported by Maciej.
- Fix verbose mode in test_xsk.sh by keeping kselftest (remove PATCH 1,
7 and 8)
- Link to v1: https://lore.kernel.org/r/20250313-xsk-v1-0-7374729a93b9@bootlin.com
====================
Link: https://lore.kernel.org/r/20251031-xsk-v7-0-39fe486593a3@bootlin.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
@@ -544,6 +544,8 @@ TRUNNER_TEST_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.test.o, \
|
||||
$$(notdir $$(wildcard $(TRUNNER_TESTS_DIR)/*.c)))
|
||||
TRUNNER_EXTRA_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
|
||||
$$(filter %.c,$(TRUNNER_EXTRA_SOURCES)))
|
||||
TRUNNER_LIB_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
|
||||
$$(filter %.c,$(TRUNNER_LIB_SOURCES)))
|
||||
TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))
|
||||
TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h
|
||||
TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))
|
||||
@@ -687,6 +689,10 @@ $(TRUNNER_EXTRA_OBJS): $(TRUNNER_OUTPUT)/%.o: \
|
||||
$$(call msg,EXT-OBJ,$(TRUNNER_BINARY),$$@)
|
||||
$(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
|
||||
|
||||
$(TRUNNER_LIB_OBJS): $(TRUNNER_OUTPUT)/%.o:$(TOOLSDIR)/lib/%.c
|
||||
$$(call msg,LIB-OBJ,$(TRUNNER_BINARY),$$@)
|
||||
$(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
|
||||
|
||||
# non-flavored in-srctree builds receive special treatment, in particular, we
|
||||
# do not need to copy extra resources (see e.g. test_btf_dump_case())
|
||||
$(TRUNNER_BINARY)-extras: $(TRUNNER_EXTRA_FILES) | $(TRUNNER_OUTPUT)
|
||||
@@ -700,6 +706,7 @@ $(OUTPUT)/$(TRUNNER_BINARY): | $(TRUNNER_BPF_OBJS)
|
||||
|
||||
$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS) \
|
||||
$(TRUNNER_EXTRA_OBJS) $$(BPFOBJ) \
|
||||
$(TRUNNER_LIB_OBJS) \
|
||||
$(RESOLVE_BTFIDS) \
|
||||
$(TRUNNER_BPFTOOL) \
|
||||
$(OUTPUT)/veristat \
|
||||
@@ -746,6 +753,7 @@ TRUNNER_EXTRA_SOURCES := test_progs.c \
|
||||
$(VERIFY_SIG_HDR) \
|
||||
flow_dissector_load.h \
|
||||
ip_check_defrag_frags.h
|
||||
TRUNNER_LIB_SOURCES := find_bit.c
|
||||
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read \
|
||||
$(OUTPUT)/liburandom_read.so \
|
||||
$(OUTPUT)/xdp_synproxy \
|
||||
@@ -783,6 +791,7 @@ endif
|
||||
TRUNNER_TESTS_DIR := map_tests
|
||||
TRUNNER_BPF_PROGS_DIR := progs
|
||||
TRUNNER_EXTRA_SOURCES := test_maps.c
|
||||
TRUNNER_LIB_SOURCES :=
|
||||
TRUNNER_EXTRA_FILES :=
|
||||
TRUNNER_BPF_BUILD_RULE := $$(error no BPF objects should be built)
|
||||
TRUNNER_BPF_CFLAGS :=
|
||||
@@ -804,7 +813,7 @@ $(OUTPUT)/test_verifier: test_verifier.c verifier/tests.h $(BPFOBJ) | $(OUTPUT)
|
||||
$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
|
||||
|
||||
# Include find_bit.c to compile xskxceiver.
|
||||
EXTRA_SRC := $(TOOLSDIR)/lib/find_bit.c
|
||||
EXTRA_SRC := $(TOOLSDIR)/lib/find_bit.c prog_tests/test_xsk.c prog_tests/test_xsk.h
|
||||
$(OUTPUT)/xskxceiver: $(EXTRA_SRC) xskxceiver.c xskxceiver.h $(OUTPUT)/network_helpers.o $(OUTPUT)/xsk.o $(OUTPUT)/xsk_xdp_progs.skel.h $(BPFOBJ) | $(OUTPUT)
|
||||
$(call msg,BINARY,,$@)
|
||||
$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
|
||||
|
||||
2596
tools/testing/selftests/bpf/prog_tests/test_xsk.c
Normal file
2596
tools/testing/selftests/bpf/prog_tests/test_xsk.c
Normal file
File diff suppressed because it is too large
Load Diff
298
tools/testing/selftests/bpf/prog_tests/test_xsk.h
Normal file
298
tools/testing/selftests/bpf/prog_tests/test_xsk.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef TEST_XSK_H_
|
||||
#define TEST_XSK_H_
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_xdp.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
#include "xsk.h"
|
||||
|
||||
#ifndef SO_PREFER_BUSY_POLL
|
||||
#define SO_PREFER_BUSY_POLL 69
|
||||
#endif
|
||||
|
||||
#ifndef SO_BUSY_POLL_BUDGET
|
||||
#define SO_BUSY_POLL_BUDGET 70
|
||||
#endif
|
||||
|
||||
#define TEST_PASS 0
|
||||
#define TEST_FAILURE -1
|
||||
#define TEST_CONTINUE 1
|
||||
#define TEST_SKIP 2
|
||||
|
||||
#define DEFAULT_PKT_CNT (4 * 1024)
|
||||
#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4)
|
||||
#define HUGEPAGE_SIZE (2 * 1024 * 1024)
|
||||
#define MIN_PKT_SIZE 64
|
||||
#define MAX_ETH_PKT_SIZE 1518
|
||||
#define MAX_INTERFACE_NAME_CHARS 16
|
||||
#define MAX_TEST_NAME_SIZE 48
|
||||
#define SOCK_RECONF_CTR 10
|
||||
#define USLEEP_MAX 10000
|
||||
|
||||
extern bool opt_verbose;
|
||||
#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0)
|
||||
|
||||
|
||||
static inline u32 ceil_u32(u32 a, u32 b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
static inline u64 ceil_u64(u64 a, u64 b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
/* Simple test */
|
||||
enum test_mode {
|
||||
TEST_MODE_SKB,
|
||||
TEST_MODE_DRV,
|
||||
TEST_MODE_ZC,
|
||||
TEST_MODE_ALL
|
||||
};
|
||||
|
||||
struct ifobject;
|
||||
struct test_spec;
|
||||
typedef int (*validation_func_t)(struct ifobject *ifobj);
|
||||
typedef void *(*thread_func_t)(void *arg);
|
||||
typedef int (*test_func_t)(struct test_spec *test);
|
||||
|
||||
struct xsk_socket_info {
|
||||
struct xsk_ring_cons rx;
|
||||
struct xsk_ring_prod tx;
|
||||
struct xsk_umem_info *umem;
|
||||
struct xsk_socket *xsk;
|
||||
struct pkt_stream *pkt_stream;
|
||||
u32 outstanding_tx;
|
||||
u32 rxqsize;
|
||||
u32 batch_size;
|
||||
u8 dst_mac[ETH_ALEN];
|
||||
u8 src_mac[ETH_ALEN];
|
||||
bool check_consumer;
|
||||
};
|
||||
|
||||
int kick_rx(struct xsk_socket_info *xsk);
|
||||
int kick_tx(struct xsk_socket_info *xsk);
|
||||
|
||||
struct xsk_umem_info {
|
||||
struct xsk_ring_prod fq;
|
||||
struct xsk_ring_cons cq;
|
||||
struct xsk_umem *umem;
|
||||
u64 next_buffer;
|
||||
u32 num_frames;
|
||||
u32 frame_headroom;
|
||||
void *buffer;
|
||||
u32 frame_size;
|
||||
u32 base_addr;
|
||||
u32 fill_size;
|
||||
u32 comp_size;
|
||||
bool unaligned_mode;
|
||||
};
|
||||
|
||||
struct set_hw_ring {
|
||||
u32 default_tx;
|
||||
u32 default_rx;
|
||||
};
|
||||
|
||||
int hw_ring_size_reset(struct ifobject *ifobj);
|
||||
|
||||
struct ifobject {
|
||||
char ifname[MAX_INTERFACE_NAME_CHARS];
|
||||
struct xsk_socket_info *xsk;
|
||||
struct xsk_socket_info *xsk_arr;
|
||||
struct xsk_umem_info *umem;
|
||||
thread_func_t func_ptr;
|
||||
validation_func_t validation_func;
|
||||
struct xsk_xdp_progs *xdp_progs;
|
||||
struct bpf_map *xskmap;
|
||||
struct bpf_program *xdp_prog;
|
||||
struct ethtool_ringparam ring;
|
||||
struct set_hw_ring set_ring;
|
||||
enum test_mode mode;
|
||||
int ifindex;
|
||||
int mtu;
|
||||
u32 bind_flags;
|
||||
u32 xdp_zc_max_segs;
|
||||
bool tx_on;
|
||||
bool rx_on;
|
||||
bool use_poll;
|
||||
bool busy_poll;
|
||||
bool use_fill_ring;
|
||||
bool release_rx;
|
||||
bool shared_umem;
|
||||
bool use_metadata;
|
||||
bool unaligned_supp;
|
||||
bool multi_buff_supp;
|
||||
bool multi_buff_zc_supp;
|
||||
bool hw_ring_size_supp;
|
||||
};
|
||||
struct ifobject *ifobject_create(void);
|
||||
void ifobject_delete(struct ifobject *ifobj);
|
||||
int init_iface(struct ifobject *ifobj, thread_func_t func_ptr);
|
||||
|
||||
int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, u64 size);
|
||||
int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
|
||||
struct ifobject *ifobject, bool shared);
|
||||
|
||||
|
||||
struct pkt {
|
||||
int offset;
|
||||
u32 len;
|
||||
u32 pkt_nb;
|
||||
bool valid;
|
||||
u16 options;
|
||||
};
|
||||
|
||||
struct pkt_stream {
|
||||
u32 nb_pkts;
|
||||
u32 current_pkt_nb;
|
||||
struct pkt *pkts;
|
||||
u32 max_pkt_len;
|
||||
u32 nb_rx_pkts;
|
||||
u32 nb_valid_entries;
|
||||
bool verbatim;
|
||||
};
|
||||
|
||||
static inline bool pkt_continues(u32 options)
|
||||
{
|
||||
return options & XDP_PKT_CONTD;
|
||||
}
|
||||
|
||||
struct pkt_stream *pkt_stream_generate(u32 nb_pkts, u32 pkt_len);
|
||||
void pkt_stream_delete(struct pkt_stream *pkt_stream);
|
||||
void pkt_stream_reset(struct pkt_stream *pkt_stream);
|
||||
void pkt_stream_restore_default(struct test_spec *test);
|
||||
|
||||
struct test_spec {
|
||||
struct ifobject *ifobj_tx;
|
||||
struct ifobject *ifobj_rx;
|
||||
struct pkt_stream *tx_pkt_stream_default;
|
||||
struct pkt_stream *rx_pkt_stream_default;
|
||||
struct bpf_program *xdp_prog_rx;
|
||||
struct bpf_program *xdp_prog_tx;
|
||||
struct bpf_map *xskmap_rx;
|
||||
struct bpf_map *xskmap_tx;
|
||||
test_func_t test_func;
|
||||
int mtu;
|
||||
u16 total_steps;
|
||||
u16 current_step;
|
||||
u16 nb_sockets;
|
||||
bool fail;
|
||||
bool set_ring;
|
||||
bool adjust_tail;
|
||||
bool adjust_tail_support;
|
||||
enum test_mode mode;
|
||||
char name[MAX_TEST_NAME_SIZE];
|
||||
};
|
||||
|
||||
#define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : ""
|
||||
static inline char *mode_string(struct test_spec *test)
|
||||
{
|
||||
switch (test->mode) {
|
||||
case TEST_MODE_SKB:
|
||||
return "SKB";
|
||||
case TEST_MODE_DRV:
|
||||
return "DRV";
|
||||
case TEST_MODE_ZC:
|
||||
return "ZC";
|
||||
default:
|
||||
return "BOGUS";
|
||||
}
|
||||
}
|
||||
|
||||
void test_init(struct test_spec *test, struct ifobject *ifobj_tx,
|
||||
struct ifobject *ifobj_rx, enum test_mode mode,
|
||||
const struct test_spec *test_to_run);
|
||||
|
||||
int testapp_adjust_tail_grow(struct test_spec *test);
|
||||
int testapp_adjust_tail_grow_mb(struct test_spec *test);
|
||||
int testapp_adjust_tail_shrink(struct test_spec *test);
|
||||
int testapp_adjust_tail_shrink_mb(struct test_spec *test);
|
||||
int testapp_aligned_inv_desc(struct test_spec *test);
|
||||
int testapp_aligned_inv_desc_2k_frame(struct test_spec *test);
|
||||
int testapp_aligned_inv_desc_mb(struct test_spec *test);
|
||||
int testapp_bidirectional(struct test_spec *test);
|
||||
int testapp_headroom(struct test_spec *test);
|
||||
int testapp_hw_sw_max_ring_size(struct test_spec *test);
|
||||
int testapp_hw_sw_min_ring_size(struct test_spec *test);
|
||||
int testapp_poll_rx(struct test_spec *test);
|
||||
int testapp_poll_rxq_tmout(struct test_spec *test);
|
||||
int testapp_poll_tx(struct test_spec *test);
|
||||
int testapp_poll_txq_tmout(struct test_spec *test);
|
||||
int testapp_send_receive(struct test_spec *test);
|
||||
int testapp_send_receive_2k_frame(struct test_spec *test);
|
||||
int testapp_send_receive_mb(struct test_spec *test);
|
||||
int testapp_send_receive_unaligned(struct test_spec *test);
|
||||
int testapp_send_receive_unaligned_mb(struct test_spec *test);
|
||||
int testapp_single_pkt(struct test_spec *test);
|
||||
int testapp_stats_fill_empty(struct test_spec *test);
|
||||
int testapp_stats_rx_dropped(struct test_spec *test);
|
||||
int testapp_stats_tx_invalid_descs(struct test_spec *test);
|
||||
int testapp_stats_rx_full(struct test_spec *test);
|
||||
int testapp_teardown(struct test_spec *test);
|
||||
int testapp_too_many_frags(struct test_spec *test);
|
||||
int testapp_tx_queue_consumer(struct test_spec *test);
|
||||
int testapp_unaligned_inv_desc(struct test_spec *test);
|
||||
int testapp_unaligned_inv_desc_4001_frame(struct test_spec *test);
|
||||
int testapp_unaligned_inv_desc_mb(struct test_spec *test);
|
||||
int testapp_xdp_drop(struct test_spec *test);
|
||||
int testapp_xdp_metadata(struct test_spec *test);
|
||||
int testapp_xdp_metadata_mb(struct test_spec *test);
|
||||
int testapp_xdp_prog_cleanup(struct test_spec *test);
|
||||
int testapp_xdp_shared_umem(struct test_spec *test);
|
||||
|
||||
void *worker_testapp_validate_rx(void *arg);
|
||||
void *worker_testapp_validate_tx(void *arg);
|
||||
|
||||
static const struct test_spec tests[] = {
|
||||
{.name = "SEND_RECEIVE", .test_func = testapp_send_receive},
|
||||
{.name = "SEND_RECEIVE_2K_FRAME", .test_func = testapp_send_receive_2k_frame},
|
||||
{.name = "SEND_RECEIVE_SINGLE_PKT", .test_func = testapp_single_pkt},
|
||||
{.name = "POLL_RX", .test_func = testapp_poll_rx},
|
||||
{.name = "POLL_TX", .test_func = testapp_poll_tx},
|
||||
{.name = "POLL_RXQ_FULL", .test_func = testapp_poll_rxq_tmout},
|
||||
{.name = "POLL_TXQ_FULL", .test_func = testapp_poll_txq_tmout},
|
||||
{.name = "ALIGNED_INV_DESC", .test_func = testapp_aligned_inv_desc},
|
||||
{.name = "ALIGNED_INV_DESC_2K_FRAME_SIZE", .test_func = testapp_aligned_inv_desc_2k_frame},
|
||||
{.name = "UMEM_HEADROOM", .test_func = testapp_headroom},
|
||||
{.name = "BIDIRECTIONAL", .test_func = testapp_bidirectional},
|
||||
{.name = "STAT_RX_DROPPED", .test_func = testapp_stats_rx_dropped},
|
||||
{.name = "STAT_TX_INVALID", .test_func = testapp_stats_tx_invalid_descs},
|
||||
{.name = "STAT_RX_FULL", .test_func = testapp_stats_rx_full},
|
||||
{.name = "STAT_FILL_EMPTY", .test_func = testapp_stats_fill_empty},
|
||||
{.name = "XDP_PROG_CLEANUP", .test_func = testapp_xdp_prog_cleanup},
|
||||
{.name = "XDP_DROP_HALF", .test_func = testapp_xdp_drop},
|
||||
{.name = "XDP_SHARED_UMEM", .test_func = testapp_xdp_shared_umem},
|
||||
{.name = "XDP_METADATA_COPY", .test_func = testapp_xdp_metadata},
|
||||
{.name = "XDP_METADATA_COPY_MULTI_BUFF", .test_func = testapp_xdp_metadata_mb},
|
||||
{.name = "ALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_aligned_inv_desc_mb},
|
||||
{.name = "TOO_MANY_FRAGS", .test_func = testapp_too_many_frags},
|
||||
{.name = "XDP_ADJUST_TAIL_SHRINK", .test_func = testapp_adjust_tail_shrink},
|
||||
{.name = "TX_QUEUE_CONSUMER", .test_func = testapp_tx_queue_consumer},
|
||||
};
|
||||
|
||||
static const struct test_spec ci_skip_tests[] = {
|
||||
/* Flaky tests */
|
||||
{.name = "XDP_ADJUST_TAIL_SHRINK_MULTI_BUFF", .test_func = testapp_adjust_tail_shrink_mb},
|
||||
{.name = "XDP_ADJUST_TAIL_GROW", .test_func = testapp_adjust_tail_grow},
|
||||
{.name = "XDP_ADJUST_TAIL_GROW_MULTI_BUFF", .test_func = testapp_adjust_tail_grow_mb},
|
||||
{.name = "SEND_RECEIVE_9K_PACKETS", .test_func = testapp_send_receive_mb},
|
||||
/* Tests with huge page dependency */
|
||||
{.name = "SEND_RECEIVE_UNALIGNED", .test_func = testapp_send_receive_unaligned},
|
||||
{.name = "UNALIGNED_INV_DESC", .test_func = testapp_unaligned_inv_desc},
|
||||
{.name = "UNALIGNED_INV_DESC_4001_FRAME_SIZE",
|
||||
.test_func = testapp_unaligned_inv_desc_4001_frame},
|
||||
{.name = "SEND_RECEIVE_UNALIGNED_9K_PACKETS",
|
||||
.test_func = testapp_send_receive_unaligned_mb},
|
||||
{.name = "UNALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_unaligned_inv_desc_mb},
|
||||
/* Test with HW ring size dependency */
|
||||
{.name = "HW_SW_MIN_RING_SIZE", .test_func = testapp_hw_sw_min_ring_size},
|
||||
{.name = "HW_SW_MAX_RING_SIZE", .test_func = testapp_hw_sw_max_ring_size},
|
||||
/* Too long test */
|
||||
{.name = "TEARDOWN", .test_func = testapp_teardown},
|
||||
};
|
||||
|
||||
|
||||
#endif /* TEST_XSK_H_ */
|
||||
151
tools/testing/selftests/bpf/prog_tests/xsk.c
Normal file
151
tools/testing/selftests/bpf/prog_tests/xsk.c
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <net/if.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "network_helpers.h"
|
||||
#include "test_progs.h"
|
||||
#include "test_xsk.h"
|
||||
#include "xsk_xdp_progs.skel.h"
|
||||
|
||||
#define VETH_RX "veth0"
|
||||
#define VETH_TX "veth1"
|
||||
#define MTU 1500
|
||||
|
||||
int setup_veth(bool busy_poll)
|
||||
{
|
||||
SYS(fail,
|
||||
"ip link add %s numtxqueues 4 numrxqueues 4 type veth peer name %s numtxqueues 4 numrxqueues 4",
|
||||
VETH_RX, VETH_TX);
|
||||
SYS(fail, "sysctl -wq net.ipv6.conf.%s.disable_ipv6=1", VETH_RX);
|
||||
SYS(fail, "sysctl -wq net.ipv6.conf.%s.disable_ipv6=1", VETH_TX);
|
||||
|
||||
if (busy_poll) {
|
||||
SYS(fail, "echo 2 > /sys/class/net/%s/napi_defer_hard_irqs", VETH_RX);
|
||||
SYS(fail, "echo 200000 > /sys/class/net/%s/gro_flush_timeout", VETH_RX);
|
||||
SYS(fail, "echo 2 > /sys/class/net/%s/napi_defer_hard_irqs", VETH_TX);
|
||||
SYS(fail, "echo 200000 > /sys/class/net/%s/gro_flush_timeout", VETH_TX);
|
||||
}
|
||||
|
||||
SYS(fail, "ip link set %s mtu %d", VETH_RX, MTU);
|
||||
SYS(fail, "ip link set %s mtu %d", VETH_TX, MTU);
|
||||
SYS(fail, "ip link set %s up", VETH_RX);
|
||||
SYS(fail, "ip link set %s up", VETH_TX);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void delete_veth(void)
|
||||
{
|
||||
SYS_NOFAIL("ip link del %s", VETH_RX);
|
||||
SYS_NOFAIL("ip link del %s", VETH_TX);
|
||||
}
|
||||
|
||||
int configure_ifobj(struct ifobject *tx, struct ifobject *rx)
|
||||
{
|
||||
rx->ifindex = if_nametoindex(VETH_RX);
|
||||
if (!ASSERT_OK_FD(rx->ifindex, "get RX ifindex"))
|
||||
return -1;
|
||||
|
||||
tx->ifindex = if_nametoindex(VETH_TX);
|
||||
if (!ASSERT_OK_FD(tx->ifindex, "get TX ifindex"))
|
||||
return -1;
|
||||
|
||||
tx->shared_umem = false;
|
||||
rx->shared_umem = false;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_xsk(const struct test_spec *test_to_run, enum test_mode mode)
|
||||
{
|
||||
struct ifobject *ifobj_tx, *ifobj_rx;
|
||||
struct test_spec test;
|
||||
int ret;
|
||||
|
||||
ifobj_tx = ifobject_create();
|
||||
if (!ASSERT_OK_PTR(ifobj_tx, "create ifobj_tx"))
|
||||
return;
|
||||
|
||||
ifobj_rx = ifobject_create();
|
||||
if (!ASSERT_OK_PTR(ifobj_rx, "create ifobj_rx"))
|
||||
goto delete_tx;
|
||||
|
||||
if (!ASSERT_OK(configure_ifobj(ifobj_tx, ifobj_rx), "conigure ifobj"))
|
||||
goto delete_rx;
|
||||
|
||||
ret = get_hw_ring_size(ifobj_tx->ifname, &ifobj_tx->ring);
|
||||
if (!ret) {
|
||||
ifobj_tx->hw_ring_size_supp = true;
|
||||
ifobj_tx->set_ring.default_tx = ifobj_tx->ring.tx_pending;
|
||||
ifobj_tx->set_ring.default_rx = ifobj_tx->ring.rx_pending;
|
||||
}
|
||||
|
||||
if (!ASSERT_OK(init_iface(ifobj_rx, worker_testapp_validate_rx), "init RX"))
|
||||
goto delete_rx;
|
||||
if (!ASSERT_OK(init_iface(ifobj_tx, worker_testapp_validate_tx), "init TX"))
|
||||
goto delete_rx;
|
||||
|
||||
test_init(&test, ifobj_tx, ifobj_rx, 0, &tests[0]);
|
||||
|
||||
test.tx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
|
||||
if (!ASSERT_OK_PTR(test.tx_pkt_stream_default, "TX pkt generation"))
|
||||
goto delete_rx;
|
||||
test.rx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
|
||||
if (!ASSERT_OK_PTR(test.rx_pkt_stream_default, "RX pkt generation"))
|
||||
goto delete_rx;
|
||||
|
||||
|
||||
test_init(&test, ifobj_tx, ifobj_rx, mode, test_to_run);
|
||||
ret = test.test_func(&test);
|
||||
if (ret != TEST_SKIP)
|
||||
ASSERT_OK(ret, "Run test");
|
||||
pkt_stream_restore_default(&test);
|
||||
|
||||
if (ifobj_tx->hw_ring_size_supp)
|
||||
hw_ring_size_reset(ifobj_tx);
|
||||
|
||||
pkt_stream_delete(test.tx_pkt_stream_default);
|
||||
pkt_stream_delete(test.rx_pkt_stream_default);
|
||||
xsk_xdp_progs__destroy(ifobj_tx->xdp_progs);
|
||||
xsk_xdp_progs__destroy(ifobj_rx->xdp_progs);
|
||||
|
||||
delete_rx:
|
||||
ifobject_delete(ifobj_rx);
|
||||
delete_tx:
|
||||
ifobject_delete(ifobj_tx);
|
||||
}
|
||||
|
||||
void test_ns_xsk_skb(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ASSERT_OK(setup_veth(false), "setup veth"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
if (test__start_subtest(tests[i].name))
|
||||
test_xsk(&tests[i], TEST_MODE_SKB);
|
||||
}
|
||||
|
||||
delete_veth();
|
||||
}
|
||||
|
||||
void test_ns_xsk_drv(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ASSERT_OK(setup_veth(false), "setup veth"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
if (test__start_subtest(tests[i].name))
|
||||
test_xsk(&tests[i], TEST_MODE_DRV);
|
||||
}
|
||||
|
||||
delete_veth();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,169 +22,13 @@
|
||||
#define PF_XDP AF_XDP
|
||||
#endif
|
||||
|
||||
#ifndef SO_BUSY_POLL_BUDGET
|
||||
#define SO_BUSY_POLL_BUDGET 70
|
||||
#endif
|
||||
|
||||
#ifndef SO_PREFER_BUSY_POLL
|
||||
#define SO_PREFER_BUSY_POLL 69
|
||||
#endif
|
||||
|
||||
#define TEST_PASS 0
|
||||
#define TEST_FAILURE -1
|
||||
#define TEST_CONTINUE 1
|
||||
#define TEST_SKIP 2
|
||||
#define MAX_INTERFACES 2
|
||||
#define MAX_INTERFACE_NAME_CHARS 16
|
||||
#define MAX_TEST_NAME_SIZE 48
|
||||
#define MAX_TEARDOWN_ITER 10
|
||||
#define PKT_HDR_SIZE (sizeof(struct ethhdr) + 2) /* Just to align the data in the packet */
|
||||
#define MIN_PKT_SIZE 64
|
||||
#define MAX_ETH_PKT_SIZE 1518
|
||||
#define MAX_ETH_JUMBO_SIZE 9000
|
||||
#define USLEEP_MAX 10000
|
||||
#define SOCK_RECONF_CTR 10
|
||||
#define DEFAULT_BATCH_SIZE 64
|
||||
#define POLL_TMOUT 1000
|
||||
#define THREAD_TMOUT 3
|
||||
#define DEFAULT_PKT_CNT (4 * 1024)
|
||||
#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4)
|
||||
#define RX_FULL_RXQSIZE 32
|
||||
#define UMEM_HEADROOM_TEST_SIZE 128
|
||||
#define XSK_UMEM__INVALID_FRAME_SIZE (MAX_ETH_JUMBO_SIZE + 1)
|
||||
#define XSK_UMEM__LARGE_FRAME_SIZE (3 * 1024)
|
||||
#define XSK_UMEM__MAX_FRAME_SIZE (4 * 1024)
|
||||
#define XSK_DESC__INVALID_OPTION (0xffff)
|
||||
#define HUGEPAGE_SIZE (2 * 1024 * 1024)
|
||||
#define PKT_DUMP_NB_TO_PRINT 16
|
||||
#define RUN_ALL_TESTS UINT_MAX
|
||||
#define NUM_MAC_ADDRESSES 4
|
||||
|
||||
#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0)
|
||||
|
||||
enum test_mode {
|
||||
TEST_MODE_SKB,
|
||||
TEST_MODE_DRV,
|
||||
TEST_MODE_ZC,
|
||||
TEST_MODE_ALL
|
||||
};
|
||||
|
||||
struct xsk_umem_info {
|
||||
struct xsk_ring_prod fq;
|
||||
struct xsk_ring_cons cq;
|
||||
struct xsk_umem *umem;
|
||||
u64 next_buffer;
|
||||
u32 num_frames;
|
||||
u32 frame_headroom;
|
||||
void *buffer;
|
||||
u32 frame_size;
|
||||
u32 base_addr;
|
||||
u32 fill_size;
|
||||
u32 comp_size;
|
||||
bool unaligned_mode;
|
||||
};
|
||||
|
||||
struct xsk_socket_info {
|
||||
struct xsk_ring_cons rx;
|
||||
struct xsk_ring_prod tx;
|
||||
struct xsk_umem_info *umem;
|
||||
struct xsk_socket *xsk;
|
||||
struct pkt_stream *pkt_stream;
|
||||
u32 outstanding_tx;
|
||||
u32 rxqsize;
|
||||
u32 batch_size;
|
||||
u8 dst_mac[ETH_ALEN];
|
||||
u8 src_mac[ETH_ALEN];
|
||||
bool check_consumer;
|
||||
};
|
||||
|
||||
struct pkt {
|
||||
int offset;
|
||||
u32 len;
|
||||
u32 pkt_nb;
|
||||
bool valid;
|
||||
u16 options;
|
||||
};
|
||||
|
||||
struct pkt_stream {
|
||||
u32 nb_pkts;
|
||||
u32 current_pkt_nb;
|
||||
struct pkt *pkts;
|
||||
u32 max_pkt_len;
|
||||
u32 nb_rx_pkts;
|
||||
u32 nb_valid_entries;
|
||||
bool verbatim;
|
||||
};
|
||||
|
||||
struct set_hw_ring {
|
||||
u32 default_tx;
|
||||
u32 default_rx;
|
||||
};
|
||||
|
||||
struct ifobject;
|
||||
struct test_spec;
|
||||
typedef int (*validation_func_t)(struct ifobject *ifobj);
|
||||
typedef void *(*thread_func_t)(void *arg);
|
||||
typedef int (*test_func_t)(struct test_spec *test);
|
||||
|
||||
struct ifobject {
|
||||
char ifname[MAX_INTERFACE_NAME_CHARS];
|
||||
struct xsk_socket_info *xsk;
|
||||
struct xsk_socket_info *xsk_arr;
|
||||
struct xsk_umem_info *umem;
|
||||
thread_func_t func_ptr;
|
||||
validation_func_t validation_func;
|
||||
struct xsk_xdp_progs *xdp_progs;
|
||||
struct bpf_map *xskmap;
|
||||
struct bpf_program *xdp_prog;
|
||||
struct ethtool_ringparam ring;
|
||||
struct set_hw_ring set_ring;
|
||||
enum test_mode mode;
|
||||
int ifindex;
|
||||
int mtu;
|
||||
u32 bind_flags;
|
||||
u32 xdp_zc_max_segs;
|
||||
bool tx_on;
|
||||
bool rx_on;
|
||||
bool use_poll;
|
||||
bool busy_poll;
|
||||
bool use_fill_ring;
|
||||
bool release_rx;
|
||||
bool shared_umem;
|
||||
bool use_metadata;
|
||||
bool unaligned_supp;
|
||||
bool multi_buff_supp;
|
||||
bool multi_buff_zc_supp;
|
||||
bool hw_ring_size_supp;
|
||||
};
|
||||
|
||||
struct test_spec {
|
||||
struct ifobject *ifobj_tx;
|
||||
struct ifobject *ifobj_rx;
|
||||
struct pkt_stream *tx_pkt_stream_default;
|
||||
struct pkt_stream *rx_pkt_stream_default;
|
||||
struct bpf_program *xdp_prog_rx;
|
||||
struct bpf_program *xdp_prog_tx;
|
||||
struct bpf_map *xskmap_rx;
|
||||
struct bpf_map *xskmap_tx;
|
||||
test_func_t test_func;
|
||||
int mtu;
|
||||
u16 total_steps;
|
||||
u16 current_step;
|
||||
u16 nb_sockets;
|
||||
bool fail;
|
||||
bool set_ring;
|
||||
bool adjust_tail;
|
||||
bool adjust_tail_support;
|
||||
enum test_mode mode;
|
||||
char name[MAX_TEST_NAME_SIZE];
|
||||
};
|
||||
|
||||
pthread_barrier_t barr;
|
||||
pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
int pkts_in_flight;
|
||||
|
||||
static const u8 g_mac[ETH_ALEN] = {0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
|
||||
|
||||
#endif /* XSKXCEIVER_H_ */
|
||||
|
||||
Reference in New Issue
Block a user