229 lines · 6.0 KB · Shell
RawDownload
#!/usr/bin/env bash# SPDX-License-Identifier: GPL-2.0 # Exercise the netconsole userdata payload.## The first part checks that the payload the target transmits follows what# configfs says: a value shows up in the next message, an update replaces the# previous one, clearing the value drops the entry, and so does removing the# key.## The second part rewrites values, creates and deletes keys, and clears the# payload entirely while messages are being sent, so the transmit path keeps# picking up payloads that are being replaced underneath it. It runs twice,# once with a payload small enough to fit in a single packet and once large# enough to be fragmented.## Author: Breno Leitao <leitao@debian.org> set -euo pipefail SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh # Number of times each torture worker loopsITERATIONS=${1:-200} # Keys owned by each torture worker. Workers do not share keys, so a failing# configfs operation means a real problem and not a lost race.CHURN_KEY="churnkey"TRANSIENT_KEY="transientkey"# Number of keys used to push a message past MAX_PRINT_CHUNKBULK_KEYS=8 USERDATA_DIR="${NETCONS_PATH}/userdata"# Values are capped at MAX_EXTRADATA_VALUE_LEN(200) bytes, so ${BULK_KEYS}# entries of this size are enough to force fragmentationLONG_VALUE=$(printf -- 'v%.0s' {1..190}) function write_key() {	local KEY="${1}"	local VALUE="${2}" 	mkdir -p "${USERDATA_DIR}/${KEY}"	echo "${VALUE}" > "${USERDATA_DIR}/${KEY}/value"} # Send a single message and capture it on the destination interfacefunction send_and_capture() {	rm -f "${OUTPUT_FILE}" 	listen_port_and_save_to "${OUTPUT_FILE}" &	wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}"	echo "${MSG}: ${TARGET}" > /dev/kmsg	busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" || true	pkill_socat	validate_msg "${OUTPUT_FILE}"} function expect_in_msg() {	local WANTED="${1}" 	if ! grep -q -- "${WANTED}" "${OUTPUT_FILE}"; then		echo "FAIL: '${WANTED}' not found in ${OUTPUT_FILE}" >&2		cat "${OUTPUT_FILE}" >&2		exit "${ksft_fail}"	fi} function expect_not_in_msg() {	local UNWANTED="${1}" 	if grep -q -- "${UNWANTED}" "${OUTPUT_FILE}"; then		echo "FAIL: '${UNWANTED}' found in ${OUTPUT_FILE}" >&2		cat "${OUTPUT_FILE}" >&2		exit "${ksft_fail}"	fi} # Every write publishes a new payload and frees the previous one. An empty# value is skipped when the payload is formatted, so this also drives the# target through having no payload at all.function churn_value() {	local i 	for i in $(seq "${ITERATIONS}")	do		echo "value${i}" > "${USERDATA_DIR}/${CHURN_KEY}/value"		echo > "${USERDATA_DIR}/${CHURN_KEY}/value"	done} # Create and delete a key underneath the senderfunction churn_key() {	local i 	for i in $(seq "${ITERATIONS}")	do		mkdir "${USERDATA_DIR}/${TRANSIENT_KEY}"		echo "transient${i}" > "${USERDATA_DIR}/${TRANSIENT_KEY}/value"		rmdir "${USERDATA_DIR}/${TRANSIENT_KEY}"	done} # Keep the transmit path busy while the payload is being replacedfunction send_messages() {	local i 	for i in $(seq "${ITERATIONS}")	do		echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg	done} # Run the workers concurrently and fail if any of them hits an errorfunction run_workers() {	local PIDS=()	local WORKER	local RET=0	local PID 	for WORKER in "$@"	do		"${WORKER}" &		PIDS+=("$!")	done 	# Reap every worker before reporting a failure, otherwise a surviving	# worker keeps writing to configfs while the exit trap cleans it up.	for PID in "${PIDS[@]}"	do		wait "${PID}" || RET=1	done 	if [[ "${RET}" -ne 0 ]]	then		echo "FAIL: userdata torture worker failed" >&2		exit "${ksft_fail}"	fi} function create_bulk_keys() {	local i 	for i in $(seq "${BULK_KEYS}")	do		write_key "bulk${i}" "${LONG_VALUE}"	done} function delete_bulk_keys() {	local i 	for i in $(seq "${BULK_KEYS}")	do		rmdir "${USERDATA_DIR}/bulk${i}"	done} # ========== ## Start here ## ========== # modprobe netdevsim 2> /dev/null || truemodprobe netconsole 2> /dev/null || true IP_VERSION="ipv4"# The content of kmsg will be saved to the following fileOUTPUT_FILE="/tmp/${TARGET}" # Check for basic system dependency and exit if not foundcheck_for_dependencies# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)echo "6 5" > /proc/sys/kernel/printk# Remove the namespace, interfaces and netconsole target on exittrap cleanup EXIT# Create one namespace and two interfacesset_network "${IP_VERSION}"# Create a dynamic target for netconsolecreate_dynamic_target # ===================================================# TEST #1# A value written to configfs reaches the destination# ===================================================write_key "${USERDATA_KEY}" "first"send_and_captureexpect_in_msg "${USERDATA_KEY}=first" # ===================================================# TEST #2# Updating the value replaces the previous payload# ===================================================write_key "${USERDATA_KEY}" "second"send_and_captureexpect_in_msg "${USERDATA_KEY}=second"expect_not_in_msg "${USERDATA_KEY}=first" # ===================================================# TEST #3# Clearing the value drops the entry# ===================================================echo > "${USERDATA_DIR}/${USERDATA_KEY}/value"send_and_captureexpect_not_in_msg "${USERDATA_KEY}=" # ===================================================# TEST #4# Removing the key drops the entry# ===================================================write_key "${USERDATA_KEY}" "third"rmdir "${USERDATA_DIR}/${USERDATA_KEY}"send_and_captureexpect_not_in_msg "${USERDATA_KEY}="rm "${OUTPUT_FILE}" # ===================================================# TEST #5# Torture the payload while messages are being sent,# first unfragmented and then fragmented# ===================================================write_key "${CHURN_KEY}" "${USERDATA_VALUE}"run_workers churn_value churn_key send_messages create_bulk_keysrun_workers churn_value churn_key send_messagesdelete_bulk_keys exit "${ksft_pass}"