Netdev List
 help / color / mirror / Atom feed
* [PATCH net 6/6] selftests: ovpn: serialize YNL listener startup
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

Starting one background YNL notification listener per peer back-to-back
can intermittently stall the test setup before the listeners even reach
the Python main function.

This was reproducible in a reduced test.sh setup-only loop: a single
listener stayed stable across repeated runs, while starting listeners
for all peers could hang early in the listener launch phase. Adding a
short delay between listener launches makes the listeners start cleanly
and eliminates the reproduced hangs in repeated normal and slow-runner
tests.

Serialize listener startup with a small sleep between setup_listener
calls.

Fixes: 77de28cd7cf1 ("selftests: ovpn: add notification parsing and matching")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/test.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh
index eca653112aeb..b50dbe45a4d0 100755
--- a/tools/testing/selftests/net/ovpn/test.sh
+++ b/tools/testing/selftests/net/ovpn/test.sh
@@ -31,6 +31,9 @@ ovpn_prepare_network() {
 	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
 		ovpn_cmd_ok "start notification listener peer${p}" \
 			ovpn_setup_listener "${p}"
+		# starting all YNL listeners back-to-back can intermittently
+		# stall their startup so serialize launches a bit
+		sleep 0.5
 	done
 
 	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 5/6] selftests: ovpn: align command flow with TAP
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

Current tests do not properly adhere to the TAP infrastructure
therefore they do not properly report failures leading to hangs of
the CI machinery.

Restructure ovpn selftests into using the TAP infrastructure: split each
test in stages, execute stage bodies with fail-fast semantics, and emit
KTAP pass/fail for each stage.

Centralize behavior control in common.sh and makes the scripts use
dedicated wrappers for required-success, expected-failure, and non-fatal
commands. Also add the OVPN_VERBOSE mode that exposes captured command
output for debugging.
This way tests won't hang anymore in case of failure when executed
within the CI machinery.

This change also makes default OVPN_CLI and YNL resolution
independent from the caller CWD by anchoring both to COMMON_DIR, so
behavior is stable across direct execution and run_tests-style
execution.

Fixes: 959bc330a439 ("testing/selftests: add test tool and scripts for ovpn module")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/common.sh    | 182 +++++++-
 .../selftests/net/ovpn/test-close-socket.sh   |  90 ++--
 tools/testing/selftests/net/ovpn/test-mark.sh | 236 ++++++----
 tools/testing/selftests/net/ovpn/test.sh      | 441 ++++++++++++------
 4 files changed, 676 insertions(+), 273 deletions(-)

diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh
index 38f187b9de23..2d844eb3aa6e 100644
--- a/tools/testing/selftests/net/ovpn/common.sh
+++ b/tools/testing/selftests/net/ovpn/common.sh
@@ -4,14 +4,18 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
+OVPN_COMMON_DIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")
+source "$OVPN_COMMON_DIR/../../kselftest/ktap_helpers.sh"
+
 OVPN_UDP_PEERS_FILE=${OVPN_UDP_PEERS_FILE:-udp_peers.txt}
 OVPN_TCP_PEERS_FILE=${OVPN_TCP_PEERS_FILE:-tcp_peers.txt}
-OVPN_CLI=${OVPN_CLI:-./ovpn-cli}
-OVPN_YNL=${OVPN_YNL:-../../../../net/ynl/pyynl/cli.py}
+OVPN_CLI=${OVPN_CLI:-${OVPN_COMMON_DIR}/ovpn-cli}
+OVPN_YNL=${OVPN_YNL:-${OVPN_COMMON_DIR}/../../../../net/ynl/pyynl/cli.py}
 OVPN_ALG=${OVPN_ALG:-aes}
 OVPN_PROTO=${OVPN_PROTO:-UDP}
 OVPN_FLOAT=${OVPN_FLOAT:-0}
 OVPN_SYMMETRIC_ID=${OVPN_SYMMETRIC_ID:-0}
+OVPN_VERBOSE=${OVPN_VERBOSE:-0}
 
 export OVPN_ID_OFFSET=$(( 9 * (OVPN_SYMMETRIC_ID == 0) ))
 
@@ -22,6 +26,111 @@ OVPN_LAN_IP="11.11.11.11"
 
 declare -A OVPN_TMP_JSONS=()
 declare -A OVPN_LISTENER_PIDS=()
