/* SPDX-License-Identifier: GPL-2.0 */ #ifndef TEST_XSK_H_ #define TEST_XSK_H_ #include #include #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_ */