[PATCH net-next v1 6/6] selftests: rds: Make rds selftests TAP compliant

Allison Henderson
2026-04-27T23:29:33Z

This patch updates the rds selftests output to be TAP compliant.

Use ksft_pr() to mark debug output with a leading '# ' so that TAP
parsers treat it as commentary, and convert all informational print()
calls to use ksft_pr(). sys.exit(0) is changed to os._exit(0) to
avoid duplicate prints from the buffered TAP output. The console
output from the tcpdump subprocess is silenced, and the gcov console
output is redirected to a gcovr.log.

Finally adjust the exit path so that the hash check loop sets a
return code instead exiting directly. Then print the TAP results
and totals lines before exiting.

Signed-off-by: Allison Henderson <achender@kernel.org>
---
tools/testing/selftests/net/rds/run.sh | 18 +++++----
tools/testing/selftests/net/rds/test.py | 53 ++++++++++++++++---------
2 files changed, 44 insertions(+), 27 deletions(-)

diff --git a/tools/testing/selftests/net/rds/run.sh b/tools/testing/selftests/net/rds/run.sh
index 3fc116d23410..805cd0915585 100755
--- a/tools/testing/selftests/net/rds/run.sh
+++ b/tools/testing/selftests/net/rds/run.sh
@@ -205,8 +205,8 @@ if ! mountpoint -q /tmp 2>/dev/null; then
fi

set +e
-echo running RDS tests...
-echo Traces will be logged to "$TRACE_FILE"
+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" \
-t "$TIMEOUT" -d "$LOG_DIR" -l "$PLOSS" -c "$PCORRUPT" \
@@ -216,7 +216,7 @@ test_rc=$?
dmesg > "${LOG_DIR}/dmesg.out"

if [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then
- echo saving coverage data...
+ echo "# saving coverage data..."

# Ensure debugfs is mounted
if ! test -d /sys/kernel/debug/gcov; then
@@ -229,17 +229,19 @@ if [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then
cat < "/sys/kernel/debug/gcov/$f" > "/$f"
done)

- echo running gcovr...
+ echo "# running gcovr..."
gcovr -s --html-details --gcov-executable "$GCOV_CMD" --gcov-ignore-parse-errors \
- --root "${ksrc_dir}" -o "${COVR_DIR}/gcovr" "${ksrc_dir}/net/rds/"
+ --root "${ksrc_dir}" -o "${COVR_DIR}/gcovr" "${ksrc_dir}/net/rds/" \
+ > "${LOG_DIR}/gcovr.log" 2>&1
+ echo "# gcovr log: ${LOG_DIR}/gcovr.log"
else
- echo "Coverage report will be skipped"
+ echo "# Coverage report will be skipped"
fi

if [ "$test_rc" -eq 0 ]; then
- echo "PASS: Test completed successfully"
+ echo "# PASS: Test completed successfully"
else
- echo "FAIL: Test failed"
+ echo "# FAIL: Test failed"
fi

exit "$test_rc"
diff --git a/tools/testing/selftests/net/rds/test.py b/tools/testing/selftests/net/rds/test.py
index 6685b960d013..bef0b02c8d5c 100755
--- a/tools/testing/selftests/net/rds/test.py
+++ b/tools/testing/selftests/net/rds/test.py
@@ -18,6 +18,7 @@ import shutil
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(this_dir, "../"))
from lib.py.utils import ip
+from lib.py.ksft import ksft_pr

libc = ctypes.cdll.LoadLibrary('libc.so.6')
setns = libc.setns
@@ -57,7 +58,7 @@ def netns_socket(netns, *sock_args):
# send resulting socket to parent
socket.send_fds(u0, [], [sock.fileno()])

- sys.exit(0)
+ os._exit(0)

# receive socket from child
_, fds, _, _ = socket.recv_fds(u1, 0, 1)
@@ -67,7 +68,7 @@ def netns_socket(netns, *sock_args):
return socket.fromfd(fds[0], *sock_args)

def collect_pcaps():
- print("Stopping network packet captures")
+ ksft_pr("Stopping network packet captures")
for p, pcap_tmp, pcap, fd in tcpdump_procs:
p.terminate()
p.wait()
@@ -78,8 +79,9 @@ def signal_handler(_sig, _frame):
"""
Test timed out signal handler
"""
- print('Test timed out')
+ ksft_pr("Test timed out")
collect_pcaps()
+ print("not ok 1 rds selftest")
sys.exit(1)

#Parse out command line arguments. We take an optional
@@ -140,7 +142,8 @@ for net in [NET0, NET1]:
fd, pcap_tmp = tempfile.mkstemp(suffix=".pcap", prefix=f"{net}-", dir="/tmp")
p = subprocess.Popen(
['ip', 'netns', 'exec', net,
- '/usr/sbin/tcpdump', '-i', 'any', '-w', pcap_tmp])
+ '/usr/sbin/tcpdump', '-i', 'any', '-w', pcap_tmp],
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
tcpdump_procs.append((p, pcap_tmp, pcap, fd))

# simulate packet loss, duplication and corruption
@@ -149,6 +152,9 @@ for net, iface in [(NET0, VETH0), (NET1, VETH1)]:
corrupt {PACKET_CORRUPTION} loss {PACKET_LOSS} duplicate \
{PACKET_DUPLICATE}")

+print("TAP version 13")
+print("1..1")
+
# add a timeout
if args.timeout > 0:
signal.alarm(args.timeout)
@@ -187,7 +193,7 @@ nr_recv = 0

while nr_send < NUM_PACKETS:
# Send as much as we can without blocking
- print("sending...", nr_send, nr_recv)
+ ksft_pr("sending...", nr_send, nr_recv)
while nr_send < NUM_PACKETS:
send_data = hashlib.sha256(
f'packet {nr_send}'.encode('utf-8')).hexdigest().encode('utf-8')
@@ -209,7 +215,7 @@ while nr_send < NUM_PACKETS:
raise

# Receive as much as we can without blocking
- print("receiving...", nr_send, nr_recv)
+ ksft_pr("receiving...", nr_send, nr_recv)
while nr_recv < nr_send:
for fileno, eventmask in ep.poll():
receiver = fileno_to_socket[fileno]
@@ -231,7 +237,7 @@ while nr_send < NUM_PACKETS:
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)
+ksft_pr("done", nr_send, nr_recv)

# the Python socket module doesn't know these
RDS_INFO_FIRST = 10000
@@ -254,25 +260,34 @@ for s in sockets:
# ignore
pass

-print(f"getsockopt(): {nr_success}/{nr_error}")
+ksft_pr(f"getsockopt(): {nr_success}/{nr_error}")
collect_pcaps()

# We're done sending and receiving stuff, now let's check if what
# we received is what we sent.
+ret = 0
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)
+ ksft_pr("FAIL: No data received")
+ ret = 1
+ break

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)
+ ksft_pr("FAIL: Send/recv mismatch")
+ ksft_pr("hash expected:", send_hash.hexdigest())
+ ksft_pr("hash received:", recv_hash.hexdigest())
+ ret = 1
+ break
+
+ ksft_pr(f"{sender}/{receiver}: ok")
+
+if ret == 0:
+ ksft_pr("Success")
+ print("ok 1 rds selftest")
+else:
+ print("not ok 1 rds selftest")
+
+ksft_pr(f"Totals: pass:{1-ret} fail:{ret} skip:0")
+sys.exit(ret)
--
2.25.1