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