xref: /linux/tools/testing/selftests/net/fib_tests.sh (revision e9f0878c4b2004ac19581274c1ae4c61ae3ca70e)
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.
6
7ret=0
8# Kselftest framework requirement - SKIP code is 4.
9ksft_skip=4
10
11# all tests in this script. Can be overridden with -t option
12TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric"
13VERBOSE=0
14PAUSE_ON_FAIL=no
15PAUSE=no
16IP="ip -netns testns"
17
18log_test()
19{
20	local rc=$1
21	local expected=$2
22	local msg="$3"
23
24	if [ ${rc} -eq ${expected} ]; then
25		printf "    TEST: %-60s  [ OK ]\n" "${msg}"
26		nsuccess=$((nsuccess+1))
27	else
28		ret=1
29		nfail=$((nfail+1))
30		printf "    TEST: %-60s  [FAIL]\n" "${msg}"
31		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
32		echo
33			echo "hit enter to continue, 'q' to quit"
34			read a
35			[ "$a" = "q" ] && exit 1
36		fi
37	fi
38
39	if [ "${PAUSE}" = "yes" ]; then
40		echo
41		echo "hit enter to continue, 'q' to quit"
42		read a
43		[ "$a" = "q" ] && exit 1
44	fi
45}
46
47setup()
48{
49	set -e
50	ip netns add testns
51	$IP link set dev lo up
52
53	$IP link add dummy0 type dummy
54	$IP link set dev dummy0 up
55	$IP address add 198.51.100.1/24 dev dummy0
56	$IP -6 address add 2001:db8:1::1/64 dev dummy0
57	set +e
58
59}
60
61cleanup()
62{
63	$IP link del dev dummy0 &> /dev/null
64	ip netns del testns
65}
66
67get_linklocal()
68{
69	local dev=$1
70	local addr
71
72	addr=$($IP -6 -br addr show dev ${dev} | \
73	awk '{
74		for (i = 3; i <= NF; ++i) {
75			if ($i ~ /^fe80/)
76				print $i
77		}
78	}'
79	)
80	addr=${addr/\/*}
81
82	[ -z "$addr" ] && return 1
83
84	echo $addr
85
86	return 0
87}
88
89fib_unreg_unicast_test()
90{
91	echo
92	echo "Single path route test"
93
94	setup
95
96	echo "    Start point"
97	$IP route get fibmatch 198.51.100.2 &> /dev/null
98	log_test $? 0 "IPv4 fibmatch"
99	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
100	log_test $? 0 "IPv6 fibmatch"
101
102	set -e
103	$IP link del dev dummy0
104	set +e
105
106	echo "    Nexthop device deleted"
107	$IP route get fibmatch 198.51.100.2 &> /dev/null
108	log_test $? 2 "IPv4 fibmatch - no route"
109	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
110	log_test $? 2 "IPv6 fibmatch - no route"
111
112	cleanup
113}
114
115fib_unreg_multipath_test()
116{
117
118	echo
119	echo "Multipath route test"
120
121	setup
122
123	set -e
124	$IP link add dummy1 type dummy
125	$IP link set dev dummy1 up
126	$IP address add 192.0.2.1/24 dev dummy1
127	$IP -6 address add 2001:db8:2::1/64 dev dummy1
128
129	$IP route add 203.0.113.0/24 \
130		nexthop via 198.51.100.2 dev dummy0 \
131		nexthop via 192.0.2.2 dev dummy1
132	$IP -6 route add 2001:db8:3::/64 \
133		nexthop via 2001:db8:1::2 dev dummy0 \
134		nexthop via 2001:db8:2::2 dev dummy1
135	set +e
136
137	echo "    Start point"
138	$IP route get fibmatch 203.0.113.1 &> /dev/null
139	log_test $? 0 "IPv4 fibmatch"
140	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
141	log_test $? 0 "IPv6 fibmatch"
142
143	set -e
144	$IP link del dev dummy0
145	set +e
146
147	echo "    One nexthop device deleted"
148	$IP route get fibmatch 203.0.113.1 &> /dev/null
149	log_test $? 2 "IPv4 - multipath route removed on delete"
150
151	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
152	# In IPv6 we do not flush the entire multipath route.
153	log_test $? 0 "IPv6 - multipath down to single path"
154
155	set -e
156	$IP link del dev dummy1
157	set +e
158
159	echo "    Second nexthop device deleted"
160	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
161	log_test $? 2 "IPv6 - no route"
162
163	cleanup
164}
165
166fib_unreg_test()
167{
168	fib_unreg_unicast_test
169	fib_unreg_multipath_test
170}
171
172fib_down_unicast_test()
173{
174	echo
175	echo "Single path, admin down"
176
177	setup
178
179	echo "    Start point"
180	$IP route get fibmatch 198.51.100.2 &> /dev/null
181	log_test $? 0 "IPv4 fibmatch"
182	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
183	log_test $? 0 "IPv6 fibmatch"
184
185	set -e
186	$IP link set dev dummy0 down
187	set +e
188
189	echo "    Route deleted on down"
190	$IP route get fibmatch 198.51.100.2 &> /dev/null
191	log_test $? 2 "IPv4 fibmatch"
192	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
193	log_test $? 2 "IPv6 fibmatch"
194
195	cleanup
196}
197
198fib_down_multipath_test_do()
199{
200	local down_dev=$1
201	local up_dev=$2
202
203	$IP route get fibmatch 203.0.113.1 \
204		oif $down_dev &> /dev/null
205	log_test $? 2 "IPv4 fibmatch on down device"
206	$IP -6 route get fibmatch 2001:db8:3::1 \
207		oif $down_dev &> /dev/null
208	log_test $? 2 "IPv6 fibmatch on down device"
209
210	$IP route get fibmatch 203.0.113.1 \
211		oif $up_dev &> /dev/null
212	log_test $? 0 "IPv4 fibmatch on up device"
213	$IP -6 route get fibmatch 2001:db8:3::1 \
214		oif $up_dev &> /dev/null
215	log_test $? 0 "IPv6 fibmatch on up device"
216
217	$IP route get fibmatch 203.0.113.1 | \
218		grep $down_dev | grep -q "dead linkdown"
219	log_test $? 0 "IPv4 flags on down device"
220	$IP -6 route get fibmatch 2001:db8:3::1 | \
221		grep $down_dev | grep -q "dead linkdown"
222	log_test $? 0 "IPv6 flags on down device"
223
224	$IP route get fibmatch 203.0.113.1 | \
225		grep $up_dev | grep -q "dead linkdown"
226	log_test $? 1 "IPv4 flags on up device"
227	$IP -6 route get fibmatch 2001:db8:3::1 | \
228		grep $up_dev | grep -q "dead linkdown"
229	log_test $? 1 "IPv6 flags on up device"
230}
231
232fib_down_multipath_test()
233{
234	echo
235	echo "Admin down multipath"
236
237	setup
238
239	set -e
240	$IP link add dummy1 type dummy
241	$IP link set dev dummy1 up
242
243	$IP address add 192.0.2.1/24 dev dummy1
244	$IP -6 address add 2001:db8:2::1/64 dev dummy1
245
246	$IP route add 203.0.113.0/24 \
247		nexthop via 198.51.100.2 dev dummy0 \
248		nexthop via 192.0.2.2 dev dummy1
249	$IP -6 route add 2001:db8:3::/64 \
250		nexthop via 2001:db8:1::2 dev dummy0 \
251		nexthop via 2001:db8:2::2 dev dummy1
252	set +e
253
254	echo "    Verify start point"
255	$IP route get fibmatch 203.0.113.1 &> /dev/null
256	log_test $? 0 "IPv4 fibmatch"
257
258	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
259	log_test $? 0 "IPv6 fibmatch"
260
261	set -e
262	$IP link set dev dummy0 down
263	set +e
264
265	echo "    One device down, one up"
266	fib_down_multipath_test_do "dummy0" "dummy1"
267
268	set -e
269	$IP link set dev dummy0 up
270	$IP link set dev dummy1 down
271	set +e
272
273	echo "    Other device down and up"
274	fib_down_multipath_test_do "dummy1" "dummy0"
275
276	set -e
277	$IP link set dev dummy0 down
278	set +e
279
280	echo "    Both devices down"
281	$IP route get fibmatch 203.0.113.1 &> /dev/null
282	log_test $? 2 "IPv4 fibmatch"
283	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
284	log_test $? 2 "IPv6 fibmatch"
285
286	$IP link del dev dummy1
287	cleanup
288}
289
290fib_down_test()
291{
292	fib_down_unicast_test
293	fib_down_multipath_test
294}
295
296# Local routes should not be affected when carrier changes.
297fib_carrier_local_test()
298{
299	echo
300	echo "Local carrier tests - single path"
301
302	setup
303
304	set -e
305	$IP link set dev dummy0 carrier on
306	set +e
307
308	echo "    Start point"
309	$IP route get fibmatch 198.51.100.1 &> /dev/null
310	log_test $? 0 "IPv4 fibmatch"
311	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
312	log_test $? 0 "IPv6 fibmatch"
313
314	$IP route get fibmatch 198.51.100.1 | \
315		grep -q "linkdown"
316	log_test $? 1 "IPv4 - no linkdown flag"
317	$IP -6 route get fibmatch 2001:db8:1::1 | \
318		grep -q "linkdown"
319	log_test $? 1 "IPv6 - no linkdown flag"
320
321	set -e
322	$IP link set dev dummy0 carrier off
323	sleep 1
324	set +e
325
326	echo "    Carrier off on nexthop"
327	$IP route get fibmatch 198.51.100.1 &> /dev/null
328	log_test $? 0 "IPv4 fibmatch"
329	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
330	log_test $? 0 "IPv6 fibmatch"
331
332	$IP route get fibmatch 198.51.100.1 | \
333		grep -q "linkdown"
334	log_test $? 1 "IPv4 - linkdown flag set"
335	$IP -6 route get fibmatch 2001:db8:1::1 | \
336		grep -q "linkdown"
337	log_test $? 1 "IPv6 - linkdown flag set"
338
339	set -e
340	$IP address add 192.0.2.1/24 dev dummy0
341	$IP -6 address add 2001:db8:2::1/64 dev dummy0
342	set +e
343
344	echo "    Route to local address with carrier down"
345	$IP route get fibmatch 192.0.2.1 &> /dev/null
346	log_test $? 0 "IPv4 fibmatch"
347	$IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
348	log_test $? 0 "IPv6 fibmatch"
349
350	$IP route get fibmatch 192.0.2.1 | \
351		grep -q "linkdown"
352	log_test $? 1 "IPv4 linkdown flag set"
353	$IP -6 route get fibmatch 2001:db8:2::1 | \
354		grep -q "linkdown"
355	log_test $? 1 "IPv6 linkdown flag set"
356
357	cleanup
358}
359
360fib_carrier_unicast_test()
361{
362	ret=0
363
364	echo
365	echo "Single path route carrier test"
366
367	setup
368
369	set -e
370	$IP link set dev dummy0 carrier on
371	set +e
372
373	echo "    Start point"
374	$IP route get fibmatch 198.51.100.2 &> /dev/null
375	log_test $? 0 "IPv4 fibmatch"
376	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
377	log_test $? 0 "IPv6 fibmatch"
378
379	$IP route get fibmatch 198.51.100.2 | \
380		grep -q "linkdown"
381	log_test $? 1 "IPv4 no linkdown flag"
382	$IP -6 route get fibmatch 2001:db8:1::2 | \
383		grep -q "linkdown"
384	log_test $? 1 "IPv6 no linkdown flag"
385
386	set -e
387	$IP link set dev dummy0 carrier off
388	set +e
389
390	echo "    Carrier down"
391	$IP route get fibmatch 198.51.100.2 &> /dev/null
392	log_test $? 0 "IPv4 fibmatch"
393	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
394	log_test $? 0 "IPv6 fibmatch"
395
396	$IP route get fibmatch 198.51.100.2 | \
397		grep -q "linkdown"
398	log_test $? 0 "IPv4 linkdown flag set"
399	$IP -6 route get fibmatch 2001:db8:1::2 | \
400		grep -q "linkdown"
401	log_test $? 0 "IPv6 linkdown flag set"
402
403	set -e
404	$IP address add 192.0.2.1/24 dev dummy0
405	$IP -6 address add 2001:db8:2::1/64 dev dummy0
406	set +e
407
408	echo "    Second address added with carrier down"
409	$IP route get fibmatch 192.0.2.2 &> /dev/null
410	log_test $? 0 "IPv4 fibmatch"
411	$IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
412	log_test $? 0 "IPv6 fibmatch"
413
414	$IP route get fibmatch 192.0.2.2 | \
415		grep -q "linkdown"
416	log_test $? 0 "IPv4 linkdown flag set"
417	$IP -6 route get fibmatch 2001:db8:2::2 | \
418		grep -q "linkdown"
419	log_test $? 0 "IPv6 linkdown flag set"
420
421	cleanup
422}
423
424fib_carrier_test()
425{
426	fib_carrier_local_test
427	fib_carrier_unicast_test
428}
429
430################################################################################
431# Tests on nexthop spec
432
433# run 'ip route add' with given spec
434add_rt()
435{
436	local desc="$1"
437	local erc=$2
438	local vrf=$3
439	local pfx=$4
440	local gw=$5
441	local dev=$6
442	local cmd out rc
443
444	[ "$vrf" = "-" ] && vrf="default"
445	[ -n "$gw" ] && gw="via $gw"
446	[ -n "$dev" ] && dev="dev $dev"
447
448	cmd="$IP route add vrf $vrf $pfx $gw $dev"
449	if [ "$VERBOSE" = "1" ]; then
450		printf "\n    COMMAND: $cmd\n"
451	fi
452
453	out=$(eval $cmd 2>&1)
454	rc=$?
455	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
456		echo "    $out"
457	fi
458	log_test $rc $erc "$desc"
459}
460
461fib4_nexthop()
462{
463	echo
464	echo "IPv4 nexthop tests"
465
466	echo "<<< write me >>>"
467}
468
469fib6_nexthop()
470{
471	local lldummy=$(get_linklocal dummy0)
472	local llv1=$(get_linklocal dummy0)
473
474	if [ -z "$lldummy" ]; then
475		echo "Failed to get linklocal address for dummy0"
476		return 1
477	fi
478	if [ -z "$llv1" ]; then
479		echo "Failed to get linklocal address for veth1"
480		return 1
481	fi
482
483	echo
484	echo "IPv6 nexthop tests"
485
486	add_rt "Directly connected nexthop, unicast address" 0 \
487		- 2001:db8:101::/64 2001:db8:1::2
488	add_rt "Directly connected nexthop, unicast address with device" 0 \
489		- 2001:db8:102::/64 2001:db8:1::2 "dummy0"
490	add_rt "Gateway is linklocal address" 0 \
491		- 2001:db8:103::1/64 $llv1 "veth0"
492
493	# fails because LL address requires a device
494	add_rt "Gateway is linklocal address, no device" 2 \
495		- 2001:db8:104::1/64 $llv1
496
497	# local address can not be a gateway
498	add_rt "Gateway can not be local unicast address" 2 \
499		- 2001:db8:105::/64 2001:db8:1::1
500	add_rt "Gateway can not be local unicast address, with device" 2 \
501		- 2001:db8:106::/64 2001:db8:1::1 "dummy0"
502	add_rt "Gateway can not be a local linklocal address" 2 \
503		- 2001:db8:107::1/64 $lldummy "dummy0"
504
505	# VRF tests
506	add_rt "Gateway can be local address in a VRF" 0 \
507		- 2001:db8:108::/64 2001:db8:51::2
508	add_rt "Gateway can be local address in a VRF, with device" 0 \
509		- 2001:db8:109::/64 2001:db8:51::2 "veth0"
510	add_rt "Gateway can be local linklocal address in a VRF" 0 \
511		- 2001:db8:110::1/64 $llv1 "veth0"
512
513	add_rt "Redirect to VRF lookup" 0 \
514		- 2001:db8:111::/64 "" "red"
515
516	add_rt "VRF route, gateway can be local address in default VRF" 0 \
517		red 2001:db8:112::/64 2001:db8:51::1
518
519	# local address in same VRF fails
520	add_rt "VRF route, gateway can not be a local address" 2 \
521		red 2001:db8:113::1/64 2001:db8:2::1
522	add_rt "VRF route, gateway can not be a local addr with device" 2 \
523		red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
524}
525
526# Default VRF:
527#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
528#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
529#
530# VRF red:
531#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
532#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
533#
534#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
535
536fib_nexthop_test()
537{
538	setup
539
540	set -e
541
542	$IP -4 rule add pref 32765 table local
543	$IP -4 rule del pref 0
544	$IP -6 rule add pref 32765 table local
545	$IP -6 rule del pref 0
546
547	$IP link add red type vrf table 1
548	$IP link set red up
549	$IP -4 route add vrf red unreachable default metric 4278198272
550	$IP -6 route add vrf red unreachable default metric 4278198272
551
552	$IP link add veth0 type veth peer name veth1
553	$IP link set dev veth0 up
554	$IP address add 192.0.2.1/24 dev veth0
555	$IP -6 address add 2001:db8:51::1/64 dev veth0
556
557	$IP link set dev veth1 vrf red up
558	$IP address add 192.0.2.2/24 dev veth1
559	$IP -6 address add 2001:db8:51::2/64 dev veth1
560
561	$IP link add dummy1 type dummy
562	$IP link set dev dummy1 vrf red up
563	$IP address add 192.168.2.1/24 dev dummy1
564	$IP -6 address add 2001:db8:2::1/64 dev dummy1
565	set +e
566
567	sleep 1
568	fib4_nexthop
569	fib6_nexthop
570
571	(
572	$IP link del dev dummy1
573	$IP link del veth0
574	$IP link del red
575	) 2>/dev/null
576	cleanup
577}
578
579################################################################################
580# Tests on route add and replace
581
582run_cmd()
583{
584	local cmd="$1"
585	local out
586	local stderr="2>/dev/null"
587
588	if [ "$VERBOSE" = "1" ]; then
589		printf "    COMMAND: $cmd\n"
590		stderr=
591	fi
592
593	out=$(eval $cmd $stderr)
594	rc=$?
595	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
596		echo "    $out"
597	fi
598
599	[ "$VERBOSE" = "1" ] && echo
600
601	return $rc
602}
603
604# add route for a prefix, flushing any existing routes first
605# expected to be the first step of a test
606add_route6()
607{
608	local pfx="$1"
609	local nh="$2"
610	local out
611
612	if [ "$VERBOSE" = "1" ]; then
613		echo
614		echo "    ##################################################"
615		echo
616	fi
617
618	run_cmd "$IP -6 ro flush ${pfx}"
619	[ $? -ne 0 ] && exit 1
620
621	out=$($IP -6 ro ls match ${pfx})
622	if [ -n "$out" ]; then
623		echo "Failed to flush routes for prefix used for tests."
624		exit 1
625	fi
626
627	run_cmd "$IP -6 ro add ${pfx} ${nh}"
628	if [ $? -ne 0 ]; then
629		echo "Failed to add initial route for test."
630		exit 1
631	fi
632}
633
634# add initial route - used in replace route tests
635add_initial_route6()
636{
637	add_route6 "2001:db8:104::/64" "$1"
638}
639
640check_route6()
641{
642	local pfx="2001:db8:104::/64"
643	local expected="$1"
644	local out
645	local rc=0
646
647	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
648	[ "${out}" = "${expected}" ] && return 0
649
650	if [ -z "${out}" ]; then
651		if [ "$VERBOSE" = "1" ]; then
652			printf "\nNo route entry found\n"
653			printf "Expected:\n"
654			printf "    ${expected}\n"
655		fi
656		return 1
657	fi
658
659	# tricky way to convert output to 1-line without ip's
660	# messy '\'; this drops all extra white space
661	out=$(echo ${out})
662	if [ "${out}" != "${expected}" ]; then
663		rc=1
664		if [ "${VERBOSE}" = "1" ]; then
665			printf "    Unexpected route entry. Have:\n"
666			printf "        ${out}\n"
667			printf "    Expected:\n"
668			printf "        ${expected}\n\n"
669		fi
670	fi
671
672	return $rc
673}
674
675route_cleanup()
676{
677	$IP li del red 2>/dev/null
678	$IP li del dummy1 2>/dev/null
679	$IP li del veth1 2>/dev/null
680	$IP li del veth3 2>/dev/null
681
682	cleanup &> /dev/null
683}
684
685route_setup()
686{
687	route_cleanup
688	setup
689
690	[ "${VERBOSE}" = "1" ] && set -x
691	set -e
692
693	$IP li add red up type vrf table 101
694	$IP li add veth1 type veth peer name veth2
695	$IP li add veth3 type veth peer name veth4
696
697	$IP li set veth1 up
698	$IP li set veth3 up
699	$IP li set veth2 vrf red up
700	$IP li set veth4 vrf red up
701	$IP li add dummy1 type dummy
702	$IP li set dummy1 vrf red up
703
704	$IP -6 addr add 2001:db8:101::1/64 dev veth1
705	$IP -6 addr add 2001:db8:101::2/64 dev veth2
706	$IP -6 addr add 2001:db8:103::1/64 dev veth3
707	$IP -6 addr add 2001:db8:103::2/64 dev veth4
708	$IP -6 addr add 2001:db8:104::1/64 dev dummy1
709
710	$IP addr add 172.16.101.1/24 dev veth1
711	$IP addr add 172.16.101.2/24 dev veth2
712	$IP addr add 172.16.103.1/24 dev veth3
713	$IP addr add 172.16.103.2/24 dev veth4
714	$IP addr add 172.16.104.1/24 dev dummy1
715
716	set +ex
717}
718
719# assumption is that basic add of a single path route works
720# otherwise just adding an address on an interface is broken
721ipv6_rt_add()
722{
723	local rc
724
725	echo
726	echo "IPv6 route add / append tests"
727
728	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
729	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
730	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
731	log_test $? 2 "Attempt to add duplicate route - gw"
732
733	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
734	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
735	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
736	log_test $? 2 "Attempt to add duplicate route - dev only"
737
738	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
739	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
740	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
741	log_test $? 2 "Attempt to add duplicate route - reject route"
742
743	# route append with same prefix adds a new route
744	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
745	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
746	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
747	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"
748	log_test $? 0 "Append nexthop to existing route - gw"
749
750	# insert mpath directly
751	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
752	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"
753	log_test $? 0 "Add multipath route"
754
755	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
756	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
757	log_test $? 2 "Attempt to add duplicate multipath route"
758
759	# insert of a second route without append but different metric
760	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
761	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
762	rc=$?
763	if [ $rc -eq 0 ]; then
764		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
765		rc=$?
766	fi
767	log_test $rc 0 "Route add with different metrics"
768
769	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
770	rc=$?
771	if [ $rc -eq 0 ]; then
772		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"
773		rc=$?
774	fi
775	log_test $rc 0 "Route delete with metric"
776}
777
778ipv6_rt_replace_single()
779{
780	# single path with single path
781	#
782	add_initial_route6 "via 2001:db8:101::2"
783	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
784	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
785	log_test $? 0 "Single path with single path"
786
787	# single path with multipath
788	#
789	add_initial_route6 "nexthop via 2001:db8:101::2"
790	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
791	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"
792	log_test $? 0 "Single path with multipath"
793
794	# single path with single path using MULTIPATH attribute
795	#
796	add_initial_route6 "via 2001:db8:101::2"
797	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
798	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
799	log_test $? 0 "Single path with single path via multipath attribute"
800
801	# route replace fails - invalid nexthop
802	add_initial_route6 "via 2001:db8:101::2"
803	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
804	if [ $? -eq 0 ]; then
805		# previous command is expected to fail so if it returns 0
806		# that means the test failed.
807		log_test 0 1 "Invalid nexthop"
808	else
809		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
810		log_test $? 0 "Invalid nexthop"
811	fi
812
813	# replace non-existent route
814	# - note use of change versus replace since ip adds NLM_F_CREATE
815	#   for replace
816	add_initial_route6 "via 2001:db8:101::2"
817	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
818	log_test $? 2 "Single path - replace of non-existent route"
819}
820
821ipv6_rt_replace_mpath()
822{
823	# multipath with multipath
824	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
825	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
826	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"
827	log_test $? 0 "Multipath with multipath"
828
829	# multipath with single
830	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
831	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
832	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
833	log_test $? 0 "Multipath with single path"
834
835	# multipath with single
836	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
837	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
838	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
839	log_test $? 0 "Multipath with single path via multipath attribute"
840
841	# route replace fails - invalid nexthop 1
842	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
843	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
844	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"
845	log_test $? 0 "Multipath - invalid first nexthop"
846
847	# route replace fails - invalid nexthop 2
848	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
849	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
850	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"
851	log_test $? 0 "Multipath - invalid second nexthop"
852
853	# multipath non-existent route
854	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
855	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
856	log_test $? 2 "Multipath - replace of non-existent route"
857}
858
859ipv6_rt_replace()
860{
861	echo
862	echo "IPv6 route replace tests"
863
864	ipv6_rt_replace_single
865	ipv6_rt_replace_mpath
866}
867
868ipv6_route_test()
869{
870	route_setup
871
872	ipv6_rt_add
873	ipv6_rt_replace
874
875	route_cleanup
876}
877
878ip_addr_metric_check()
879{
880	ip addr help 2>&1 | grep -q metric
881	if [ $? -ne 0 ]; then
882		echo "iproute2 command does not support metric for addresses. Skipping test"
883		return 1
884	fi
885
886	return 0
887}
888
889ipv6_addr_metric_test()
890{
891	local rc
892
893	echo
894	echo "IPv6 prefix route tests"
895
896	ip_addr_metric_check || return 1
897
898	setup
899
900	set -e
901	$IP li add dummy1 type dummy
902	$IP li add dummy2 type dummy
903	$IP li set dummy1 up
904	$IP li set dummy2 up
905
906	# default entry is metric 256
907	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
908	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
909	set +e
910
911	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
912	log_test $? 0 "Default metric"
913
914	set -e
915	run_cmd "$IP -6 addr flush dev dummy1"
916	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
917	set +e
918
919	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
920	log_test $? 0 "User specified metric on first device"
921
922	set -e
923	run_cmd "$IP -6 addr flush dev dummy2"
924	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
925	set +e
926
927	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
928	log_test $? 0 "User specified metric on second device"
929
930	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
931	rc=$?
932	if [ $rc -eq 0 ]; then
933		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
934		rc=$?
935	fi
936	log_test $rc 0 "Delete of address on first device"
937
938	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
939	rc=$?
940	if [ $rc -eq 0 ]; then
941		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
942		rc=$?
943	fi
944	log_test $rc 0 "Modify metric of address"
945
946	# verify prefix route removed on down
947	run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
948	run_cmd "$IP li set dev dummy2 down"
949	rc=$?
950	if [ $rc -eq 0 ]; then
951		check_route6 ""
952		rc=$?
953	fi
954	log_test $rc 0 "Prefix route removed on link down"
955
956	# verify prefix route re-inserted with assigned metric
957	run_cmd "$IP li set dev dummy2 up"
958	rc=$?
959	if [ $rc -eq 0 ]; then
960		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
961		rc=$?
962	fi
963	log_test $rc 0 "Prefix route with metric on link up"
964
965	$IP li del dummy1
966	$IP li del dummy2
967	cleanup
968}
969
970# add route for a prefix, flushing any existing routes first
971# expected to be the first step of a test
972add_route()
973{
974	local pfx="$1"
975	local nh="$2"
976	local out
977
978	if [ "$VERBOSE" = "1" ]; then
979		echo
980		echo "    ##################################################"
981		echo
982	fi
983
984	run_cmd "$IP ro flush ${pfx}"
985	[ $? -ne 0 ] && exit 1
986
987	out=$($IP ro ls match ${pfx})
988	if [ -n "$out" ]; then
989		echo "Failed to flush routes for prefix used for tests."
990		exit 1
991	fi
992
993	run_cmd "$IP ro add ${pfx} ${nh}"
994	if [ $? -ne 0 ]; then
995		echo "Failed to add initial route for test."
996		exit 1
997	fi
998}
999
1000# add initial route - used in replace route tests
1001add_initial_route()
1002{
1003	add_route "172.16.104.0/24" "$1"
1004}
1005
1006check_route()
1007{
1008	local pfx="172.16.104.0/24"
1009	local expected="$1"
1010	local out
1011	local rc=0
1012
1013	out=$($IP ro ls match ${pfx})
1014	[ "${out}" = "${expected}" ] && return 0
1015
1016	if [ -z "${out}" ]; then
1017		if [ "$VERBOSE" = "1" ]; then
1018			printf "\nNo route entry found\n"
1019			printf "Expected:\n"
1020			printf "    ${expected}\n"
1021		fi
1022		return 1
1023	fi
1024
1025	# tricky way to convert output to 1-line without ip's
1026	# messy '\'; this drops all extra white space
1027	out=$(echo ${out})
1028	if [ "${out}" != "${expected}" ]; then
1029		rc=1
1030		if [ "${VERBOSE}" = "1" ]; then
1031			printf "    Unexpected route entry. Have:\n"
1032			printf "        ${out}\n"
1033			printf "    Expected:\n"
1034			printf "        ${expected}\n\n"
1035		fi
1036	fi
1037
1038	return $rc
1039}
1040
1041# assumption is that basic add of a single path route works
1042# otherwise just adding an address on an interface is broken
1043ipv4_rt_add()
1044{
1045	local rc
1046
1047	echo
1048	echo "IPv4 route add / append tests"
1049
1050	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1051	add_route "172.16.104.0/24" "via 172.16.101.2"
1052	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1053	log_test $? 2 "Attempt to add duplicate route - gw"
1054
1055	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1056	add_route "172.16.104.0/24" "via 172.16.101.2"
1057	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1058	log_test $? 2 "Attempt to add duplicate route - dev only"
1059
1060	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1061	add_route "172.16.104.0/24" "via 172.16.101.2"
1062	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1063	log_test $? 2 "Attempt to add duplicate route - reject route"
1064
1065	# iproute2 prepend only sets NLM_F_CREATE
1066	# - adds a new route; does NOT convert existing route to ECMP
1067	add_route "172.16.104.0/24" "via 172.16.101.2"
1068	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1069	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"
1070	log_test $? 0 "Add new nexthop for existing prefix"
1071
1072	# route append with same prefix adds a new route
1073	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1074	add_route "172.16.104.0/24" "via 172.16.101.2"
1075	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1076	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"
1077	log_test $? 0 "Append nexthop to existing route - gw"
1078
1079	add_route "172.16.104.0/24" "via 172.16.101.2"
1080	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1081	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1082	log_test $? 0 "Append nexthop to existing route - dev only"
1083
1084	add_route "172.16.104.0/24" "via 172.16.101.2"
1085	run_cmd "$IP ro append unreachable 172.16.104.0/24"
1086	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1087	log_test $? 0 "Append nexthop to existing route - reject route"
1088
1089	run_cmd "$IP ro flush 172.16.104.0/24"
1090	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1091	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1092	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1093	log_test $? 0 "Append nexthop to existing reject route - gw"
1094
1095	run_cmd "$IP ro flush 172.16.104.0/24"
1096	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1097	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1098	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1099	log_test $? 0 "Append nexthop to existing reject route - dev only"
1100
1101	# insert mpath directly
1102	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1103	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"
1104	log_test $? 0 "add multipath route"
1105
1106	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1107	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1108	log_test $? 2 "Attempt to add duplicate multipath route"
1109
1110	# insert of a second route without append but different metric
1111	add_route "172.16.104.0/24" "via 172.16.101.2"
1112	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1113	rc=$?
1114	if [ $rc -eq 0 ]; then
1115		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1116		rc=$?
1117	fi
1118	log_test $rc 0 "Route add with different metrics"
1119
1120	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1121	rc=$?
1122	if [ $rc -eq 0 ]; then
1123		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"
1124		rc=$?
1125	fi
1126	log_test $rc 0 "Route delete with metric"
1127}
1128
1129ipv4_rt_replace_single()
1130{
1131	# single path with single path
1132	#
1133	add_initial_route "via 172.16.101.2"
1134	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1135	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1136	log_test $? 0 "Single path with single path"
1137
1138	# single path with multipath
1139	#
1140	add_initial_route "nexthop via 172.16.101.2"
1141	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1142	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"
1143	log_test $? 0 "Single path with multipath"
1144
1145	# single path with reject
1146	#
1147	add_initial_route "nexthop via 172.16.101.2"
1148	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1149	check_route "unreachable 172.16.104.0/24"
1150	log_test $? 0 "Single path with reject route"
1151
1152	# single path with single path using MULTIPATH attribute
1153	#
1154	add_initial_route "via 172.16.101.2"
1155	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1156	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1157	log_test $? 0 "Single path with single path via multipath attribute"
1158
1159	# route replace fails - invalid nexthop
1160	add_initial_route "via 172.16.101.2"
1161	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1162	if [ $? -eq 0 ]; then
1163		# previous command is expected to fail so if it returns 0
1164		# that means the test failed.
1165		log_test 0 1 "Invalid nexthop"
1166	else
1167		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1168		log_test $? 0 "Invalid nexthop"
1169	fi
1170
1171	# replace non-existent route
1172	# - note use of change versus replace since ip adds NLM_F_CREATE
1173	#   for replace
1174	add_initial_route "via 172.16.101.2"
1175	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1176	log_test $? 2 "Single path - replace of non-existent route"
1177}
1178
1179ipv4_rt_replace_mpath()
1180{
1181	# multipath with multipath
1182	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1183	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1184	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"
1185	log_test $? 0 "Multipath with multipath"
1186
1187	# multipath with single
1188	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1189	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1190	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1191	log_test $? 0 "Multipath with single path"
1192
1193	# multipath with single
1194	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1195	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1196	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1197	log_test $? 0 "Multipath with single path via multipath attribute"
1198
1199	# multipath with reject
1200	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1201	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1202	check_route "unreachable 172.16.104.0/24"
1203	log_test $? 0 "Multipath with reject route"
1204
1205	# route replace fails - invalid nexthop 1
1206	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1207	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1208	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"
1209	log_test $? 0 "Multipath - invalid first nexthop"
1210
1211	# route replace fails - invalid nexthop 2
1212	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1213	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1214	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"
1215	log_test $? 0 "Multipath - invalid second nexthop"
1216
1217	# multipath non-existent route
1218	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1219	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1220	log_test $? 2 "Multipath - replace of non-existent route"
1221}
1222
1223ipv4_rt_replace()
1224{
1225	echo
1226	echo "IPv4 route replace tests"
1227
1228	ipv4_rt_replace_single
1229	ipv4_rt_replace_mpath
1230}
1231
1232ipv4_route_test()
1233{
1234	route_setup
1235
1236	ipv4_rt_add
1237	ipv4_rt_replace
1238
1239	route_cleanup
1240}
1241
1242ipv4_addr_metric_test()
1243{
1244	local rc
1245
1246	echo
1247	echo "IPv4 prefix route tests"
1248
1249	ip_addr_metric_check || return 1
1250
1251	setup
1252
1253	set -e
1254	$IP li add dummy1 type dummy
1255	$IP li add dummy2 type dummy
1256	$IP li set dummy1 up
1257	$IP li set dummy2 up
1258
1259	# default entry is metric 256
1260	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1261	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1262	set +e
1263
1264	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"
1265	log_test $? 0 "Default metric"
1266
1267	set -e
1268	run_cmd "$IP addr flush dev dummy1"
1269	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1270	set +e
1271
1272	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"
1273	log_test $? 0 "User specified metric on first device"
1274
1275	set -e
1276	run_cmd "$IP addr flush dev dummy2"
1277	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1278	set +e
1279
1280	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"
1281	log_test $? 0 "User specified metric on second device"
1282
1283	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1284	rc=$?
1285	if [ $rc -eq 0 ]; then
1286		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1287		rc=$?
1288	fi
1289	log_test $rc 0 "Delete of address on first device"
1290
1291	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1292	rc=$?
1293	if [ $rc -eq 0 ]; then
1294		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1295		rc=$?
1296	fi
1297	log_test $rc 0 "Modify metric of address"
1298
1299	# verify prefix route removed on down
1300	run_cmd "$IP li set dev dummy2 down"
1301	rc=$?
1302	if [ $rc -eq 0 ]; then
1303		check_route ""
1304		rc=$?
1305	fi
1306	log_test $rc 0 "Prefix route removed on link down"
1307
1308	# verify prefix route re-inserted with assigned metric
1309	run_cmd "$IP li set dev dummy2 up"
1310	rc=$?
1311	if [ $rc -eq 0 ]; then
1312		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1313		rc=$?
1314	fi
1315	log_test $rc 0 "Prefix route with metric on link up"
1316
1317	$IP li del dummy1
1318	$IP li del dummy2
1319	cleanup
1320}
1321
1322################################################################################
1323# usage
1324
1325usage()
1326{
1327	cat <<EOF
1328usage: ${0##*/} OPTS
1329
1330        -t <test>   Test(s) to run (default: all)
1331                    (options: $TESTS)
1332        -p          Pause on fail
1333        -P          Pause after each test before cleanup
1334        -v          verbose mode (show commands and output)
1335EOF
1336}
1337
1338################################################################################
1339# main
1340
1341while getopts :t:pPhv o
1342do
1343	case $o in
1344		t) TESTS=$OPTARG;;
1345		p) PAUSE_ON_FAIL=yes;;
1346		P) PAUSE=yes;;
1347		v) VERBOSE=$(($VERBOSE + 1));;
1348		h) usage; exit 0;;
1349		*) usage; exit 1;;
1350	esac
1351done
1352
1353PEER_CMD="ip netns exec ${PEER_NS}"
1354
1355# make sure we don't pause twice
1356[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1357
1358if [ "$(id -u)" -ne 0 ];then
1359	echo "SKIP: Need root privileges"
1360	exit $ksft_skip;
1361fi
1362
1363if [ ! -x "$(command -v ip)" ]; then
1364	echo "SKIP: Could not run test without ip tool"
1365	exit $ksft_skip
1366fi
1367
1368ip route help 2>&1 | grep -q fibmatch
1369if [ $? -ne 0 ]; then
1370	echo "SKIP: iproute2 too old, missing fibmatch"
1371	exit $ksft_skip
1372fi
1373
1374# start clean
1375cleanup &> /dev/null
1376
1377for t in $TESTS
1378do
1379	case $t in
1380	fib_unreg_test|unregister)	fib_unreg_test;;
1381	fib_down_test|down)		fib_down_test;;
1382	fib_carrier_test|carrier)	fib_carrier_test;;
1383	fib_nexthop_test|nexthop)	fib_nexthop_test;;
1384	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
1385	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
1386	ipv6_addr_metric)		ipv6_addr_metric_test;;
1387	ipv4_addr_metric)		ipv4_addr_metric_test;;
1388
1389	help) echo "Test names: $TESTS"; exit 0;;
1390	esac
1391done
1392
1393if [ "$TESTS" != "none" ]; then
1394	printf "\nTests passed: %3d\n" ${nsuccess}
1395	printf "Tests failed: %3d\n"   ${nfail}
1396fi
1397
1398exit $ret
1399