• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	sleep 1
389	set +e
390
391	echo "    Carrier down"
392	$IP route get fibmatch 198.51.100.2 &> /dev/null
393	log_test $? 0 "IPv4 fibmatch"
394	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
395	log_test $? 0 "IPv6 fibmatch"
396
397	$IP route get fibmatch 198.51.100.2 | \
398		grep -q "linkdown"
399	log_test $? 0 "IPv4 linkdown flag set"
400	$IP -6 route get fibmatch 2001:db8:1::2 | \
401		grep -q "linkdown"
402	log_test $? 0 "IPv6 linkdown flag set"
403
404	set -e
405	$IP address add 192.0.2.1/24 dev dummy0
406	$IP -6 address add 2001:db8:2::1/64 dev dummy0
407	set +e
408
409	echo "    Second address added with carrier down"
410	$IP route get fibmatch 192.0.2.2 &> /dev/null
411	log_test $? 0 "IPv4 fibmatch"
412	$IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
413	log_test $? 0 "IPv6 fibmatch"
414
415	$IP route get fibmatch 192.0.2.2 | \
416		grep -q "linkdown"
417	log_test $? 0 "IPv4 linkdown flag set"
418	$IP -6 route get fibmatch 2001:db8:2::2 | \
419		grep -q "linkdown"
420	log_test $? 0 "IPv6 linkdown flag set"
421
422	cleanup
423}
424
425fib_carrier_test()
426{
427	fib_carrier_local_test
428	fib_carrier_unicast_test
429}
430
431################################################################################
432# Tests on nexthop spec
433
434# run 'ip route add' with given spec
435add_rt()
436{
437	local desc="$1"
438	local erc=$2
439	local vrf=$3
440	local pfx=$4
441	local gw=$5
442	local dev=$6
443	local cmd out rc
444
445	[ "$vrf" = "-" ] && vrf="default"
446	[ -n "$gw" ] && gw="via $gw"
447	[ -n "$dev" ] && dev="dev $dev"
448
449	cmd="$IP route add vrf $vrf $pfx $gw $dev"
450	if [ "$VERBOSE" = "1" ]; then
451		printf "\n    COMMAND: $cmd\n"
452	fi
453
454	out=$(eval $cmd 2>&1)
455	rc=$?
456	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
457		echo "    $out"
458	fi
459	log_test $rc $erc "$desc"
460}
461
462fib4_nexthop()
463{
464	echo
465	echo "IPv4 nexthop tests"
466
467	echo "<<< write me >>>"
468}
469
470fib6_nexthop()
471{
472	local lldummy=$(get_linklocal dummy0)
473	local llv1=$(get_linklocal dummy0)
474
475	if [ -z "$lldummy" ]; then
476		echo "Failed to get linklocal address for dummy0"
477		return 1
478	fi
479	if [ -z "$llv1" ]; then
480		echo "Failed to get linklocal address for veth1"
481		return 1
482	fi
483
484	echo
485	echo "IPv6 nexthop tests"
486
487	add_rt "Directly connected nexthop, unicast address" 0 \
488		- 2001:db8:101::/64 2001:db8:1::2
489	add_rt "Directly connected nexthop, unicast address with device" 0 \
490		- 2001:db8:102::/64 2001:db8:1::2 "dummy0"
491	add_rt "Gateway is linklocal address" 0 \
492		- 2001:db8:103::1/64 $llv1 "veth0"
493
494	# fails because LL address requires a device
495	add_rt "Gateway is linklocal address, no device" 2 \
496		- 2001:db8:104::1/64 $llv1
497
498	# local address can not be a gateway
499	add_rt "Gateway can not be local unicast address" 2 \
500		- 2001:db8:105::/64 2001:db8:1::1
501	add_rt "Gateway can not be local unicast address, with device" 2 \
502		- 2001:db8:106::/64 2001:db8:1::1 "dummy0"
503	add_rt "Gateway can not be a local linklocal address" 2 \
504		- 2001:db8:107::1/64 $lldummy "dummy0"
505
506	# VRF tests
507	add_rt "Gateway can be local address in a VRF" 0 \
508		- 2001:db8:108::/64 2001:db8:51::2
509	add_rt "Gateway can be local address in a VRF, with device" 0 \
510		- 2001:db8:109::/64 2001:db8:51::2 "veth0"
511	add_rt "Gateway can be local linklocal address in a VRF" 0 \
512		- 2001:db8:110::1/64 $llv1 "veth0"
513
514	add_rt "Redirect to VRF lookup" 0 \
515		- 2001:db8:111::/64 "" "red"
516
517	add_rt "VRF route, gateway can be local address in default VRF" 0 \
518		red 2001:db8:112::/64 2001:db8:51::1
519
520	# local address in same VRF fails
521	add_rt "VRF route, gateway can not be a local address" 2 \
522		red 2001:db8:113::1/64 2001:db8:2::1
523	add_rt "VRF route, gateway can not be a local addr with device" 2 \
524		red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
525}
526
527# Default VRF:
528#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
529#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
530#
531# VRF red:
532#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
533#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
534#
535#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
536
537fib_nexthop_test()
538{
539	setup
540
541	set -e
542
543	$IP -4 rule add pref 32765 table local
544	$IP -4 rule del pref 0
545	$IP -6 rule add pref 32765 table local
546	$IP -6 rule del pref 0
547
548	$IP link add red type vrf table 1
549	$IP link set red up
550	$IP -4 route add vrf red unreachable default metric 4278198272
551	$IP -6 route add vrf red unreachable default metric 4278198272
552
553	$IP link add veth0 type veth peer name veth1
554	$IP link set dev veth0 up
555	$IP address add 192.0.2.1/24 dev veth0
556	$IP -6 address add 2001:db8:51::1/64 dev veth0
557
558	$IP link set dev veth1 vrf red up
559	$IP address add 192.0.2.2/24 dev veth1
560	$IP -6 address add 2001:db8:51::2/64 dev veth1
561
562	$IP link add dummy1 type dummy
563	$IP link set dev dummy1 vrf red up
564	$IP address add 192.168.2.1/24 dev dummy1
565	$IP -6 address add 2001:db8:2::1/64 dev dummy1
566	set +e
567
568	sleep 1
569	fib4_nexthop
570	fib6_nexthop
571
572	(
573	$IP link del dev dummy1
574	$IP link del veth0
575	$IP link del red
576	) 2>/dev/null
577	cleanup
578}
579
580################################################################################
581# Tests on route add and replace
582
583run_cmd()
584{
585	local cmd="$1"
586	local out
587	local stderr="2>/dev/null"
588
589	if [ "$VERBOSE" = "1" ]; then
590		printf "    COMMAND: $cmd\n"
591		stderr=
592	fi
593
594	out=$(eval $cmd $stderr)
595	rc=$?
596	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
597		echo "    $out"
598	fi
599
600	[ "$VERBOSE" = "1" ] && echo
601
602	return $rc
603}
604
605check_expected()
606{
607	local out="$1"
608	local expected="$2"
609	local rc=0
610
611	[ "${out}" = "${expected}" ] && return 0
612
613	if [ -z "${out}" ]; then
614		if [ "$VERBOSE" = "1" ]; then
615			printf "\nNo route entry found\n"
616			printf "Expected:\n"
617			printf "    ${expected}\n"
618		fi
619		return 1
620	fi
621
622	# tricky way to convert output to 1-line without ip's
623	# messy '\'; this drops all extra white space
624	out=$(echo ${out})
625	if [ "${out}" != "${expected}" ]; then
626		rc=1
627		if [ "${VERBOSE}" = "1" ]; then
628			printf "    Unexpected route entry. Have:\n"
629			printf "        ${out}\n"
630			printf "    Expected:\n"
631			printf "        ${expected}\n\n"
632		fi
633	fi
634
635	return $rc
636}
637
638# add route for a prefix, flushing any existing routes first
639# expected to be the first step of a test
640add_route6()
641{
642	local pfx="$1"
643	local nh="$2"
644	local out
645
646	if [ "$VERBOSE" = "1" ]; then
647		echo
648		echo "    ##################################################"
649		echo
650	fi
651
652	run_cmd "$IP -6 ro flush ${pfx}"
653	[ $? -ne 0 ] && exit 1
654
655	out=$($IP -6 ro ls match ${pfx})
656	if [ -n "$out" ]; then
657		echo "Failed to flush routes for prefix used for tests."
658		exit 1
659	fi
660
661	run_cmd "$IP -6 ro add ${pfx} ${nh}"
662	if [ $? -ne 0 ]; then
663		echo "Failed to add initial route for test."
664		exit 1
665	fi
666}
667
668# add initial route - used in replace route tests
669add_initial_route6()
670{
671	add_route6 "2001:db8:104::/64" "$1"
672}
673
674check_route6()
675{
676	local pfx="2001:db8:104::/64"
677	local expected="$1"
678	local out
679	local rc=0
680
681	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
682	check_expected "${out}" "${expected}"
683}
684
685route_cleanup()
686{
687	$IP li del red 2>/dev/null
688	$IP li del dummy1 2>/dev/null
689	$IP li del veth1 2>/dev/null
690	$IP li del veth3 2>/dev/null
691
692	cleanup &> /dev/null
693}
694
695route_setup()
696{
697	route_cleanup
698	setup
699
700	[ "${VERBOSE}" = "1" ] && set -x
701	set -e
702
703	$IP li add red up type vrf table 101
704	$IP li add veth1 type veth peer name veth2
705	$IP li add veth3 type veth peer name veth4
706
707	$IP li set veth1 up
708	$IP li set veth3 up
709	$IP li set veth2 vrf red up
710	$IP li set veth4 vrf red up
711	$IP li add dummy1 type dummy
712	$IP li set dummy1 vrf red up
713
714	$IP -6 addr add 2001:db8:101::1/64 dev veth1
715	$IP -6 addr add 2001:db8:101::2/64 dev veth2
716	$IP -6 addr add 2001:db8:103::1/64 dev veth3
717	$IP -6 addr add 2001:db8:103::2/64 dev veth4
718	$IP -6 addr add 2001:db8:104::1/64 dev dummy1
719
720	$IP addr add 172.16.101.1/24 dev veth1
721	$IP addr add 172.16.101.2/24 dev veth2
722	$IP addr add 172.16.103.1/24 dev veth3
723	$IP addr add 172.16.103.2/24 dev veth4
724	$IP addr add 172.16.104.1/24 dev dummy1
725
726	set +e
727}
728
729# assumption is that basic add of a single path route works
730# otherwise just adding an address on an interface is broken
731ipv6_rt_add()
732{
733	local rc
734
735	echo
736	echo "IPv6 route add / append tests"
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 2001:db8:104::/64 via 2001:db8:103::2"
741	log_test $? 2 "Attempt to add duplicate route - gw"
742
743	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
744	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
745	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
746	log_test $? 2 "Attempt to add duplicate route - dev only"
747
748	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
749	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
750	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
751	log_test $? 2 "Attempt to add duplicate route - reject route"
752
753	# route append with same prefix adds a new route
754	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
755	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
756	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
757	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"
758	log_test $? 0 "Append nexthop to existing route - gw"
759
760	# insert mpath directly
761	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
762	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"
763	log_test $? 0 "Add multipath route"
764
765	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
766	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
767	log_test $? 2 "Attempt to add duplicate multipath route"
768
769	# insert of a second route without append but different metric
770	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
771	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
772	rc=$?
773	if [ $rc -eq 0 ]; then
774		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
775		rc=$?
776	fi
777	log_test $rc 0 "Route add with different metrics"
778
779	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
780	rc=$?
781	if [ $rc -eq 0 ]; then
782		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"
783		rc=$?
784	fi
785	log_test $rc 0 "Route delete with metric"
786}
787
788ipv6_rt_replace_single()
789{
790	# single path with single path
791	#
792	add_initial_route6 "via 2001:db8:101::2"
793	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
794	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
795	log_test $? 0 "Single path with single path"
796
797	# single path with multipath
798	#
799	add_initial_route6 "nexthop via 2001:db8:101::2"
800	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
801	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"
802	log_test $? 0 "Single path with multipath"
803
804	# single path with single path using MULTIPATH attribute
805	#
806	add_initial_route6 "via 2001:db8:101::2"
807	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
808	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
809	log_test $? 0 "Single path with single path via multipath attribute"
810
811	# route replace fails - invalid nexthop
812	add_initial_route6 "via 2001:db8:101::2"
813	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
814	if [ $? -eq 0 ]; then
815		# previous command is expected to fail so if it returns 0
816		# that means the test failed.
817		log_test 0 1 "Invalid nexthop"
818	else
819		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
820		log_test $? 0 "Invalid nexthop"
821	fi
822
823	# replace non-existent route
824	# - note use of change versus replace since ip adds NLM_F_CREATE
825	#   for replace
826	add_initial_route6 "via 2001:db8:101::2"
827	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
828	log_test $? 2 "Single path - replace of non-existent route"
829}
830
831ipv6_rt_replace_mpath()
832{
833	# multipath with multipath
834	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
835	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
836	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"
837	log_test $? 0 "Multipath with multipath"
838
839	# multipath with single
840	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
841	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
842	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
843	log_test $? 0 "Multipath with single path"
844
845	# multipath with single
846	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
847	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
848	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
849	log_test $? 0 "Multipath with single path via multipath attribute"
850
851	# multipath with dev-only
852	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
853	run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
854	check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
855	log_test $? 0 "Multipath with dev-only"
856
857	# route replace fails - invalid nexthop 1
858	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
859	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
860	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"
861	log_test $? 0 "Multipath - invalid first nexthop"
862
863	# route replace fails - invalid nexthop 2
864	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
865	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
866	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"
867	log_test $? 0 "Multipath - invalid second nexthop"
868
869	# multipath non-existent route
870	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
871	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
872	log_test $? 2 "Multipath - replace of non-existent route"
873}
874
875ipv6_rt_replace()
876{
877	echo
878	echo "IPv6 route replace tests"
879
880	ipv6_rt_replace_single
881	ipv6_rt_replace_mpath
882}
883
884ipv6_route_test()
885{
886	route_setup
887
888	ipv6_rt_add
889	ipv6_rt_replace
890
891	route_cleanup
892}
893
894ip_addr_metric_check()
895{
896	ip addr help 2>&1 | grep -q metric
897	if [ $? -ne 0 ]; then
898		echo "iproute2 command does not support metric for addresses. Skipping test"
899		return 1
900	fi
901
902	return 0
903}
904
905ipv6_addr_metric_test()
906{
907	local rc
908
909	echo
910	echo "IPv6 prefix route tests"
911
912	ip_addr_metric_check || return 1
913
914	setup
915
916	set -e
917	$IP li add dummy1 type dummy
918	$IP li add dummy2 type dummy
919	$IP li set dummy1 up
920	$IP li set dummy2 up
921
922	# default entry is metric 256
923	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
924	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
925	set +e
926
927	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
928	log_test $? 0 "Default metric"
929
930	set -e
931	run_cmd "$IP -6 addr flush dev dummy1"
932	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
933	set +e
934
935	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
936	log_test $? 0 "User specified metric on first device"
937
938	set -e
939	run_cmd "$IP -6 addr flush dev dummy2"
940	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
941	set +e
942
943	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
944	log_test $? 0 "User specified metric on second device"
945
946	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
947	rc=$?
948	if [ $rc -eq 0 ]; then
949		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
950		rc=$?
951	fi
952	log_test $rc 0 "Delete of address on first device"
953
954	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
955	rc=$?
956	if [ $rc -eq 0 ]; then
957		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
958		rc=$?
959	fi
960	log_test $rc 0 "Modify metric of address"
961
962	# verify prefix route removed on down
963	run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
964	run_cmd "$IP li set dev dummy2 down"
965	rc=$?
966	if [ $rc -eq 0 ]; then
967		out=$($IP -6 ro ls match 2001:db8:104::/64)
968		check_expected "${out}" ""
969		rc=$?
970	fi
971	log_test $rc 0 "Prefix route removed on link down"
972
973	# verify prefix route re-inserted with assigned metric
974	run_cmd "$IP li set dev dummy2 up"
975	rc=$?
976	if [ $rc -eq 0 ]; then
977		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
978		rc=$?
979	fi
980	log_test $rc 0 "Prefix route with metric on link up"
981
982	# verify peer metric added correctly
983	set -e
984	run_cmd "$IP -6 addr flush dev dummy2"
985	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
986	set +e
987
988	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
989	log_test $? 0 "Set metric with peer route on local side"
990	log_test $? 0 "User specified metric on local address"
991	check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
992	log_test $? 0 "Set metric with peer route on peer side"
993
994	set -e
995	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
996	set +e
997
998	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
999	log_test $? 0 "Modify metric and peer address on local side"
1000	check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1001	log_test $? 0 "Modify metric and peer address on peer side"
1002
1003	$IP li del dummy1
1004	$IP li del dummy2
1005	cleanup
1006}
1007
1008# add route for a prefix, flushing any existing routes first
1009# expected to be the first step of a test
1010add_route()
1011{
1012	local pfx="$1"
1013	local nh="$2"
1014	local out
1015
1016	if [ "$VERBOSE" = "1" ]; then
1017		echo
1018		echo "    ##################################################"
1019		echo
1020	fi
1021
1022	run_cmd "$IP ro flush ${pfx}"
1023	[ $? -ne 0 ] && exit 1
1024
1025	out=$($IP ro ls match ${pfx})
1026	if [ -n "$out" ]; then
1027		echo "Failed to flush routes for prefix used for tests."
1028		exit 1
1029	fi
1030
1031	run_cmd "$IP ro add ${pfx} ${nh}"
1032	if [ $? -ne 0 ]; then
1033		echo "Failed to add initial route for test."
1034		exit 1
1035	fi
1036}
1037
1038# add initial route - used in replace route tests
1039add_initial_route()
1040{
1041	add_route "172.16.104.0/24" "$1"
1042}
1043
1044check_route()
1045{
1046	local pfx="172.16.104.0/24"
1047	local expected="$1"
1048	local out
1049
1050	out=$($IP ro ls match ${pfx})
1051	check_expected "${out}" "${expected}"
1052}
1053
1054# assumption is that basic add of a single path route works
1055# otherwise just adding an address on an interface is broken
1056ipv4_rt_add()
1057{
1058	local rc
1059
1060	echo
1061	echo "IPv4 route add / append tests"
1062
1063	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1064	add_route "172.16.104.0/24" "via 172.16.101.2"
1065	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1066	log_test $? 2 "Attempt to add duplicate route - gw"
1067
1068	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1069	add_route "172.16.104.0/24" "via 172.16.101.2"
1070	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1071	log_test $? 2 "Attempt to add duplicate route - dev only"
1072
1073	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1074	add_route "172.16.104.0/24" "via 172.16.101.2"
1075	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1076	log_test $? 2 "Attempt to add duplicate route - reject route"
1077
1078	# iproute2 prepend only sets NLM_F_CREATE
1079	# - adds a new route; does NOT convert existing route to ECMP
1080	add_route "172.16.104.0/24" "via 172.16.101.2"
1081	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1082	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"
1083	log_test $? 0 "Add new nexthop for existing prefix"
1084
1085	# route append with same prefix adds a new route
1086	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1087	add_route "172.16.104.0/24" "via 172.16.101.2"
1088	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1089	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"
1090	log_test $? 0 "Append nexthop to existing route - gw"
1091
1092	add_route "172.16.104.0/24" "via 172.16.101.2"
1093	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1094	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1095	log_test $? 0 "Append nexthop to existing route - dev only"
1096
1097	add_route "172.16.104.0/24" "via 172.16.101.2"
1098	run_cmd "$IP ro append unreachable 172.16.104.0/24"
1099	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1100	log_test $? 0 "Append nexthop to existing route - reject route"
1101
1102	run_cmd "$IP ro flush 172.16.104.0/24"
1103	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1104	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1105	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1106	log_test $? 0 "Append nexthop to existing reject route - gw"
1107
1108	run_cmd "$IP ro flush 172.16.104.0/24"
1109	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1110	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1111	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1112	log_test $? 0 "Append nexthop to existing reject route - dev only"
1113
1114	# insert mpath directly
1115	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1116	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"
1117	log_test $? 0 "add multipath route"
1118
1119	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1120	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1121	log_test $? 2 "Attempt to add duplicate multipath route"
1122
1123	# insert of a second route without append but different metric
1124	add_route "172.16.104.0/24" "via 172.16.101.2"
1125	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1126	rc=$?
1127	if [ $rc -eq 0 ]; then
1128		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1129		rc=$?
1130	fi
1131	log_test $rc 0 "Route add with different metrics"
1132
1133	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1134	rc=$?
1135	if [ $rc -eq 0 ]; then
1136		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"
1137		rc=$?
1138	fi
1139	log_test $rc 0 "Route delete with metric"
1140}
1141
1142ipv4_rt_replace_single()
1143{
1144	# single path with single path
1145	#
1146	add_initial_route "via 172.16.101.2"
1147	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1148	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1149	log_test $? 0 "Single path with single path"
1150
1151	# single path with multipath
1152	#
1153	add_initial_route "nexthop via 172.16.101.2"
1154	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1155	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"
1156	log_test $? 0 "Single path with multipath"
1157
1158	# single path with reject
1159	#
1160	add_initial_route "nexthop via 172.16.101.2"
1161	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1162	check_route "unreachable 172.16.104.0/24"
1163	log_test $? 0 "Single path with reject route"
1164
1165	# single path with single path using MULTIPATH attribute
1166	#
1167	add_initial_route "via 172.16.101.2"
1168	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1169	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1170	log_test $? 0 "Single path with single path via multipath attribute"
1171
1172	# route replace fails - invalid nexthop
1173	add_initial_route "via 172.16.101.2"
1174	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1175	if [ $? -eq 0 ]; then
1176		# previous command is expected to fail so if it returns 0
1177		# that means the test failed.
1178		log_test 0 1 "Invalid nexthop"
1179	else
1180		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1181		log_test $? 0 "Invalid nexthop"
1182	fi
1183
1184	# replace non-existent route
1185	# - note use of change versus replace since ip adds NLM_F_CREATE
1186	#   for replace
1187	add_initial_route "via 172.16.101.2"
1188	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1189	log_test $? 2 "Single path - replace of non-existent route"
1190}
1191
1192ipv4_rt_replace_mpath()
1193{
1194	# multipath with multipath
1195	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1196	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1197	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"
1198	log_test $? 0 "Multipath with multipath"
1199
1200	# multipath with single
1201	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1202	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1203	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1204	log_test $? 0 "Multipath with single path"
1205
1206	# multipath with single
1207	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1208	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1209	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1210	log_test $? 0 "Multipath with single path via multipath attribute"
1211
1212	# multipath with reject
1213	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1214	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1215	check_route "unreachable 172.16.104.0/24"
1216	log_test $? 0 "Multipath with reject route"
1217
1218	# route replace fails - invalid nexthop 1
1219	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1220	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1221	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"
1222	log_test $? 0 "Multipath - invalid first nexthop"
1223
1224	# route replace fails - invalid nexthop 2
1225	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1226	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1227	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"
1228	log_test $? 0 "Multipath - invalid second nexthop"
1229
1230	# multipath non-existent route
1231	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1232	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1233	log_test $? 2 "Multipath - replace of non-existent route"
1234}
1235
1236ipv4_rt_replace()
1237{
1238	echo
1239	echo "IPv4 route replace tests"
1240
1241	ipv4_rt_replace_single
1242	ipv4_rt_replace_mpath
1243}
1244
1245ipv4_route_test()
1246{
1247	route_setup
1248
1249	ipv4_rt_add
1250	ipv4_rt_replace
1251
1252	route_cleanup
1253}
1254
1255ipv4_addr_metric_test()
1256{
1257	local rc
1258
1259	echo
1260	echo "IPv4 prefix route tests"
1261
1262	ip_addr_metric_check || return 1
1263
1264	setup
1265
1266	set -e
1267	$IP li add dummy1 type dummy
1268	$IP li add dummy2 type dummy
1269	$IP li set dummy1 up
1270	$IP li set dummy2 up
1271
1272	# default entry is metric 256
1273	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1274	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1275	set +e
1276
1277	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"
1278	log_test $? 0 "Default metric"
1279
1280	set -e
1281	run_cmd "$IP addr flush dev dummy1"
1282	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1283	set +e
1284
1285	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"
1286	log_test $? 0 "User specified metric on first device"
1287
1288	set -e
1289	run_cmd "$IP addr flush dev dummy2"
1290	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1291	set +e
1292
1293	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"
1294	log_test $? 0 "User specified metric on second device"
1295
1296	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1297	rc=$?
1298	if [ $rc -eq 0 ]; then
1299		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1300		rc=$?
1301	fi
1302	log_test $rc 0 "Delete of address on first device"
1303
1304	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1305	rc=$?
1306	if [ $rc -eq 0 ]; then
1307		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1308		rc=$?
1309	fi
1310	log_test $rc 0 "Modify metric of address"
1311
1312	# verify prefix route removed on down
1313	run_cmd "$IP li set dev dummy2 down"
1314	rc=$?
1315	if [ $rc -eq 0 ]; then
1316		out=$($IP ro ls match 172.16.104.0/24)
1317		check_expected "${out}" ""
1318		rc=$?
1319	fi
1320	log_test $rc 0 "Prefix route removed on link down"
1321
1322	# verify prefix route re-inserted with assigned metric
1323	run_cmd "$IP li set dev dummy2 up"
1324	rc=$?
1325	if [ $rc -eq 0 ]; then
1326		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1327		rc=$?
1328	fi
1329	log_test $rc 0 "Prefix route with metric on link up"
1330
1331	# explicitly check for metric changes on edge scenarios
1332	run_cmd "$IP addr flush dev dummy2"
1333	run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1334	run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1335	rc=$?
1336	if [ $rc -eq 0 ]; then
1337		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1338		rc=$?
1339	fi
1340	log_test $rc 0 "Modify metric of .0/24 address"
1341
1342	run_cmd "$IP addr flush dev dummy2"
1343	run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1344	rc=$?
1345	if [ $rc -eq 0 ]; then
1346		check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1347		rc=$?
1348	fi
1349	log_test $rc 0 "Set metric of address with peer route"
1350
1351	run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1352	rc=$?
1353	if [ $rc -eq 0 ]; then
1354		check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1355		rc=$?
1356	fi
1357	log_test $rc 0 "Modify metric and peer address for peer route"
1358
1359	$IP li del dummy1
1360	$IP li del dummy2
1361	cleanup
1362}
1363
1364################################################################################
1365# usage
1366
1367usage()
1368{
1369	cat <<EOF
1370usage: ${0##*/} OPTS
1371
1372        -t <test>   Test(s) to run (default: all)
1373                    (options: $TESTS)
1374        -p          Pause on fail
1375        -P          Pause after each test before cleanup
1376        -v          verbose mode (show commands and output)
1377EOF
1378}
1379
1380################################################################################
1381# main
1382
1383while getopts :t:pPhv o
1384do
1385	case $o in
1386		t) TESTS=$OPTARG;;
1387		p) PAUSE_ON_FAIL=yes;;
1388		P) PAUSE=yes;;
1389		v) VERBOSE=$(($VERBOSE + 1));;
1390		h) usage; exit 0;;
1391		*) usage; exit 1;;
1392	esac
1393done
1394
1395PEER_CMD="ip netns exec ${PEER_NS}"
1396
1397# make sure we don't pause twice
1398[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1399
1400if [ "$(id -u)" -ne 0 ];then
1401	echo "SKIP: Need root privileges"
1402	exit $ksft_skip;
1403fi
1404
1405if [ ! -x "$(command -v ip)" ]; then
1406	echo "SKIP: Could not run test without ip tool"
1407	exit $ksft_skip
1408fi
1409
1410ip route help 2>&1 | grep -q fibmatch
1411if [ $? -ne 0 ]; then
1412	echo "SKIP: iproute2 too old, missing fibmatch"
1413	exit $ksft_skip
1414fi
1415
1416# start clean
1417cleanup &> /dev/null
1418
1419for t in $TESTS
1420do
1421	case $t in
1422	fib_unreg_test|unregister)	fib_unreg_test;;
1423	fib_down_test|down)		fib_down_test;;
1424	fib_carrier_test|carrier)	fib_carrier_test;;
1425	fib_nexthop_test|nexthop)	fib_nexthop_test;;
1426	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
1427	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
1428	ipv6_addr_metric)		ipv6_addr_metric_test;;
1429	ipv4_addr_metric)		ipv4_addr_metric_test;;
1430
1431	help) echo "Test names: $TESTS"; exit 0;;
1432	esac
1433done
1434
1435if [ "$TESTS" != "none" ]; then
1436	printf "\nTests passed: %3d\n" ${nsuccess}
1437	printf "Tests failed: %3d\n"   ${nfail}
1438fi
1439
1440exit $ret
1441