From: Tariq Toukan <tariqt@nvidia.com>
To: Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, <netdev@vger.kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
Sabrina Dubroca <sd@queasysnail.net>
Cc: Aleksandr Loktionov <aleksandr.loktionov@intel.com>,
Alexei Lazar <alazar@nvidia.com>,
Boris Pismenny <borisp@nvidia.com>,
Carolina Jubran <cjubran@nvidia.com>, Chris Mi <cmi@nvidia.com>,
Cosmin Ratiu <cratiu@nvidia.com>,
Daniel Zahka <daniel.zahka@gmail.com>,
Doruk Tan Ozturk <doruk@0sec.ai>,
Dragos Tatulea <dtatulea@nvidia.com>,
Gal Pressman <gal@nvidia.com>,
Jacob Keller <Jacob.e.keller@intel.com>,
Jianbo Liu <jianbol@nvidia.com>, Kees Cook <kees@kernel.org>,
Lama Kayal <lkayal@nvidia.com>, Leon Romanovsky <leon@kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-kselftest@vger.kernel.org>,
<linux-rdma@vger.kernel.org>, Mark Bloch <mbloch@nvidia.com>,
"Patrisious Haddad" <phaddad@nvidia.com>,
Raed Salem <raeds@nvidia.com>,
Rahul Rameshbabu <rrameshbabu@nvidia.com>,
Saeed Mahameed <saeedm@nvidia.com>, Shuah Khan <shuah@kernel.org>,
Shuah Khan <skhan@linuxfoundation.org>,
Simon Horman <horms@kernel.org>,
Stanislav Fomichev <sdf@fomichev.me>,
Stanislav Fomichev <sdf.kernel@gmail.com>,
Tariq Toukan <tariqt@nvidia.com>
Subject: [PATCH net-next 12/12] net: psp: Add a self test for PSP with HW-GRO
Date: Thu, 30 Jul 2026 12:17:54 +0300 [thread overview]
Message-ID: <20260730091756.2543777-13-tariqt@nvidia.com> (raw)
In-Reply-To: <20260730091756.2543777-1-tariqt@nvidia.com>
From: Cosmin Ratiu <cratiu@nvidia.com>
Add a test case which attempts to send several 64K chunks over PSP,
which is more than MTU, and thus trigger GSO on the TX side and
hopefully HW GRO on the RX side. Verify HW GRO counters increase.
This required the addition of a new command in the psp responder, so it
sends the data in order to get it reassembled on the local (DUT) side.
This is required in order to read the qstats.
Some light refactoring of the PSP responder was also done, because the
number of indentation levels started making checkpack unhappy.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
tools/testing/selftests/drivers/net/psp.py | 129 ++++++++++++++++--
.../selftests/drivers/net/psp_responder.c | 51 +++++++
2 files changed, 172 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index 315648a770d0..7ac13df6d59d 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -18,9 +18,10 @@ from lib.py import ksft_not_none
from lib.py import ksft_variants, KsftNamedVariant
from lib.py import KsftSkipEx, KsftFailEx
from lib.py import NetDrvEpEnv, NetDrvContEnv
-from lib.py import Netlink, NlError, PSPFamily, RtnlFamily
+from lib.py import Netlink, NlError, NetdevFamily, PSPFamily, RtnlFamily
from lib.py import NetNSEnter
from lib.py import bkg, rand_port, wait_port_listen
+from lib.py import bkg, ethtool, rand_port, wait_port_listen, CmdExitFailure
from lib.py import ip
@@ -30,15 +31,25 @@ def _get_outq(s):
return struct.unpack("I", outq)[0]
+def _recv_exact(sock, n):
+ buf = b''
+ while len(buf) < n:
+ chunk = sock.recv(n - len(buf))
+ if not chunk:
+ break
+ buf += chunk
+ return buf
+
+
def _send_with_ack(cfg, msg):
- cfg.comm_sock.send(msg)
- response = cfg.comm_sock.recv(4)
+ cfg.comm_sock.sendall(msg)
+ response = _recv_exact(cfg.comm_sock, 4)
if response != b'ack\0':
raise RuntimeError("Unexpected server response", response)
def _remote_read_len(cfg):
- cfg.comm_sock.send(b'read len\0')
+ cfg.comm_sock.sendall(b'read len\0')
return int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))
@@ -97,7 +108,7 @@ def _send_careful(cfg, s, rounds):
def _check_data_rx(cfg, exp_len):
read_len = -1
for _ in range(30):
- cfg.comm_sock.send(b'read len\0')
+ cfg.comm_sock.sendall(b'read len\0')
read_len = int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))
if read_len == exp_len:
break
@@ -583,6 +594,108 @@ def _get_psp_ver_ip_variants():
for ipv in ("4", "6"):
yield KsftNamedVariant(f"v{ver}_ip{ipv}", ver, ipv)
+def _enable_local_hw_gro(cfg):
+ cfg.require_cmd("ethtool")
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ gro = feat.get("rx-gro-hw")
+ if not gro or "active" not in gro or "fixed" not in gro:
+ raise KsftSkipEx("HW GRO feature not reported by ethtool")
+ if gro["fixed"] and not gro["active"]:
+ raise KsftSkipEx("HW GRO not supported by device")
+ if not gro["active"]:
+ try:
+ ethtool(f"-K {cfg.ifname} rx-gro-hw on")
+ except CmdExitFailure as e:
+ raise KsftSkipEx("Cannot enable HW GRO via ethtool") from e
+ defer(ethtool, f"-K {cfg.ifname} rx-gro-hw off")
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ gro = feat.get("rx-gro-hw", {})
+ if not gro.get("active"):
+ raise KsftSkipEx("HW GRO failed to activate")
+
+
+def _remote_send(cfg, size):
+ cfg.comm_sock.sendall(b'data send\0' + struct.pack('I', size))
+ response = _recv_exact(cfg.comm_sock, 4)
+ if response != b'ack\0':
+ raise RuntimeError("Unexpected server response to data send", response)
+
+
+def _recv_all(s, expected, timeout=20):
+ s.settimeout(timeout)
+ total = 0
+ try:
+ while total < expected:
+ data = s.recv(min(65536, expected - total))
+ if not data:
+ break
+ total += len(data)
+ except socket.timeout:
+ raise RuntimeError(
+ f"Timed out receiving data: got {total}/{expected} bytes "
+ f"(responder may have failed to send)")
+ if total < expected:
+ raise RuntimeError(
+ f"Short read: got {total}/{expected} bytes "
+ f"(responder connection closed early)")
+ return total
+
+
+def _data_hw_gro(cfg, version, ipver):
+ """ Test PSP data transfer with HW GRO enabled """
+ _init_psp_dev(cfg)
+ # Version 0 is required by spec, don't let it skip
+ if version:
+ name = cfg.pspnl.consts["version"].entries_by_val[version].name
+ if name not in cfg.psp_info['psp-versions-cap']:
+ raise KsftSkipEx("PSP version not supported", name)
+
+ _enable_local_hw_gro(cfg)
+
+ s = _make_psp_conn(cfg, version, ipver)
+ try:
+ rx_assoc = cfg.pspnl.rx_assoc({"version": version,
+ "dev-id": cfg.psp_dev_id,
+ "sock-fd": s.fileno()})
+ rx = rx_assoc['rx-key']
+ tx = _spi_xchg(s, rx)
+ cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id,
+ "version": version,
+ "tx-key": tx,
+ "sock-fd": s.fileno()})
+
+ try:
+ before = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
+ except NlError as e:
+ if e.error == errno.EOPNOTSUPP:
+ raise KsftSkipEx("qstats not supported by the device") from e
+ raise
+ if ('rx-hw-gro-packets' not in before or
+ 'rx-hw-gro-wire-packets' not in before):
+ raise KsftSkipEx("rx-hw-gro-packets counter not available")
+
+ # Remote sends data in 8KB chunks; GSO on remote TX segments them,
+ # HW GRO reassembles on local RX
+ data_len = 10 * 65536
+ _remote_send(cfg, data_len)
+ recv_len = _recv_all(s, data_len)
+ ksft_eq(recv_len, data_len)
+
+ cfg.wait_hw_stats_settle()
+ after = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
+ ksft_gt(after['rx-hw-gro-packets'],
+ before['rx-hw-gro-packets'])
+ ksft_gt(after['rx-hw-gro-wire-packets'],
+ before['rx-hw-gro-wire-packets'])
+ finally:
+ _close_psp_conn(cfg, s)
+
+@ksft_variants(_get_psp_ver_ip_variants())
+def data_hw_gro(cfg, version, ipver):
+ """ Test PSP data transfer with HW GRO enabled """
+ cfg.require_ipver(ipver)
+ _data_hw_gro(cfg, version, ipver)
+
def _get_ip_variants():
for ipv in ("4", "6"):
@@ -937,7 +1050,6 @@ def _setup_psp_attributes(cfg):
cfg.psp_dev_peer_nsid = _get_nsid(cfg.netns.name)
-
def main() -> None:
""" Ksft boiler plate main """
@@ -954,6 +1066,7 @@ def main() -> None:
with env as cfg:
cfg.pspnl = PSPFamily()
+ cfg.netnl = NetdevFamily()
if has_cont:
_setup_psp_attributes(cfg)
@@ -973,7 +1086,7 @@ def main() -> None:
cfg.comm_port),
timeout=1)
- cases = [data_basic_send, data_mss_adjust]
+ cases = [data_basic_send, data_hw_gro, data_mss_adjust]
if has_cont:
cases += [
@@ -990,7 +1103,7 @@ def main() -> None:
case_pfx={"dev_", "data_", "assoc_", "removal_"},
args=(cfg, ))
- cfg.comm_sock.send(b"exit\0")
+ cfg.comm_sock.sendall(b"exit\0")
cfg.comm_sock.close()
finally:
if srv and (srv.stdout or srv.stderr):
diff --git a/tools/testing/selftests/drivers/net/psp_responder.c b/tools/testing/selftests/drivers/net/psp_responder.c
index a26e7628bbb1..90f09c1f6984 100644
--- a/tools/testing/selftests/drivers/net/psp_responder.c
+++ b/tools/testing/selftests/drivers/net/psp_responder.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/poll.h>
@@ -118,6 +119,34 @@ static void send_str(int sock, int value)
send(sock, buf, ret + 1, MSG_WAITALL);
}
+static int send_data(int sock, size_t len)
+{
+ char sbuf[8192] = {0};
+ ssize_t sent;
+
+ while (len > 0) {
+ size_t chunk = len;
+
+ if (chunk > sizeof(sbuf))
+ chunk = sizeof(sbuf);
+
+ sent = send(sock, sbuf, chunk, MSG_NOSIGNAL);
+ if (sent < 0) {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "ERR: %s: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+ if (sent == 0) {
+ fprintf(stderr, "ERR: %s: peer closed\n", __func__);
+ return -1;
+ }
+ len -= sent;
+ }
+ return 0;
+}
+
static void
run_session(struct ynl_sock *ys, struct opts *opts,
int server_sock, int comm_sock)
@@ -224,6 +253,28 @@ run_session(struct ynl_sock *ys, struct opts *opts,
fprintf(stderr, "WARN: echo but no data sock\n");
send_ack(comm_sock);
}
+ if (cmd("data send")) {
+ __u32 len;
+
+ if (data_sock < 0) {
+ fprintf(stderr, "WARN: send but no data sock\n");
+ send_err(comm_sock);
+ continue;
+ }
+
+ if (off < 4) {
+ fprintf(stderr, "WARN: short data send command!\n");
+ send_err(comm_sock);
+ continue;
+ }
+ memcpy(&len, buf, sizeof(len));
+ __consume(sizeof(len));
+ send_ack(comm_sock);
+ if (send_data(data_sock, len))
+ fprintf(stderr,
+ "WARN: send incomplete for %u bytes\n",
+ len);
+ }
if (cmd("data close")) {
if (data_sock >= 0) {
close(data_sock);
--
2.44.0
next prev parent reply other threads:[~2026-07-30 9:20 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 9:17 [PATCH net-next 00/13] net/mlx5e: Add support for HW-GRO to PSP Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 01/13] net/mlx5e: Generalize TC <-> IPsec mutual exclusion Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 02/13] net/mlx5e: ipsec: Block TC offload when IPsec is enabled Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 03/13] net/mlx5e: psp: Block TC offload when PSP " Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 04/13] net/mlx5e: macsec: Block TC offload when MACsec " Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 05/13] net/mlx5e: psp: Move RX marker from ft_metadata to flow_tag Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 06/13] net/mlx5e: ipsec: " Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 07/13] net/mlx5e: macsec: " Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 08/13] net/mlx5e: psp: Handle HW-decapsulated RX PSP packets Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 09/13] net/mlx5e: psp: Add an rx_decap steering table Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 10/13] net/mlx5e: shampo: Flush session on PSP mismatch Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 11/13] net/mlx5e: psp: Dynamically reconfigure based on SHAMPO mode Tariq Toukan
2026-07-30 9:17 ` Tariq Toukan [this message]
2026-07-30 9:58 ` [PATCH net-next 12/12] net: psp: Add a self test for PSP with HW-GRO Tariq Toukan
2026-07-30 20:13 ` Jakub Kicinski
2026-07-30 9:17 ` [PATCH net-next 12/13] selftests: drv-net: psp: Fix responder parsing Tariq Toukan
2026-07-30 9:17 ` [PATCH net-next 13/13] selftests: drv-net: psp: Add a test for PSP with HW-GRO Tariq Toukan
2026-07-31 1:53 ` 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=20260730091756.2543777-13-tariqt@nvidia.com \
--to=tariqt@nvidia.com \
--cc=Jacob.e.keller@intel.com \
--cc=alazar@nvidia.com \
--cc=aleksandr.loktionov@intel.com \
--cc=andrew+netdev@lunn.ch \
--cc=borisp@nvidia.com \
--cc=cjubran@nvidia.com \
--cc=cmi@nvidia.com \
--cc=cratiu@nvidia.com \
--cc=daniel.zahka@gmail.com \
--cc=davem@davemloft.net \
--cc=doruk@0sec.ai \
--cc=dtatulea@nvidia.com \
--cc=edumazet@google.com \
--cc=gal@nvidia.com \
--cc=horms@kernel.org \
--cc=jianbol@nvidia.com \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=lkayal@nvidia.com \
--cc=mbloch@nvidia.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=phaddad@nvidia.com \
--cc=raeds@nvidia.com \
--cc=rrameshbabu@nvidia.com \
--cc=saeedm@nvidia.com \
--cc=sd@queasysnail.net \
--cc=sdf.kernel@gmail.com \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=skhan@linuxfoundation.org \
/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