From b3827c91cc9979fe04d99e016fb9c5f6260f29a0 Mon Sep 17 00:00:00 2001 From: Andre Carvalho Date: Tue, 27 Jan 2026 19:39:20 +0000 Subject: netconsole: selftests: Move netconsole selftests to separate target This patch moves netconsole selftests from drivers/net to its own target in drivers/net/netconsole. This change helps saving some resources from CI since tests in drivers/net automatically run against real hardware which are not used by netconsole tests as they rely solely on netdevsim. lib_netcons.sh is kept under drivers/net/lib since it is also used by bonding selftests. Finally, drivers/net config remains unchanged as netpoll_basic.py requires netconsole (and does leverage real HW testing). Reviewed-by: Breno Leitao Signed-off-by: Andre Carvalho Link: https://patch.msgid.link/20260127-netcons-selftest-target-v2-1-f509ab65b3bc@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/drivers/net/Makefile | 7 - .../testing/selftests/drivers/net/netcons_basic.sh | 74 ------ .../selftests/drivers/net/netcons_cmdline.sh | 65 ----- .../drivers/net/netcons_fragmented_msg.sh | 122 --------- .../selftests/drivers/net/netcons_overflow.sh | 67 ----- .../selftests/drivers/net/netcons_resume.sh | 124 ---------- .../selftests/drivers/net/netcons_sysdata.sh | 272 --------------------- .../selftests/drivers/net/netcons_torture.sh | 130 ---------- .../selftests/drivers/net/netconsole/Makefile | 19 ++ .../selftests/drivers/net/netconsole/config | 6 + .../drivers/net/netconsole/netcons_basic.sh | 74 ++++++ .../drivers/net/netconsole/netcons_cmdline.sh | 65 +++++ .../net/netconsole/netcons_fragmented_msg.sh | 122 +++++++++ .../drivers/net/netconsole/netcons_overflow.sh | 67 +++++ .../drivers/net/netconsole/netcons_resume.sh | 124 ++++++++++ .../drivers/net/netconsole/netcons_sysdata.sh | 272 +++++++++++++++++++++ .../drivers/net/netconsole/netcons_torture.sh | 130 ++++++++++ 18 files changed, 880 insertions(+), 861 deletions(-) delete mode 100755 tools/testing/selftests/drivers/net/netcons_basic.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_cmdline.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_fragmented_msg.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_overflow.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_resume.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_sysdata.sh delete mode 100755 tools/testing/selftests/drivers/net/netcons_torture.sh create mode 100644 tools/testing/selftests/drivers/net/netconsole/Makefile create mode 100644 tools/testing/selftests/drivers/net/netconsole/config create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_basic.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_cmdline.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_fragmented_msg.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_overflow.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_resume.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_sysdata.sh create mode 100755 tools/testing/selftests/drivers/net/netconsole/netcons_torture.sh (limited to 'tools') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 56e44a98d6a5..450f13ba4cca 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -22,6 +22,7 @@ TARGETS += drivers/ntsync TARGETS += drivers/s390x/uvdevice TARGETS += drivers/net TARGETS += drivers/net/bonding +TARGETS += drivers/net/netconsole TARGETS += drivers/net/team TARGETS += drivers/net/virtio_net TARGETS += drivers/platform/x86/intel/ifs diff --git a/tools/testing/selftests/drivers/net/Makefile b/tools/testing/selftests/drivers/net/Makefile index 3eba569b3366..8154d6d429d3 100644 --- a/tools/testing/selftests/drivers/net/Makefile +++ b/tools/testing/selftests/drivers/net/Makefile @@ -15,13 +15,6 @@ TEST_PROGS := \ hds.py \ napi_id.py \ napi_threaded.py \ - netcons_basic.sh \ - netcons_cmdline.sh \ - netcons_fragmented_msg.sh \ - netcons_overflow.sh \ - netcons_resume.sh \ - netcons_sysdata.sh \ - netcons_torture.sh \ netpoll_basic.py \ ping.py \ psp.py \ diff --git a/tools/testing/selftests/drivers/net/netcons_basic.sh b/tools/testing/selftests/drivers/net/netcons_basic.sh deleted file mode 100755 index 2022f3061738..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_basic.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# This test creates two netdevsim virtual interfaces, assigns one of them (the -# "destination interface") to a new namespace, and assigns IP addresses to both -# interfaces. -# -# It listens on the destination interface using socat and configures a dynamic -# target on netconsole, pointing to the destination IP address. -# -# Finally, it checks whether the message was received properly on the -# destination interface. Note that this test may pollute the kernel log buffer -# (dmesg) and relies on dynamic configuration and namespaces being configured. -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -modprobe netdevsim 2> /dev/null || true -modprobe netconsole 2> /dev/null || true - -# The content of kmsg will be save to the following file -OUTPUT_FILE="/tmp/${TARGET}" - -# Check for basic system dependency and exit if not found -check_for_dependencies -# Remove the namespace, interfaces and netconsole target on exit -trap cleanup EXIT - -# Run the test twice, with different format modes -for FORMAT in "basic" "extended" -do - for IP_VERSION in "ipv6" "ipv4" - do - echo "Running with target mode: ${FORMAT} (${IP_VERSION})" - # Set current loglevel to KERN_INFO(6), and default to - # KERN_NOTICE(5) - echo "6 5" > /proc/sys/kernel/printk - # Create one namespace and two interfaces - set_network "${IP_VERSION}" - # Create a dynamic target for netconsole - create_dynamic_target "${FORMAT}" - # Only set userdata for extended format - if [ "$FORMAT" == "extended" ] - then - # Set userdata "key" with the "value" value - set_user_data - fi - # Listed for netconsole port inside the namespace and - # destination interface - listen_port_and_save_to "${OUTPUT_FILE}" "${IP_VERSION}" & - # Wait for socat to start and listen to the port. - wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}" - # Send the message - echo "${MSG}: ${TARGET}" > /dev/kmsg - # Wait until socat saves the file to disk - busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" - - # Make sure the message was received in the dst part - # and exit - validate_result "${OUTPUT_FILE}" "${FORMAT}" - # kill socat in case it is still running - pkill_socat - cleanup - echo "${FORMAT} : ${IP_VERSION} : Test passed" >&2 - done -done - -trap - EXIT -exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netcons_cmdline.sh b/tools/testing/selftests/drivers/net/netcons_cmdline.sh deleted file mode 100755 index d1d23dc67f99..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_cmdline.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# This is a selftest to test cmdline arguments on netconsole. -# It exercises loading of netconsole from cmdline instead of the dynamic -# reconfiguration. This includes parsing the long netconsole= line and all the -# flow through init_netconsole(). -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -check_netconsole_module - -modprobe netdevsim 2> /dev/null || true -rmmod netconsole 2> /dev/null || true - -# Check for basic system dependency and exit if not found -# check_for_dependencies -# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) -echo "6 5" > /proc/sys/kernel/printk -# Remove the namespace and network interfaces -trap do_cleanup EXIT -# Create one namespace and two interfaces -set_network - -# Run the test twice, with different cmdline parameters -for BINDMODE in "ifname" "mac" -do - echo "Running with bind mode: ${BINDMODE}" >&2 - # Create the command line for netconsole, with the configuration from - # the function above - CMDLINE=$(create_cmdline_str "${BINDMODE}") - - # The content of kmsg will be save to the following file - OUTPUT_FILE="/tmp/${TARGET}-${BINDMODE}" - - # Load the module, with the cmdline set - modprobe netconsole "${CMDLINE}" - - # Listed for netconsole port inside the namespace and destination - # interface - listen_port_and_save_to "${OUTPUT_FILE}" & - # Wait for socat to start and listen to the port. - wait_local_port_listen "${NAMESPACE}" "${PORT}" udp - # Send the message - echo "${MSG}: ${TARGET}" > /dev/kmsg - # Wait until socat saves the file to disk - busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" - # Make sure the message was received in the dst part - # and exit - validate_msg "${OUTPUT_FILE}" - - # kill socat in case it is still running - pkill_socat - # Unload the module - rmmod netconsole - echo "${BINDMODE} : Test passed" >&2 -done - -exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netcons_fragmented_msg.sh b/tools/testing/selftests/drivers/net/netcons_fragmented_msg.sh deleted file mode 100755 index 4a71e01a230c..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_fragmented_msg.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# Test netconsole's message fragmentation functionality. -# -# When a message exceeds the maximum packet size, netconsole splits it into -# multiple fragments for transmission. This test verifies: -# - Correct fragmentation of large messages -# - Proper reassembly of fragments at the receiver -# - Preservation of userdata across fragments -# - Behavior with and without kernel release version appending -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -modprobe netdevsim 2> /dev/null || true -modprobe netconsole 2> /dev/null || true - -# The content of kmsg will be save to the following file -OUTPUT_FILE="/tmp/${TARGET}" - -# set userdata to a long value. In this case, it is "1-2-3-4...50-" -USERDATA_VALUE=$(printf -- '%.2s-' {1..60}) - -# Convert the header string in a regexp, so, we can remove -# the second header as well. -# A header looks like "13,468,514729715,-,ncfrag=0/1135;". If -# release is appended, you might find something like:L -# "6.13.0-04048-g4f561a87745a,13,468,514729715,-,ncfrag=0/1135;" -function header_to_regex() { - # header is everything before ; - local HEADER="${1}" - REGEX=$(echo "${HEADER}" | cut -d'=' -f1) - echo "${REGEX}=[0-9]*\/[0-9]*;" -} - -# We have two headers in the message. Remove both to get the full message, -# and extract the full message. -function extract_msg() { - local MSGFILE="${1}" - # Extract the header, which is the very first thing that arrives in the - # first list. - HEADER=$(sed -n '1p' "${MSGFILE}" | cut -d';' -f1) - HEADER_REGEX=$(header_to_regex "${HEADER}") - - # Remove the two headers from the received message - # This will return the message without any header, similarly to what - # was sent. - sed "s/""${HEADER_REGEX}""//g" "${MSGFILE}" -} - -# Validate the message, which has two messages glued together. -# unwrap them to make sure all the characters were transmitted. -# File will look like the following: -# 13,468,514729715,-,ncfrag=0/1135; -# key=-13,468,514729715,-,ncfrag=967/1135; -function validate_fragmented_result() { - # Discard the netconsole headers, and assemble the full message - RCVMSG=$(extract_msg "${1}") - - # check for the main message - if ! echo "${RCVMSG}" | grep -q "${MSG}"; then - echo "Message body doesn't match." >&2 - echo "msg received=" "${RCVMSG}" >&2 - exit "${ksft_fail}" - fi - - # check userdata - if ! echo "${RCVMSG}" | grep -q "${USERDATA_VALUE}"; then - echo "message userdata doesn't match" >&2 - echo "msg received=" "${RCVMSG}" >&2 - exit "${ksft_fail}" - fi - # test passed. hooray -} - -# Check for basic system dependency and exit if not found -check_for_dependencies -# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) -echo "6 5" > /proc/sys/kernel/printk -# Remove the namespace, interfaces and netconsole target on exit -trap cleanup EXIT -# Create one namespace and two interfaces -set_network -# Create a dynamic target for netconsole -create_dynamic_target -# Set userdata "key" with the "value" value -set_user_data - - -# TEST 1: Send message and userdata. They will fragment -# ======= -MSG=$(printf -- 'MSG%.3s=' {1..150}) - -# Listen for netconsole port inside the namespace and destination interface -listen_port_and_save_to "${OUTPUT_FILE}" & -# Wait for socat to start and listen to the port. -wait_local_port_listen "${NAMESPACE}" "${PORT}" udp -# Send the message -echo "${MSG}: ${TARGET}" > /dev/kmsg -# Wait until socat saves the file to disk -busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" -# Check if the message was not corrupted -validate_fragmented_result "${OUTPUT_FILE}" - -# TEST 2: Test with smaller message, and without release appended -# ======= -MSG=$(printf -- 'FOOBAR%.3s=' {1..100}) -# Let's disable release and test again. -disable_release_append - -listen_port_and_save_to "${OUTPUT_FILE}" & -wait_local_port_listen "${NAMESPACE}" "${PORT}" udp -echo "${MSG}: ${TARGET}" > /dev/kmsg -busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" -validate_fragmented_result "${OUTPUT_FILE}" -exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netcons_overflow.sh b/tools/testing/selftests/drivers/net/netcons_overflow.sh deleted file mode 100755 index 06089643b771..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_overflow.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# This test verifies that users can successfully create up to -# MAX_USERDATA_ITEMS userdata entries without encountering any failures. -# -# Additionally, it tests for expected failure when attempting to exceed this -# maximum limit. -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh -# This is coming from netconsole code. Check for it in drivers/net/netconsole.c -MAX_USERDATA_ITEMS=256 - -# Function to create userdata entries -function create_userdata_max_entries() { - # All these keys should be created without any error - for i in $(seq $MAX_USERDATA_ITEMS) - do - # USERDATA_KEY is used by set_user_data - USERDATA_KEY="key"${i} - set_user_data - done -} - -# Function to verify the entry limit -function verify_entry_limit() { - # Allowing the test to fail without exiting, since the next command - # will fail - set +e - mkdir "${NETCONS_PATH}/userdata/key_that_will_fail" 2> /dev/null - ret="$?" - set -e - if [ "$ret" -eq 0 ]; - then - echo "Adding more than ${MAX_USERDATA_ITEMS} entries in userdata should fail, but it didn't" >&2 - ls "${NETCONS_PATH}/userdata/" >&2 - exit "${ksft_fail}" - fi -} - -# ========== # -# Start here # -# ========== # - -modprobe netdevsim 2> /dev/null || true -modprobe netconsole 2> /dev/null || true - -# Check for basic system dependency and exit if not found -check_for_dependencies - -# Remove the namespace, interfaces and netconsole target on exit -trap cleanup EXIT -# Create one namespace and two interfaces -set_network -# Create a dynamic target for netconsole -create_dynamic_target -# populate the maximum number of supported keys in userdata -create_userdata_max_entries -# Verify an additional entry is not allowed -verify_entry_limit -exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netcons_resume.sh b/tools/testing/selftests/drivers/net/netcons_resume.sh deleted file mode 100755 index fc5e5e3ad3d4..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_resume.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# This test validates that netconsole is able to resume a target that was -# deactivated when its interface was removed when the interface is brought -# back up. -# -# The test configures a netconsole target and then removes netdevsim module to -# cause the interface to disappear. Targets are configured via cmdline to ensure -# targets bound by interface name and mac address can be resumed. -# The test verifies that the target moved to disabled state before adding -# netdevsim and the interface back. -# -# Finally, the test verifies that the target is re-enabled automatically and -# the message is received on the destination interface. -# -# Author: Andre Carvalho - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -SAVED_SRCMAC="" # to be populated later -SAVED_DSTMAC="" # to be populated later - -modprobe netdevsim 2> /dev/null || true -rmmod netconsole 2> /dev/null || true - -check_netconsole_module - -function cleanup() { - cleanup_netcons "${NETCONS_CONFIGFS}/cmdline0" - do_cleanup - rmmod netconsole -} - -function trigger_reactivation() { - # Add back low level module - modprobe netdevsim - # Recreate namespace and two interfaces - set_network - # Restore MACs - ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" \ - address "${SAVED_DSTMAC}" - if [ "${BINDMODE}" == "mac" ]; then - ip link set dev "${SRCIF}" down - ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}" - # Rename device in order to trigger target resume, as initial - # when device was recreated it didn't have correct mac address. - ip link set dev "${SRCIF}" name "${TARGET}" - fi -} - -function trigger_deactivation() { - # Start by storing mac addresses so we can be restored in reactivate - SAVED_DSTMAC=$(ip netns exec "${NAMESPACE}" \ - cat /sys/class/net/"$DSTIF"/address) - SAVED_SRCMAC=$(mac_get "${SRCIF}") - # Remove low level module - rmmod netdevsim -} - -trap cleanup EXIT - -# Run the test twice, with different cmdline parameters -for BINDMODE in "ifname" "mac" -do - echo "Running with bind mode: ${BINDMODE}" >&2 - # Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) - echo "6 5" > /proc/sys/kernel/printk - - # Create one namespace and two interfaces - set_network - - # Create the command line for netconsole, with the configuration from - # the function above - CMDLINE=$(create_cmdline_str "${BINDMODE}") - - # The content of kmsg will be save to the following file - OUTPUT_FILE="/tmp/${TARGET}-${BINDMODE}" - - # Load the module, with the cmdline set - modprobe netconsole "${CMDLINE}" - # Expose cmdline target in configfs - mkdir "${NETCONS_CONFIGFS}/cmdline0" - - # Target should be enabled - wait_target_state "cmdline0" "enabled" - - # Trigger deactivation by unloading netdevsim module. Target should be - # disabled. - trigger_deactivation - wait_target_state "cmdline0" "disabled" - - # Trigger reactivation by loading netdevsim, recreating the network and - # restoring mac addresses. Target should be re-enabled. - trigger_reactivation - wait_target_state "cmdline0" "enabled" - - # Listen for netconsole port inside the namespace and destination - # interface - listen_port_and_save_to "${OUTPUT_FILE}" & - # Wait for socat to start and listen to the port. - wait_local_port_listen "${NAMESPACE}" "${PORT}" udp - # Send the message - echo "${MSG}: ${TARGET}" > /dev/kmsg - # Wait until socat saves the file to disk - busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" - # Make sure the message was received in the dst part - # and exit - validate_msg "${OUTPUT_FILE}" - - # kill socat in case it is still running - pkill_socat - # Cleanup & unload the module - cleanup - - echo "${BINDMODE} : Test passed" >&2 -done - -trap - EXIT -exit "${EXIT_STATUS}" diff --git a/tools/testing/selftests/drivers/net/netcons_sysdata.sh b/tools/testing/selftests/drivers/net/netcons_sysdata.sh deleted file mode 100755 index baf69031089e..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_sysdata.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# A test that makes sure that sysdata runtime CPU data is properly set -# when a message is sent. -# -# There are 3 different tests, every time sent using a random CPU. -# - Test #1 -# * Only enable cpu_nr sysdata feature. -# - Test #2 -# * Keep cpu_nr sysdata feature enable and enable userdata. -# - Test #3 -# * keep userdata enabled, and disable sysdata cpu_nr feature. -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -# Enable the sysdata cpu_nr feature -function set_cpu_nr() { - if [[ ! -f "${NETCONS_PATH}/userdata/cpu_nr_enabled" ]] - then - echo "Populate CPU configfs path not available in ${NETCONS_PATH}/userdata/cpu_nr_enabled" >&2 - exit "${ksft_skip}" - fi - - echo 1 > "${NETCONS_PATH}/userdata/cpu_nr_enabled" -} - -# Enable the taskname to be appended to sysdata -function set_taskname() { - if [[ ! -f "${NETCONS_PATH}/userdata/taskname_enabled" ]] - then - echo "Not able to enable taskname sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/taskname_enabled" >&2 - exit "${ksft_skip}" - fi - - echo 1 > "${NETCONS_PATH}/userdata/taskname_enabled" -} - -# Enable the release to be appended to sysdata -function set_release() { - if [[ ! -f "${NETCONS_PATH}/userdata/release_enabled" ]] - then - echo "Not able to enable release sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/release_enabled" >&2 - exit "${ksft_skip}" - fi - - echo 1 > "${NETCONS_PATH}/userdata/release_enabled" -} - -# Enable the msgid to be appended to sysdata -function set_msgid() { - if [[ ! -f "${NETCONS_PATH}/userdata/msgid_enabled" ]] - then - echo "Not able to enable msgid sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/msgid_enabled" >&2 - exit "${ksft_skip}" - fi - - echo 1 > "${NETCONS_PATH}/userdata/msgid_enabled" -} - -# Disable the sysdata cpu_nr feature -function unset_cpu_nr() { - echo 0 > "${NETCONS_PATH}/userdata/cpu_nr_enabled" -} - -# Once called, taskname=<..> will not be appended anymore -function unset_taskname() { - echo 0 > "${NETCONS_PATH}/userdata/taskname_enabled" -} - -function unset_release() { - echo 0 > "${NETCONS_PATH}/userdata/release_enabled" -} - -function unset_msgid() { - echo 0 > "${NETCONS_PATH}/userdata/msgid_enabled" -} - -# Test if MSG contains sysdata -function validate_sysdata() { - # OUTPUT_FILE will contain something like: - # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM - # userdatakey=userdatavalue - # cpu=X - # taskname= - # msgid= - - # Echo is what this test uses to create the message. See runtest() - # function - SENDER="echo" - - if [ ! -f "$OUTPUT_FILE" ]; then - echo "FAIL: File was not generated." >&2 - exit "${ksft_fail}" - fi - - if ! grep -q "${MSG}" "${OUTPUT_FILE}"; then - echo "FAIL: ${MSG} not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - # Check if cpu=XX exists in the file and matches the one used - # in taskset(1) - if ! grep -q "cpu=${CPU}\+" "${OUTPUT_FILE}"; then - echo "FAIL: 'cpu=${CPU}' not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if ! grep -q "taskname=${SENDER}" "${OUTPUT_FILE}"; then - echo "FAIL: 'taskname=echo' not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if ! grep -q "msgid=[0-9]\+$" "${OUTPUT_FILE}"; then - echo "FAIL: 'msgid=' not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - rm "${OUTPUT_FILE}" - pkill_socat -} - -function validate_release() { - RELEASE=$(uname -r) - - if [ ! -f "$OUTPUT_FILE" ]; then - echo "FAIL: File was not generated." >&2 - exit "${ksft_fail}" - fi - - if ! grep -q "release=${RELEASE}" "${OUTPUT_FILE}"; then - echo "FAIL: 'release=${RELEASE}' not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi -} - -# Test if MSG content exists in OUTPUT_FILE but no `cpu=` and `taskname=` -# strings -function validate_no_sysdata() { - if [ ! -f "$OUTPUT_FILE" ]; then - echo "FAIL: File was not generated." >&2 - exit "${ksft_fail}" - fi - - if ! grep -q "${MSG}" "${OUTPUT_FILE}"; then - echo "FAIL: ${MSG} not found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if grep -q "cpu=" "${OUTPUT_FILE}"; then - echo "FAIL: 'cpu= found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if grep -q "taskname=" "${OUTPUT_FILE}"; then - echo "FAIL: 'taskname= found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if grep -q "release=" "${OUTPUT_FILE}"; then - echo "FAIL: 'release= found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - if grep -q "msgid=" "${OUTPUT_FILE}"; then - echo "FAIL: 'msgid= found in ${OUTPUT_FILE}" >&2 - cat "${OUTPUT_FILE}" >&2 - exit "${ksft_fail}" - fi - - rm "${OUTPUT_FILE}" -} - -# Start socat, send the message and wait for the file to show up in the file -# system -function runtest { - # Listen for netconsole port inside the namespace and destination - # interface - listen_port_and_save_to "${OUTPUT_FILE}" & - # Wait for socat to start and listen to the port. - wait_local_port_listen "${NAMESPACE}" "${PORT}" udp - # Send the message - taskset -c "${CPU}" echo "${MSG}: ${TARGET}" > /dev/kmsg - # Wait until socat saves the file to disk - busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" -} - -# ========== # -# Start here # -# ========== # - -modprobe netdevsim 2> /dev/null || true -modprobe netconsole 2> /dev/null || true - -# Check for basic system dependency and exit if not found -check_for_dependencies -# This test also depends on taskset(1). Check for it before starting the test -check_for_taskset - -# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) -echo "6 5" > /proc/sys/kernel/printk -# Remove the namespace, interfaces and netconsole target on exit -trap cleanup EXIT -# Create one namespace and two interfaces -set_network -# Create a dynamic target for netconsole -create_dynamic_target - -#==================================================== -# TEST #1 -# Send message from a random CPU -#==================================================== -# Random CPU in the system -CPU=$((RANDOM % $(nproc))) -OUTPUT_FILE="/tmp/${TARGET}_1" -MSG="Test #1 from CPU${CPU}" -# Enable the auto population of cpu_nr -set_cpu_nr -# Enable taskname to be appended to sysdata -set_taskname -set_release -set_msgid -runtest -# Make sure the message was received in the dst part -# and exit -validate_release -validate_sysdata - -#==================================================== -# TEST #2 -# This test now adds userdata together with sysdata -# =================================================== -# Get a new random CPU -CPU=$((RANDOM % $(nproc))) -OUTPUT_FILE="/tmp/${TARGET}_2" -MSG="Test #2 from CPU${CPU}" -set_user_data -runtest -validate_release -validate_sysdata - -# =================================================== -# TEST #3 -# Unset all sysdata, fail if any userdata is set -# =================================================== -CPU=$((RANDOM % $(nproc))) -OUTPUT_FILE="/tmp/${TARGET}_3" -MSG="Test #3 from CPU${CPU}" -unset_cpu_nr -unset_taskname -unset_release -unset_msgid -runtest -# At this time, cpu= shouldn't be present in the msg -validate_no_sysdata - -exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netcons_torture.sh b/tools/testing/selftests/drivers/net/netcons_torture.sh deleted file mode 100755 index 2ce9ee3719d1..000000000000 --- a/tools/testing/selftests/drivers/net/netcons_torture.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: GPL-2.0 - -# Repeatedly send kernel messages, toggles netconsole targets on and off, -# creates and deletes targets in parallel, and toggles the source interface to -# simulate stress conditions. -# -# This test aims to verify the robustness of netconsole under dynamic -# configurations and concurrent operations. -# -# The major goal is to run this test with LOCKDEP, Kmemleak and KASAN to make -# sure no issues is reported. -# -# Author: Breno Leitao - -set -euo pipefail - -SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") - -source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh - -# Number of times the main loop run -ITERATIONS=${1:-150} - -# Only test extended format -FORMAT="extended" -# And ipv6 only -IP_VERSION="ipv6" - -# Create, enable and delete some targets. -create_and_delete_random_target() { - COUNT=2 - RND_PREFIX=$(mktemp -u netcons_rnd_XXXX_) - - if [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}${COUNT}" ] || \ - [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}0" ]; then - echo "Function didn't finish yet, skipping it." >&2 - return - fi - - # enable COUNT targets - for i in $(seq ${COUNT}) - do - RND_TARGET="${RND_PREFIX}"${i} - RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}" - - # Basic population so the target can come up - _create_dynamic_target "${FORMAT}" "${RND_TARGET_PATH}" - done - - echo "netconsole selftest: ${COUNT} additional targets were created" > /dev/kmsg - # disable them all - for i in $(seq ${COUNT}) - do - RND_TARGET="${RND_PREFIX}"${i} - RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}" - if [[ $(cat "${RND_TARGET_PATH}/enabled") -eq 1 ]] - then - echo 0 > "${RND_TARGET_PATH}"/enabled - fi - rmdir "${RND_TARGET_PATH}" - done -} - -# Disable and enable the target mid-air, while messages -# are being transmitted. -toggle_netcons_target() { - for i in $(seq 2) - do - if [ ! -d "${NETCONS_PATH}" ] - then - break - fi - echo 0 > "${NETCONS_PATH}"/enabled 2> /dev/null || true - # Try to enable a bit harder, given it might fail to enable - # Write to `enabled` might fail depending on the lock, which is - # highly contentious here - for _ in $(seq 5) - do - echo 1 > "${NETCONS_PATH}"/enabled 2> /dev/null || true - done - done -} - -toggle_iface(){ - ip link set "${SRCIF}" down - ip link set "${SRCIF}" up -} - -# Start here - -modprobe netdevsim 2> /dev/null || true -modprobe netconsole 2> /dev/null || true - -# Check for basic system dependency and exit if not found -check_for_dependencies -# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) -echo "6 5" > /proc/sys/kernel/printk -# Remove the namespace, interfaces and netconsole target on exit -trap cleanup EXIT -# Create one namespace and two interfaces -set_network "${IP_VERSION}" -# Create a dynamic target for netconsole -create_dynamic_target "${FORMAT}" - -for i in $(seq "$ITERATIONS") -do - for _ in $(seq 10) - do - echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg - done - wait - - if (( i % 30 == 0 )); then - toggle_netcons_target & - fi - - if (( i % 50 == 0 )); then - # create some targets, enable them, send msg and disable - # all in a parallel thread - create_and_delete_random_target & - fi - - if (( i % 70 == 0 )); then - toggle_iface & - fi -done -wait - -exit "${EXIT_STATUS}" diff --git a/tools/testing/selftests/drivers/net/netconsole/Makefile b/tools/testing/selftests/drivers/net/netconsole/Makefile new file mode 100644 index 000000000000..b56c70b7e274 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_INCLUDES := \ + ../../../net/lib.sh \ + ../lib/sh/lib_netcons.sh \ +# end of TEST_INCLUDES + +TEST_PROGS := \ + netcons_basic.sh \ + netcons_cmdline.sh \ + netcons_fragmented_msg.sh \ + netcons_overflow.sh \ + netcons_resume.sh \ + netcons_sysdata.sh \ + netcons_torture.sh \ +# end of TEST_PROGS + +include ../../../lib.mk + diff --git a/tools/testing/selftests/drivers/net/netconsole/config b/tools/testing/selftests/drivers/net/netconsole/config new file mode 100644 index 000000000000..a3f6b0fd44ef --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/config @@ -0,0 +1,6 @@ +CONFIG_CONFIGFS_FS=y +CONFIG_IPV6=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETCONSOLE_EXTENDED_LOG=y +CONFIG_NETDEVSIM=m diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_basic.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_basic.sh new file mode 100755 index 000000000000..59cf10013ecd --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_basic.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# This test creates two netdevsim virtual interfaces, assigns one of them (the +# "destination interface") to a new namespace, and assigns IP addresses to both +# interfaces. +# +# It listens on the destination interface using socat and configures a dynamic +# target on netconsole, pointing to the destination IP address. +# +# Finally, it checks whether the message was received properly on the +# destination interface. Note that this test may pollute the kernel log buffer +# (dmesg) and relies on dynamic configuration and namespaces being configured. +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +# The content of kmsg will be save to the following file +OUTPUT_FILE="/tmp/${TARGET}" + +# Check for basic system dependency and exit if not found +check_for_dependencies +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT + +# Run the test twice, with different format modes +for FORMAT in "basic" "extended" +do + for IP_VERSION in "ipv6" "ipv4" + do + echo "Running with target mode: ${FORMAT} (${IP_VERSION})" + # Set current loglevel to KERN_INFO(6), and default to + # KERN_NOTICE(5) + echo "6 5" > /proc/sys/kernel/printk + # Create one namespace and two interfaces + set_network "${IP_VERSION}" + # Create a dynamic target for netconsole + create_dynamic_target "${FORMAT}" + # Only set userdata for extended format + if [ "$FORMAT" == "extended" ] + then + # Set userdata "key" with the "value" value + set_user_data + fi + # Listed for netconsole port inside the namespace and + # destination interface + listen_port_and_save_to "${OUTPUT_FILE}" "${IP_VERSION}" & + # Wait for socat to start and listen to the port. + wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}" + # Send the message + echo "${MSG}: ${TARGET}" > /dev/kmsg + # Wait until socat saves the file to disk + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" + + # Make sure the message was received in the dst part + # and exit + validate_result "${OUTPUT_FILE}" "${FORMAT}" + # kill socat in case it is still running + pkill_socat + cleanup + echo "${FORMAT} : ${IP_VERSION} : Test passed" >&2 + done +done + +trap - EXIT +exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_cmdline.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_cmdline.sh new file mode 100755 index 000000000000..96d704b8d9d9 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_cmdline.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# This is a selftest to test cmdline arguments on netconsole. +# It exercises loading of netconsole from cmdline instead of the dynamic +# reconfiguration. This includes parsing the long netconsole= line and all the +# flow through init_netconsole(). +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +check_netconsole_module + +modprobe netdevsim 2> /dev/null || true +rmmod netconsole 2> /dev/null || true + +# Check for basic system dependency and exit if not found +# check_for_dependencies +# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) +echo "6 5" > /proc/sys/kernel/printk +# Remove the namespace and network interfaces +trap do_cleanup EXIT +# Create one namespace and two interfaces +set_network + +# Run the test twice, with different cmdline parameters +for BINDMODE in "ifname" "mac" +do + echo "Running with bind mode: ${BINDMODE}" >&2 + # Create the command line for netconsole, with the configuration from + # the function above + CMDLINE=$(create_cmdline_str "${BINDMODE}") + + # The content of kmsg will be save to the following file + OUTPUT_FILE="/tmp/${TARGET}-${BINDMODE}" + + # Load the module, with the cmdline set + modprobe netconsole "${CMDLINE}" + + # Listed for netconsole port inside the namespace and destination + # interface + listen_port_and_save_to "${OUTPUT_FILE}" & + # Wait for socat to start and listen to the port. + wait_local_port_listen "${NAMESPACE}" "${PORT}" udp + # Send the message + echo "${MSG}: ${TARGET}" > /dev/kmsg + # Wait until socat saves the file to disk + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" + # Make sure the message was received in the dst part + # and exit + validate_msg "${OUTPUT_FILE}" + + # kill socat in case it is still running + pkill_socat + # Unload the module + rmmod netconsole + echo "${BINDMODE} : Test passed" >&2 +done + +exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_fragmented_msg.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_fragmented_msg.sh new file mode 100755 index 000000000000..0dc7280c3080 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_fragmented_msg.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# Test netconsole's message fragmentation functionality. +# +# When a message exceeds the maximum packet size, netconsole splits it into +# multiple fragments for transmission. This test verifies: +# - Correct fragmentation of large messages +# - Proper reassembly of fragments at the receiver +# - Preservation of userdata across fragments +# - Behavior with and without kernel release version appending +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +# The content of kmsg will be save to the following file +OUTPUT_FILE="/tmp/${TARGET}" + +# set userdata to a long value. In this case, it is "1-2-3-4...50-" +USERDATA_VALUE=$(printf -- '%.2s-' {1..60}) + +# Convert the header string in a regexp, so, we can remove +# the second header as well. +# A header looks like "13,468,514729715,-,ncfrag=0/1135;". If +# release is appended, you might find something like:L +# "6.13.0-04048-g4f561a87745a,13,468,514729715,-,ncfrag=0/1135;" +function header_to_regex() { + # header is everything before ; + local HEADER="${1}" + REGEX=$(echo "${HEADER}" | cut -d'=' -f1) + echo "${REGEX}=[0-9]*\/[0-9]*;" +} + +# We have two headers in the message. Remove both to get the full message, +# and extract the full message. +function extract_msg() { + local MSGFILE="${1}" + # Extract the header, which is the very first thing that arrives in the + # first list. + HEADER=$(sed -n '1p' "${MSGFILE}" | cut -d';' -f1) + HEADER_REGEX=$(header_to_regex "${HEADER}") + + # Remove the two headers from the received message + # This will return the message without any header, similarly to what + # was sent. + sed "s/""${HEADER_REGEX}""//g" "${MSGFILE}" +} + +# Validate the message, which has two messages glued together. +# unwrap them to make sure all the characters were transmitted. +# File will look like the following: +# 13,468,514729715,-,ncfrag=0/1135; +# key=-13,468,514729715,-,ncfrag=967/1135; +function validate_fragmented_result() { + # Discard the netconsole headers, and assemble the full message + RCVMSG=$(extract_msg "${1}") + + # check for the main message + if ! echo "${RCVMSG}" | grep -q "${MSG}"; then + echo "Message body doesn't match." >&2 + echo "msg received=" "${RCVMSG}" >&2 + exit "${ksft_fail}" + fi + + # check userdata + if ! echo "${RCVMSG}" | grep -q "${USERDATA_VALUE}"; then + echo "message userdata doesn't match" >&2 + echo "msg received=" "${RCVMSG}" >&2 + exit "${ksft_fail}" + fi + # test passed. hooray +} + +# Check for basic system dependency and exit if not found +check_for_dependencies +# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) +echo "6 5" > /proc/sys/kernel/printk +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT +# Create one namespace and two interfaces +set_network +# Create a dynamic target for netconsole +create_dynamic_target +# Set userdata "key" with the "value" value +set_user_data + + +# TEST 1: Send message and userdata. They will fragment +# ======= +MSG=$(printf -- 'MSG%.3s=' {1..150}) + +# Listen for netconsole port inside the namespace and destination interface +listen_port_and_save_to "${OUTPUT_FILE}" & +# Wait for socat to start and listen to the port. +wait_local_port_listen "${NAMESPACE}" "${PORT}" udp +# Send the message +echo "${MSG}: ${TARGET}" > /dev/kmsg +# Wait until socat saves the file to disk +busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" +# Check if the message was not corrupted +validate_fragmented_result "${OUTPUT_FILE}" + +# TEST 2: Test with smaller message, and without release appended +# ======= +MSG=$(printf -- 'FOOBAR%.3s=' {1..100}) +# Let's disable release and test again. +disable_release_append + +listen_port_and_save_to "${OUTPUT_FILE}" & +wait_local_port_listen "${NAMESPACE}" "${PORT}" udp +echo "${MSG}: ${TARGET}" > /dev/kmsg +busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" +validate_fragmented_result "${OUTPUT_FILE}" +exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_overflow.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_overflow.sh new file mode 100755 index 000000000000..a8e43d08c166 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_overflow.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# This test verifies that users can successfully create up to +# MAX_USERDATA_ITEMS userdata entries without encountering any failures. +# +# Additionally, it tests for expected failure when attempting to exceed this +# maximum limit. +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh +# This is coming from netconsole code. Check for it in drivers/net/netconsole.c +MAX_USERDATA_ITEMS=256 + +# Function to create userdata entries +function create_userdata_max_entries() { + # All these keys should be created without any error + for i in $(seq $MAX_USERDATA_ITEMS) + do + # USERDATA_KEY is used by set_user_data + USERDATA_KEY="key"${i} + set_user_data + done +} + +# Function to verify the entry limit +function verify_entry_limit() { + # Allowing the test to fail without exiting, since the next command + # will fail + set +e + mkdir "${NETCONS_PATH}/userdata/key_that_will_fail" 2> /dev/null + ret="$?" + set -e + if [ "$ret" -eq 0 ]; + then + echo "Adding more than ${MAX_USERDATA_ITEMS} entries in userdata should fail, but it didn't" >&2 + ls "${NETCONS_PATH}/userdata/" >&2 + exit "${ksft_fail}" + fi +} + +# ========== # +# Start here # +# ========== # + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +# Check for basic system dependency and exit if not found +check_for_dependencies + +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT +# Create one namespace and two interfaces +set_network +# Create a dynamic target for netconsole +create_dynamic_target +# populate the maximum number of supported keys in userdata +create_userdata_max_entries +# Verify an additional entry is not allowed +verify_entry_limit +exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_resume.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_resume.sh new file mode 100755 index 000000000000..cb59cf436dd0 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_resume.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# This test validates that netconsole is able to resume a target that was +# deactivated when its interface was removed when the interface is brought +# back up. +# +# The test configures a netconsole target and then removes netdevsim module to +# cause the interface to disappear. Targets are configured via cmdline to ensure +# targets bound by interface name and mac address can be resumed. +# The test verifies that the target moved to disabled state before adding +# netdevsim and the interface back. +# +# Finally, the test verifies that the target is re-enabled automatically and +# the message is received on the destination interface. +# +# Author: Andre Carvalho + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +SAVED_SRCMAC="" # to be populated later +SAVED_DSTMAC="" # to be populated later + +modprobe netdevsim 2> /dev/null || true +rmmod netconsole 2> /dev/null || true + +check_netconsole_module + +function cleanup() { + cleanup_netcons "${NETCONS_CONFIGFS}/cmdline0" + do_cleanup + rmmod netconsole +} + +function trigger_reactivation() { + # Add back low level module + modprobe netdevsim + # Recreate namespace and two interfaces + set_network + # Restore MACs + ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" \ + address "${SAVED_DSTMAC}" + if [ "${BINDMODE}" == "mac" ]; then + ip link set dev "${SRCIF}" down + ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}" + # Rename device in order to trigger target resume, as initial + # when device was recreated it didn't have correct mac address. + ip link set dev "${SRCIF}" name "${TARGET}" + fi +} + +function trigger_deactivation() { + # Start by storing mac addresses so we can be restored in reactivate + SAVED_DSTMAC=$(ip netns exec "${NAMESPACE}" \ + cat /sys/class/net/"$DSTIF"/address) + SAVED_SRCMAC=$(mac_get "${SRCIF}") + # Remove low level module + rmmod netdevsim +} + +trap cleanup EXIT + +# Run the test twice, with different cmdline parameters +for BINDMODE in "ifname" "mac" +do + echo "Running with bind mode: ${BINDMODE}" >&2 + # Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) + echo "6 5" > /proc/sys/kernel/printk + + # Create one namespace and two interfaces + set_network + + # Create the command line for netconsole, with the configuration from + # the function above + CMDLINE=$(create_cmdline_str "${BINDMODE}") + + # The content of kmsg will be save to the following file + OUTPUT_FILE="/tmp/${TARGET}-${BINDMODE}" + + # Load the module, with the cmdline set + modprobe netconsole "${CMDLINE}" + # Expose cmdline target in configfs + mkdir "${NETCONS_CONFIGFS}/cmdline0" + + # Target should be enabled + wait_target_state "cmdline0" "enabled" + + # Trigger deactivation by unloading netdevsim module. Target should be + # disabled. + trigger_deactivation + wait_target_state "cmdline0" "disabled" + + # Trigger reactivation by loading netdevsim, recreating the network and + # restoring mac addresses. Target should be re-enabled. + trigger_reactivation + wait_target_state "cmdline0" "enabled" + + # Listen for netconsole port inside the namespace and destination + # interface + listen_port_and_save_to "${OUTPUT_FILE}" & + # Wait for socat to start and listen to the port. + wait_local_port_listen "${NAMESPACE}" "${PORT}" udp + # Send the message + echo "${MSG}: ${TARGET}" > /dev/kmsg + # Wait until socat saves the file to disk + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" + # Make sure the message was received in the dst part + # and exit + validate_msg "${OUTPUT_FILE}" + + # kill socat in case it is still running + pkill_socat + # Cleanup & unload the module + cleanup + + echo "${BINDMODE} : Test passed" >&2 +done + +trap - EXIT +exit "${EXIT_STATUS}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_sysdata.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_sysdata.sh new file mode 100755 index 000000000000..3fb8c4afe3d2 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_sysdata.sh @@ -0,0 +1,272 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# A test that makes sure that sysdata runtime CPU data is properly set +# when a message is sent. +# +# There are 3 different tests, every time sent using a random CPU. +# - Test #1 +# * Only enable cpu_nr sysdata feature. +# - Test #2 +# * Keep cpu_nr sysdata feature enable and enable userdata. +# - Test #3 +# * keep userdata enabled, and disable sysdata cpu_nr feature. +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +# Enable the sysdata cpu_nr feature +function set_cpu_nr() { + if [[ ! -f "${NETCONS_PATH}/userdata/cpu_nr_enabled" ]] + then + echo "Populate CPU configfs path not available in ${NETCONS_PATH}/userdata/cpu_nr_enabled" >&2 + exit "${ksft_skip}" + fi + + echo 1 > "${NETCONS_PATH}/userdata/cpu_nr_enabled" +} + +# Enable the taskname to be appended to sysdata +function set_taskname() { + if [[ ! -f "${NETCONS_PATH}/userdata/taskname_enabled" ]] + then + echo "Not able to enable taskname sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/taskname_enabled" >&2 + exit "${ksft_skip}" + fi + + echo 1 > "${NETCONS_PATH}/userdata/taskname_enabled" +} + +# Enable the release to be appended to sysdata +function set_release() { + if [[ ! -f "${NETCONS_PATH}/userdata/release_enabled" ]] + then + echo "Not able to enable release sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/release_enabled" >&2 + exit "${ksft_skip}" + fi + + echo 1 > "${NETCONS_PATH}/userdata/release_enabled" +} + +# Enable the msgid to be appended to sysdata +function set_msgid() { + if [[ ! -f "${NETCONS_PATH}/userdata/msgid_enabled" ]] + then + echo "Not able to enable msgid sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/msgid_enabled" >&2 + exit "${ksft_skip}" + fi + + echo 1 > "${NETCONS_PATH}/userdata/msgid_enabled" +} + +# Disable the sysdata cpu_nr feature +function unset_cpu_nr() { + echo 0 > "${NETCONS_PATH}/userdata/cpu_nr_enabled" +} + +# Once called, taskname=<..> will not be appended anymore +function unset_taskname() { + echo 0 > "${NETCONS_PATH}/userdata/taskname_enabled" +} + +function unset_release() { + echo 0 > "${NETCONS_PATH}/userdata/release_enabled" +} + +function unset_msgid() { + echo 0 > "${NETCONS_PATH}/userdata/msgid_enabled" +} + +# Test if MSG contains sysdata +function validate_sysdata() { + # OUTPUT_FILE will contain something like: + # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM + # userdatakey=userdatavalue + # cpu=X + # taskname= + # msgid= + + # Echo is what this test uses to create the message. See runtest() + # function + SENDER="echo" + + if [ ! -f "$OUTPUT_FILE" ]; then + echo "FAIL: File was not generated." >&2 + exit "${ksft_fail}" + fi + + if ! grep -q "${MSG}" "${OUTPUT_FILE}"; then + echo "FAIL: ${MSG} not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + # Check if cpu=XX exists in the file and matches the one used + # in taskset(1) + if ! grep -q "cpu=${CPU}\+" "${OUTPUT_FILE}"; then + echo "FAIL: 'cpu=${CPU}' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if ! grep -q "taskname=${SENDER}" "${OUTPUT_FILE}"; then + echo "FAIL: 'taskname=echo' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if ! grep -q "msgid=[0-9]\+$" "${OUTPUT_FILE}"; then + echo "FAIL: 'msgid=' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + rm "${OUTPUT_FILE}" + pkill_socat +} + +function validate_release() { + RELEASE=$(uname -r) + + if [ ! -f "$OUTPUT_FILE" ]; then + echo "FAIL: File was not generated." >&2 + exit "${ksft_fail}" + fi + + if ! grep -q "release=${RELEASE}" "${OUTPUT_FILE}"; then + echo "FAIL: 'release=${RELEASE}' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi +} + +# Test if MSG content exists in OUTPUT_FILE but no `cpu=` and `taskname=` +# strings +function validate_no_sysdata() { + if [ ! -f "$OUTPUT_FILE" ]; then + echo "FAIL: File was not generated." >&2 + exit "${ksft_fail}" + fi + + if ! grep -q "${MSG}" "${OUTPUT_FILE}"; then + echo "FAIL: ${MSG} not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if grep -q "cpu=" "${OUTPUT_FILE}"; then + echo "FAIL: 'cpu= found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if grep -q "taskname=" "${OUTPUT_FILE}"; then + echo "FAIL: 'taskname= found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if grep -q "release=" "${OUTPUT_FILE}"; then + echo "FAIL: 'release= found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + if grep -q "msgid=" "${OUTPUT_FILE}"; then + echo "FAIL: 'msgid= found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + + rm "${OUTPUT_FILE}" +} + +# Start socat, send the message and wait for the file to show up in the file +# system +function runtest { + # Listen for netconsole port inside the namespace and destination + # interface + listen_port_and_save_to "${OUTPUT_FILE}" & + # Wait for socat to start and listen to the port. + wait_local_port_listen "${NAMESPACE}" "${PORT}" udp + # Send the message + taskset -c "${CPU}" echo "${MSG}: ${TARGET}" > /dev/kmsg + # Wait until socat saves the file to disk + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" +} + +# ========== # +# Start here # +# ========== # + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +# Check for basic system dependency and exit if not found +check_for_dependencies +# This test also depends on taskset(1). Check for it before starting the test +check_for_taskset + +# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) +echo "6 5" > /proc/sys/kernel/printk +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT +# Create one namespace and two interfaces +set_network +# Create a dynamic target for netconsole +create_dynamic_target + +#==================================================== +# TEST #1 +# Send message from a random CPU +#==================================================== +# Random CPU in the system +CPU=$((RANDOM % $(nproc))) +OUTPUT_FILE="/tmp/${TARGET}_1" +MSG="Test #1 from CPU${CPU}" +# Enable the auto population of cpu_nr +set_cpu_nr +# Enable taskname to be appended to sysdata +set_taskname +set_release +set_msgid +runtest +# Make sure the message was received in the dst part +# and exit +validate_release +validate_sysdata + +#==================================================== +# TEST #2 +# This test now adds userdata together with sysdata +# =================================================== +# Get a new random CPU +CPU=$((RANDOM % $(nproc))) +OUTPUT_FILE="/tmp/${TARGET}_2" +MSG="Test #2 from CPU${CPU}" +set_user_data +runtest +validate_release +validate_sysdata + +# =================================================== +# TEST #3 +# Unset all sysdata, fail if any userdata is set +# =================================================== +CPU=$((RANDOM % $(nproc))) +OUTPUT_FILE="/tmp/${TARGET}_3" +MSG="Test #3 from CPU${CPU}" +unset_cpu_nr +unset_taskname +unset_release +unset_msgid +runtest +# At this time, cpu= shouldn't be present in the msg +validate_no_sysdata + +exit "${ksft_pass}" diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_torture.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_torture.sh new file mode 100755 index 000000000000..33a44adb6f8f --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_torture.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# Repeatedly send kernel messages, toggles netconsole targets on and off, +# creates and deletes targets in parallel, and toggles the source interface to +# simulate stress conditions. +# +# This test aims to verify the robustness of netconsole under dynamic +# configurations and concurrent operations. +# +# The major goal is to run this test with LOCKDEP, Kmemleak and KASAN to make +# sure no issues is reported. +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +# Number of times the main loop run +ITERATIONS=${1:-150} + +# Only test extended format +FORMAT="extended" +# And ipv6 only +IP_VERSION="ipv6" + +# Create, enable and delete some targets. +create_and_delete_random_target() { + COUNT=2 + RND_PREFIX=$(mktemp -u netcons_rnd_XXXX_) + + if [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}${COUNT}" ] || \ + [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}0" ]; then + echo "Function didn't finish yet, skipping it." >&2 + return + fi + + # enable COUNT targets + for i in $(seq ${COUNT}) + do + RND_TARGET="${RND_PREFIX}"${i} + RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}" + + # Basic population so the target can come up + _create_dynamic_target "${FORMAT}" "${RND_TARGET_PATH}" + done + + echo "netconsole selftest: ${COUNT} additional targets were created" > /dev/kmsg + # disable them all + for i in $(seq ${COUNT}) + do + RND_TARGET="${RND_PREFIX}"${i} + RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}" + if [[ $(cat "${RND_TARGET_PATH}/enabled") -eq 1 ]] + then + echo 0 > "${RND_TARGET_PATH}"/enabled + fi + rmdir "${RND_TARGET_PATH}" + done +} + +# Disable and enable the target mid-air, while messages +# are being transmitted. +toggle_netcons_target() { + for i in $(seq 2) + do + if [ ! -d "${NETCONS_PATH}" ] + then + break + fi + echo 0 > "${NETCONS_PATH}"/enabled 2> /dev/null || true + # Try to enable a bit harder, given it might fail to enable + # Write to `enabled` might fail depending on the lock, which is + # highly contentious here + for _ in $(seq 5) + do + echo 1 > "${NETCONS_PATH}"/enabled 2> /dev/null || true + done + done +} + +toggle_iface(){ + ip link set "${SRCIF}" down + ip link set "${SRCIF}" up +} + +# Start here + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +# Check for basic system dependency and exit if not found +check_for_dependencies +# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) +echo "6 5" > /proc/sys/kernel/printk +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT +# Create one namespace and two interfaces +set_network "${IP_VERSION}" +# Create a dynamic target for netconsole +create_dynamic_target "${FORMAT}" + +for i in $(seq "$ITERATIONS") +do + for _ in $(seq 10) + do + echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg + done + wait + + if (( i % 30 == 0 )); then + toggle_netcons_target & + fi + + if (( i % 50 == 0 )); then + # create some targets, enable them, send msg and disable + # all in a parallel thread + create_and_delete_random_target & + fi + + if (( i % 70 == 0 )); then + toggle_iface & + fi +done +wait + +exit "${EXIT_STATUS}" -- cgit v1.2.3