From b56cded1313718706f27a3b3ea545cff45f8b274 Mon Sep 17 00:00:00 2001 From: Tushar Vyavahare Date: Tue, 16 Jun 2026 21:19:52 +0530 Subject: [PATCH 1/3] selftests/xsk: make poll timeout mode explicit Stop inferring timeout behavior from RX UMEM initialization state. That ties timeout semantics to setup internals and obscures intent. Use test_spec::poll_tmout as the explicit timeout-mode selector in TX and RX paths. In RX, treat poll timeout as expected only in timeout mode. In TX, let send_pkts() own loop completion in non-timeout mode and use __send_pkts() only for progress and timeout detection. This makes timeout logic explicit and keeps control flow predictable. Signed-off-by: Magnus Karlsson Signed-off-by: Tushar Vyavahare Reviewed-by: Jason Xing Acked-by: Maciej Fijalkowski Tested-by: Maciej Fijalkowski Link: https://patch.msgid.link/20260616154955.1492560-2-tushar.vyavahare@intel.com Signed-off-by: Jakub Kicinski --- .../selftests/bpf/prog_tests/test_xsk.c | 44 +++++++++---------- .../selftests/bpf/prog_tests/test_xsk.h | 1 + 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c index 72875071d4f1..ca47a16ceb1a 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c +++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c @@ -65,11 +65,6 @@ static void gen_eth_hdr(struct xsk_socket_info *xsk, struct ethhdr *eth_hdr) eth_hdr->h_proto = htons(ETH_P_LOOPBACK); } -static bool is_umem_valid(struct xsk_socket_info *xsk) -{ - return !!xsk->umem->umem; -} - static u32 mode_to_xdp_flags(enum test_mode mode) { return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; @@ -1010,7 +1005,7 @@ static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) return TEST_FAILURE; if (!ret) { - if (!is_umem_valid(test->ifobj_tx->xsk)) + if (test->poll_tmout) return TEST_PASS; ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__); @@ -1149,7 +1144,7 @@ static int receive_pkts(struct test_spec *test) break; res = __receive_pkts(test, xsk); - if (!(res == TEST_PASS || res == TEST_CONTINUE)) + if (res != TEST_CONTINUE) return res; ret = gettimeofday(&tv_now, NULL); @@ -1166,7 +1161,8 @@ static int receive_pkts(struct test_spec *test) return TEST_PASS; } -static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, bool timeout) +static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, + bool test_timeout) { u32 i, idx = 0, valid_pkts = 0, valid_frags = 0, buffer_len; struct pkt_stream *pkt_stream = xsk->pkt_stream; @@ -1178,7 +1174,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b buffer_len = pkt_get_buffer_len(umem, pkt_stream->max_pkt_len); /* pkts_in_flight might be negative if many invalid packets are sent */ if (pkts_in_flight >= (int)((umem_size(umem) - xsk->batch_size * buffer_len) / - buffer_len)) { + buffer_len) && !test_timeout) { ret = kick_tx(xsk); if (ret) return TEST_FAILURE; @@ -1191,7 +1187,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b while (xsk_ring_prod__reserve(&xsk->tx, xsk->batch_size, &idx) < xsk->batch_size) { if (use_poll) { ret = poll(&fds, 1, POLL_TMOUT); - if (timeout) { + if (test_timeout) { if (ret < 0) { ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, errno); @@ -1271,7 +1267,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b if (use_poll) { ret = poll(&fds, 1, POLL_TMOUT); if (ret <= 0) { - if (ret == 0 && timeout) + if (ret == 0 && test_timeout) return TEST_PASS; ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret); @@ -1279,14 +1275,14 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b } } - if (!timeout) { + if (!test_timeout) { if (complete_pkts(xsk, i)) return TEST_FAILURE; usleep(10); - return TEST_PASS; } + /* Loop completion is driven by send_pkts() stream progress checks. */ return TEST_CONTINUE; } @@ -1322,7 +1318,6 @@ bool all_packets_sent(struct test_spec *test, unsigned long *bitmap) static int send_pkts(struct test_spec *test, struct ifobject *ifobject) { - bool timeout = !is_umem_valid(test->ifobj_rx->xsk); DECLARE_BITMAP(bitmap, test->nb_sockets); u32 i, ret; @@ -1337,19 +1332,18 @@ static int send_pkts(struct test_spec *test, struct ifobject *ifobject) __set_bit(i, bitmap); continue; } - ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], timeout); - if (ret == TEST_CONTINUE && !test->fail) - continue; - - if ((ret || test->fail) && !timeout) - return TEST_FAILURE; - - if (ret == TEST_PASS && timeout) + ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], test->poll_tmout); + if (ret != TEST_CONTINUE) return ret; - ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); - if (ret) + if (test->fail) return TEST_FAILURE; + + if (!test->poll_tmout) { + ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); + if (ret) + return TEST_FAILURE; + } } } @@ -2231,6 +2225,7 @@ int testapp_xdp_shared_umem(struct test_spec *test) int testapp_poll_txq_tmout(struct test_spec *test) { + test->poll_tmout = true; test->ifobj_tx->use_poll = true; /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ test->ifobj_tx->xsk->umem->frame_size = 2048; @@ -2241,6 +2236,7 @@ int testapp_poll_txq_tmout(struct test_spec *test) int testapp_poll_rxq_tmout(struct test_spec *test) { + test->poll_tmout = true; test->ifobj_rx->use_poll = true; return testapp_validate_traffic_single_thread(test, test->ifobj_rx); } diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.h b/tools/testing/selftests/bpf/prog_tests/test_xsk.h index 4313d0d87235..20eaaa254998 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_xsk.h +++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.h @@ -207,6 +207,7 @@ struct test_spec { bool set_ring; bool adjust_tail; bool adjust_tail_support; + bool poll_tmout; enum test_mode mode; char name[MAX_TEST_NAME_SIZE]; }; From 483c1405f8172d926df5fbf0477dbfacef822e64 Mon Sep 17 00:00:00 2001 From: Tushar Vyavahare Date: Tue, 16 Jun 2026 21:19:53 +0530 Subject: [PATCH 2/3] selftests/xsk: fix timeout thread harness sequencing Prevent workers from running before XDP program attachment completes. The previous ordering allowed races between worker startup and setup. Attach XDP programs before entering traffic validation. Remove SIGUSR1-based worker termination and use pthread_join() for thread shutdown so blocking syscalls are not interrupted. Use barriers only for dual-thread runs so participants match and teardown ordering stays deterministic. This removes setup/startup races and stabilizes harness sequencing. Signed-off-by: Tushar Vyavahare Reviewed-by: Jason Xing Acked-by: Maciej Fijalkowski Tested-by: Maciej Fijalkowski Link: https://patch.msgid.link/20260616154955.1492560-3-tushar.vyavahare@intel.com Signed-off-by: Jakub Kicinski --- .../selftests/bpf/prog_tests/test_xsk.c | 33 ++++++++++--------- .../selftests/bpf/prog_tests/test_xsk.h | 1 + 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c index ca47a16ceb1a..d4702d2aac5e 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c +++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -1671,7 +1670,8 @@ void *worker_testapp_validate_rx(void *arg) strerror(-err)); } - pthread_barrier_wait(&barr); + if (test->use_barrier) + pthread_barrier_wait(&barr); /* We leave only now in case of error to avoid getting stuck in the barrier */ if (err) { @@ -1710,11 +1710,6 @@ static void testapp_clean_xsk_umem(struct ifobject *ifobj) munmap(umem->buffer, umem->mmap_size); } -static void handler(int signum) -{ - pthread_exit(NULL); -} - static bool xdp_prog_changed_rx(struct test_spec *test) { struct ifobject *ifobj = test->ifobj_rx; @@ -1819,9 +1814,18 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i return TEST_FAILURE; } - if (ifobj2) { + err = xsk_attach_xdp_progs(test, ifobj1, ifobj2); + if (err) { + ksft_print_msg("Error: failed to attach XDP programs: %d (%s)\n", + err, strerror(-err)); + return TEST_FAILURE; + } + test->use_barrier = !!ifobj2; + + if (test->use_barrier) { if (pthread_barrier_init(&barr, NULL, 2)) return TEST_FAILURE; + pkt_stream_reset(ifobj2->xsk->pkt_stream); } @@ -1829,27 +1833,26 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i pkt_stream_reset(ifobj1->xsk->pkt_stream); pkts_in_flight = 0; - signal(SIGUSR1, handler); /*Spawn RX thread */ pthread_create(&t0, NULL, ifobj1->func_ptr, test); - if (ifobj2) { + if (test->use_barrier) { pthread_barrier_wait(&barr); if (pthread_barrier_destroy(&barr)) { - pthread_kill(t0, SIGUSR1); + test->use_barrier = false; + pthread_join(t0, NULL); clean_sockets(test, ifobj1); clean_umem(test, ifobj1, NULL); return TEST_FAILURE; } + } + if (ifobj2) { /*Spawn TX thread */ pthread_create(&t1, NULL, ifobj2->func_ptr, test); - pthread_join(t1, NULL); } - if (!ifobj2) - pthread_kill(t0, SIGUSR1); pthread_join(t0, NULL); if (test->total_steps == test->current_step || test->fail) { @@ -1887,8 +1890,6 @@ static int testapp_validate_traffic(struct test_spec *test) } } - if (xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx)) - return TEST_FAILURE; return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); } diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.h b/tools/testing/selftests/bpf/prog_tests/test_xsk.h index 20eaaa254998..03753ddc5dcd 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_xsk.h +++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.h @@ -208,6 +208,7 @@ struct test_spec { bool adjust_tail; bool adjust_tail_support; bool poll_tmout; + bool use_barrier; enum test_mode mode; char name[MAX_TEST_NAME_SIZE]; }; From ea4e9c9d8b2bd1f8b8538491443bc47d72f47e5b Mon Sep 17 00:00:00 2001 From: Tushar Vyavahare Date: Tue, 16 Jun 2026 21:19:54 +0530 Subject: [PATCH 3/3] selftests/xsk: restore shared_umem after POLL_TXQ_FULL POLL_TXQ_FULL temporarily disables shared_umem on TX to exercise the TX timeout path in isolation. With shared_umem enabled, TX setup expects RX UMEM to be initialized first and fails with: "RX UMEM is not initialized before shared-UMEM TX setup". Save and restore shared_umem around POLL_TXQ_FULL execution, and restore it on both success and pkt_stream_replace() failure paths. Also add an in-code comment explaining why shared_umem is temporarily disabled in this test. This keeps timeout setup local and prevents cross-test state leakage. Signed-off-by: Tushar Vyavahare Reviewed-by: Jason Xing Acked-by: Maciej Fijalkowski Tested-by: Maciej Fijalkowski Link: https://patch.msgid.link/20260616154955.1492560-4-tushar.vyavahare@intel.com Signed-off-by: Jakub Kicinski --- .../selftests/bpf/prog_tests/test_xsk.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c index d4702d2aac5e..6eb9096d084c 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c +++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c @@ -2226,13 +2226,28 @@ int testapp_xdp_shared_umem(struct test_spec *test) int testapp_poll_txq_tmout(struct test_spec *test) { + bool shared_umem = test->ifobj_tx->shared_umem; + int ret; + test->poll_tmout = true; + /* + * POLL_TXQ_FULL exercises TX timeout setup in isolation. + * Keep TX out of shared-UMEM mode here so TX setup does not require + * RX UMEM to be initialized first. + */ + test->ifobj_tx->shared_umem = false; test->ifobj_tx->use_poll = true; /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ test->ifobj_tx->xsk->umem->frame_size = 2048; - if (pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048)) + if (pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048)) { + test->ifobj_tx->shared_umem = shared_umem; return TEST_FAILURE; - return testapp_validate_traffic_single_thread(test, test->ifobj_tx); + } + + ret = testapp_validate_traffic_single_thread(test, test->ifobj_tx); + test->ifobj_tx->shared_umem = shared_umem; + + return ret; } int testapp_poll_rxq_tmout(struct test_spec *test)