selftests: rds: Add RDS_LOG_DIR env variable

This patch modifies the rds selftest to look for an env variable
RDS_LOG_DIR, and log all traces, pcaps and gcov collections to
the folder specified in RDS_LOG_DIR.  If RDS_LOG_DIR is unset,
logs are not collected.

Signed-off-by: Allison Henderson <achender@kernel.org>
Link: https://patch.msgid.link/20260504054143.4027538-6-achender@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Allison Henderson 2026-05-03 22:41:38 -07:00 committed by Jakub Kicinski
parent 7d6a32e7cb
commit ad070d9037
3 changed files with 59 additions and 39 deletions

View File

@ -15,7 +15,9 @@ USAGE:
[-u packet_duplicate] [-t timeout]
OPTIONS:
-d Log directory. Defaults to tools/testing/selftests/net/rds/rds_logs
-d Log directory. If set, logs will be stored in the
given dir, or skipped if unset. Log dir can also be
set through the RDS_LOG_DIR env variable
-l Simulates a percentage of packet loss
@ -25,6 +27,16 @@ OPTIONS:
-t Test timeout. Defaults to tools/testing/selftests/net/rds/settings
ENV VARIABLES:
RDS_LOG_DIR Log directory. If set, logs will be stored in
the given dir, or skipped if unset. Log dir
can also be set with the -d flag.
Use with --rwdir on the CI path to retain logs after
test compleation. Log dir end point must be within
the specified --rwdir path for logs to persist on
the host.
EXAMPLE:
# Create a suitable gcov enabled .config
@ -41,6 +53,7 @@ EXAMPLE:
# launch the tests in a VM
vng -v --rwdir ./ --run . --user root --cpus 4 -- \
"export PYTHONPATH=tools/testing/selftests/net/; tools/testing/selftests/net/rds/run.sh"
"export PYTHONPATH=tools/testing/selftests/net/; \
export RDS_LOG_DIR=tools/testing/selftests/net/rds/rds_logs; \
tools/testing/selftests/net/rds/run.sh"
An HTML coverage report will be output in tools/testing/selftests/net/rds/rds_logs/coverage/.

View File

@ -150,28 +150,26 @@ check_env()
fi
}
LOG_DIR="$current_dir"/rds_logs
PLOSS=0
PCORRUPT=0
PDUP=0
LOG_DIR="${RDS_LOG_DIR:-}"
TIMEOUT=$timeout
GENERATE_GCOV_REPORT=1
FLAGS=()
while getopts "d:l:c:u:t:" opt; do
case ${opt} in
d)
LOG_DIR=${OPTARG}
;;
l)
PLOSS=${OPTARG}
FLAGS+=("-l" "${OPTARG}")
;;
c)
PCORRUPT=${OPTARG}
FLAGS+=("-c" "${OPTARG}")
;;
t)
TIMEOUT=${OPTARG}
;;
u)
PDUP=${OPTARG}
FLAGS+=("-u" "${OPTARG}")
;;
:)
echo "USAGE: run.sh [-d logdir] [-l packet_loss] [-c packet_corruption]" \
@ -185,30 +183,37 @@ while getopts "d:l:c:u:t:" opt; do
esac
done
check_env
check_conf
check_gcov_conf
TRACE_CMD=()
if [[ -n "$LOG_DIR" ]]; then
rm -fr "$LOG_DIR"
FLAGS+=("-d" "$LOG_DIR")
rm -fr "$LOG_DIR"
TRACE_FILE="${LOG_DIR}/rds-strace.txt"
COVR_DIR="${LOG_DIR}/coverage/"
mkdir -p "$LOG_DIR"
mkdir -p "$COVR_DIR"
TRACE_FILE="${LOG_DIR}/rds-strace.txt"
COVR_DIR="${LOG_DIR}/coverage/"
mkdir -p "$LOG_DIR"
mkdir -p "$COVR_DIR"
echo Traces will be logged to "${TRACE_FILE}"
rm -f "$TRACE_FILE"
TRACE_CMD=(strace -T -tt -o "${TRACE_FILE}")
fi
set +e
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" \
-u "$PDUP"
"${TRACE_CMD[@]}" python3 "$(dirname "$0")/test.py" "${FLAGS[@]}" -t "$TIMEOUT"
test_rc=$?
dmesg > "${LOG_DIR}/dmesg.out"
if [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then
if [[ -n "$LOG_DIR" ]]; then
dmesg > "${LOG_DIR}/dmesg.out"
fi
if [[ -n "$LOG_DIR" ]] && [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then
echo saving coverage data...
(set +x; cd /sys/kernel/debug/gcov; find ./* -name '*.gcda' | \
while read -r f

View File

@ -82,7 +82,7 @@ def signal_handler(_sig, _frame):
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")
help="directory to store logs", default=None)
parser.add_argument('-t', '--timeout', help="timeout to terminate hung test",
type=int, default=0)
parser.add_argument('-l', '--loss', help="Simulate tcp packet loss",
@ -128,16 +128,17 @@ ip(f"-n {NET1} route add {addrs[0][0]}/32 dev {VETH1}")
# and communicating by doing a single ping
ip(f"netns exec {NET0} ping -c 1 {addrs[1][0]}")
# Start a packet capture on each network
tcpdump_procs = []
for net in [NET0, NET1]:
pcap = logdir+'/'+net+'.pcap'
fd, pcap_tmp = tempfile.mkstemp(suffix=".pcap", prefix=f"{net}-", dir="/tmp")
# pylint: disable-next=consider-using-with
p = subprocess.Popen(
['ip', 'netns', 'exec', net,
'/usr/sbin/tcpdump', '-i', 'any', '-w', pcap_tmp])
tcpdump_procs.append((p, pcap_tmp, pcap, fd))
# Start a packet capture on each network
if logdir is not None:
for net in [NET0, NET1]:
pcap = logdir+'/'+net+'.pcap'
fd, pcap_tmp = tempfile.mkstemp(suffix=".pcap", prefix=f"{net}-", dir="/tmp")
# pylint: disable-next=consider-using-with
p = subprocess.Popen(
['ip', 'netns', 'exec', net,
'/usr/sbin/tcpdump', '-i', 'any', '-w', pcap_tmp])
tcpdump_procs.append((p, pcap_tmp, pcap, fd))
# simulate packet loss, duplication and corruption
for net, iface in [(NET0, VETH0), (NET1, VETH1)]:
@ -252,12 +253,13 @@ for s in sockets:
print(f"getsockopt(): {nr_success}/{nr_error}")
print("Stopping network packet captures")
for p, pcap_tmp, pcap, fd in tcpdump_procs:
p.terminate()
p.wait()
os.close(fd)
shutil.move(pcap_tmp, pcap)
if logdir is not None:
print("Stopping network packet captures")
for p, pcap_tmp, pcap, fd in tcpdump_procs:
p.terminate()
p.wait()
os.close(fd)
shutil.move(pcap_tmp, pcap)
# We're done sending and receiving stuff, now let's check if what
# we received is what we sent.