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 DSTMAC=$(ip netns exec "${NAMESPACE}" \ 99 ip link show "${DSTIF}" | awk '/ether/ {print $2}') 100 101 # Create a dynamic target 102 mkdir "${NETCONS_PATH}" 103 104 echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip 105 echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip 106 echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac 107 echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name 108 109 echo 1 > "${NETCONS_PATH}"/enabled 110} 111 112# Do not append the release to the header of the message 113function disable_release_append() { 114 echo 0 > "${NETCONS_PATH}"/enabled 115 echo 0 > "${NETCONS_PATH}"/release 116 echo 1 > "${NETCONS_PATH}"/enabled 117} 118 119function cleanup() { 120 local NSIM_DEV_SYS_DEL="/sys/bus/netdevsim/del_device" 121 122 # delete netconsole dynamic reconfiguration 123 echo 0 > "${NETCONS_PATH}"/enabled 124 # Remove all the keys that got created during the selftest 125 find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete 126 # Remove the configfs entry 127 rmdir "${NETCONS_PATH}" 128 129 # Delete netdevsim devices 130 echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_DEL" 131 echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_DEL" 132 133 # this is coming from lib.sh 134 cleanup_all_ns 135 136 # Restoring printk configurations 137 echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk 138} 139 140function set_user_data() { 141 if [[ ! -d "${NETCONS_PATH}""/userdata" ]] 142 then 143 echo "Userdata path not available in ${NETCONS_PATH}/userdata" 144 exit "${ksft_skip}" 145 fi 146 147 KEY_PATH="${NETCONS_PATH}/userdata/${USERDATA_KEY}" 148 mkdir -p "${KEY_PATH}" 149 VALUE_PATH="${KEY_PATH}""/value" 150 echo "${USERDATA_VALUE}" > "${VALUE_PATH}" 151} 152 153function listen_port_and_save_to() { 154 local OUTPUT=${1} 155 # Just wait for 2 seconds 156 timeout 2 ip netns exec "${NAMESPACE}" \ 157 socat UDP-LISTEN:"${PORT}",fork "${OUTPUT}" 158} 159 160function validate_result() { 161 local TMPFILENAME="$1" 162 163 # TMPFILENAME will contain something like: 164 # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM 165 # key=value 166 167 # Check if the file exists 168 if [ ! -f "$TMPFILENAME" ]; then 169 echo "FAIL: File was not generated." >&2 170 exit "${ksft_fail}" 171 fi 172 173 if ! grep -q "${MSG}" "${TMPFILENAME}"; then 174 echo "FAIL: ${MSG} not found in ${TMPFILENAME}" >&2 175 cat "${TMPFILENAME}" >&2 176 exit "${ksft_fail}" 177 fi 178 179 if ! grep -q "${USERDATA_KEY}=${USERDATA_VALUE}" "${TMPFILENAME}"; then 180 echo "FAIL: ${USERDATA_KEY}=${USERDATA_VALUE} not found in ${TMPFILENAME}" >&2 181 cat "${TMPFILENAME}" >&2 182 exit "${ksft_fail}" 183 fi 184 185 # Delete the file once it is validated, otherwise keep it 186 # for debugging purposes 187 rm "${TMPFILENAME}" 188 exit "${ksft_pass}" 189} 190 191function check_for_dependencies() { 192 if [ "$(id -u)" -ne 0 ]; then 193 echo "This test must be run as root" >&2 194 exit "${ksft_skip}" 195 fi 196 197 if ! which socat > /dev/null ; then 198 echo "SKIP: socat(1) is not available" >&2 199 exit "${ksft_skip}" 200 fi 201 202 if ! which ip > /dev/null ; then 203 echo "SKIP: ip(1) is not available" >&2 204 exit "${ksft_skip}" 205 fi 206 207 if ! which udevadm > /dev/null ; then 208 echo "SKIP: udevadm(1) is not available" >&2 209 exit "${ksft_skip}" 210 fi 211 212 if [ ! -f "${NSIM_DEV_SYS_NEW}" ]; then 213 echo "SKIP: file ${NSIM_DEV_SYS_NEW} does not exist. Check if CONFIG_NETDEVSIM is enabled" >&2 214 exit "${ksft_skip}" 215 fi 216 217 if [ ! -d "${NETCONS_CONFIGFS}" ]; then 218 echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2 219 exit "${ksft_skip}" 220 fi 221 222 if ip link show "${DSTIF}" 2> /dev/null; then 223 echo "SKIP: interface ${DSTIF} exists in the system. Not overwriting it." >&2 224 exit "${ksft_skip}" 225 fi 226 227 if ip addr list | grep -E "inet.*(${SRCIP}|${DSTIP})" 2> /dev/null; then 228 echo "SKIP: IPs already in use. Skipping it" >&2 229 exit "${ksft_skip}" 230 fi 231} 232 233function check_for_taskset() { 234 if ! which taskset > /dev/null ; then 235 echo "SKIP: taskset(1) is not available" >&2 236 exit "${ksft_skip}" 237 fi 238} 239 240# This is necessary if running multiple tests in a row 241function pkill_socat() { 242 PROCESS_NAME="socat UDP-LISTEN:6666,fork ${OUTPUT_FILE}" 243 # socat runs under timeout(1), kill it if it is still alive 244 # do not fail if socat doesn't exist anymore 245 set +e 246 pkill -f "${PROCESS_NAME}" 247 set -e 248} 249