| 
 | 1 | +// SPDX-License-Identifier: GPL-2.0  | 
 | 2 | +#include <net/if.h>  | 
 | 3 | +#include <stdarg.h>  | 
 | 4 | + | 
 | 5 | +#include "network_helpers.h"  | 
 | 6 | +#include "test_progs.h"  | 
 | 7 | +#include "test_xsk.h"  | 
 | 8 | +#include "xsk_xdp_progs.skel.h"  | 
 | 9 | + | 
 | 10 | +#define VETH_RX "veth0"  | 
 | 11 | +#define VETH_TX "veth1"  | 
 | 12 | +#define MTU	1500  | 
 | 13 | + | 
 | 14 | +int setup_veth(bool busy_poll)  | 
 | 15 | +{  | 
 | 16 | +	SYS(fail,  | 
 | 17 | +	"ip link add %s numtxqueues 4 numrxqueues 4 type veth peer name %s numtxqueues 4 numrxqueues 4",  | 
 | 18 | +	VETH_RX, VETH_TX);  | 
 | 19 | +	SYS(fail, "sysctl -wq net.ipv6.conf.%s.disable_ipv6=1", VETH_RX);  | 
 | 20 | +	SYS(fail, "sysctl -wq net.ipv6.conf.%s.disable_ipv6=1", VETH_TX);  | 
 | 21 | + | 
 | 22 | +	if (busy_poll) {  | 
 | 23 | +		SYS(fail, "echo 2 > /sys/class/net/%s/napi_defer_hard_irqs", VETH_RX);  | 
 | 24 | +		SYS(fail, "echo 200000 > /sys/class/net/%s/gro_flush_timeout", VETH_RX);  | 
 | 25 | +		SYS(fail, "echo 2 > /sys/class/net/%s/napi_defer_hard_irqs", VETH_TX);  | 
 | 26 | +		SYS(fail, "echo 200000 > /sys/class/net/%s/gro_flush_timeout", VETH_TX);  | 
 | 27 | +	}  | 
 | 28 | + | 
 | 29 | +	SYS(fail, "ip link set %s mtu %d", VETH_RX, MTU);  | 
 | 30 | +	SYS(fail, "ip link set %s mtu %d", VETH_TX, MTU);  | 
 | 31 | +	SYS(fail, "ip link set %s up", VETH_RX);  | 
 | 32 | +	SYS(fail, "ip link set %s up", VETH_TX);  | 
 | 33 | + | 
 | 34 | +	return 0;  | 
 | 35 | + | 
 | 36 | +fail:  | 
 | 37 | +	return -1;  | 
 | 38 | +}  | 
 | 39 | + | 
 | 40 | +void delete_veth(void)  | 
 | 41 | +{  | 
 | 42 | +	SYS_NOFAIL("ip link del %s", VETH_RX);  | 
 | 43 | +	SYS_NOFAIL("ip link del %s", VETH_TX);  | 
 | 44 | +}  | 
 | 45 | + | 
 | 46 | +int configure_ifobj(struct ifobject *tx, struct ifobject *rx)  | 
 | 47 | +{  | 
 | 48 | +	rx->ifindex = if_nametoindex(VETH_RX);  | 
 | 49 | +	if (!ASSERT_OK_FD(rx->ifindex, "get RX ifindex"))  | 
 | 50 | +		return -1;  | 
 | 51 | + | 
 | 52 | +	tx->ifindex = if_nametoindex(VETH_TX);  | 
 | 53 | +	if (!ASSERT_OK_FD(tx->ifindex, "get TX ifindex"))  | 
 | 54 | +		return -1;  | 
 | 55 | + | 
 | 56 | +	tx->shared_umem = false;  | 
 | 57 | +	rx->shared_umem = false;  | 
 | 58 | + | 
 | 59 | + | 
 | 60 | +	return 0;  | 
 | 61 | +}  | 
 | 62 | + | 
 | 63 | +static void test_xsk(const struct test_spec *test_to_run, enum test_mode mode)  | 
 | 64 | +{  | 
 | 65 | +	struct ifobject *ifobj_tx, *ifobj_rx;  | 
 | 66 | +	struct test_spec test;  | 
 | 67 | +	int ret;  | 
 | 68 | + | 
 | 69 | +	ifobj_tx = ifobject_create();  | 
 | 70 | +	if (!ASSERT_OK_PTR(ifobj_tx, "create ifobj_tx"))  | 
 | 71 | +		return;  | 
 | 72 | + | 
 | 73 | +	ifobj_rx = ifobject_create();  | 
 | 74 | +	if (!ASSERT_OK_PTR(ifobj_rx, "create ifobj_rx"))  | 
 | 75 | +		goto delete_tx;  | 
 | 76 | + | 
 | 77 | +	if (!ASSERT_OK(configure_ifobj(ifobj_tx, ifobj_rx), "conigure ifobj"))  | 
 | 78 | +		goto delete_rx;  | 
 | 79 | + | 
 | 80 | +	ret = get_hw_ring_size(ifobj_tx->ifname, &ifobj_tx->ring);  | 
 | 81 | +	if (!ret) {  | 
 | 82 | +		ifobj_tx->hw_ring_size_supp = true;  | 
 | 83 | +		ifobj_tx->set_ring.default_tx = ifobj_tx->ring.tx_pending;  | 
 | 84 | +		ifobj_tx->set_ring.default_rx = ifobj_tx->ring.rx_pending;  | 
 | 85 | +	}  | 
 | 86 | + | 
 | 87 | +	if (!ASSERT_OK(init_iface(ifobj_rx, worker_testapp_validate_rx), "init RX"))  | 
 | 88 | +		goto delete_rx;  | 
 | 89 | +	if (!ASSERT_OK(init_iface(ifobj_tx, worker_testapp_validate_tx), "init TX"))  | 
 | 90 | +		goto delete_rx;  | 
 | 91 | + | 
 | 92 | +	test_init(&test, ifobj_tx, ifobj_rx, 0, &tests[0]);  | 
 | 93 | + | 
 | 94 | +	test.tx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);  | 
 | 95 | +	if (!ASSERT_OK_PTR(test.tx_pkt_stream_default, "TX pkt generation"))  | 
 | 96 | +		goto delete_rx;  | 
 | 97 | +	test.rx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);  | 
 | 98 | +	if (!ASSERT_OK_PTR(test.rx_pkt_stream_default, "RX pkt generation"))  | 
 | 99 | +		goto delete_rx;  | 
 | 100 | + | 
 | 101 | + | 
 | 102 | +	test_init(&test, ifobj_tx, ifobj_rx, mode, test_to_run);  | 
 | 103 | +	ret = test.test_func(&test);  | 
 | 104 | +	if (ret != TEST_SKIP)  | 
 | 105 | +		ASSERT_OK(ret, "Run test");  | 
 | 106 | +	pkt_stream_restore_default(&test);  | 
 | 107 | + | 
 | 108 | +	if (ifobj_tx->hw_ring_size_supp)  | 
 | 109 | +		hw_ring_size_reset(ifobj_tx);  | 
 | 110 | + | 
 | 111 | +	pkt_stream_delete(test.tx_pkt_stream_default);  | 
 | 112 | +	pkt_stream_delete(test.rx_pkt_stream_default);  | 
 | 113 | +	xsk_xdp_progs__destroy(ifobj_tx->xdp_progs);  | 
 | 114 | +	xsk_xdp_progs__destroy(ifobj_rx->xdp_progs);  | 
 | 115 | + | 
 | 116 | +delete_rx:  | 
 | 117 | +	ifobject_delete(ifobj_rx);  | 
 | 118 | +delete_tx:  | 
 | 119 | +	ifobject_delete(ifobj_tx);  | 
 | 120 | +}  | 
 | 121 | + | 
 | 122 | +void test_ns_xsk_skb(void)  | 
 | 123 | +{  | 
 | 124 | +	int i;  | 
 | 125 | + | 
 | 126 | +	if (!ASSERT_OK(setup_veth(false), "setup veth"))  | 
 | 127 | +		return;  | 
 | 128 | + | 
 | 129 | +	for (i = 0; i < ARRAY_SIZE(tests); i++) {  | 
 | 130 | +		if (test__start_subtest(tests[i].name))  | 
 | 131 | +			test_xsk(&tests[i], TEST_MODE_SKB);  | 
 | 132 | +	}  | 
 | 133 | + | 
 | 134 | +	delete_veth();  | 
 | 135 | +}  | 
 | 136 | + | 
 | 137 | +void test_ns_xsk_drv(void)  | 
 | 138 | +{  | 
 | 139 | +	int i;  | 
 | 140 | + | 
 | 141 | +	if (!ASSERT_OK(setup_veth(false), "setup veth"))  | 
 | 142 | +		return;  | 
 | 143 | + | 
 | 144 | +	for (i = 0; i < ARRAY_SIZE(tests); i++) {  | 
 | 145 | +		if (test__start_subtest(tests[i].name))  | 
 | 146 | +			test_xsk(&tests[i], TEST_MODE_DRV);  | 
 | 147 | +	}  | 
 | 148 | + | 
 | 149 | +	delete_veth();  | 
 | 150 | +}  | 
 | 151 | + | 
0 commit comments