[Openvpn-devel,RFC,net-next,v8,2/2] ovpn: add broadcast and multicast selftests
Commit Message
Add a test stage that verifies the ovpn module forwards broadcast
(IPv4) and multicast (IPv4/v6) packets to all active peers.
For each mode we start tcpdump on every client peer, send a single
ping from peer0 to the broadcast/multicast address, and verify all
peers captured the packet.
Assign link-local addresses explicitly for the IPv6
multicast test so that ping to ff02::1 has a valid source address.
Signed-off-by: Marco Baffo <marco@mandelbit.com>
---
Changes un v8:
- Moved the disabling of automatic address generation to the previous patch.
Changes in v7:
- Disable automatic IPv6 link-local address generation and assign
addresses only for the IPv6 multicast test, avoiding background
traffic that affects the mark test's packet counts.
- Replace fixed startup delays with bounded tcpdump readiness checks.
- Consolidate capture handling in a shared helper with timeouts,
per-peer diagnostics, and process/temporary-file cleanup.
tools/testing/selftests/net/ovpn/test.sh | 78 +++++++++++++++++++++++-
1 file changed, 76 insertions(+), 2 deletions(-)
@@ -56,6 +56,79 @@ ovpn_prepare_network() {
done
}
+ovpn_run_mbcast_test() (
+ local label="$1"
+ local destination="$2"
+ local filter="$3"
+ local capture_dir
+ local deadline
+ local p
+ local ret=0
+ local -a pids=()
+
+ shift 3
+ capture_dir=$(mktemp -d) || return 1
+ trap 'kill "${pids[@]}" 2>/dev/null || true
+ wait "${pids[@]}" 2>/dev/null || true
+ rm -rf "${capture_dir}"' EXIT
+ trap 'exit 1' INT TERM
+
+ ovpn_log "Testing ${label}:"
+ # Allow five seconds for startup, plus time to send and capture the ping.
+ deadline=$((SECONDS + 5))
+ for p in $(seq 1 "${OVPN_NUM_PEERS}"); do
+ : >"${capture_dir}/${p}" || return 1
+ LC_ALL=C timeout 10 ip netns exec "ovpn_peer${p}" \
+ tcpdump --immediate-mode -p -ni "tun${p}" -c 1 \
+ "${filter}" >/dev/null 2>"${capture_dir}/${p}" &
+ pids[p]=$!
+ done
+
+ for p in $(seq 1 "${OVPN_NUM_PEERS}"); do
+ while ! grep -q "listening on tun${p}," "${capture_dir}/${p}"; do
+ if ! kill -0 "${pids[p]}" 2>/dev/null ||
+ ((SECONDS >= deadline)); then
+ printf '# %s: capture not ready on peer%s\n' \
+ "${label}" "${p}"
+ cat "${capture_dir}/${p}"
+ return 1
+ fi
+ sleep 0.1
+ done
+ done
+
+ ovpn_cmd_mayfail "send ${label} ping from peer0" \
+ ip netns exec ovpn_peer0 ping "$@" -qc 1 -w 3 -I tun0 \
+ "${destination}"
+ for p in $(seq 1 "${OVPN_NUM_PEERS}"); do
+ if ! wait "${pids[p]}"; then
+ printf '# %s: capture failed on peer%s\n' "${label}" "${p}"
+ cat "${capture_dir}/${p}"
+ ret=1
+ fi
+ unset 'pids[p]'
+ done
+
+ return "${ret}"
+)
+
+ovpn_run_mbcast_tests() {
+ local p
+
+ ovpn_run_mbcast_test "broadcast" 5.5.5.255 \
+ 'icmp and dst host 5.5.5.255' -b || return 1
+ ovpn_run_mbcast_test "IPv4 multicast" 224.0.0.1 \
+ 'icmp and dst host 224.0.0.1' || return 1
+
+ for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
+ ovpn_cmd_ok "configure IPv6 address on peer${p}" \
+ ip -n "ovpn_peer${p}" addr add fe80::$((p + 1))/64 \
+ dev tun${p} scope link
+ done
+ ovpn_run_mbcast_test "IPv6 multicast" ff02::1 \
+ 'icmp6 and dst host ff02::1' -6 || return 1
+}
+
ovpn_run_basic_traffic() {
local p
local header1
@@ -293,9 +366,9 @@ trap ovpn_stage_err ERR
ktap_print_header
if [ "${OVPN_FLOAT}" == "1" ]; then
- ktap_set_plan 13
+ ktap_set_plan 14
else
- ktap_set_plan 12
+ ktap_set_plan 13
fi
ovpn_cleanup
@@ -303,6 +376,7 @@ 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 multi/broadcast traffic" ovpn_run_mbcast_tests
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