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