+OVPN_CURRENT_STAGE=""
+
+ovpn_is_verbose() {
+	[[ "${OVPN_VERBOSE}" == "1" ]]
+}
+
+ovpn_log() {
+	ovpn_is_verbose || return 0
+	printf '%s\n' "$*"
+}
+
+ovpn_print_cmd_output() {
+	local output_file="$1"
+	local line
+
+	[[ -s "${output_file}" ]] || return 0
+
+	while IFS= read -r line; do
+		ovpn_log "${line}"
+	done < "${output_file}"
+}
+
+ovpn_cmd_run() {
+	local mode="$1"
+	local label="$2"
+	local output_file
+	local rc
+	local ret=0
+
+	shift 2
+
+	output_file=$(mktemp)
+	if "$@" >"${output_file}" 2>&1; then
+		rc=0
+	else
+		rc=$?
+	fi
+
+	case "${mode}" in
+	ok)
+		if [[ "${rc}" -ne 0 ]]; then
+			cat "${output_file}"
+			printf '%s\n' \
+				"${label}: command failed with rc=${rc}: $*"
+			ret="${rc}"
+		fi
+		;;
+	mayfail)
+		;;
+	fail)
+		[[ "${rc}" -eq 0 ]] && ret=1
+		;;
+	esac
+
+	if ovpn_is_verbose && [[ "${rc}" -eq 0 || "${mode}" != "ok" ]]; then
+		ovpn_print_cmd_output "${output_file}"
+	fi
+
+	rm -f "${output_file}"
+	return "${ret}"
+}
+
+ovpn_cmd_ok() {
+	ovpn_cmd_run ok "$@"
+}
+
+ovpn_cmd_mayfail() {
+	ovpn_cmd_run mayfail "$@"
+}
+
+ovpn_cmd_fail() {
+	ovpn_cmd_run fail "$@"
+}
+
+ovpn_run_bg() {
+	local pid_var="$1"
+
+	shift
+	if ovpn_is_verbose; then
+		"$@" &
+	else
+		"$@" >/dev/null 2>&1 &
+	fi
+
+	printf -v "${pid_var}" '%s' "$!"
+}
+
+ovpn_run_stage() {
+	local label="$1"
+
+	shift
+	OVPN_CURRENT_STAGE="${label}"
+	"$@"
+	OVPN_CURRENT_STAGE=""
+	ktap_test_pass "${label}"
+}
+
+ovpn_stage_err() {
+	# ERR trap is global under set -eE: only report failures that happen
+	# while ovpn_run_stage() is actively executing a stage body.
+	if [[ -n "${OVPN_CURRENT_STAGE}" ]]; then
+		ktap_test_fail "${OVPN_CURRENT_STAGE}"
+		OVPN_CURRENT_STAGE=""
+	fi
+}
 
 ovpn_create_ns() {
 	ip netns add "ovpn_peer${1}"
@@ -87,12 +196,16 @@ ovpn_build_capture_filter() {
 }
 
 ovpn_setup_listener() {
-	local peer_ns="ovpn_peer${p}"
+	local peer="$1"
+	local file
+	local peer_ns="ovpn_peer${peer}"
+
 	file=$(mktemp)
 	PYTHONUNBUFFERED=1 ip netns exec "${peer_ns}" "${OVPN_YNL}" --family \
-		ovpn --subscribe peers --output-json --duration 40 > ${file} &
-	OVPN_LISTENER_PIDS[$1]=$!
-	OVPN_TMP_JSONS[$1]="${file}"
+		ovpn --subscribe peers --output-json > "${file}" \
+		2>/dev/null &
+	OVPN_LISTENER_PIDS["${peer}"]=$!
+	OVPN_TMP_JSONS["${peer}"]="${file}"
 }
 
 ovpn_add_peer() {
@@ -173,8 +286,7 @@ ovpn_compare_ntfs() {
 		received="${OVPN_TMP_JSONS[$1]}"
 		diff_file=$(mktemp)
 
-		kill -TERM ${OVPN_LISTENER_PIDS[$1]} || true
-		wait ${OVPN_LISTENER_PIDS[$1]} || true
+		ovpn_stop_listener "${1}" 1
 		printf "Checking notifications for peer ${1}... "
 		if diff <(jq -s "${OVPN_JQ_FILTER}" ${expected}) \
 			<(jq -s "${OVPN_JQ_FILTER}" ${received}) \
@@ -187,30 +299,60 @@ ovpn_compare_ntfs() {
 		fi
 
 		rm -f "${diff_file}" || true
-		rm -f ${received} || true
+		rm -f "${received}" || true
+		unset "OVPN_TMP_JSONS[$1]"
 	fi
 
 	return "${diff_rc}"
 }
 
+ovpn_stop_listener() {
+	local peer="$1"
+	local keep_json="${2:-0}"
+	local pid="${OVPN_LISTENER_PIDS[$peer]:-}"
+	local json="${OVPN_TMP_JSONS[$peer]:-}"
+
+	if [[ -n "${pid}" ]]; then
+		kill -TERM "${pid}" 2>/dev/null || true
+		wait "${pid}" 2>/dev/null || true
+		unset "OVPN_LISTENER_PIDS[$peer]"
+	fi
+
+	if [[ -n "${json}" && "${keep_json}" -eq 0 ]]; then
+		rm -f "${json}" || true
+		unset "OVPN_TMP_JSONS[$peer]"
+	fi
+}
+
+ovpn_cleanup_peer_ns() {
+	local peer="$1"
+	local peer_id="${peer#ovpn_peer}"
+
+	ip -n "${peer}" link set tun${peer_id} down 2>/dev/null || true
+	ip netns exec "${peer}" ${OVPN_CLI} del_iface tun${peer_id} \
+		1>/dev/null 2>&1 || true
+	ip netns del "${peer}" 2>/dev/null || true
+}
+
 ovpn_cleanup() {
-	local peer_ns
+	local peer
+
 	# some ovpn-cli processes sleep in background so they need manual poking
-	killall $(basename ${OVPN_CLI}) 2>/dev/null || true
+	killall "$(basename "${OVPN_CLI}")" 2>/dev/null || true
 
-	# netns peer0 is deleted without erasing ifaces first
-	for p in $(seq 1 10); do
-		peer_ns="ovpn_peer${p}"
-		ip -n "${peer_ns}" link set tun${p} down 2>/dev/null || true
-		ip netns exec "${peer_ns}" ${OVPN_CLI} del_iface tun${p} \
-			2>/dev/null || true
+	for peer in "${!OVPN_LISTENER_PIDS[@]}"; do
+		ovpn_stop_listener "${peer}" 2>/dev/null
 	done
+
 	for p in $(seq 1 10); do
 		ip -n ovpn_peer0 link del veth${p} 2>/dev/null || true
 	done
-	for p in $(seq 0 10); do
-		ip netns del "ovpn_peer${p}" 2>/dev/null || true
-	done
+
+	# remove from ovpn's netns pool
+	while IFS= read -r peer; do
+		[[ -n "${peer}" ]] || continue
+		ovpn_cleanup_peer_ns "${peer}" 2>/dev/null
+	done < <(ip netns list 2>/dev/null | awk '/^ovpn_/ {print $1}')
 }
 
 if [ "${OVPN_PROTO}" == "UDP" ]; then
diff --git a/tools/testing/selftests/net/ovpn/test-close-socket.sh b/tools/testing/selftests/net/ovpn/test-close-socket.sh
index 6bc1b6eab8ac..af1532b4d2da 100755
--- a/tools/testing/selftests/net/ovpn/test-close-socket.sh
+++ b/tools/testing/selftests/net/ovpn/test-close-socket.sh
@@ -5,43 +5,81 @@
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
 #set -x
-set -e
+set -eE
 
 source ./common.sh
-server_ns="ovpn_peer0"
 
-ovpn_cleanup
+ovpn_test_finished=0
 
-modprobe -q ovpn || true
+ovpn_test_exit() {
+	ovpn_cleanup
+	modprobe -r ovpn || true
+
+	if [ "${ovpn_test_finished}" -eq 0 ]; then
+		ktap_print_totals
+	fi
+}
+
+ovpn_prepare_network() {
+	local p
+	local peer_ns
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+	done
 
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_create_ns ${p}
-done
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+			"${p}" 5.5.5.$((p + 1))/24
+	done
 
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_setup_ns ${p} 5.5.5.$((${p} + 1))/24
-done
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+	done
 
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_add_peer ${p}
-done
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+			ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+				${p} 60 120
+		ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+				tun${p} $((p + OVPN_ID_OFFSET)) 60 120
+	done
+}
 
-for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 60 120
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} $((${p}+9)) \
-		60 120
-done
+ovpn_run_ping_traffic() {
+	local p
 
-sleep 1
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "send ping traffic to peer ${p}" \
+			ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+				5.5.5.$((p + 1))
+	done
+}
 
-for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
-done
+ovpn_run_iperf() {
+	local iperf_pid
 
-ip netns exec "${server_ns}" iperf3 -1 -s &
-sleep 1
-ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
+	ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s
+	sleep 1
+	ovpn_cmd_ok "run iperf throughput flow" \
+		ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
+	wait "${iperf_pid}" || return 1
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+ktap_set_plan 3
 
 ovpn_cleanup
+modprobe -q ovpn || true
+
+ovpn_run_stage "setup network topology" ovpn_prepare_network
+ovpn_run_stage "run ping traffic" ovpn_run_ping_traffic
+ovpn_run_stage "run iperf throughput" ovpn_run_iperf
 
-modprobe -r ovpn || true
+ovpn_test_finished=1
+ktap_finished
diff --git a/tools/testing/selftests/net/ovpn/test-mark.sh b/tools/testing/selftests/net/ovpn/test-mark.sh
index 2ee5dc5fc538..5a8f47554286 100755
--- a/tools/testing/selftests/net/ovpn/test-mark.sh
+++ b/tools/testing/selftests/net/ovpn/test-mark.sh
@@ -6,92 +6,166 @@
 #		Antonio Quartulli <antonio@openvpn.net>
 
 #set -x
-set -e
+set -eE
 
 MARK=1056
+MARK_DROP_COUNTER=0
 
 source ./common.sh
-server_ns="ovpn_peer0"
 
-ovpn_cleanup
-
-modprobe -q ovpn || true
-
-for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
-	ovpn_create_ns "${p}"
-done
-
-for p in $(seq 0 3); do
-	ovpn_setup_ns "${p}" 5.5.5.$((p + 1))/24
-done
-
-# add peer0 with mark
-ip netns exec "${server_ns}" "${OVPN_CLI}" new_multi_peer tun0 1 ASYMM \
-	"${OVPN_UDP_PEERS_FILE}" \
-	${MARK}
-for p in $(seq 1 3); do
-	ip netns exec "${server_ns}" "${OVPN_CLI}" new_key tun0 "${p}" 1 0 \
-		"${OVPN_ALG}" 0 data64.key
-done
-
-for p in $(seq 1 3); do
-	ovpn_add_peer "${p}"
-done
-
-for p in $(seq 1 3); do
-	ip netns exec "${server_ns}" "${OVPN_CLI}" set_peer tun0 "${p}" 60 120
-	ip netns exec "ovpn_peer${p}" "${OVPN_CLI}" set_peer tun"${p}" \
-		$((p + 9)) 60 120
-done
-
-sleep 1
-
-for p in $(seq 1 3); do
-	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((p + 1))
-done
-
-echo "Adding an nftables drop rule based on mark value ${MARK}"
-ip netns exec "${server_ns}" nft flush ruleset
-ip netns exec "${server_ns}" nft 'add table inet filter'
-ip netns exec "${server_ns}" nft 'add chain inet filter output {
-	type filter hook output priority 0;
-	policy accept;
-}'
-ip netns exec "${server_ns}" nft add rule inet filter output \
-	meta mark == ${MARK} \
-	counter drop
-
-DROP_COUNTER=$(ip netns exec "${server_ns}" nft list chain inet filter output \
-	| sed -n 's/.*packets \([0-9]*\).*/\1/p')
-sleep 1
-
-# ping should fail
-for p in $(seq 1 3); do
-	PING_OUTPUT=$(ip netns exec "${server_ns}" ping \
-		-qfc 500 -w 1 5.5.5.$((p + 1)) 2>&1) && exit 1
-	echo "${PING_OUTPUT}"
-	LOST_PACKETS=$(echo "$PING_OUTPUT" \
-		| awk '/packets transmitted/ { print $1 }')
-	# increment the drop counter by the amount of lost packets
-	DROP_COUNTER=$((DROP_COUNTER + LOST_PACKETS))
-done
-
-# check if the final nft counter matches our counter
-TOTAL_COUNT=$(ip netns exec "${server_ns}" nft list chain inet filter output \
-	| sed -n 's/.*packets \([0-9]*\).*/\1/p')
-if [ "${DROP_COUNTER}" -ne "${TOTAL_COUNT}" ]; then
-	echo "Expected ${TOTAL_COUNT} drops, got ${DROP_COUNTER}"
-	exit 1
-fi
-
-echo "Removing the drop rule"
-ip netns exec "${server_ns}" nft flush ruleset
-sleep 1
-
-for p in $(seq 1 3); do
-	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((p + 1))
-done
+ovpn_test_finished=0
+
+ovpn_test_exit() {
+	ovpn_cleanup
+	modprobe -r ovpn || true
+
+	if [ "${ovpn_test_finished}" -eq 0 ]; then
+		ktap_print_totals
+	fi
+}
+
+ovpn_mark_prepare_network() {
+	local p
+	local peer_ns
+
+	for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
+		ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+	done
+
+	for p in $(seq 0 3); do
+		ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+			"${p}" 5.5.5.$((p + 1))/24
+	done
+
+	ovpn_cmd_ok "create server-side multi-peer with fwmark" \
+		ip netns exec ovpn_peer0 "${OVPN_CLI}" new_multi_peer tun0 1 \
+			ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}"
+	for p in $(seq 1 3); do
+		ovpn_cmd_ok "install server key for peer ${p}" \
+			ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \
+				"${p}" 1 0 "${OVPN_ALG}" 0 data64.key
+	done
+
+	for p in $(seq 1 3); do
+		ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+	done
+
+	for p in $(seq 1 3); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+			ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \
+				"${p}" 60 120
+		ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+			ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \
+				tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120
+	done
+}
+
+ovpn_mark_run_baseline_traffic() {
+	local p
+
+	for p in $(seq 1 3); do
+		ovpn_cmd_ok "send baseline traffic to peer ${p}" \
+			ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+				5.5.5.$((p + 1))
+	done
+}
+
+ovpn_mark_add_drop_rule() {
+	ovpn_log "Adding an nftables drop rule based on mark value ${MARK}"
+
+	ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
+		ruleset
+	ovpn_cmd_ok "create nft filter table" ip netns exec ovpn_peer0 nft \
+		"add table inet filter"
+	ovpn_cmd_ok "create nft filter output chain" \
+		ip netns exec ovpn_peer0 nft "add chain inet filter output { \
+			type filter hook output priority 0; policy accept; }"
+	ovpn_cmd_ok "add nft drop rule for mark ${MARK}" \
+		ip netns exec ovpn_peer0 nft add rule inet filter output \
+			meta mark == "${MARK}" \
+			counter drop
+
+	MARK_DROP_COUNTER=$(ip netns exec ovpn_peer0 nft list chain inet \
+		filter output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
+	if [ -z "${MARK_DROP_COUNTER}" ]; then
+		printf '%s\n' "unable to read nft drop counter"
+		return 1
+	fi
+}
+
+ovpn_mark_verify_drop_traffic() {
+	local p
+	local ping_output
+	local lost_packets
+	local total_count
+
+	for p in $(seq 1 3); do
+		if ping_output=$(ip netns exec ovpn_peer0 ping -qfc 500 -w 1 \
+			5.5.5.$((p + 1)) 2>&1); then
+			printf '%s\n' "expected ping to peer ${p} to fail \
+				after nft drop rule"
+			return 1
+		fi
+		ovpn_log "${ping_output}"
+		lost_packets=$(echo "${ping_output}" | \
+				awk '/packets transmitted/ { print $1 }')
+		if [ -z "${lost_packets}" ]; then
+			printf '%s\n' "unable to parse lost packets for peer \
+				${p}"
+			return 1
+		fi
+		MARK_DROP_COUNTER=$((MARK_DROP_COUNTER + lost_packets))
+	done
+
+	total_count=$(ip netns exec ovpn_peer0 nft list chain inet filter \
+		output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
+	if [ -z "${total_count}" ]; then
+		printf '%s\n' "unable to read final nft drop counter"
+		return 1
+	fi
+	if [ "${MARK_DROP_COUNTER}" -ne "${total_count}" ]; then
+		printf '%s\n' "expected ${MARK_DROP_COUNTER} drops, got \
+			${total_count}"
+		return 1
+	fi
+}
+
+ovpn_mark_remove_drop_rule() {
+	ovpn_log "Removing the drop rule"
+
+	ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
+		ruleset
+}
+
+ovpn_mark_verify_traffic_recovery() {
+	local p
+
+	sleep 1
+	for p in $(seq 1 3); do
+		ovpn_cmd_ok "send recovery traffic to peer ${p}" \
+			ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+				5.5.5.$((p + 1))
+	done
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+ktap_set_plan 6
 
 ovpn_cleanup
+modprobe -q ovpn || true
 
-modprobe -r ovpn || true
+ovpn_run_stage "setup marked network topology" ovpn_mark_prepare_network
+ovpn_run_stage "run baseline traffic" ovpn_mark_run_baseline_traffic
+ovpn_run_stage "install nft mark drop rule" ovpn_mark_add_drop_rule
+ovpn_run_stage "drop marked traffic and count packets" \
+	ovpn_mark_verify_drop_traffic
+ovpn_run_stage "remove nft drop rule" ovpn_mark_remove_drop_rule
+ovpn_run_stage "traffic recovers after drop removal" \
+	ovpn_mark_verify_traffic_recovery
+
+ovpn_test_finished=1
+ktap_finished
diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh
index b766f4842940..eca653112aeb 100755
--- a/tools/testing/selftests/net/ovpn/test.sh
+++ b/tools/testing/selftests/net/ovpn/test.sh
@@ -5,164 +5,313 @@
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
 #set -x
-set -e
+set -eE
 
 source ./common.sh
-server_ns="ovpn_peer0"
 
-ovpn_cleanup
+ovpn_test_finished=0
 
-modprobe -q ovpn || true
+ovpn_test_exit() {
+	ovpn_cleanup
+	modprobe -r ovpn || true
 
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_create_ns ${p}
-done
-
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_setup_listener ${p}
-done
-
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU}
-done
-
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_add_peer ${p}
-done
-
-for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 60 120
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
-		$((${p}+OVPN_ID_OFFSET)) 60 120
-done
-
-sleep 1
-
-TCPDUMP_TIMEOUT="1.5s"
-for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-	# The first part of the data packet header consists of:
-	# - TCP only: 2 bytes for the packet length
-	# - 5 bits for opcode ("9" for DATA_V2)
-	# - 3 bits for key-id ("0" at this point)
-	# - 12 bytes for peer-id:
-	#     - with asymmetric ID: "${p}" one way and "${p} + 9" the other way
-	#     - with symmetric ID: "${p}" both ways
-	HEADER1=$(printf "0x4800000%x" ${p})
-	HEADER2=$(printf "0x4800000%x" $((${p} + OVPN_ID_OFFSET)))
-	RADDR=""
-	if [ "${OVPN_PROTO}" == "UDP" ]; then
-		RADDR=$(awk "NR == ${p} {print \$3}" ${OVPN_UDP_PEERS_FILE})
+	if [ "${ovpn_test_finished}" -eq 0 ]; then
+		ktap_print_totals
 	fi
+}
+
+ovpn_prepare_network() {
+	local p
+	local peer_ns
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+	done
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "start notification listener peer${p}" \
+			ovpn_setup_listener "${p}"
+	done
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+			"${p}" 5.5.5.$((p + 1))/24 "${MTU}"
+	done
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+	done
 
-	timeout ${TCPDUMP_TIMEOUT} ip netns exec "ovpn_peer${p}" \
-		tcpdump --immediate-mode -p -ni veth${p} -c 1 \
-		"$(ovpn_build_capture_filter "${HEADER1}" "${RADDR}")" \
-		>/dev/null 2>&1 &
-	TCPDUMP_PID1=$!
-	timeout ${TCPDUMP_TIMEOUT} ip netns exec "ovpn_peer${p}" \
-		tcpdump --immediate-mode -p -ni veth${p} -c 1 \
-		"$(ovpn_build_capture_filter "${HEADER2}" "${RADDR}")" \
-		>/dev/null 2>&1 &
-	TCPDUMP_PID2=$!
-
-	sleep 0.3
-	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
-	ip netns exec "${server_ns}" ping -qfc 500 -s 3000 -w 3 \
-		5.5.5.$((${p} + 1))
-
-	wait ${TCPDUMP_PID1}
-	wait ${TCPDUMP_PID2}
-done
-
-# ping LAN behind client 1
-ip netns exec "${server_ns}" ping -qfc 500 -w 3 ${OVPN_LAN_IP}
-
-if [ "$OVPN_FLOAT" == "1" ]; then
-	# make clients float..
 	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-		ip -n "ovpn_peer${p}" addr del 10.10.${p}.2/24 dev veth${p}
-		ip -n "ovpn_peer${p}" addr add 10.10.${p}.3/24 dev veth${p}
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+			ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+				${p} 60 120
+		ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+				tun${p} $((p + OVPN_ID_OFFSET)) 60 120
 	done
+}
+
+ovpn_run_basic_traffic() {
+	local p
+	local header1
+	local header2
+	local peer_ns
+	local raddr
+	local tcpdump_pid1
+	local tcpdump_pid2
+	local tcpdump_timeout="1.5s"
+
 	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-		ip netns exec "ovpn_peer${p}" ping -qfc 500 -w 3 5.5.5.1
+		# The first part of the data packet header consists of:
+		# - TCP only: 2 bytes for the packet length
+		# - 5 bits for opcode ("9" for DATA_V2)
+		# - 3 bits for key-id ("0" at this point)
+		# - 12 bytes for peer-id:
+		#     - with asymmetric ID: "${p}" one way and "${p} + 9" the
+		#	other way
+		#     - with symmetric ID: "${p}" both ways
+		header1=$(printf "0x4800000%x" ${p})
+		header2=$(printf "0x4800000%x" $((p + OVPN_ID_OFFSET)))
+		raddr=""
+		if [ "${OVPN_PROTO}" == "UDP" ]; then
+			raddr=$(awk "NR == ${p} {print \$3}" \
+				"${OVPN_UDP_PEERS_FILE}")
+		fi
+		peer_ns="ovpn_peer${p}"
+
+		timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
+			tcpdump --immediate-mode -p -ni veth${p} -c 1 \
+			"$(ovpn_build_capture_filter "${header1}" "${raddr}")" \
+			>/dev/null 2>&1 &
+		tcpdump_pid1=$!
+		timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
+			tcpdump --immediate-mode -p -ni veth${p} -c 1 \
+			"$(ovpn_build_capture_filter "${header2}" "${raddr}")" \
+			>/dev/null 2>&1 &
+		tcpdump_pid2=$!
+
+		sleep 0.3
+		ovpn_cmd_ok "send baseline traffic to peer ${p}" \
+			ip netns exec ovpn_peer0 \
+			ping -qfc 500 -w 3 5.5.5.$((p + 1))
+		ovpn_cmd_ok "send large-payload traffic to peer ${p}" \
+			ip netns exec ovpn_peer0 \
+			ping -qfc 500 -s 3000 -w 3 5.5.5.$((p + 1))
+
+		wait "${tcpdump_pid1}" || return 1
+		wait "${tcpdump_pid2}" || return 1
 	done
-fi
+}
+
+ovpn_run_lan_traffic() {
+	ovpn_cmd_ok "ping LAN behind peer1" \
+		ip netns exec ovpn_peer0 ping -qfc 500 -w 3 "${OVPN_LAN_IP}"
+}
+
+ovpn_run_float_mode() {
+	local p
+	local peer_ns
+
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "float: remove old transport address on peer${p}" \
+			ip -n "${peer_ns}" addr del 10.10.${p}.2/24 dev veth${p}
+		ovpn_cmd_ok "float: add new transport address on peer${p}" \
+			ip -n "${peer_ns}" addr add 10.10.${p}.3/24 dev veth${p}
+	done
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "ping tunnel after float peer ${p}" \
+			ip netns exec "${peer_ns}" ping -qfc 500 -w 3 5.5.5.1
+	done
+}
+
+ovpn_run_iperf() {
+	local iperf_pid
+
+	ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s
+	sleep 1
+
+	ovpn_cmd_ok "run iperf throughput flow" \
+		ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
+	wait "${iperf_pid}" || return 1
+}
+
+ovpn_run_key_rollover() {
+	local p
+	local peer_ns
+
+	ovpn_log "Adding secondary key and then swap:"
+
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "add secondary key on peer0 for peer ${p}" \
+			ip netns exec ovpn_peer0 ${OVPN_CLI} new_key tun0 \
+				${p} 2 1 ${OVPN_ALG} 0 data64.key
+		ovpn_cmd_ok "add secondary key on peer${p} for peer ${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${p} \
+				$((p + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 \
+				data64.key
+		ovpn_cmd_ok "swap keys on peer${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} swap_keys \
+				tun${p} $((p + OVPN_ID_OFFSET))
+	done
+}
+
+ovpn_run_queries() {
+	ovpn_log "Querying all peers:"
+
+	ovpn_cmd_ok "query all peers from peer0" \
+		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0
+	ovpn_cmd_ok "query all peers from peer1" \
+		ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1
 
-ip netns exec "${server_ns}" iperf3 -1 -s &
-sleep 1
-ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
-
-echo "Adding secondary key and then swap:"
-for p in $(seq 1 ${OVPN_NUM_PEERS}); do
-	ip netns exec "${server_ns}" ${OVPN_CLI} new_key tun0 ${p} 2 1 \
-		${OVPN_ALG} 0 data64.key
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} new_key tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 data64.key
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} swap_keys tun${p} \
-		$((${p} + OVPN_ID_OFFSET))
-done
-
-sleep 1
-
-echo "Querying all peers:"
-ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0
-ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1
-
-echo "Querying peer 1:"
-ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0 1
-
-echo "Querying non-existent peer 20:"
-ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0 20 || true
-
-echo "Deleting peer 1:"
-ip netns exec "${server_ns}" ${OVPN_CLI} del_peer tun0 1
-ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 $((1 + OVPN_ID_OFFSET))
-
-echo "Querying keys:"
-for p in $(seq 2 ${OVPN_NUM_PEERS}); do
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} get_key tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 1
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} get_key tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 2
-done
-
-echo "Deleting peer while sending traffic:"
-(ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1)&
-sleep 2
-ip netns exec "${server_ns}" ${OVPN_CLI} del_peer tun0 2
-# following command fails in TCP mode
-# (both ends get conn reset when one peer disconnects)
-ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET)) || \
-	true
-
-echo "Deleting keys:"
-for p in $(seq 3 ${OVPN_NUM_PEERS}); do
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} del_key tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 1
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} del_key tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 2
-done
-
-echo "Setting timeout to 3s MP:"
-for p in $(seq 3 ${OVPN_NUM_PEERS}); do
-	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 0 0
-done
-# wait for peers to timeout
-sleep 5
-
-echo "Setting timeout to 3s P2P:"
-for p in $(seq 3 ${OVPN_NUM_PEERS}); do
-	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
-		$((${p} + OVPN_ID_OFFSET)) 3 3
-done
-sleep 5
-
-for p in $(seq 0 ${OVPN_NUM_PEERS}); do
-	ovpn_compare_ntfs ${p}
-done
+	ovpn_log "Querying peer 1:"
+
+	ovpn_cmd_ok "query peer 1 from peer0" \
+		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 1
+}
+
+ovpn_query_peer_missing() {
+	ovpn_log "Querying non-existent peer 20:"
+
+	ovpn_cmd_fail "query missing peer 20 on peer0" \
+		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 20
+}
+
+ovpn_run_peer_cleanup() {
+	local p
+	local peer_ns
+
+	ovpn_log "Deleting peer 1:"
+
+	ovpn_cmd_ok "delete peer1 on peer0" \
+		ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 1
+	ovpn_cmd_ok "delete peer1 on peer1" \
+		ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 \
+			$((1 + OVPN_ID_OFFSET))
+
+	ovpn_log "Querying keys:"
+
+	for p in $(seq 2 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "query peer${p} key 1" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
+				$((p + OVPN_ID_OFFSET)) 1
+		ovpn_cmd_ok "query peer${p} key 2" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
+				$((p + OVPN_ID_OFFSET)) 2
+	done
+}
+
+ovpn_run_traffic_delete_peer() {
+	local ping_pid
+
+	ovpn_log "Deleting peer while sending traffic:"
+
+	ovpn_run_bg ping_pid ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1
+	sleep 2
+	ovpn_cmd_ok "delete peer0 peer 2" \
+		ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 2
+
+	if [ "${OVPN_PROTO}" == "TCP" ]; then
+		# In TCP mode this command is expected to fail for both peers.
+		ovpn_cmd_mayfail "delete peer2 peer 2 (TCP non-fatal)" \
+			ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 \
+				$((2 + OVPN_ID_OFFSET))
+	else
+		ovpn_cmd_ok "delete peer2 peer 2" ip netns exec ovpn_peer2 \
+			${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET))
+	fi
+
+	wait "${ping_pid}" || true
+}
+
+ovpn_run_key_cleanup() {
+	local p
+	local peer_ns
+
+	ovpn_log "Deleting keys:"
+
+	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "delete key 1 for peer${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
+				$((p + OVPN_ID_OFFSET)) 1
+		ovpn_cmd_ok "delete key 2 for peer${p}" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
+				$((p + OVPN_ID_OFFSET)) 2
+	done
+}
+
+ovpn_run_timeouts() {
+	local p
+	local peer_ns
+
+	ovpn_log "Setting timeout to 3s MP:"
+
+	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+		# Non-fatal: this may fail in some protocol modes.
+		ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \
+			ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+				${p} 3 3
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \
+			state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+			tun${p} $((p + OVPN_ID_OFFSET)) 0 0
+	done
+	# wait for peers to timeout
+	sleep 5
+
+	ovpn_log "Setting timeout to 3s P2P:"
+
+	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+		peer_ns="ovpn_peer${p}"
+		ovpn_cmd_ok "set peer${p} P2P timeout" \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+				tun${p} $((p + OVPN_ID_OFFSET)) 3 3
+	done
+	sleep 5
+}
+
+ovpn_run_notifications() {
+	local p
+
+	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+		ovpn_cmd_ok "validate listener output for peer ${p}" \
+			ovpn_compare_ntfs "${p}"
+	done
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+if [ "${OVPN_FLOAT}" == "1" ]; then
+	ktap_set_plan 13
+else
+	ktap_set_plan 12
+fi
 
 ovpn_cleanup
+modprobe -q ovpn || true
+
+ovpn_run_stage "setup network topology" ovpn_prepare_network
+ovpn_run_stage "run baseline data traffic" ovpn_run_basic_traffic
+ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic
+[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \
+	ovpn_run_float_mode
+ovpn_run_stage "run iperf throughput" ovpn_run_iperf
+ovpn_run_stage "run key rollout" ovpn_run_key_rollover
+ovpn_run_stage "query peers" ovpn_run_queries
+ovpn_run_stage "query missing peer fails" ovpn_query_peer_missing
+ovpn_run_stage "peer lifecycle and key queries" ovpn_run_peer_cleanup
+ovpn_run_stage "delete peer while traffic" ovpn_run_traffic_delete_peer
+ovpn_run_stage "delete stale keys" ovpn_run_key_cleanup
+ovpn_run_stage "check timeout behavior" ovpn_run_timeouts
+ovpn_run_stage "validate notification output" ovpn_run_notifications
 
-modprobe -r ovpn || true
+ovpn_test_finished=1
+ktap_finished
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 4/6] selftests: ovpn: add prefix to helpers and shared variables
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

Current naming for shared variables, helpers and netnamespaces is
a bit unfortunate as it doesn't come with a clean prefix.
This showed to be problematic in case of name clashes with external
scripts or in case of abrupt test termination (hanging netns' weren't
easily reconducible to ovpn).

Rename common helper entry points and all shared globals in the ovpn
selftests to ovpn_ or OVPN_ names so test scripts and wrappers use a
single explicit prefix. Also rename the temporary network namespaces
created by the tests from peerN to ovpn_peerN. This makes leaked
namespaces easier to identify.

This is a mechanical refactor only, behavior is unchanged.

Fixes: 959bc330a439 ("testing/selftests: add test tool and scripts for ovpn module")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/common.sh    | 186 ++++++++++--------
 .../selftests/net/ovpn/test-chachapoly.sh     |   2 +-
 .../net/ovpn/test-close-socket-tcp.sh         |   2 +-
 .../selftests/net/ovpn/test-close-socket.sh   |  32 +--
 .../testing/selftests/net/ovpn/test-float.sh  |   2 +-
 tools/testing/selftests/net/ovpn/test-mark.sh |  45 ++---
 .../net/ovpn/test-symmetric-id-float.sh       |   4 +-
 .../net/ovpn/test-symmetric-id-tcp.sh         |   4 +-
 .../selftests/net/ovpn/test-symmetric-id.sh   |   2 +-
 tools/testing/selftests/net/ovpn/test-tcp.sh  |   2 +-
 tools/testing/selftests/net/ovpn/test.sh      | 139 ++++++-------
 11 files changed, 226 insertions(+), 194 deletions(-)

diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh
index d3b322e84fab..38f187b9de23 100644
--- a/tools/testing/selftests/net/ovpn/common.sh
+++ b/tools/testing/selftests/net/ovpn/common.sh
@@ -4,63 +4,72 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
-UDP_PEERS_FILE=${UDP_PEERS_FILE:-udp_peers.txt}
-TCP_PEERS_FILE=${TCP_PEERS_FILE:-tcp_peers.txt}
+OVPN_UDP_PEERS_FILE=${OVPN_UDP_PEERS_FILE:-udp_peers.txt}
+OVPN_TCP_PEERS_FILE=${OVPN_TCP_PEERS_FILE:-tcp_peers.txt}
 OVPN_CLI=${OVPN_CLI:-./ovpn-cli}
-YNL_CLI=${YNL_CLI:-../../../../net/ynl/pyynl/cli.py}
-ALG=${ALG:-aes}
-PROTO=${PROTO:-UDP}
-FLOAT=${FLOAT:-0}
-SYMMETRIC_ID=${SYMMETRIC_ID:-0}
+OVPN_YNL=${OVPN_YNL:-../../../../net/ynl/pyynl/cli.py}
+OVPN_ALG=${OVPN_ALG:-aes}
+OVPN_PROTO=${OVPN_PROTO:-UDP}
+OVPN_FLOAT=${OVPN_FLOAT:-0}
+OVPN_SYMMETRIC_ID=${OVPN_SYMMETRIC_ID:-0}
 
-export ID_OFFSET=$(( 9 * (SYMMETRIC_ID == 0) ))
+export OVPN_ID_OFFSET=$(( 9 * (OVPN_SYMMETRIC_ID == 0) ))
 
-JQ_FILTER='map(if type == "array" then .[] else . end) |
+OVPN_JQ_FILTER='map(if type == "array" then .[] else . end) |
 	map(select(.msg.peer | has("remote-ipv6") | not)) |
 	map(del(.msg.ifindex)) | sort_by(.msg.peer.id)[]'
-LAN_IP="11.11.11.11"
+OVPN_LAN_IP="11.11.11.11"
 
-declare -A tmp_jsons=()
-declare -A listener_pids=()
+declare -A OVPN_TMP_JSONS=()
+declare -A OVPN_LISTENER_PIDS=()
 
-create_ns() {
-	ip netns add peer${1}
+ovpn_create_ns() {
+	ip netns add "ovpn_peer${1}"
 }
 
-setup_ns() {
+ovpn_setup_ns() {
+	local peer="ovpn_peer${1}"
+	local server_ns="ovpn_peer0"
+	local peer_ns
 	MODE="P2P"
 
 	if [ ${1} -eq 0 ]; then
 		MODE="MP"
-		for p in $(seq 1 ${NUM_PEERS}); do
-			ip link add veth${p} netns peer0 type veth peer name veth${p} netns peer${p}
-
-			ip -n peer0 addr add 10.10.${p}.1/24 dev veth${p}
-			ip -n peer0 addr add fd00:0:0:${p}::1/64 dev veth${p}
-			ip -n peer0 link set veth${p} up
-
-			ip -n peer${p} addr add 10.10.${p}.2/24 dev veth${p}
-			ip -n peer${p} addr add fd00:0:0:${p}::2/64 dev veth${p}
-			ip -n peer${p} link set veth${p} up
+		for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+			peer_ns="ovpn_peer${p}"
+			ip link add veth${p} netns "${server_ns}" type veth \
+				peer name veth${p} netns "${peer_ns}"
+
+			ip -n "${server_ns}" addr add 10.10.${p}.1/24 dev \
+				veth${p}
+			ip -n "${server_ns}" addr add fd00:0:0:${p}::1/64 dev \
+				veth${p}
+			ip -n "${server_ns}" link set veth${p} up
+
+			ip -n "${peer_ns}" addr add 10.10.${p}.2/24 dev veth${p}
+			ip -n "${peer_ns}" addr add fd00:0:0:${p}::2/64 dev \
+				veth${p}
+			ip -n "${peer_ns}" link set veth${p} up
 		done
 	fi
 
-	ip netns exec peer${1} ${OVPN_CLI} new_iface tun${1} $MODE
-	ip -n peer${1} addr add ${2} dev tun${1}
+	ip netns exec "${peer}" ${OVPN_CLI} new_iface tun${1} $MODE
+	ip -n "${peer}" addr add ${2} dev tun${1}
 	# add a secondary IP to peer 1, to test a LAN behind a client
-	if [ ${1} -eq 1 -a -n "${LAN_IP}" ]; then
-		ip -n peer${1} addr add ${LAN_IP} dev tun${1}
-		ip -n peer0 route add ${LAN_IP} via $(echo ${2} |sed -e s'!/.*!!') dev tun0
+	if [ ${1} -eq 1 -a -n "${OVPN_LAN_IP}" ]; then
+		ip -n "${peer}" addr add ${OVPN_LAN_IP} dev tun${1}
+		ip -n "${server_ns}" route add ${OVPN_LAN_IP} via \
+			$(echo ${2} |sed -e s'!/.*!!') dev tun0
 	fi
 	if [ -n "${3}" ]; then
-		ip -n peer${1} link set mtu ${3} dev tun${1}
+		ip -n "${peer}" link set mtu ${3} dev tun${1}
 	fi
-	ip -n peer${1} link set tun${1} up
+	ip -n "${peer}" link set tun${1} up
 }
 
-build_capture_filter() {
+ovpn_build_capture_filter() {
 	# match the first four bytes of the openvpn data payload
-	if [ "${PROTO}" == "UDP" ]; then
+	if [ "${OVPN_PROTO}" == "UDP" ]; then
 		# For UDP, libpcap transport indexing only works for IPv4, so
 		# use an explicit IPv4 or IPv6 expression based on the peer
 		# address. The IPv6 branch assumes there are no extension
@@ -77,86 +86,98 @@ build_capture_filter() {
 	fi
 }
 
-setup_listener() {
+ovpn_setup_listener() {
+	local peer_ns="ovpn_peer${p}"
 	file=$(mktemp)
-	PYTHONUNBUFFERED=1 ip netns exec peer${p} ${YNL_CLI} --family ovpn \
-		--subscribe peers --output-json --duration 40 > ${file} &
-	listener_pids[$1]=$!
-	tmp_jsons[$1]="${file}"
+	PYTHONUNBUFFERED=1 ip netns exec "${peer_ns}" "${OVPN_YNL}" --family \
+		ovpn --subscribe peers --output-json --duration 40 > ${file} &
+	OVPN_LISTENER_PIDS[$1]=$!
+	OVPN_TMP_JSONS[$1]="${file}"
 }
 
-add_peer() {
+ovpn_add_peer() {
 	labels=("ASYMM" "SYMM")
-	M_ID=${labels[SYMMETRIC_ID]}
+	local peer_ns
+	local server_ns="ovpn_peer0"
+	M_ID=${labels[OVPN_SYMMETRIC_ID]}
 
-	if [ "${PROTO}" == "UDP" ]; then
+	if [ "${OVPN_PROTO}" == "UDP" ]; then
 		if [ ${1} -eq 0 ]; then
-			ip netns exec peer0 ${OVPN_CLI} new_multi_peer tun0 1 \
-				${M_ID} ${UDP_PEERS_FILE}
+			ip netns exec "${server_ns}" ${OVPN_CLI} \
+				new_multi_peer tun0 1 ${M_ID} \
+				${OVPN_UDP_PEERS_FILE}
 
-			for p in $(seq 1 ${NUM_PEERS}); do
-				ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 ${ALG} 0 \
+			for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+				ip netns exec "${server_ns}" ${OVPN_CLI} \
+					new_key tun0 ${p} 1 0 ${OVPN_ALG} 0 \
 					data64.key
 			done
 		else
-			if [ "${SYMMETRIC_ID}" -eq 1 ]; then
+			peer_ns="ovpn_peer${1}"
+			if [ "${OVPN_SYMMETRIC_ID}" -eq 1 ]; then
 				PEER_ID=${1}
 				TX_ID="none"
 			else
 				PEER_ID=$(awk "NR == ${1} {print \$2}" \
-					${UDP_PEERS_FILE})
+					${OVPN_UDP_PEERS_FILE})
 				TX_ID=${1}
 			fi
-			RADDR=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE})
-			RPORT=$(awk "NR == ${1} {print \$4}" ${UDP_PEERS_FILE})
-			LPORT=$(awk "NR == ${1} {print \$6}" ${UDP_PEERS_FILE})
-			ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} \
-				${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} ${RPORT}
-			ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} \
-				${PEER_ID} 1 0 ${ALG} 1 data64.key
+			RADDR=$(awk "NR == ${1} {print \$3}" \
+				${OVPN_UDP_PEERS_FILE})
+			RPORT=$(awk "NR == ${1} {print \$4}" \
+				${OVPN_UDP_PEERS_FILE})
+			LPORT=$(awk "NR == ${1} {print \$6}" \
+				${OVPN_UDP_PEERS_FILE})
+			ip netns exec "${peer_ns}" ${OVPN_CLI} new_peer \
+				tun${1} ${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} \
+				${RPORT}
+			ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${1} \
+				${PEER_ID} 1 0 ${OVPN_ALG} 1 data64.key
 		fi
 	else
 		if [ ${1} -eq 0 ]; then
-			(ip netns exec peer0 ${OVPN_CLI} listen tun0 1 ${M_ID} \
-				${TCP_PEERS_FILE} && {
-				for p in $(seq 1 ${NUM_PEERS}); do
-					ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 \
-						${ALG} 0 data64.key
+			(ip netns exec "${server_ns}" ${OVPN_CLI} listen tun0 \
+				1 ${M_ID} ${OVPN_TCP_PEERS_FILE} && {
+				for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+					ip netns exec "${server_ns}" \
+						${OVPN_CLI} new_key tun0 ${p} \
+						1 0 ${OVPN_ALG} 0 data64.key
 				done
 			}) &
 			sleep 5
 		else
-			if [ "${SYMMETRIC_ID}" -eq 1 ]; then
+			peer_ns="ovpn_peer${1}"
+			if [ "${OVPN_SYMMETRIC_ID}" -eq 1 ]; then
 				PEER_ID=${1}
 				TX_ID="none"
 			else
 				PEER_ID=$(awk "NR == ${1} {print \$2}" \
-					${TCP_PEERS_FILE})
+					${OVPN_TCP_PEERS_FILE})
 				TX_ID=${1}
 			fi
-			ip netns exec peer${1} ${OVPN_CLI} connect tun${1} \
+			ip netns exec "${peer_ns}" ${OVPN_CLI} connect tun${1} \
 				${PEER_ID} ${TX_ID} 10.10.${1}.1 1 data64.key
 		fi
 	fi
 }
 
-compare_ntfs() {
+ovpn_compare_ntfs() {
 	local diff_rc=0
 	local diff_file
 
-	if [ ${#tmp_jsons[@]} -gt 0 ]; then
+	if [ ${#OVPN_TMP_JSONS[@]} -gt 0 ]; then
 		suffix=""
-		[ "${SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm"
-		[ "$FLOAT" == 1 ] && suffix="${suffix}-float"
+		[ "${OVPN_SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm"
+		[ "$OVPN_FLOAT" == 1 ] && suffix="${suffix}-float"
 		expected="json/peer${1}${suffix}.json"
-		received="${tmp_jsons[$1]}"
+		received="${OVPN_TMP_JSONS[$1]}"
 		diff_file=$(mktemp)
 
-		kill -TERM ${listener_pids[$1]} || true
-		wait ${listener_pids[$1]} || true
+		kill -TERM ${OVPN_LISTENER_PIDS[$1]} || true
+		wait ${OVPN_LISTENER_PIDS[$1]} || true
 		printf "Checking notifications for peer ${1}... "
-		if diff <(jq -s "${JQ_FILTER}" ${expected}) \
-			<(jq -s "${JQ_FILTER}" ${received}) \
+		if diff <(jq -s "${OVPN_JQ_FILTER}" ${expected}) \
+			<(jq -s "${OVPN_JQ_FILTER}" ${received}) \
 			>"${diff_file}" 2>&1; then
 			echo "OK"
 		else
@@ -172,25 +193,30 @@ compare_ntfs() {
 	return "${diff_rc}"
 }
 
-cleanup() {
+ovpn_cleanup() {
+	local peer_ns
 	# some ovpn-cli processes sleep in background so they need manual poking
 	killall $(basename ${OVPN_CLI}) 2>/dev/null || true
 
 	# netns peer0 is deleted without erasing ifaces first
 	for p in $(seq 1 10); do
-		ip -n peer${p} link set tun${p} down 2>/dev/null || true
-		ip netns exec peer${p} ${OVPN_CLI} del_iface tun${p} 2>/dev/null || true
+		peer_ns="ovpn_peer${p}"
+		ip -n "${peer_ns}" link set tun${p} down 2>/dev/null || true
+		ip netns exec "${peer_ns}" ${OVPN_CLI} del_iface tun${p} \
+			2>/dev/null || true
 	done
 	for p in $(seq 1 10); do
-		ip -n peer0 link del veth${p} 2>/dev/null || true
+		ip -n ovpn_peer0 link del veth${p} 2>/dev/null || true
 	done
 	for p in $(seq 0 10); do
-		ip netns del peer${p} 2>/dev/null || true
+		ip netns del "ovpn_peer${p}" 2>/dev/null || true
 	done
 }
 
-if [ "${PROTO}" == "UDP" ]; then
-	NUM_PEERS=${NUM_PEERS:-$(wc -l ${UDP_PEERS_FILE} | awk '{print $1}')}
+if [ "${OVPN_PROTO}" == "UDP" ]; then
+	OVPN_NUM_PEERS=${OVPN_NUM_PEERS:-$(wc -l ${OVPN_UDP_PEERS_FILE} | \
+		awk '{print $1}')}
 else
-	NUM_PEERS=${NUM_PEERS:-$(wc -l ${TCP_PEERS_FILE} | awk '{print $1}')}
+	OVPN_NUM_PEERS=${OVPN_NUM_PEERS:-$(wc -l ${OVPN_TCP_PEERS_FILE} | \
+		awk '{print $1}')}
 fi
diff --git a/tools/testing/selftests/net/ovpn/test-chachapoly.sh b/tools/testing/selftests/net/ovpn/test-chachapoly.sh
index 32504079a2b8..cd3d94355d58 100755
--- a/tools/testing/selftests/net/ovpn/test-chachapoly.sh
+++ b/tools/testing/selftests/net/ovpn/test-chachapoly.sh
@@ -4,6 +4,6 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
-ALG="chachapoly"
+OVPN_ALG="chachapoly"
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh b/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
index 093d44772ffd..392d269bada5 100755
--- a/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
@@ -4,6 +4,6 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
-PROTO="TCP"
+OVPN_PROTO="TCP"
 
 source test-close-socket.sh
diff --git a/tools/testing/selftests/net/ovpn/test-close-socket.sh b/tools/testing/selftests/net/ovpn/test-close-socket.sh
index 0d09df14fe8e..6bc1b6eab8ac 100755
--- a/tools/testing/selftests/net/ovpn/test-close-socket.sh
+++ b/tools/testing/selftests/net/ovpn/test-close-socket.sh
@@ -8,38 +8,40 @@
 set -e
 
 source ./common.sh
+server_ns="ovpn_peer0"
 
-cleanup
+ovpn_cleanup
 
 modprobe -q ovpn || true
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	create_ns ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_create_ns ${p}
 done
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	setup_ns ${p} 5.5.5.$((${p} + 1))/24
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_setup_ns ${p} 5.5.5.$((${p} + 1))/24
 done
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	add_peer ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_add_peer ${p}
 done
 
-for p in $(seq 1 ${NUM_PEERS}); do
-	ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
-	ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} $((${p}+9)) 60 120
+for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 60 120
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} $((${p}+9)) \
+		60 120
 done
 
 sleep 1
 
-for p in $(seq 1 ${NUM_PEERS}); do
-	ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
+for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
 done
 
-ip netns exec peer0 iperf3 -1 -s &
+ip netns exec "${server_ns}" iperf3 -1 -s &
 sleep 1
-ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
+ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
 
-cleanup
+ovpn_cleanup
 
 modprobe -r ovpn || true
diff --git a/tools/testing/selftests/net/ovpn/test-float.sh b/tools/testing/selftests/net/ovpn/test-float.sh
index ba5d725e18b0..91f8e113718e 100755
--- a/tools/testing/selftests/net/ovpn/test-float.sh
+++ b/tools/testing/selftests/net/ovpn/test-float.sh
@@ -4,6 +4,6 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
-FLOAT="1"
+OVPN_FLOAT="1"
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-mark.sh b/tools/testing/selftests/net/ovpn/test-mark.sh
index 8534428ed3eb..2ee5dc5fc538 100755
--- a/tools/testing/selftests/net/ovpn/test-mark.sh
+++ b/tools/testing/selftests/net/ovpn/test-mark.sh
@@ -11,62 +11,63 @@ set -e
 MARK=1056
 
 source ./common.sh
+server_ns="ovpn_peer0"
 
-cleanup
+ovpn_cleanup
 
 modprobe -q ovpn || true
 
-for p in $(seq 0 "${NUM_PEERS}"); do
-	create_ns "${p}"
+for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
+	ovpn_create_ns "${p}"
 done
 
 for p in $(seq 0 3); do
-	setup_ns "${p}" 5.5.5.$((p + 1))/24
+	ovpn_setup_ns "${p}" 5.5.5.$((p + 1))/24
 done
 
 # add peer0 with mark
-ip netns exec peer0 "${OVPN_CLI}" new_multi_peer tun0 1 ASYMM \
-	"${UDP_PEERS_FILE}" \
+ip netns exec "${server_ns}" "${OVPN_CLI}" new_multi_peer tun0 1 ASYMM \
+	"${OVPN_UDP_PEERS_FILE}" \
 	${MARK}
 for p in $(seq 1 3); do
-	ip netns exec peer0 "${OVPN_CLI}" new_key tun0 "${p}" 1 0 "${ALG}" 0 \
-		data64.key
+	ip netns exec "${server_ns}" "${OVPN_CLI}" new_key tun0 "${p}" 1 0 \
+		"${OVPN_ALG}" 0 data64.key
 done
 
 for p in $(seq 1 3); do
-	add_peer "${p}"
+	ovpn_add_peer "${p}"
 done
 
 for p in $(seq 1 3); do
-	ip netns exec peer0 "${OVPN_CLI}" set_peer tun0 "${p}" 60 120
-	ip netns exec peer"${p}" "${OVPN_CLI}" set_peer tun"${p}" \
+	ip netns exec "${server_ns}" "${OVPN_CLI}" set_peer tun0 "${p}" 60 120
+	ip netns exec "ovpn_peer${p}" "${OVPN_CLI}" set_peer tun"${p}" \
 		$((p + 9)) 60 120
 done
 
 sleep 1
 
 for p in $(seq 1 3); do
-	ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1))
+	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((p + 1))
 done
 
 echo "Adding an nftables drop rule based on mark value ${MARK}"
-ip netns exec peer0 nft flush ruleset
-ip netns exec peer0 nft 'add table inet filter'
-ip netns exec peer0 nft 'add chain inet filter output {
+ip netns exec "${server_ns}" nft flush ruleset
+ip netns exec "${server_ns}" nft 'add table inet filter'
+ip netns exec "${server_ns}" nft 'add chain inet filter output {
 	type filter hook output priority 0;
 	policy accept;
 }'
-ip netns exec peer0 nft add rule inet filter output \
+ip netns exec "${server_ns}" nft add rule inet filter output \
 	meta mark == ${MARK} \
 	counter drop
 
-DROP_COUNTER=$(ip netns exec peer0 nft list chain inet filter output \
+DROP_COUNTER=$(ip netns exec "${server_ns}" nft list chain inet filter output \
 	| sed -n 's/.*packets \([0-9]*\).*/\1/p')
 sleep 1
 
 # ping should fail
 for p in $(seq 1 3); do
-	PING_OUTPUT=$(ip netns exec peer0 ping \
+	PING_OUTPUT=$(ip netns exec "${server_ns}" ping \
 		-qfc 500 -w 1 5.5.5.$((p + 1)) 2>&1) && exit 1
 	echo "${PING_OUTPUT}"
 	LOST_PACKETS=$(echo "$PING_OUTPUT" \
@@ -76,7 +77,7 @@ for p in $(seq 1 3); do
 done
 
 # check if the final nft counter matches our counter
-TOTAL_COUNT=$(ip netns exec peer0 nft list chain inet filter output \
+TOTAL_COUNT=$(ip netns exec "${server_ns}" nft list chain inet filter output \
 	| sed -n 's/.*packets \([0-9]*\).*/\1/p')
 if [ "${DROP_COUNTER}" -ne "${TOTAL_COUNT}" ]; then
 	echo "Expected ${TOTAL_COUNT} drops, got ${DROP_COUNTER}"
@@ -84,13 +85,13 @@ if [ "${DROP_COUNTER}" -ne "${TOTAL_COUNT}" ]; then
 fi
 
 echo "Removing the drop rule"
-ip netns exec peer0 nft flush ruleset
+ip netns exec "${server_ns}" nft flush ruleset
 sleep 1
 
 for p in $(seq 1 3); do
-	ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1))
+	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((p + 1))
 done
 
-cleanup
+ovpn_cleanup
 
 modprobe -r ovpn || true
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
index b3711a81b463..75296fe72c39 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
@@ -5,7 +5,7 @@
 #	Author:	Ralf Lici <ralf@mandelbit.com>
 #		Antonio Quartulli <antonio@openvpn.net>
 
-SYMMETRIC_ID="1"
-FLOAT="1"
+OVPN_SYMMETRIC_ID="1"
+OVPN_FLOAT="1"
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
index 188cafb67b2f..680a465c49d2 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
@@ -5,7 +5,7 @@
 #	Author:	Ralf Lici <ralf@mandelbit.com>
 #		Antonio Quartulli <antonio@openvpn.net>
 
-PROTO="TCP"
-SYMMETRIC_ID=1
+OVPN_PROTO="TCP"
+OVPN_SYMMETRIC_ID=1
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
index 35b119c72e4f..a2e2808959d9 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
@@ -5,6 +5,6 @@
 #	Author:	Ralf Lici <ralf@mandelbit.com>
 #		Antonio Quartulli <antonio@openvpn.net>
 
-SYMMETRIC_ID="1"
+OVPN_SYMMETRIC_ID="1"
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-tcp.sh b/tools/testing/selftests/net/ovpn/test-tcp.sh
index ba3f1f315a34..27cc6e7b98bc 100755
--- a/tools/testing/selftests/net/ovpn/test-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-tcp.sh
@@ -4,6 +4,6 @@
 #
 #  Author:	Antonio Quartulli <antonio@openvpn.net>
 
-PROTO="TCP"
+OVPN_PROTO="TCP"
 
 source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh
index b60e94a4094e..b766f4842940 100755
--- a/tools/testing/selftests/net/ovpn/test.sh
+++ b/tools/testing/selftests/net/ovpn/test.sh
@@ -8,37 +8,38 @@
 set -e
 
 source ./common.sh
+server_ns="ovpn_peer0"
 
-cleanup
+ovpn_cleanup
 
 modprobe -q ovpn || true
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	create_ns ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_create_ns ${p}
 done
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	setup_listener ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_setup_listener ${p}
 done
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU}
 done
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	add_peer ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_add_peer ${p}
 done
 
-for p in $(seq 1 ${NUM_PEERS}); do
-	ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
-	ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
-		$((${p}+ID_OFFSET)) 60 120
+for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 60 120
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
+		$((${p}+OVPN_ID_OFFSET)) 60 120
 done
 
 sleep 1
 
 TCPDUMP_TIMEOUT="1.5s"
-for p in $(seq 1 ${NUM_PEERS}); do
+for p in $(seq 1 ${OVPN_NUM_PEERS}); do
 	# The first part of the data packet header consists of:
 	# - TCP only: 2 bytes for the packet length
 	# - 5 bits for opcode ("9" for DATA_V2)
@@ -47,119 +48,121 @@ for p in $(seq 1 ${NUM_PEERS}); do
 	#     - with asymmetric ID: "${p}" one way and "${p} + 9" the other way
 	#     - with symmetric ID: "${p}" both ways
 	HEADER1=$(printf "0x4800000%x" ${p})
-	HEADER2=$(printf "0x4800000%x" $((${p} + ID_OFFSET)))
+	HEADER2=$(printf "0x4800000%x" $((${p} + OVPN_ID_OFFSET)))
 	RADDR=""
-	if [ "${PROTO}" == "UDP" ]; then
-		RADDR=$(awk "NR == ${p} {print \$3}" ${UDP_PEERS_FILE})
+	if [ "${OVPN_PROTO}" == "UDP" ]; then
+		RADDR=$(awk "NR == ${p} {print \$3}" ${OVPN_UDP_PEERS_FILE})
 	fi
 
-	timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \
+	timeout ${TCPDUMP_TIMEOUT} ip netns exec "ovpn_peer${p}" \
 		tcpdump --immediate-mode -p -ni veth${p} -c 1 \
-		"$(build_capture_filter "${HEADER1}" "${RADDR}")" \
+		"$(ovpn_build_capture_filter "${HEADER1}" "${RADDR}")" \
 		>/dev/null 2>&1 &
 	TCPDUMP_PID1=$!
-	timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \
+	timeout ${TCPDUMP_TIMEOUT} ip netns exec "ovpn_peer${p}" \
 		tcpdump --immediate-mode -p -ni veth${p} -c 1 \
-		"$(build_capture_filter "${HEADER2}" "${RADDR}")" \
+		"$(ovpn_build_capture_filter "${HEADER2}" "${RADDR}")" \
 		>/dev/null 2>&1 &
 	TCPDUMP_PID2=$!
 
 	sleep 0.3
-	ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
-	ip netns exec peer0 ping -qfc 500 -s 3000 -w 3 5.5.5.$((${p} + 1))
+	ip netns exec "${server_ns}" ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
+	ip netns exec "${server_ns}" ping -qfc 500 -s 3000 -w 3 \
+		5.5.5.$((${p} + 1))
 
 	wait ${TCPDUMP_PID1}
 	wait ${TCPDUMP_PID2}
 done
 
 # ping LAN behind client 1
-ip netns exec peer0 ping -qfc 500 -w 3 ${LAN_IP}
+ip netns exec "${server_ns}" ping -qfc 500 -w 3 ${OVPN_LAN_IP}
 
-if [ "$FLOAT" == "1" ]; then
+if [ "$OVPN_FLOAT" == "1" ]; then
 	# make clients float..
-	for p in $(seq 1 ${NUM_PEERS}); do
-		ip -n peer${p} addr del 10.10.${p}.2/24 dev veth${p}
-		ip -n peer${p} addr add 10.10.${p}.3/24 dev veth${p}
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		ip -n "ovpn_peer${p}" addr del 10.10.${p}.2/24 dev veth${p}
+		ip -n "ovpn_peer${p}" addr add 10.10.${p}.3/24 dev veth${p}
 	done
-	for p in $(seq 1 ${NUM_PEERS}); do
-		ip netns exec peer${p} ping -qfc 500 -w 3 5.5.5.1
+	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+		ip netns exec "ovpn_peer${p}" ping -qfc 500 -w 3 5.5.5.1
 	done
 fi
 
-ip netns exec peer0 iperf3 -1 -s &
+ip netns exec "${server_ns}" iperf3 -1 -s &
 sleep 1
-ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
+ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
 
 echo "Adding secondary key and then swap:"
-for p in $(seq 1 ${NUM_PEERS}); do
-	ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 2 1 ${ALG} 0 \
-		data64.key
-	ip netns exec peer${p} ${OVPN_CLI} new_key tun${p} \
-		$((${p} + ID_OFFSET)) 2 1 ${ALG} 1 data64.key
-	ip netns exec peer${p} ${OVPN_CLI} swap_keys tun${p} \
-		$((${p} + ID_OFFSET))
+for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+	ip netns exec "${server_ns}" ${OVPN_CLI} new_key tun0 ${p} 2 1 \
+		${OVPN_ALG} 0 data64.key
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} new_key tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 data64.key
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} swap_keys tun${p} \
+		$((${p} + OVPN_ID_OFFSET))
 done
 
 sleep 1
 
 echo "Querying all peers:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0
-ip netns exec peer1 ${OVPN_CLI} get_peer tun1
+ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0
+ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1
 
 echo "Querying peer 1:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0 1
+ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0 1
 
 echo "Querying non-existent peer 20:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0 20 || true
+ip netns exec "${server_ns}" ${OVPN_CLI} get_peer tun0 20 || true
 
 echo "Deleting peer 1:"
-ip netns exec peer0 ${OVPN_CLI} del_peer tun0 1
-ip netns exec peer1 ${OVPN_CLI} del_peer tun1 $((1 + ID_OFFSET))
+ip netns exec "${server_ns}" ${OVPN_CLI} del_peer tun0 1
+ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 $((1 + OVPN_ID_OFFSET))
 
 echo "Querying keys:"
-for p in $(seq 2 ${NUM_PEERS}); do
-	ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \
-		$((${p} + ID_OFFSET)) 1
-	ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \
-		$((${p} + ID_OFFSET)) 2
+for p in $(seq 2 ${OVPN_NUM_PEERS}); do
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} get_key tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 1
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} get_key tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 2
 done
 
 echo "Deleting peer while sending traffic:"
-(ip netns exec peer2 ping -qf -w 4 5.5.5.1)&
+(ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1)&
 sleep 2
-ip netns exec peer0 ${OVPN_CLI} del_peer tun0 2
+ip netns exec "${server_ns}" ${OVPN_CLI} del_peer tun0 2
 # following command fails in TCP mode
 # (both ends get conn reset when one peer disconnects)
-ip netns exec peer2 ${OVPN_CLI} del_peer tun2 $((2 + ID_OFFSET)) || true
+ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET)) || \
+	true
 
 echo "Deleting keys:"
-for p in $(seq 3 ${NUM_PEERS}); do
-	ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \
-		$((${p} + ID_OFFSET)) 1
-	ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \
-		$((${p} + ID_OFFSET)) 2
+for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} del_key tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 1
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} del_key tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 2
 done
 
 echo "Setting timeout to 3s MP:"
