xref: /linux/tools/testing/selftests/net/ovpn/test.sh (revision fcee7d82f27d6a8b1ddc5bbefda59b4e441e9bc0)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (C) 2020-2025 OpenVPN, Inc.
4#
5#  Author:	Antonio Quartulli <antonio@openvpn.net>
6
7#set -x
8set -eE
9
10source ./common.sh
11
12ovpn_test_finished=0
13
14ovpn_test_exit() {
15	ovpn_cleanup
16	modprobe -r ovpn || true
17
18	if [ "${ovpn_test_finished}" -eq 0 ]; then
19		ktap_print_totals
20	fi
21}
22
23ovpn_prepare_network() {
24	local p
25	local peer_ns
26
27	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
28		ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
29	done
30
31	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
32		ovpn_cmd_ok "start notification listener peer${p}" \
33			ovpn_setup_listener "${p}"
34		# starting all YNL listeners back-to-back can intermittently
35		# stall their startup so serialize launches a bit
36		sleep 0.5
37	done
38
39	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
40		ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
41			"${p}" 5.5.5.$((p + 1))/24 "${MTU}"
42	done
43
44	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
45		ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
46	done
47
48	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
49		peer_ns="ovpn_peer${p}"
50		ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
51			ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
52				${p} 60 120
53		ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
54			ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
55				tun${p} $((p + OVPN_ID_OFFSET)) 60 120
56	done
57}
58
59ovpn_run_basic_traffic() {
60	local p
61	local header1
62	local header2
63	local peer_ns
64	local raddr
65	local tcpdump_pid1
66	local tcpdump_pid2
67	local tcpdump_timeout="1.5s"
68
69	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
70		# The first part of the data packet header consists of:
71		# - TCP only: 2 bytes for the packet length
72		# - 5 bits for opcode ("9" for DATA_V2)
73		# - 3 bits for key-id ("0" at this point)
74		# - 12 bytes for peer-id:
75		#     - with asymmetric ID: "${p}" one way and "${p} + 9" the
76		#	other way
77		#     - with symmetric ID: "${p}" both ways
78		header1=$(printf "0x4800000%x" ${p})
79		header2=$(printf "0x4800000%x" $((p + OVPN_ID_OFFSET)))
80		raddr=""
81		if [ "${OVPN_PROTO}" == "UDP" ]; then
82			raddr=$(awk "NR == ${p} {print \$3}" \
83				"${OVPN_UDP_PEERS_FILE}")
84		fi
85		peer_ns="ovpn_peer${p}"
86
87		timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
88			tcpdump --immediate-mode -p -ni veth${p} -c 1 \
89			"$(ovpn_build_capture_filter "${header1}" "${raddr}")" \
90			>/dev/null 2>&1 &
91		tcpdump_pid1=$!
92		timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
93			tcpdump --immediate-mode -p -ni veth${p} -c 1 \
94			"$(ovpn_build_capture_filter "${header2}" "${raddr}")" \
95			>/dev/null 2>&1 &
96		tcpdump_pid2=$!
97
98		sleep 0.3
99		ovpn_cmd_ok "send baseline traffic to peer ${p}" \
100			ip netns exec ovpn_peer0 \
101			ping -qfc 100 -w 3 5.5.5.$((p + 1))
102		ovpn_cmd_ok "send large-payload traffic to peer ${p}" \
103			ip netns exec ovpn_peer0 \
104			ping -qfc 100 -s 3000 -w 3 5.5.5.$((p + 1))
105
106		wait "${tcpdump_pid1}" || return 1
107		wait "${tcpdump_pid2}" || return 1
108	done
109}
110
111ovpn_run_lan_traffic() {
112	ovpn_cmd_ok "ping LAN behind peer1" \
113		ip netns exec ovpn_peer0 ping -qfc 500 -w 3 "${OVPN_LAN_IP}"
114}
115
116ovpn_run_float_mode() {
117	local p
118	local peer_ns
119
120	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
121		peer_ns="ovpn_peer${p}"
122		ovpn_cmd_ok "float: remove old transport address on peer${p}" \
123			ip -n "${peer_ns}" addr del 10.10.${p}.2/24 dev veth${p}
124		ovpn_cmd_ok "float: add new transport address on peer${p}" \
125			ip -n "${peer_ns}" addr add 10.10.${p}.3/24 dev veth${p}
126	done
127	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
128		peer_ns="ovpn_peer${p}"
129		ovpn_cmd_ok "ping tunnel after float peer ${p}" \
130			ip netns exec "${peer_ns}" ping -qfc 500 -w 3 5.5.5.1
131	done
132}
133
134ovpn_run_iperf() {
135	local iperf_pid
136
137	ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s
138	sleep 1
139
140	ovpn_cmd_ok "run iperf throughput flow" \
141		ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
142	wait "${iperf_pid}" || return 1
143}
144
145ovpn_run_key_rollover() {
146	local p
147	local peer_ns
148
149	ovpn_log "Adding secondary key and then swap:"
150
151	for p in $(seq 1 ${OVPN_NUM_PEERS}); do
152		peer_ns="ovpn_peer${p}"
153		ovpn_cmd_ok "add secondary key on peer0 for peer ${p}" \
154			ip netns exec ovpn_peer0 ${OVPN_CLI} new_key tun0 \
155				${p} 2 1 ${OVPN_ALG} 0 data64.key
156		ovpn_cmd_ok "add secondary key on peer${p} for peer ${p}" \
157			ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${p} \
158				$((p + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 \
159				data64.key
160		ovpn_cmd_ok "swap keys on peer${p}" \
161			ip netns exec "${peer_ns}" ${OVPN_CLI} swap_keys \
162				tun${p} $((p + OVPN_ID_OFFSET))
163	done
164}
165
166ovpn_run_queries() {
167	ovpn_log "Querying all peers:"
168
169	ovpn_cmd_ok "query all peers from peer0" \
170		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0
171	ovpn_cmd_ok "query all peers from peer1" \
172		ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1
173
174	ovpn_log "Querying peer 1:"
175
176	ovpn_cmd_ok "query peer 1 from peer0" \
177		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 1
178}
179
180ovpn_query_peer_missing() {
181	ovpn_log "Querying non-existent peer 20:"
182
183	ovpn_cmd_fail "query missing peer 20 on peer0" \
184		ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 20
185}
186
187ovpn_run_peer_cleanup() {
188	local p
189	local peer_ns
190
191	ovpn_log "Deleting peer 1:"
192
193	ovpn_cmd_ok "delete peer1 on peer0" \
194		ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 1
195	ovpn_cmd_ok "delete peer1 on peer1" \
196		ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 \
197			$((1 + OVPN_ID_OFFSET))
198
199	ovpn_log "Querying keys:"
200
201	for p in $(seq 2 ${OVPN_NUM_PEERS}); do
202		peer_ns="ovpn_peer${p}"
203		ovpn_cmd_ok "query peer${p} key 1" \
204			ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
205				$((p + OVPN_ID_OFFSET)) 1
206		ovpn_cmd_ok "query peer${p} key 2" \
207			ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
208				$((p + OVPN_ID_OFFSET)) 2
209	done
210}
211
212ovpn_run_traffic_delete_peer() {
213	local ping_pid
214
215	ovpn_log "Deleting peer while sending traffic:"
216
217	ovpn_run_bg ping_pid ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1
218	sleep 2
219	ovpn_cmd_ok "delete peer0 peer 2" \
220		ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 2
221
222	if [ "${OVPN_PROTO}" == "TCP" ]; then
223		# In TCP mode this command is expected to fail for both peers.
224		ovpn_cmd_mayfail "delete peer2 peer 2 (TCP non-fatal)" \
225			ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 \
226				$((2 + OVPN_ID_OFFSET))
227	else
228		ovpn_cmd_ok "delete peer2 peer 2" ip netns exec ovpn_peer2 \
229			${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET))
230	fi
231
232	wait "${ping_pid}" || true
233}
234
235ovpn_run_key_cleanup() {
236	local p
237	local peer_ns
238
239	ovpn_log "Deleting keys:"
240
241	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
242		peer_ns="ovpn_peer${p}"
243		ovpn_cmd_ok "delete key 1 for peer${p}" \
244			ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
245				$((p + OVPN_ID_OFFSET)) 1
246		ovpn_cmd_ok "delete key 2 for peer${p}" \
247			ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
248				$((p + OVPN_ID_OFFSET)) 2
249	done
250}
251
252ovpn_run_timeouts() {
253	local p
254	local peer_ns
255
256	ovpn_log "Setting timeout to 3s MP:"
257
258	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
259		# Non-fatal: this may fail in some protocol modes.
260		ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \
261			ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
262				${p} 3 3
263		peer_ns="ovpn_peer${p}"
264		ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \
265			state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
266			tun${p} $((p + OVPN_ID_OFFSET)) 0 0
267	done
268	# wait for peers to timeout
269	sleep 5
270
271	ovpn_log "Setting timeout to 3s P2P:"
272
273	for p in $(seq 3 ${OVPN_NUM_PEERS}); do
274		peer_ns="ovpn_peer${p}"
275		ovpn_cmd_ok "set peer${p} P2P timeout" \
276			ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
277				tun${p} $((p + OVPN_ID_OFFSET)) 3 3
278	done
279	sleep 5
280}
281
282ovpn_run_notifications() {
283	local p
284
285	for p in $(seq 0 ${OVPN_NUM_PEERS}); do
286		ovpn_cmd_ok "validate listener output for peer ${p}" \
287			ovpn_compare_ntfs "${p}"
288	done
289}
290
291trap ovpn_test_exit EXIT
292trap ovpn_stage_err ERR
293
294ktap_print_header
295if [ "${OVPN_FLOAT}" == "1" ]; then
296	ktap_set_plan 13
297else
298	ktap_set_plan 12
299fi
300
301ovpn_cleanup
302modprobe -q ovpn || true
303
304ovpn_run_stage "setup network topology" ovpn_prepare_network
305ovpn_run_stage "run baseline data traffic" ovpn_run_basic_traffic
306ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic
307[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \
308	ovpn_run_float_mode
309ovpn_run_stage "run iperf throughput" ovpn_run_iperf
310ovpn_run_stage "run key rollout" ovpn_run_key_rollover
311ovpn_run_stage "query peers" ovpn_run_queries
312ovpn_run_stage "query missing peer fails" ovpn_query_peer_missing
313ovpn_run_stage "peer lifecycle and key queries" ovpn_run_peer_cleanup
314ovpn_run_stage "delete peer while traffic" ovpn_run_traffic_delete_peer
315ovpn_run_stage "delete stale keys" ovpn_run_key_cleanup
316ovpn_run_stage "check timeout behavior" ovpn_run_timeouts
317ovpn_run_stage "validate notification output" ovpn_run_notifications
318
319ovpn_test_finished=1
320ktap_finished
321