selftests/xsk: Introduce set_ring_size function with a retry mechanism for handling...
authorTushar Vyavahare <tushar.vyavahare@intel.com>
Tue, 2 Apr 2024 11:45:27 +0000 (11:45 +0000)
committerDaniel Borkmann <daniel@iogearbox.net>
Wed, 3 Apr 2024 14:03:57 +0000 (16:03 +0200)
Introduce a new function, set_ring_size(), to manage asynchronous AF_XDP
socket closure. Retry set_hw_ring_size up to SOCK_RECONF_CTR times if it
fails due to an active AF_XDP socket. Return an error immediately for
non-EBUSY errors. This enhances robustness against asynchronous AF_XDP
socket closures during ring size changes.

Signed-off-by: Tushar Vyavahare <tushar.vyavahare@intel.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Magnus Karlsson <magnus.karlsson@intel.com>
Link: https://lore.kernel.org/bpf/20240402114529.545475-6-tushar.vyavahare@intel.com
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/xskxceiver.c
tools/testing/selftests/bpf/xskxceiver.h

index b0ac3dd80acfcb24f410ad834537d208eee6b5a9..eea5b8deaaf09e15812867404e5c024da53e64b8 100644 (file)
@@ -695,7 +695,7 @@ $(OUTPUT)/test_verifier: test_verifier.c verifier/tests.h $(BPFOBJ) | $(OUTPUT)
 
 # Include find_bit.c to compile xskxceiver.
 EXTRA_SRC := $(TOOLSDIR)/lib/find_bit.c
-$(OUTPUT)/xskxceiver: $(EXTRA_SRC) xskxceiver.c xskxceiver.h $(OUTPUT)/xsk.o $(OUTPUT)/xsk_xdp_progs.skel.h $(BPFOBJ) | $(OUTPUT)
+$(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 $@
 
index eaa102c8098b903b5a3cd8c449b083c028e20a2f..8c26868e17cfdf2af5ebc63660fb6e8c7d8159bb 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/mman.h>
 #include <linux/netdev.h>
 #include <linux/bitmap.h>
+#include <linux/ethtool.h>
 #include <arpa/inet.h>
 #include <net/if.h>
 #include <locale.h>
 #include "../kselftest.h"
 #include "xsk_xdp_common.h"
 
+#include <network_helpers.h>
+
 static bool opt_verbose;
 static bool opt_print_tests;
 static enum test_mode opt_mode = TEST_MODE_ALL;
 static u32 opt_run_test = RUN_ALL_TESTS;
 
+void test__fail(void) { /* for network_helpers.c */ }
+
 static void __exit_with_error(int error, const char *file, const char *func, int line)
 {
        ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error,
@@ -409,6 +414,33 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj
        }
 }
 
+static int set_ring_size(struct ifobject *ifobj)
+{
+       int ret;
+       u32 ctr = 0;
+
+       while (ctr++ < SOCK_RECONF_CTR) {
+               ret = set_hw_ring_size(ifobj->ifname, &ifobj->ring);
+               if (!ret)
+                       break;
+
+               /* Retry if it fails */
+               if (ctr >= SOCK_RECONF_CTR || errno != EBUSY)
+                       return -errno;
+
+               usleep(USLEEP_MAX);
+       }
+
+       return ret;
+}
+
+static int hw_ring_size_reset(struct ifobject *ifobj)
+{
+       ifobj->ring.tx_pending = ifobj->set_ring.default_tx;
+       ifobj->ring.rx_pending = ifobj->set_ring.default_rx;
+       return set_ring_size(ifobj);
+}
+
 static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
                             struct ifobject *ifobj_rx)
 {
@@ -452,12 +484,16 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
                }
        }
 
+       if (ifobj_tx->hw_ring_size_supp)
+               hw_ring_size_reset(ifobj_tx);
+
        test->ifobj_tx = ifobj_tx;
        test->ifobj_rx = ifobj_rx;
        test->current_step = 0;
        test->total_steps = 1;
        test->nb_sockets = 1;
        test->fail = false;
+       test->set_ring = false;
        test->mtu = MAX_ETH_PKT_SIZE;
        test->xdp_prog_rx = ifobj_rx->xdp_progs->progs.xsk_def_prog;
        test->xskmap_rx = ifobj_rx->xdp_progs->maps.xsk;
@@ -1862,6 +1898,14 @@ static int testapp_validate_traffic(struct test_spec *test)
                return TEST_SKIP;
        }
 
+       if (test->set_ring) {
+               if (ifobj_tx->hw_ring_size_supp)
+                       return set_ring_size(ifobj_tx);
+
+       ksft_test_result_skip("Changing HW ring size not supported.\n");
+       return TEST_SKIP;
+       }
+
        xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx);
        return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx);
 }
@@ -2479,7 +2523,7 @@ static const struct test_spec tests[] = {
        {.name = "ALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_aligned_inv_desc_mb},
        {.name = "UNALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_unaligned_inv_desc_mb},
        {.name = "TOO_MANY_FRAGS", .test_func = testapp_too_many_frags},
-};
+       };
 
 static void print_tests(void)
 {
@@ -2499,6 +2543,7 @@ int main(int argc, char **argv)
        int modes = TEST_MODE_SKB + 1;
        struct test_spec test;
        bool shared_netdev;
+       int ret;
 
        /* Use libbpf 1.0 API mode */
        libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
@@ -2536,6 +2581,13 @@ int main(int argc, char **argv)
                        modes++;
        }
 
+       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;
+       }
+
        init_iface(ifobj_rx, worker_testapp_validate_rx);
        init_iface(ifobj_tx, worker_testapp_validate_tx);
 
@@ -2583,6 +2635,9 @@ int main(int argc, char **argv)
                }
        }
 
+       if (ifobj_tx->hw_ring_size_supp)
+               hw_ring_size_reset(ifobj_tx);
+
        pkt_stream_delete(tx_pkt_stream_default);
        pkt_stream_delete(rx_pkt_stream_default);
        xsk_unload_xdp_programs(ifobj_tx);
index 425304e52f3566913454dcb7c8d4599b625947e8..906de5fab7a366774a11f6c15d3a46c29ba2d87f 100644 (file)
@@ -114,6 +114,11 @@ struct pkt_stream {
        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);
@@ -130,6 +135,8 @@ struct ifobject {
        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;
@@ -146,6 +153,7 @@ struct ifobject {
        bool unaligned_supp;
        bool multi_buff_supp;
        bool multi_buff_zc_supp;
+       bool hw_ring_size_supp;
 };
 
 struct test_spec {
@@ -163,6 +171,7 @@ struct test_spec {
        u16 current_step;
        u16 nb_sockets;
        bool fail;
+       bool set_ring;
        enum test_mode mode;
        char name[MAX_TEST_NAME_SIZE];
 };