-for p in $(seq 3 ${NUM_PEERS}); do
-	ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true
-	ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
-		$((${p} + ID_OFFSET)) 0 0
+for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+	ip netns exec "${server_ns}" ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 0 0
 done
 # wait for peers to timeout
 sleep 5
 
 echo "Setting timeout to 3s P2P:"
-for p in $(seq 3 ${NUM_PEERS}); do
-	ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
-		$((${p} + ID_OFFSET)) 3 3
+for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+	ip netns exec "ovpn_peer${p}" ${OVPN_CLI} set_peer tun${p} \
+		$((${p} + OVPN_ID_OFFSET)) 3 3
 done
 sleep 5
 
-for p in $(seq 0 ${NUM_PEERS}); do
-	compare_ntfs ${p}
+for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+	ovpn_compare_ntfs ${p}
 done
 
-cleanup
+ovpn_cleanup
 
 modprobe -r ovpn || true
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 3/6] selftests: ovpn: flatten slurped notification JSON before filtering
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

Notification comparison uses jq -s, which slurps all inputs into an
array. Some inputs can be arrays themselves, and applying the .msg.peer
filter directly on those entries triggers jq type errors.

Expand any array-valued JSON items returned by jq -s before selecting
.msg.peer, so the filter handles both normal notification objects and []
entries without type errors.

