From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
To: netdev@vger.kernel.org
Cc: bpf@vger.kernel.org, magnus.karlsson@intel.com,
stfomichev@gmail.com, kuba@kernel.org, pabeni@redhat.com,
tushar.vyavahare@intel.com, kerneljasonxing@gmail.com,
bjorn@kernel.org,
Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Subject: [PATCH net-next 07/13] selftests: xsk: split xskxceiver main() into setup, run and cleanup
Date: Thu, 1 Oct 2026 22:21:18 +0200 [thread overview]
Message-ID: <20261001202124.692591-8-maciej.fijalkowski@intel.com> (raw)
In-Reply-To: <20261001202124.692591-1-maciej.fijalkowski@intel.com>
Prepare xskxceiver for running a single endpoint per process by
untangling main():
- bind_iface() resolves and initializes one interface from its -i
argument, so the interface list can be assigned to roles after
parsing; -l lists tests and exits without needing interfaces
- detect_mode_caps() records DRV and zero-copy support and
detect_ifobj_caps() HW ring support as XSK_CAP flags, and
mode_supported() tells from them whether a mode can run
- run_pkt_test() returns the result, and main() counts failures from
it rather than from test->fail, which not every failing path sets
- cleanup_iface() restores rings, detaches and unloads per interface
and is safe on partially initialized objects, as is
pkt_stream_delete(NULL), so main() has a single exit path
Call ksft_print_header() before ksft_set_plan(): xskxceiver never did,
and that is where kselftest.h switches stdout to line buffering, so a
launcher reading through a pipe only saw the output at exit.
While at it, exit with 0 for -l instead of KSFT_XPASS: listing the
tests is not a test result, so scripts should be able to run it like
any other command.
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
.../testing/selftests/net/lib/xsk/test_xsk.c | 10 +
.../testing/selftests/net/lib/xsk/test_xsk.h | 2 +
.../selftests/net/lib/xsk/xskxceiver.c | 184 +++++++++---------
3 files changed, 107 insertions(+), 89 deletions(-)
diff --git a/tools/testing/selftests/net/lib/xsk/test_xsk.c b/tools/testing/selftests/net/lib/xsk/test_xsk.c
index a26f4d8378c4..eb91d74a9f94 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.c
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.c
@@ -369,6 +369,9 @@ static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32
void pkt_stream_delete(struct pkt_stream *pkt_stream)
{
+ if (!pkt_stream)
+ return;
+
free(pkt_stream->pkts);
free(pkt_stream);
}
@@ -2331,6 +2334,13 @@ static int detect_ifobj_caps(struct ifobject *ifobj)
}
}
+ if (!get_hw_ring_size(ifobj->ifname, &ifobj->ring)) {
+ ifobj_set_cap(ifobj, XSK_CAP_HW_RING);
+ ifobj->caps.tx_max_pending = ifobj->ring.tx_max_pending;
+ ifobj->set_ring.default_tx = ifobj->ring.tx_pending;
+ ifobj->set_ring.default_rx = ifobj->ring.rx_pending;
+ }
+
return 0;
}
diff --git a/tools/testing/selftests/net/lib/xsk/test_xsk.h b/tools/testing/selftests/net/lib/xsk/test_xsk.h
index 1d17e214db91..861a2ee3b8e1 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.h
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.h
@@ -123,6 +123,8 @@ int hw_ring_size_reset(struct ifobject *ifobj);
#define XSK_CAP_MBUF (1U << 1)
#define XSK_CAP_MBUF_ZC (1U << 2)
#define XSK_CAP_HW_RING (1U << 3)
+#define XSK_CAP_DRV (1U << 4)
+#define XSK_CAP_ZC (1U << 5)
struct xsk_caps {
u32 flags;
diff --git a/tools/testing/selftests/net/lib/xsk/xskxceiver.c b/tools/testing/selftests/net/lib/xsk/xskxceiver.c
index 8b3e4d18e982..afd6b242aa0d 100644
--- a/tools/testing/selftests/net/lib/xsk/xskxceiver.c
+++ b/tools/testing/selftests/net/lib/xsk/xskxceiver.c
@@ -81,7 +81,6 @@
#include <linux/netdev.h>
#include <linux/ethtool.h>
#include <linux/align.h>
-#include <linux/kernel.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <locale.h>
@@ -101,7 +100,6 @@
#include "kselftest.h"
#include "xsk_xdp_common.h"
-static bool opt_print_tests;
static enum test_mode opt_mode = TEST_MODE_ALL;
static u32 opt_run_test = RUN_ALL_TESTS;
@@ -185,17 +183,40 @@ static void print_usage(char **argv)
ksft_exit_xfail();
}
-static bool validate_interface(struct ifobject *ifobj)
+static void bind_iface(struct ifobject *ifobj, const char *ifname, thread_func_t func,
+ char **argv)
{
- if (!strcmp(ifobj->ifname, ""))
- return false;
- return true;
+ size_t len = ifname ? strlen(ifname) : 0;
+
+ if (!len || len >= sizeof(ifobj->ifname))
+ print_usage(argv);
+
+ memcpy(ifobj->ifname, ifname, len + 1);
+ ifobj->ifindex = if_nametoindex(ifobj->ifname);
+ if (!ifobj->ifindex) {
+ ksft_print_msg("Error: cannot resolve interface %s\n", ifobj->ifname);
+ ksft_exit_fail();
+ }
+
+ if (init_iface(ifobj, func)) {
+ ksft_print_msg("Error: cannot initialize interface %s\n", ifobj->ifname);
+ ksft_exit_fail();
+ }
+}
+
+static void print_tests(void)
+{
+ u32 i;
+
+ printf("Tests:\n");
+ for (i = 0; i < ARRAY_SIZE(tests); i++)
+ printf("%u: %s\n", i, tests[i].name);
}
static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx, int argc,
char **argv)
{
- struct ifobject *ifobj;
+ const char *ifname[2] = {};
u32 interface_nb = 0;
int option_index, c;
@@ -208,21 +229,10 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj
switch (c) {
case 'i':
- if (interface_nb == 0)
- ifobj = ifobj_tx;
- else if (interface_nb == 1)
- ifobj = ifobj_rx;
- else
+ if (interface_nb >= ARRAY_SIZE(ifname))
break;
- memcpy(ifobj->ifname, optarg,
- min_t(size_t, MAX_INTERFACE_NAME_CHARS, strlen(optarg)));
-
- ifobj->ifindex = if_nametoindex(ifobj->ifname);
- if (!ifobj->ifindex)
- exit_with_error(errno);
-
- interface_nb++;
+ ifname[interface_nb++] = optarg;
break;
case 'v':
opt_verbose = true;
@@ -242,7 +252,8 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj
print_usage(argv);
break;
case 'l':
- opt_print_tests = true;
+ print_tests();
+ ksft_exit_pass();
break;
case 't':
errno = 0;
@@ -255,6 +266,9 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj
print_usage(argv);
}
}
+
+ bind_iface(ifobj_tx, ifname[0], worker_testapp_validate_tx, argv);
+ bind_iface(ifobj_rx, ifname[1], worker_testapp_validate_rx, argv);
}
static void xsk_unload_xdp_programs(struct ifobject *ifobj)
@@ -262,7 +276,7 @@ static void xsk_unload_xdp_programs(struct ifobject *ifobj)
xsk_xdp_progs__destroy(ifobj->xdp_progs);
}
-static void run_pkt_test(struct test_spec *test)
+static int run_pkt_test(struct test_spec *test)
{
int ret;
@@ -287,6 +301,7 @@ static void run_pkt_test(struct test_spec *test)
}
pkt_stream_restore_default(test);
+ return ret;
}
static bool is_xdp_supported(int ifindex)
@@ -317,26 +332,46 @@ static bool is_xdp_supported(int ifindex)
return true;
}
-static void print_tests(void)
+static u32 detect_mode_caps(struct ifobject *ifobj)
{
- u32 i;
+ if (is_xdp_supported(ifobj->ifindex)) {
+ ifobj_set_cap(ifobj, XSK_CAP_DRV);
+ if (ifobj_zc_avail(ifobj))
+ ifobj_set_cap(ifobj, XSK_CAP_ZC);
+ }
- printf("Tests:\n");
- for (i = 0; i < ARRAY_SIZE(tests); i++)
- printf("%u: %s\n", i, tests[i].name);
+ return ifobj->caps.flags;
+}
+
+static bool mode_supported(enum test_mode mode, u32 caps)
+{
+ if (mode == TEST_MODE_SKB)
+ return true;
+ if (mode == TEST_MODE_DRV)
+ return caps & XSK_CAP_DRV;
+ return caps & XSK_CAP_ZC;
+}
+
+static void cleanup_iface(struct ifobject *ifobj)
+{
+ if (ifobj_has_cap(ifobj, XSK_CAP_HW_RING))
+ hw_ring_size_reset(ifobj);
+ if (ifobj->xdp_prog)
+ xsk_detach_xdp_program(ifobj->ifindex,
+ ifobj->mode == TEST_MODE_SKB ?
+ XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE);
+ xsk_unload_xdp_programs(ifobj);
}
int main(int argc, char **argv)
{
u32 cache_line_size, max_frags, umem_tailroom;
const size_t total_tests = ARRAY_SIZE(tests);
- struct pkt_stream *rx_pkt_stream_default;
- struct pkt_stream *tx_pkt_stream_default;
struct ifobject *ifobj_tx, *ifobj_rx;
u32 i, j, failed_tests = 0, nb_tests;
- int modes = TEST_MODE_SKB + 1;
- struct test_spec test;
- int ret;
+ struct test_spec test = {};
+ int ret = TEST_FAILURE;
+ u32 caps, modes = 0;
/* Use libbpf 1.0 API mode */
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
@@ -373,93 +408,64 @@ int main(int argc, char **argv)
parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
- if (opt_print_tests) {
- print_tests();
- ksft_exit_xpass();
- }
if (opt_run_test != RUN_ALL_TESTS && opt_run_test >= total_tests) {
ksft_print_msg("Error: test %u does not exist.\n", opt_run_test);
ksft_exit_xfail();
}
- if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx))
- print_usage(argv);
-
- if (is_xdp_supported(ifobj_tx->ifindex)) {
- modes++;
- if (ifobj_zc_avail(ifobj_tx))
- modes++;
- }
+ test.tx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
+ test.rx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
+ if (!test.tx_pkt_stream_default || !test.rx_pkt_stream_default)
+ goto out;
- ret = get_hw_ring_size(ifobj_tx->ifname, &ifobj_tx->ring);
- if (!ret) {
- ifobj_set_cap(ifobj_tx, XSK_CAP_HW_RING);
- ifobj_tx->caps.tx_max_pending = ifobj_tx->ring.tx_max_pending;
- ifobj_tx->set_ring.default_tx = ifobj_tx->ring.tx_pending;
- ifobj_tx->set_ring.default_rx = ifobj_tx->ring.rx_pending;
- }
+ caps = detect_mode_caps(ifobj_tx);
- if (init_iface(ifobj_rx, worker_testapp_validate_rx) ||
- init_iface(ifobj_tx, worker_testapp_validate_tx)) {
- ksft_print_msg("Error : can't initialize interfaces\n");
+ if (opt_mode != TEST_MODE_ALL && !mode_supported(opt_mode, caps)) {
+ if (opt_mode == TEST_MODE_DRV)
+ ksft_print_msg("Error: XDP_DRV mode not supported.\n");
+ else
+ ksft_print_msg("Error: zero-copy mode not supported.\n");
ksft_exit_xfail();
}
- test_init(&test, ifobj_tx, ifobj_rx, 0, &tests[0]);
- tx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
- rx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE);
- if (!tx_pkt_stream_default || !rx_pkt_stream_default)
- exit_with_error(ENOMEM);
- test.tx_pkt_stream_default = tx_pkt_stream_default;
- test.rx_pkt_stream_default = rx_pkt_stream_default;
-
+ for (i = TEST_MODE_SKB; i <= TEST_MODE_ZC; i++)
+ if ((opt_mode == TEST_MODE_ALL || i == opt_mode) && mode_supported(i, caps))
+ modes++;
if (opt_run_test == RUN_ALL_TESTS)
nb_tests = total_tests;
else
nb_tests = 1;
- if (opt_mode == TEST_MODE_ALL) {
- ksft_set_plan(modes * nb_tests);
- } else {
- if (opt_mode == TEST_MODE_DRV && modes <= TEST_MODE_DRV) {
- ksft_print_msg("Error: XDP_DRV mode not supported.\n");
- ksft_exit_xfail();
- }
- if (opt_mode == TEST_MODE_ZC && modes <= TEST_MODE_ZC) {
- ksft_print_msg("Error: zero-copy mode not supported.\n");
- ksft_exit_xfail();
- }
-
- ksft_set_plan(nb_tests);
- }
+ /* Line-buffer stdout so verdicts reach a capturing launcher live. */
+ ksft_print_header();
+ ksft_set_plan(modes * nb_tests);
- for (i = 0; i < modes; i++) {
+ for (i = TEST_MODE_SKB; i <= TEST_MODE_ZC; i++) {
if (opt_mode != TEST_MODE_ALL && i != opt_mode)
continue;
+ if (!mode_supported(i, caps))
+ continue;
for (j = 0; j < total_tests; j++) {
if (opt_run_test != RUN_ALL_TESTS && j != opt_run_test)
continue;
test_init(&test, ifobj_tx, ifobj_rx, i, &tests[j]);
- run_pkt_test(&test);
- usleep(USLEEP_MAX);
-
- if (test.fail)
+ if (run_pkt_test(&test) == TEST_FAILURE)
failed_tests++;
+ usleep(USLEEP_MAX);
}
}
+ ret = failed_tests ? TEST_FAILURE : TEST_PASS;
- if (ifobj_has_cap(ifobj_tx, XSK_CAP_HW_RING))
- 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);
- xsk_unload_xdp_programs(ifobj_rx);
+out:
+ cleanup_iface(ifobj_tx);
+ cleanup_iface(ifobj_rx);
+ pkt_stream_delete(test.tx_pkt_stream_default);
+ pkt_stream_delete(test.rx_pkt_stream_default);
ifobject_delete(ifobj_tx);
ifobject_delete(ifobj_rx);
- if (failed_tests)
+ if (ret)
ksft_exit_fail();
else
ksft_exit_pass();
--
2.43.0
next prev parent reply other threads:[~2026-10-01 20:22 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 20:21 [PATCH net-next 00/13] selftests: net: migrate AF_XDP test suite over to net Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 01/13] selftests: xsk: factor endpoint work out of pthread wrappers Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 02/13] selftests: xsk: drop the single-interface loopback mode Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 03/13] selftests/bpf: drop the test_progs AF_XDP wrapper Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 04/13] selftests: net: add a generic rule for BPF skeletons Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 05/13] selftests: xsk: move the AF_XDP test suite to selftests/net Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 06/13] selftests: xsk: collect interface capabilities in struct xsk_caps Maciej Fijalkowski
2026-10-01 20:21 ` Maciej Fijalkowski [this message]
2026-10-01 20:21 ` [PATCH net-next 08/13] selftests: xsk: run one test case per xskxceiver invocation Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 09/13] selftests: xsk: run the RX and TX endpoints in separate processes Maciej Fijalkowski
2026-10-02 18:07 ` Vyavahare, Tushar
2026-10-01 20:21 ` [PATCH net-next 10/13] selftests: xsk: add a hardware mode to xskxceiver Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 11/13] selftests: xsk: share test case definitions with hardware runner Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 12/13] selftests: drv-net: test AF_XDP zero-copy with an SKB peer Maciej Fijalkowski
2026-10-01 20:21 ` [PATCH net-next 13/13] selftests: xsk: document generic and hardware endpoint runs Maciej Fijalkowski
2026-10-05 18:06 ` [PATCH net-next 00/13] selftests: net: migrate AF_XDP test suite over to net Stanislav Fomichev
2026-10-06 17:42 ` Maciej Fijalkowski
2026-10-06 22:04 ` Stanislav Fomichev
2026-10-07 12:22 ` Maciej Fijalkowski
2026-10-07 17:26 ` Stanislav Fomichev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261001202124.692591-8-maciej.fijalkowski@intel.com \
--to=maciej.fijalkowski@intel.com \
--cc=bjorn@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=kerneljasonxing@gmail.com \
--cc=kuba@kernel.org \
--cc=magnus.karlsson@intel.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stfomichev@gmail.com \
--cc=tushar.vyavahare@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox