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 v4 net-next 07/15] selftests: xsk: collect interface capabilities in struct xsk_caps
Date: Fri, 16 Oct 2026 19:43:30 +0200 [thread overview]
Message-ID: <20261016174338.787135-8-maciej.fijalkowski@intel.com> (raw)
In-Reply-To: <20261016174338.787135-1-maciej.fijalkowski@intel.com>
A later patch runs the TX and RX endpoints of a case as separate
processes, possibly on different hosts, each binding only its own
interface. The shared test code still looks at the capabilities of both
ifobjects, e.g. to check both for multi-buffer support or to size the
RX batch from the TX ring limit. As the endpoints do not exchange
capabilities, a process will represent the other side by a shadow
ifobject that mirrors the local ones.
Prepare for that by replacing the per-interface support booleans and
limits in struct ifobject with one struct xsk_caps, so that mirroring
takes a single struct assignment and a capability added later cannot
be left out of the copy. The maximum TX ring size, which comes from the
ethtool ring parameters that a shadow does not mirror, is copied there
too. ifobj_has_cap() and ifobj_set_cap() test and set the flags, and
xsk_get_cap() reads a limit from the TX ifobject, the only one that has
all of them set, as the open-coded reads did.
Reviewed-by: Björn Töpel <bjorn@kernel.org>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
.../testing/selftests/net/lib/xsk/test_xsk.c | 82 +++++++++++--------
.../testing/selftests/net/lib/xsk/test_xsk.h | 34 ++++++--
.../selftests/net/lib/xsk/xskxceiver.c | 14 ++--
3 files changed, 82 insertions(+), 48 deletions(-)
diff --git a/tools/testing/selftests/net/lib/xsk/test_xsk.c b/tools/testing/selftests/net/lib/xsk/test_xsk.c
index 63267d886b17..edb1feb54c54 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.c
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.c
@@ -1743,20 +1743,24 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i
struct ifobject *ifobj2)
{
pthread_t t0, t1;
+ u32 mbuf_cap;
int err;
- if (test->mtu > MAX_ETH_PKT_SIZE) {
- if (test->mode == TEST_MODE_ZC && (!ifobj1->multi_buff_zc_supp ||
- (ifobj2 && !ifobj2->multi_buff_zc_supp))) {
- ksft_print_msg("Multi buffer for zero-copy not supported.\n");
- return TEST_SKIP;
- }
- if (test->mode != TEST_MODE_ZC && (!ifobj1->multi_buff_supp ||
- (ifobj2 && !ifobj2->multi_buff_supp))) {
- ksft_print_msg("Multi buffer not supported.\n");
- return TEST_SKIP;
- }
+ if (test->mtu <= MAX_ETH_PKT_SIZE)
+ goto skip_mbuf_check;
+
+ mbuf_cap = test->mode == TEST_MODE_ZC ? XSK_CAP_MBUF_ZC :
+ XSK_CAP_MBUF;
+
+ if (!ifobj_has_cap(ifobj1, mbuf_cap) ||
+ (ifobj2 && !ifobj_has_cap(ifobj2, mbuf_cap))) {
+ ksft_print_msg("Multi buffer%s not supported.\n",
+ mbuf_cap == XSK_CAP_MBUF_ZC ?
+ " for zero-copy" : "");
+ return TEST_SKIP;
}
+
+skip_mbuf_check:
err = test_spec_set_mtu(test, test->mtu);
if (err) {
ksft_print_msg("Error, could not set mtu.\n");
@@ -1821,8 +1825,10 @@ static int testapp_validate_traffic(struct test_spec *test)
struct ifobject *ifobj_rx = test->ifobj_rx;
struct ifobject *ifobj_tx = test->ifobj_tx;
- if ((ifobj_rx->xsk->umem->unaligned_mode && !ifobj_rx->unaligned_supp) ||
- (ifobj_tx->xsk->umem->unaligned_mode && !ifobj_tx->unaligned_supp)) {
+ if ((ifobj_rx->xsk->umem->unaligned_mode &&
+ !ifobj_has_cap(ifobj_rx, XSK_CAP_UNALIGNED)) ||
+ (ifobj_tx->xsk->umem->unaligned_mode &&
+ !ifobj_has_cap(ifobj_tx, XSK_CAP_UNALIGNED))) {
ksft_print_msg("No huge pages present.\n");
return TEST_SKIP;
}
@@ -1922,7 +1928,7 @@ int testapp_headroom(struct test_spec *test)
int testapp_stats_rx_dropped(struct test_spec *test)
{
struct xsk_umem_info *umem = test->ifobj_rx->xsk->umem;
- u32 umem_tr = test->ifobj_tx->umem_tailroom;
+ u32 umem_tr = xsk_get_cap(test, umem_tailroom);
if (test->mode == TEST_MODE_ZC) {
ksft_print_msg("Can not run RX_DROPPED test for ZC mode\n");
@@ -2184,9 +2190,9 @@ int testapp_too_many_frags(struct test_spec *test)
int ret = TEST_FAILURE;
if (test->mode == TEST_MODE_ZC) {
- max_frags = test->ifobj_tx->xdp_zc_max_segs;
+ max_frags = xsk_get_cap(test, xdp_zc_max_segs);
} else {
- max_frags = test->ifobj_tx->max_skb_frags;
+ max_frags = xsk_get_cap(test, max_skb_frags);
max_frags += 1;
}
@@ -2246,7 +2252,6 @@ static int xsk_load_xdp_programs(struct ifobject *ifobj)
return 0;
}
-/* Simple test */
static bool hugepages_present(void)
{
size_t mmap_sz = 2 * DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE;
@@ -2262,21 +2267,13 @@ static bool hugepages_present(void)
return true;
}
-int init_iface(struct ifobject *ifobj, thread_func_t func_ptr)
+static int detect_ifobj_caps(struct ifobject *ifobj)
{
LIBBPF_OPTS(bpf_xdp_query_opts, query_opts);
int err;
- ifobj->func_ptr = func_ptr;
-
- err = xsk_load_xdp_programs(ifobj);
- if (err) {
- ksft_print_msg("Error loading XDP program\n");
- return err;
- }
-
if (hugepages_present())
- ifobj->unaligned_supp = true;
+ ifobj_set_cap(ifobj, XSK_CAP_UNALIGNED);
err = bpf_xdp_query(ifobj->ifindex, XDP_FLAGS_DRV_MODE, &query_opts);
if (err) {
@@ -2284,19 +2281,34 @@ int init_iface(struct ifobject *ifobj, thread_func_t func_ptr)
return err;
}
if (query_opts.feature_flags & NETDEV_XDP_ACT_RX_SG)
- ifobj->multi_buff_supp = true;
+ ifobj_set_cap(ifobj, XSK_CAP_MBUF);
if (query_opts.feature_flags & NETDEV_XDP_ACT_XSK_ZEROCOPY) {
if (query_opts.xdp_zc_max_segs > 1) {
- ifobj->multi_buff_zc_supp = true;
- ifobj->xdp_zc_max_segs = query_opts.xdp_zc_max_segs;
+ ifobj_set_cap(ifobj, XSK_CAP_MBUF_ZC);
+ ifobj->caps.xdp_zc_max_segs = query_opts.xdp_zc_max_segs;
} else {
- ifobj->xdp_zc_max_segs = 0;
+ ifobj->caps.xdp_zc_max_segs = 0;
}
}
return 0;
}
+int init_iface(struct ifobject *ifobj, thread_func_t func_ptr)
+{
+ int err;
+
+ ifobj->func_ptr = func_ptr;
+
+ err = xsk_load_xdp_programs(ifobj);
+ if (err) {
+ ksft_print_msg("Error loading XDP program\n");
+ return err;
+ }
+
+ return detect_ifobj_caps(ifobj);
+}
+
int testapp_send_receive(struct test_spec *test)
{
return testapp_validate_traffic(test);
@@ -2386,7 +2398,7 @@ int testapp_hw_sw_min_ring_size(struct test_spec *test)
{
int ret;
- if (!test->ifobj_tx->hw_ring_size_supp) {
+ if (!ifobj_has_cap(test->ifobj_tx, XSK_CAP_HW_RING)) {
ksft_print_msg("HW ring sizes not supported.\n");
return TEST_SKIP;
}
@@ -2413,7 +2425,7 @@ int testapp_hw_sw_max_ring_size(struct test_spec *test)
u32 batch_size;
int ret;
- if (!test->ifobj_tx->hw_ring_size_supp) {
+ if (!ifobj_has_cap(test->ifobj_tx, XSK_CAP_HW_RING)) {
ksft_print_msg("HW ring sizes not supported.\n");
return TEST_SKIP;
}
@@ -2436,7 +2448,7 @@ int testapp_hw_sw_max_ring_size(struct test_spec *test)
* updating the Rx HW tail register. __send_pkts() waits until a whole batch fits
* in the XSK TX ring, so keep it below that ring's size on NICs with larger rings.
*/
- batch_size = min(test->ifobj_tx->ring.tx_max_pending, max_descs) - 8;
+ batch_size = min(xsk_get_cap(test, tx_max_pending), max_descs) - 8;
test->ifobj_tx->xsk->batch_size = batch_size;
test->ifobj_rx->xsk->batch_size = batch_size;
if (pkt_stream_replace(test, max_descs, MIN_PKT_SIZE)) {
@@ -2531,7 +2543,7 @@ int testapp_adjust_tail_grow_mb(struct test_spec *test)
grow_size = XSK_UMEM__MAX_FRAME_SIZE -
XSK_UMEM__LARGE_FRAME_SIZE -
XDP_PACKET_HEADROOM -
- test->ifobj_tx->umem_tailroom;
+ xsk_get_cap(test, umem_tailroom);
test->mtu = MAX_ETH_JUMBO_SIZE;
return testapp_adjust_tail(test, grow_size, XSK_UMEM__LARGE_FRAME_SIZE * 2);
diff --git a/tools/testing/selftests/net/lib/xsk/test_xsk.h b/tools/testing/selftests/net/lib/xsk/test_xsk.h
index 410702f89dc9..716ea044797c 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.h
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.h
@@ -112,8 +112,22 @@ struct xsk_umem_info {
bool unaligned_mode;
};
+#define XSK_CAP_UNALIGNED (1U << 0)
+#define XSK_CAP_MBUF (1U << 1)
+#define XSK_CAP_MBUF_ZC (1U << 2)
+#define XSK_CAP_HW_RING (1U << 3)
+
+struct xsk_caps {
+ u32 flags;
+ u32 xdp_zc_max_segs;
+ u32 max_skb_frags;
+ u32 umem_tailroom;
+ u32 tx_max_pending;
+};
+
struct ifobject {
char ifname[MAX_INTERFACE_NAME_CHARS];
+ struct xsk_caps caps;
struct xsk_socket_info *xsk;
struct xsk_socket_info *xsk_arr;
thread_func_t func_ptr;
@@ -126,9 +140,6 @@ struct ifobject {
int ifindex;
int mtu;
u32 bind_flags;
- u32 xdp_zc_max_segs;
- u32 umem_tailroom;
- u32 max_skb_frags;
bool tx_on;
bool rx_on;
bool use_poll;
@@ -136,11 +147,20 @@ struct ifobject {
bool use_fill_ring;
bool release_rx;
bool use_metadata;
- bool unaligned_supp;
- bool multi_buff_supp;
- bool multi_buff_zc_supp;
- bool hw_ring_size_supp;
};
+
+static inline bool ifobj_has_cap(const struct ifobject *ifobj, u32 cap)
+{
+ return ifobj && (ifobj->caps.flags & cap);
+}
+
+static inline void ifobj_set_cap(struct ifobject *ifobj, u32 cap)
+{
+ ifobj->caps.flags |= cap;
+}
+
+#define xsk_get_cap(test, cap) ((test)->ifobj_tx->caps.cap)
+
struct ifobject *ifobject_create(void);
void ifobject_delete(struct ifobject *ifobj);
int init_iface(struct ifobject *ifobj, thread_func_t func_ptr);
diff --git a/tools/testing/selftests/net/lib/xsk/xskxceiver.c b/tools/testing/selftests/net/lib/xsk/xskxceiver.c
index 7876ad47ed0f..d82224a4fa4b 100644
--- a/tools/testing/selftests/net/lib/xsk/xskxceiver.c
+++ b/tools/testing/selftests/net/lib/xsk/xskxceiver.c
@@ -361,15 +361,15 @@ int main(int argc, char **argv)
ksft_print_msg("Can't get MAX_SKB_FRAGS from system, using default (17)\n");
max_frags = 17;
}
- ifobj_tx->max_skb_frags = max_frags;
- ifobj_rx->max_skb_frags = max_frags;
+ ifobj_tx->caps.max_skb_frags = max_frags;
+ ifobj_rx->caps.max_skb_frags = max_frags;
/* 48 bytes is a part of skb_shared_info w/o frags array;
* 16 bytes is sizeof(skb_frag_t)
*/
umem_tailroom = ALIGN(48 + (max_frags * 16), cache_line_size);
- ifobj_tx->umem_tailroom = umem_tailroom;
- ifobj_rx->umem_tailroom = umem_tailroom;
+ ifobj_tx->caps.umem_tailroom = umem_tailroom;
+ ifobj_rx->caps.umem_tailroom = umem_tailroom;
parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
@@ -392,8 +392,10 @@ int main(int argc, char **argv)
}
ret = get_hw_ring_size(ifobj_tx->ifname, &ifobj_tx->ring);
- if (!ret)
- ifobj_tx->hw_ring_size_supp = true;
+ if (!ret) {
+ ifobj_set_cap(ifobj_tx, XSK_CAP_HW_RING);
+ ifobj_tx->caps.tx_max_pending = ifobj_tx->ring.tx_max_pending;
+ }
if (init_iface(ifobj_rx, worker_testapp_validate_rx) ||
init_iface(ifobj_tx, worker_testapp_validate_tx)) {
--
2.43.0
next prev parent reply other threads:[~2026-10-16 17:44 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 17:43 [PATCH v4 net-next 00/15] selftests: net: migrate AF_XDP test suite over to net Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 01/15] selftests: xsk: factor endpoint work out of pthread wrappers Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 02/15] selftests: xsk: size the TX UMEM in HW_SW_MAX_RING_SIZE Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 03/15] selftests: xsk: drop the single-interface loopback mode Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 04/15] selftests/bpf: drop the test_progs AF_XDP wrapper Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 05/15] selftests: net: add a generic rule for BPF skeletons Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 06/15] selftests: xsk: move the AF_XDP test suite to selftests/net Maciej Fijalkowski
2026-10-16 17:43 ` Maciej Fijalkowski [this message]
2026-10-16 17:43 ` [PATCH v4 net-next 08/15] selftests: xsk: split xskxceiver main() into setup, run and cleanup Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 09/15] selftests: xsk: run one test case per xskxceiver invocation Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 10/15] selftests: xsk: run the RX and TX endpoints in separate processes Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 11/15] selftests: xsk: send UDP over IPv4 or IPv6 between the interface MACs Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 12/15] selftests: xsk: prepare xskxceiver for endpoints on two hosts Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 13/15] selftests: xsk: list the hardware test cases Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 14/15] selftests: drv-net: test AF_XDP zero-copy with an SKB peer Maciej Fijalkowski
2026-10-16 17:43 ` [PATCH v4 net-next 15/15] selftests: xsk: document generic and hardware endpoint runs Maciej Fijalkowski
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=20261016174338.787135-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