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