xref: /linux/tools/testing/selftests/net/hsr/link_faults.sh (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# shellcheck disable=SC2329
4
5source ../lib.sh
6
7ALL_TESTS="
8	test_clean_hsrv0
9	test_cut_link_hsrv0
10	test_packet_loss_hsrv0
11	test_high_packet_loss_hsrv0
12	test_reordering_hsrv0
13
14	test_clean_hsrv1
15	test_cut_link_hsrv1
16	test_packet_loss_hsrv1
17	test_high_packet_loss_hsrv1
18	test_reordering_hsrv1
19
20	test_clean_prp
21	test_cut_link_prp
22	test_packet_loss_prp
23	test_high_packet_loss_prp
24	test_reordering_prp
25"
26
27# The tests are running ping for 5sec with a relatively short interval in
28# different scenarios with faulty links (cut links, packet loss, delay,
29# reordering) that should be recoverable by HSR/PRP. The ping interval (10ms)
30# is short enough that the base delay (50ms) leads to a queue in the netem
31# qdiscs which is needed for reordering.
32
33setup_hsr_topo()
34{
35	# Three HSR nodes in a ring, every node has a LAN A interface connected
36	# to the LAN B interface of the next node.
37	#
38	#    node1            node2
39	#
40	#     vethA -------- vethB
41	#   hsr1                 hsr2
42	#     vethB          vethA
43	#         \          /
44	#         vethA  vethB
45	#             hsr3
46	#
47	#            node3
48
49	local ver="$1"
50
51	setup_ns node1 node2 node3
52
53	# veth links
54	# shellcheck disable=SC2154 # variables assigned by setup_ns
55	ip link add vethA netns "$node1" type veth peer name vethB netns "$node2"
56	# shellcheck disable=SC2154 # variables assigned by setup_ns
57	ip link add vethA netns "$node2" type veth peer name vethB netns "$node3"
58	ip link add vethA netns "$node3" type veth peer name vethB netns "$node1"
59
60	# MAC addresses (not needed for HSR operation, but helps with debugging)
61	ip -net "$node1" link set address 00:11:22:00:01:01 dev vethA
62	ip -net "$node1" link set address 00:11:22:00:01:02 dev vethB
63
64	ip -net "$node2" link set address 00:11:22:00:02:01 dev vethA
65	ip -net "$node2" link set address 00:11:22:00:02:02 dev vethB
66
67	ip -net "$node3" link set address 00:11:22:00:03:01 dev vethA
68	ip -net "$node3" link set address 00:11:22:00:03:02 dev vethB
69
70	# HSR interfaces
71	ip -net "$node1" link add name hsr1 type hsr proto 0 version "$ver" \
72		slave1 vethA slave2 vethB supervision 45
73	ip -net "$node2" link add name hsr2 type hsr proto 0 version "$ver" \
74		slave1 vethA slave2 vethB supervision 45
75	ip -net "$node3" link add name hsr3 type hsr proto 0 version "$ver" \
76		slave1 vethA slave2 vethB supervision 45
77
78	# IP addresses
79	ip -net "$node1" addr add 100.64.0.1/24 dev hsr1
80	ip -net "$node2" addr add 100.64.0.2/24 dev hsr2
81	ip -net "$node3" addr add 100.64.0.3/24 dev hsr3
82
83	# Set all links up
84	ip -net "$node1" link set vethA up
85	ip -net "$node1" link set vethB up
86	ip -net "$node1" link set hsr1 up
87
88	ip -net "$node2" link set vethA up
89	ip -net "$node2" link set vethB up
90	ip -net "$node2" link set hsr2 up
91
92	ip -net "$node3" link set vethA up
93	ip -net "$node3" link set vethB up
94	ip -net "$node3" link set hsr3 up
95}
96
97setup_prp_topo()
98{
99	# Two PRP nodes, connected by two links (treated as LAN A and LAN B).
100	#
101	#       vethA ----- vethA
102	#     prp1             prp2
103	#       vethB ----- vethB
104	#
105	#     node1           node2
106
107	setup_ns node1 node2
108
109	# veth links
110	ip link add vethA netns "$node1" type veth peer name vethA netns "$node2"
111	ip link add vethB netns "$node1" type veth peer name vethB netns "$node2"
112
113	# MAC addresses will be copied from LAN A interface
114	ip -net "$node1" link set address 00:11:22:00:00:01 dev vethA
115	ip -net "$node2" link set address 00:11:22:00:00:02 dev vethA
116
117	# PRP interfaces
118	ip -net "$node1" link add name prp1 type hsr \
119		slave1 vethA slave2 vethB supervision 45 proto 1
120	ip -net "$node2" link add name prp2 type hsr \
121		slave1 vethA slave2 vethB supervision 45 proto 1
122
123	# IP addresses
124	ip -net "$node1" addr add 100.64.0.1/24 dev prp1
125	ip -net "$node2" addr add 100.64.0.2/24 dev prp2
126
127	# All links up
128	ip -net "$node1" link set vethA up
129	ip -net "$node1" link set vethB up
130	ip -net "$node1" link set prp1 up
131
132	ip -net "$node2" link set vethA up
133	ip -net "$node2" link set vethB up
134	ip -net "$node2" link set prp2 up
135}
136
137wait_for_hsr_node_table()
138{
139	log_info "Wait for node table entries to be merged."
140	WAIT=5
141	while [ "${WAIT}" -gt 0 ]; do
142		nts=$(cat /sys/kernel/debug/hsr/hsr*/node_table)
143
144		# We need entries in the node tables, and they need to be merged
145		if (echo "$nts" | grep -qE "^([0-9a-f]{2}:){5}") && \
146		    ! (echo "$nts" | grep -q "00:00:00:00:00:00"); then
147			return
148		fi
149
150		sleep 1
151		((WAIT--))
152	done
153	check_err 1 "Failed to wait for merged node table entries"
154}
155
156setup_topo()
157{
158	local proto="$1"
159
160	if [ "$proto" = "HSRv0" ]; then
161		setup_hsr_topo 0
162		wait_for_hsr_node_table
163	elif [ "$proto" = "HSRv1" ]; then
164		setup_hsr_topo 1
165		wait_for_hsr_node_table
166	elif [ "$proto" = "PRP" ]; then
167		setup_prp_topo
168	else
169		check_err 1 "Unknown protocol (${proto})"
170	fi
171}
172
173check_ping()
174{
175	local node="$1"
176	local dst="$2"
177	local accepted_dups="$3"
178	local ping_args="-q -i 0.01 -c 400"
179
180	log_info "Running ping $node -> $dst"
181	# shellcheck disable=SC2086
182	output=$(ip netns exec "$node" ping $ping_args "$dst" | \
183		grep "packets transmitted")
184	log_info "$output"
185
186	dups=0
187	loss=0
188
189	if [[ "$output" =~ \+([0-9]+)" duplicates" ]]; then
190		dups="${BASH_REMATCH[1]}"
191	fi
192	if [[ "$output" =~ ([0-9\.]+\%)" packet loss" ]]; then
193		loss="${BASH_REMATCH[1]}"
194	fi
195
196	if [ "$dups" -gt "$accepted_dups" ]; then
197		check_err 1 "Unexpected duplicate packets (${dups})"
198	fi
199	if [ "$loss" != "0%" ]; then
200		check_err 1 "Unexpected packet loss (${loss})"
201	fi
202}
203
204test_clean()
205{
206	local proto="$1"
207
208	RET=0
209	tname="${FUNCNAME[0]} - ${proto}"
210
211	setup_topo "$proto"
212	if ((RET != ksft_pass)); then
213		log_test "${tname} setup"
214		return
215	fi
216
217	check_ping "$node1" "100.64.0.2" 0
218
219	log_test "${tname}"
220}
221
222test_clean_hsrv0()
223{
224	test_clean "HSRv0"
225}
226
227test_clean_hsrv1()
228{
229	test_clean "HSRv1"
230}
231
232test_clean_prp()
233{
234	test_clean "PRP"
235}
236
237test_cut_link()
238{
239	local proto="$1"
240
241	RET=0
242	tname="${FUNCNAME[0]} - ${proto}"
243
244	setup_topo "$proto"
245	if ((RET != ksft_pass)); then
246		log_test "${tname} setup"
247		return
248	fi
249
250	# Cutting link from subshell, so check_ping can run in the normal shell
251	# with access to global variables from the test harness.
252	(
253		sleep 2
254		log_info "Cutting link"
255		ip -net "$node1" link set vethB down
256	) &
257	check_ping "$node1" "100.64.0.2" 0
258
259	wait
260	log_test "${tname}"
261}
262
263
264test_cut_link_hsrv0()
265{
266	test_cut_link "HSRv0"
267}
268
269test_cut_link_hsrv1()
270{
271	test_cut_link "HSRv1"
272}
273
274test_cut_link_prp()
275{
276	test_cut_link "PRP"
277}
278
279test_packet_loss()
280{
281	local proto="$1"
282	local loss="$2"
283
284	RET=0
285	tname="${FUNCNAME[0]} - ${proto}, ${loss}"
286
287	setup_topo "$proto"
288	if ((RET != ksft_pass)); then
289		log_test "${tname} setup"
290		return
291	fi
292
293	# Packet loss with lower delay makes sure the packets on the lossy link
294	# arrive first.
295	tc -net "$node1" qdisc add dev vethA root netem delay 50ms
296	tc -net "$node1" qdisc add dev vethB root netem delay 20ms loss "$loss"
297
298	check_ping "$node1" "100.64.0.2" 40
299
300	log_test "${tname}"
301}
302
303test_packet_loss_hsrv0()
304{
305	test_packet_loss "HSRv0" "20%"
306}
307
308test_packet_loss_hsrv1()
309{
310	test_packet_loss "HSRv1" "20%"
311}
312
313test_packet_loss_prp()
314{
315	test_packet_loss "PRP" "20%"
316}
317
318test_high_packet_loss_hsrv0()
319{
320	test_packet_loss "HSRv0" "80%"
321}
322
323test_high_packet_loss_hsrv1()
324{
325	test_packet_loss "HSRv1" "80%"
326}
327
328test_high_packet_loss_prp()
329{
330	test_packet_loss "PRP" "80%"
331}
332
333test_reordering()
334{
335	local proto="$1"
336
337	RET=0
338	tname="${FUNCNAME[0]} - ${proto}"
339
340	setup_topo "$proto"
341	if ((RET != ksft_pass)); then
342		log_test "${tname} setup"
343		return
344	fi
345
346	tc -net "$node1" qdisc add dev vethA root netem delay 50ms
347	tc -net "$node1" qdisc add dev vethB root netem delay 50ms reorder 20%
348
349	check_ping "$node1" "100.64.0.2" 40
350
351	log_test "${tname}"
352}
353
354test_reordering_hsrv0()
355{
356	test_reordering "HSRv0"
357}
358
359test_reordering_hsrv1()
360{
361	test_reordering "HSRv1"
362}
363
364test_reordering_prp()
365{
366	test_reordering "PRP"
367}
368
369cleanup()
370{
371	cleanup_all_ns
372}
373
374trap cleanup EXIT
375
376tests_run
377
378exit $EXIT_STATUS
379