Fixes: 77de28cd7cf1 ("selftests: ovpn: add notification parsing and matching")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/common.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh
index c92415aaddfc..d3b322e84fab 100644
--- a/tools/testing/selftests/net/ovpn/common.sh
+++ b/tools/testing/selftests/net/ovpn/common.sh
@@ -15,7 +15,8 @@ SYMMETRIC_ID=${SYMMETRIC_ID:-0}
 
 export ID_OFFSET=$(( 9 * (SYMMETRIC_ID == 0) ))
 
-JQ_FILTER='map(select(.msg.peer | has("remote-ipv6") | not)) |
+JQ_FILTER='map(if type == "array" then .[] else . end) |
+	map(select(.msg.peer | has("remote-ipv6") | not)) |
 	map(del(.msg.ifindex)) | sort_by(.msg.peer.id)[]'
 LAN_IP="11.11.11.11"
 
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 2/6] selftests: ovpn: fail notification check on mismatch
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

compare_ntfs doesn't fail when expected and received notification
streams diverge.

Fix this bug by tracking the diff exit status explicitly and return it
to the caller so notification mismatches propagate as test failures.

Fixes: 77de28cd7cf1 ("selftests: ovpn: add notification parsing and matching")
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/common.sh | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh
index 4c08f756e63a..c92415aaddfc 100644
--- a/tools/testing/selftests/net/ovpn/common.sh
+++ b/tools/testing/selftests/net/ovpn/common.sh
@@ -140,23 +140,35 @@ add_peer() {
 }
 
 compare_ntfs() {
+	local diff_rc=0
+	local diff_file
+
 	if [ ${#tmp_jsons[@]} -gt 0 ]; then
 		suffix=""
 		[ "${SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm"
 		[ "$FLOAT" == 1 ] && suffix="${suffix}-float"
 		expected="json/peer${1}${suffix}.json"
 		received="${tmp_jsons[$1]}"
+		diff_file=$(mktemp)
 
 		kill -TERM ${listener_pids[$1]} || true
 		wait ${listener_pids[$1]} || true
 		printf "Checking notifications for peer ${1}... "
 		if diff <(jq -s "${JQ_FILTER}" ${expected}) \
-			<(jq -s "${JQ_FILTER}" ${received}); then
+			<(jq -s "${JQ_FILTER}" ${received}) \
+			>"${diff_file}" 2>&1; then
 			echo "OK"
+		else
+			diff_rc=$?
+			echo "failed"
+			cat "${diff_file}"
 		fi
 
+		rm -f "${diff_file}" || true
 		rm -f ${received} || true
 	fi
+
+	return "${diff_rc}"
 }
 
 cleanup() {
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 1/6] selftests: ovpn: add nftables config dependencies for test-mark
From: Antonio Quartulli @ 2026-04-17  9:03 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Sabrina Dubroca, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller, Eric Dumazet, Antonio Quartulli
In-Reply-To: <20260417090305.2775723-1-antonio@openvpn.net>

From: Ralf Lici <ralf@mandelbit.com>

test-mark.sh installs nftables rules in an inet/filter output chain and
verifies packet drops via nft counters. In vmksft this can fail when the
nftables core is not enabled by the ovpn selftest config.

Add the missing kernel options required by this test:
- CONFIG_NETFILTER
- CONFIG_NF_TABLES
- CONFIG_NF_TABLES_INET

Fixes: 7b80d8a33500 ("selftests: ovpn: add test for the FW mark feature")
Reported-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/all/20260319124114.42f91f72@kernel.org/
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 tools/testing/selftests/net/ovpn/config | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tools/testing/selftests/net/ovpn/config b/tools/testing/selftests/net/ovpn/config
index 42699740936d..d6cf033d555e 100644
--- a/tools/testing/selftests/net/ovpn/config
+++ b/tools/testing/selftests/net/ovpn/config
@@ -5,6 +5,9 @@ CONFIG_CRYPTO_GCM=y
 CONFIG_DST_CACHE=y
 CONFIG_INET=y
 CONFIG_NET=y
+CONFIG_NETFILTER=y
 CONFIG_NET_UDP_TUNNEL=y
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
 CONFIG_OVPN=m
 CONFIG_STREAM_PARSER=y
-- 
2.52.0


^ permalink raw reply related

* [PATCH net 0/6] pull request: fixes for ovpn 2026-04-17
From: Antonio Quartulli @ 2026-04-17  9:02 UTC (permalink / raw)
  To: netdev
  Cc: ralf, shuah, horms, Antonio Quartulli, Sabrina Dubroca,
	Jakub Kicinski, Paolo Abeni, Andrew Lunn, David S. Miller,
	Eric Dumazet

Hi Jakub,

This is a respin of the PR I originally sent against net-next + an extra
fix (patch 6).

Please note that this patch:
https://lore.kernel.org/all/20260225010833.11301-1-liuhangbin@gmail.com/
broke the selftests entirely due to the switch from sh to bash.

There are new commits in the kselftest tree which take care of this:
https://lore.kernel.org/all/20260416-selftest-fix-readlink-e-v1-0-94e4cabbdec4@kernel.org/
but they are not in net yet, therefore you won't be able to test/run
our kselftests for now.

This being said...

TCP tests are still failing every now and then.
It seems that sometimes a single ping over a TCP tunnel is lost,
thus making the selftest fail.

We believe this is a bug in ovpn which we are currently hunting down.
So it's nothing wrong about the tests (they are actually doing their
job!).

Test hangs you reported on slow kernels are fixed.

See the tag content for a more detailed summary.
Please pull or let me know of any issue!

Thanks a lot,
	Antonio


The following changes since commit 82c21069028c5db3463f851ae8ac9cc2e38a3827:

  selftests: net: add missing CMAC to tcp_ao config (2026-04-16 19:35:43 -0700)

are available in the Git repository at:

  https://github.com/OpenVPN/ovpn-net-next.git tags/ovpn-net-20260417

for you to fetch changes up to 6c9b1dc218fea8b15893953f5299b209f11fa0a8:

  selftests: ovpn: serialize YNL listener startup (2026-04-17 10:54:04 +0200)

----------------------------------------------------------------
This batch includes only fixes to the selftest harness:
* switch to TAP test orchestration
* parse slurped notifications as returned by jq -s
* add ovpn_ prefix to helpers and global variables to avoid clashes
* fail test in case of netlink notification mismatch
* add missing kernel config dependencies
* add delay when launching multiple ynl/cli.py listeners

----------------------------------------------------------------
Ralf Lici (6):
      selftests: ovpn: add nftables config dependencies for test-mark
      selftests: ovpn: fail notification check on mismatch
      selftests: ovpn: flatten slurped notification JSON before filtering
      selftests: ovpn: add prefix to helpers and shared variables
      selftests: ovpn: align command flow with TAP
      selftests: ovpn: serialize YNL listener startup

 tools/testing/selftests/net/ovpn/common.sh         | 355 ++++++++++++----
 tools/testing/selftests/net/ovpn/config            |   3 +
 .../testing/selftests/net/ovpn/test-chachapoly.sh  |   2 +-
 .../selftests/net/ovpn/test-close-socket-tcp.sh    |   2 +-
 .../selftests/net/ovpn/test-close-socket.sh        |  90 +++--
 tools/testing/selftests/net/ovpn/test-float.sh     |   2 +-
 tools/testing/selftests/net/ovpn/test-mark.sh      | 237 +++++++----
 .../selftests/net/ovpn/test-symmetric-id-float.sh  |   4 +-
 .../selftests/net/ovpn/test-symmetric-id-tcp.sh    |   4 +-
 .../selftests/net/ovpn/test-symmetric-id.sh        |   2 +-
 tools/testing/selftests/net/ovpn/test-tcp.sh       |   2 +-
 tools/testing/selftests/net/ovpn/test.sh           | 449 ++++++++++++++-------
 12 files changed, 803 insertions(+), 349 deletions(-)

^ permalink raw reply

* Re: [PATCH net-next 5/6] net: stmmac: move PHY handling out of __stmmac_open()/release()
From: Alexander Stein @ 2026-04-17  8:47 UTC (permalink / raw)
  To: Russell King (Oracle), Maxime Chevallier
  Cc: Andrew Lunn, Heiner Kallweit, Alexandre Torgue, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
	linux-stm32, Maxime Coquelin, netdev, Paolo Abeni
In-Reply-To: <680c384c-135f-44cd-a2cd-7e4fd0ec4bf7@bootlin.com>

Am Freitag, 17. April 2026, 09:11:59 CEST schrieb Maxime Chevallier:
> Hi,
> 
> On 16/04/2026 14:13, Russell King (Oracle) wrote:
> > On Thu, Apr 16, 2026 at 02:02:53PM +0200, Alexander Stein wrote:
> >> Hi Russel,
> >>
> >> Am Donnerstag, 16. April 2026, 12:49:25 CEST schrieb Russell King (Oracle):
> >>> On Thu, Apr 16, 2026 at 08:20:13AM +0200, Alexander Stein wrote:
> >>>> Am Mittwoch, 15. April 2026, 14:59:32 CEST schrieb Russell King (Oracle):
> >>>>> On Wed, Apr 15, 2026 at 08:08:40AM +0200, Alexander Stein wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> Am Dienstag, 23. September 2025, 13:26:19 CEST schrieb Russell King (Oracle):
> >>>>>>> Move the PHY attachment/detachment from the network driver out of
> >>>>>>> __stmmac_open() and __stmmac_release() into stmmac_open() and
> >>>>>>> stmmac_release() where these actions will only happen when the
> >>>>>>> interface is administratively brought up or down. It does not make
> >>>>>>> sense to detach and re-attach the PHY during a change of MTU.
> >>>>>>
> >>>>>> Sorry for coming up now. But I recently noticed this commit breaks changing
> >>>>>> the MTU on i.MX8MP. Once I simply change the MTU I run into some DMA error:
> >>>>>> $ ip link set dev end1 mtu 1400
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Register MEM_TYPE_PAGE_POOL RxQ-0
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Register MEM_TYPE_PAGE_POOL RxQ-1
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Register MEM_TYPE_PAGE_POOL RxQ-2
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Register MEM_TYPE_PAGE_POOL RxQ-3
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Register MEM_TYPE_PAGE_POOL RxQ-4
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Link is Down
> >>>>>> imx-dwmac 30bf0000.ethernet end1: Failed to reset the dma
> >>>>>> imx-dwmac 30bf0000.ethernet end1: stmmac_hw_setup: DMA engine initialization failed
> >>>>>
> >>>>> This basically means that a clock is missing. Please provide more
> >>>>> information:
> >>>>>
> >>>>> - what kernel version are you using?
> >>>>
> >>>> Currently I am using v6.18.22.
> >>>> $ ethtool -i end1
> >>>> driver: st_gmac
> >>>> version: 6.18.22
> >>>> firmware-version: 
> >>>> expansion-rom-version: 
> >>>> bus-info: 30bf0000.ethernet
> >>>> supports-statistics: yes
> >>>> supports-test: no
> >>>> supports-eeprom-access: no
> >>>> supports-register-dump: yes
> >>>> supports-priv-flags: no
> >>>>
> >>>>> - has EEE been negotiated?
> >>>>
> >>>> No. It is marked as not supported
> >>>>
> >>>> $ ethtool --show-eee end1
> >>>> EEE settings for end1:
> >>>>         EEE status: not supported
> >>>>
> >>>>> - does the problem persist when EEE is disabled?
> >>>>
> >>>> As EEE is not supported the problem occurs even with EEE disabled.
> >>>>
> >>>>> - which PHY is attached to stmmac?
> >>>>
> >>>> It is a TI DP83867.
> >>>>
> >>>> imx-dwmac 30bf0000.ethernet eth1: PHY [stmmac-1:03] driver [TI DP83867] (irq=136)
> >>>>
> >>>>> - which PHY interface mode is being used to connect the PHY to stmmac?
> >>>>
> >>>> For this interface
> >>>>> phy-mode = "rgmii-id";
> >>>> is set.
> >>>>
> >>>> In case it is helpful. My platform is arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
> >>>> Thanks for assisting. If there a further questions, don't hesitate to ask.
> >>>
> >>> Thanks.
> >>>
> >>> So, as best I can determine at the moment, we end up with the following
> >>> sequence:
> >>>
> >>> stmmac_change_mtu()
> >>>  __stmmac_release()
> >>>   phylink_stop()
> >>>    phy_stop()
> >>>     phy->state = PHY_HALTED
> >>>     _phy_state_machine() returns PHY_STATE_WORK_SUSPEND
> >>>     _phy_state_machine_post_work()
> >>>      phy_suspend()
> >>>       genphy_suspend()
> >>>        phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN)
> >>>
> >>> With the DP83867, this causes most of the PHY to be powered down, thus
> >>> stopping the clocks, and this causes the stmmac reset to time out.
> >>>
> >>> Prior to this commit, we would have called phylink_disconnect_phy()
> >>> immediately after phylink_stop(), but I can see nothing that would
> >>> be affected by this change there (since that also calls
> >>> phy_suspend(), but as the PHY is already suspended, this becomes a
> >>> no-op.)
> >>>
> >>> However, __stmmac_open() would have called stmmac_init_phy(), which
> >>> would reattach the PHY. This would have called phy_init_hw(), 
> >>> resetting the PHY, and phy_resume() which would ensure that the
> >>> PDOWN bit is clear - thus clocks would be running.
> >>>
> >>> As a hack, please can you try calling phylink_prepare_resume()
> >>> between the __stmmac_release() and __stmmac_open() in
> >>> stmmac_change_mtu(). This should resume the PHY, thus restoring the
> >>> clocks necessary for stmmac to reset.
> >>
> >> I tried the following patch. This works as you suspected.
> > 
> > Brilliant, thanks for proving the theory why it broke.
> > 
> > I'll have a think about the best way to solve this, because
> > phylink_prepare_resume() is supposed to be paired with phylink_resume()
> > and that isn't the case here.
> > 
> > Please bear with me as my availability for looking at the kernel is
> > very unpredictable at present (family health issues.)
> 
> FWIW I am able to reproduce this with imx8mp + ksz9131
> 
> I can give this a try as Russell isn't available.

Thanks for conforming this for another PHY. What I'm wondering right now:
Why is the PHY stopped in the first place? We are just changing the MTU, no?
This has no effect on the PHY itself. "all" we need to do is reconfiguring
the DMA. I have a proof of concept running, but it needs more cleanup due
to code duplication.

Best regards
Alexander
-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/



^ permalink raw reply

* [PATCH net 2/2] net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()
From: Lorenzo Bianconi @ 2026-04-17  8:40 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Lorenzo Bianconi
  Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260417-airoha_qdma_init_rx_queue-fix-v1-0-db9fa5e468e5@kernel.org>

If airoha_qdma_init routine fails before airoha_qdma_tx_irq_init() runs
successfully for all TX NAPIs, airoha_qdma_cleanup() will
unconditionally runs netif_napi_del() on TX NAPIs, triggering a NULL
pointer dereference. Fix the issue relying on q_tx_irq size value to
check if the TX NAPIs is properly initialized in airoha_qdma_cleanup().

Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/ethernet/airoha/airoha_eth.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index a6f8b231583d..1ca4087e675d 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1398,8 +1398,12 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
 		}
 	}
 
-	for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
+	for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+		if (!qdma->q_tx_irq[i].size)
+			continue;
+
 		netif_napi_del(&qdma->q_tx_irq[i].napi);
+	}
 
 	for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
 		if (!qdma->q_tx[i].ndesc)

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 1/2] net: airoha: Move ndesc initialization at end of airoha_qdma_init_rx_queue()
From: Lorenzo Bianconi @ 2026-04-17  8:40 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Lorenzo Bianconi
  Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260417-airoha_qdma_init_rx_queue-fix-v1-0-db9fa5e468e5@kernel.org>

If queue entry or DMA descriptor list allocation fails in
airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a
NULL pointer dereference running netif_napi_del() for RX queue NAPIs
since netif_napi_add() has never been executed to this particular RX NAPI.
The issue is due to the early ndesc initialization in
airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc
value to check if the queue is properly initialized. Fix the issue moving
ndesc initialization at end of airoha_qdma_init_tx routine.

Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/ethernet/airoha/airoha_eth.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index e1ab15f1ee7d..a6f8b231583d 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -745,10 +745,9 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
 	dma_addr_t dma_addr;
 
 	q->buf_size = PAGE_SIZE / 2;
-	q->ndesc = ndesc;
 	q->qdma = qdma;
 
-	q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
+	q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
 				GFP_KERNEL);
 	if (!q->entry)
 		return -ENOMEM;
