xref: /linux/tools/testing/selftests/net/fib_tests.sh (revision 4841fb8f557d090b37900f9179d3ff668f678b16)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is for checking IPv4 and IPv6 FIB behavior in response to
5# different events.
6source lib.sh
7ret=0
8
9# all tests in this script. Can be overridden with -t option
10TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
11       ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics \
12       ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
13       ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
14       ipv4_mpath_list ipv6_mpath_list ipv4_mpath_balance ipv6_mpath_balance \
15       ipv4_mpath_balance_preferred ipv4_mpath_oif ipv4_mpath_oif_nh \
16       ipv4_mpath_oif_vrf ipv6_mpath_oif ipv6_mpath_oif_nh ipv6_mpath_oif_vrf \
17       fib6_ra_to_static fib6_temp_addr_renewal"
18
19VERBOSE=0
20PAUSE_ON_FAIL=no
21PAUSE=no
22
23which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
24
25log_test()
26{
27	log_test_expected "$1" "$2" "$3"
28}
29
30setup()
31{
32	set -e
33	setup_ns ns1
34	IP="$(which ip) -netns $ns1"
35	NS_EXEC="$(which ip) netns exec $ns1"
36	ip netns exec $ns1 sysctl -qw net.ipv4.ip_forward=1
37	ip netns exec $ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
38
39	$IP link add dummy0 type dummy
40	$IP link set dev dummy0 up
41	$IP address add 198.51.100.1/24 dev dummy0
42	$IP -6 address add 2001:db8:1::1/64 dev dummy0
43	set +e
44
45}
46
47cleanup()
48{
49	$IP link del dev dummy0 &> /dev/null
50	cleanup_ns $ns1 $ns2
51}
52
53get_linklocal()
54{
55	local dev=$1
56	local addr
57
58	addr=$($IP -6 -br addr show dev ${dev} | \
59	awk '{
60		for (i = 3; i <= NF; ++i) {
61			if ($i ~ /^fe80/)
62				print $i
63		}
64	}'
65	)
66	addr=${addr/\/*}
67
68	[ -z "$addr" ] && return 1
69
70	echo $addr
71
72	return 0
73}
74
75fib_unreg_unicast_test()
76{
77	echo
78	echo "Single path route test"
79
80	setup
81
82	echo "    Start point"
83	$IP route get fibmatch 198.51.100.2 &> /dev/null
84	log_test $? 0 "IPv4 fibmatch"
85	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
86	log_test $? 0 "IPv6 fibmatch"
87
88	set -e
89	$IP link del dev dummy0
90	set +e
91
92	echo "    Nexthop device deleted"
93	$IP route get fibmatch 198.51.100.2 &> /dev/null
94	log_test $? 2 "IPv4 fibmatch - no route"
95	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
96	log_test $? 2 "IPv6 fibmatch - no route"
97
98	cleanup
99}
100
101fib_unreg_multipath_test()
102{
103
104	echo
105	echo "Multipath route test"
106
107	setup
108
109	set -e
110	$IP link add dummy1 type dummy
111	$IP link set dev dummy1 up
112	$IP address add 192.0.2.1/24 dev dummy1
113	$IP -6 address add 2001:db8:2::1/64 dev dummy1
114
115	$IP route add 203.0.113.0/24 \
116		nexthop via 198.51.100.2 dev dummy0 \
117		nexthop via 192.0.2.2 dev dummy1
118	$IP -6 route add 2001:db8:3::/64 \
119		nexthop via 2001:db8:1::2 dev dummy0 \
120		nexthop via 2001:db8:2::2 dev dummy1
121	set +e
122
123	echo "    Start point"
124	$IP route get fibmatch 203.0.113.1 &> /dev/null
125	log_test $? 0 "IPv4 fibmatch"
126	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
127	log_test $? 0 "IPv6 fibmatch"
128
129	set -e
130	$IP link del dev dummy0
131	set +e
132
133	echo "    One nexthop device deleted"
134	$IP route get fibmatch 203.0.113.1 &> /dev/null
135	log_test $? 2 "IPv4 - multipath route removed on delete"
136
137	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
138	# In IPv6 we do not flush the entire multipath route.
139	log_test $? 0 "IPv6 - multipath down to single path"
140
141	set -e
142	$IP link del dev dummy1
143	set +e
144
145	echo "    Second nexthop device deleted"
146	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
147	log_test $? 2 "IPv6 - no route"
148
149	cleanup
150}
151
152fib_unreg_test()
153{
154	fib_unreg_unicast_test
155	fib_unreg_multipath_test
156}
157
158fib_down_unicast_test()
159{
160	echo
161	echo "Single path, admin down"
162
163	setup
164
165	echo "    Start point"
166	$IP route get fibmatch 198.51.100.2 &> /dev/null
167	log_test $? 0 "IPv4 fibmatch"
168	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
169	log_test $? 0 "IPv6 fibmatch"
170
171	set -e
172	$IP link set dev dummy0 down
173	set +e
174
175	echo "    Route deleted on down"
176	$IP route get fibmatch 198.51.100.2 &> /dev/null
177	log_test $? 2 "IPv4 fibmatch"
178	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
179	log_test $? 2 "IPv6 fibmatch"
180
181	cleanup
182}
183
184fib_down_multipath_test_do()
185{
186	local down_dev=$1
187	local up_dev=$2
188
189	$IP route get fibmatch 203.0.113.1 \
190		oif $down_dev &> /dev/null
191	log_test $? 2 "IPv4 fibmatch on down device"
192	$IP -6 route get fibmatch 2001:db8:3::1 \
193		oif $down_dev &> /dev/null
194	log_test $? 2 "IPv6 fibmatch on down device"
195
196	$IP route get fibmatch 203.0.113.1 \
197		oif $up_dev &> /dev/null
198	log_test $? 0 "IPv4 fibmatch on up device"
199	$IP -6 route get fibmatch 2001:db8:3::1 \
200		oif $up_dev &> /dev/null
201	log_test $? 0 "IPv6 fibmatch on up device"
202
203	$IP route get fibmatch 203.0.113.1 | \
204		grep $down_dev | grep -q "dead linkdown"
205	log_test $? 0 "IPv4 flags on down device"
206	$IP -6 route get fibmatch 2001:db8:3::1 | \
207		grep $down_dev | grep -q "dead linkdown"
208	log_test $? 0 "IPv6 flags on down device"
209
210	$IP route get fibmatch 203.0.113.1 | \
211		grep $up_dev | grep -q "dead linkdown"
212	log_test $? 1 "IPv4 flags on up device"
213	$IP -6 route get fibmatch 2001:db8:3::1 | \
214		grep $up_dev | grep -q "dead linkdown"
215	log_test $? 1 "IPv6 flags on up device"
216}
217
218fib_down_multipath_test()
219{
220	echo
221	echo "Admin down multipath"
222
223	setup
224
225	set -e
226	$IP link add dummy1 type dummy
227	$IP link set dev dummy1 up
228
229	$IP address add 192.0.2.1/24 dev dummy1
230	$IP -6 address add 2001:db8:2::1/64 dev dummy1
231
232	$IP route add 203.0.113.0/24 \
233		nexthop via 198.51.100.2 dev dummy0 \
234		nexthop via 192.0.2.2 dev dummy1
235	$IP -6 route add 2001:db8:3::/64 \
236		nexthop via 2001:db8:1::2 dev dummy0 \
237		nexthop via 2001:db8:2::2 dev dummy1
238	set +e
239
240	echo "    Verify start point"
241	$IP route get fibmatch 203.0.113.1 &> /dev/null
242	log_test $? 0 "IPv4 fibmatch"
243
244	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
245	log_test $? 0 "IPv6 fibmatch"
246
247	set -e
248	$IP link set dev dummy0 down
249	set +e
250
251	echo "    One device down, one up"
252	fib_down_multipath_test_do "dummy0" "dummy1"
253
254	set -e
255	$IP link set dev dummy0 up
256	$IP link set dev dummy1 down
257	set +e
258
259	echo "    Other device down and up"
260	fib_down_multipath_test_do "dummy1" "dummy0"
261
262	set -e
263	$IP link set dev dummy0 down
264	set +e
265
266	echo "    Both devices down"
267	$IP route get fibmatch 203.0.113.1 &> /dev/null
268	log_test $? 2 "IPv4 fibmatch"
269	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
270	log_test $? 2 "IPv6 fibmatch"
271
272	$IP link del dev dummy1
273	cleanup
274}
275
276fib_down_test()
277{
278	fib_down_unicast_test
279	fib_down_multipath_test
280}
281
282# Local routes should not be affected when carrier changes.
283fib_carrier_local_test()
284{
285	echo
286	echo "Local carrier tests - single path"
287
288	setup
289
290	set -e
291	$IP link set dev dummy0 carrier on
292	set +e
293
294	echo "    Start point"
295	$IP route get fibmatch 198.51.100.1 &> /dev/null
296	log_test $? 0 "IPv4 fibmatch"
297	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
298	log_test $? 0 "IPv6 fibmatch"
299
300	$IP route get fibmatch 198.51.100.1 | \
301		grep -q "linkdown"
302	log_test $? 1 "IPv4 - no linkdown flag"
303	$IP -6 route get fibmatch 2001:db8:1::1 | \
304		grep -q "linkdown"
305	log_test $? 1 "IPv6 - no linkdown flag"
306
307	set -e
308	$IP link set dev dummy0 carrier off
309	sleep 1
310	set +e
311
312	echo "    Carrier off on nexthop"
313	$IP route get fibmatch 198.51.100.1 &> /dev/null
314	log_test $? 0 "IPv4 fibmatch"
315	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
316	log_test $? 0 "IPv6 fibmatch"
317
318	$IP route get fibmatch 198.51.100.1 | \
319		grep -q "linkdown"
320	log_test $? 1 "IPv4 - linkdown flag set"
321	$IP -6 route get fibmatch 2001:db8:1::1 | \
322		grep -q "linkdown"
323	log_test $? 1 "IPv6 - linkdown flag set"
324
325	set -e
326	$IP address add 192.0.2.1/24 dev dummy0
327	$IP -6 address add 2001:db8:2::1/64 dev dummy0
328	set +e
329
330	echo "    Route to local address with carrier down"
331	$IP route get fibmatch 192.0.2.1 &> /dev/null
332	log_test $? 0 "IPv4 fibmatch"
333	$IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
334	log_test $? 0 "IPv6 fibmatch"
335
336	$IP route get fibmatch 192.0.2.1 | \
337		grep -q "linkdown"
338	log_test $? 1 "IPv4 linkdown flag set"
339	$IP -6 route get fibmatch 2001:db8:2::1 | \
340		grep -q "linkdown"
341	log_test $? 1 "IPv6 linkdown flag set"
342
343	cleanup
344}
345
346fib_carrier_unicast_test()
347{
348	echo
349	echo "Single path route carrier test"
350
351	setup
352
353	set -e
354	$IP link set dev dummy0 carrier on
355	set +e
356
357	echo "    Start point"
358	$IP route get fibmatch 198.51.100.2 &> /dev/null
359	log_test $? 0 "IPv4 fibmatch"
360	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
361	log_test $? 0 "IPv6 fibmatch"
362
363	$IP route get fibmatch 198.51.100.2 | \
364		grep -q "linkdown"
365	log_test $? 1 "IPv4 no linkdown flag"
366	$IP -6 route get fibmatch 2001:db8:1::2 | \
367		grep -q "linkdown"
368	log_test $? 1 "IPv6 no linkdown flag"
369
370	set -e
371	$IP link set dev dummy0 carrier off
372	sleep 1
373	set +e
374
375	echo "    Carrier down"
376	$IP route get fibmatch 198.51.100.2 &> /dev/null
377	log_test $? 0 "IPv4 fibmatch"
378	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
379	log_test $? 0 "IPv6 fibmatch"
380
381	$IP route get fibmatch 198.51.100.2 | \
382		grep -q "linkdown"
383	log_test $? 0 "IPv4 linkdown flag set"
384	$IP -6 route get fibmatch 2001:db8:1::2 | \
385		grep -q "linkdown"
386	log_test $? 0 "IPv6 linkdown flag set"
387
388	set -e
389	$IP address add 192.0.2.1/24 dev dummy0
390	$IP -6 address add 2001:db8:2::1/64 dev dummy0
391	set +e
392
393	echo "    Second address added with carrier down"
394	$IP route get fibmatch 192.0.2.2 &> /dev/null
395	log_test $? 0 "IPv4 fibmatch"
396	$IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
397	log_test $? 0 "IPv6 fibmatch"
398
399	$IP route get fibmatch 192.0.2.2 | \
400		grep -q "linkdown"
401	log_test $? 0 "IPv4 linkdown flag set"
402	$IP -6 route get fibmatch 2001:db8:2::2 | \
403		grep -q "linkdown"
404	log_test $? 0 "IPv6 linkdown flag set"
405
406	cleanup
407}
408
409fib_carrier_test()
410{
411	fib_carrier_local_test
412	fib_carrier_unicast_test
413}
414
415fib_rp_filter_test()
416{
417	echo
418	echo "IPv4 rp_filter tests"
419
420	setup
421
422	set -e
423	setup_ns ns2
424
425	$IP link add name veth1 type veth peer name veth2
426	$IP link set dev veth2 netns $ns2
427	$IP address add 192.0.2.1/24 dev veth1
428	ip -netns $ns2 address add 192.0.2.1/24 dev veth2
429	$IP link set dev veth1 up
430	ip -netns $ns2 link set dev veth2 up
431
432	$IP link set dev lo address 52:54:00:6a:c7:5e
433	$IP link set dev veth1 address 52:54:00:6a:c7:5e
434	ip -netns $ns2 link set dev lo address 52:54:00:6a:c7:5e
435	ip -netns $ns2 link set dev veth2 address 52:54:00:6a:c7:5e
436
437	# 1. (ns2) redirect lo's egress to veth2's egress
438	ip netns exec $ns2 tc qdisc add dev lo parent root handle 1: fq_codel
439	ip netns exec $ns2 tc filter add dev lo parent 1: protocol arp basic \
440		action mirred egress redirect dev veth2
441	ip netns exec $ns2 tc filter add dev lo parent 1: protocol ip basic \
442		action mirred egress redirect dev veth2
443
444	# 2. (ns1) redirect veth1's ingress to lo's ingress
445	$NS_EXEC tc qdisc add dev veth1 ingress
446	$NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
447		action mirred ingress redirect dev lo
448	$NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
449		action mirred ingress redirect dev lo
450
451	# 3. (ns1) redirect lo's egress to veth1's egress
452	$NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
453	$NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
454		action mirred egress redirect dev veth1
455	$NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
456		action mirred egress redirect dev veth1
457
458	# 4. (ns2) redirect veth2's ingress to lo's ingress
459	ip netns exec $ns2 tc qdisc add dev veth2 ingress
460	ip netns exec $ns2 tc filter add dev veth2 ingress protocol arp basic \
461		action mirred ingress redirect dev lo
462	ip netns exec $ns2 tc filter add dev veth2 ingress protocol ip basic \
463		action mirred ingress redirect dev lo
464
465	$NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
466	$NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
467	$NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
468	ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
469	ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
470	ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
471	set +e
472
473	run_cmd "ip netns exec $ns2 ping -w1 -c1 192.0.2.1"
474	log_test $? 0 "rp_filter passes local packets"
475
476	run_cmd "ip netns exec $ns2 ping -w1 -c1 127.0.0.1"
477	log_test $? 0 "rp_filter passes loopback packets"
478
479	cleanup
480}
481
482################################################################################
483# Tests on nexthop spec
484
485# run 'ip route add' with given spec
486add_rt()
487{
488	local desc="$1"
489	local erc=$2
490	local vrf=$3
491	local pfx=$4
492	local gw=$5
493	local dev=$6
494	local cmd out rc
495
496	[ "$vrf" = "-" ] && vrf="default"
497	[ -n "$gw" ] && gw="via $gw"
498	[ -n "$dev" ] && dev="dev $dev"
499
500	cmd="$IP route add vrf $vrf $pfx $gw $dev"
501	if [ "$VERBOSE" = "1" ]; then
502		printf "\n    COMMAND: $cmd\n"
503	fi
504
505	out=$(eval $cmd 2>&1)
506	rc=$?
507	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
508		echo "    $out"
509	fi
510	log_test $rc $erc "$desc"
511}
512
513fib4_nexthop()
514{
515	echo
516	echo "IPv4 nexthop tests"
517
518	echo "<<< write me >>>"
519}
520
521fib6_nexthop()
522{
523	local lldummy=$(get_linklocal dummy0)
524	local llv1=$(get_linklocal veth1)
525
526	if [ -z "$lldummy" ]; then
527		echo "Failed to get linklocal address for dummy0"
528		return 1
529	fi
530	if [ -z "$llv1" ]; then
531		echo "Failed to get linklocal address for veth1"
532		return 1
533	fi
534
535	echo
536	echo "IPv6 nexthop tests"
537
538	add_rt "Directly connected nexthop, unicast address" 0 \
539		- 2001:db8:101::/64 2001:db8:1::2
540	add_rt "Directly connected nexthop, unicast address with device" 0 \
541		- 2001:db8:102::/64 2001:db8:1::2 "dummy0"
542	add_rt "Gateway is linklocal address" 0 \
543		- 2001:db8:103::1/64 $llv1 "veth0"
544
545	# fails because LL address requires a device
546	add_rt "Gateway is linklocal address, no device" 2 \
547		- 2001:db8:104::1/64 $llv1
548
549	# local address can not be a gateway
550	add_rt "Gateway can not be local unicast address" 2 \
551		- 2001:db8:105::/64 2001:db8:1::1
552	add_rt "Gateway can not be local unicast address, with device" 2 \
553		- 2001:db8:106::/64 2001:db8:1::1 "dummy0"
554	add_rt "Gateway can not be a local linklocal address" 2 \
555		- 2001:db8:107::1/64 $lldummy "dummy0"
556
557	# VRF tests
558	add_rt "Gateway can be local address in a VRF" 0 \
559		- 2001:db8:108::/64 2001:db8:51::2
560	add_rt "Gateway can be local address in a VRF, with device" 0 \
561		- 2001:db8:109::/64 2001:db8:51::2 "veth0"
562	add_rt "Gateway can be local linklocal address in a VRF" 0 \
563		- 2001:db8:110::1/64 $llv1 "veth0"
564
565	add_rt "Redirect to VRF lookup" 0 \
566		- 2001:db8:111::/64 "" "red"
567
568	add_rt "VRF route, gateway can be local address in default VRF" 0 \
569		red 2001:db8:112::/64 2001:db8:51::1
570
571	# local address in same VRF fails
572	add_rt "VRF route, gateway can not be a local address" 2 \
573		red 2001:db8:113::1/64 2001:db8:2::1
574	add_rt "VRF route, gateway can not be a local addr with device" 2 \
575		red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
576}
577
578# Default VRF:
579#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
580#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
581#
582# VRF red:
583#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
584#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
585#
586#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
587
588fib_nexthop_test()
589{
590	setup
591
592	set -e
593
594	$IP -4 rule add pref 32765 table local
595	$IP -4 rule del pref 0
596	$IP -6 rule add pref 32765 table local
597	$IP -6 rule del pref 0
598
599	$IP link add red type vrf table 1
600	$IP link set red up
601	$IP -4 route add vrf red unreachable default metric 4278198272
602	$IP -6 route add vrf red unreachable default metric 4278198272
603
604	$IP link add veth0 type veth peer name veth1
605	$IP link set dev veth0 up
606	$IP address add 192.0.2.1/24 dev veth0
607	$IP -6 address add 2001:db8:51::1/64 dev veth0
608
609	$IP link set dev veth1 vrf red up
610	$IP address add 192.0.2.2/24 dev veth1
611	$IP -6 address add 2001:db8:51::2/64 dev veth1
612
613	$IP link add dummy1 type dummy
614	$IP link set dev dummy1 vrf red up
615	$IP address add 192.168.2.1/24 dev dummy1
616	$IP -6 address add 2001:db8:2::1/64 dev dummy1
617	set +e
618
619	sleep 1
620	fib4_nexthop
621	fib6_nexthop
622
623	(
624	$IP link del dev dummy1
625	$IP link del veth0
626	$IP link del red
627	) 2>/dev/null
628	cleanup
629}
630
631fib6_notify_test()
632{
633	setup
634
635	echo
636	echo "Fib6 info length calculation in route notify test"
637	set -e
638
639	for i in 10 20 30 40 50 60 70;
640	do
641		$IP link add dummy_$i type dummy
642		$IP link set dev dummy_$i up
643		$IP -6 address add 2001:$i::1/64 dev dummy_$i
644	done
645
646	$NS_EXEC ip monitor route &> errors.txt &
647	sleep 2
648
649	$IP -6 route add 2001::/64 \
650                nexthop via 2001:10::2 dev dummy_10 \
651                nexthop encap ip6 dst 2002::20 via 2001:20::2 dev dummy_20 \
652                nexthop encap ip6 dst 2002::30 via 2001:30::2 dev dummy_30 \
653                nexthop encap ip6 dst 2002::40 via 2001:40::2 dev dummy_40 \
654                nexthop encap ip6 dst 2002::50 via 2001:50::2 dev dummy_50 \
655                nexthop encap ip6 dst 2002::60 via 2001:60::2 dev dummy_60 \
656                nexthop encap ip6 dst 2002::70 via 2001:70::2 dev dummy_70
657
658	set +e
659
660	err=`cat errors.txt |grep "Message too long"`
661	if [ -z "$err" ];then
662		RET=0
663	else
664		RET=1
665	fi
666
667	log_test "$RET" 0 "ipv6 route add notify"
668
669	kill_process %%
670
671	#rm errors.txt
672
673	cleanup &> /dev/null
674}
675
676
677fib_notify_test()
678{
679	setup
680
681	echo
682	echo "Fib4 info length calculation in route notify test"
683
684	set -e
685
686	for i in 10 20 30 40 50 60 70;
687	do
688		$IP link add dummy_$i type dummy
689		$IP link set dev dummy_$i up
690		$IP address add 20.20.$i.2/24 dev dummy_$i
691	done
692
693	$NS_EXEC ip monitor route &> errors.txt &
694	sleep 2
695
696        $IP route add 10.0.0.0/24 \
697                nexthop via 20.20.10.1 dev dummy_10 \
698                nexthop encap ip dst 192.168.10.20 via 20.20.20.1 dev dummy_20 \
699                nexthop encap ip dst 192.168.10.30 via 20.20.30.1 dev dummy_30 \
700                nexthop encap ip dst 192.168.10.40 via 20.20.40.1 dev dummy_40 \
701                nexthop encap ip dst 192.168.10.50 via 20.20.50.1 dev dummy_50 \
702                nexthop encap ip dst 192.168.10.60 via 20.20.60.1 dev dummy_60 \
703                nexthop encap ip dst 192.168.10.70 via 20.20.70.1 dev dummy_70
704
705	set +e
706
707	err=`cat errors.txt |grep "Message too long"`
708	if [ -z "$err" ];then
709		RET=0
710	else
711		RET=1
712	fi
713
714	log_test "$RET" 0 "ipv4 route add notify"
715
716	kill_process %%
717
718	rm  errors.txt
719
720	cleanup &> /dev/null
721}
722
723# Create a new dummy_10 to remove all associated routes.
724reset_dummy_10()
725{
726	$IP link del dev dummy_10
727
728	$IP link add dummy_10 type dummy
729	$IP link set dev dummy_10 up
730	$IP -6 address add 2001:10::1/64 dev dummy_10
731}
732
733check_rt_num()
734{
735    local expected=$1
736    local num=$2
737
738    if [ $num -ne $expected ]; then
739	echo "FAIL: Expected $expected routes, got $num"
740	RET=1
741    else
742	RET=0
743    fi
744}
745
746check_rt_num_clean()
747{
748    local expected=$1
749    local num=$2
750
751    if [ $num -ne $expected ]; then
752	log_test 1 0 "expected $expected routes, got $num"
753	set +e
754	cleanup &> /dev/null
755	return 1
756    fi
757    return 0
758}
759
760fib6_gc_test()
761{
762	setup
763
764	echo
765	echo "Fib6 garbage collection test"
766	set -e
767
768	EXPIRE=5
769	GC_WAIT_TIME=$((EXPIRE * 2 + 2))
770
771	# Check expiration of routes every $EXPIRE seconds (GC)
772	$NS_EXEC sysctl -wq net.ipv6.route.gc_interval=$EXPIRE
773
774	$IP link add dummy_10 type dummy
775	$IP link set dev dummy_10 up
776	$IP -6 address add 2001:10::1/64 dev dummy_10
777
778	$NS_EXEC sysctl -wq net.ipv6.route.flush=1
779
780	# Temporary routes
781	for i in $(seq 1 5); do
782	    # Expire route after $EXPIRE seconds
783	    $IP -6 route add 2001:20::$i \
784		via 2001:10::2 dev dummy_10 expires $EXPIRE
785	done
786	sleep $GC_WAIT_TIME
787	$NS_EXEC sysctl -wq net.ipv6.route.flush=1
788	check_rt_num 0 $($IP -6 route list |grep expires|wc -l)
789	log_test "$RET" 0 "ipv6 route garbage collection"
790
791	reset_dummy_10
792
793	# Permanent routes
794	for i in $(seq 1 5); do
795	    $IP -6 route add 2001:30::$i \
796		via 2001:10::2 dev dummy_10
797	done
798	# Temporary routes
799	for i in $(seq 1 5); do
800	    # Expire route after $EXPIRE seconds
801	    $IP -6 route add 2001:20::$i \
802		via 2001:10::2 dev dummy_10 expires $EXPIRE
803	done
804	# Wait for GC
805	sleep $GC_WAIT_TIME
806	check_rt_num 0 $($IP -6 route list |grep expires|wc -l)
807	log_test "$RET" 0 "ipv6 route garbage collection (with permanent routes)"
808
809	reset_dummy_10
810
811	# Permanent routes
812	for i in $(seq 1 5); do
813	    $IP -6 route add 2001:20::$i \
814		via 2001:10::2 dev dummy_10
815	done
816	# Replace with temporary routes
817	for i in $(seq 1 5); do
818	    # Expire route after $EXPIRE seconds
819	    $IP -6 route replace 2001:20::$i \
820		via 2001:10::2 dev dummy_10 expires $EXPIRE
821	done
822	# Wait for GC
823	sleep $GC_WAIT_TIME
824	check_rt_num 0 $($IP -6 route list |grep expires|wc -l)
825	log_test "$RET" 0 "ipv6 route garbage collection (replace with expires)"
826
827	reset_dummy_10
828
829	# Temporary routes
830	for i in $(seq 1 5); do
831	    # Expire route after $EXPIRE seconds
832	    $IP -6 route add 2001:20::$i \
833		via 2001:10::2 dev dummy_10 expires $EXPIRE
834	done
835	# Replace with permanent routes
836	for i in $(seq 1 5); do
837	    $IP -6 route replace 2001:20::$i \
838		via 2001:10::2 dev dummy_10
839	done
840	check_rt_num_clean 0 $($IP -6 route list |grep expires|wc -l) || return
841
842	# Wait for GC
843	sleep $GC_WAIT_TIME
844	check_rt_num 5 $($IP -6 route list |grep -v expires|grep 2001:20::|wc -l)
845	log_test "$RET" 0 "ipv6 route garbage collection (replace with permanent)"
846
847	# Delete dummy_10 and remove all routes
848	$IP link del dev dummy_10
849
850	# rd6 is required for the next test. (ipv6toolkit)
851	if [ ! -x "$(command -v rd6)" ]; then
852	    echo "SKIP: rd6 not found."
853	    set +e
854	    cleanup &> /dev/null
855	    return
856	fi
857
858	setup_ns ns2
859	$IP link add veth1 type veth peer veth2 netns $ns2
860	$IP link set veth1 up
861	ip -netns $ns2 link set veth2 up
862	$IP addr add fe80:dead::1/64 dev veth1
863	ip -netns $ns2 addr add fe80:dead::2/64 dev veth2
864
865	# Add NTF_ROUTER neighbour to prevent rt6_age_examine_exception()
866	# from removing not-yet-expired exceptions.
867	ip -netns $ns2 link set veth2 address 00:11:22:33:44:55
868	$IP neigh add fe80:dead::3 lladdr 00:11:22:33:44:55 dev veth1 router
869
870	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_redirects=1
871	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.forwarding=0
872
873	# Temporary routes
874	for i in $(seq 1 5); do
875	    # Expire route after $EXPIRE seconds
876	    $IP -6 route add 2001:10::$i \
877		via fe80:dead::2 dev veth1 expires $EXPIRE
878
879	    ip netns exec $ns2 rd6 -i veth2 \
880		-s fe80:dead::2 -d fe80:dead::1 \
881		-r 2001:10::$i -t fe80:dead::3 -p ICMP6
882	done
883
884	check_rt_num 5 $($IP -6 route list | grep expires | grep 2001:10:: | wc -l)
885
886	# Promote to permanent routes by "prepend" (w/o NLM_F_EXCL and NLM_F_REPLACE)
887	for i in $(seq 1 5); do
888	    # -EEXIST, but the temporary route becomes the permanent route.
889	    $IP -6 route append 2001:10::$i \
890		via fe80:dead::2 dev veth1 2>/dev/null || true
891	done
892
893	check_rt_num 5 $($IP -6 route list | grep -v expires | grep 2001:10:: | wc -l)
894	check_rt_num 5 $($IP -6 route list cache | grep 2001:10:: | wc -l)
895
896	# Trigger GC instead of waiting $GC_WAIT_TIME.
897	# rt6_nh_dump_exceptions() just skips expired exceptions.
898	$NS_EXEC sysctl -wq net.ipv6.route.flush=1
899	check_rt_num 0 $($IP -6 route list cache | grep 2001:10:: | wc -l)
900	log_test "$RET" 0 "ipv6 route garbage collection (promote to permanent routes)"
901
902	$IP neigh del fe80:dead::3 lladdr 00:11:22:33:44:55 dev veth1 router
903	$IP link del veth1
904
905	# ra6 is required for the next test. (ipv6toolkit)
906	if [ ! -x "$(command -v ra6)" ]; then
907	    echo "SKIP: ra6 not found."
908	    set +e
909	    cleanup &> /dev/null
910	    return
911	fi
912
913	# Create a pair of veth devices to send a RA message from one
914	# device to another.
915	$IP link add veth1 type veth peer name veth2
916	$IP link set dev veth1 up
917	$IP link set dev veth2 up
918	$IP -6 address add 2001:10::1/64 dev veth1 nodad
919	$IP -6 address add 2001:10::2/64 dev veth2 nodad
920
921	# Make veth1 ready to receive RA messages.
922	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
923
924	# Send a RA message with a route from veth2 to veth1.
925	$NS_EXEC ra6 -i veth2 -d 2001:10::1 -t $EXPIRE
926
927	# Wait for the RA message.
928	sleep 1
929
930	# systemd may mess up the test.  You syould make sure that
931	# systemd-networkd.service and systemd-networkd.socket are stopped.
932	check_rt_num_clean 1 $($IP -6 route list|grep expires|wc -l) || return
933
934	# Wait for GC
935	sleep $GC_WAIT_TIME
936	check_rt_num 0 $($IP -6 route list |grep expires|wc -l)
937	log_test "$RET" 0 "ipv6 route garbage collection (RA message)"
938
939	set +e
940
941	cleanup &> /dev/null
942}
943
944fib_suppress_test()
945{
946	echo
947	echo "FIB rule with suppress_prefixlength"
948	setup
949
950	$IP link add dummy1 type dummy
951	$IP link set dummy1 up
952	$IP -6 route add default dev dummy1
953	$IP -6 rule add table main suppress_prefixlength 0
954	ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
955	$IP -6 rule del table main suppress_prefixlength 0
956	$IP link del dummy1
957
958	# If we got here without crashing, we're good.
959	log_test 0 0 "FIB rule suppress test"
960
961	cleanup
962}
963
964################################################################################
965# Tests on route add and replace
966
967run_cmd()
968{
969	local cmd="$1"
970	local out
971	local stderr="2>/dev/null"
972
973	if [ "$VERBOSE" = "1" ]; then
974		printf "    COMMAND: $cmd\n"
975		stderr=
976	fi
977
978	out=$(eval $cmd $stderr)
979	rc=$?
980	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
981		echo "    $out"
982	fi
983
984	[ "$VERBOSE" = "1" ] && echo
985
986	return $rc
987}
988
989check_expected()
990{
991	local out="$1"
992	local expected="$2"
993	local rc=0
994
995	[ "${out}" = "${expected}" ] && return 0
996
997	if [ -z "${out}" ]; then
998		if [ "$VERBOSE" = "1" ]; then
999			printf "\nNo route entry found\n"
1000			printf "Expected:\n"
1001			printf "    ${expected}\n"
1002		fi
1003		return 1
1004	fi
1005
1006	# tricky way to convert output to 1-line without ip's
1007	# messy '\'; this drops all extra white space
1008	out=$(echo ${out})
1009	if [ "${out}" != "${expected}" ]; then
1010		rc=1
1011		if [ "${VERBOSE}" = "1" ]; then
1012			printf "    Unexpected route entry. Have:\n"
1013			printf "        ${out}\n"
1014			printf "    Expected:\n"
1015			printf "        ${expected}\n\n"
1016		fi
1017	fi
1018
1019	return $rc
1020}
1021
1022# add route for a prefix, flushing any existing routes first
1023# expected to be the first step of a test
1024add_route6()
1025{
1026	local pfx="$1"
1027	local nh="$2"
1028	local out
1029
1030	if [ "$VERBOSE" = "1" ]; then
1031		echo
1032		echo "    ##################################################"
1033		echo
1034	fi
1035
1036	run_cmd "$IP -6 ro flush ${pfx}"
1037	[ $? -ne 0 ] && exit 1
1038
1039	out=$($IP -6 ro ls match ${pfx})
1040	if [ -n "$out" ]; then
1041		echo "Failed to flush routes for prefix used for tests."
1042		exit 1
1043	fi
1044
1045	run_cmd "$IP -6 ro add ${pfx} ${nh}"
1046	if [ $? -ne 0 ]; then
1047		echo "Failed to add initial route for test."
1048		exit 1
1049	fi
1050}
1051
1052# add initial route - used in replace route tests
1053add_initial_route6()
1054{
1055	add_route6 "2001:db8:104::/64" "$1"
1056}
1057
1058check_route6()
1059{
1060	local pfx
1061	local expected="$1"
1062	local out
1063	local rc=0
1064
1065	set -- $expected
1066	pfx=$1
1067
1068	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
1069	check_expected "${out}" "${expected}"
1070}
1071
1072route_cleanup()
1073{
1074	$IP li del red 2>/dev/null
1075	$IP li del dummy1 2>/dev/null
1076	$IP li del veth1 2>/dev/null
1077	$IP li del veth3 2>/dev/null
1078
1079	cleanup &> /dev/null
1080}
1081
1082route_setup()
1083{
1084	route_cleanup
1085	setup
1086
1087	[ "${VERBOSE}" = "1" ] && set -x
1088	set -e
1089
1090	setup_ns ns2
1091	ip netns exec $ns2 sysctl -qw net.ipv4.ip_forward=1
1092	ip netns exec $ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
1093
1094	$IP li add veth1 type veth peer name veth2
1095	$IP li add veth3 type veth peer name veth4
1096
1097	$IP li set veth1 up
1098	$IP li set veth3 up
1099	$IP li set veth2 netns $ns2 up
1100	$IP li set veth4 netns $ns2 up
1101	ip -netns $ns2 li add dummy1 type dummy
1102	ip -netns $ns2 li set dummy1 up
1103
1104	$IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
1105	$IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
1106	$IP addr add 172.16.101.1/24 dev veth1
1107	$IP addr add 172.16.103.1/24 dev veth3
1108
1109	ip -netns $ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
1110	ip -netns $ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
1111	ip -netns $ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
1112
1113	ip -netns $ns2 addr add 172.16.101.2/24 dev veth2
1114	ip -netns $ns2 addr add 172.16.103.2/24 dev veth4
1115	ip -netns $ns2 addr add 172.16.104.1/24 dev dummy1
1116
1117	set +e
1118}
1119
1120forwarding_cleanup()
1121{
1122	cleanup_ns $ns3
1123
1124	route_cleanup
1125}
1126
1127# extend route_setup with an ns3 reachable through ns2 over both devices
1128forwarding_setup()
1129{
1130	forwarding_cleanup
1131
1132	route_setup
1133
1134	setup_ns ns3
1135
1136	ip link add veth5 netns $ns3 type veth peer name veth6 netns $ns2
1137	ip -netns $ns3 link set veth5 up
1138	ip -netns $ns2 link set veth6 up
1139
1140	ip -netns $ns3 -4 addr add dev veth5 172.16.105.1/24
1141	ip -netns $ns2 -4 addr add dev veth6 172.16.105.2/24
1142	ip -netns $ns3 -4 route add 172.16.100.0/22 via 172.16.105.2
1143
1144	ip -netns $ns3 -6 addr add dev veth5 2001:db8:105::1/64 nodad
1145	ip -netns $ns2 -6 addr add dev veth6 2001:db8:105::2/64 nodad
1146	ip -netns $ns3 -6 route add 2001:db8:101::/33 via 2001:db8:105::2
1147}
1148
1149# assumption is that basic add of a single path route works
1150# otherwise just adding an address on an interface is broken
1151ipv6_rt_add()
1152{
1153	local rc
1154
1155	echo
1156	echo "IPv6 route add / append tests"
1157
1158	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1159	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1160	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
1161	log_test $? 2 "Attempt to add duplicate route - gw"
1162
1163	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1164	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1165	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
1166	log_test $? 2 "Attempt to add duplicate route - dev only"
1167
1168	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1169	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1170	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
1171	log_test $? 2 "Attempt to add duplicate route - reject route"
1172
1173	# route append with same prefix adds a new route
1174	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1175	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1176	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
1177	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1178	log_test $? 0 "Append nexthop to existing route - gw"
1179
1180	# insert mpath directly
1181	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1182	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1183	log_test $? 0 "Add multipath route"
1184
1185	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1186	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1187	log_test $? 2 "Attempt to add duplicate multipath route"
1188
1189	# insert of a second route without append but different metric
1190	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1191	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
1192	rc=$?
1193	if [ $rc -eq 0 ]; then
1194		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
1195		rc=$?
1196	fi
1197	log_test $rc 0 "Route add with different metrics"
1198
1199	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
1200	rc=$?
1201	if [ $rc -eq 0 ]; then
1202		check_route6 "2001:db8:104::/64 via 2001:db8:103::3 dev veth3 metric 256 2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
1203		rc=$?
1204	fi
1205	log_test $rc 0 "Route delete with metric"
1206}
1207
1208ipv6_rt_replace_single()
1209{
1210	# single path with single path
1211	#
1212	add_initial_route6 "via 2001:db8:101::2"
1213	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
1214	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
1215	log_test $? 0 "Single path with single path"
1216
1217	# single path with multipath
1218	#
1219	add_initial_route6 "nexthop via 2001:db8:101::2"
1220	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
1221	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1222	log_test $? 0 "Single path with multipath"
1223
1224	# single path with single path using MULTIPATH attribute
1225	#
1226	add_initial_route6 "via 2001:db8:101::2"
1227	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
1228	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
1229	log_test $? 0 "Single path with single path via multipath attribute"
1230
1231	# route replace fails - invalid nexthop
1232	add_initial_route6 "via 2001:db8:101::2"
1233	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
1234	if [ $? -eq 0 ]; then
1235		# previous command is expected to fail so if it returns 0
1236		# that means the test failed.
1237		log_test 0 1 "Invalid nexthop"
1238	else
1239		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
1240		log_test $? 0 "Invalid nexthop"
1241	fi
1242
1243	# replace non-existent route
1244	# - note use of change versus replace since ip adds NLM_F_CREATE
1245	#   for replace
1246	add_initial_route6 "via 2001:db8:101::2"
1247	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
1248	log_test $? 2 "Single path - replace of non-existent route"
1249}
1250
1251ipv6_rt_replace_mpath()
1252{
1253	# multipath with multipath
1254	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1255	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
1256	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::3 dev veth3 weight 1"
1257	log_test $? 0 "Multipath with multipath"
1258
1259	# multipath with single
1260	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1261	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
1262	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
1263	log_test $? 0 "Multipath with single path"
1264
1265	# multipath with single
1266	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1267	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
1268	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
1269	log_test $? 0 "Multipath with single path via multipath attribute"
1270
1271	# multipath with dev-only
1272	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1273	run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
1274	check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
1275	log_test $? 0 "Multipath with dev-only"
1276
1277	# route replace fails - invalid nexthop 1
1278	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1279	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
1280	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1281	log_test $? 0 "Multipath - invalid first nexthop"
1282
1283	# route replace fails - invalid nexthop 2
1284	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1285	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
1286	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1287	log_test $? 0 "Multipath - invalid second nexthop"
1288
1289	# multipath non-existent route
1290	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1291	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
1292	log_test $? 2 "Multipath - replace of non-existent route"
1293}
1294
1295ipv6_rt_replace()
1296{
1297	echo
1298	echo "IPv6 route replace tests"
1299
1300	ipv6_rt_replace_single
1301	ipv6_rt_replace_mpath
1302}
1303
1304ipv6_rt_dsfield()
1305{
1306	echo
1307	echo "IPv6 route with dsfield tests"
1308
1309	run_cmd "$IP -6 route flush 2001:db8:102::/64"
1310
1311	# IPv6 doesn't support routing based on dsfield
1312	run_cmd "$IP -6 route add 2001:db8:102::/64 dsfield 0x04 via 2001:db8:101::2"
1313	log_test $? 2 "Reject route with dsfield"
1314}
1315
1316ipv6_route_test()
1317{
1318	route_setup
1319
1320	ipv6_rt_add
1321	ipv6_rt_replace
1322	ipv6_rt_dsfield
1323
1324	route_cleanup
1325}
1326
1327ip_addr_metric_check()
1328{
1329	ip addr help 2>&1 | grep -q metric
1330	if [ $? -ne 0 ]; then
1331		echo "iproute2 command does not support metric for addresses. Skipping test"
1332		return 1
1333	fi
1334
1335	return 0
1336}
1337
1338ipv6_addr_metric_test()
1339{
1340	local rc
1341
1342	echo
1343	echo "IPv6 prefix route tests"
1344
1345	ip_addr_metric_check || return 1
1346
1347	setup
1348
1349	set -e
1350	$IP li add dummy1 type dummy
1351	$IP li add dummy2 type dummy
1352	$IP li set dummy1 up
1353	$IP li set dummy2 up
1354
1355	# default entry is metric 256
1356	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1357	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1358	set +e
1359
1360	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1361	log_test $? 0 "Default metric"
1362
1363	set -e
1364	run_cmd "$IP -6 addr flush dev dummy1"
1365	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1366	set +e
1367
1368	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1369	log_test $? 0 "User specified metric on first device"
1370
1371	set -e
1372	run_cmd "$IP -6 addr flush dev dummy2"
1373	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1374	set +e
1375
1376	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1377	log_test $? 0 "User specified metric on second device"
1378
1379	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1380	rc=$?
1381	if [ $rc -eq 0 ]; then
1382		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1383		rc=$?
1384	fi
1385	log_test $rc 0 "Delete of address on first device"
1386
1387	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1388	rc=$?
1389	if [ $rc -eq 0 ]; then
1390		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1391		rc=$?
1392	fi
1393	log_test $rc 0 "Modify metric of address"
1394
1395	# verify prefix route removed on down
1396	run_cmd "ip netns exec $ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1397	run_cmd "$IP li set dev dummy2 down"
1398	rc=$?
1399	if [ $rc -eq 0 ]; then
1400		out=$($IP -6 ro ls match 2001:db8:104::/64)
1401		check_expected "${out}" ""
1402		rc=$?
1403	fi
1404	log_test $rc 0 "Prefix route removed on link down"
1405
1406	# verify prefix route re-inserted with assigned metric
1407	run_cmd "$IP li set dev dummy2 up"
1408	rc=$?
1409	if [ $rc -eq 0 ]; then
1410		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1411		rc=$?
1412	fi
1413	log_test $rc 0 "Prefix route with metric on link up"
1414
1415	# verify peer metric added correctly
1416	set -e
1417	run_cmd "$IP -6 addr flush dev dummy2"
1418	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1419	set +e
1420
1421	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1422	log_test $? 0 "Set metric with peer route on local side"
1423	check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1424	log_test $? 0 "Set metric with peer route on peer side"
1425
1426	set -e
1427	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1428	set +e
1429
1430	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1431	log_test $? 0 "Modify metric and peer address on local side"
1432	check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1433	log_test $? 0 "Modify metric and peer address on peer side"
1434
1435	$IP li del dummy1
1436	$IP li del dummy2
1437	cleanup
1438}
1439
1440ipv6_route_metrics_test()
1441{
1442	local rc
1443
1444	echo
1445	echo "IPv6 routes with metrics"
1446
1447	route_setup
1448
1449	#
1450	# single path with metrics
1451	#
1452	run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1453	rc=$?
1454	if [ $rc -eq 0 ]; then
1455		check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1456		rc=$?
1457	fi
1458	log_test $rc 0 "Single path route with mtu metric"
1459
1460
1461	#
1462	# multipath via separate routes with metrics
1463	#
1464	run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1465	run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1466	rc=$?
1467	if [ $rc -eq 0 ]; then
1468		check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1469		rc=$?
1470	fi
1471	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1472
1473	# second route is coalesced to first to make a multipath route.
1474	# MTU of the second path is hidden from display!
1475	run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1476	run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1477	rc=$?
1478	if [ $rc -eq 0 ]; then
1479		check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1480		rc=$?
1481	fi
1482	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1483
1484	run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1485	if [ $? -eq 0 ]; then
1486		check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1487		log_test $? 0 "    MTU of second leg"
1488	fi
1489
1490	#
1491	# multipath with metrics
1492	#
1493	run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1494	rc=$?
1495	if [ $rc -eq 0 ]; then
1496		check_route6  "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1497		rc=$?
1498	fi
1499	log_test $rc 0 "Multipath route with mtu metric"
1500
1501	$IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1502	run_cmd "ip netns exec $ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1503	log_test $? 0 "Using route with mtu metric"
1504
1505	run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1506	log_test $? 2 "Invalid metric (fails metric_convert)"
1507
1508	route_cleanup
1509}
1510
1511fib6_ra_to_static()
1512{
1513	setup
1514
1515	echo
1516	echo "Fib6 route promotion from RA-learned to static test"
1517	set -e
1518
1519	# ra6 is required for the test. (ipv6toolkit)
1520	if [ ! -x "$(command -v ra6)" ]; then
1521	    echo "SKIP: ra6 not found."
1522	    set +e
1523	    cleanup &> /dev/null
1524	    return
1525	fi
1526
1527	# Create a pair of veth devices to send a RA message from one
1528	# device to another.
1529	$IP link add veth1 type veth peer name veth2
1530	$IP link set dev veth1 up
1531	$IP link set dev veth2 up
1532	$IP -6 address add 2001:10::1/64 dev veth1 nodad
1533	$IP -6 address add 2001:10::2/64 dev veth2 nodad
1534
1535	# Make veth1 ready to receive RA messages.
1536	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
1537
1538	# Send a RA message with a prefix from veth2.
1539	$NS_EXEC ra6 -i veth2 -d 2001:10::1 -P 2001:12::/64\#LA\#120\#60
1540
1541	# Wait for the RA message.
1542	sleep 1
1543
1544	# systemd may mess up the test. Make sure that
1545	# systemd-networkd.service and systemd-networkd.socket are stopped.
1546	check_rt_num_clean 2 $($IP -6 route list|grep expires|wc -l) || return
1547
1548	# Configure static address on the same prefix
1549	$IP -6 address add 2001:12::dead/64 dev veth1 nodad
1550
1551	# On-link route won't expire anymore, default route still owned by RA
1552	check_rt_num 1 $($IP -6 route list |grep expires|wc -l)
1553
1554	# Send a second RA message with a prefix from veth2.
1555	$NS_EXEC ra6 -i veth2 -d 2001:10::1 -P 2001:12::/64\#LA\#120\#60
1556	sleep 1
1557
1558	# Expire is not back, on-link route is still static
1559	check_rt_num 1 $($IP -6 route list |grep expires|wc -l)
1560
1561	$IP -6 address del 2001:12::dead/64 dev veth1 nodad
1562
1563	# Expire is back, on-link route is now owned by RA again
1564	check_rt_num 2 $($IP -6 route list |grep expires|wc -l)
1565
1566	log_test "$RET" 0 "ipv6 promote RA route to static"
1567
1568	# Prepare for RA route with gateway
1569	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra_rt_info_max_plen=64
1570
1571	# Add initial route to cause ECMP merging
1572	$IP -6 route add 2001:12::/64 via fe80::dead:beef dev veth1
1573
1574	$NS_EXEC ra6 -i veth2 -d 2001:10::1 -R 2001:12::/64#1#120
1575
1576	# Routes are not merged as RA routes are not elegible for ECMP
1577	check_rt_num 2 "$($IP -6 route list | grep -c "2001:12::/64 via")"
1578
1579	$IP -6 route append 2001:12::/64 via fe80::dead:feeb dev veth1
1580
1581	check_rt_num 2 "$($IP -6 route list | grep -c "nexthop via")"
1582
1583	log_test "$RET" 0 "ipv6 RA route with nexthop do not merge into ECMP with static"
1584
1585	set +e
1586
1587	cleanup &> /dev/null
1588}
1589
1590fib6_temp_addr_renewal() {
1591	setup
1592
1593	echo
1594	echo "Fib6 temporary address renewal test"
1595	set -e
1596
1597	# ra6 is required for the test. (ipv6toolkit)
1598	if [ ! -x "$(command -v ra6)" ]; then
1599	    echo "SKIP: ra6 not found."
1600	    set +e
1601	    cleanup &> /dev/null
1602	    return
1603	fi
1604
1605	# Create a pair of veth devices to send a RA message from one
1606	# device to another.
1607	$IP link add veth1 type veth peer name veth2
1608	$IP link set dev veth1 up
1609	$IP link set dev veth2 up
1610
1611	# Make veth1 ready to receive RA messages.
1612	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
1613	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.use_tempaddr=2
1614	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.temp_prefered_lft=15
1615	$NS_EXEC sysctl -wq net.ipv6.conf.veth1.max_desync_factor=0
1616
1617	# Send a RA message with a prefix from veth2.
1618	$NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
1619	sleep 3
1620
1621	# Deprecate it
1622	$NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#0 -e
1623	sleep 3
1624
1625	# Restore it
1626	$NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
1627
1628	RET=1
1629	for i in $(seq 1 25); do
1630		sleep 1
1631		num_dep="$($IP -6 addr | grep -c "temporary deprecated" || true)"
1632		num_tot="$($IP -6 addr | grep -c "temporary" || true)"
1633
1634		if [ "$num_dep" -eq 1 ] && [ "$num_tot" -ge 2 ]; then
1635			RET=0
1636			break
1637		fi
1638	done
1639	log_test "$RET" 0 "IPv6 temporary address cleanly deprecated and regenerated"
1640
1641	set +e
1642
1643	cleanup &> /dev/null
1644}
1645
1646# add route for a prefix, flushing any existing routes first
1647# expected to be the first step of a test
1648add_route()
1649{
1650	local pfx="$1"
1651	local nh="$2"
1652	local out
1653
1654	if [ "$VERBOSE" = "1" ]; then
1655		echo
1656		echo "    ##################################################"
1657		echo
1658	fi
1659
1660	run_cmd "$IP ro flush ${pfx}"
1661	[ $? -ne 0 ] && exit 1
1662
1663	out=$($IP ro ls match ${pfx})
1664	if [ -n "$out" ]; then
1665		echo "Failed to flush routes for prefix used for tests."
1666		exit 1
1667	fi
1668
1669	run_cmd "$IP ro add ${pfx} ${nh}"
1670	if [ $? -ne 0 ]; then
1671		echo "Failed to add initial route for test."
1672		exit 1
1673	fi
1674}
1675
1676# add initial route - used in replace route tests
1677add_initial_route()
1678{
1679	add_route "172.16.104.0/24" "$1"
1680}
1681
1682check_route()
1683{
1684	local pfx
1685	local expected="$1"
1686	local out
1687
1688	set -- $expected
1689	pfx=$1
1690	[ "${pfx}" = "unreachable" ] && pfx=$2
1691
1692	out=$($IP ro ls match ${pfx})
1693	check_expected "${out}" "${expected}"
1694}
1695
1696# assumption is that basic add of a single path route works
1697# otherwise just adding an address on an interface is broken
1698ipv4_rt_add()
1699{
1700	local rc
1701
1702	echo
1703	echo "IPv4 route add / append tests"
1704
1705	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1706	add_route "172.16.104.0/24" "via 172.16.101.2"
1707	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1708	log_test $? 2 "Attempt to add duplicate route - gw"
1709
1710	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1711	add_route "172.16.104.0/24" "via 172.16.101.2"
1712	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1713	log_test $? 2 "Attempt to add duplicate route - dev only"
1714
1715	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1716	add_route "172.16.104.0/24" "via 172.16.101.2"
1717	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1718	log_test $? 2 "Attempt to add duplicate route - reject route"
1719
1720	# iproute2 prepend only sets NLM_F_CREATE
1721	# - adds a new route; does NOT convert existing route to ECMP
1722	add_route "172.16.104.0/24" "via 172.16.101.2"
1723	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1724	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3 172.16.104.0/24 via 172.16.101.2 dev veth1"
1725	log_test $? 0 "Add new nexthop for existing prefix"
1726
1727	# route append with same prefix adds a new route
1728	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1729	add_route "172.16.104.0/24" "via 172.16.101.2"
1730	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1731	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.2 dev veth3"
1732	log_test $? 0 "Append nexthop to existing route - gw"
1733
1734	add_route "172.16.104.0/24" "via 172.16.101.2"
1735	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1736	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1737	log_test $? 0 "Append nexthop to existing route - dev only"
1738
1739	add_route "172.16.104.0/24" "via 172.16.101.2"
1740	run_cmd "$IP ro append unreachable 172.16.104.0/24"
1741	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1742	log_test $? 0 "Append nexthop to existing route - reject route"
1743
1744	run_cmd "$IP ro flush 172.16.104.0/24"
1745	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1746	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1747	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1748	log_test $? 0 "Append nexthop to existing reject route - gw"
1749
1750	run_cmd "$IP ro flush 172.16.104.0/24"
1751	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1752	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1753	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1754	log_test $? 0 "Append nexthop to existing reject route - dev only"
1755
1756	# insert mpath directly
1757	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1758	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1759	log_test $? 0 "add multipath route"
1760
1761	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1762	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1763	log_test $? 2 "Attempt to add duplicate multipath route"
1764
1765	# insert of a second route without append but different metric
1766	add_route "172.16.104.0/24" "via 172.16.101.2"
1767	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1768	rc=$?
1769	if [ $rc -eq 0 ]; then
1770		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1771		rc=$?
1772	fi
1773	log_test $rc 0 "Route add with different metrics"
1774
1775	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1776	rc=$?
1777	if [ $rc -eq 0 ]; then
1778		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.3 dev veth3 metric 256"
1779		rc=$?
1780	fi
1781	log_test $rc 0 "Route delete with metric"
1782}
1783
1784ipv4_rt_replace_single()
1785{
1786	# single path with single path
1787	#
1788	add_initial_route "via 172.16.101.2"
1789	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1790	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1791	log_test $? 0 "Single path with single path"
1792
1793	# single path with multipath
1794	#
1795	add_initial_route "nexthop via 172.16.101.2"
1796	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1797	check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1798	log_test $? 0 "Single path with multipath"
1799
1800	# single path with reject
1801	#
1802	add_initial_route "nexthop via 172.16.101.2"
1803	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1804	check_route "unreachable 172.16.104.0/24"
1805	log_test $? 0 "Single path with reject route"
1806
1807	# single path with single path using MULTIPATH attribute
1808	#
1809	add_initial_route "via 172.16.101.2"
1810	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1811	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1812	log_test $? 0 "Single path with single path via multipath attribute"
1813
1814	# route replace fails - invalid nexthop
1815	add_initial_route "via 172.16.101.2"
1816	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1817	if [ $? -eq 0 ]; then
1818		# previous command is expected to fail so if it returns 0
1819		# that means the test failed.
1820		log_test 0 1 "Invalid nexthop"
1821	else
1822		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1823		log_test $? 0 "Invalid nexthop"
1824	fi
1825
1826	# replace non-existent route
1827	# - note use of change versus replace since ip adds NLM_F_CREATE
1828	#   for replace
1829	add_initial_route "via 172.16.101.2"
1830	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1831	log_test $? 2 "Single path - replace of non-existent route"
1832}
1833
1834ipv4_rt_replace_mpath()
1835{
1836	# multipath with multipath
1837	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1838	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1839	check_route  "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.3 dev veth3 weight 1"
1840	log_test $? 0 "Multipath with multipath"
1841
1842	# multipath with single
1843	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1844	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1845	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1846	log_test $? 0 "Multipath with single path"
1847
1848	# multipath with single
1849	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1850	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1851	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1852	log_test $? 0 "Multipath with single path via multipath attribute"
1853
1854	# multipath with reject
1855	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1856	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1857	check_route "unreachable 172.16.104.0/24"
1858	log_test $? 0 "Multipath with reject route"
1859
1860	# route replace fails - invalid nexthop 1
1861	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1862	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1863	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1864	log_test $? 0 "Multipath - invalid first nexthop"
1865
1866	# route replace fails - invalid nexthop 2
1867	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1868	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1869	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1870	log_test $? 0 "Multipath - invalid second nexthop"
1871
1872	# multipath non-existent route
1873	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1874	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1875	log_test $? 2 "Multipath - replace of non-existent route"
1876}
1877
1878ipv4_rt_replace()
1879{
1880	echo
1881	echo "IPv4 route replace tests"
1882
1883	ipv4_rt_replace_single
1884	ipv4_rt_replace_mpath
1885}
1886
1887# checks that cached input route on VRF port is deleted
1888# when VRF is deleted
1889ipv4_local_rt_cache()
1890{
1891	run_cmd "ip addr add 10.0.0.1/32 dev lo"
1892	run_cmd "setup_ns test-ns"
1893	run_cmd "ip link add veth-outside type veth peer name veth-inside"
1894	run_cmd "ip link add vrf-100 type vrf table 1100"
1895	run_cmd "ip link set veth-outside master vrf-100"
1896	run_cmd "ip link set veth-inside netns $test-ns"
1897	run_cmd "ip link set veth-outside up"
1898	run_cmd "ip link set vrf-100 up"
1899	run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1900	run_cmd "ip netns exec $test-ns ip link set veth-inside up"
1901	run_cmd "ip netns exec $test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1902	run_cmd "ip netns exec $test-ns ip route add 10.0.0.1/32 dev veth-inside"
1903	run_cmd "ip netns exec $test-ns ip route add default via 10.0.0.1"
1904	run_cmd "ip netns exec $test-ns ping 10.0.0.1 -c 1 -i 1"
1905	run_cmd "ip link delete vrf-100"
1906
1907	# if we do not hang test is a success
1908	log_test $? 0 "Cached route removed from VRF port device"
1909}
1910
1911ipv4_rt_dsfield()
1912{
1913	echo
1914	echo "IPv4 route with dsfield tests"
1915
1916	run_cmd "$IP route flush 172.16.102.0/24"
1917
1918	# New routes should reject dsfield options that interfere with ECN
1919	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
1920	log_test $? 2 "Reject route with dsfield 0x01"
1921
1922	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
1923	log_test $? 2 "Reject route with dsfield 0x02"
1924
1925	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
1926	log_test $? 2 "Reject route with dsfield 0x03"
1927
1928	# A generic route that doesn't take DSCP into account
1929	run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
1930
1931	# A more specific route for DSCP 0x10
1932	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
1933
1934	# DSCP 0x10 should match the specific route, no matter the ECN bits
1935	$IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
1936		grep -q "172.16.102.0/24 tos 0x10 via 172.16.103.2"
1937	log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
1938
1939	$IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
1940		grep -q "172.16.102.0/24 tos 0x10 via 172.16.103.2"
1941	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
1942
1943	$IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
1944		grep -q "172.16.102.0/24 tos 0x10 via 172.16.103.2"
1945	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
1946
1947	$IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
1948		grep -q "172.16.102.0/24 tos 0x10 via 172.16.103.2"
1949	log_test $? 0 "IPv4 route with DSCP and ECN:CE"
1950
1951	# Unknown DSCP should match the generic route, no matter the ECN bits
1952	$IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
1953		grep -q "172.16.102.0/24 via 172.16.101.2"
1954	log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
1955
1956	$IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
1957		grep -q "172.16.102.0/24 via 172.16.101.2"
1958	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
1959
1960	$IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
1961		grep -q "172.16.102.0/24 via 172.16.101.2"
1962	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
1963
1964	$IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
1965		grep -q "172.16.102.0/24 via 172.16.101.2"
1966	log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
1967
1968	# Null DSCP should match the generic route, no matter the ECN bits
1969	$IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
1970		grep -q "172.16.102.0/24 via 172.16.101.2"
1971	log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
1972
1973	$IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
1974		grep -q "172.16.102.0/24 via 172.16.101.2"
1975	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
1976
1977	$IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
1978		grep -q "172.16.102.0/24 via 172.16.101.2"
1979	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
1980
1981	$IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
1982		grep -q "172.16.102.0/24 via 172.16.101.2"
1983	log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
1984}
1985
1986ipv4_route_test()
1987{
1988	route_setup
1989
1990	ipv4_rt_add
1991	ipv4_rt_replace
1992	ipv4_local_rt_cache
1993	ipv4_rt_dsfield
1994
1995	route_cleanup
1996}
1997
1998ipv4_addr_metric_test()
1999{
2000	local rc
2001
2002	echo
2003	echo "IPv4 prefix route tests"
2004
2005	ip_addr_metric_check || return 1
2006
2007	setup
2008
2009	set -e
2010	$IP li add dummy1 type dummy
2011	$IP li add dummy2 type dummy
2012	$IP li set dummy1 up
2013	$IP li set dummy2 up
2014
2015	# default entry is metric 256
2016	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
2017	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
2018	set +e
2019
2020	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2"
2021	log_test $? 0 "Default metric"
2022
2023	set -e
2024	run_cmd "$IP addr flush dev dummy1"
2025	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
2026	set +e
2027
2028	check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257"
2029	log_test $? 0 "User specified metric on first device"
2030
2031	set -e
2032	run_cmd "$IP addr flush dev dummy2"
2033	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
2034	set +e
2035
2036	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
2037	log_test $? 0 "User specified metric on second device"
2038
2039	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
2040	rc=$?
2041	if [ $rc -eq 0 ]; then
2042		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
2043		rc=$?
2044	fi
2045	log_test $rc 0 "Delete of address on first device"
2046
2047	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
2048	rc=$?
2049	if [ $rc -eq 0 ]; then
2050		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
2051		rc=$?
2052	fi
2053	log_test $rc 0 "Modify metric of address"
2054
2055	# verify prefix route removed on down
2056	run_cmd "$IP li set dev dummy2 down"
2057	rc=$?
2058	if [ $rc -eq 0 ]; then
2059		out=$($IP ro ls match 172.16.104.0/24)
2060		check_expected "${out}" ""
2061		rc=$?
2062	fi
2063	log_test $rc 0 "Prefix route removed on link down"
2064
2065	# verify prefix route re-inserted with assigned metric
2066	run_cmd "$IP li set dev dummy2 up"
2067	rc=$?
2068	if [ $rc -eq 0 ]; then
2069		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
2070		rc=$?
2071	fi
2072	log_test $rc 0 "Prefix route with metric on link up"
2073
2074	# explicitly check for metric changes on edge scenarios
2075	run_cmd "$IP addr flush dev dummy2"
2076	run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
2077	run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
2078	rc=$?
2079	if [ $rc -eq 0 ]; then
2080		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
2081		rc=$?
2082	fi
2083	log_test $rc 0 "Modify metric of .0/24 address"
2084
2085	run_cmd "$IP addr flush dev dummy2"
2086	run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
2087	rc=$?
2088	if [ $rc -eq 0 ]; then
2089		check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
2090		rc=$?
2091	fi
2092	log_test $rc 0 "Set metric of address with peer route"
2093
2094	run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
2095	rc=$?
2096	if [ $rc -eq 0 ]; then
2097		check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
2098		rc=$?
2099	fi
2100	log_test $rc 0 "Modify metric and peer address for peer route"
2101
2102	$IP li del dummy1
2103	$IP li del dummy2
2104	cleanup
2105}
2106
2107ipv4_route_metrics_test()
2108{
2109	local rc
2110
2111	echo
2112	echo "IPv4 route add / append tests"
2113
2114	route_setup
2115
2116	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
2117	rc=$?
2118	if [ $rc -eq 0 ]; then
2119		check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
2120		rc=$?
2121	fi
2122	log_test $rc 0 "Single path route with mtu metric"
2123
2124
2125	run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
2126	rc=$?
2127	if [ $rc -eq 0 ]; then
2128		check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
2129		rc=$?
2130	fi
2131	log_test $rc 0 "Multipath route with mtu metric"
2132
2133	$IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
2134	run_cmd "ip netns exec $ns1 ping -w1 -c1 -s 1500 172.16.104.1"
2135	log_test $? 0 "Using route with mtu metric"
2136
2137	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
2138	log_test $? 2 "Invalid metric (fails metric_convert)"
2139
2140	route_cleanup
2141}
2142
2143ipv4_del_addr_test()
2144{
2145	echo
2146	echo "IPv4 delete address route tests"
2147
2148	setup
2149
2150	set -e
2151	$IP li add dummy1 type dummy
2152	$IP li set dummy1 up
2153	$IP li add dummy2 type dummy
2154	$IP li set dummy2 up
2155	$IP li add red type vrf table 1111
2156	$IP li set red up
2157	$IP ro add vrf red unreachable default
2158	$IP li set dummy2 vrf red
2159
2160	$IP addr add dev dummy1 172.16.104.1/24
2161	$IP addr add dev dummy1 172.16.104.11/24
2162	$IP addr add dev dummy1 172.16.104.12/24
2163	$IP addr add dev dummy1 172.16.104.13/24
2164	$IP addr add dev dummy2 172.16.104.1/24
2165	$IP addr add dev dummy2 172.16.104.11/24
2166	$IP addr add dev dummy2 172.16.104.12/24
2167	$IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
2168	$IP route add 172.16.106.0/24 dev lo src 172.16.104.12
2169	$IP route add table 0 172.16.107.0/24 via 172.16.104.2 src 172.16.104.13
2170	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
2171	$IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
2172	set +e
2173
2174	# removing address from device in vrf should only remove route from vrf table
2175	echo "    Regular FIB info"
2176
2177	$IP addr del dev dummy2 172.16.104.11/24
2178	$IP ro ls vrf red | grep -q 172.16.105.0/24
2179	log_test $? 1 "Route removed from VRF when source address deleted"
2180
2181	$IP ro ls | grep -q 172.16.105.0/24
2182	log_test $? 0 "Route in default VRF not removed"
2183
2184	$IP addr add dev dummy2 172.16.104.11/24
2185	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
2186
2187	$IP addr del dev dummy1 172.16.104.11/24
2188	$IP ro ls | grep -q 172.16.105.0/24
2189	log_test $? 1 "Route removed in default VRF when source address deleted"
2190
2191	$IP ro ls vrf red | grep -q 172.16.105.0/24
2192	log_test $? 0 "Route in VRF is not removed by address delete"
2193
2194	# removing address from device in vrf should only remove route from vrf
2195	# table even when the associated fib info only differs in table ID
2196	echo "    Identical FIB info with different table ID"
2197
2198	$IP addr del dev dummy2 172.16.104.12/24
2199	$IP ro ls vrf red | grep -q 172.16.106.0/24
2200	log_test $? 1 "Route removed from VRF when source address deleted"
2201
2202	$IP ro ls | grep -q 172.16.106.0/24
2203	log_test $? 0 "Route in default VRF not removed"
2204
2205	$IP addr add dev dummy2 172.16.104.12/24
2206	$IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
2207
2208	$IP addr del dev dummy1 172.16.104.12/24
2209	$IP ro ls | grep -q 172.16.106.0/24
2210	log_test $? 1 "Route removed in default VRF when source address deleted"
2211
2212	$IP ro ls vrf red | grep -q 172.16.106.0/24
2213	log_test $? 0 "Route in VRF is not removed by address delete"
2214
2215	# removing address from device in default vrf should remove route from
2216	# the default vrf even when route was inserted with a table ID of 0.
2217	echo "    Table ID 0"
2218
2219	$IP addr del dev dummy1 172.16.104.13/24
2220	$IP ro ls | grep -q 172.16.107.0/24
2221	log_test $? 1 "Route removed in default VRF when source address deleted"
2222
2223	$IP li del dummy1
2224	$IP li del dummy2
2225	cleanup
2226}
2227
2228ipv6_del_addr_test()
2229{
2230	echo
2231	echo "IPv6 delete address route tests"
2232
2233	setup
2234
2235	set -e
2236	for i in $(seq 6); do
2237		$IP li add dummy${i} up type dummy
2238	done
2239
2240	$IP li add red up type vrf table 1111
2241	$IP ro add vrf red unreachable default
2242	for i in $(seq 4 6); do
2243		$IP li set dummy${i} vrf red
2244	done
2245
2246	$IP addr add dev dummy1 fe80::1/128
2247	$IP addr add dev dummy1 2001:db8:101::1/64
2248	$IP addr add dev dummy1 2001:db8:101::10/64
2249	$IP addr add dev dummy1 2001:db8:101::11/64
2250	$IP addr add dev dummy1 2001:db8:101::12/64
2251	$IP addr add dev dummy1 2001:db8:101::13/64
2252	$IP addr add dev dummy1 2001:db8:101::14/64
2253	$IP addr add dev dummy1 2001:db8:101::15/64
2254	$IP addr add dev dummy2 fe80::1/128
2255	$IP addr add dev dummy2 2001:db8:101::1/64
2256	$IP addr add dev dummy2 2001:db8:101::11/64
2257	$IP addr add dev dummy3 fe80::1/128
2258
2259	$IP addr add dev dummy4 2001:db8:101::1/64
2260	$IP addr add dev dummy4 2001:db8:101::10/64
2261	$IP addr add dev dummy4 2001:db8:101::11/64
2262	$IP addr add dev dummy4 2001:db8:101::12/64
2263	$IP addr add dev dummy4 2001:db8:101::13/64
2264	$IP addr add dev dummy4 2001:db8:101::14/64
2265	$IP addr add dev dummy5 2001:db8:101::1/64
2266	$IP addr add dev dummy5 2001:db8:101::11/64
2267
2268	# Single device using src address
2269	$IP route add 2001:db8:110::/64 dev dummy3 src 2001:db8:101::10
2270	# Two devices with the same source address
2271	$IP route add 2001:db8:111::/64 dev dummy3 src 2001:db8:101::11
2272	# VRF with single device using src address
2273	$IP route add vrf red 2001:db8:110::/64 dev dummy6 src 2001:db8:101::10
2274	# VRF with two devices using src address
2275	$IP route add vrf red 2001:db8:111::/64 dev dummy6 src 2001:db8:101::11
2276	# src address and nexthop dev in same VRF
2277	$IP route add 2001:db8:112::/64 dev dummy3 src 2001:db8:101::12
2278	$IP route add vrf red 2001:db8:112::/64 dev dummy6 src 2001:db8:101::12
2279	# src address and nexthop device in different VRF
2280	$IP route add 2001:db8:113::/64 dev lo src 2001:db8:101::13
2281	$IP route add vrf red 2001:db8:113::/64 dev lo src 2001:db8:101::13
2282	# table ID 0
2283	$IP route add table 0 2001:db8:115::/64 via 2001:db8:101::2 src 2001:db8:101::15
2284	# Link local source route
2285	$IP route add 2001:db8:116::/64 dev dummy2 src fe80::1
2286	$IP route add 2001:db8:117::/64 dev dummy3 src fe80::1
2287	set +e
2288
2289	echo "    Single device using src address"
2290
2291	$IP addr del dev dummy1 2001:db8:101::10/64
2292	$IP -6 route show | grep -q "src 2001:db8:101::10 "
2293	log_test $? 1 "Prefsrc removed when src address removed on other device"
2294
2295	echo "    Two devices with the same source address"
2296
2297	$IP addr del dev dummy1 2001:db8:101::11/64
2298	$IP -6 route show | grep -q "src 2001:db8:101::11 "
2299	log_test $? 0 "Prefsrc not removed when src address exist on other device"
2300
2301	$IP addr del dev dummy2 2001:db8:101::11/64
2302	$IP -6 route show | grep -q "src 2001:db8:101::11 "
2303	log_test $? 1 "Prefsrc removed when src address removed on all devices"
2304
2305	echo "    VRF with single device using src address"
2306
2307	$IP addr del dev dummy4 2001:db8:101::10/64
2308	$IP -6 route show vrf red | grep -q "src 2001:db8:101::10 "
2309	log_test $? 1 "Prefsrc removed when src address removed on other device"
2310
2311	echo "    VRF with two devices using src address"
2312
2313	$IP addr del dev dummy4 2001:db8:101::11/64
2314	$IP -6 route show vrf red | grep -q "src 2001:db8:101::11 "
2315	log_test $? 0 "Prefsrc not removed when src address exist on other device"
2316
2317	$IP addr del dev dummy5 2001:db8:101::11/64
2318	$IP -6 route show vrf red | grep -q "src 2001:db8:101::11 "
2319	log_test $? 1 "Prefsrc removed when src address removed on all devices"
2320
2321	echo "    src address and nexthop dev in same VRF"
2322
2323	$IP addr del dev dummy4 2001:db8:101::12/64
2324	$IP -6 route show vrf red | grep -q "src 2001:db8:101::12 "
2325	log_test $? 1 "Prefsrc removed from VRF when source address deleted"
2326	$IP -6 route show | grep -q " src 2001:db8:101::12 "
2327	log_test $? 0 "Prefsrc in default VRF not removed"
2328
2329	$IP addr add dev dummy4 2001:db8:101::12/64
2330	$IP route replace vrf red 2001:db8:112::/64 dev dummy6 src 2001:db8:101::12
2331	$IP addr del dev dummy1 2001:db8:101::12/64
2332	$IP -6 route show vrf red | grep -q "src 2001:db8:101::12 "
2333	log_test $? 0 "Prefsrc not removed from VRF when source address exist"
2334	$IP -6 route show | grep -q " src 2001:db8:101::12 "
2335	log_test $? 1 "Prefsrc in default VRF removed"
2336
2337	echo "    src address and nexthop device in different VRF"
2338
2339	$IP addr del dev dummy4 2001:db8:101::13/64
2340	$IP -6 route show vrf red | grep -q "src 2001:db8:101::13 "
2341	log_test $? 0 "Prefsrc not removed from VRF when nexthop dev in diff VRF"
2342	$IP -6 route show | grep -q "src 2001:db8:101::13 "
2343	log_test $? 0 "Prefsrc not removed in default VRF"
2344
2345	$IP addr add dev dummy4 2001:db8:101::13/64
2346	$IP addr del dev dummy1 2001:db8:101::13/64
2347	$IP -6 route show vrf red | grep -q "src 2001:db8:101::13 "
2348	log_test $? 1 "Prefsrc removed from VRF when nexthop dev in diff VRF"
2349	$IP -6 route show | grep -q "src 2001:db8:101::13 "
2350	log_test $? 1 "Prefsrc removed in default VRF"
2351
2352	echo "    Table ID 0"
2353
2354	$IP addr del dev dummy1 2001:db8:101::15/64
2355	$IP -6 route show | grep -q "src 2001:db8:101::15"
2356	log_test $? 1 "Prefsrc removed from default VRF when source address deleted"
2357
2358	echo "    Link local source route"
2359	$IP addr del dev dummy1 fe80::1/128
2360	$IP -6 route show | grep -q "2001:db8:116::/64 dev dummy2 src fe80::1"
2361	log_test $? 0 "Prefsrc not removed when delete ll addr from other dev"
2362	$IP addr del dev dummy2 fe80::1/128
2363	$IP -6 route show | grep -q "2001:db8:116::/64 dev dummy2 src fe80::1"
2364	log_test $? 1 "Prefsrc removed when delete ll addr"
2365	$IP -6 route show | grep -q "2001:db8:117::/64 dev dummy3 src fe80::1"
2366	log_test $? 0 "Prefsrc not removed when delete ll addr from other dev"
2367	$IP addr add dev dummy1 fe80::1/128
2368	$IP addr del dev dummy3 fe80::1/128
2369	$IP -6 route show | grep -q "2001:db8:117::/64 dev dummy3 src fe80::1"
2370	log_test $? 1 "Prefsrc removed even ll addr still exist on other dev"
2371
2372	for i in $(seq 6); do
2373		$IP li del dummy${i}
2374	done
2375	cleanup
2376}
2377
2378ipv4_route_v6_gw_test()
2379{
2380	local rc
2381
2382	echo
2383	echo "IPv4 route with IPv6 gateway tests"
2384
2385	route_setup
2386	sleep 2
2387
2388	#
2389	# single path route
2390	#
2391	run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
2392	rc=$?
2393	log_test $rc 0 "Single path route with IPv6 gateway"
2394	if [ $rc -eq 0 ]; then
2395		check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
2396	fi
2397
2398	run_cmd "ip netns exec $ns1 ping -w1 -c1 172.16.104.1"
2399	log_test $rc 0 "Single path route with IPv6 gateway - ping"
2400
2401	run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
2402	rc=$?
2403	log_test $rc 0 "Single path route delete"
2404	if [ $rc -eq 0 ]; then
2405		check_route "172.16.112.0/24"
2406	fi
2407
2408	#
2409	# multipath - v6 then v4
2410	#
2411	run_cmd "$IP ro add 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2412	rc=$?
2413	log_test $rc 0 "Multipath route add - v6 nexthop then v4"
2414	if [ $rc -eq 0 ]; then
2415		check_route "172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
2416	fi
2417
2418	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2419	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
2420
2421	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2422	log_test $? 0 "    Multipath route delete exact match"
2423
2424	#
2425	# multipath - v4 then v6
2426	#
2427	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2428	rc=$?
2429	log_test $rc 0 "Multipath route add - v4 nexthop then v6"
2430	if [ $rc -eq 0 ]; then
2431		check_route "172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 weight 1 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1"
2432	fi
2433
2434	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2435	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
2436
2437	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2438	log_test $? 0 "    Multipath route delete exact match"
2439
2440	route_cleanup
2441}
2442
2443socat_check()
2444{
2445	if [ ! -x "$(command -v socat)" ]; then
2446		echo "socat command not found. Skipping test"
2447		return 1
2448	fi
2449
2450	return 0
2451}
2452
2453iptables_check()
2454{
2455	iptables -t mangle -L OUTPUT &> /dev/null
2456	if [ $? -ne 0 ]; then
2457		echo "iptables configuration not supported. Skipping test"
2458		return 1
2459	fi
2460
2461	return 0
2462}
2463
2464ip6tables_check()
2465{
2466	ip6tables -t mangle -L OUTPUT &> /dev/null
2467	if [ $? -ne 0 ]; then
2468		echo "ip6tables configuration not supported. Skipping test"
2469		return 1
2470	fi
2471
2472	return 0
2473}
2474
2475ipv4_mangle_test()
2476{
2477	local rc
2478
2479	echo
2480	echo "IPv4 mangling tests"
2481
2482	socat_check || return 1
2483	iptables_check || return 1
2484
2485	route_setup
2486	sleep 2
2487
2488	local tmp_file=$(mktemp)
2489	ip netns exec $ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
2490
2491	# Add a FIB rule and a route that will direct our connection to the
2492	# listening server.
2493	$IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
2494	$IP route add table 123 172.16.101.0/24 dev veth1
2495
2496	# Add an unreachable route to the main table that will block our
2497	# connection in case the FIB rule is not hit.
2498	$IP route add unreachable 172.16.101.2/32
2499
2500	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2501	log_test $? 0 "    Connection with correct parameters"
2502
2503	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
2504	log_test $? 1 "    Connection with incorrect parameters"
2505
2506	# Add a mangling rule and make sure connection is still successful.
2507	$NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
2508
2509	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2510	log_test $? 0 "    Connection with correct parameters - mangling"
2511
2512	# Delete the mangling rule and make sure connection is still
2513	# successful.
2514	$NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
2515
2516	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2517	log_test $? 0 "    Connection with correct parameters - no mangling"
2518
2519	# Verify connections were indeed successful on server side.
2520	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
2521	log_test $? 0 "    Connection check - server side"
2522
2523	$IP route del unreachable 172.16.101.2/32
2524	$IP route del table 123 172.16.101.0/24 dev veth1
2525	$IP rule del pref 100
2526
2527	kill_process %%
2528	rm $tmp_file
2529
2530	route_cleanup
2531}
2532
2533ipv6_mangle_test()
2534{
2535	local rc
2536
2537	echo
2538	echo "IPv6 mangling tests"
2539
2540	socat_check || return 1
2541	ip6tables_check || return 1
2542
2543	route_setup
2544	sleep 2
2545
2546	local tmp_file=$(mktemp)
2547	ip netns exec $ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
2548
2549	# Add a FIB rule and a route that will direct our connection to the
2550	# listening server.
2551	$IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
2552	$IP -6 route add table 123 2001:db8:101::/64 dev veth1
2553
2554	# Add an unreachable route to the main table that will block our
2555	# connection in case the FIB rule is not hit.
2556	$IP -6 route add unreachable 2001:db8:101::2/128
2557
2558	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2559	log_test $? 0 "    Connection with correct parameters"
2560
2561	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
2562	log_test $? 1 "    Connection with incorrect parameters"
2563
2564	# Add a mangling rule and make sure connection is still successful.
2565	$NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
2566
2567	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2568	log_test $? 0 "    Connection with correct parameters - mangling"
2569
2570	# Delete the mangling rule and make sure connection is still
2571	# successful.
2572	$NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
2573
2574	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2575	log_test $? 0 "    Connection with correct parameters - no mangling"
2576
2577	# Verify connections were indeed successful on server side.
2578	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
2579	log_test $? 0 "    Connection check - server side"
2580
2581	$IP -6 route del unreachable 2001:db8:101::2/128
2582	$IP -6 route del table 123 2001:db8:101::/64 dev veth1
2583	$IP -6 rule del pref 100
2584
2585	kill_process %%
2586	rm $tmp_file
2587
2588	route_cleanup
2589}
2590
2591ip_neigh_get_check()
2592{
2593	ip neigh help 2>&1 | grep -q 'ip neigh get'
2594	if [ $? -ne 0 ]; then
2595		echo "iproute2 command does not support neigh get. Skipping test"
2596		return 1
2597	fi
2598
2599	return 0
2600}
2601
2602ipv4_bcast_neigh_test()
2603{
2604	local rc
2605
2606	echo
2607	echo "IPv4 broadcast neighbour tests"
2608
2609	ip_neigh_get_check || return 1
2610
2611	setup
2612
2613	set -e
2614	run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2615	run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2616
2617	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2618	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2619
2620	run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"
2621
2622	run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
2623	run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"
2624
2625	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2626	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2627
2628	run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
2629	set +e
2630
2631	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2632	log_test $? 0 "Resolved neighbour for broadcast address"
2633
2634	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2635	log_test $? 0 "Resolved neighbour for network broadcast address"
2636
2637	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2638	log_test $? 2 "Unresolved neighbour for broadcast address"
2639
2640	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2641	log_test $? 2 "Unresolved neighbour for network broadcast address"
2642
2643	cleanup
2644}
2645
2646mpath_dep_check()
2647{
2648	if [ ! -x "$(command -v mausezahn)" ]; then
2649		echo "mausezahn command not found. Skipping test"
2650		return 1
2651	fi
2652
2653	if [ ! -x "$(command -v jq)" ]; then
2654		echo "jq command not found. Skipping test"
2655		return 1
2656	fi
2657
2658	if [ ! -x "$(command -v bc)" ]; then
2659		echo "bc command not found. Skipping test"
2660		return 1
2661	fi
2662
2663	if [ ! -x "$(command -v perf)" ]; then
2664		echo "perf command not found. Skipping test"
2665		return 1
2666	fi
2667
2668	perf list fib:* | grep -q fib_table_lookup
2669	if [ $? -ne 0 ]; then
2670		echo "IPv4 FIB tracepoint not found. Skipping test"
2671		return 1
2672	fi
2673
2674	perf list fib6:* | grep -q fib6_table_lookup
2675	if [ $? -ne 0 ]; then
2676		echo "IPv6 FIB tracepoint not found. Skipping test"
2677		return 1
2678	fi
2679
2680	return 0
2681}
2682
2683link_stats_get()
2684{
2685	local ns=$1; shift
2686	local dev=$1; shift
2687	local dir=$1; shift
2688	local stat=$1; shift
2689
2690	ip -n $ns -j -s link show dev $dev \
2691		| jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
2692}
2693
2694list_rcv_eval()
2695{
2696	local file=$1; shift
2697	local expected=$1; shift
2698
2699	local count=$(tail -n 1 $file | jq '.["counter-value"] | tonumber | floor')
2700	local ratio=$(echo "scale=2; $count / $expected" | bc -l)
2701	local res=$(echo "$ratio >= 0.95" | bc)
2702	[[ $res -eq 1 ]]
2703	log_test $? 0 "Multipath route hit ratio ($ratio)"
2704}
2705
2706ipv4_mpath_list_test()
2707{
2708	echo
2709	echo "IPv4 multipath list receive tests"
2710
2711	mpath_dep_check || return 1
2712
2713	route_setup
2714
2715	set -e
2716	run_cmd "ip netns exec $ns1 ethtool -K veth1 tcp-segmentation-offload off"
2717
2718	run_cmd "ip netns exec $ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
2719	run_cmd "ip netns exec $ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
2720	run_cmd "ip netns exec $ns2 ethtool -K veth2 generic-receive-offload on"
2721	run_cmd "ip -n $ns2 link add name nh1 up type dummy"
2722	run_cmd "ip -n $ns2 link add name nh2 up type dummy"
2723	run_cmd "ip -n $ns2 address add 172.16.201.1/24 dev nh1"
2724	run_cmd "ip -n $ns2 address add 172.16.202.1/24 dev nh2"
2725	run_cmd "ip -n $ns2 neigh add 172.16.201.2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
2726	run_cmd "ip -n $ns2 neigh add 172.16.202.2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
2727	run_cmd "ip -n $ns2 route add 203.0.113.0/24
2728		nexthop via 172.16.201.2 nexthop via 172.16.202.2"
2729	run_cmd "ip netns exec $ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
2730	set +e
2731
2732	local dmac=$(ip -n $ns2 -j link show dev veth2 | jq -r '.[]["address"]')
2733	local tmp_file=$(mktemp)
2734	local cmd="ip netns exec $ns1 mausezahn veth1 -a own -b $dmac
2735		-A 172.16.101.1 -B 203.0.113.1 -t udp 'sp=12345,dp=0-65535' -q"
2736
2737	# Packets forwarded in a list using a multipath route must not reuse a
2738	# cached result so that a flow always hits the same nexthop. In other
2739	# words, the FIB lookup tracepoint needs to be triggered for every
2740	# packet.
2741	local t0_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
2742	run_cmd "perf stat -a -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
2743	local t1_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
2744	local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
2745	list_rcv_eval $tmp_file $diff
2746
2747	rm $tmp_file
2748	route_cleanup
2749}
2750
2751ipv6_mpath_list_test()
2752{
2753	echo
2754	echo "IPv6 multipath list receive tests"
2755
2756	mpath_dep_check || return 1
2757
2758	route_setup
2759
2760	set -e
2761	run_cmd "ip netns exec $ns1 ethtool -K veth1 tcp-segmentation-offload off"
2762
2763	run_cmd "ip netns exec $ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
2764	run_cmd "ip netns exec $ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
2765	run_cmd "ip netns exec $ns2 ethtool -K veth2 generic-receive-offload on"
2766	run_cmd "ip -n $ns2 link add name nh1 up type dummy"
2767	run_cmd "ip -n $ns2 link add name nh2 up type dummy"
2768	run_cmd "ip -n $ns2 -6 address add 2001:db8:201::1/64 dev nh1"
2769	run_cmd "ip -n $ns2 -6 address add 2001:db8:202::1/64 dev nh2"
2770	run_cmd "ip -n $ns2 -6 neigh add 2001:db8:201::2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
2771	run_cmd "ip -n $ns2 -6 neigh add 2001:db8:202::2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
2772	run_cmd "ip -n $ns2 -6 route add 2001:db8:301::/64
2773		nexthop via 2001:db8:201::2 nexthop via 2001:db8:202::2"
2774	run_cmd "ip netns exec $ns2 sysctl -qw net.ipv6.fib_multipath_hash_policy=1"
2775	set +e
2776
2777	local dmac=$(ip -n $ns2 -j link show dev veth2 | jq -r '.[]["address"]')
2778	local tmp_file=$(mktemp)
2779	local cmd="ip netns exec $ns1 mausezahn -6 veth1 -a own -b $dmac
2780		-A 2001:db8:101::1 -B 2001:db8:301::1 -t udp 'sp=12345,dp=0-65535' -q"
2781
2782	# Packets forwarded in a list using a multipath route must not reuse a
2783	# cached result so that a flow always hits the same nexthop. In other
2784	# words, the FIB lookup tracepoint needs to be triggered for every
2785	# packet.
2786	local t0_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
2787	run_cmd "perf stat -a -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
2788	local t1_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
2789	local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
2790	list_rcv_eval $tmp_file $diff
2791
2792	rm $tmp_file
2793	route_cleanup
2794}
2795
2796tc_set_flower_counter__saddr_syn() {
2797	tc_set_flower_counter $1 $2 $3 "src_ip $4 ip_proto tcp tcp_flags 0x2"
2798}
2799
2800ip_mpath_balance_dep_check()
2801{
2802	if [ ! -x "$(command -v socat)" ]; then
2803		echo "socat command not found. Skipping test"
2804		return 1
2805	fi
2806
2807	if [ ! -x "$(command -v jq)" ]; then
2808		echo "jq command not found. Skipping test"
2809		return 1
2810	fi
2811}
2812
2813ip_mpath_balance() {
2814	local -r ipver=$1
2815	local -r daddr=$2
2816	local -r num_conn=20
2817
2818	for i in $(seq 1 $num_conn); do
2819		ip netns exec $ns3 socat $ipver TCP-LISTEN:8000 STDIO >/dev/null &
2820		sleep 0.02
2821		echo -n a | ip netns exec $ns1 socat $ipver STDIO TCP:$daddr:8000
2822	done
2823
2824	local -r syn0="$(tc_get_flower_counter $ns1 veth1)"
2825	local -r syn1="$(tc_get_flower_counter $ns1 veth3)"
2826	local -r syns=$((syn0+syn1))
2827
2828	[ "$VERBOSE" = "1" ] && echo "multipath: syns seen: ($syn0,$syn1)"
2829
2830	[[ $syns -ge $num_conn ]] && [[ $syn0 -gt 0 ]] && [[ $syn1 -gt 0 ]]
2831}
2832
2833ipv4_mpath_balance_test()
2834{
2835	echo
2836	echo "IPv4 multipath load balance test"
2837
2838	ip_mpath_balance_dep_check || return 1
2839	forwarding_setup
2840
2841	$IP route add 172.16.105.1 \
2842		nexthop via 172.16.101.2 \
2843		nexthop via 172.16.103.2
2844
2845	ip netns exec $ns1 \
2846		sysctl -q -w net.ipv4.fib_multipath_hash_policy=1
2847
2848	tc_set_flower_counter__saddr_syn $ns1 4 veth1 172.16.101.1
2849	tc_set_flower_counter__saddr_syn $ns1 4 veth3 172.16.103.1
2850
2851	ip_mpath_balance -4 172.16.105.1
2852
2853	log_test $? 0 "IPv4 multipath loadbalance"
2854
2855	forwarding_cleanup
2856}
2857
2858get_route_dev_src()
2859{
2860	local pfx="$1"
2861	local src="$2"
2862	local out
2863
2864	if out=$($IP -j route get "$pfx" from "$src" | jq -re ".[0].dev"); then
2865		echo "$out"
2866	fi
2867}
2868
2869ipv4_mpath_preferred()
2870{
2871	local src_ip=$1
2872	local pref_dev=$2
2873	local dev routes
2874	local route0=0
2875	local route1=0
2876	local pref_route=0
2877	num_routes=254
2878
2879	for i in $(seq 1 $num_routes) ; do
2880		dev=$(get_route_dev_src 172.16.105.$i $src_ip)
2881		if [ "$dev" = "$pref_dev" ]; then
2882			pref_route=$((pref_route+1))
2883		elif [ "$dev" = "veth1" ]; then
2884			route0=$((route0+1))
2885		elif [ "$dev" = "veth3" ]; then
2886			route1=$((route1+1))
2887		fi
2888	done
2889
2890	routes=$((route0+route1))
2891
2892	[ "$VERBOSE" = "1" ] && echo "multipath: routes seen: ($route0,$route1,$pref_route)"
2893
2894	if [ x"$pref_dev" = x"" ]; then
2895		[[ $routes -ge $num_routes ]] && [[ $route0 -gt 0 ]] && [[ $route1 -gt 0 ]]
2896	else
2897		[[ $pref_route -ge $num_routes ]]
2898	fi
2899
2900}
2901
2902ipv4_mpath_balance_preferred_test()
2903{
2904	echo
2905	echo "IPv4 multipath load balance preferred route"
2906
2907	forwarding_setup
2908
2909	$IP route add 172.16.105.0/24 \
2910		nexthop via 172.16.101.2 \
2911		nexthop via 172.16.103.2
2912
2913	ipv4_mpath_preferred 172.16.101.1 veth1
2914	log_test $? 0 "IPv4 multipath loadbalance from veth1"
2915
2916	ipv4_mpath_preferred 172.16.103.1 veth3
2917	log_test $? 0 "IPv4 multipath loadbalance from veth3"
2918
2919	ipv4_mpath_preferred 198.51.100.1
2920	log_test $? 0 "IPv4 multipath loadbalance from dummy"
2921
2922	forwarding_cleanup
2923}
2924
2925ipv6_mpath_balance_test()
2926{
2927	echo
2928	echo "IPv6 multipath load balance test"
2929
2930	ip_mpath_balance_dep_check || return 1
2931	forwarding_setup
2932
2933	$IP route add 2001:db8:105::1\
2934		nexthop via 2001:db8:101::2 \
2935		nexthop via 2001:db8:103::2
2936
2937	ip netns exec $ns1 \
2938		sysctl -q -w net.ipv6.fib_multipath_hash_policy=1
2939
2940	tc_set_flower_counter__saddr_syn $ns1 6 veth1 2001:db8:101::1
2941	tc_set_flower_counter__saddr_syn $ns1 6 veth3 2001:db8:103::1
2942
2943	ip_mpath_balance -6 "[2001:db8:105::1]"
2944
2945	log_test $? 0 "IPv6 multipath loadbalance"
2946
2947	forwarding_cleanup
2948}
2949
2950ipv4_mpath_oif_test_common()
2951{
2952	local get_param=$1; shift
2953	local expected_oif=$1; shift
2954	local test_name=$1; shift
2955	local tmp_file
2956
2957	tmp_file=$(mktemp)
2958
2959	for i in {1..100}; do
2960		$IP route get 203.0.113.${i} $get_param >> "$tmp_file"
2961	done
2962
2963	[[ $(grep "$expected_oif" "$tmp_file" | wc -l) -eq 100 ]]
2964	log_test $? 0 "$test_name"
2965
2966	rm "$tmp_file"
2967}
2968
2969ipv4_mpath_oif_test()
2970{
2971	echo
2972	echo "IPv4 multipath oif test"
2973
2974	setup
2975
2976	set -e
2977	$IP link add dummy1 up type dummy
2978	$IP address add 192.0.2.1/28 dev dummy1
2979	$IP address add 192.0.2.17/32 dev lo
2980
2981	$IP route add 203.0.113.0/24 \
2982		nexthop via 198.51.100.2 dev dummy0 \
2983		nexthop via 192.0.2.2 dev dummy1
2984	set +e
2985
2986	ipv4_mpath_oif_test_common "oif dummy0" "dummy0" \
2987		"IPv4 multipath via first nexthop"
2988
2989	ipv4_mpath_oif_test_common "oif dummy1" "dummy1" \
2990		"IPv4 multipath via second nexthop"
2991
2992	ipv4_mpath_oif_test_common "oif dummy0 from 192.0.2.17" "dummy0" \
2993		"IPv4 multipath via first nexthop with source address"
2994
2995	ipv4_mpath_oif_test_common "oif dummy1 from 192.0.2.17" "dummy1" \
2996		"IPv4 multipath via second nexthop with source address"
2997
2998	cleanup
2999}
3000
3001ipv4_mpath_oif_nh_test()
3002{
3003	echo
3004	echo "IPv4 multipath oif with nexthop object test"
3005
3006	setup
3007
3008	set -e
3009	$IP link add dummy1 up type dummy
3010	$IP address add 192.0.2.1/28 dev dummy1
3011	$IP address add 192.0.2.17/32 dev lo
3012
3013	$IP nexthop add id 1 via 198.51.100.2 dev dummy0
3014	$IP nexthop add id 2 via 192.0.2.2 dev dummy1
3015	$IP nexthop add id 3 group 1/2
3016	$IP route add 203.0.113.0/24 nhid 3
3017	set +e
3018
3019	ipv4_mpath_oif_test_common "oif dummy0" "dummy0" \
3020		"IPv4 multipath via first nexthop"
3021
3022	ipv4_mpath_oif_test_common "oif dummy1" "dummy1" \
3023		"IPv4 multipath via second nexthop"
3024
3025	ipv4_mpath_oif_test_common "oif dummy0 from 192.0.2.17" "dummy0" \
3026		"IPv4 multipath via first nexthop with source address"
3027
3028	ipv4_mpath_oif_test_common "oif dummy1 from 192.0.2.17" "dummy1" \
3029		"IPv4 multipath via second nexthop with source address"
3030
3031	cleanup
3032}
3033
3034ipv4_mpath_oif_vrf_test()
3035{
3036	echo
3037	echo "IPv4 multipath oif with VRF test"
3038
3039	setup
3040
3041	set -e
3042	$IP -4 rule add pref 32765 table local
3043	$IP -4 rule del pref 0
3044	$IP link add name vrf-123 up type vrf table 123
3045	$IP link set dev dummy0 master vrf-123
3046	$IP link add dummy1 up master vrf-123 type dummy
3047	$IP address add 192.0.2.1/28 dev dummy1
3048	$IP address add 192.0.2.17/32 dev vrf-123
3049
3050	$IP route add 203.0.113.0/24 vrf vrf-123 \
3051		nexthop via 198.51.100.2 dev dummy0 \
3052		nexthop via 192.0.2.2 dev dummy1
3053	set +e
3054
3055	ipv4_mpath_oif_test_common "oif dummy0" "dummy0" \
3056		"IPv4 multipath via first nexthop"
3057
3058	ipv4_mpath_oif_test_common "oif dummy1" "dummy1" \
3059		"IPv4 multipath via second nexthop"
3060
3061	ipv4_mpath_oif_test_common "oif dummy0 from 192.0.2.17" "dummy0" \
3062		"IPv4 multipath via first nexthop with source address"
3063
3064	ipv4_mpath_oif_test_common "oif dummy1 from 192.0.2.17" "dummy1" \
3065		"IPv4 multipath via second nexthop with source address"
3066
3067	cleanup
3068}
3069
3070ipv6_mpath_oif_test_common()
3071{
3072	local get_param=$1; shift
3073	local expected_oif=$1; shift
3074	local test_name=$1; shift
3075	local tmp_file
3076
3077	tmp_file=$(mktemp)
3078
3079	for i in {1..100}; do
3080		$IP route get 2001:db8:10::${i} $get_param >> "$tmp_file"
3081	done
3082
3083	[[ $(grep "$expected_oif" "$tmp_file" | wc -l) -eq 100 ]]
3084	log_test $? 0 "$test_name"
3085
3086	rm "$tmp_file"
3087}
3088
3089ipv6_mpath_oif_test()
3090{
3091	echo
3092	echo "IPv6 multipath oif test"
3093
3094	setup
3095
3096	set -e
3097	$IP link add dummy1 up type dummy
3098	$IP address add 2001:db8:2::1/64 dev dummy1
3099	$IP address add 2001:db8:100::1/128 dev lo
3100
3101	$IP route add 2001:db8:10::/64 \
3102		nexthop via 2001:db8:1::2 dev dummy0 \
3103		nexthop via 2001:db8:2::2 dev dummy1
3104	set +e
3105
3106	ipv6_mpath_oif_test_common "oif dummy0" "dummy0" \
3107		"IPv6 multipath via first nexthop"
3108
3109	ipv6_mpath_oif_test_common "oif dummy1" "dummy1" \
3110		"IPv6 multipath via second nexthop"
3111
3112	ipv6_mpath_oif_test_common "oif dummy0 from 2001:db8:100::1" "dummy0" \
3113		"IPv6 multipath via first nexthop with source address"
3114
3115	ipv6_mpath_oif_test_common "oif dummy1 from 2001:db8:100::1" "dummy1" \
3116		"IPv6 multipath via second nexthop with source address"
3117
3118	cleanup
3119}
3120
3121ipv6_mpath_oif_nh_test()
3122{
3123	echo
3124	echo "IPv6 multipath oif with nexthop object test"
3125
3126	setup
3127
3128	set -e
3129	$IP link add dummy1 up type dummy
3130	$IP address add 2001:db8:2::1/64 dev dummy1
3131	$IP address add 2001:db8:100::1/128 dev lo
3132
3133	$IP nexthop add id 1 via 2001:db8:1::2 dev dummy0
3134	$IP nexthop add id 2 via 2001:db8:2::2 dev dummy1
3135	$IP nexthop add id 3 group 1/2
3136	$IP route add 2001:db8:10::/64 nhid 3
3137	set +e
3138
3139	ipv6_mpath_oif_test_common "oif dummy0" "dummy0" \
3140		"IPv6 multipath via first nexthop"
3141
3142	ipv6_mpath_oif_test_common "oif dummy1" "dummy1" \
3143		"IPv6 multipath via second nexthop"
3144
3145	ipv6_mpath_oif_test_common "oif dummy0 from 2001:db8:100::1" "dummy0" \
3146		"IPv6 multipath via first nexthop with source address"
3147
3148	ipv6_mpath_oif_test_common "oif dummy1 from 2001:db8:100::1" "dummy1" \
3149		"IPv6 multipath via second nexthop with source address"
3150
3151	cleanup
3152}
3153
3154ipv6_mpath_oif_vrf_test()
3155{
3156	echo
3157	echo "IPv6 multipath oif with VRF test"
3158
3159	setup
3160
3161	set -e
3162	$NS_EXEC sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
3163	$IP -6 rule add pref 32765 table local
3164	$IP -6 rule del pref 0
3165	$IP link add name vrf-123 up type vrf table 123
3166	$IP link set dev dummy0 master vrf-123
3167	$IP link add dummy1 up master vrf-123 type dummy
3168	$IP address add 2001:db8:2::1/64 dev dummy1
3169	$IP address add 2001:db8:100::1/128 dev vrf-123
3170
3171	$IP route add 2001:db8:10::/64 vrf vrf-123 \
3172		nexthop via 2001:db8:1::2 dev dummy0 \
3173		nexthop via 2001:db8:2::2 dev dummy1
3174	set +e
3175
3176	ipv6_mpath_oif_test_common "oif dummy0" "dummy0" \
3177		"IPv6 multipath via first nexthop"
3178
3179	ipv6_mpath_oif_test_common "oif dummy1" "dummy1" \
3180		"IPv6 multipath via second nexthop"
3181
3182	ipv6_mpath_oif_test_common "oif dummy0 from 2001:db8:100::1" "dummy0" \
3183		"IPv6 multipath via first nexthop with source address"
3184
3185	ipv6_mpath_oif_test_common "oif dummy1 from 2001:db8:100::1" "dummy1" \
3186		"IPv6 multipath via second nexthop with source address"
3187
3188	cleanup
3189}
3190
3191################################################################################
3192# usage
3193
3194usage()
3195{
3196	cat <<EOF
3197usage: ${0##*/} OPTS
3198
3199        -t <test>   Test(s) to run (default: all)
3200                    (options: $TESTS)
3201        -p          Pause on fail
3202        -P          Pause after each test before cleanup
3203        -v          verbose mode (show commands and output)
3204EOF
3205}
3206
3207################################################################################
3208# main
3209
3210trap cleanup EXIT
3211
3212while getopts :t:pPhv o
3213do
3214	case $o in
3215		t) TESTS=$OPTARG;;
3216		p) PAUSE_ON_FAIL=yes;;
3217		P) PAUSE=yes;;
3218		v) VERBOSE=$(($VERBOSE + 1));;
3219		h) usage; exit 0;;
3220		*) usage; exit 1;;
3221	esac
3222done
3223
3224PEER_CMD="ip netns exec ${PEER_NS}"
3225
3226# make sure we don't pause twice
3227[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
3228
3229if [ "$(id -u)" -ne 0 ];then
3230	echo "SKIP: Need root privileges"
3231	exit $ksft_skip;
3232fi
3233
3234if [ ! -x "$(command -v ip)" ]; then
3235	echo "SKIP: Could not run test without ip tool"
3236	exit $ksft_skip
3237fi
3238
3239ip route help 2>&1 | grep -q fibmatch
3240if [ $? -ne 0 ]; then
3241	echo "SKIP: iproute2 too old, missing fibmatch"
3242	exit $ksft_skip
3243fi
3244
3245# start clean
3246cleanup &> /dev/null
3247
3248for t in $TESTS
3249do
3250	case $t in
3251	fib_unreg_test|unregister)	fib_unreg_test;;
3252	fib_down_test|down)		fib_down_test;;
3253	fib_carrier_test|carrier)	fib_carrier_test;;
3254	fib_rp_filter_test|rp_filter)	fib_rp_filter_test;;
3255	fib_nexthop_test|nexthop)	fib_nexthop_test;;
3256	fib_notify_test|ipv4_notify)	fib_notify_test;;
3257	fib6_notify_test|ipv6_notify)	fib6_notify_test;;
3258	fib_suppress_test|suppress)	fib_suppress_test;;
3259	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
3260	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
3261	ipv6_addr_metric)		ipv6_addr_metric_test;;
3262	ipv4_addr_metric)		ipv4_addr_metric_test;;
3263	ipv4_del_addr)			ipv4_del_addr_test;;
3264	ipv6_del_addr)			ipv6_del_addr_test;;
3265	ipv6_route_metrics)		ipv6_route_metrics_test;;
3266	ipv4_route_metrics)		ipv4_route_metrics_test;;
3267	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
3268	ipv4_mangle)			ipv4_mangle_test;;
3269	ipv6_mangle)			ipv6_mangle_test;;
3270	ipv4_bcast_neigh)		ipv4_bcast_neigh_test;;
3271	fib6_gc_test|ipv6_gc)		fib6_gc_test;;
3272	ipv4_mpath_list)		ipv4_mpath_list_test;;
3273	ipv6_mpath_list)		ipv6_mpath_list_test;;
3274	ipv4_mpath_balance)		ipv4_mpath_balance_test;;
3275	ipv6_mpath_balance)		ipv6_mpath_balance_test;;
3276	ipv4_mpath_balance_preferred)	ipv4_mpath_balance_preferred_test;;
3277	ipv4_mpath_oif)			ipv4_mpath_oif_test;;
3278	ipv4_mpath_oif_nh)		ipv4_mpath_oif_nh_test;;
3279	ipv4_mpath_oif_vrf)		ipv4_mpath_oif_vrf_test;;
3280	ipv6_mpath_oif)			ipv6_mpath_oif_test;;
3281	ipv6_mpath_oif_nh)		ipv6_mpath_oif_nh_test;;
3282	ipv6_mpath_oif_vrf)		ipv6_mpath_oif_vrf_test;;
3283	fib6_ra_to_static)		fib6_ra_to_static;;
3284	fib6_temp_addr_renewal)		fib6_temp_addr_renewal;;
3285
3286	help) echo "Test names: $TESTS"; exit 0;;
3287	esac
3288done
3289
3290if [ "$TESTS" != "none" ]; then
3291	printf "\nTests passed: %3d\n" ${nsuccess}
3292	printf "Tests failed: %3d\n"   ${nfail}
3293fi
3294
3295exit $ret
3296