public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
@ 2026-03-02  5:55 Allison Henderson
  2026-03-02  5:55 ` [PATCH net-next v1 1/2] selftests: rds: Refactor test.py Allison Henderson
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Allison Henderson @ 2026-03-02  5:55 UTC (permalink / raw)
  To: netdev
  Cc: linux-kselftest, pabeni, edumazet, rds-devel, kuba, horms,
	linux-rdma, allison.henderson

Hi all,

This series aims to improve the current rds selftests.  The first patch
refactors the existing test.py such that the networking set up can be
reused as general purpose infrastructure for other tests.  The existing
send and receive code is hoisted into a separate rds_basic.py.  The next
patch adds a new rds_stress.py that exercises RDS via the external
rds-stress tool from the rds-tools package if it is available on the host.
We add two new flags to test.py, -b and -s to select rds_basic or
rds_stress respectively.  The intent is to make the RDS selftests more
modular and extensible.  Let me know what you all think.

Questions, comments, suggestions appreciated!
Thanks!

Allison

v1:
  - fixed pylint warnings

Allison Henderson (2):
  selftests: rds: Refactor test.py
  selftests: rds: Add rds_stress.py

 tools/testing/selftests/net/rds/Makefile      |   2 +
 tools/testing/selftests/net/rds/rds_basic.py  | 183 +++++++++++++++++
 tools/testing/selftests/net/rds/rds_stress.py |  58 ++++++
 tools/testing/selftests/net/rds/run.sh        |  42 +++-
 tools/testing/selftests/net/rds/test.py       | 184 +++---------------
 5 files changed, 308 insertions(+), 161 deletions(-)
 create mode 100755 tools/testing/selftests/net/rds/rds_basic.py
 create mode 100644 tools/testing/selftests/net/rds/rds_stress.py

-- 
2.43.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next v1 1/2] selftests: rds: Refactor test.py
  2026-03-02  5:55 [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Allison Henderson
@ 2026-03-02  5:55 ` Allison Henderson
  2026-03-02  5:55 ` [PATCH net-next v1 2/2] selftests: rds: Add rds_stress.py Allison Henderson
  2026-03-03  1:33 ` [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Jakub Kicinski
  2 siblings, 0 replies; 8+ messages in thread
From: Allison Henderson @ 2026-03-02  5:55 UTC (permalink / raw)
  To: netdev
  Cc: linux-kselftest, pabeni, edumazet, rds-devel, kuba, horms,
	linux-rdma, allison.henderson

From: Allison Henderson <allison.henderson@oracle.com>

This patch hoists the send and recv logic from test.py into a helper
module rds_basic.py, keeping the namespace and networking configurations
in the calling test.py script.  This will allow us to reuse the test.py
infrastructure to add additional rds tests.  No functional changes are
added in this initial refactor.

Signed-off-by: Allison Henderson <achender@kernel.org>
---
 tools/testing/selftests/net/rds/Makefile     |   1 +
 tools/testing/selftests/net/rds/rds_basic.py | 183 +++++++++++++++++++
 tools/testing/selftests/net/rds/test.py      | 169 +----------------
 3 files changed, 191 insertions(+), 162 deletions(-)

diff --git a/tools/testing/selftests/net/rds/Makefile b/tools/testing/selftests/net/rds/Makefile
index 762845cc973c..611ed6f2bf91 100644
--- a/tools/testing/selftests/net/rds/Makefile
+++ b/tools/testing/selftests/net/rds/Makefile
@@ -8,6 +8,7 @@ TEST_PROGS := run.sh
 TEST_FILES := \
 	include.sh \
 	test.py \
+	rds_basic.py \
 # end of TEST_FILES
 
 EXTRA_CLEAN := \
diff --git a/tools/testing/selftests/net/rds/rds_basic.py b/tools/testing/selftests/net/rds/rds_basic.py
new file mode 100755
index 000000000000..49c524e2c72a
--- /dev/null
+++ b/tools/testing/selftests/net/rds/rds_basic.py
@@ -0,0 +1,183 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+import ctypes
+import errno
+import hashlib
+import os
+import select
+import socket
+import sys
+
+# Allow utils module to be imported from different directory
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(this_dir, "../"))
+from lib.py.utils import ip
+
+libc = ctypes.cdll.LoadLibrary('libc.so.6')
+setns = libc.setns
+
+# Helper function for creating a socket inside a network namespace.
+# We need this because otherwise RDS will detect that the two TCP
+# sockets are on the same interface and use the loop transport instead
+# of the TCP transport.
+def netns_socket(netns, *args):
+    """Create a socket inside a network namespace."""
+    u0, u1 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+
+    child = os.fork()
+    if child == 0:
+        # change network namespace
+        with open(f'/var/run/netns/{netns}', encoding='utf-8') as f:
+            try:
+                setns(f.fileno(), 0)
+            except IOError as ioe:
+                print(ioe.errno)
+                print(ioe)
+
+        # create socket in target namespace
+        s = socket.socket(*args)
+
+        # send resulting socket to parent
+        socket.send_fds(u0, [], [s.fileno()])
+
+        sys.exit(0)
+
+    # receive socket from child
+    _, s, _, _ = socket.recv_fds(u1, 0, 1)
+    os.waitpid(child, 0)
+    u0.close()
+    u1.close()
+    return socket.fromfd(s[0], *args)
+
+def run_test(env):
+    """Run basic RDS selftest.
+
+    env is a dictionary provided by test.py and is expected to contain:
+      - 'addrs':   list of (ip, port) tuples matching the sockets
+      - 'netns':   list of network namespace names (for sysctl exercises)
+    """
+    addrs = env['addrs']        # [('10.0.0.1', 10000), ('10.0.0.2', 20000)]
+    netns_list = env['netns']   # ['net0', 'net1']
+
+    sockets = [
+        netns_socket(netns_list[0], socket.AF_RDS, socket.SOCK_SEQPACKET),
+        netns_socket(netns_list[1], socket.AF_RDS, socket.SOCK_SEQPACKET),
+    ]
+
+    for s, addr in zip(sockets, addrs):
+        s.bind(addr)
+        s.setblocking(0)
+
+    fileno_to_socket = {
+        s.fileno(): s for s in sockets
+    }
+
+    addr_to_socket = dict(zip(addrs, sockets))
+
+    socket_to_addr = {
+        s: addr for addr, s in zip(addrs, sockets)
+    }
+
+    send_hashes = {}
+    recv_hashes = {}
+
+    ep = select.epoll()
+
+    for s in sockets:
+        ep.register(s, select.EPOLLRDNORM)
+
+    n = 50000
+    nr_send = 0
+    nr_recv = 0
+
+    while nr_send < n:
+        # Send as much as we can without blocking
+        print("sending...", nr_send, nr_recv)
+        while nr_send < n:
+            send_data = hashlib.sha256(
+                f'packet {nr_send}'.encode('utf-8')).hexdigest().encode('utf-8')
+
+            # pseudo-random send/receive pattern
+            sender = sockets[nr_send % 2]
+            receiver = sockets[1 - (nr_send % 3) % 2]
+
+            try:
+                sender.sendto(send_data, socket_to_addr[receiver])
+                send_hashes.setdefault((sender.fileno(), receiver.fileno()),
+                        hashlib.sha256()).update(f'<{send_data}>'.encode('utf-8'))
+                nr_send = nr_send + 1
+            except BlockingIOError:
+                break
+            except OSError as e:
+                if e.errno in [errno.ENOBUFS, errno.ECONNRESET, errno.EPIPE]:
+                    break
+                raise
+
+        # Receive as much as we can without blocking
+        print("receiving...", nr_send, nr_recv)
+        while nr_recv < nr_send:
+            for fileno, eventmask in ep.poll():
+                receiver = fileno_to_socket[fileno]
+
+                if eventmask & select.EPOLLRDNORM:
+                    while True:
+                        try:
+                            recv_data, address = receiver.recvfrom(1024)
+                            sender = addr_to_socket[address]
+                            recv_hashes.setdefault((sender.fileno(),
+                                receiver.fileno()), hashlib.sha256()).update(
+                                        f'<{recv_data}>'.encode('utf-8'))
+                            nr_recv = nr_recv + 1
+                        except BlockingIOError:
+                            break
+
+        # exercise net/rds/tcp.c:rds_tcp_sysctl_reset()
+        for net in netns_list:
+            ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_rcvbuf=10000")
+            ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_sndbuf=10000")
+
+    print("done", nr_send, nr_recv)
+
+    # the Python socket module doesn't know these
+    RDS_INFO_FIRST = 10000
+    RDS_INFO_LAST = 10017
+
+    nr_success = 0
+    nr_error = 0
+
+    for s in sockets:
+        for optname in range(RDS_INFO_FIRST, RDS_INFO_LAST + 1):
+            # Sigh, the Python socket module doesn't allow us to pass
+            # buffer lengths greater than 1024 for some reason. RDS
+            # wants multiple pages.
+            try:
+                s.getsockopt(socket.SOL_RDS, optname, 1024)
+                nr_success = nr_success + 1
+            except OSError as ose:
+                nr_error = nr_error + 1
+                if ose.errno == errno.ENOSPC:
+                    # ignore
+                    pass
+
+    print(f"getsockopt(): {nr_success}/{nr_error}")
+
+    # We're done sending and receiving stuff, now let's check if what
+    # we received is what we sent.
+    for (sender, receiver), send_hash in send_hashes.items():
+        recv_hash = recv_hashes.get((sender, receiver))
+
+        if recv_hash is None:
+            print("FAIL: No data received")
+            return 1
+
+        if send_hash.hexdigest() != recv_hash.hexdigest():
+            print("FAIL: Send/recv mismatch")
+            print("hash expected:", send_hash.hexdigest())
+            print("hash received:", recv_hash.hexdigest())
+            return 1
+
+        print(f"{sender}/{receiver}: ok")
+
+    print("Success")
+    return 0
diff --git a/tools/testing/selftests/net/rds/test.py b/tools/testing/selftests/net/rds/test.py
index 4a7178d11193..0cb060073f6d 100755
--- a/tools/testing/selftests/net/rds/test.py
+++ b/tools/testing/selftests/net/rds/test.py
@@ -2,65 +2,25 @@
 # SPDX-License-Identifier: GPL-2.0
 
 import argparse
