Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/env bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This file contains functions and helpers to support the netconsole
5# selftests
6#
7# Author: Breno Leitao <leitao@debian.org>
8
9set -euo pipefail
10
11LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
12
13SRCIF="" # to be populated later
14SRCIP="" # to be populated later
15SRCIP4="192.0.2.1"
16SRCIP6="fc00::1"
17DSTIF="" # to be populated later
18DSTIP="" # to be populated later
19DSTIP4="192.0.2.2"
20DSTIP6="fc00::2"
21
22PORT="6666"
23MSG="netconsole selftest"
24USERDATA_KEY="key"
25USERDATA_VALUE="value"
26TARGET=$(mktemp -u netcons_XXXXX)
27DEFAULT_PRINTK_VALUES=$(cat /proc/sys/kernel/printk)
28NETCONS_CONFIGFS="/sys/kernel/config/netconsole"
29NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
30# NAMESPACE will be populated by setup_ns with a random value
31NAMESPACE=""
32
33# IDs for netdevsim. We either use NSIM_DEV_{1,2}_ID for standard test
34# or NSIM_BOND_{T,R}X_{1,2} for the bonding tests. Not both at the
35# same time.
36NSIM_DEV_1_ID=$((256 + RANDOM % 256))
37NSIM_DEV_2_ID=$((512 + RANDOM % 256))
38NSIM_BOND_TX_1=$((768 + RANDOM % 256))
39NSIM_BOND_TX_2=$((1024 + RANDOM % 256))
40NSIM_BOND_RX_1=$((1280 + RANDOM % 256))
41NSIM_BOND_RX_2=$((1536 + RANDOM % 256))
42NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device"
43NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
44
45# Used to create and delete namespaces
46source "${LIBDIR}"/../../../../net/lib.sh
47
48# Create netdevsim interfaces
49create_ifaces() {
50 echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
51 echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
52 udevadm settle 2> /dev/null || true
53
54 local NSIM1=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_1_ID"
55 local NSIM2=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_2_ID"
56
57 # These are global variables
58 SRCIF=$(find "$NSIM1"/net -maxdepth 1 -type d ! \
59 -path "$NSIM1"/net -exec basename {} \;)
60 DSTIF=$(find "$NSIM2"/net -maxdepth 1 -type d ! \
61 -path "$NSIM2"/net -exec basename {} \;)
62}
63
64link_ifaces() {
65 local NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
66 local SRCIF_IFIDX=$(cat /sys/class/net/"$SRCIF"/ifindex)
67 local DSTIF_IFIDX=$(cat /sys/class/net/"$DSTIF"/ifindex)
68
69 exec {NAMESPACE_FD}</var/run/netns/"${NAMESPACE}"
70 exec {INITNS_FD}</proc/self/ns/net
71
72 # Bind the dst interface to namespace
73 ip link set "${DSTIF}" netns "${NAMESPACE}"
74
75 # Linking one device to the other one (on the other namespace}
76 if ! echo "${INITNS_FD}:$SRCIF_IFIDX $NAMESPACE_FD:$DSTIF_IFIDX" > $NSIM_DEV_SYS_LINK
77 then
78 echo "linking netdevsim1 with netdevsim2 should succeed"
79 cleanup
80 exit "${ksft_skip}"
81 fi
82}
83
84function configure_ip() {
85 # Configure the IPs for both interfaces
86 ip netns exec "${NAMESPACE}" ip addr add "${DSTIP}"/24 dev "${DSTIF}"
87 ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" up
88
89 ip addr add "${SRCIP}"/24 dev "${SRCIF}"
90 ip link set "${SRCIF}" up
91}
92
93function select_ipv4_or_ipv6()
94{
95 local VERSION=${1}
96
97 if [[ "$VERSION" == "ipv6" ]]
98 then
99 DSTIP="${DSTIP6}"
100 SRCIP="${SRCIP6}"
101 else
102 DSTIP="${DSTIP4}"
103 SRCIP="${SRCIP4}"
104 fi
105}
106
107function set_network() {
108 local IP_VERSION=${1:-"ipv4"}
109
110 # setup_ns function is coming from lib.sh
111 setup_ns NAMESPACE
112
113 # Create both interfaces, and assign the destination to a different
114 # namespace
115 create_ifaces
116
117 # Link both interfaces back to back
118 link_ifaces
119
120 select_ipv4_or_ipv6 "${IP_VERSION}"
121 configure_ip
122}
123
124function _create_dynamic_target() {
125 local FORMAT="${1:?FORMAT parameter required}"
126 local NCPATH="${2:?NCPATH parameter required}"
127
128 DSTMAC=$(ip netns exec "${NAMESPACE}" \
129 ip link show "${DSTIF}" | awk '/ether/ {print $2}')
130
131 # Create a dynamic target
132 mkdir "${NCPATH}"
133
134 echo "${DSTIP}" > "${NCPATH}"/remote_ip
135 echo "${SRCIP}" > "${NCPATH}"/local_ip
136 echo "${DSTMAC}" > "${NCPATH}"/remote_mac
137 echo "${SRCIF}" > "${NCPATH}"/dev_name
138
139 if [ "${FORMAT}" == "basic" ]
140 then
141 # Basic target does not support release
142 echo 0 > "${NCPATH}"/release
143 echo 0 > "${NCPATH}"/extended
144 elif [ "${FORMAT}" == "extended" ]
145 then
146 echo 1 > "${NCPATH}"/extended
147 fi
148}
149
150function create_dynamic_target() {
151 local FORMAT=${1:-"extended"}
152 local NCPATH=${2:-"$NETCONS_PATH"}
153 _create_dynamic_target "${FORMAT}" "${NCPATH}"
154
155 echo 1 > "${NCPATH}"/enabled
156
157 # This will make sure that the kernel was able to
158 # load the netconsole driver configuration. The console message
159 # gets more organized/sequential as well.
160 sleep 1
161}
162
163# Generate the command line argument for netconsole following:
164# netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
165function create_cmdline_str() {
166 local BINDMODE=${1:-"ifname"}
167 if [ "${BINDMODE}" == "ifname" ]
168 then
169 SRCDEV=${SRCIF}
170 else
171 SRCDEV=$(mac_get "${SRCIF}")
172 fi
173
174 DSTMAC=$(ip netns exec "${NAMESPACE}" \
175 ip link show "${DSTIF}" | awk '/ether/ {print $2}')
176 SRCPORT="1514"
177 TGTPORT="6666"
178
179 echo "netconsole=\"+${SRCPORT}@${SRCIP}/${SRCDEV},${TGTPORT}@${DSTIP}/${DSTMAC}\""
180}
181
182# Do not append the release to the header of the message
183function disable_release_append() {
184 echo 0 > "${NETCONS_PATH}"/enabled
185 echo 0 > "${NETCONS_PATH}"/release
186 echo 1 > "${NETCONS_PATH}"/enabled
187}
188
189function do_cleanup() {
190 local NSIM_DEV_SYS_DEL="/sys/bus/netdevsim/del_device"
191
192 # Delete netdevsim devices
193 echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_DEL"
194 echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_DEL"
195
196 # this is coming from lib.sh
197 cleanup_all_ns
198
199 # Restoring printk configurations
200 echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
201}
202
203function cleanup_netcons() {
204 # delete netconsole dynamic reconfiguration
205 # do not fail if the target is already disabled
206 local TARGET_PATH=${1:-${NETCONS_PATH}}
207
208 if [[ ! -d "${TARGET_PATH}" ]]
209 then
210 # in some cases this is called before netcons path is created
211 return
212 fi
213 if [[ $(cat "${TARGET_PATH}"/enabled) != 0 ]]
214 then
215 echo 0 > "${TARGET_PATH}"/enabled || true
216 fi
217 # Remove all the keys that got created during the selftest
218 find "${TARGET_PATH}/userdata/" -mindepth 1 -type d -delete
219 # Remove the configfs entry
220 rmdir "${TARGET_PATH}"
221}
222
223function cleanup() {
224 cleanup_netcons
225 do_cleanup
226}
227
228function set_user_data() {
229 if [[ ! -d "${NETCONS_PATH}""/userdata" ]]
230 then
231 echo "Userdata path not available in ${NETCONS_PATH}/userdata"
232 exit "${ksft_skip}"
233 fi
234
235 KEY_PATH="${NETCONS_PATH}/userdata/${USERDATA_KEY}"
236 mkdir -p "${KEY_PATH}"
237 VALUE_PATH="${KEY_PATH}""/value"
238 echo "${USERDATA_VALUE}" > "${VALUE_PATH}"
239}
240
241function listen_port_and_save_to() {
242 local OUTPUT=${1}
243 local IPVERSION=${2:-"ipv4"}
244
245 if [ "${IPVERSION}" == "ipv4" ]
246 then
247 SOCAT_MODE="UDP-LISTEN"
248 else
249 SOCAT_MODE="UDP6-LISTEN"
250 fi
251
252 # Just wait for 3 seconds
253 timeout 3 ip netns exec "${NAMESPACE}" \
254 socat "${SOCAT_MODE}":"${PORT}",fork,shut-none "${OUTPUT}" 2> /dev/null
255}
256
257# Only validate that the message arrived properly
258function validate_msg() {
259 local TMPFILENAME="$1"
260
261 # Check if the file exists
262 if [ ! -f "$TMPFILENAME" ]; then
263 echo "FAIL: File was not generated." >&2
264 exit "${ksft_fail}"
265 fi
266
267 if ! grep -q "${MSG}" "${TMPFILENAME}"; then
268 echo "FAIL: ${MSG} not found in ${TMPFILENAME}" >&2
269 cat "${TMPFILENAME}" >&2
270 exit "${ksft_fail}"
271 fi
272}
273
274# Validate the message and userdata
275function validate_result() {
276 local TMPFILENAME="$1"
277
278 # TMPFILENAME will contain something like:
279 # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM
280 # key=value
281
282 validate_msg "${TMPFILENAME}"
283
284 # userdata is not supported on basic format target,
285 # thus, do not validate it.
286 if [ "${FORMAT}" != "basic" ];
287 then
288 if ! grep -q "${USERDATA_KEY}=${USERDATA_VALUE}" "${TMPFILENAME}"; then
289 echo "FAIL: ${USERDATA_KEY}=${USERDATA_VALUE} not found in ${TMPFILENAME}" >&2
290 cat "${TMPFILENAME}" >&2
291 exit "${ksft_fail}"
292 fi
293 fi
294
295 # Delete the file once it is validated, otherwise keep it
296 # for debugging purposes
297 rm "${TMPFILENAME}"
298}
299
300function check_for_dependencies() {
301 if [ "$(id -u)" -ne 0 ]; then
302 echo "This test must be run as root" >&2
303 exit "${ksft_skip}"
304 fi
305
306 if ! which socat > /dev/null ; then
307 echo "SKIP: socat(1) is not available" >&2
308 exit "${ksft_skip}"
309 fi
310
311 if ! which ip > /dev/null ; then
312 echo "SKIP: ip(1) is not available" >&2
313 exit "${ksft_skip}"
314 fi
315
316 if ! which udevadm > /dev/null ; then
317 echo "SKIP: udevadm(1) is not available" >&2
318 exit "${ksft_skip}"
319 fi
320
321 if [ ! -f /proc/net/if_inet6 ]; then
322 echo "SKIP: IPv6 not configured. Check if CONFIG_IPV6 is enabled" >&2
323 exit "${ksft_skip}"
324 fi
325
326 if [ ! -f "${NSIM_DEV_SYS_NEW}" ]; then
327 echo "SKIP: file ${NSIM_DEV_SYS_NEW} does not exist. Check if CONFIG_NETDEVSIM is enabled" >&2
328 exit "${ksft_skip}"
329 fi
330
331 if [ ! -d "${NETCONS_CONFIGFS}" ]; then
332 echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2
333 exit "${ksft_skip}"
334 fi
335
336 if ip link show "${DSTIF}" 2> /dev/null; then
337 echo "SKIP: interface ${DSTIF} exists in the system. Not overwriting it." >&2
338 exit "${ksft_skip}"
339 fi
340
341 REGEXP4="inet.*(${SRCIP4}|${DSTIP4})"
342 REGEXP6="inet.*(${SRCIP6}|${DSTIP6})"
343 if ip addr list | grep -E "${REGEXP4}" 2> /dev/null; then
344 echo "SKIP: IPv4s already in use. Skipping it" >&2
345 exit "${ksft_skip}"
346 fi
347
348 if ip addr list | grep -E "${REGEXP6}" 2> /dev/null; then
349 echo "SKIP: IPv6s already in use. Skipping it" >&2
350 exit "${ksft_skip}"
351 fi
352}
353
354function check_for_taskset() {
355 if ! which taskset > /dev/null ; then
356 echo "SKIP: taskset(1) is not available" >&2
357 exit "${ksft_skip}"
358 fi
359}
360
361# This is necessary if running multiple tests in a row
362function pkill_socat() {
363 PROCESS_NAME4="socat UDP-LISTEN:6666,fork,shut-none ${OUTPUT_FILE}"
364 PROCESS_NAME6="socat UDP6-LISTEN:6666,fork,shut-none ${OUTPUT_FILE}"
365 # socat runs under timeout(1), kill it if it is still alive
366 # do not fail if socat doesn't exist anymore
367 set +e
368 pkill -f "${PROCESS_NAME4}"
369 pkill -f "${PROCESS_NAME6}"
370 set -e
371}
372
373# Check if netconsole was compiled as a module, otherwise exit
374function check_netconsole_module() {
375 if modinfo netconsole | grep filename: | grep -q builtin
376 then
377 echo "SKIP: netconsole should be compiled as a module" >&2
378 exit "${ksft_skip}"
379 fi
380}
381
382function wait_target_state() {
383 local TARGET=${1}
384 local STATE=${2}
385 local TARGET_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
386 local ENABLED=0
387
388 if [ "${STATE}" == "enabled" ]
389 then
390 ENABLED=1
391 fi
392
393 if [ ! -d "$TARGET_PATH" ]; then
394 echo "FAIL: Target does not exist." >&2
395 exit "${ksft_fail}"
396 fi
397
398 local CHECK_CMD="grep \"$ENABLED\" \"$TARGET_PATH/enabled\""
399 slowwait 2 sh -c "test -n \"\$($CHECK_CMD)\"" || {
400 echo "FAIL: ${TARGET} is not ${STATE}." >&2
401 exit "${ksft_fail}"
402 }
403}
404
405# A wrapper to translate protocol version to udp version
406function wait_for_port() {
407 local NAMESPACE=${1}
408 local PORT=${2}
409 IP_VERSION=${3}
410
411 if [ "${IP_VERSION}" == "ipv6" ]
412 then
413 PROTOCOL="udp6"
414 else
415 PROTOCOL="udp"
416 fi
417
418 wait_local_port_listen "${NAMESPACE}" "${PORT}" "${PROTOCOL}"
419 # even after the port is open, let's wait 1 second before writing
420 # otherwise the packet could be missed, and the test will fail. Happens
421 # more frequently on IPv6
422 sleep 1
423}
424
425# Clean up netdevsim ifaces created for bonding test
426function cleanup_bond_nsim() {
427 ip -n "${TXNS}" \
428 link delete "${BOND_TX_MAIN_IF}" type bond || true
429 ip -n "${RXNS}" \
430 link delete "${BOND_RX_MAIN_IF}" type bond || true
431
432 cleanup_netdevsim "$NSIM_BOND_TX_1"
433 cleanup_netdevsim "$NSIM_BOND_TX_2"
434 cleanup_netdevsim "$NSIM_BOND_RX_1"
435 cleanup_netdevsim "$NSIM_BOND_RX_2"
436}
437
438# cleanup tests that use bonding interfaces
439function cleanup_bond() {
440 cleanup_netcons
441 cleanup_bond_nsim
442 cleanup_all_ns
443 ip link delete "${VETH0}" || true
444}