@@ -761,11 +760,12 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
 		return err;
 	}
 
-	q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
+	q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
 				      &dma_addr, GFP_KERNEL);
 	if (!q->desc)
 		return -ENOMEM;
 
+	q->ndesc = ndesc;
 	netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
 
 	airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);

-- 
2.53.0


^ permalink raw reply related

* [PATCH net 0/2] net: airoha: Fix NULL pointer derefrences in airoha_qdma_cleanup()
From: Lorenzo Bianconi @ 2026-04-17  8:40 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Lorenzo Bianconi
  Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev

Fix two possible NULL pointer derefrences in airoha_qdma_cleanup routine
if airoha_qdma_init() fails.

---
Lorenzo Bianconi (2):
      net: airoha: Move ndesc initialization at end of airoha_qdma_init_rx_queue()
      net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()

 drivers/net/ethernet/airoha/airoha_eth.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
---
base-commit: 82c21069028c5db3463f851ae8ac9cc2e38a3827
change-id: 20260417-airoha_qdma_init_rx_queue-fix-b9bfada51671

Best regards,
-- 
Lorenzo Bianconi <lorenzo@kernel.org>


^ permalink raw reply

* [PATCH 5.15.y] nf_tables: nft_dynset: fix possible stateful expression memleak in error path
From: Li hongliang @ 2026-04-17  8:22 UTC (permalink / raw)
  To: gregkh, stable, pablo
  Cc: patches, linux-kernel, kadlec, fw, davem, edumazet, kuba, pabeni,
	netfilter-devel, coreteam, netdev, giki.shergill

From: Pablo Neira Ayuso <pablo@netfilter.org>

[ Upstream commit 0548a13b5a145b16e4da0628b5936baf35f51b43 ]

If cloning the second stateful expression in the element via GFP_ATOMIC
fails, then the first stateful expression remains in place without being
released.

   unreferenced object (percpu) 0x607b97e9cab8 (size 16):
     comm "softirq", pid 0, jiffies 4294931867
     hex dump (first 16 bytes on cpu 3):
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     backtrace (crc 0):
       pcpu_alloc_noprof+0x453/0xd80
       nft_counter_clone+0x9c/0x190 [nf_tables]
       nft_expr_clone+0x8f/0x1b0 [nf_tables]
       nft_dynset_new+0x2cb/0x5f0 [nf_tables]
       nft_rhash_update+0x236/0x11c0 [nf_tables]
       nft_dynset_eval+0x11f/0x670 [nf_tables]
       nft_do_chain+0x253/0x1700 [nf_tables]
       nft_do_chain_ipv4+0x18d/0x270 [nf_tables]
       nf_hook_slow+0xaa/0x1e0
       ip_local_deliver+0x209/0x330

Fixes: 563125a73ac3 ("netfilter: nftables: generalize set extension to support for several expressions")
Reported-by: Gurpreet Shergill <giki.shergill@proton.me>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
[ Minor conflict resolved. ]
Signed-off-by: Li hongliang <1468888505@139.com>
---
 include/net/netfilter/nf_tables.h |  2 ++
 net/netfilter/nf_tables_api.c     |  4 ++--
 net/netfilter/nft_dynset.c        | 10 +++++++++-
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 605d4c0a63e9..1f805590b838 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -821,6 +821,8 @@ void *nft_set_elem_init(const struct nft_set *set,
 			u64 timeout, u64 expiration, gfp_t gfp);
 int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
 			    struct nft_expr *expr_array[]);
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
 			  bool destroy_expr);
 void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index cbec5fc23719..b78949933acf 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5919,8 +5919,8 @@ static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
 	}
 }
 
-static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
-				      struct nft_set_elem_expr *elem_expr)
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr)
 {
 	struct nft_expr *expr;
 	u32 size;
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index ecdd4a60db9c..673c5e6a3e8d 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -30,18 +30,26 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
 				 const struct nft_set_ext *ext)
 {
 	struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
+	struct nft_ctx ctx = {
+		.net	= read_pnet(&priv->set->net),
+		.family	= priv->set->table->family,
+	};
 	struct nft_expr *expr;
 	int i;
 
 	for (i = 0; i < priv->num_exprs; i++) {
 		expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
 		if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
-			return -1;
+			goto err_out;
 
 		elem_expr->size += priv->expr_array[i]->ops->size;
 	}
 
 	return 0;
+err_out:
+	nft_set_elem_expr_destroy(&ctx, elem_expr);
+
+	return -1;
 }
 
 static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
-- 
2.34.1



^ permalink raw reply related

* [PATCH 6.1.y] nf_tables: nft_dynset: fix possible stateful expression memleak in error path
From: Li hongliang @ 2026-04-17  8:21 UTC (permalink / raw)
  To: gregkh, stable, pablo
  Cc: patches, linux-kernel, kadlec, fw, davem, edumazet, kuba, pabeni,
	netfilter-devel, coreteam, netdev, giki.shergill

From: Pablo Neira Ayuso <pablo@netfilter.org>

[ Upstream commit 0548a13b5a145b16e4da0628b5936baf35f51b43 ]

If cloning the second stateful expression in the element via GFP_ATOMIC
fails, then the first stateful expression remains in place without being
released.

   unreferenced object (percpu) 0x607b97e9cab8 (size 16):
     comm "softirq", pid 0, jiffies 4294931867
     hex dump (first 16 bytes on cpu 3):
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     backtrace (crc 0):
       pcpu_alloc_noprof+0x453/0xd80
       nft_counter_clone+0x9c/0x190 [nf_tables]
       nft_expr_clone+0x8f/0x1b0 [nf_tables]
       nft_dynset_new+0x2cb/0x5f0 [nf_tables]
       nft_rhash_update+0x236/0x11c0 [nf_tables]
       nft_dynset_eval+0x11f/0x670 [nf_tables]
       nft_do_chain+0x253/0x1700 [nf_tables]
       nft_do_chain_ipv4+0x18d/0x270 [nf_tables]
       nf_hook_slow+0xaa/0x1e0
       ip_local_deliver+0x209/0x330

Fixes: 563125a73ac3 ("netfilter: nftables: generalize set extension to support for several expressions")
Reported-by: Gurpreet Shergill <giki.shergill@proton.me>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
[ Minor conflict resolved. ]
Signed-off-by: Li hongliang <1468888505@139.com>
---
 include/net/netfilter/nf_tables.h |  2 ++
 net/netfilter/nf_tables_api.c     |  4 ++--
 net/netfilter/nft_dynset.c        | 10 +++++++++-
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 38c74f9fcce2..dafa0a32e6e1 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -838,6 +838,8 @@ void *nft_set_elem_init(const struct nft_set *set,
 			u64 timeout, u64 expiration, gfp_t gfp);
 int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
 			    struct nft_expr *expr_array[]);
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
 			  bool destroy_expr);
 void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index fb3d529ebf5a..0c4224282638 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6025,8 +6025,8 @@ static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
 	}
 }
 
-static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
-				      struct nft_set_elem_expr *elem_expr)
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr)
 {
 	struct nft_expr *expr;
 	u32 size;
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 953aba871f45..5f58ac874005 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -30,18 +30,26 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
 				 const struct nft_set_ext *ext)
 {
 	struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
+	struct nft_ctx ctx = {
+		.net	= read_pnet(&priv->set->net),
+		.family	= priv->set->table->family,
+	};
 	struct nft_expr *expr;
 	int i;
 
 	for (i = 0; i < priv->num_exprs; i++) {
 		expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
 		if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
-			return -1;
+			goto err_out;
 
 		elem_expr->size += priv->expr_array[i]->ops->size;
 	}
 
 	return 0;
+err_out:
+	nft_set_elem_expr_destroy(&ctx, elem_expr);
+
+	return -1;
 }
 
 static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
-- 
2.34.1



^ permalink raw reply related

* [PATCH 6.6.y] nf_tables: nft_dynset: fix possible stateful expression memleak in error path
From: Li hongliang @ 2026-04-17  8:18 UTC (permalink / raw)
  To: gregkh, stable, pablo
  Cc: patches, linux-kernel, kadlec, fw, davem, edumazet, kuba, pabeni,
	netfilter-devel, coreteam, netdev, giki.shergill

From: Pablo Neira Ayuso <pablo@netfilter.org>

[ Upstream commit 0548a13b5a145b16e4da0628b5936baf35f51b43 ]