-import ctypes
-import errno
-import hashlib
 import os
-import select
 import signal
-import socket
 import subprocess
 import sys
-import atexit
 from pwd import getpwuid
 from os import stat
+import rds_basic
 
 # Allow utils module to be imported from different directory
 this_dir = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(this_dir, "../"))
 from lib.py.utils import ip
 
-libc = ctypes.cdll.LoadLibrary('libc.so.6')
-setns = libc.setns
-
 net0 = 'net0'
 net1 = 'net1'
 
 veth0 = 'veth0'
 veth1 = 'veth1'
 
-# Helper function for creating a socket inside a network namespace.
-# We need this because otherwise RDS will detect that the two TCP
-# sockets are on the same interface and use the loop transport instead
-# of the TCP transport.
-def netns_socket(netns, *args):
-    u0, u1 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-
-    child = os.fork()
-    if child == 0:
-        # change network namespace
-        with open(f'/var/run/netns/{netns}') as f:
-            try:
-                ret = setns(f.fileno(), 0)
-            except IOError as e:
-                print(e.errno)
-                print(e)
-
-        # create socket in target namespace
-        s = socket.socket(*args)
-
-        # send resulting socket to parent
-        socket.send_fds(u0, [], [s.fileno()])
-
-        sys.exit(0)
-
-    # receive socket from child
-    _, s, _, _ = socket.recv_fds(u1, 0, 1)
-    os.waitpid(child, 0)
-    u0.close()
-    u1.close()
-    return socket.fromfd(s[0], *args)
-
 def signal_handler(sig, frame):
     print('Test timed out')
     sys.exit(1)
