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=192.0.2.1 15DSTIF="" # to be populated later 16DSTIP=192.0.2.2 17 18PORT="6666" 19MSG="netconsole selftest" 20USERDATA_KEY="key" 21USERDATA_VALUE="value" 22TARGET=$(mktemp -u netcons_XXXXX) 23DEFAULT_PRINTK_VALUES=$(cat /proc/sys/kernel/printk) 24NETCONS_CONFIGFS="/sys/kernel/config/netconsole" 25NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}" 26# NAMESPACE will be populated by setup_ns with a random value 27NAMESPACE="" 28 29# IDs for netdevsim 30NSIM_DEV_1_ID=$((256 + RANDOM % 256)) 31NSIM_DEV_2_ID=$((512 + RANDOM % 256)) 32NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device" 33 34# Used to create and delete namespaces 35source "${LIBDIR}"/../../../../net/lib.sh 36 37# Create netdevsim interfaces 38create_ifaces() { 39 40 echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW" 41 echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW" 42 udevadm settle 2> /dev/null || true 43 44 local NSIM1=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_1_ID" 45 local NSIM2=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_2_ID" 46 47 # These are global variables 48 SRCIF=$(find "$NSIM1"/net -maxdepth 1 -type d ! \ 49 -path "$NSIM1"/net -exec basename {} \;) 50 DSTIF=$(find "$NSIM2"/net -maxdepth 1 -type d ! \ 51 -path "$NSIM2"/net -exec basename {} \;) 52} 53 54link_ifaces() { 55 local NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device" 56 local SRCIF_IFIDX=$(cat /sys/class/net/"$SRCIF"/ifindex) 57 local DSTIF_IFIDX=$(cat /sys/class/net/"$DSTIF"/ifindex) 58 59 exec {NAMESPACE_FD}</var/run/netns/"${NAMESPACE}" 60 exec {INITNS_FD}</proc/self/ns/net 61 62 # Bind the dst interface to namespace 63 ip link set "${DSTIF}" netns "${NAMESPACE}" 64 65 # Linking one device to the other one (on the other namespace} 66 if ! echo "${INITNS_FD}:$SRCIF_IFIDX $NAMESPACE_FD:$DSTIF_IFIDX" > $NSIM_DEV_SYS_LINK 67 then 68 echo "linking netdevsim1 with netdevsim2 should succeed" 69 cleanup 70 exit "${ksft_skip}" 71 fi 72} 73 74function configure_ip() { 75 # Configure the IPs for both interfaces 76 ip netns exec "${NAMESPACE}" ip addr add "${DSTIP}"/24 dev "${DSTIF}" 77 ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" up 78 79 ip addr add "${SRCIP}"/24 dev "${SRCIF}" 80 ip link set "${SRCIF}" up 81} 82 83function set_network() { 84 # setup_ns function is coming from lib.sh 85 setup_ns NAMESPACE 86 87 # Create both interfaces, and assign the destination to a different 88 # namespace 89 create_ifaces 90 91 # Link both interfaces back to back 92 link_ifaces 93 94 configure_ip 95} 96 97function create_dynamic_target() { 98 local FORMAT=${1:-"extended"} 99 100 DSTMAC=$(ip netns exec "${NAMESPACE}" \ 101 ip link show "${DSTIF}" | awk '/ether/ {print $2}') 102 103 # Create a dynamic target 104 mkdir "${NETCONS_PATH}" 105 106 echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip 107 echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip 108 echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac 109 echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name 110 111 if [ "${FORMAT}" == "basic" ] 112 then 113 # Basic target does not support release 114 echo 0 > "${NETCONS_PATH}"/release 115 echo 0 > "${NETCONS_PATH}"/extended 116 elif [ "${FORMAT}" == "extended" ] 117 then 118 echo 1 > "${NETCONS_PATH}"/extended 119 fi 120 121 echo 1 > "${NETCONS_PATH}"/enabled 122} 123 124# Generate the command line argument for netconsole following: 125# netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr] 126function create_cmdline_str() { 127 DSTMAC=$(ip netns exec "${NAMESPACE}" \ 128 ip link show "${DSTIF}" | awk '/ether/ {print $2}') 129 SRCPORT="1514" 130 TGTPORT="6666" 131 132 echo "netconsole=\"+${SRCPORT}@${SRCIP}/${SRCIF},${TGTPORT}@${DSTIP}/${DSTMAC}\"" 133} 134 135# Do not append the release to the header of the message 136function disable_release_append() { 137 echo 0 > "${NETCONS_PATH}"/enabled 138 echo 0 > "${NETCONS_PATH}"/release 139 echo 1 > "${NETCONS_PATH}"/enabled 140} 141 142function do_cleanup() { 143 local NSIM_DEV_SYS_DEL="/sys/bus/netdevsim/del_device" 144 145 # Delete netdevsim devices 146 echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_DEL" 147 echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_DEL" 148 149 # this is coming from lib.sh 150 cleanup_all_ns 151 152 # Restoring printk configurations 153 echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk 154} 155 156function cleanup() { 157 # delete netconsole dynamic reconfiguration 158 echo 0 > "${NETCONS_PATH}"/enabled 159 # Remove all the keys that got created during the selftest 160 find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete 161 # Remove the configfs entry 162 rmdir "${NETCONS_PATH}" 163 164 do_cleanup 165} 166 167function set_user_data() { 168 if [[ ! -d "${NETCONS_PATH}""/userdata" ]] 169 then 170 echo "Userdata path not available in ${NETCONS_PATH}/userdata" 171 exit "${ksft_skip}" 172 fi 173 174 KEY_PATH="${NETCONS_PATH}/userdata/${USERDATA_KEY}" 175 mkdir -p "${KEY_PATH}" 176 VALUE_PATH="${KEY_PATH}""/value" 177 echo "${USERDATA_VALUE}" > "${VALUE_PATH}" 178} 179 180function listen_port_and_save_to() { 181 local OUTPUT=${1} 182 # Just wait for 2 seconds 183 timeout 2 ip netns exec "${NAMESPACE}" \ 184 socat UDP-LISTEN:"${PORT}",fork "${OUTPUT}" 185} 186 187# Only validate that the message arrived properly 188function validate_msg() { 189 local TMPFILENAME="$1" 190 191 # Check if the file exists 192 if [ ! -f "$TMPFILENAME" ]; then 193 echo "FAIL: File was not generated." >&2 194 exit "${ksft_fail}" 195 fi 196 197 if ! grep -q "${MSG}" "${TMPFILENAME}"; then 198 echo "FAIL: ${MSG} not found in ${TMPFILENAME}" >&2 199 cat "${TMPFILENAME}" >&2 200 exit "${ksft_fail}" 201 fi 202} 203 204# Validate the message and userdata 205function validate_result() { 206 local TMPFILENAME="$1" 207 208 # TMPFILENAME will contain something like: 209 # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM 210 # key=value 211 212 validate_msg "${TMPFILENAME}" 213 214 # userdata is not supported on basic format target, 215 # thus, do not validate it. 216 if [ "${FORMAT}" != "basic" ]; 217 then 218 if ! grep -q "${USERDATA_KEY}=${USERDATA_VALUE}" "${TMPFILENAME}"; then 219 echo "FAIL: ${USERDATA_KEY}=${USERDATA_VALUE} not found in ${TMPFILENAME}" >&2 220 cat "${TMPFILENAME}" >&2 221 exit "${ksft_fail}" 222 fi 223 fi 224 225 # Delete the file once it is validated, otherwise keep it 226 # for debugging purposes 227 rm "${TMPFILENAME}" 228} 229 230function check_for_dependencies() { 231 if [ "$(id -u)" -ne 0 ]; then 232 echo "This test must be run as root" >&2 233 exit "${ksft_skip}" 234 fi 235 236 if ! which socat > /dev/null ; then 237 echo "SKIP: socat(1) is not available" >&2 238 exit "${ksft_skip}" 239 fi 240 241 if ! which ip > /dev/null ; then 242 echo "SKIP: ip(1) is not available" >&2 243 exit "${ksft_skip}" 244 fi 245 246 if ! which udevadm > /dev/null ; then 247 echo "SKIP: udevadm(1) is not available" >&2 248 exit "${ksft_skip}" 249 fi 250 251 if [ ! -f "${NSIM_DEV_SYS_NEW}" ]; then 252 echo "SKIP: file ${NSIM_DEV_SYS_NEW} does not exist. Check if CONFIG_NETDEVSIM is enabled" >&2 253 exit "${ksft_skip}" 254 fi 255 256 if [ ! -d "${NETCONS_CONFIGFS}" ]; then 257 echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2 258 exit "${ksft_skip}" 259 fi 260 261 if ip link show "${DSTIF}" 2> /dev/null; then 262 echo "SKIP: interface ${DSTIF} exists in the system. Not overwriting it." >&2 263 exit "${ksft_skip}" 264 fi 265 266 if ip addr list | grep -E "inet.*(${SRCIP}|${DSTIP})" 2> /dev/null; then 267 echo "SKIP: IPs already in use. Skipping it" >&2 268 exit "${ksft_skip}" 269 fi 270} 271 272function check_for_taskset() { 273 if ! which taskset > /dev/null ; then 274 echo "SKIP: taskset(1) is not available" >&2 275 exit "${ksft_skip}" 276 fi 277} 278 279# This is necessary if running multiple tests in a row 280function pkill_socat() { 281 PROCESS_NAME="socat UDP-LISTEN:6666,fork ${OUTPUT_FILE}" 282 # socat runs under timeout(1), kill it if it is still alive 283 # do not fail if socat doesn't exist anymore 284 set +e 285 pkill -f "${PROCESS_NAME}" 286 set -e 287} 288 289# Check if netconsole was compiled as a module, otherwise exit 290function check_netconsole_module() { 291 if modinfo netconsole | grep filename: | grep -q builtin 292 then 293 echo "SKIP: netconsole should be compiled as a module" >&2 294 exit "${ksft_skip}" 295 fi 296} 297