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