@@ -87,7 +47,7 @@ packet_duplicate=str(args.duplicate)+'%'
 
 ip(f"netns add {net0}")
 ip(f"netns add {net1}")
-ip(f"link add type veth")
+ip("link add type veth")
 
 addrs = [
     # we technically don't need different port numbers, but this will
@@ -137,129 +97,14 @@ if args.timeout > 0:
     signal.alarm(args.timeout)
     signal.signal(signal.SIGALRM, signal_handler)
 
-sockets = [
-    netns_socket(net0, socket.AF_RDS, socket.SOCK_SEQPACKET),
-    netns_socket(net1, socket.AF_RDS, socket.SOCK_SEQPACKET),
-]
-
-for s, addr in zip(sockets, addrs):
-    s.bind(addr)
-    s.setblocking(0)
-
-fileno_to_socket = {
-    s.fileno(): s for s in sockets
-}
-
-addr_to_socket = {
-    addr: s for addr, s in zip(addrs, sockets)
+env = {
+    'addrs': addrs,
+    'netns': [net0, net1],
 }
 
-socket_to_addr = {
-    s: addr for addr, s in zip(addrs, sockets)
-}
-
-send_hashes = {}
-recv_hashes = {}
-
-ep = select.epoll()
-
-for s in sockets:
-    ep.register(s, select.EPOLLRDNORM)
-
-n = 50000
-nr_send = 0
-nr_recv = 0
-
-while nr_send < n:
-    # Send as much as we can without blocking
-    print("sending...", nr_send, nr_recv)
-    while nr_send < n:
-        send_data = hashlib.sha256(
-            f'packet {nr_send}'.encode('utf-8')).hexdigest().encode('utf-8')
-
-        # pseudo-random send/receive pattern
-        sender = sockets[nr_send % 2]
-        receiver = sockets[1 - (nr_send % 3) % 2]
-
-        try:
-            sender.sendto(send_data, socket_to_addr[receiver])
-            send_hashes.setdefault((sender.fileno(), receiver.fileno()),
-                    hashlib.sha256()).update(f'<{send_data}>'.encode('utf-8'))
-            nr_send = nr_send + 1
-        except BlockingIOError as e:
-            break
-        except OSError as e:
-            if e.errno in [errno.ENOBUFS, errno.ECONNRESET, errno.EPIPE]:
-                break
-            raise
-
-    # Receive as much as we can without blocking
-    print("receiving...", nr_send, nr_recv)
-    while nr_recv < nr_send:
-        for fileno, eventmask in ep.poll():
-            receiver = fileno_to_socket[fileno]
-
-            if eventmask & select.EPOLLRDNORM:
-                while True:
-                    try:
-                        recv_data, address = receiver.recvfrom(1024)
-                        sender = addr_to_socket[address]
-                        recv_hashes.setdefault((sender.fileno(),
-                            receiver.fileno()), hashlib.sha256()).update(
-                                    f'<{recv_data}>'.encode('utf-8'))
-                        nr_recv = nr_recv + 1
-                    except BlockingIOError as e:
-                        break
-
-    # exercise net/rds/tcp.c:rds_tcp_sysctl_reset()
-    for net in [net0, net1]:
-        ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_rcvbuf=10000")
-        ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_sndbuf=10000")
-
-print("done", nr_send, nr_recv)
-
-# the Python socket module doesn't know these
-RDS_INFO_FIRST = 10000
-RDS_INFO_LAST = 10017
-
-nr_success = 0
-nr_error = 0
-
-for s in sockets:
-    for optname in range(RDS_INFO_FIRST, RDS_INFO_LAST + 1):
-        # Sigh, the Python socket module doesn't allow us to pass
-        # buffer lengths greater than 1024 for some reason. RDS
-        # wants multiple pages.
-        try:
-            s.getsockopt(socket.SOL_RDS, optname, 1024)
-            nr_success = nr_success + 1
-        except OSError as e:
-            nr_error = nr_error + 1
-            if e.errno == errno.ENOSPC:
-                # ignore
-                pass
-
-print(f"getsockopt(): {nr_success}/{nr_error}")
+ret = rds_basic.run_test(env)
 
 print("Stopping network packet captures")
 subprocess.check_call(['killall', '-q', 'tcpdump'])
 
-# We're done sending and receiving stuff, now let's check if what
-# we received is what we sent.
-for (sender, receiver), send_hash in send_hashes.items():
-    recv_hash = recv_hashes.get((sender, receiver))
-
-    if recv_hash is None:
-        print("FAIL: No data received")
-        sys.exit(1)
-
-    if send_hash.hexdigest() != recv_hash.hexdigest():
-        print("FAIL: Send/recv mismatch")
-        print("hash expected:", send_hash.hexdigest())
-        print("hash received:", recv_hash.hexdigest())
-        sys.exit(1)
-
-    print(f"{sender}/{receiver}: ok")
-
-print("Success")
-sys.exit(0)
+sys.exit(ret)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next v1 2/2] selftests: rds: Add rds_stress.py
  2026-03-02  5:55 [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Allison Henderson
  2026-03-02  5:55 ` [PATCH net-next v1 1/2] selftests: rds: Refactor test.py Allison Henderson
@ 2026-03-02  5:55 ` Allison Henderson
  2026-03-03  1:33 ` [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Jakub Kicinski
  2 siblings, 0 replies; 8+ messages in thread
From: Allison Henderson @ 2026-03-02  5:55 UTC (permalink / raw)
  To: netdev
  Cc: linux-kselftest, pabeni, edumazet, rds-devel, kuba, horms,
	linux-rdma, allison.henderson

From: Allison Henderson <allison.henderson@oracle.com>

This patch adds a new rds stress test to the rds selftests suite.
rds_stress is available through the rds-tools package, and can be
run in the selftests infrastructure if it is installed on the host.
We also add new test flags --rds_stress and --rds_basic to the
calling test.py script to run one or both of the tests.

Signed-off-by: Allison Henderson <achender@kernel.org>
---
 tools/testing/selftests/net/rds/Makefile      |  1 +
 tools/testing/selftests/net/rds/rds_stress.py | 58 +++++++++++++++++++
 tools/testing/selftests/net/rds/run.sh        | 42 ++++++++++++--
 tools/testing/selftests/net/rds/test.py       | 27 ++++++++-
 4 files changed, 123 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/net/rds/Makefile b/tools/testing/selftests/net/rds/Makefile
index 611ed6f2bf91..a37bd4314f0e 100644
--- a/tools/testing/selftests/net/rds/Makefile
+++ b/tools/testing/selftests/net/rds/Makefile
@@ -9,6 +9,7 @@ TEST_FILES := \
 	include.sh \
 	test.py \
 	rds_basic.py \
+	rds_stress.py \
 # end of TEST_FILES
 
 EXTRA_CLEAN := \
diff --git a/tools/testing/selftests/net/rds/rds_stress.py b/tools/testing/selftests/net/rds/rds_stress.py
new file mode 100644
index 000000000000..8a86fa0b050d
--- /dev/null
+++ b/tools/testing/selftests/net/rds/rds_stress.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+import subprocess
+import time
+
+def run_test(env):
+    """Run RDS stress selftest.
+
+    env is a dictionary provided by test.py and is expected to contain:
+      - 'addrs':   list of (ip, port) tuples matching the sockets
+      - 'netns':   list of network namespace names (for sysctl exercises)
+    """
+    addrs = env['addrs']      # [('10.0.0.1', 10000), ('10.0.0.2', 20000)]
+    netns_list = env['netns'] # ['net0', 'net1']
+
+    a0, a1 = addrs
+    recv_addr = a0[0]
+    send_addr = a1[0]
+    port = a0[1]
+
+    nr_tasks = 1  # max child tasks created
+    q_depth = 1   # max outstanding messages
+    duration = 60 # duration of test in seconds
+
+    # server side
+    p0 = subprocess.Popen([
+        'ip', 'netns', 'exec', netns_list[0],
+        'rds-stress',
+        '-r', str(recv_addr),
+        '-p', str(port),
+        '-t', str(nr_tasks),
+        '-d', str(q_depth),
+        '-T', str(duration+5) # add some extra time to let the client finish
+    ])
+
+    time.sleep(1) # delay to allow server time to come up
+
+    # client side
+    p1 = subprocess.Popen([
+        'ip', 'netns', 'exec', netns_list[1],
+        'rds-stress',
+        '-r', str(send_addr), '-s', str(recv_addr),
+        '-p', str(port),
+        '-t', str(nr_tasks),
+        '-d', str(q_depth),
+        '-T', str(duration)
+    ])
+
+    rc1 = p1.wait() # wait for client
+    rc0 = p0.wait() # then wait for the server
+
+    if rc0 != 0 or rc1 != 0:
+        print(f"rds-stress failed: server={rc0} client={rc1}")
+        return 1
+
+    print("Success")
+    return 0
diff --git a/tools/testing/selftests/net/rds/run.sh b/tools/testing/selftests/net/rds/run.sh
index 8aee244f582a..5917c3222237 100755
--- a/tools/testing/selftests/net/rds/run.sh
+++ b/tools/testing/selftests/net/rds/run.sh
@@ -152,7 +152,34 @@ PLOSS=0
 PCORRUPT=0
 PDUP=0
 GENERATE_GCOV_REPORT=1
-while getopts "d:l:c:u:" opt; do
+RDS_BASIC=0
+RDS_STRESS=0
+FLAGS=""
+
+check_flags()
+{
+	if [ "$RDS_STRESS" -ne 0 ] && ! which rds-stress > /dev/null 2>&1; then
+		echo "selftests: Could not run rds-stress.  Disabling rds-stress."
+		RDS_STRESS=0
+	fi
+	if [ "$RDS_STRESS" -eq 0 ] && [ "$RDS_BASIC" -eq 0 ]; then
+		echo "selftests: Default to rds basic tests"
+		RDS_BASIC=1
+	fi
+}
+
+set_flags()
+{
+	if [ "$RDS_STRESS" -ne 0 ];then
+		FLAGS="$FLAGS -s"
+	fi
+
+	if [ "$RDS_BASIC" -ne 0 ]; then
+		FLAGS="$FLAGS -b"
+	fi
+}
+
+while getopts "d:l:c:u:bs" opt; do
   case ${opt} in
     d)
       LOG_DIR=${OPTARG}
@@ -166,9 +193,15 @@ while getopts "d:l:c:u:" opt; do
     u)
       PDUP=${OPTARG}
       ;;
+    b)
+      RDS_BASIC=1
+      ;;
+    s)
+      RDS_STRESS=1
+      ;;
     :)
       echo "USAGE: run.sh [-d logdir] [-l packet_loss] [-c packet_corruption]" \
-           "[-u packet_duplcate] [-g]"
+           "[-u packet_duplcate] [-g] [-b] [-s]"
       exit 1
       ;;
     ?)
@@ -182,7 +215,8 @@ done
 check_env
 check_conf
 check_gcov_conf
-
+check_flags
+set_flags
 
 rm -fr "$LOG_DIR"
 TRACE_FILE="${LOG_DIR}/rds-strace.txt"
@@ -195,7 +229,7 @@ echo running RDS tests...
 echo Traces will be logged to "$TRACE_FILE"
 rm -f "$TRACE_FILE"
 strace -T -tt -o "$TRACE_FILE" python3 "$(dirname "$0")/test.py" --timeout 400 -d "$LOG_DIR" \
-       -l "$PLOSS" -c "$PCORRUPT" -u "$PDUP"
+       -l "$PLOSS" -c "$PCORRUPT" -u "$PDUP" $FLAGS
 
 test_rc=$?
 dmesg > "${LOG_DIR}/dmesg.out"
diff --git a/tools/testing/selftests/net/rds/test.py b/tools/testing/selftests/net/rds/test.py
index 0cb060073f6d..6a02809e27e6 100755
--- a/tools/testing/selftests/net/rds/test.py
+++ b/tools/testing/selftests/net/rds/test.py
@@ -9,6 +9,7 @@ import sys
 from pwd import getpwuid
 from os import stat
 import rds_basic
+import rds_stress
 
 # Allow utils module to be imported from different directory
 this_dir = os.path.dirname(os.path.realpath(__file__))
@@ -21,6 +22,20 @@ net1 = 'net1'
 veth0 = 'veth0'
 veth1 = 'veth1'
 
+def increment_ports(addrs, inc):
+    """Increment port numbers in the addrs list by inc.
+       Use between tests to make the port numbers unique
+
+    addrs: list of (ip, port) tuples
+    inc: int
+    """
+    new_addrs = []
+
+    for addr, port in addrs:
+        new_addrs.append((addr, port + inc))
+
+    return new_addrs
+
 def signal_handler(sig, frame):
     print('Test timed out')
     sys.exit(1)
@@ -31,6 +46,10 @@ parser = argparse.ArgumentParser(description="init script args",
                   formatter_class=argparse.ArgumentDefaultsHelpFormatter)
 parser.add_argument("-d", "--logdir", action="store",
                     help="directory to store logs", default="/tmp")
+parser.add_argument("-b", "--rds_basic", action="store_true",
+                    help="Run rds basic tests")
+parser.add_argument("-s", "--rds_stress", action="store_true",
+                    help="Run rds stress tests")
 parser.add_argument('--timeout', help="timeout to terminate hung test",
                     type=int, default=0)
 parser.add_argument('-l', '--loss', help="Simulate tcp packet loss",
@@ -102,7 +121,13 @@ env = {
     'netns': [net0, net1],
 }
 
-ret = rds_basic.run_test(env)
+ret = 0
+if args.rds_basic:
+    ret = rds_basic.run_test(env)
+
+if ret == 0 and args.rds_stress:
+    env['addrs'] = increment_ports(env['addrs'], 1000)
+    ret = rds_stress.run_test(env)
 
 print("Stopping network packet captures")
 subprocess.check_call(['killall', '-q', 'tcpdump'])
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
  2026-03-02  5:55 [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Allison Henderson
  2026-03-02  5:55 ` [PATCH net-next v1 1/2] selftests: rds: Refactor test.py Allison Henderson
  2026-03-02  5:55 ` [PATCH net-next v1 2/2] selftests: rds: Add rds_stress.py Allison Henderson
@ 2026-03-03  1:33 ` Jakub Kicinski
  2026-03-04  2:50   ` Allison Henderson
  2 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2026-03-03  1:33 UTC (permalink / raw)
  To: Allison Henderson
  Cc: netdev, linux-kselftest, pabeni, edumazet, rds-devel, horms,
	linux-rdma, allison.henderson

On Sun,  1 Mar 2026 22:55:16 -0700 Allison Henderson wrote:
> This series aims to improve the current rds selftests.  The first patch
> refactors the existing test.py such that the networking set up can be
> reused as general purpose infrastructure for other tests.  The existing
> send and receive code is hoisted into a separate rds_basic.py.  The next
> patch adds a new rds_stress.py that exercises RDS via the external
> rds-stress tool from the rds-tools package if it is available on the host.
> We add two new flags to test.py, -b and -s to select rds_basic or
> rds_stress respectively.  The intent is to make the RDS selftests more
> modular and extensible.  Let me know what you all think.
> 
> Questions, comments, suggestions appreciated!

IDK Allison. I tried to integrate the remaining tests with Netdev CI
this weekend. The two groups of networking tests which can't be run
like all the other selftests are vsock and RDS. I get vsock being
different. vsock is used to communicate between VMs and host, setting
up the vms with the locally built kernel makes it different.

But I'm not exactly sure what makes RDS different. Would you mind
explaining the challenges with fitting RDS into the ksft framework?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
  2026-03-03  1:33 ` [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Jakub Kicinski
@ 2026-03-04  2:50   ` Allison Henderson
  2026-03-04 18:32     ` Jakub Kicinski
  0 siblings, 1 reply; 8+ messages in thread
From: Allison Henderson @ 2026-03-04  2:50 UTC (permalink / raw)
  To: kuba@kernel.org, achender@kernel.org
  Cc: linux-rdma@vger.kernel.org, rds-devel@oss.oracle.com,
	horms@kernel.org, edumazet@google.com, netdev@vger.kernel.org,
	linux-kselftest@vger.kernel.org, pabeni@redhat.com

On Mon, 2026-03-02 at 17:33 -0800, Jakub Kicinski wrote:
> On Sun,  1 Mar 2026 22:55:16 -0700 Allison Henderson wrote:
> > This series aims to improve the current rds selftests.  The first patch
> > refactors the existing test.py such that the networking set up can be
> > reused as general purpose infrastructure for other tests.  The existing
> > send and receive code is hoisted into a separate rds_basic.py.  The next
> > patch adds a new rds_stress.py that exercises RDS via the external
> > rds-stress tool from the rds-tools package if it is available on the host.
> > We add two new flags to test.py, -b and -s to select rds_basic or
> > rds_stress respectively.  The intent is to make the RDS selftests more
> > modular and extensible.  Let me know what you all think.
> > 
> > Questions, comments, suggestions appreciated!
> 
> IDK Allison. I tried to integrate the remaining tests with Netdev CI
> this weekend. The two groups of networking tests which can't be run
> like all the other selftests are vsock and RDS. I get vsock being
> different. vsock is used to communicate between VMs and host, setting
> up the vms with the locally built kernel makes it different.
> 
> But I'm not exactly sure what makes RDS different. Would you mind
> explaining the challenges with fitting RDS into the ksft framework?

Hi Jakub,

I didnt know it was causing you grief, but I am happy to work with you to adapt it.  RDS is a little unique in that the
network topology defines the underlying transport it uses.  If you were to run it with just a pair of veth interfaces on
a single host or vm, then you will only be using the loop back transport in rds.ko.  In order to get it to load and test
rds_tcp.ko, we need the endpoints to be in separate network namespaces so that the destination IP isn't seen as local. 
So the test case does this by forking server/client processes across name spaces.  There really isnt a rush on this
series, so if you think we should do some refactoring/cleanup for ksft first that is fine.  Let me know your thoughts.

Thanks,
Allison


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
  2026-03-04  2:50   ` Allison Henderson
@ 2026-03-04 18:32     ` Jakub Kicinski
  2026-03-06  7:43       ` Allison Henderson
  0 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2026-03-04 18:32 UTC (permalink / raw)
  To: Allison Henderson
  Cc: achender@kernel.org, linux-rdma@vger.kernel.org,
	rds-devel@oss.oracle.com, horms@kernel.org, edumazet@google.com,
	netdev@vger.kernel.org, linux-kselftest@vger.kernel.org,
	pabeni@redhat.com

On Wed, 4 Mar 2026 02:50:34 +0000 Allison Henderson wrote:
> I didnt know it was causing you grief, but I am happy to work with
> you to adapt it.  RDS is a little unique in that the network topology
> defines the underlying transport it uses.  If you were to run it with
> just a pair of veth interfaces on a single host or vm, then you will
> only be using the loop back transport in rds.ko.  In order to get it
> to load and test rds_tcp.ko, we need the endpoints to be in separate
> network namespaces so that the destination IP isn't seen as local. So
> the test case does this by forking server/client processes across
> name spaces.  There really isnt a rush on this series, so if you
> think we should do some refactoring/cleanup for ksft first that is
> fine.  Let me know your thoughts.

IIUC the need to set up a veth + 2 name spaces topology is very common.
We have bash "libraries" / helpers in various lib.sh files to do it.
Python libs also have some support (tho the default linking there is
by pairing two netdevsim devices).

Well, maybe to be clear I should say that we _even_ have support in
libraries for this. Not really strongly opposed to you rolling your own
way of setting up the namespaces at this point. I primarily care about
us being able to execute all your tests in our CI, with standard ksft
commands. Maybe I did something wrong but

 make -C tools/testing/selftests TARGETS=net/rds run_tests

did not work for me.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
  2026-03-04 18:32     ` Jakub Kicinski
@ 2026-03-06  7:43       ` Allison Henderson
  2026-03-06 20:07         ` Jakub Kicinski
  0 siblings, 1 reply; 8+ messages in thread
From: Allison Henderson @ 2026-03-06  7:43 UTC (permalink / raw)
  To: kuba@kernel.org
  Cc: linux-rdma@vger.kernel.org, linux-kselftest@vger.kernel.org,
	rds-devel@oss.oracle.com, pabeni@redhat.com, horms@kernel.org,
	edumazet@google.com, netdev@vger.kernel.org, achender@kernel.org

On Wed, 2026-03-04 at 10:32 -0800, Jakub Kicinski wrote:
> On Wed, 4 Mar 2026 02:50:34 +0000 Allison Henderson wrote:
> > I didnt know it was causing you grief, but I am happy to work with
> > you to adapt it.  RDS is a little unique in that the network topology
> > defines the underlying transport it uses.  If you were to run it with
> > just a pair of veth interfaces on a single host or vm, then you will
> > only be using the loop back transport in rds.ko.  In order to get it
> > to load and test rds_tcp.ko, we need the endpoints to be in separate
> > network namespaces so that the destination IP isn't seen as local. So
> > the test case does this by forking server/client processes across
> > name spaces.  There really isnt a rush on this series, so if you
> > think we should do some refactoring/cleanup for ksft first that is
> > fine.  Let me know your thoughts.
> 
> IIUC the need to set up a veth + 2 name spaces topology is very common.
> We have bash "libraries" / helpers in various lib.sh files to do it.
> Python libs also have some support (tho the default linking there is
> by pairing two netdevsim devices).
> 
> Well, maybe to be clear I should say that we _even_ have support in
> libraries for this. Not really strongly opposed to you rolling your own
> way of setting up the namespaces at this point. I primarily care about
> us being able to execute all your tests in our CI, with standard ksft
> commands. Maybe I did something wrong but
> 
>  make -C tools/testing/selftests TARGETS=net/rds run_tests
> 
> did not work for me.

Sure, lets get this fixed first then.  Usually when I run the test, I just run the one rds test directly like this:

vng --build  --config .config; vng -v --rwdir ./ --run . --user root --cpus 16 -- "export
PYTHONPATH=tools/testing/selftests/net/; tools/testing/selftests/net/rds/run.sh" 2>&1 | tee outfile.txt;

I believe the way you run it would have it run directly on the host though.  Which can work but it would have to be
built and configured correctly for rds. Also I think when run it through make run_tests, ksft may have other lib
includes that get inherited by the child processes which can affect how they run.  But I'd like to see your output to
confirm. Could you include the output you are seeing?  Then I'll see if I can recreate and address what you're seeing on
my end. 

Thank you!
Allison


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test
  2026-03-06  7:43       ` Allison Henderson
@ 2026-03-06 20:07         ` Jakub Kicinski
  0 siblings, 0 replies; 8+ messages in thread
From: Jakub Kicinski @ 2026-03-06 20:07 UTC (permalink / raw)
  To: Allison Henderson
  Cc: linux-rdma@vger.kernel.org, linux-kselftest@vger.kernel.org,
	rds-devel@oss.oracle.com, pabeni@redhat.com, horms@kernel.org,
	edumazet@google.com, netdev@vger.kernel.org, achender@kernel.org

On Fri, 6 Mar 2026 07:43:56 +0000 Allison Henderson wrote:
> On Wed, 2026-03-04 at 10:32 -0800, Jakub Kicinski wrote:
> > On Wed, 4 Mar 2026 02:50:34 +0000 Allison Henderson wrote:  
> > > I didnt know it was causing you grief, but I am happy to work with
> > > you to adapt it.  RDS is a little unique in that the network topology
> > > defines the underlying transport it uses.  If you were to run it with
> > > just a pair of veth interfaces on a single host or vm, then you will
> > > only be using the loop back transport in rds.ko.  In order to get it
> > > to load and test rds_tcp.ko, we need the endpoints to be in separate
> > > network namespaces so that the destination IP isn't seen as local. So
> > > the test case does this by forking server/client processes across
> > > name spaces.  There really isnt a rush on this series, so if you
> > > think we should do some refactoring/cleanup for ksft first that is
> > > fine.  Let me know your thoughts.  
> > 
> > IIUC the need to set up a veth + 2 name spaces topology is very common.
> > We have bash "libraries" / helpers in various lib.sh files to do it.
> > Python libs also have some support (tho the default linking there is
> > by pairing two netdevsim devices).
> > 
> > Well, maybe to be clear I should say that we _even_ have support in
> > libraries for this. Not really strongly opposed to you rolling your own
> > way of setting up the namespaces at this point. I primarily care about
> > us being able to execute all your tests in our CI, with standard ksft
> > commands. Maybe I did something wrong but
> > 
> >  make -C tools/testing/selftests TARGETS=net/rds run_tests
> > 
> > did not work for me.  
> 
> Sure, lets get this fixed first then.  Usually when I run the test, I just run the one rds test directly like this:
> 
> vng --build  --config .config; vng -v --rwdir ./ --run . --user root --cpus 16 -- "export
> PYTHONPATH=tools/testing/selftests/net/; tools/testing/selftests/net/rds/run.sh" 2>&1 | tee outfile.txt;
> 
> I believe the way you run it would have it run directly on the host though.  Which can work but it would have to be
> built and configured correctly for rds. Also I think when run it through make run_tests, ksft may have other lib
> includes that get inherited by the child processes which can affect how they run.  But I'd like to see your output to
> confirm. Could you include the output you are seeing?  Then I'll see if I can recreate and address what you're seeing on
> my end. 

This is how we run:

https://github.com/linux-netdev/nipa/wiki/How-to-run-netdev-selftests-CI-style

Base system is Fedora 43 (since we use vng that's what the "VM" is
effectively also using). Please re-ask the questions that are still
relevant after you go thru the link above? I'm not sure what "run
directly on the host" means exactly ;) 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-03-06 20:07 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-02  5:55 [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Allison Henderson
2026-03-02  5:55 ` [PATCH net-next v1 1/2] selftests: rds: Refactor test.py Allison Henderson
2026-03-02  5:55 ` [PATCH net-next v1 2/2] selftests: rds: Add rds_stress.py Allison Henderson
2026-03-03  1:33 ` [PATCH net-next v1 0/2] selftests: rds: refactor and expand rds selftests test Jakub Kicinski
2026-03-04  2:50   ` Allison Henderson
2026-03-04 18:32     ` Jakub Kicinski
2026-03-06  7:43       ` Allison Henderson
2026-03-06 20:07         ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox