1*b3827c91SAndre Carvalho#!/usr/bin/env bash 2*b3827c91SAndre Carvalho# SPDX-License-Identifier: GPL-2.0 3*b3827c91SAndre Carvalho 4*b3827c91SAndre Carvalho# Test netconsole's message fragmentation functionality. 5*b3827c91SAndre Carvalho# 6*b3827c91SAndre Carvalho# When a message exceeds the maximum packet size, netconsole splits it into 7*b3827c91SAndre Carvalho# multiple fragments for transmission. This test verifies: 8*b3827c91SAndre Carvalho# - Correct fragmentation of large messages 9*b3827c91SAndre Carvalho# - Proper reassembly of fragments at the receiver 10*b3827c91SAndre Carvalho# - Preservation of userdata across fragments 11*b3827c91SAndre Carvalho# - Behavior with and without kernel release version appending 12*b3827c91SAndre Carvalho# 13*b3827c91SAndre Carvalho# Author: Breno Leitao <leitao@debian.org> 14*b3827c91SAndre Carvalho 15*b3827c91SAndre Carvalhoset -euo pipefail 16*b3827c91SAndre Carvalho 17*b3827c91SAndre CarvalhoSCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") 18*b3827c91SAndre Carvalho 19*b3827c91SAndre Carvalhosource "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh 20*b3827c91SAndre Carvalho 21*b3827c91SAndre Carvalhomodprobe netdevsim 2> /dev/null || true 22*b3827c91SAndre Carvalhomodprobe netconsole 2> /dev/null || true 23*b3827c91SAndre Carvalho 24*b3827c91SAndre Carvalho# The content of kmsg will be save to the following file 25*b3827c91SAndre CarvalhoOUTPUT_FILE="/tmp/${TARGET}" 26*b3827c91SAndre Carvalho 27*b3827c91SAndre Carvalho# set userdata to a long value. In this case, it is "1-2-3-4...50-" 28*b3827c91SAndre CarvalhoUSERDATA_VALUE=$(printf -- '%.2s-' {1..60}) 29*b3827c91SAndre Carvalho 30*b3827c91SAndre Carvalho# Convert the header string in a regexp, so, we can remove 31*b3827c91SAndre Carvalho# the second header as well. 32*b3827c91SAndre Carvalho# A header looks like "13,468,514729715,-,ncfrag=0/1135;". If 33*b3827c91SAndre Carvalho# release is appended, you might find something like:L 34*b3827c91SAndre Carvalho# "6.13.0-04048-g4f561a87745a,13,468,514729715,-,ncfrag=0/1135;" 35*b3827c91SAndre Carvalhofunction header_to_regex() { 36*b3827c91SAndre Carvalho # header is everything before ; 37*b3827c91SAndre Carvalho local HEADER="${1}" 38*b3827c91SAndre Carvalho REGEX=$(echo "${HEADER}" | cut -d'=' -f1) 39*b3827c91SAndre Carvalho echo "${REGEX}=[0-9]*\/[0-9]*;" 40*b3827c91SAndre Carvalho} 41*b3827c91SAndre Carvalho 42*b3827c91SAndre Carvalho# We have two headers in the message. Remove both to get the full message, 43*b3827c91SAndre Carvalho# and extract the full message. 44*b3827c91SAndre Carvalhofunction extract_msg() { 45*b3827c91SAndre Carvalho local MSGFILE="${1}" 46*b3827c91SAndre Carvalho # Extract the header, which is the very first thing that arrives in the 47*b3827c91SAndre Carvalho # first list. 48*b3827c91SAndre Carvalho HEADER=$(sed -n '1p' "${MSGFILE}" | cut -d';' -f1) 49*b3827c91SAndre Carvalho HEADER_REGEX=$(header_to_regex "${HEADER}") 50*b3827c91SAndre Carvalho 51*b3827c91SAndre Carvalho # Remove the two headers from the received message 52*b3827c91SAndre Carvalho # This will return the message without any header, similarly to what 53*b3827c91SAndre Carvalho # was sent. 54*b3827c91SAndre Carvalho sed "s/""${HEADER_REGEX}""//g" "${MSGFILE}" 55*b3827c91SAndre Carvalho} 56*b3827c91SAndre Carvalho 57*b3827c91SAndre Carvalho# Validate the message, which has two messages glued together. 58*b3827c91SAndre Carvalho# unwrap them to make sure all the characters were transmitted. 59*b3827c91SAndre Carvalho# File will look like the following: 60*b3827c91SAndre Carvalho# 13,468,514729715,-,ncfrag=0/1135;<message> 61*b3827c91SAndre Carvalho# key=<part of key>-13,468,514729715,-,ncfrag=967/1135;<rest of the key> 62*b3827c91SAndre Carvalhofunction validate_fragmented_result() { 63*b3827c91SAndre Carvalho # Discard the netconsole headers, and assemble the full message 64*b3827c91SAndre Carvalho RCVMSG=$(extract_msg "${1}") 65*b3827c91SAndre Carvalho 66*b3827c91SAndre Carvalho # check for the main message 67*b3827c91SAndre Carvalho if ! echo "${RCVMSG}" | grep -q "${MSG}"; then 68*b3827c91SAndre Carvalho echo "Message body doesn't match." >&2 69*b3827c91SAndre Carvalho echo "msg received=" "${RCVMSG}" >&2 70*b3827c91SAndre Carvalho exit "${ksft_fail}" 71*b3827c91SAndre Carvalho fi 72*b3827c91SAndre Carvalho 73*b3827c91SAndre Carvalho # check userdata 74*b3827c91SAndre Carvalho if ! echo "${RCVMSG}" | grep -q "${USERDATA_VALUE}"; then 75*b3827c91SAndre Carvalho echo "message userdata doesn't match" >&2 76*b3827c91SAndre Carvalho echo "msg received=" "${RCVMSG}" >&2 77*b3827c91SAndre Carvalho exit "${ksft_fail}" 78*b3827c91SAndre Carvalho fi 79*b3827c91SAndre Carvalho # test passed. hooray 80*b3827c91SAndre Carvalho} 81*b3827c91SAndre Carvalho 82*b3827c91SAndre Carvalho# Check for basic system dependency and exit if not found 83*b3827c91SAndre Carvalhocheck_for_dependencies 84*b3827c91SAndre Carvalho# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) 85*b3827c91SAndre Carvalhoecho "6 5" > /proc/sys/kernel/printk 86*b3827c91SAndre Carvalho# Remove the namespace, interfaces and netconsole target on exit 87*b3827c91SAndre Carvalhotrap cleanup EXIT 88*b3827c91SAndre Carvalho# Create one namespace and two interfaces 89*b3827c91SAndre Carvalhoset_network 90*b3827c91SAndre Carvalho# Create a dynamic target for netconsole 91*b3827c91SAndre Carvalhocreate_dynamic_target 92*b3827c91SAndre Carvalho# Set userdata "key" with the "value" value 93*b3827c91SAndre Carvalhoset_user_data 94*b3827c91SAndre Carvalho 95*b3827c91SAndre Carvalho 96*b3827c91SAndre Carvalho# TEST 1: Send message and userdata. They will fragment 97*b3827c91SAndre Carvalho# ======= 98*b3827c91SAndre CarvalhoMSG=$(printf -- 'MSG%.3s=' {1..150}) 99*b3827c91SAndre Carvalho 100*b3827c91SAndre Carvalho# Listen for netconsole port inside the namespace and destination interface 101*b3827c91SAndre Carvalholisten_port_and_save_to "${OUTPUT_FILE}" & 102*b3827c91SAndre Carvalho# Wait for socat to start and listen to the port. 103*b3827c91SAndre Carvalhowait_local_port_listen "${NAMESPACE}" "${PORT}" udp 104*b3827c91SAndre Carvalho# Send the message 105*b3827c91SAndre Carvalhoecho "${MSG}: ${TARGET}" > /dev/kmsg 106*b3827c91SAndre Carvalho# Wait until socat saves the file to disk 107*b3827c91SAndre Carvalhobusywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" 108*b3827c91SAndre Carvalho# Check if the message was not corrupted 109*b3827c91SAndre Carvalhovalidate_fragmented_result "${OUTPUT_FILE}" 110*b3827c91SAndre Carvalho 111*b3827c91SAndre Carvalho# TEST 2: Test with smaller message, and without release appended 112*b3827c91SAndre Carvalho# ======= 113*b3827c91SAndre CarvalhoMSG=$(printf -- 'FOOBAR%.3s=' {1..100}) 114*b3827c91SAndre Carvalho# Let's disable release and test again. 115*b3827c91SAndre Carvalhodisable_release_append 116*b3827c91SAndre Carvalho 117*b3827c91SAndre Carvalholisten_port_and_save_to "${OUTPUT_FILE}" & 118*b3827c91SAndre Carvalhowait_local_port_listen "${NAMESPACE}" "${PORT}" udp 119*b3827c91SAndre Carvalhoecho "${MSG}: ${TARGET}" > /dev/kmsg 120*b3827c91SAndre Carvalhobusywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" 121*b3827c91SAndre Carvalhovalidate_fragmented_result "${OUTPUT_FILE}" 122*b3827c91SAndre Carvalhoexit "${ksft_pass}" 123