xref: /linux/tools/testing/selftests/net/ovpn/test-mark.sh (revision e728258debd553c95d2e70f9cd97c9fde27c7130)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (C) 2020-2025 OpenVPN, Inc.
4#
5#	Author:	Ralf Lici <ralf@mandelbit.com>
6#		Antonio Quartulli <antonio@openvpn.net>
7
8#set -x
9set -eE
10
11MARK=1056
12MARK_DROP_COUNTER=0
13
14source ./common.sh
15
16ovpn_test_finished=0
17
18ovpn_test_exit() {
19	ovpn_cleanup
20	modprobe -r ovpn || true
21
22	if [ "${ovpn_test_finished}" -eq 0 ]; then
23		ktap_print_totals
24	fi
25}
26
27ovpn_mark_prepare_network() {
28	local p
29	local peer_ns
30
31	for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
32		ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
33	done
34
35	for p in $(seq 0 3); do
36		ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
37			"${p}" 5.5.5.$((p + 1))/24
38	done
39
40	ovpn_cmd_ok "create server-side multi-peer with fwmark" \
41		ip netns exec ovpn_peer0 "${OVPN_CLI}" new_multi_peer tun0 1 \
42			ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}"
43	for p in $(seq 1 3); do
44		ovpn_cmd_ok "install server key for peer ${p}" \
45			ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \
46				"${p}" 1 0 "${OVPN_ALG}" 0 data64.key
47	done
48
49	for p in $(seq 1 3); do
50		ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
51	done
52
53	for p in $(seq 1 3); do
54		peer_ns="ovpn_peer${p}"
55		ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
56			ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \
57				"${p}" 60 120
58		ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
59			ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \
60				tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120
61	done
62}
63
64ovpn_mark_run_baseline_traffic() {
65	local p
66
67	for p in $(seq 1 3); do
68		ovpn_cmd_ok "send baseline traffic to peer ${p}" \
69			ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
70				5.5.5.$((p + 1))
71	done
72}
73
74ovpn_mark_add_drop_rule() {
75	ovpn_log "Adding an nftables drop rule based on mark value ${MARK}"
76
77	ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
78		ruleset
79	ovpn_cmd_ok "create nft filter table" ip netns exec ovpn_peer0 nft \
80		"add table inet filter"
81	ovpn_cmd_ok "create nft filter output chain" \
82		ip netns exec ovpn_peer0 nft "add chain inet filter output { \
83			type filter hook output priority 0; policy accept; }"
84	ovpn_cmd_ok "add nft drop rule for mark ${MARK}" \
85		ip netns exec ovpn_peer0 nft add rule inet filter output \
86			meta mark == "${MARK}" \
87			counter drop
88
89	MARK_DROP_COUNTER=$(ip netns exec ovpn_peer0 nft list chain inet \
90		filter output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
91	if [ -z "${MARK_DROP_COUNTER}" ]; then
92		printf '%s\n' "unable to read nft drop counter"
93		return 1
94	fi
95}
96
97ovpn_mark_verify_drop_traffic() {
98	local p
99	local ping_output
100	local lost_packets
101	local total_count
102
103	for p in $(seq 1 3); do
104		if ping_output=$(ip netns exec ovpn_peer0 ping -qfc 500 -w 1 \
105			5.5.5.$((p + 1)) 2>&1); then
106			printf '%s\n' "expected ping to peer ${p} to fail \
107				after nft drop rule"
108			return 1
109		fi
110		ovpn_log "${ping_output}"
111		lost_packets=$(echo "${ping_output}" | \
112				awk '/packets transmitted/ { print $1 }')
113		if [ -z "${lost_packets}" ]; then
114			printf '%s\n' "unable to parse lost packets for peer \
115				${p}"
116			return 1
117		fi
118		MARK_DROP_COUNTER=$((MARK_DROP_COUNTER + lost_packets))
119	done
120
121	total_count=$(ip netns exec ovpn_peer0 nft list chain inet filter \
122		output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
123	if [ -z "${total_count}" ]; then
124		printf '%s\n' "unable to read final nft drop counter"
125		return 1
126	fi
127	if [ "${MARK_DROP_COUNTER}" -ne "${total_count}" ]; then
128		printf '%s\n' "expected ${MARK_DROP_COUNTER} drops, got \
129			${total_count}"
130		return 1
131	fi
132}
133
134ovpn_mark_remove_drop_rule() {
135	ovpn_log "Removing the drop rule"
136
137	ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
138		ruleset
139}
140
141ovpn_mark_verify_traffic_recovery() {
142	local p
143
144	sleep 1
145	for p in $(seq 1 3); do
146		ovpn_cmd_ok "send recovery traffic to peer ${p}" \
147			ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
148				5.5.5.$((p + 1))
149	done
150}
151
152trap ovpn_test_exit EXIT
153trap ovpn_stage_err ERR
154
155ktap_print_header
156ktap_set_plan 6
157
158ovpn_cleanup
159modprobe -q ovpn || true
160
161ovpn_run_stage "setup marked network topology" ovpn_mark_prepare_network
162ovpn_run_stage "run baseline traffic" ovpn_mark_run_baseline_traffic
163ovpn_run_stage "install nft mark drop rule" ovpn_mark_add_drop_rule
164ovpn_run_stage "drop marked traffic and count packets" \
165	ovpn_mark_verify_drop_traffic
166ovpn_run_stage "remove nft drop rule" ovpn_mark_remove_drop_rule
167ovpn_run_stage "traffic recovers after drop removal" \
168	ovpn_mark_verify_traffic_recovery
169
170ovpn_test_finished=1
171ktap_finished
172