1#!/usr/bin/env bash 2# SPDX-License-Identifier: GPL-2.0 3 4# Exercise the netconsole userdata payload. 5# 6# The first part checks that the payload the target transmits follows what 7# configfs says: a value shows up in the next message, an update replaces the 8# previous one, clearing the value drops the entry, and so does removing the 9# key. 10# 11# The second part rewrites values, creates and deletes keys, and clears the 12# payload entirely while messages are being sent, so the transmit path keeps 13# picking up payloads that are being replaced underneath it. It runs twice, 14# once with a payload small enough to fit in a single packet and once large 15# enough to be fragmented. 16# 17# Author: Breno Leitao <leitao@debian.org> 18 19set -euo pipefail 20 21SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") 22 23source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh 24 25# Number of times each torture worker loops 26ITERATIONS=${1:-200} 27 28# Keys owned by each torture worker. Workers do not share keys, so a failing 29# configfs operation means a real problem and not a lost race. 30CHURN_KEY="churnkey" 31TRANSIENT_KEY="transientkey" 32# Number of keys used to push a message past MAX_PRINT_CHUNK 33BULK_KEYS=8 34 35USERDATA_DIR="${NETCONS_PATH}/userdata" 36# Values are capped at MAX_EXTRADATA_VALUE_LEN(200) bytes, so ${BULK_KEYS} 37# entries of this size are enough to force fragmentation 38LONG_VALUE=$(printf -- 'v%.0s' {1..190}) 39 40function write_key() { 41 local KEY="${1}" 42 local VALUE="${2}" 43 44 mkdir -p "${USERDATA_DIR}/${KEY}" 45 echo "${VALUE}" > "${USERDATA_DIR}/${KEY}/value" 46} 47 48# Send a single message and capture it on the destination interface 49function send_and_capture() { 50 rm -f "${OUTPUT_FILE}" 51 52 listen_port_and_save_to "${OUTPUT_FILE}" & 53 wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}" 54 echo "${MSG}: ${TARGET}" > /dev/kmsg 55 busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" || true 56 pkill_socat 57 validate_msg "${OUTPUT_FILE}" 58} 59 60function expect_in_msg() { 61 local WANTED="${1}" 62 63 if ! grep -q -- "${WANTED}" "${OUTPUT_FILE}"; then 64 echo "FAIL: '${WANTED}' not found in ${OUTPUT_FILE}" >&2 65 cat "${OUTPUT_FILE}" >&2 66 exit "${ksft_fail}" 67 fi 68} 69 70function expect_not_in_msg() { 71 local UNWANTED="${1}" 72 73 if grep -q -- "${UNWANTED}" "${OUTPUT_FILE}"; then 74 echo "FAIL: '${UNWANTED}' found in ${OUTPUT_FILE}" >&2 75 cat "${OUTPUT_FILE}" >&2 76 exit "${ksft_fail}" 77 fi 78} 79 80# Every write publishes a new payload and frees the previous one. An empty 81# value is skipped when the payload is formatted, so this also drives the 82# target through having no payload at all. 83function churn_value() { 84 local i 85 86 for i in $(seq "${ITERATIONS}") 87 do 88 echo "value${i}" > "${USERDATA_DIR}/${CHURN_KEY}/value" 89 echo > "${USERDATA_DIR}/${CHURN_KEY}/value" 90 done 91} 92 93# Create and delete a key underneath the sender 94function churn_key() { 95 local i 96 97 for i in $(seq "${ITERATIONS}") 98 do 99 mkdir "${USERDATA_DIR}/${TRANSIENT_KEY}" 100 echo "transient${i}" > "${USERDATA_DIR}/${TRANSIENT_KEY}/value" 101 rmdir "${USERDATA_DIR}/${TRANSIENT_KEY}" 102 done 103} 104 105# Keep the transmit path busy while the payload is being replaced 106function send_messages() { 107 local i 108 109 for i in $(seq "${ITERATIONS}") 110 do 111 echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg 112 done 113} 114 115# Run the workers concurrently and fail if any of them hits an error 116function run_workers() { 117 local PIDS=() 118 local WORKER 119 local RET=0 120 local PID 121 122 for WORKER in "$@" 123 do 124 "${WORKER}" & 125 PIDS+=("$!") 126 done 127 128 # Reap every worker before reporting a failure, otherwise a surviving 129 # worker keeps writing to configfs while the exit trap cleans it up. 130 for PID in "${PIDS[@]}" 131 do 132 wait "${PID}" || RET=1 133 done 134 135 if [[ "${RET}" -ne 0 ]] 136 then 137 echo "FAIL: userdata torture worker failed" >&2 138 exit "${ksft_fail}" 139 fi 140} 141 142function create_bulk_keys() { 143 local i 144 145 for i in $(seq "${BULK_KEYS}") 146 do 147 write_key "bulk${i}" "${LONG_VALUE}" 148 done 149} 150 151function delete_bulk_keys() { 152 local i 153 154 for i in $(seq "${BULK_KEYS}") 155 do 156 rmdir "${USERDATA_DIR}/bulk${i}" 157 done 158} 159 160# ========== # 161# Start here # 162# ========== # 163 164modprobe netdevsim 2> /dev/null || true 165modprobe netconsole 2> /dev/null || true 166 167IP_VERSION="ipv4" 168# The content of kmsg will be saved to the following file 169OUTPUT_FILE="/tmp/${TARGET}" 170 171# Check for basic system dependency and exit if not found 172check_for_dependencies 173# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) 174echo "6 5" > /proc/sys/kernel/printk 175# Remove the namespace, interfaces and netconsole target on exit 176trap cleanup EXIT 177# Create one namespace and two interfaces 178set_network "${IP_VERSION}" 179# Create a dynamic target for netconsole 180create_dynamic_target 181 182# =================================================== 183# TEST #1 184# A value written to configfs reaches the destination 185# =================================================== 186write_key "${USERDATA_KEY}" "first" 187send_and_capture 188expect_in_msg "${USERDATA_KEY}=first" 189 190# =================================================== 191# TEST #2 192# Updating the value replaces the previous payload 193# =================================================== 194write_key "${USERDATA_KEY}" "second" 195send_and_capture 196expect_in_msg "${USERDATA_KEY}=second" 197expect_not_in_msg "${USERDATA_KEY}=first" 198 199# =================================================== 200# TEST #3 201# Clearing the value drops the entry 202# =================================================== 203echo > "${USERDATA_DIR}/${USERDATA_KEY}/value" 204send_and_capture 205expect_not_in_msg "${USERDATA_KEY}=" 206 207# =================================================== 208# TEST #4 209# Removing the key drops the entry 210# =================================================== 211write_key "${USERDATA_KEY}" "third" 212rmdir "${USERDATA_DIR}/${USERDATA_KEY}" 213send_and_capture 214expect_not_in_msg "${USERDATA_KEY}=" 215rm "${OUTPUT_FILE}" 216 217# =================================================== 218# TEST #5 219# Torture the payload while messages are being sent, 220# first unfragmented and then fragmented 221# =================================================== 222write_key "${CHURN_KEY}" "${USERDATA_VALUE}" 223run_workers churn_value churn_key send_messages 224 225create_bulk_keys 226run_workers churn_value churn_key send_messages 227delete_bulk_keys 228 229exit "${ksft_pass}" 230