[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251104-scratch-bobbyeshleman-devmem-tcp-token-upstream-v6-6-ea98cf4d40b3@meta.com>
Date: Tue, 04 Nov 2025 17:23:25 -0800
From: Bobby Eshleman <bobbyeshleman@...il.com>
To: "David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>,
Kuniyuki Iwashima <kuniyu@...gle.com>,
Willem de Bruijn <willemb@...gle.com>, Neal Cardwell <ncardwell@...gle.com>,
David Ahern <dsahern@...nel.org>, Arnd Bergmann <arnd@...db.de>,
Jonathan Corbet <corbet@....net>, Andrew Lunn <andrew+netdev@...n.ch>,
Shuah Khan <shuah@...nel.org>, Mina Almasry <almasrymina@...gle.com>
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-arch@...r.kernel.org, linux-doc@...r.kernel.org,
linux-kselftest@...r.kernel.org, Stanislav Fomichev <sdf@...ichev.me>,
Bobby Eshleman <bobbyeshleman@...a.com>
Subject: [PATCH net-next v6 6/6] net: devmem: add tests for
SO_DEVMEM_AUTORELEASE socket option
From: Bobby Eshleman <bobbyeshleman@...a.com>
Add -A flag to ncdevmem to set autorelease mode.
Add tests for the SO_DEVMEM_AUTORELEASE socket option:
New tests include:
- check_sockopt_autorelease_default: Verifies default value is 0
- check_sockopt_autorelease_set_0: Tests setting to 0 and reading
back
- check_sockopt_autorelease_set_1: Tests toggling from 0 to 1
- check_sockopt_autorelease_invalid: Tests invalid value (2) returns
EINVAL
- check_autorelease_disabled: Tests ncdevmem in manual token release
mode
- check_autorelease_enabled: Tests ncdevmem in autorelease mode
All check_sockopt tests gracefully skip with KsftSkipEx if
SO_DEVMEM_AUTORELEASE is not supported by the kernel.
Signed-off-by: Bobby Eshleman <bobbyeshleman@...a.com>
---
tools/testing/selftests/drivers/net/hw/devmem.py | 115 +++++++++++++++++++++-
tools/testing/selftests/drivers/net/hw/ncdevmem.c | 20 +++-
2 files changed, 133 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/devmem.py b/tools/testing/selftests/drivers/net/hw/devmem.py
index 45c2d49d55b6..29ec179d651f 100755
--- a/tools/testing/selftests/drivers/net/hw/devmem.py
+++ b/tools/testing/selftests/drivers/net/hw/devmem.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
+import socket
+import errno
+
from os import path
from lib.py import ksft_run, ksft_exit
from lib.py import ksft_eq, KsftSkipEx
@@ -63,12 +66,122 @@ def check_tx_chunks(cfg) -> None:
ksft_eq(socat.stdout.strip(), "hello\nworld")
+@...t_disruptive
+def check_autorelease_disabled(cfg) -> None:
+ """Test RX with autorelease disabled (requires manual token release in ncdevmem)"""
+ require_devmem(cfg)
+
+ port = rand_port()
+ socat = f"socat -u - TCP{cfg.addr_ipver}:{cfg.baddr}:{port},bind={cfg.remote_baddr}:{port}"
+ listen_cmd = f"{cfg.bin_local} -l -f {cfg.ifname} -s {cfg.addr} -p {port} -c {cfg.remote_addr} -v 7 -A 0"
+
+ with bkg(listen_cmd, exit_wait=True) as ncdevmem:
+ wait_port_listen(port)
+ cmd(f"yes $(echo -e \x01\x02\x03\x04\x05\x06) | \
+ head -c 1K | {socat}", host=cfg.remote, shell=True)
+
+ ksft_eq(ncdevmem.ret, 0)
+
+
+@...t_disruptive
+def check_autorelease_enabled(cfg) -> None:
+ """Test RX with autorelease enabled (requires token autorelease in ncdevmem)"""
+ require_devmem(cfg)
+
+ port = rand_port()
+ socat = f"socat -u - TCP{cfg.addr_ipver}:{cfg.baddr}:{port},bind={cfg.remote_baddr}:{port}"
+ listen_cmd = f"{cfg.bin_local} -l -f {cfg.ifname} -s {cfg.addr} -p {port} -c {cfg.remote_addr} -v 7 -A 1"
+
+ with bkg(listen_cmd, exit_wait=True) as ncdevmem:
+ wait_port_listen(port)
+ cmd(f"yes $(echo -e \x01\x02\x03\x04\x05\x06) | \
+ head -c 1K | {socat}", host=cfg.remote, shell=True)
+
+ ksft_eq(ncdevmem.ret, 0)
+
+
+def check_sockopt_autorelease_default(cfg) -> None:
+ """Test that SO_DEVMEM_AUTORELEASE default is 0"""
+ SO_DEVMEM_AUTORELEASE = 85
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ val = sock.getsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE)
+ ksft_eq(val, 0, "Default autorelease should be 0")
+ except OSError as e:
+ if e.errno == errno.ENOPROTOOPT:
+ raise KsftSkipEx("SO_DEVMEM_AUTORELEASE not supported")
+ raise
+ finally:
+ sock.close()
+
+
+def check_sockopt_autorelease_set_0(cfg) -> None:
+ """Test setting SO_DEVMEM_AUTORELEASE to 0"""
+ SO_DEVMEM_AUTORELEASE = 85
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ sock.setsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE, 0)
+ val = sock.getsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE)
+ ksft_eq(val, 0, "Autorelease should be 0 after setting")
+ except OSError as e:
+ if e.errno == errno.ENOPROTOOPT:
+ raise KsftSkipEx("SO_DEVMEM_AUTORELEASE not supported")
+ raise
+ finally:
+ sock.close()
+
+
+def check_sockopt_autorelease_set_1(cfg) -> None:
+ """Test setting SO_DEVMEM_AUTORELEASE to 1"""
+ SO_DEVMEM_AUTORELEASE = 85
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ # First set to 0
+ sock.setsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE, 0)
+ # Then set back to 1
+ sock.setsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE, 1)
+ val = sock.getsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE)
+ ksft_eq(val, 1, "Autorelease should be 1 after setting")
+ except OSError as e:
+ if e.errno == errno.ENOPROTOOPT:
+ raise KsftSkipEx("SO_DEVMEM_AUTORELEASE not supported")
+ raise
+ finally:
+ sock.close()
+
+
+def check_sockopt_autorelease_invalid(cfg) -> None:
+ """Test that SO_DEVMEM_AUTORELEASE rejects invalid values"""
+ SO_DEVMEM_AUTORELEASE = 85
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ try:
+ sock.setsockopt(socket.SOL_SOCKET, SO_DEVMEM_AUTORELEASE, 2)
+ raise Exception("setsockopt should have failed with EINVAL")
+ except OSError as e:
+ if e.errno == errno.ENOPROTOOPT:
+ raise KsftSkipEx("SO_DEVMEM_AUTORELEASE not supported")
+ ksft_eq(e.errno, errno.EINVAL, "Should fail with EINVAL for invalid value")
+ finally:
+ sock.close()
+
+
def main() -> None:
with NetDrvEpEnv(__file__) as cfg:
cfg.bin_local = path.abspath(path.dirname(__file__) + "/ncdevmem")
cfg.bin_remote = cfg.remote.deploy(cfg.bin_local)
- ksft_run([check_rx, check_tx, check_tx_chunks],
+ ksft_run([check_rx, check_tx, check_tx_chunks,
+ check_autorelease_enabled,
+ check_autorelease_disabled,
+ check_sockopt_autorelease_default,
+ check_sockopt_autorelease_set_0,
+ check_sockopt_autorelease_set_1,
+ check_sockopt_autorelease_invalid],
args=(cfg, ))
ksft_exit()
diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
index 3288ed04ce08..34d608d07bec 100644
--- a/tools/testing/selftests/drivers/net/hw/ncdevmem.c
+++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
@@ -83,6 +83,10 @@
#define MSG_SOCK_DEVMEM 0x2000000
#endif
+#ifndef SO_DEVMEM_AUTORELEASE
+#define SO_DEVMEM_AUTORELEASE 85
+#endif
+
#define MAX_IOV 1024
static size_t max_chunk;
@@ -97,6 +101,7 @@ static unsigned int ifindex;
static unsigned int dmabuf_id;
static uint32_t tx_dmabuf_id;
static int waittime_ms = 500;
+static int autorelease = -1;
/* System state loaded by current_config_load() */
#define MAX_FLOWS 8
@@ -890,6 +895,16 @@ static int do_server(struct memory_buffer *mem)
if (enable_reuseaddr(socket_fd))
goto err_close_socket;
+ if (autorelease >= 0) {
+ ret = setsockopt(socket_fd, SOL_SOCKET, SO_DEVMEM_AUTORELEASE,
+ &autorelease, sizeof(autorelease));
+ if (ret) {
+ pr_err("SO_DEVMEM_AUTORELEASE failed");
+ goto err_close_socket;
+ }
+ fprintf(stderr, "Set SO_DEVMEM_AUTORELEASE to %d\n", autorelease);
+ }
+
fprintf(stderr, "binding to address %s:%d\n", server_ip,
ntohs(server_sin.sin6_port));
@@ -1397,7 +1412,7 @@ int main(int argc, char *argv[])
int is_server = 0, opt;
int ret, err = 1;
- while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:z:")) != -1) {
+ while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:z:A:")) != -1) {
switch (opt) {
case 'l':
is_server = 1;
@@ -1426,6 +1441,9 @@ int main(int argc, char *argv[])
case 'z':
max_chunk = atoi(optarg);
break;
+ case 'A':
+ autorelease = atoi(optarg);
+ break;
case '?':
fprintf(stderr, "unknown option: %c\n", optopt);
break;
--
2.47.3
Powered by blists - more mailing lists