| #!/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 <leitao@debian.org> | |
| 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;<message> | |
| # key=<part of key>-13,468,514729715,-,ncfrag=967/1135;<rest of the key> | |
| 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}" || true | |
| # 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}" || true | |
| validate_fragmented_result "${OUTPUT_FILE}" | |
| exit "${ksft_pass}" |