If cloning the second stateful expression in the element via GFP_ATOMIC
fails, then the first stateful expression remains in place without being
released.

   unreferenced object (percpu) 0x607b97e9cab8 (size 16):
     comm "softirq", pid 0, jiffies 4294931867
     hex dump (first 16 bytes on cpu 3):
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     backtrace (crc 0):
       pcpu_alloc_noprof+0x453/0xd80
       nft_counter_clone+0x9c/0x190 [nf_tables]
       nft_expr_clone+0x8f/0x1b0 [nf_tables]
       nft_dynset_new+0x2cb/0x5f0 [nf_tables]
       nft_rhash_update+0x236/0x11c0 [nf_tables]
       nft_dynset_eval+0x11f/0x670 [nf_tables]
       nft_do_chain+0x253/0x1700 [nf_tables]
       nft_do_chain_ipv4+0x18d/0x270 [nf_tables]
       nf_hook_slow+0xaa/0x1e0
       ip_local_deliver+0x209/0x330

Fixes: 563125a73ac3 ("netfilter: nftables: generalize set extension to support for several expressions")
Reported-by: Gurpreet Shergill <giki.shergill@proton.me>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
[ Minor conflict resolved. ]
Signed-off-by: Li hongliang <1468888505@139.com>
---
 include/net/netfilter/nf_tables.h |  2 ++
 net/netfilter/nf_tables_api.c     |  4 ++--
 net/netfilter/nft_dynset.c        | 10 +++++++++-
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 000ae2900f8c..ab0567951e31 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -861,6 +861,8 @@ void *nft_set_elem_init(const struct nft_set *set,
 			u64 timeout, u64 expiration, gfp_t gfp);
 int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
 			    struct nft_expr *expr_array[]);
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
 			  bool destroy_expr);
 void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 0aaddc1131c6..a0914a92e07d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6464,8 +6464,8 @@ static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
 	}
 }
 
-static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
-				      struct nft_set_elem_expr *elem_expr)
+void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
+			       struct nft_set_elem_expr *elem_expr)
 {
 	struct nft_expr *expr;
 	u32 size;
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 9a0aaeed2360..87c6a02675ba 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -30,18 +30,26 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
 				 const struct nft_set_ext *ext)
 {
 	struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
+	struct nft_ctx ctx = {
+		.net	= read_pnet(&priv->set->net),
+		.family	= priv->set->table->family,
+	};
 	struct nft_expr *expr;
 	int i;
 
 	for (i = 0; i < priv->num_exprs; i++) {
 		expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
 		if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
-			return -1;
+			goto err_out;
 
 		elem_expr->size += priv->expr_array[i]->ops->size;
 	}
 
 	return 0;
+err_out:
+	nft_set_elem_expr_destroy(&ctx, elem_expr);
+
+	return -1;
 }
 
 static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
-- 
2.34.1



^ permalink raw reply related

* Re: [PATCH RFC 1/4] dt-bindings: net: qcom,ipa: document Eliza compatible
From: Konrad Dybcio @ 2026-04-17  8:16 UTC (permalink / raw)
  To: Alexander Koskovich, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alex Elder
  Cc: linux-arm-msm, netdev, devicetree, linux-kernel
In-Reply-To: <20260416-eliza-ipa-v1-1-f4109a8e43c4@pm.me>

On 4/17/26 12:40 AM, Alexander Koskovich wrote:
> Document the IPA on the Eliza Platform which uses version 5.5.1,
> which is a minor revision of v5.5 found on SM8550, thus we can
> use the SM8550 bindings as fallback since it shares the same
> register mappings.
> 
> Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
> ---
>  Documentation/devicetree/bindings/net/qcom,ipa.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
> index fdeaa81b9645..38a5a337c34f 100644
> --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml
> +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
> @@ -60,6 +60,7 @@ properties:
>            - const: qcom,sc7180-ipa
>        - items:
>            - enum:
> +              - qcom,eliza-ipa
>                - qcom,sm8650-ipa
>            - const: qcom,sm8550-ipa

FWIW:

8650 -> v5.5.1

eliza
8750
and a couple others
-> 5.5.2

Konrad

^ permalink raw reply

* Re: [PATCH] net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
From: Willem de Bruijn @ 2026-04-17  8:15 UTC (permalink / raw)
  To: Zero Mark, Willem de Bruijn
  Cc: security, David S . Miller, Jakub Kicinski, Eric Dumazet, netdev,
	Zero Mark
In-Reply-To: <20260417060714.35488-1-patzilla007@gmail.com>

Zero Mark wrote:
> In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points
> directly into the mmap'd TX ring buffer shared with userspace. The
> kernel validates the header via __packet_snd_vnet_parse() but then
> re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent
> userspace thread can modify the vnet_hdr fields (gso_type, gso_size,
> flags, csum_start, csum_offset) between validation and use, bypassing
> all safety checks.
> 
> This can lead to:
>  - Out-of-bounds checksum writes via crafted csum_start/csum_offset
>  - Malicious GSO segmentation parameters
>  - Kernel memory corruption and potential local privilege escalation
> 
> The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr
> to a stack-local variable. All other vnet_hdr consumers in the kernel
> (tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX
> path is the only caller of virtio_net_hdr_to_skb() that reads directly
> from user-controlled shared memory.
> 
> Fix this by copying vnet_hdr from the mmap'd ring buffer to a
> stack-local variable before validation and use, consistent with the
> approach used in packet_snd() and all other callers.
> 
> Exploitation requires CAP_NET_RAW, which can be obtained without
> special privileges via user namespaces.
> 
> Confirmed with a PoC on Linux 6.8.0 (Ubuntu): kprobe tracing on
> skb_partial_csum_set captured 77 race wins in 500,000 iterations.

No need to add such details on exploitability of bugs.

> Affects all kernels since PACKET_VNET_HDR support was added to the
> TPACKET TX path (~v3.14).
> 
> Fixes: 9ed988e5 ("packet: add vnet_hdr support for tpacket_snd")

This patch does not exist. Also 12-char SHA1.

I think this should be

Fixes: 1d036d25e560 ("packet: tpacket_snd gso and checksum offload")

> Signed-off-by: Zero Mark <patzilla007@gmail.com>

Thanks for the fix!

Only it does not apply cleanly. Please mark fixes [PATCH net] and
ensure that they apply to current netdev-net/main

https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html

> ---
>  net/packet/af_packet.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index abcdef012345..fedcba654321 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -2725,7 +2725,8 @@ static int tpacket_parse_header(struct packet_sock *po, void *frame,
>  static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
>  {
>  	struct sk_buff *skb = NULL;
>  	struct net_device *dev;
> -	struct virtio_net_hdr *vnet_hdr = NULL;
> +	struct virtio_net_hdr vnet_hdr;
> +	bool has_vnet_hdr = false;
>  	struct sockcm_cookie sockc;
>  	__be16 proto;
>  	int err, reserve = 0;
> @@ -2828,16 +2829,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
>  		if (po->has_vnet_hdr) {
> -			vnet_hdr = data;
> -			data += sizeof(*vnet_hdr);
> -			tp_len -= sizeof(*vnet_hdr);
> +			memcpy(&vnet_hdr, data, sizeof(vnet_hdr));

Move the tp_len < 0 check before memcpy

> +			data += sizeof(vnet_hdr);
> +			tp_len -= sizeof(vnet_hdr);
>  			if (tp_len < 0 ||
> -			    __packet_snd_vnet_parse(vnet_hdr, tp_len)) {
> +			    __packet_snd_vnet_parse(&vnet_hdr, tp_len)) {
>  				tp_len = -EINVAL;
>  				goto tpacket_error;
>  			}
>  			copylen = __virtio16_to_cpu(vio_le(),
> -						    vnet_hdr->hdr_len);
> +						    vnet_hdr.hdr_len);
> +			has_vnet_hdr = true;
>  		}
>  		copylen = max_t(int, copylen, dev->hard_header_len);
>  		skb = sock_alloc_send_skb(&po->sk,
> @@ -2875,11 +2877,11 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
>  		}
> 
> -		if (po->has_vnet_hdr) {
> -			if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) {
> +		if (has_vnet_hdr) {
> +			if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le())) {
>  				tp_len = -EINVAL;
>  				goto tpacket_error;
>  			}
> -			virtio_net_hdr_set_proto(skb, vnet_hdr);
> +			virtio_net_hdr_set_proto(skb, &vnet_hdr);
>  		}
> 
>  		skb->destructor = tpacket_destruct_skb;
> --
> 2.43.0
> 



^ permalink raw reply

* Re: Path forward for NFC in the kernel
From: David Heidelberg @ 2026-04-17  8:12 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jakub Kicinski, Michael Thalmeier,
	Raymond Hackley, Michael Walle, Bongsu Jeon, Mark Greer
  Cc: netdev
In-Reply-To: <9c4a4acf-b4f1-4e84-93bf-cdf080cb9970@kernel.org>

On 17/04/2026 09:18, Krzysztof Kozlowski wrote:
> On 16/04/2026 19:10, Jakub Kicinski wrote:
>> Hi folks!
>>
>> We are struggling to keep up with the number of security reports and AI
>> generated patches in the kernel. NFC is infamous for being a huge CVE
>> magnet. We need someone to step up as a maintainer, create an NFC tree
>> and handle all the incoming submissions. Send us (or Linus if you
>> prefer) periodic PRs, like WiFi, Bluetooth etc. do. If that does not
>> happen I'm afraid we'll have to move the NFC code out of the tree,
>> put it up on GH or some such, and let it accumulate CVEs there..
>>
>> I'm planning to send a PR to Linus to shed the unmaintained code early
>> next week. We need to have a maintainer established by then.
> 
> +Cc David Heidelberg recently trying to use Linux NFC stack,
> 
> Just "collecting" patches is not a big deal, I could do this, but
> actually reviewing the patches with necessary due diligence is the
> effort I could not provide in a reasonable time frame. And picking up
> patches without proper review feels risky...

Hello Krzystof, Jakub,

thanks for putting me into loop.

I can do limited reviews and basic maintenance. My knowledge about NFC is for 
now somehow limited (but I'm willing to invest my limited time into learning more).

As "I & LLM" wrote [1] userspace very basic reader for GNOME and planning to do 
more tight integration into GNOME, so would make sense to keep the kernel stack 
alive.

[1] https://gitlab.gnome.org/dh/gnfc/

> 
> NFC has a long history of issues, first mostly pointed out by syzbot but
> now apparently by AI tools. The code base is quite old, with no major
> improvements or testings happening but not in a way "oh, it's stable and
> working like 'cp' command" but rather "no one knows how many bugs are on
> top of each other and if it actually still works".
> 
> Syzbot and AI reported bugs encourage random drive-by fixes by people
> not testing the code, thus particular bug report might be fixed, but for
> example NFC stops working and no one knows that.

I think I could filter out nonsense, possibly with help of Sashiko [2].

[2] https://sashiko.dev/

> 
> Does anyone knows if the NFC stack/drivers actually works fine? Did
> anyone test actual devices?

Yes, nxp,pn553, nxp,pn557.

Other people did also test on some phones with different tags (I currently have 
only one tag with vCARD loaded on it).

David

> 
> If not, then moving to Github would be even more reasonable.
> 
> Another point is that AFAIU, most of real world devices, like
> Android-based phones, don't use the Linux NFC stack but their custom
> HAL/user-space based libraries and drivers. Some other non-Android
> projects use libnfc userspace, which seems to be maintained only as
> bugfix (https://github.com/nfc-tools/libnfc/commits/master/).
> 
> Best regards,
> Krzysztof

^ permalink raw reply

* Re: [RFC PATCH] mm: net: disable kswapd for high-order network buffer allocation
From: wang lian @ 2026-04-17  8:11 UTC (permalink / raw)
  To: willy
  Cc: 21cnbao, corbet, davem, edumazet, hannes, horms, jackmanb, kuba,
	kuniyu, linux-doc, linux-kernel, linux-mm, linyunsheng, mhocko,
	netdev, pabeni, surenb, v-songbaohua, vbabka, willemb, zhouhuacai,
	ziy, wang lian
In-Reply-To: <aO11jqD6jgNs5h8K@casper.infradead.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 4537 bytes --]

Hi Matthew, Barry,

> So, we try to do an order-3 allocation. kswapd runs and ...
> succeeds in creating order-3 pages? Or fails to?
From our reproducer runs, both happen. We observe intermittent order-3
successes, but also frequent high-order failures followed by order-0
fallback.

> If it fails, that's something we need to sort out.
Agreed. In this workload, the bottleneck appears to be contiguity, not
raw reclaimable memory shortage. Order-0 memory remains available while
suitable order-3 blocks are often unavailable.

> If it succeeds, now we have several order-3 pages, great. But where do
> they all go that we need to run kswapd again?
In our runs, order-3 pockets do show up, but they do not last long.
They get consumed quickly by ongoing skb demand, and the pressure returns.

To investigate this, we built a reproducer that keeps creating memory fragments 
while the network stack continuously requests order-3 allocations.[1][2]

Raw sample output (trimmed):
---------------------------------------------------------------------------------------------------
TIME       | BUDDYINFO (Normal Zone)        | MEMINFO                   | KSWAPD CPU & VMSTAT      
---------------------------------------------------------------------------------------------------
11:08:11   | ord0:11622 ord3:0              | Free:96MB Avail:1309MB    | CPU: 10.0%  scan:83107932
[*] PHASE 3: Triggering Order-3 Pressure (UDP Storm).
11:08:15   | ord0:52079 ord3:0              | Free:273MB Avail:1300MB   | CPU: 90.9%  scan:85328881
11:08:16   | ord0:102895 ord3:0             | Free:477MB Avail:1309MB   | CPU: 60.0%  scan:85873777
11:08:17   | ord0:115459 ord3:5             | Free:517MB Avail:1284MB   | CPU: 54.5%  scan:86584389
11:08:18   | ord0:115164 ord3:0             | Free:509MB Avail:1107MB   | CPU: 36.4%  scan:87083561
---------------------------------------------------------------------------------------------------

The current phenomenon we observed is: Free memory is plentiful, Order-0 
pages are abundant, and the network allocation has already successfully 
entered the fallback-to-order-0 path. Everything seems normal on the 
surface, yet kswapd remains trapped in a futile loop.

It appears that kswapd is stuck in the following logic: 
wakeup_kswapd -> pgdat_balance -> __zone_watermark_ok. 

Specifically, in __zone_watermark_ok():

        /* For a high-order request, check at least one suitable page is free */
        for (o = order; o < NR_PAGE_ORDERS; o++) {
                struct free_area *area = &z->free_area[o];
                int mt;

                if (!area->nr_free)
                        continue;

                for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
                        if (!free_area_empty(area, mt))
                                return true;
                }
        }

Because our reproducer keeps creating fragmentation while the network 
stack requests order-3, this loop continues to return 'false' for the 
high-order requirement, even though the system is functionally fine 
with order-0. To be clear, we are not intentionally creating "artificial" 
fragments just for the sake of it. Rather, we designed this reproducer to 
effectively stress-test and expose the existing feedback gap in the 
reclaim/compaction logic—helping to pinpoint why kswapd continues 
thumping CPU cycles to satisfy a watermark that the allocator has 
already abandoned in favor of order-0 fallback.

A related discussion in [3] helps reduce vmpressure noise in this area.
Useful, but it does not close the contiguity gap by itself: high-order
wake/reclaim can still repeat when contiguous blocks cannot be formed.

It seems the current situation directs us to take a much closer look at 
how kswapd behaves in these scenarios. After carefully reviewing 
everyone's input, we believe it is time to do some targeted work on 
handling these high-order page issues. 

We already have some rough ideas and plan to conduct further experiments 
in this area. We would appreciate a broader discussion to help address 
this potential oversight that we might have collectively missed.

Links:
[1] https://github.com/hack-kernel-just-for-fun/kswap/blob/main/kswapd_spin_repro.c
[2] https://github.com/hack-kernel-just-for-fun/kswap/blob/main/kswapd.sh
[3] https://lore.kernel.org/all/20260406195014.112521-1-jp.kobryn@linux.dev/#r

This was reproduced and cross-checked independently by our team
(Wang Lian <lianux.mm@gmail.com> and Kunwu Chan <kunwu.chan@gmail.com>).

--
Best Regards,
wang lian

^ permalink raw reply

* Re: [PATCH net v2] hv_sock: Report EOF instead of -EIO for FIN
From: Stefano Garzarella @ 2026-04-17  8:11 UTC (permalink / raw)
  To: Dexuan Cui
  Cc: kys, haiyangz, wei.liu, longli, davem, edumazet, kuba, pabeni,
	horms, niuxuewei.nxw, linux-hyperv, virtualization, netdev,
	linux-kernel, stable, Ben Hillis, Mitchell Levy
In-Reply-To: <20260416191433.840637-1-decui@microsoft.com>

On Thu, Apr 16, 2026 at 12:14:33PM -0700, Dexuan Cui wrote:
>Commit f0c5827d07cb unluckily causes a regression for the FIN packet,
>and the final read syscall gets an error rather than 0.
>
>Ideally, we would want to fix hvs_channel_readable_payload() so that it
>could return 0 in the FIN scenario, but it's not good for the hv_sock
>driver to use the VMBus ringbuffer's cached priv_read_index, which is
>internal data in the VMBus driver.
>
>Fix the regression in hv_sock by returning 0 rather than -EIO.
>
>Fixes: f0c5827d07cb ("hv_sock: Return the readable bytes in hvs_stream_has_data()")
>Cc: stable@vger.kernel.org
>Reported-by: Ben Hillis <Ben.Hillis@microsoft.com>
>Reported-by: Mitchell Levy <levymitchell0@gmail.com>
>Signed-off-by: Dexuan Cui <decui@microsoft.com>
>---
>
>Changes since v1:
>    Removed the local variable 'need_refill' to make the code more
>    readable. Stefano, thanks!

Thanks for the fix!

>
>    No other change.
>
> net/vmw_vsock/hyperv_transport.c | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)

