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 v2 net-next 06/14] selftests: xsk: collect interface capabilities in struct xsk_caps
Date: Thu, 8 Oct 2026 13:49:01 +0200 [thread overview]
Message-ID: <20261008114909.734364-7-maciej.fijalkowski@intel.com> (raw)
In-Reply-To: <20261008114909.734364-1-maciej.fijalkowski@intel.com>
A later patch runs the TX and RX endpoints of a test case as separate
processes, possibly on different hosts, and each process binds only its
own interface. The shared test code still looks at the capabilities of
both the TX and the RX ifobject, for instance when it checks both sides
for multi-buffer support or when it sizes the RX batch from the TX ring
limit. The endpoints do not exchange capabilities, so a process will
represent the other side by a shadow ifobject that mirrors the local
capabilities.
Prepare for that by replacing the per-interface support booleans and
limits in struct ifobject with one struct xsk_caps holding capability
flags and interface limits. Mirroring the local capabilities then takes
a single struct assignment, and a capability added later cannot be left
out of the copy. The maximum TX ring size is copied there from the
ethtool ring parameters, which a shadow does not mirror.
Add ifobj_has_cap() and ifobj_set_cap() to test and set the flags, and
xsk_get_cap() to read a limit. Like the open-coded reads it replaces,
xsk_get_cap() takes the limit from the TX ifobject, the only one that
has all of them set.
The unaligned UMEM check, which this patch rewrites anyway, now looks
at the RX ifobject only. The flag comes from a huge page probe that does
not depend on the interface, and test_spec_set_unaligned() switches
both UMEMs to unaligned mode together, so checking the TX side as well
adds nothing.
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
.../testing/selftests/net/lib/xsk/test_xsk.c | 84 +++++++++++--------
.../testing/selftests/net/lib/xsk/test_xsk.h | 34 ++++++--
.../selftests/net/lib/xsk/xskxceiver.c | 13 +--
3 files changed, 81 insertions(+), 50 deletions(-)
diff --git a/tools/testing/selftests/net/lib/xsk/test_xsk.c b/tools/testing/selftests/net/lib/xsk/test_xsk.c
index 237d9e076e10..22a81723d5de 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.c
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.c
@@ -244,7 +244,7 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
ifobj->xsk->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
}
- if (ifobj_tx->hw_ring_size_supp)
+ if (ifobj_has_cap(ifobj_tx, XSK_CAP_HW_RING))
hw_ring_size_reset(ifobj_tx);
test->ifobj_tx = ifobj_tx;
@@ -1774,20 +1774,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");
@@ -1852,14 +1856,14 @@ 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)) {
ksft_print_msg("No huge pages present.\n");
return TEST_SKIP;
}
if (test->set_ring) {
- if (ifobj_tx->hw_ring_size_supp) {
+ if (ifobj_has_cap(ifobj_tx, XSK_CAP_HW_RING)) {
if (set_ring_size(ifobj_tx)) {
ksft_print_msg("Failed to change HW ring size.\n");
return TEST_FAILURE;
@@ -1965,7 +1969,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");
@@ -2227,9 +2231,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;
}
@@ -2289,7 +2293,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;
@@ -2305,21 +2308,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) {
@@ -2327,19 +2322,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);
@@ -2449,7 +2459,7 @@ int testapp_hw_sw_max_ring_size(struct test_spec *test)
test->set_ring = true;
test->total_steps = 2;
- test->ifobj_tx->ring.tx_pending = test->ifobj_tx->ring.tx_max_pending;
+ test->ifobj_tx->ring.tx_pending = xsk_get_cap(test, tx_max_pending);
test->ifobj_tx->ring.rx_pending = test->ifobj_tx->ring.rx_max_pending;
test->ifobj_rx->xsk->umem->num_frames = max_descs;
test->ifobj_rx->xsk->umem->fill_size = max_descs;
@@ -2464,8 +2474,8 @@ int testapp_hw_sw_max_ring_size(struct test_spec *test)
/* Set batch_size to 8152 for testing, as the ice HW ignores the 3 lowest bits when
* updating the Rx HW tail register.
*/
- test->ifobj_tx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8;
- test->ifobj_rx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8;
+ test->ifobj_tx->xsk->batch_size = xsk_get_cap(test, tx_max_pending) - 8;
+ test->ifobj_rx->xsk->batch_size = xsk_get_cap(test, tx_max_pending) - 8;
if (pkt_stream_replace(test, max_descs, MIN_PKT_SIZE)) {
clean_sockets(test, test->ifobj_tx);
clean_sockets(test, test->ifobj_rx);
@@ -2558,7 +2568,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 0717d855e4df..1d17e214db91 100644
--- a/tools/testing/selftests/net/lib/xsk/test_xsk.h
+++ b/tools/testing/selftests/net/lib/xsk/test_xsk.h
@@ -119,8 +119,22 @@ struct set_hw_ring {
int hw_ring_size_reset(struct ifobject *ifobj);
+#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;
@@ -134,9 +148,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;
@@ -144,11 +155,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 f4a2f45a6752..8b3e4d18e982 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);
@@ -393,7 +393,8 @@ 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;
+ 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;
}
@@ -448,7 +449,7 @@ int main(int argc, char **argv)
}
}
- if (ifobj_tx->hw_ring_size_supp)
+ if (ifobj_has_cap(ifobj_tx, XSK_CAP_HW_RING))
hw_ring_size_reset(ifobj_tx);
pkt_stream_delete(tx_pkt_stream_default);
--
2.43.0
next prev parent reply other threads:[~2026-10-08 11:49 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 11:48 [PATCH v2 net-next 00/14] selftests: net: migrate AF_XDP test suite over to net Maciej Fijalkowski
2026-10-08 11:48 ` [PATCH v2 net-next 01/14] selftests: xsk: factor endpoint work out of pthread wrappers Maciej Fijalkowski
2026-10-08 11:48 ` [PATCH v2 net-next 02/14] selftests: xsk: drop the single-interface loopback mode Maciej Fijalkowski
2026-10-09 9:46 ` Björn Töpel
2026-10-08 11:48 ` [PATCH v2 net-next 03/14] selftests/bpf: drop the test_progs AF_XDP wrapper Maciej Fijalkowski
2026-10-08 11:48 ` [PATCH v2 net-next 04/14] selftests: net: add a generic rule for BPF skeletons Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 05/14] selftests: xsk: move the AF_XDP test suite to selftests/net Maciej Fijalkowski
2026-10-09 11:18 ` Björn Töpel
2026-10-08 11:49 ` Maciej Fijalkowski [this message]
2026-10-08 11:49 ` [PATCH v2 net-next 07/14] selftests: xsk: split xskxceiver main() into setup, run and cleanup Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 08/14] selftests: xsk: run one test case per xskxceiver invocation Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 09/14] selftests: xsk: run the RX and TX endpoints in separate processes Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 10/14] selftests: xsk: add a hardware mode to xskxceiver Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 11/14] selftests: xsk: pass non-test traffic to the stack in hardware mode Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 12/14] selftests: xsk: share test case definitions with hardware runner Maciej Fijalkowski
2026-10-08 11:49 ` [PATCH v2 net-next 13/14] selftests: drv-net: test AF_XDP zero-copy with an SKB peer Maciej Fijalkowski
2026-10-08 21:37 ` Jakub Kicinski
2026-10-08 11:49 ` [PATCH v2 net-next 14/14] selftests: xsk: document generic and hardware endpoint runs Maciej Fijalkowski
2026-10-08 21:41 ` Jakub Kicinski
2026-10-08 21:30 ` [PATCH v2 net-next 00/14] selftests: net: migrate AF_XDP test suite over to net Jakub Kicinski
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=20261008114909.734364-7-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