xref: /linux/tools/testing/selftests/net/rds/rds_run.sh (revision 90e63d5354951d37fa2b3b91e6f17b95d2bf9bee)
1#! /bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4set -e
5set -u
6
7unset KBUILD_OUTPUT
8
9current_dir="$(realpath "$(dirname "$0")")"
10build_dir="$current_dir"
11
12build_include="$current_dir/include.sh"
13if 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"
20fi
21
22# Source settings for timeout value (also used by ksft runner)
23source "$current_dir"/settings
24
25# This test requires kernel source and the *.gcda data therein
26# Locate the top level of the kernel source, and the net/rds
27# subfolder with the appropriate *.gcno object files
28ksrc_dir="$(realpath "$build_dir"/../../../../../)"
29kconfig="$ksrc_dir/.config"
30obj_dir="$ksrc_dir/net/rds"
31
32GCOV_CMD=gcov
33
34#check to see if the host has the required packages to generate a gcov report
35check_gcov_env()
36{
37	if ! which "$GCOV_CMD" > /dev/null 2>&1; then
38		echo "# Warning: Could not find gcov. "
39		GENERATE_GCOV_REPORT=0
40		return
41	fi
42
43	# the gcov version must match the gcc version
44	GCC_VER=$(gcc -dumpfullversion)
45	GCOV_VER=$($GCOV_CMD -v | grep gcov | awk '{print $3}'| awk 'BEGIN {FS="-"}{print $1}')
46	if [ "$GCOV_VER" != "$GCC_VER" ]; then
47		#attempt to find a matching gcov version
48		GCOV_CMD=gcov-$(gcc -dumpversion)
49
50		if ! which "$GCOV_CMD" > /dev/null 2>&1; then
51			echo "# Warning: Could not find an appropriate gcov installation. \
52				gcov version must match gcc version"
53			GENERATE_GCOV_REPORT=0
54			return
55		fi
56
57		#recheck version number of found gcov executable
58		GCOV_VER=$($GCOV_CMD -v | grep gcov | awk '{print $3}'| \
59			awk 'BEGIN {FS="-"}{print $1}')
60		if [ "$GCOV_VER" != "$GCC_VER" ]; then
61			echo "# Warning: Could not find an appropriate gcov installation. \
62				gcov version must match gcc version"
63			GENERATE_GCOV_REPORT=0
64		else
65			echo "# Warning: Mismatched gcc and gcov detected.  Using $GCOV_CMD"
66		fi
67	fi
68}
69
70# Check to see if the kconfig has the required configs to generate a coverage report
71check_gcov_conf()
72{
73	if ! grep -x "CONFIG_GCOV_PROFILE_RDS=y" "$kconfig" > /dev/null 2>&1; then
74		echo "# INFO: CONFIG_GCOV_PROFILE_RDS should be enabled for coverage reports"
75		GENERATE_GCOV_REPORT=0
76	fi
77	if ! grep -x "CONFIG_GCOV_KERNEL=y" "$kconfig" > /dev/null 2>&1; then
78		echo "# INFO: CONFIG_GCOV_KERNEL should be enabled for coverage reports"
79		GENERATE_GCOV_REPORT=0
80	fi
81	if grep -x "CONFIG_GCOV_PROFILE_ALL=y" "$kconfig" > /dev/null 2>&1; then
82		echo "# INFO: CONFIG_GCOV_PROFILE_ALL should be disabled for coverage reports"
83		GENERATE_GCOV_REPORT=0
84	fi
85
86	if [ "$GENERATE_GCOV_REPORT" -eq 0 ]; then
87		echo "# To enable gcov reports, please run "\
88			"\"tools/testing/selftests/net/rds/config.sh -g\" and rebuild the kernel"
89	else
90		# if we have the required kernel configs, proceed to check the environment to
91		# ensure we have the required gcov packages
92		check_gcov_env
93	fi
94}
95
96# Checks if a kconfig is enabled (set to =y or =m)
97# $1: kconfig symbol to check
98# $2: (optional) module name backing $1
99#     Ex: check_conf_enabled CONFIG_RDS_TCP rds_tcp
100#     Modules for configs set to  =m will be probed
101#     If omitted, only a built-in (=y) config is accepted.
102# Returns on success.  exits 4 on failure
103# Kselftest framework requirement - SKIP code is 4.
104check_conf_enabled() {
105	if grep -x "$1=y" "$kconfig" > /dev/null 2>&1; then
106		return
107	fi
108	if [ -n "${2:-}" ] && grep -x "$1=m" "$kconfig" > /dev/null 2>&1; then
109		probe_module "$2"
110		return
111	fi
112	echo "selftests: [SKIP] This test requires $1 enabled"
113	echo "Please run" \
114	     "tools/testing/selftests/net/rds/config.sh and rebuild the kernel"
115	exit 4
116}
117
118check_rdma_conf_enabled() {
119	if grep -x "$1=y" "$kconfig" > /dev/null 2>&1; then
120		return
121	fi
122	if [ -n "${2:-}" ] && grep -x "$1=m" "$kconfig" > /dev/null 2>&1; then
123		probe_module "$2"
124		return
125	fi
126	echo "selftests: [XFAIL] rdma transport requires $1 enabled"
127	echo "To enable, run" \
128	     "tools/testing/selftests/net/rds/config.sh -r and rebuild"
129	exit 2
130}
131
132# Load the module backing a config that is built as a loadable module
133# (=m).  Built-in (=y) configs are already available and don't reach
134# here.  Exits with the SKIP code if a required module cannot be loaded.
135probe_module() {
136	if ! modprobe -q "$1"; then
137		echo "selftests: [SKIP] could not load required module $1"
138		exit 4
139	fi
140}
141
142check_conf() {
143	check_conf_enabled CONFIG_NET_SCH_NETEM sch_netem
144	check_conf_enabled CONFIG_VETH veth
145	check_conf_enabled CONFIG_NET_NS
146	check_conf_enabled CONFIG_RDS_TCP rds_tcp
147	check_conf_enabled CONFIG_RDS rds
148}
149
150# Check kernel config and host environment for RDS-RDMA support.
151# Exits with XFAIL (2) if the user requested rdma but prerequisites
152# are not met.
153check_rdma_conf()
154{
155	case "$TRANSPORT" in
156	  *rdma*) ;;
157	  *) return ;;
158	esac
159
160	# Kconfig will enforce CONFIG_INFINIBAND_* as dependencies
161	# of CONFIG_RDMA_RXE
162	check_rdma_conf_enabled CONFIG_RDMA_RXE rdma_rxe
163	check_rdma_conf_enabled CONFIG_RDS_RDMA rds_rdma
164
165	if ! which rdma > /dev/null 2>&1; then
166		echo "selftests: [XFAIL] rdma transport requires the 'rdma'" \
167		      "tool (iproute2)"
168		exit 2
169	fi
170}
171
172check_env()
173{
174	if ! test -d "$obj_dir"; then
175		echo "selftests: [SKIP] This test requires a kernel source tree"
176		exit 4
177	fi
178	if ! test -e "$kconfig"; then
179		echo "selftests: [SKIP] This test requires a configured kernel source tree"
180		exit 4
181	fi
182	if ! which strace > /dev/null 2>&1; then
183		echo "selftests: [SKIP] Could not run test without strace"
184		exit 4
185	fi
186	if ! which tcpdump > /dev/null 2>&1; then
187		echo "selftests: [SKIP] Could not run test without tcpdump"
188		exit 4
189	fi
190
191	if ! which python3 > /dev/null 2>&1; then
192		echo "selftests: [SKIP] Could not run test without python3"
193		exit 4
194	fi
195
196	python_major=$(python3 -c "import sys; print(sys.version_info[0])")
197	python_minor=$(python3 -c "import sys; print(sys.version_info[1])")
198	if [[ python_major -lt 3 || ( python_major -eq 3 && python_minor -lt 9 ) ]] ; then
199		echo "selftests: [SKIP] Could not run test without at least python3.9"
200		python3 -V
201		exit 4
202	fi
203}
204
205LOG_DIR="${RDS_LOG_DIR:-}"
206TIMEOUT=$timeout
207GENERATE_GCOV_REPORT=1
208TRANSPORT=tcp
209FLAGS=()
210
211while getopts "d:l:c:u:t:T:" opt; do
212  case ${opt} in
213    d)
214      LOG_DIR=${OPTARG}
215      ;;
216    l)
217      FLAGS+=("-l" "${OPTARG}")
218      ;;
219    c)
220      FLAGS+=("-c" "${OPTARG}")
221      ;;
222    t)
223      TIMEOUT=${OPTARG}
224      ;;
225    u)
226      FLAGS+=("-u" "${OPTARG}")
227      ;;
228    T)
229      TRANSPORT=${OPTARG}
230      ;;
231    :)
232      echo "USAGE: rds_run.sh [-d logdir] [-l packet_loss]" \
233           "[-c packet_corruption] [-u packet_duplicate] [-t timeout]" \
234           "[-T tcp|rdma|tcp,rdma]"
235      exit 1
236      ;;
237    ?)
238      echo "Invalid option: -${OPTARG}."
239      exit 1
240      ;;
241  esac
242done
243
244# Validate transport tokens
245IFS=',' read -ra transports <<< "$TRANSPORT"
246for t in "${transports[@]}"; do
247    if [ "$t" != "tcp" ] && [ "$t" != "rdma" ]; then
248        echo "rds_run.sh: unknown transport '$t' (expected tcp or rdma)"
249        exit 1
250    fi
251done
252
253FLAGS+=("--transport" "${TRANSPORT}")
254
255check_env
256check_conf
257check_gcov_conf
258check_rdma_conf
259
260TRACE_CMD=()
261if [[ -n "$LOG_DIR" ]]; then
262   FLAGS+=("-d" "$LOG_DIR")
263
264   TRACE_FILE="${LOG_DIR}/rds-strace.txt"
265   COVR_DIR="${LOG_DIR}/coverage/"
266   DMESG_FILE="${LOG_DIR}/rds-dmesg.out"
267
268   mkdir -p  "$LOG_DIR"
269   mkdir -p "$COVR_DIR"
270
271   rm -f "$TRACE_FILE"
272   rm -f "$DMESG_FILE"
273   rm -f "$LOG_DIR"/rds-*.pcap
274   rm -f "$COVR_DIR"/gcovr*
275
276   echo "# Traces will be logged to ${TRACE_FILE}"
277   TRACE_CMD=(strace -T -tt -o "${TRACE_FILE}")
278fi
279
280set +e
281echo "# running RDS tests..."
282"${TRACE_CMD[@]}" python3 "$(dirname "$0")/test.py" "${FLAGS[@]}" -t "$TIMEOUT"
283
284test_rc=$?
285
286if [[ -n "$LOG_DIR" ]]; then
287   dmesg > "${DMESG_FILE}"
288fi
289
290if [[ -n "$LOG_DIR" ]] && [ "$GENERATE_GCOV_REPORT" -eq 1 ]; then
291       echo "# saving coverage data..."
292
293       # Ensure debugfs is mounted before reading gcov data.
294       if ! mountpoint -q /sys/kernel/debug 2>/dev/null; then
295               mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null || true
296       fi
297
298       (set +x; cd /sys/kernel/debug/gcov; find ./* -name '*.gcda' | \
299       while read -r f
300       do
301               cat < "/sys/kernel/debug/gcov/$f" > "/$f"
302       done)
303
304       echo "# running gcovr..."
305       gcovr -s --html-details --gcov-executable "$GCOV_CMD" --gcov-ignore-parse-errors \
306             --root "${ksrc_dir}" -o "${COVR_DIR}/gcovr" "${ksrc_dir}/net/rds/" \
307             > "${LOG_DIR}/gcovr.log" 2>&1
308       echo "# gcovr log: ${LOG_DIR}/gcovr.log"
309else
310       echo "# Coverage report will be skipped"
311fi
312
313if [ "$test_rc" -eq 0 ]; then
314	echo "# PASS: Test completed successfully"
315else
316	echo "# FAIL: Test failed"
317fi
318
319exit "$test_rc"
320