mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-04-19 03:53:51 -04:00
Extend the existing netconsole cmdline selftest to also validate that interface selection can be performed via MAC address. The test now validates that netconsole works with both interface name and MAC address, improving test coverage. Suggested-by: Breno Leitao <leitao@debian.org> Reviewed-by: Breno Leitao <leitao@debian.org> Signed-off-by: Andre Carvalho <asantostc@gmail.com> Link: https://patch.msgid.link/20250812-netcons-cmdline-selftest-v2-1-8099fb7afa9e@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
372 lines
9.3 KiB
Bash
372 lines
9.3 KiB
Bash
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
# This file contains functions and helpers to support the netconsole
|
|
# selftests
|
|
#
|
|
# Author: Breno Leitao <leitao@debian.org>
|
|
|
|
set -euo pipefail
|
|
|
|
LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
|
|
|
|
SRCIF="" # to be populated later
|
|
SRCIP4="192.0.2.1"
|
|
SRCIP6="fc00::1"
|
|
DSTIF="" # to be populated later
|
|
DSTIP4="192.0.2.2"
|
|
DSTIP6="fc00::2"
|
|
|
|
PORT="6666"
|
|
MSG="netconsole selftest"
|
|
USERDATA_KEY="key"
|
|
USERDATA_VALUE="value"
|
|
TARGET=$(mktemp -u netcons_XXXXX)
|
|
DEFAULT_PRINTK_VALUES=$(cat /proc/sys/kernel/printk)
|
|
NETCONS_CONFIGFS="/sys/kernel/config/netconsole"
|
|
NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
|
|
# NAMESPACE will be populated by setup_ns with a random value
|
|
NAMESPACE=""
|
|
|
|
# IDs for netdevsim
|
|
NSIM_DEV_1_ID=$((256 + RANDOM % 256))
|
|
NSIM_DEV_2_ID=$((512 + RANDOM % 256))
|
|
NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device"
|
|
|
|
# Used to create and delete namespaces
|
|
source "${LIBDIR}"/../../../../net/lib.sh
|
|
|
|
# Create netdevsim interfaces
|
|
create_ifaces() {
|
|
|
|
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
|
|
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
|
|
udevadm settle 2> /dev/null || true
|
|
|
|
local NSIM1=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_1_ID"
|
|
local NSIM2=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_2_ID"
|
|
|
|
# These are global variables
|
|
SRCIF=$(find "$NSIM1"/net -maxdepth 1 -type d ! \
|
|
-path "$NSIM1"/net -exec basename {} \;)
|
|
DSTIF=$(find "$NSIM2"/net -maxdepth 1 -type d ! \
|
|
-path "$NSIM2"/net -exec basename {} \;)
|
|
}
|
|
|
|
link_ifaces() {
|
|
local NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
|
|
local SRCIF_IFIDX=$(cat /sys/class/net/"$SRCIF"/ifindex)
|
|
local DSTIF_IFIDX=$(cat /sys/class/net/"$DSTIF"/ifindex)
|
|
|
|
exec {NAMESPACE_FD}</var/run/netns/"${NAMESPACE}"
|
|
exec {INITNS_FD}</proc/self/ns/net
|
|
|
|
# Bind the dst interface to namespace
|
|
ip link set "${DSTIF}" netns "${NAMESPACE}"
|
|
|
|
# Linking one device to the other one (on the other namespace}
|
|
if ! echo "${INITNS_FD}:$SRCIF_IFIDX $NAMESPACE_FD:$DSTIF_IFIDX" > $NSIM_DEV_SYS_LINK
|
|
then
|
|
echo "linking netdevsim1 with netdevsim2 should succeed"
|
|
cleanup
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
function configure_ip() {
|
|
# Configure the IPs for both interfaces
|
|
ip netns exec "${NAMESPACE}" ip addr add "${DSTIP}"/24 dev "${DSTIF}"
|
|
ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" up
|
|
|
|
ip addr add "${SRCIP}"/24 dev "${SRCIF}"
|
|
ip link set "${SRCIF}" up
|
|
}
|
|
|
|
function select_ipv4_or_ipv6()
|
|
{
|
|
local VERSION=${1}
|
|
|
|
if [[ "$VERSION" == "ipv6" ]]
|
|
then
|
|
DSTIP="${DSTIP6}"
|
|
SRCIP="${SRCIP6}"
|
|
else
|
|
DSTIP="${DSTIP4}"
|
|
SRCIP="${SRCIP4}"
|
|
fi
|
|
}
|
|
|
|
function set_network() {
|
|
local IP_VERSION=${1:-"ipv4"}
|
|
|
|
# setup_ns function is coming from lib.sh
|
|
setup_ns NAMESPACE
|
|
|
|
# Create both interfaces, and assign the destination to a different
|
|
# namespace
|
|
create_ifaces
|
|
|
|
# Link both interfaces back to back
|
|
link_ifaces
|
|
|
|
select_ipv4_or_ipv6 "${IP_VERSION}"
|
|
configure_ip
|
|
}
|
|
|
|
function create_dynamic_target() {
|
|
local FORMAT=${1:-"extended"}
|
|
|
|
DSTMAC=$(ip netns exec "${NAMESPACE}" \
|
|
ip link show "${DSTIF}" | awk '/ether/ {print $2}')
|
|
|
|
# Create a dynamic target
|
|
mkdir "${NETCONS_PATH}"
|
|
|
|
echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip
|
|
echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip
|
|
echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac
|
|
echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name
|
|
|
|
if [ "${FORMAT}" == "basic" ]
|
|
then
|
|
# Basic target does not support release
|
|
echo 0 > "${NETCONS_PATH}"/release
|
|
echo 0 > "${NETCONS_PATH}"/extended
|
|
elif [ "${FORMAT}" == "extended" ]
|
|
then
|
|
echo 1 > "${NETCONS_PATH}"/extended
|
|
fi
|
|
|
|
echo 1 > "${NETCONS_PATH}"/enabled
|
|
|
|
# This will make sure that the kernel was able to
|
|
# load the netconsole driver configuration. The console message
|
|
# gets more organized/sequential as well.
|
|
sleep 1
|
|
}
|
|
|
|
# Generate the command line argument for netconsole following:
|
|
# netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
|
|
function create_cmdline_str() {
|
|
local BINDMODE=${1:-"ifname"}
|
|
if [ "${BINDMODE}" == "ifname" ]
|
|
then
|
|
SRCDEV=${SRCIF}
|
|
else
|
|
SRCDEV=$(mac_get "${SRCIF}")
|
|
fi
|
|
|
|
DSTMAC=$(ip netns exec "${NAMESPACE}" \
|
|
ip link show "${DSTIF}" | awk '/ether/ {print $2}')
|
|
SRCPORT="1514"
|
|
TGTPORT="6666"
|
|
|
|
echo "netconsole=\"+${SRCPORT}@${SRCIP}/${SRCDEV},${TGTPORT}@${DSTIP}/${DSTMAC}\""
|
|
}
|
|
|
|
# Do not append the release to the header of the message
|
|
function disable_release_append() {
|
|
echo 0 > "${NETCONS_PATH}"/enabled
|
|
echo 0 > "${NETCONS_PATH}"/release
|
|
echo 1 > "${NETCONS_PATH}"/enabled
|
|
}
|
|
|
|
function do_cleanup() {
|
|
local NSIM_DEV_SYS_DEL="/sys/bus/netdevsim/del_device"
|
|
|
|
# Delete netdevsim devices
|
|
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_DEL"
|
|
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_DEL"
|
|
|
|
# this is coming from lib.sh
|
|
cleanup_all_ns
|
|
|
|
# Restoring printk configurations
|
|
echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
|
|
}
|
|
|
|
function cleanup() {
|
|
# delete netconsole dynamic reconfiguration
|
|
echo 0 > "${NETCONS_PATH}"/enabled
|
|
# Remove all the keys that got created during the selftest
|
|
find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete
|
|
# Remove the configfs entry
|
|
rmdir "${NETCONS_PATH}"
|
|
|
|
do_cleanup
|
|
}
|
|
|
|
function set_user_data() {
|
|
if [[ ! -d "${NETCONS_PATH}""/userdata" ]]
|
|
then
|
|
echo "Userdata path not available in ${NETCONS_PATH}/userdata"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
KEY_PATH="${NETCONS_PATH}/userdata/${USERDATA_KEY}"
|
|
mkdir -p "${KEY_PATH}"
|
|
VALUE_PATH="${KEY_PATH}""/value"
|
|
echo "${USERDATA_VALUE}" > "${VALUE_PATH}"
|
|
}
|
|
|
|
function listen_port_and_save_to() {
|
|
local OUTPUT=${1}
|
|
local IPVERSION=${2:-"ipv4"}
|
|
|
|
if [ "${IPVERSION}" == "ipv4" ]
|
|
then
|
|
SOCAT_MODE="UDP-LISTEN"
|
|
else
|
|
SOCAT_MODE="UDP6-LISTEN"
|
|
fi
|
|
|
|
# Just wait for 2 seconds
|
|
timeout 2 ip netns exec "${NAMESPACE}" \
|
|
socat "${SOCAT_MODE}":"${PORT}",fork "${OUTPUT}"
|
|
}
|
|
|
|
# Only validate that the message arrived properly
|
|
function validate_msg() {
|
|
local TMPFILENAME="$1"
|
|
|
|
# Check if the file exists
|
|
if [ ! -f "$TMPFILENAME" ]; then
|
|
echo "FAIL: File was not generated." >&2
|
|
exit "${ksft_fail}"
|
|
fi
|
|
|
|
if ! grep -q "${MSG}" "${TMPFILENAME}"; then
|
|
echo "FAIL: ${MSG} not found in ${TMPFILENAME}" >&2
|
|
cat "${TMPFILENAME}" >&2
|
|
exit "${ksft_fail}"
|
|
fi
|
|
}
|
|
|
|
# Validate the message and userdata
|
|
function validate_result() {
|
|
local TMPFILENAME="$1"
|
|
|
|
# TMPFILENAME will contain something like:
|
|
# 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM
|
|
# key=value
|
|
|
|
validate_msg "${TMPFILENAME}"
|
|
|
|
# userdata is not supported on basic format target,
|
|
# thus, do not validate it.
|
|
if [ "${FORMAT}" != "basic" ];
|
|
then
|
|
if ! grep -q "${USERDATA_KEY}=${USERDATA_VALUE}" "${TMPFILENAME}"; then
|
|
echo "FAIL: ${USERDATA_KEY}=${USERDATA_VALUE} not found in ${TMPFILENAME}" >&2
|
|
cat "${TMPFILENAME}" >&2
|
|
exit "${ksft_fail}"
|
|
fi
|
|
fi
|
|
|
|
# Delete the file once it is validated, otherwise keep it
|
|
# for debugging purposes
|
|
rm "${TMPFILENAME}"
|
|
}
|
|
|
|
function check_for_dependencies() {
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "This test must be run as root" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if ! which socat > /dev/null ; then
|
|
echo "SKIP: socat(1) is not available" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if ! which ip > /dev/null ; then
|
|
echo "SKIP: ip(1) is not available" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if ! which udevadm > /dev/null ; then
|
|
echo "SKIP: udevadm(1) is not available" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if [ ! -f /proc/net/if_inet6 ]; then
|
|
echo "SKIP: IPv6 not configured. Check if CONFIG_IPV6 is enabled" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if [ ! -f "${NSIM_DEV_SYS_NEW}" ]; then
|
|
echo "SKIP: file ${NSIM_DEV_SYS_NEW} does not exist. Check if CONFIG_NETDEVSIM is enabled" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if [ ! -d "${NETCONS_CONFIGFS}" ]; then
|
|
echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if ip link show "${DSTIF}" 2> /dev/null; then
|
|
echo "SKIP: interface ${DSTIF} exists in the system. Not overwriting it." >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
REGEXP4="inet.*(${SRCIP4}|${DSTIP4})"
|
|
REGEXP6="inet.*(${SRCIP6}|${DSTIP6})"
|
|
if ip addr list | grep -E "${REGEXP4}" 2> /dev/null; then
|
|
echo "SKIP: IPv4s already in use. Skipping it" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
if ip addr list | grep -E "${REGEXP6}" 2> /dev/null; then
|
|
echo "SKIP: IPv6s already in use. Skipping it" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
function check_for_taskset() {
|
|
if ! which taskset > /dev/null ; then
|
|
echo "SKIP: taskset(1) is not available" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
# This is necessary if running multiple tests in a row
|
|
function pkill_socat() {
|
|
PROCESS_NAME4="socat UDP-LISTEN:6666,fork ${OUTPUT_FILE}"
|
|
PROCESS_NAME6="socat UDP6-LISTEN:6666,fork ${OUTPUT_FILE}"
|
|
# socat runs under timeout(1), kill it if it is still alive
|
|
# do not fail if socat doesn't exist anymore
|
|
set +e
|
|
pkill -f "${PROCESS_NAME4}"
|
|
pkill -f "${PROCESS_NAME6}"
|
|
set -e
|
|
}
|
|
|
|
# Check if netconsole was compiled as a module, otherwise exit
|
|
function check_netconsole_module() {
|
|
if modinfo netconsole | grep filename: | grep -q builtin
|
|
then
|
|
echo "SKIP: netconsole should be compiled as a module" >&2
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
# A wrapper to translate protocol version to udp version
|
|
function wait_for_port() {
|
|
local NAMESPACE=${1}
|
|
local PORT=${2}
|
|
IP_VERSION=${3}
|
|
|
|
if [ "${IP_VERSION}" == "ipv6" ]
|
|
then
|
|
PROTOCOL="udp6"
|
|
else
|
|
PROTOCOL="udp"
|
|
fi
|
|
|
|
wait_local_port_listen "${NAMESPACE}" "${PORT}" "${PROTOCOL}"
|
|
# even after the port is open, let's wait 1 second before writing
|
|
# otherwise the packet could be missed, and the test will fail. Happens
|
|
# more frequently on IPv6
|
|
sleep 1
|
|
}
|