Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftest-rds'

Allison Henderson says:

====================
selftests: rds selftest

This series is a new selftest that Vegard, Chuck and myself have been
working on to provide some test coverage for rds. I've modified the
scripts to include the feedback from the last version, but let me know
if there's anything missed. Questions and comments appreciated.

Thanks everyone!

Allison

Changes in v2:
- Removed qemu vm creation and related code
- Updated README.txt with examples of running the test with virtme
- Removed init.sh. run.sh now directly calls test.py
- Some clean up done with the return code handling since there is no
vm between the scripts anymore
- Imported ip python function in
tools/testing/selftests/net/lib/py/utils.py into test.py
- Adapted test.py to use the imported ip function, and removed the
local ip wrapper
- Some line wrap clean up
- Link to v1:
https://lore.kernel.org/netdev/20240626012834.5678-3-allison.henderson@oracle.com/T
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+620
+1
.gitignore
··· 24 24 *.dwo 25 25 *.elf 26 26 *.gcno 27 + *.gcda 27 28 *.gz 28 29 *.i 29 30 *.ko
+11
Documentation/dev-tools/gcov.rst
··· 75 75 kernel modules are supported by this mechanism. 76 76 77 77 78 + Module specific configs 79 + ----------------------- 80 + 81 + Gcov kernel configs for specific modules are described below: 82 + 83 + CONFIG_GCOV_PROFILE_RDS: 84 + Enables GCOV profiling on RDS for checking which functions or 85 + lines are executed. This config is used by the rds selftest to 86 + generate coverage reports. If left unset the report is omitted. 87 + 88 + 78 89 Files 79 90 ----- 80 91
+1
MAINTAINERS
··· 19197 19197 W: https://oss.oracle.com/projects/rds/ 19198 19198 F: Documentation/networking/rds.rst 19199 19199 F: net/rds/ 19200 + F: tools/testing/selftests/net/rds/ 19200 19201 19201 19202 RDT - RESOURCE ALLOCATION 19202 19203 M: Fenghua Yu <fenghua.yu@intel.com>
+9
net/rds/Kconfig
··· 26 26 bool "RDS debugging messages" 27 27 depends on RDS 28 28 default n 29 + 30 + config GCOV_PROFILE_RDS 31 + bool "Enable GCOV profiling on RDS" 32 + depends on GCOV_KERNEL 33 + help 34 + Enable GCOV profiling on RDS for checking which functions/lines 35 + are executed. 36 + 37 + If unsure, say N.
+5
net/rds/Makefile
··· 15 15 tcp_send.o tcp_stats.o 16 16 17 17 ccflags-$(CONFIG_RDS_DEBUG) := -DRDS_DEBUG 18 + 19 + # for GCOV coverage profiling 20 + ifdef CONFIG_GCOV_PROFILE_RDS 21 + GCOV_PROFILE := y 22 + endif
+1
tools/testing/selftests/Makefile
··· 68 68 TARGETS += net/openvswitch 69 69 TARGETS += net/tcp_ao 70 70 TARGETS += net/netfilter 71 + TARGETS += net/rds 71 72 TARGETS += nsfs 72 73 TARGETS += perf_events 73 74 TARGETS += pidfd
+12
tools/testing/selftests/net/rds/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + all: 4 + @echo mk_build_dir="$(shell pwd)" > include.sh 5 + 6 + TEST_PROGS := run.sh \ 7 + include.sh \ 8 + test.py 9 + 10 + EXTRA_CLEAN := /tmp/rds_logs 11 + 12 + include ../../lib.mk
+41
tools/testing/selftests/net/rds/README.txt
··· 1 + RDS self-tests 2 + ============== 3 + 4 + These scripts provide a coverage test for RDS-TCP by creating two 5 + network namespaces and running rds packets between them. A loopback 6 + network is provisioned with optional probability of packet loss or 7 + corruption. A workload of 50000 hashes, each 64 characters in size, 8 + are passed over an RDS socket on this test network. A passing test means 9 + the RDS-TCP stack was able to recover properly. The provided config.sh 10 + can be used to compile the kernel with the necessary gcov options. The 11 + kernel may optionally be configured to omit the coverage report as well. 12 + 13 + USAGE: 14 + run.sh [-d logdir] [-l packet_loss] [-c packet_corruption] 15 + [-u packet_duplcate] 16 + 17 + OPTIONS: 18 + -d Log directory. Defaults to tools/testing/selftests/net/rds/rds_logs 19 + 20 + -l Simulates a percentage of packet loss 21 + 22 + -c Simulates a percentage of packet corruption 23 + 24 + -u Simulates a percentage of packet duplication. 25 + 26 + EXAMPLE: 27 + 28 + # Create a suitable gcov enabled .config 29 + tools/testing/selftests/net/rds/config.sh -g 30 + 31 + # Alternatly create a gcov disabled .config 32 + tools/testing/selftests/net/rds/config.sh 33 + 34 + # build the kernel 35 + vng --build --config tools/testing/selftests/net/config 36 + 37 + # launch the tests in a VM 38 + vng -v --rwdir ./ --run . --user root --cpus 4 -- \ 39 + "export PYTHONPATH=tools/testing/selftests/net/; tools/testing/selftests/net/rds/run.sh" 40 + 41 + An HTML coverage report will be output in tools/testing/selftests/net/rds/rds_logs/coverage/.
+53
tools/testing/selftests/net/rds/config.sh
··· 1 + #! /bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + set -e 5 + set -u 6 + set -x 7 + 8 + unset KBUILD_OUTPUT 9 + 10 + GENERATE_GCOV_REPORT=0 11 + while getopts "g" opt; do 12 + case ${opt} in 13 + g) 14 + GENERATE_GCOV_REPORT=1 15 + ;; 16 + :) 17 + echo "USAGE: config.sh [-g]" 18 + exit 1 19 + ;; 20 + ?) 21 + echo "Invalid option: -${OPTARG}." 22 + exit 1 23 + ;; 24 + esac 25 + done 26 + 27 + CONF_FILE="tools/testing/selftests/net/config" 28 + 29 + # no modules 30 + scripts/config --file "$CONF_FILE" --disable CONFIG_MODULES 31 + 32 + # enable RDS 33 + scripts/config --file "$CONF_FILE" --enable CONFIG_RDS 34 + scripts/config --file "$CONF_FILE" --enable CONFIG_RDS_TCP 35 + 36 + if [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then 37 + # instrument RDS and only RDS 38 + scripts/config --file "$CONF_FILE" --enable CONFIG_GCOV_KERNEL 39 + scripts/config --file "$CONF_FILE" --disable GCOV_PROFILE_ALL 40 + scripts/config --file "$CONF_FILE" --enable GCOV_PROFILE_RDS 41 + else 42 + scripts/config --file "$CONF_FILE" --disable CONFIG_GCOV_KERNEL 43 + scripts/config --file "$CONF_FILE" --disable GCOV_PROFILE_ALL 44 + scripts/config --file "$CONF_FILE" --disable GCOV_PROFILE_RDS 45 + fi 46 + 47 + # need network namespaces to run tests with veth network interfaces 48 + scripts/config --file "$CONF_FILE" --enable CONFIG_NET_NS 49 + scripts/config --file "$CONF_FILE" --enable CONFIG_VETH 50 + 51 + # simulate packet loss 52 + scripts/config --file "$CONF_FILE" --enable CONFIG_NET_SCH_NETEM 53 +
+224
tools/testing/selftests/net/rds/run.sh
··· 1 + #! /bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + set -e 5 + set -u 6 + 7 + unset KBUILD_OUTPUT 8 + 9 + current_dir="$(realpath "$(dirname "$0")")" 10 + build_dir="$current_dir" 11 + 12 + build_include="$current_dir/include.sh" 13 + if test -f "$build_include"; then 14 + # this include will define "$mk_build_dir" as the location the test was 15 + # built. We will need this if the tests are installed in a location 16 + # other than the kernel source 17 + 18 + source "$build_include" 19 + build_dir="$mk_build_dir" 20 + fi 21 + 22 + # This test requires kernel source and the *.gcda data therein 23 + # Locate the top level of the kernel source, and the net/rds 24 + # subfolder with the appropriate *.gcno object files 25 + ksrc_dir="$(realpath "$build_dir"/../../../../../)" 26 + kconfig="$ksrc_dir/.config" 27 + obj_dir="$ksrc_dir/net/rds" 28 + 29 + GCOV_CMD=gcov 30 + 31 + #check to see if the host has the required packages to generate a gcov report 32 + check_gcov_env() 33 + { 34 + if ! which "$GCOV_CMD" > /dev/null 2>&1; then 35 + echo "Warning: Could not find gcov. " 36 + GENERATE_GCOV_REPORT=0 37 + return 38 + fi 39 + 40 + # the gcov version must match the gcc version 41 + GCC_VER=$(gcc -dumpfullversion) 42 + GCOV_VER=$($GCOV_CMD -v | grep gcov | awk '{print $3}'| awk 'BEGIN {FS="-"}{print $1}') 43 + if [ "$GCOV_VER" != "$GCC_VER" ]; then 44 + #attempt to find a matching gcov version 45 + GCOV_CMD=gcov-$(gcc -dumpversion) 46 + 47 + if ! which "$GCOV_CMD" > /dev/null 2>&1; then 48 + echo "Warning: Could not find an appropriate gcov installation. \ 49 + gcov version must match gcc version" 50 + GENERATE_GCOV_REPORT=0 51 + return 52 + fi 53 + 54 + #recheck version number of found gcov executable 55 + GCOV_VER=$($GCOV_CMD -v | grep gcov | awk '{print $3}'| \ 56 + awk 'BEGIN {FS="-"}{print $1}') 57 + if [ "$GCOV_VER" != "$GCC_VER" ]; then 58 + echo "Warning: Could not find an appropriate gcov installation. \ 59 + gcov version must match gcc version" 60 + GENERATE_GCOV_REPORT=0 61 + else 62 + echo "Warning: Mismatched gcc and gcov detected. Using $GCOV_CMD" 63 + fi 64 + fi 65 + } 66 + 67 + # Check to see if the kconfig has the required configs to generate a coverage report 68 + check_gcov_conf() 69 + { 70 + if ! grep -x "CONFIG_GCOV_PROFILE_RDS=y" "$kconfig" > /dev/null 2>&1; then 71 + echo "INFO: CONFIG_GCOV_PROFILE_RDS should be enabled for coverage reports" 72 + GENERATE_GCOV_REPORT=0 73 + fi 74 + if ! grep -x "CONFIG_GCOV_KERNEL=y" "$kconfig" > /dev/null 2>&1; then 75 + echo "INFO: CONFIG_GCOV_KERNEL should be enabled for coverage reports" 76 + GENERATE_GCOV_REPORT=0 77 + fi 78 + if grep -x "CONFIG_GCOV_PROFILE_ALL=y" "$kconfig" > /dev/null 2>&1; then 79 + echo "INFO: CONFIG_GCOV_PROFILE_ALL should be disabled for coverage reports" 80 + GENERATE_GCOV_REPORT=0 81 + fi 82 + 83 + if [ "$GENERATE_GCOV_REPORT" -eq 0 ]; then 84 + echo "To enable gcov reports, please run "\ 85 + "\"tools/testing/selftests/net/rds/config.sh -g\" and rebuild the kernel" 86 + else 87 + # if we have the required kernel configs, proceed to check the environment to 88 + # ensure we have the required gcov packages 89 + check_gcov_env 90 + fi 91 + } 92 + 93 + # Kselftest framework requirement - SKIP code is 4. 94 + check_conf_enabled() { 95 + if ! grep -x "$1=y" "$kconfig" > /dev/null 2>&1; then 96 + echo "selftests: [SKIP] This test requires $1 enabled" 97 + echo "Please run tools/testing/selftests/net/rds/config.sh and rebuild the kernel" 98 + exit 4 99 + fi 100 + } 101 + check_conf_disabled() { 102 + if grep -x "$1=y" "$kconfig" > /dev/null 2>&1; then 103 + echo "selftests: [SKIP] This test requires $1 disabled" 104 + echo "Please run tools/testing/selftests/net/rds/config.sh and rebuild the kernel" 105 + exit 4 106 + fi 107 + } 108 + check_conf() { 109 + check_conf_enabled CONFIG_NET_SCH_NETEM 110 + check_conf_enabled CONFIG_VETH 111 + check_conf_enabled CONFIG_NET_NS 112 + check_conf_enabled CONFIG_RDS_TCP 113 + check_conf_enabled CONFIG_RDS 114 + check_conf_disabled CONFIG_MODULES 115 + } 116 + 117 + check_env() 118 + { 119 + if ! test -d "$obj_dir"; then 120 + echo "selftests: [SKIP] This test requires a kernel source tree" 121 + exit 4 122 + fi 123 + if ! test -e "$kconfig"; then 124 + echo "selftests: [SKIP] This test requires a configured kernel source tree" 125 + exit 4 126 + fi 127 + if ! which strace > /dev/null 2>&1; then 128 + echo "selftests: [SKIP] Could not run test without strace" 129 + exit 4 130 + fi 131 + if ! which tcpdump > /dev/null 2>&1; then 132 + echo "selftests: [SKIP] Could not run test without tcpdump" 133 + exit 4 134 + fi 135 + 136 + if ! which python3 > /dev/null 2>&1; then 137 + echo "selftests: [SKIP] Could not run test without python3" 138 + exit 4 139 + fi 140 + 141 + python_major=$(python3 -c "import sys; print(sys.version_info[0])") 142 + python_minor=$(python3 -c "import sys; print(sys.version_info[1])") 143 + if [[ python_major -lt 3 || ( python_major -eq 3 && python_minor -lt 9 ) ]] ; then 144 + echo "selftests: [SKIP] Could not run test without at least python3.9" 145 + python3 -V 146 + exit 4 147 + fi 148 + } 149 + 150 + LOG_DIR="$current_dir"/rds_logs 151 + PLOSS=0 152 + PCORRUPT=0 153 + PDUP=0 154 + GENERATE_GCOV_REPORT=1 155 + while getopts "d:l:c:u:" opt; do 156 + case ${opt} in 157 + d) 158 + LOG_DIR=${OPTARG} 159 + ;; 160 + l) 161 + PLOSS=${OPTARG} 162 + ;; 163 + c) 164 + PCORRUPT=${OPTARG} 165 + ;; 166 + u) 167 + PDUP=${OPTARG} 168 + ;; 169 + :) 170 + echo "USAGE: run.sh [-d logdir] [-l packet_loss] [-c packet_corruption]" \ 171 + "[-u packet_duplcate] [-g]" 172 + exit 1 173 + ;; 174 + ?) 175 + echo "Invalid option: -${OPTARG}." 176 + exit 1 177 + ;; 178 + esac 179 + done 180 + 181 + 182 + check_env 183 + check_conf 184 + check_gcov_conf 185 + 186 + 187 + rm -fr "$LOG_DIR" 188 + TRACE_FILE="${LOG_DIR}/rds-strace.txt" 189 + COVR_DIR="${LOG_DIR}/coverage/" 190 + mkdir -p "$LOG_DIR" 191 + mkdir -p "$COVR_DIR" 192 + 193 + set +e 194 + echo running RDS tests... 195 + echo Traces will be logged to "$TRACE_FILE" 196 + rm -f "$TRACE_FILE" 197 + strace -T -tt -o "$TRACE_FILE" python3 "$(dirname "$0")/test.py" --timeout 400 -d "$LOG_DIR" \ 198 + -l "$PLOSS" -c "$PCORRUPT" -u "$PDUP" 199 + 200 + test_rc=$? 201 + dmesg > "${LOG_DIR}/dmesg.out" 202 + 203 + if [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then 204 + echo saving coverage data... 205 + (set +x; cd /sys/kernel/debug/gcov; find ./* -name '*.gcda' | \ 206 + while read -r f 207 + do 208 + cat < "/sys/kernel/debug/gcov/$f" > "/$f" 209 + done) 210 + 211 + echo running gcovr... 212 + gcovr -s --html-details --gcov-executable "$GCOV_CMD" --gcov-ignore-parse-errors \ 213 + -o "${COVR_DIR}/gcovr" "${ksrc_dir}/net/rds/" 214 + else 215 + echo "Coverage report will be skipped" 216 + fi 217 + 218 + if [ "$test_rc" -eq 0 ]; then 219 + echo "PASS: Test completed successfully" 220 + else 221 + echo "FAIL: Test failed" 222 + fi 223 + 224 + exit "$test_rc"
+262
tools/testing/selftests/net/rds/test.py
··· 1 + #! /usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + import argparse 5 + import ctypes 6 + import errno 7 + import hashlib 8 + import os 9 + import select 10 + import signal 11 + import socket 12 + import subprocess 13 + import sys 14 + import atexit 15 + from pwd import getpwuid 16 + from os import stat 17 + from lib.py import ip 18 + 19 + 20 + libc = ctypes.cdll.LoadLibrary('libc.so.6') 21 + setns = libc.setns 22 + 23 + net0 = 'net0' 24 + net1 = 'net1' 25 + 26 + veth0 = 'veth0' 27 + veth1 = 'veth1' 28 + 29 + # Helper function for creating a socket inside a network namespace. 30 + # We need this because otherwise RDS will detect that the two TCP 31 + # sockets are on the same interface and use the loop transport instead 32 + # of the TCP transport. 33 + def netns_socket(netns, *args): 34 + u0, u1 = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET) 35 + 36 + child = os.fork() 37 + if child == 0: 38 + # change network namespace 39 + with open(f'/var/run/netns/{netns}') as f: 40 + try: 41 + ret = setns(f.fileno(), 0) 42 + except IOError as e: 43 + print(e.errno) 44 + print(e) 45 + 46 + # create socket in target namespace 47 + s = socket.socket(*args) 48 + 49 + # send resulting socket to parent 50 + socket.send_fds(u0, [], [s.fileno()]) 51 + 52 + sys.exit(0) 53 + 54 + # receive socket from child 55 + _, s, _, _ = socket.recv_fds(u1, 0, 1) 56 + os.waitpid(child, 0) 57 + u0.close() 58 + u1.close() 59 + return socket.fromfd(s[0], *args) 60 + 61 + def signal_handler(sig, frame): 62 + print('Test timed out') 63 + sys.exit(1) 64 + 65 + #Parse out command line arguments. We take an optional 66 + # timeout parameter and an optional log output folder 67 + parser = argparse.ArgumentParser(description="init script args", 68 + formatter_class=argparse.ArgumentDefaultsHelpFormatter) 69 + parser.add_argument("-d", "--logdir", action="store", 70 + help="directory to store logs", default="/tmp") 71 + parser.add_argument('--timeout', help="timeout to terminate hung test", 72 + type=int, default=0) 73 + parser.add_argument('-l', '--loss', help="Simulate tcp packet loss", 74 + type=int, default=0) 75 + parser.add_argument('-c', '--corruption', help="Simulate tcp packet corruption", 76 + type=int, default=0) 77 + parser.add_argument('-u', '--duplicate', help="Simulate tcp packet duplication", 78 + type=int, default=0) 79 + args = parser.parse_args() 80 + logdir=args.logdir 81 + packet_loss=str(args.loss)+'%' 82 + packet_corruption=str(args.corruption)+'%' 83 + packet_duplicate=str(args.duplicate)+'%' 84 + 85 + ip(f"netns add {net0}") 86 + ip(f"netns add {net1}") 87 + ip(f"link add type veth") 88 + 89 + addrs = [ 90 + # we technically don't need different port numbers, but this will 91 + # help identify traffic in the network analyzer 92 + ('10.0.0.1', 10000), 93 + ('10.0.0.2', 20000), 94 + ] 95 + 96 + # move interfaces to separate namespaces so they can no longer be 97 + # bound directly; this prevents rds from switching over from the tcp 98 + # transport to the loop transport. 99 + ip(f"link set {veth0} netns {net0} up") 100 + ip(f"link set {veth1} netns {net1} up") 101 + 102 + 103 + 104 + # add addresses 105 + ip(f"-n {net0} addr add {addrs[0][0]}/32 dev {veth0}") 106 + ip(f"-n {net1} addr add {addrs[1][0]}/32 dev {veth1}") 107 + 108 + # add routes 109 + ip(f"-n {net0} route add {addrs[1][0]}/32 dev {veth0}") 110 + ip(f"-n {net1} route add {addrs[0][0]}/32 dev {veth1}") 111 + 112 + # sanity check that our two interfaces/addresses are correctly set up 113 + # and communicating by doing a single ping 114 + ip(f"netns exec {net0} ping -c 1 {addrs[1][0]}") 115 + 116 + # Start a packet capture on each network 117 + for net in [net0, net1]: 118 + tcpdump_pid = os.fork() 119 + if tcpdump_pid == 0: 120 + pcap = logdir+'/'+net+'.pcap' 121 + subprocess.check_call(['touch', pcap]) 122 + user = getpwuid(stat(pcap).st_uid).pw_name 123 + ip(f"netns exec {net} /usr/sbin/tcpdump -Z {user} -i any -w {pcap}") 124 + sys.exit(0) 125 + 126 + # simulate packet loss, duplication and corruption 127 + for net, iface in [(net0, veth0), (net1, veth1)]: 128 + ip(f"netns exec {net} /usr/sbin/tc qdisc add dev {iface} root netem \ 129 + corrupt {packet_corruption} loss {packet_loss} duplicate \ 130 + {packet_duplicate}") 131 + 132 + # add a timeout 133 + if args.timeout > 0: 134 + signal.alarm(args.timeout) 135 + signal.signal(signal.SIGALRM, signal_handler) 136 + 137 + sockets = [ 138 + netns_socket(net0, socket.AF_RDS, socket.SOCK_SEQPACKET), 139 + netns_socket(net1, socket.AF_RDS, socket.SOCK_SEQPACKET), 140 + ] 141 + 142 + for s, addr in zip(sockets, addrs): 143 + s.bind(addr) 144 + s.setblocking(0) 145 + 146 + fileno_to_socket = { 147 + s.fileno(): s for s in sockets 148 + } 149 + 150 + addr_to_socket = { 151 + addr: s for addr, s in zip(addrs, sockets) 152 + } 153 + 154 + socket_to_addr = { 155 + s: addr for addr, s in zip(addrs, sockets) 156 + } 157 + 158 + send_hashes = {} 159 + recv_hashes = {} 160 + 161 + ep = select.epoll() 162 + 163 + for s in sockets: 164 + ep.register(s, select.EPOLLRDNORM) 165 + 166 + n = 50000 167 + nr_send = 0 168 + nr_recv = 0 169 + 170 + while nr_send < n: 171 + # Send as much as we can without blocking 172 + print("sending...", nr_send, nr_recv) 173 + while nr_send < n: 174 + send_data = hashlib.sha256( 175 + f'packet {nr_send}'.encode('utf-8')).hexdigest().encode('utf-8') 176 + 177 + # pseudo-random send/receive pattern 178 + sender = sockets[nr_send % 2] 179 + receiver = sockets[1 - (nr_send % 3) % 2] 180 + 181 + try: 182 + sender.sendto(send_data, socket_to_addr[receiver]) 183 + send_hashes.setdefault((sender.fileno(), receiver.fileno()), 184 + hashlib.sha256()).update(f'<{send_data}>'.encode('utf-8')) 185 + nr_send = nr_send + 1 186 + except BlockingIOError as e: 187 + break 188 + except OSError as e: 189 + if e.errno in [errno.ENOBUFS, errno.ECONNRESET, errno.EPIPE]: 190 + break 191 + raise 192 + 193 + # Receive as much as we can without blocking 194 + print("receiving...", nr_send, nr_recv) 195 + while nr_recv < nr_send: 196 + for fileno, eventmask in ep.poll(): 197 + receiver = fileno_to_socket[fileno] 198 + 199 + if eventmask & select.EPOLLRDNORM: 200 + while True: 201 + try: 202 + recv_data, address = receiver.recvfrom(1024) 203 + sender = addr_to_socket[address] 204 + recv_hashes.setdefault((sender.fileno(), 205 + receiver.fileno()), hashlib.sha256()).update( 206 + f'<{recv_data}>'.encode('utf-8')) 207 + nr_recv = nr_recv + 1 208 + except BlockingIOError as e: 209 + break 210 + 211 + # exercise net/rds/tcp.c:rds_tcp_sysctl_reset() 212 + for net in [net0, net1]: 213 + ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_rcvbuf=10000") 214 + ip(f"netns exec {net} /usr/sbin/sysctl net.rds.tcp.rds_tcp_sndbuf=10000") 215 + 216 + print("done", nr_send, nr_recv) 217 + 218 + # the Python socket module doesn't know these 219 + RDS_INFO_FIRST = 10000 220 + RDS_INFO_LAST = 10017 221 + 222 + nr_success = 0 223 + nr_error = 0 224 + 225 + for s in sockets: 226 + for optname in range(RDS_INFO_FIRST, RDS_INFO_LAST + 1): 227 + # Sigh, the Python socket module doesn't allow us to pass 228 + # buffer lengths greater than 1024 for some reason. RDS 229 + # wants multiple pages. 230 + try: 231 + s.getsockopt(socket.SOL_RDS, optname, 1024) 232 + nr_success = nr_success + 1 233 + except OSError as e: 234 + nr_error = nr_error + 1 235 + if e.errno == errno.ENOSPC: 236 + # ignore 237 + pass 238 + 239 + print(f"getsockopt(): {nr_success}/{nr_error}") 240 + 241 + print("Stopping network packet captures") 242 + subprocess.check_call(['killall', '-q', 'tcpdump']) 243 + 244 + # We're done sending and receiving stuff, now let's check if what 245 + # we received is what we sent. 246 + for (sender, receiver), send_hash in send_hashes.items(): 247 + recv_hash = recv_hashes.get((sender, receiver)) 248 + 249 + if recv_hash is None: 250 + print("FAIL: No data received") 251 + sys.exit(1) 252 + 253 + if send_hash.hexdigest() != recv_hash.hexdigest(): 254 + print("FAIL: Send/recv mismatch") 255 + print("hash expected:", send_hash.hexdigest()) 256 + print("hash received:", recv_hash.hexdigest()) 257 + sys.exit(1) 258 + 259 + print(f"{sender}/{receiver}: ok") 260 + 261 + print("Success") 262 + sys.exit(0)