summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/ovpn/test-mark.sh
blob: 7c1d56e9c525d597f2f314b1f45b2c9238eaa5b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020-2025 OpenVPN, Inc.
#
#	Author:	Ralf Lici <ralf@mandelbit.com>
#		Antonio Quartulli <antonio@openvpn.net>

#set -x
set -eE

MARK=1056
MARK_DROP_COUNTER=0

source ./common.sh

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 100 -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 100 -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 100 -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

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