Acked-by: Stefano Garzarella <sgarzare@redhat.com>


^ permalink raw reply

* [PATCH] tipc: crypto: require a NUL-terminated AEAD algorithm name
From: Pengpeng Hou @ 2026-04-17  7:53 UTC (permalink / raw)
  To: Jon Maloy, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
	tipc-discussion, linux-kernel, Pengpeng Hou, stable

struct tipc_aead_key carries alg_name in a fixed 32-byte field, but both
the generic netlink validation path and the MSG_CRYPTO receive path pass
that field straight to crypto_has_alg(), strcmp(), and
crypto_alloc_aead() without first proving that it contains a terminating
NUL.

Reject locally supplied and received keys whose algorithm name fills the
entire fixed-width field without a terminator.

Fixes: fc1b6d6de220 ("tipc: introduce TIPC encryption & authentication")
Cc: stable@vger.kernel.org

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 net/tipc/crypto.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
index 6d3b6b89b1d1..60110ea0fe7c 100644
--- a/net/tipc/crypto.c
+++ b/net/tipc/crypto.c
@@ -307,6 +307,11 @@ static void tipc_crypto_work_tx(struct work_struct *work);
 static void tipc_crypto_work_rx(struct work_struct *work);
 static int tipc_aead_key_generate(struct tipc_aead_key *skey);
 
+static bool tipc_aead_alg_name_valid(const char *alg_name)
+{
+	return strnlen(alg_name, TIPC_AEAD_ALG_NAME) < TIPC_AEAD_ALG_NAME;
+}
+
 #define is_tx(crypto) (!(crypto)->node)
 #define is_rx(crypto) (!is_tx(crypto))
 
@@ -335,6 +340,11 @@ int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info)
 {
 	int keylen;
 
+	if (unlikely(!tipc_aead_alg_name_valid(ukey->alg_name))) {
+		GENL_SET_ERR_MSG(info, "algorithm name is not NUL-terminated");
+		return -EINVAL;
+	}
+
 	/* Check if algorithm exists */
 	if (unlikely(!crypto_has_alg(ukey->alg_name, 0, 0))) {
 		GENL_SET_ERR_MSG(info, "unable to load the algorithm (module existed?)");
@@ -2298,6 +2308,10 @@ static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
 		pr_debug("%s: invalid MSG_CRYPTO key size\n", rx->name);
 		goto exit;
 	}
+	if (unlikely(!tipc_aead_alg_name_valid(data))) {
+		pr_debug("%s: invalid MSG_CRYPTO algorithm name\n", rx->name);
+		goto exit;
+	}
 
 	spin_lock(&rx->lock);
 	if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) {
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* Re: [PATCH net,v2 00/11] Netfilter/IPVS fixes for net
From: Pablo Neira Ayuso @ 2026-04-17  7:51 UTC (permalink / raw)
  To: Florian Westphal
  Cc: netfilter-devel, davem, netdev, kuba, pabeni, edumazet, horms
In-Reply-To: <aeFRt__YQqJ84ZaN@strlen.de>

On Thu, Apr 16, 2026 at 11:16:39PM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
[...]
> If you don't want to take this v2 because of above issues, please
> consider at least applying
> 
>   ↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 08/11] ipvs: fix MTU check for GSO packets in tunnel mode
>   ↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 09/11] netfilter: nf_tables: use list_del_rcu for netlink hooks
>   ↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 10/11] rculist: add list_splice_rcu() for private lists
>   ↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 05/11] netfilter: conntrack: remove sprintf usage
>   ↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 06/11] netfilter: xtables: restrict several matches to inet family
> 
> manually.  nf:main always tracks net:main, applying them manually
> doesn't cause issues.

Florian, I am going to prepare a v3.

^ permalink raw reply

* Re: [PATCH for-7.1-fixes 1/2] rhashtable: add no_sync_grow option
From: Herbert Xu @ 2026-04-17  7:51 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Thomas Graf, David Vernet, Andrea Righi, Changwoo Min,
	Emil Tsalapatis, linux-crypto, sched-ext, linux-kernel,
	Florian Westphal, netdev
In-Reply-To: <aeHjjGEhlikSsxCX@slm.duckdns.org>

On Thu, Apr 16, 2026 at 09:38:52PM -1000, Tejun Heo wrote:
>
> Also, taking a step back, if rhashtable allows usage under raw spin locks,
> isn't this broken regardless of how easy or difficult it may be to reproduce
> the problem? Practically speaking, the scx_sched_hash one is unlikely to
> trigger in real world; however, it is still theoretically possible and I'm
> pretty positive that one would be able to create a repro case with the right
> interference workload. It'd be contrived for sure but should be possible.

rhashtable originated in networking where it tries very hard to
stop the hash table from ever degenerating into a linked list.

If your use-case is not as adversarial as that, and you're happy
for the hash table to degenerate into a linked-list in the worst
case, then yes it's aboslutely fine to not grow the table (or
try to grow it and fail with kmalloc_nolock).

It's just that we haven't had any users like this until now and
the feature that you want got removed because of that.

I'm more than happy to bring it back (commit 5f8ddeab10ce).

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCHv3] selftests: Use ktap helpers for runner.sh
From: Hangbin Liu @ 2026-04-17  7:43 UTC (permalink / raw)
  To: Qingfang Deng
  Cc: Brendan Jackman, Mark Brown, Shuah Khan, linux-kselftest, netdev
In-Reply-To: <861b722f-6d5e-4f47-9d17-00a98fceb8cc@linux.dev>

On Thu, Apr 16, 2026 at 04:07:08PM +0800, Qingfang Deng wrote:
> Hi, Hangbin
> 
> This patch broke selftests run with `make -C tools/testing/selftests` as
> make uses /bin/sh by default:
> 
> /bin/sh: 5: /home/qf/linux-next/tools/testing/selftests/kselftest/runner.sh:
> Bad substitution
> 
> Add `SHELL := /bin/bash` to the start of lib.mk to fix this.

Hi Qingfang,

Thanks for the report. I saw Mark helped fix this issue.
Sorry for the inconvenient.

hangbin

^ permalink raw reply

* Re: [PATCH net] net: dsa: mt7530: fix .get_stats64 sleeping in atomic context
From: Chester A. Unal @ 2026-04-17  7:35 UTC (permalink / raw)
  To: Daniel Golle, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Matthias Brugger,
	AngeloGioacchino Del Regno, Russell King, Christian Marangi,
	netdev, linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: Frank Wunderlich, John Crispin
In-Reply-To: <79dc0ec5b6be698b14cb66339d6f63033ca2934a.1776397542.git.daniel@makrotopia.org>

On 17 April 2026 04:55:57 WEST, Daniel Golle <daniel@makrotopia.org> wrote:
>The .get_stats64 callback runs in atomic context, but on
>MDIO-connected switches every register read acquires the MDIO bus
>mutex, which can sleep:
>[   12.645973] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:609
>[   12.654442] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 759, name: grep
>[   12.663377] preempt_count: 0, expected: 0
>[   12.667410] RCU nest depth: 1, expected: 0
>[   12.671511] INFO: lockdep is turned off.
>[   12.675441] CPU: 0 UID: 0 PID: 759 Comm: grep Tainted: G S      W           7.0.0+ #0 PREEMPT
>[   12.675453] Tainted: [S]=CPU_OUT_OF_SPEC, [W]=WARN
>[   12.675456] Hardware name: Bananapi BPI-R64 (DT)
>[   12.675459] Call trace:
>[   12.675462]  show_stack+0x14/0x1c (C)
>[   12.675477]  dump_stack_lvl+0x68/0x8c
>[   12.675487]  dump_stack+0x14/0x1c
>[   12.675495]  __might_resched+0x14c/0x220
>[   12.675504]  __might_sleep+0x44/0x80
>[   12.675511]  __mutex_lock+0x50/0xb10
>[   12.675523]  mutex_lock_nested+0x20/0x30
>[   12.675532]  mt7530_get_stats64+0x40/0x2ac
>[   12.675542]  dsa_user_get_stats64+0x2c/0x40
>[   12.675553]  dev_get_stats+0x44/0x1e0
>[   12.675564]  dev_seq_printf_stats+0x24/0xe0
>[   12.675575]  dev_seq_show+0x14/0x3c
>[   12.675583]  seq_read_iter+0x37c/0x480
>[   12.675595]  seq_read+0xd0/0xec
>[   12.675605]  proc_reg_read+0x94/0xe4
>[   12.675615]  vfs_read+0x98/0x29c
>[   12.675625]  ksys_read+0x54/0xdc
>[   12.675633]  __arm64_sys_read+0x18/0x20
>[   12.675642]  invoke_syscall.constprop.0+0x54/0xec
>[   12.675653]  do_el0_svc+0x3c/0xb4
>[   12.675662]  el0_svc+0x38/0x200
>[   12.675670]  el0t_64_sync_handler+0x98/0xdc
>[   12.675679]  el0t_64_sync+0x158/0x15c
>
>For MDIO-connected switches, poll MIB counters asynchronously using a
>delayed workqueue every second and let .get_stats64 return the cached
>values under a per-port spinlock. A mod_delayed_work() call on each
>read triggers an immediate refresh so counters stay responsive when
>queried more frequently.
>
>MMIO-connected switches (MT7988, EN7581, AN7583) are not affected
>because their regmap does not sleep, so they continue to read MIB
>counters directly in .get_stats64.
>
>Fixes: 88c810f35ed5 ("net: dsa: mt7530: implement .get_stats64")
>Signed-off-by: Daniel Golle <daniel@makrotopia.org>
>---
>This bug highlights a bigger problem and the actual cause:
>Locking in the mt7530 driver deserves a cleanup, and refactoring
>towards cleanly and directly using the regmap API.
>I've prepared this already and am going to submit a series doing
>most of that using Coccinelle semantic patches once net-next opens
>again.

Acked-by: Chester A. Unal <chester.a.unal@arinc9.com>

Chester A.

^ permalink raw reply

* Re: TCP default settings (bugzilla)
From: Willy Tarreau @ 2026-04-17  7:33 UTC (permalink / raw)
  To: plantegg ren; +Cc: stephen, netdev
In-Reply-To: <CAMrUUotdnC+Gv3oud75Ns3BMiOCEo+_fNYX4_L=r=YhtyzZ0Qw@mail.gmail.com>

On Fri, Apr 17, 2026 at 03:01:08PM +0800, plantegg ren wrote:
> Hi,
> 
> One more real-world data point that just happened two weeks ago,
> directly related to tcp_keepalive_time.
> 
> AWS recently rolled out Nitro V6 (8th-gen EC2 instances) which reduced
> the ENI connection tracking timeout from 432000 seconds (5 days) to
> just 350 seconds:
> 
>   https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-connection-tracking.html
> 
> Our MySQL/HikariCP connection pools started seeing intermittent timeout
> errors every 20-30 minutes after migrating to 8th-gen instances. We
> captured packets on both client and server simultaneously. Here is what
> we found on a single connection (idle for 818 seconds, well past the
> 350-second ENI timeout):
> 
> Server side -- MySQL receives the request and sends responses normally:
> 
>   #270  71.51s  10.23.99.71 -> 172.20.64.240  [ACK]     last activity
>                   ~~~ connection idle for 818 seconds ~~~
>   #271 889.94s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  client
> request arrives
>   #272 889.94s  172.20.64.240 -> 10.23.99.71  [PSH,ACK] len=11 server
> responds OK
>   #275 890.15s  172.20.64.240 -> 10.23.99.71  [PSH,ACK] len=11 server
> retransmits
>   #278 890.59s  172.20.64.240 -> 10.23.99.71  [PSH,ACK] len=11 server
> retransmits
>   #281 891.02s  172.20.64.240 -> 10.23.99.71  [PSH,ACK] len=11 server
> retransmits
>     ... (server keeps retransmitting, client never ACKs)
> 
> Client side -- sends request, but NEVER receives any server response:
> 
>   #267  71.51s  10.23.99.71 -> 172.20.64.240  [ACK]     last activity
>                   ~~~ connection idle for 818 seconds ~~~
>   #268 889.94s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  sends request
>   #269 890.15s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  retransmit 1
>   #270 890.37s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  retransmit 2
>   #271 890.79s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  retransmit 3
>   #272 891.65s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  retransmit 4
>   #273 893.38s  10.23.99.71 -> 172.20.64.240  [PSH,ACK] len=5  retransmit 5
>   #274 894.94s  10.23.99.71 -> 172.20.64.240  [FIN,ACK]         gives up
> 
>   Zero packets from 172.20.64.240 after the idle gap. Zero RSTs.
> 
> The ENI silently drops all inbound packets (server -> client) because
> the connection tracking entry expired after 350 seconds. Outbound
> packets (client -> server) still pass through, so the server receives
> the request and responds -- but its responses are black-holed by the
> ENI. No RST is sent, so both sides are completely unaware.
> 
> If tcp_keepalive_time were lower than 350 seconds, the keepalive probes
> would have kept the ENI tracking entry alive, and none of this would
> have happened.
> 
> The trend is clear -- middlebox idle timeouts are getting shorter (AWS
> went from 432000s to 350s overnight), while tcp_keepalive_time has
> stayed at 7200 seconds for decades. The gap is widening.

It's up to the application to configure the keepalive interval if it
is relying on long connections, it's done using TCP_KEEPINTVL, and if
you're dealing with an application that doesn't expose the setting,
you indeed still have access to the system-wide setting above.

It's been well-known for at least two decades that no middle box could
sanely keep idle connections forever with the amount of traffic they're
seeing. 25 years ago I was already tuning the conntrack timeouts for a
bank firewall that was dealing with only 6k connections per second so
as to stay within reasonable memory sizes while keeping a good quality
of service. There's nothing new here.

Willy

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox