xref: /linux/tools/testing/selftests/net/test_bridge_backup_port.sh (revision e47e2e0ba9103df7b3d25356421e6832c4d0e7be)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# This test is for checking bridge backup port and backup nexthop ID
5# functionality. The topology consists of two bridge (VTEPs) connected using
6# VXLAN. The test checks that when the switch port (swp1) is down, traffic is
7# redirected to the VXLAN port (vx0). When a backup nexthop ID is configured,
8# the test checks that traffic is redirected with the correct nexthop
9# information.
10#
11# +------------------------------------+ +------------------------------------+
12# |    + swp1                   + vx0  | |    + swp1                   + vx0  |
13# |    |                        |      | |    |                        |      |
14# |    |           br0          |      | |    |                        |      |
15# |    +------------+-----------+      | |    +------------+-----------+      |
16# |                 |                  | |                 |                  |
17# |                 |                  | |                 |                  |
18# |                 +                  | |                 +                  |
19# |                br0                 | |                br0                 |
20# |                 +                  | |                 +                  |
21# |                 |                  | |                 |                  |
22# |                 |                  | |                 |                  |
23# |                 +                  | |                 +                  |
24# |              br0.10                | |              br0.10                |
25# |           192.0.2.65/28            | |            192.0.2.66/28           |
26# |                                    | |                                    |
27# |                                    | |                                    |
28# |                 192.0.2.33         | |                 192.0.2.34         |
29# |                 + lo               | |                 + lo               |
30# |                                    | |                                    |
31# |                                    | |                                    |
32# |                   192.0.2.49/28    | |    192.0.2.50/28                   |
33# |                           veth0 +-------+ veth0                           |
34# |                                    | |                                    |
35# | sw1                                | | sw2                                |
36# +------------------------------------+ +------------------------------------+
37
38source lib.sh
39ret=0
40
41# All tests in this script. Can be overridden with -t option.
42TESTS="
43	backup_port
44	backup_nhid
45	backup_nhid_invalid
46	backup_nhid_ping
47	backup_nhid_torture
48"
49VERBOSE=0
50PAUSE_ON_FAIL=no
51PAUSE=no
52PING_TIMEOUT=5
53
54################################################################################
55# Utilities
56
57log_test()
58{
59	local rc=$1
60	local expected=$2
61	local msg="$3"
62
63	if [ ${rc} -eq ${expected} ]; then
64		printf "TEST: %-60s  [ OK ]\n" "${msg}"
65		nsuccess=$((nsuccess+1))
66	else
67		ret=1
68		nfail=$((nfail+1))
69		printf "TEST: %-60s  [FAIL]\n" "${msg}"
70		if [ "$VERBOSE" = "1" ]; then
71			echo "    rc=$rc, expected $expected"
72		fi
73
74		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
75		echo
76			echo "hit enter to continue, 'q' to quit"
77			read a
78			[ "$a" = "q" ] && exit 1
79		fi
80	fi
81
82	if [ "${PAUSE}" = "yes" ]; then
83		echo
84		echo "hit enter to continue, 'q' to quit"
85		read a
86		[ "$a" = "q" ] && exit 1
87	fi
88
89	[ "$VERBOSE" = "1" ] && echo
90}
91
92run_cmd()
93{
94	local cmd="$1"
95	local out
96	local stderr="2>/dev/null"
97
98	if [ "$VERBOSE" = "1" ]; then
99		printf "COMMAND: $cmd\n"
100		stderr=
101	fi
102
103	out=$(eval $cmd $stderr)
104	rc=$?
105	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
106		echo "    $out"
107	fi
108
109	return $rc
110}
111
112tc_check_packets()
113{
114	local ns=$1; shift
115	local id=$1; shift
116	local handle=$1; shift
117	local count=$1; shift
118	local pkts
119
120	sleep 0.1
121	pkts=$(tc -n $ns -j -s filter show $id \
122		| jq ".[] | select(.options.handle == $handle) | \
123		.options.actions[0].stats.packets")
124	[[ $pkts == $count ]]
125}
126
127################################################################################
128# Setup
129
130setup_topo_ns()
131{
132	local ns=$1; shift
133
134	ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
135	ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1
136	ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0
137	ip netns exec $ns sysctl -qw net.ipv6.conf.default.accept_dad=0
138}
139
140setup_topo()
141{
142	local ns
143
144	setup_ns sw1 sw2
145	for ns in $sw1 $sw2; do
146		setup_topo_ns $ns
147	done
148
149	ip link add name veth0 type veth peer name veth1
150	ip link set dev veth0 netns $sw1 name veth0
151	ip link set dev veth1 netns $sw2 name veth0
152}
153
154setup_sw_common()
155{
156	local ns=$1; shift
157	local local_addr=$1; shift
158	local remote_addr=$1; shift
159	local veth_addr=$1; shift
160	local gw_addr=$1; shift
161	local br_addr=$1; shift
162
163	ip -n $ns address add $local_addr/32 dev lo
164
165	ip -n $ns link set dev veth0 up
166	ip -n $ns address add $veth_addr/28 dev veth0
167	ip -n $ns route add default via $gw_addr
168
169	ip -n $ns link add name br0 up type bridge vlan_filtering 1 \
170		vlan_default_pvid 0 mcast_snooping 0
171
172	ip -n $ns link add link br0 name br0.10 up type vlan id 10
173	bridge -n $ns vlan add vid 10 dev br0 self
174	ip -n $ns address add $br_addr/28 dev br0.10
175
176	ip -n $ns link add name swp1 up type dummy
177	ip -n $ns link set dev swp1 master br0
178	bridge -n $ns vlan add vid 10 dev swp1 untagged
179
180	ip -n $ns link add name vx0 up master br0 type vxlan \
181		local $local_addr dstport 4789 nolearning external
182	bridge -n $ns link set dev vx0 vlan_tunnel on learning off
183
184	bridge -n $ns vlan add vid 10 dev vx0
185	bridge -n $ns vlan add vid 10 dev vx0 tunnel_info id 10010
186}
187
188setup_sw1()
189{
190	local ns=$sw1
191	local local_addr=192.0.2.33
192	local remote_addr=192.0.2.34
193	local veth_addr=192.0.2.49
194	local gw_addr=192.0.2.50
195	local br_addr=192.0.2.65
196
197	setup_sw_common $ns $local_addr $remote_addr $veth_addr $gw_addr \
198		$br_addr
199}
200
201setup_sw2()
202{
203	local ns=$sw2
204	local local_addr=192.0.2.34
205	local remote_addr=192.0.2.33
206	local veth_addr=192.0.2.50
207	local gw_addr=192.0.2.49
208	local br_addr=192.0.2.66
209
210	setup_sw_common $ns $local_addr $remote_addr $veth_addr $gw_addr \
211		$br_addr
212}
213
214setup()
215{
216	set -e
217
218	setup_topo
219	setup_sw1
220	setup_sw2
221
222	sleep 5
223
224	set +e
225}
226
227cleanup()
228{
229	cleanup_ns $sw1 $sw2
230}
231
232################################################################################
233# Tests
234
235backup_port()
236{
237	local dmac=00:11:22:33:44:55
238	local smac=00:aa:bb:cc:dd:ee
239
240	echo
241	echo "Backup port"
242	echo "-----------"
243
244	run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
245	run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
246
247	run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
248	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
249
250	run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
251
252	# Initial state - check that packets are forwarded out of swp1 when it
253	# has a carrier and not forwarded out of any port when it does not have
254	# a carrier.
255	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
256	tc_check_packets $sw1 "dev swp1 egress" 101 1
257	log_test $? 0 "Forwarding out of swp1"
258	tc_check_packets $sw1 "dev vx0 egress" 101 0
259	log_test $? 0 "No forwarding out of vx0"
260
261	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
262	log_test $? 0 "swp1 carrier off"
263
264	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
265	tc_check_packets $sw1 "dev swp1 egress" 101 1
266	log_test $? 0 "No forwarding out of swp1"
267	tc_check_packets $sw1 "dev vx0 egress" 101 0
268	log_test $? 0 "No forwarding out of vx0"
269
270	run_cmd "ip -n $sw1 link set dev swp1 carrier on"
271	log_test $? 0 "swp1 carrier on"
272
273	# Configure vx0 as the backup port of swp1 and check that packets are
274	# forwarded out of swp1 when it has a carrier and out of vx0 when swp1
275	# does not have a carrier.
276	run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
277	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
278	log_test $? 0 "vx0 configured as backup port of swp1"
279
280	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
281	tc_check_packets $sw1 "dev swp1 egress" 101 2
282	log_test $? 0 "Forwarding out of swp1"
283	tc_check_packets $sw1 "dev vx0 egress" 101 0
284	log_test $? 0 "No forwarding out of vx0"
285
286	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
287	log_test $? 0 "swp1 carrier off"
288
289	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
290	tc_check_packets $sw1 "dev swp1 egress" 101 2
291	log_test $? 0 "No forwarding out of swp1"
292	tc_check_packets $sw1 "dev vx0 egress" 101 1
293	log_test $? 0 "Forwarding out of vx0"
294
295	run_cmd "ip -n $sw1 link set dev swp1 carrier on"
296	log_test $? 0 "swp1 carrier on"
297
298	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
299	tc_check_packets $sw1 "dev swp1 egress" 101 3
300	log_test $? 0 "Forwarding out of swp1"
301	tc_check_packets $sw1 "dev vx0 egress" 101 1
302	log_test $? 0 "No forwarding out of vx0"
303
304	# Remove vx0 as the backup port of swp1 and check that packets are no
305	# longer forwarded out of vx0 when swp1 does not have a carrier.
306	run_cmd "bridge -n $sw1 link set dev swp1 nobackup_port"
307	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
308	log_test $? 1 "vx0 not configured as backup port of swp1"
309
310	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
311	tc_check_packets $sw1 "dev swp1 egress" 101 4
312	log_test $? 0 "Forwarding out of swp1"
313	tc_check_packets $sw1 "dev vx0 egress" 101 1
314	log_test $? 0 "No forwarding out of vx0"
315
316	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
317	log_test $? 0 "swp1 carrier off"
318
319	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
320	tc_check_packets $sw1 "dev swp1 egress" 101 4
321	log_test $? 0 "No forwarding out of swp1"
322	tc_check_packets $sw1 "dev vx0 egress" 101 1
323	log_test $? 0 "No forwarding out of vx0"
324}
325
326backup_nhid()
327{
328	local dmac=00:11:22:33:44:55
329	local smac=00:aa:bb:cc:dd:ee
330
331	echo
332	echo "Backup nexthop ID"
333	echo "-----------------"
334
335	run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
336	run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
337
338	run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
339	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
340
341	run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
342	run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
343	run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
344
345	run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
346	run_cmd "bridge -n $sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010"
347
348	run_cmd "ip -n $sw2 address replace 192.0.2.36/32 dev lo"
349
350	# The first filter matches on packets forwarded using the backup
351	# nexthop ID and the second filter matches on packets forwarded using a
352	# regular VXLAN FDB entry.
353	run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact"
354	run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
355	run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass"
356
357	# Configure vx0 as the backup port of swp1 and check that packets are
358	# forwarded out of swp1 when it has a carrier and out of vx0 when swp1
359	# does not have a carrier. When packets are forwarded out of vx0, check
360	# that they are forwarded by the VXLAN FDB entry.
361	run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
362	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
363	log_test $? 0 "vx0 configured as backup port of swp1"
364
365	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
366	tc_check_packets $sw1 "dev swp1 egress" 101 1
367	log_test $? 0 "Forwarding out of swp1"
368	tc_check_packets $sw1 "dev vx0 egress" 101 0
369	log_test $? 0 "No forwarding out of vx0"
370
371	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
372	log_test $? 0 "swp1 carrier off"
373
374	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
375	tc_check_packets $sw1 "dev swp1 egress" 101 1
376	log_test $? 0 "No forwarding out of swp1"
377	tc_check_packets $sw1 "dev vx0 egress" 101 1
378	log_test $? 0 "Forwarding out of vx0"
379	tc_check_packets $sw2 "dev vx0 ingress" 101 0
380	log_test $? 0 "No forwarding using backup nexthop ID"
381	tc_check_packets $sw2 "dev vx0 ingress" 102 1
382	log_test $? 0 "Forwarding using VXLAN FDB entry"
383
384	run_cmd "ip -n $sw1 link set dev swp1 carrier on"
385	log_test $? 0 "swp1 carrier on"
386
387	# Configure nexthop ID 10 as the backup nexthop ID of swp1 and check
388	# that when packets are forwarded out of vx0, they are forwarded using
389	# the backup nexthop ID.
390	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
391	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
392	log_test $? 0 "nexthop ID 10 configured as backup nexthop ID of swp1"
393
394	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
395	tc_check_packets $sw1 "dev swp1 egress" 101 2
396	log_test $? 0 "Forwarding out of swp1"
397	tc_check_packets $sw1 "dev vx0 egress" 101 1
398	log_test $? 0 "No forwarding out of vx0"
399
400	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
401	log_test $? 0 "swp1 carrier off"
402
403	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
404	tc_check_packets $sw1 "dev swp1 egress" 101 2
405	log_test $? 0 "No forwarding out of swp1"
406	tc_check_packets $sw1 "dev vx0 egress" 101 2
407	log_test $? 0 "Forwarding out of vx0"
408	tc_check_packets $sw2 "dev vx0 ingress" 101 1
409	log_test $? 0 "Forwarding using backup nexthop ID"
410	tc_check_packets $sw2 "dev vx0 ingress" 102 1
411	log_test $? 0 "No forwarding using VXLAN FDB entry"
412
413	run_cmd "ip -n $sw1 link set dev swp1 carrier on"
414	log_test $? 0 "swp1 carrier on"
415
416	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
417	tc_check_packets $sw1 "dev swp1 egress" 101 3
418	log_test $? 0 "Forwarding out of swp1"
419	tc_check_packets $sw1 "dev vx0 egress" 101 2
420	log_test $? 0 "No forwarding out of vx0"
421	tc_check_packets $sw2 "dev vx0 ingress" 101 1
422	log_test $? 0 "No forwarding using backup nexthop ID"
423	tc_check_packets $sw2 "dev vx0 ingress" 102 1
424	log_test $? 0 "No forwarding using VXLAN FDB entry"
425
426	# Reset the backup nexthop ID to 0 and check that packets are no longer
427	# forwarded using the backup nexthop ID when swp1 does not have a
428	# carrier and are instead forwarded by the VXLAN FDB.
429	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0"
430	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid\""
431	log_test $? 1 "No backup nexthop ID configured for swp1"
432
433	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
434	tc_check_packets $sw1 "dev swp1 egress" 101 4
435	log_test $? 0 "Forwarding out of swp1"
436	tc_check_packets $sw1 "dev vx0 egress" 101 2
437	log_test $? 0 "No forwarding out of vx0"
438	tc_check_packets $sw2 "dev vx0 ingress" 101 1
439	log_test $? 0 "No forwarding using backup nexthop ID"
440	tc_check_packets $sw2 "dev vx0 ingress" 102 1
441	log_test $? 0 "No forwarding using VXLAN FDB entry"
442
443	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
444	log_test $? 0 "swp1 carrier off"
445
446	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
447	tc_check_packets $sw1 "dev swp1 egress" 101 4
448	log_test $? 0 "No forwarding out of swp1"
449	tc_check_packets $sw1 "dev vx0 egress" 101 3
450	log_test $? 0 "Forwarding out of vx0"
451	tc_check_packets $sw2 "dev vx0 ingress" 101 1
452	log_test $? 0 "No forwarding using backup nexthop ID"
453	tc_check_packets $sw2 "dev vx0 ingress" 102 2
454	log_test $? 0 "Forwarding using VXLAN FDB entry"
455}
456
457backup_nhid_invalid()
458{
459	local dmac=00:11:22:33:44:55
460	local smac=00:aa:bb:cc:dd:ee
461	local tx_drop
462
463	echo
464	echo "Backup nexthop ID - invalid IDs"
465	echo "-------------------------------"
466
467	# Check that when traffic is redirected with an invalid nexthop ID, it
468	# is forwarded out of the VXLAN port, but dropped by the VXLAN driver
469	# and does not crash the host.
470
471	run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
472	run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
473
474	run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
475	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
476	# Drop all other Tx traffic to avoid changes to Tx drop counter.
477	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop"
478
479	tx_drop=$(ip -n $sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]')
480
481	run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
482	run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
483	run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
484
485	run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
486
487	run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact"
488	run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
489
490	# First, check that redirection works.
491	run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
492	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
493	log_test $? 0 "vx0 configured as backup port of swp1"
494
495	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
496	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
497	log_test $? 0 "Valid nexthop as backup nexthop"
498
499	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
500	log_test $? 0 "swp1 carrier off"
501
502	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
503	tc_check_packets $sw1 "dev swp1 egress" 101 0
504	log_test $? 0 "No forwarding out of swp1"
505	tc_check_packets $sw1 "dev vx0 egress" 101 1
506	log_test $? 0 "Forwarding out of vx0"
507	tc_check_packets $sw2 "dev vx0 ingress" 101 1
508	log_test $? 0 "Forwarding using backup nexthop ID"
509	run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'"
510	log_test $? 0 "No Tx drop increase"
511
512	# Use a non-existent nexthop ID.
513	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 20"
514	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 20\""
515	log_test $? 0 "Non-existent nexthop as backup nexthop"
516
517	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
518	tc_check_packets $sw1 "dev swp1 egress" 101 0
519	log_test $? 0 "No forwarding out of swp1"
520	tc_check_packets $sw1 "dev vx0 egress" 101 2
521	log_test $? 0 "Forwarding out of vx0"
522	tc_check_packets $sw2 "dev vx0 ingress" 101 1
523	log_test $? 0 "No forwarding using backup nexthop ID"
524	run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'"
525	log_test $? 0 "Tx drop increased"
526
527	# Use a blckhole nexthop.
528	run_cmd "ip -n $sw1 nexthop replace id 30 blackhole"
529	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 30"
530	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 30\""
531	log_test $? 0 "Blackhole nexthop as backup nexthop"
532
533	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
534	tc_check_packets $sw1 "dev swp1 egress" 101 0
535	log_test $? 0 "No forwarding out of swp1"
536	tc_check_packets $sw1 "dev vx0 egress" 101 3
537	log_test $? 0 "Forwarding out of vx0"
538	tc_check_packets $sw2 "dev vx0 ingress" 101 1
539	log_test $? 0 "No forwarding using backup nexthop ID"
540	run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'"
541	log_test $? 0 "Tx drop increased"
542
543	# Non-group FDB nexthop.
544	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 1"
545	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 1\""
546	log_test $? 0 "Non-group FDB nexthop as backup nexthop"
547
548	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
549	tc_check_packets $sw1 "dev swp1 egress" 101 0
550	log_test $? 0 "No forwarding out of swp1"
551	tc_check_packets $sw1 "dev vx0 egress" 101 4
552	log_test $? 0 "Forwarding out of vx0"
553	tc_check_packets $sw2 "dev vx0 ingress" 101 1
554	log_test $? 0 "No forwarding using backup nexthop ID"
555	run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'"
556	log_test $? 0 "Tx drop increased"
557
558	# IPv6 address family nexthop.
559	run_cmd "ip -n $sw1 nexthop replace id 100 via 2001:db8:100::1 fdb"
560	run_cmd "ip -n $sw1 nexthop replace id 200 via 2001:db8:100::1 fdb"
561	run_cmd "ip -n $sw1 nexthop replace id 300 group 100/200 fdb"
562	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 300"
563	run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 300\""
564	log_test $? 0 "IPv6 address family nexthop as backup nexthop"
565
566	run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
567	tc_check_packets $sw1 "dev swp1 egress" 101 0
568	log_test $? 0 "No forwarding out of swp1"
569	tc_check_packets $sw1 "dev vx0 egress" 101 5
570	log_test $? 0 "Forwarding out of vx0"
571	tc_check_packets $sw2 "dev vx0 ingress" 101 1
572	log_test $? 0 "No forwarding using backup nexthop ID"
573	run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'"
574	log_test $? 0 "Tx drop increased"
575}
576
577backup_nhid_ping()
578{
579	local sw1_mac
580	local sw2_mac
581
582	echo
583	echo "Backup nexthop ID - ping"
584	echo "------------------------"
585
586	# Test bidirectional traffic when traffic is redirected in both VTEPs.
587	sw1_mac=$(ip -n $sw1 -j -p link show br0.10 | jq -r '.[]["address"]')
588	sw2_mac=$(ip -n $sw2 -j -p link show br0.10 | jq -r '.[]["address"]')
589
590	run_cmd "bridge -n $sw1 fdb replace $sw2_mac dev swp1 master static vlan 10"
591	run_cmd "bridge -n $sw2 fdb replace $sw1_mac dev swp1 master static vlan 10"
592
593	run_cmd "ip -n $sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10"
594	run_cmd "ip -n $sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10"
595
596	run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
597	run_cmd "ip -n $sw2 nexthop replace id 1 via 192.0.2.33 fdb"
598	run_cmd "ip -n $sw1 nexthop replace id 10 group 1 fdb"
599	run_cmd "ip -n $sw2 nexthop replace id 10 group 1 fdb"
600
601	run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
602	run_cmd "bridge -n $sw2 link set dev swp1 backup_port vx0"
603	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
604	run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10"
605
606	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
607	run_cmd "ip -n $sw2 link set dev swp1 carrier off"
608
609	run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
610	log_test $? 0 "Ping with backup nexthop ID"
611
612	# Reset the backup nexthop ID to 0 and check that ping fails.
613	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0"
614	run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 0"
615
616	run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
617	log_test $? 1 "Ping after disabling backup nexthop ID"
618}
619
620backup_nhid_add_del_loop()
621{
622	while true; do
623		ip -n $sw1 nexthop del id 10
624		ip -n $sw1 nexthop replace id 10 group 1/2 fdb
625	done >/dev/null 2>&1
626}
627
628backup_nhid_torture()
629{
630	local dmac=00:11:22:33:44:55
631	local smac=00:aa:bb:cc:dd:ee
632	local pid1
633	local pid2
634	local pid3
635
636	echo
637	echo "Backup nexthop ID - torture test"
638	echo "--------------------------------"
639
640	# Continuously send traffic through the backup nexthop while adding and
641	# deleting the group. The test is considered successful if nothing
642	# crashed.
643
644	run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
645	run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
646	run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
647
648	run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
649
650	run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
651	run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
652	run_cmd "ip -n $sw1 link set dev swp1 carrier off"
653
654	backup_nhid_add_del_loop &
655	pid1=$!
656	ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 &
657	pid2=$!
658
659	sleep 30
660	kill -9 $pid1 $pid2
661	wait $pid1 $pid2 2>/dev/null
662
663	log_test 0 0 "Torture test"
664}
665
666################################################################################
667# Usage
668
669usage()
670{
671	cat <<EOF
672usage: ${0##*/} OPTS
673
674        -t <test>   Test(s) to run (default: all)
675                    (options: $TESTS)
676        -p          Pause on fail
677        -P          Pause after each test before cleanup
678        -v          Verbose mode (show commands and output)
679        -w          Timeout for ping
680EOF
681}
682
683################################################################################
684# Main
685
686trap cleanup EXIT
687
688while getopts ":t:pPvhw:" opt; do
689	case $opt in
690		t) TESTS=$OPTARG;;
691		p) PAUSE_ON_FAIL=yes;;
692		P) PAUSE=yes;;
693		v) VERBOSE=$(($VERBOSE + 1));;
694		w) PING_TIMEOUT=$OPTARG;;
695		h) usage; exit 0;;
696		*) usage; exit 1;;
697	esac
698done
699
700# Make sure we don't pause twice.
701[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
702
703if [ "$(id -u)" -ne 0 ];then
704	echo "SKIP: Need root privileges"
705	exit $ksft_skip;
706fi
707
708if [ ! -x "$(command -v ip)" ]; then
709	echo "SKIP: Could not run test without ip tool"
710	exit $ksft_skip
711fi
712
713if [ ! -x "$(command -v bridge)" ]; then
714	echo "SKIP: Could not run test without bridge tool"
715	exit $ksft_skip
716fi
717
718if [ ! -x "$(command -v tc)" ]; then
719	echo "SKIP: Could not run test without tc tool"
720	exit $ksft_skip
721fi
722
723if [ ! -x "$(command -v mausezahn)" ]; then
724	echo "SKIP: Could not run test without mausezahn tool"
725	exit $ksft_skip
726fi
727
728if [ ! -x "$(command -v jq)" ]; then
729	echo "SKIP: Could not run test without jq tool"
730	exit $ksft_skip
731fi
732
733bridge link help 2>&1 | grep -q "backup_nhid"
734if [ $? -ne 0 ]; then
735   echo "SKIP: iproute2 bridge too old, missing backup nexthop ID support"
736   exit $ksft_skip
737fi
738
739# Start clean.
740cleanup
741
742for t in $TESTS
743do
744	setup; $t; cleanup;
745done
746
747if [ "$TESTS" != "none" ]; then
748	printf "\nTests passed: %3d\n" ${nsuccess}
749	printf "Tests failed: %3d\n"   ${nfail}
750fi
751
752exit $ret
753