Merge tag 'pm-4.18-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
[linux-2.6-microblaze.git] / tools / testing / selftests / net / fib_tests.sh
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
7 ret=0
8 # Kselftest framework requirement - SKIP code is 4.
9 ksft_skip=4
10
11 # all tests in this script. Can be overridden with -t option
12 TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric"
13 VERBOSE=0
14 PAUSE_ON_FAIL=no
15 PAUSE=no
16 IP="ip -netns testns"
17
18 log_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
47 setup()
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
61 cleanup()
62 {
63         $IP link del dev dummy0 &> /dev/null
64         ip netns del testns
65 }
66
67 get_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
89 fib_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
115 fib_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
166 fib_unreg_test()
167 {
168         fib_unreg_unicast_test
169         fib_unreg_multipath_test
170 }
171
172 fib_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
198 fib_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
232 fib_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
290 fib_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.
297 fib_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
360 fib_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
424 fib_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
434 add_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
461 fib4_nexthop()
462 {
463         echo
464         echo "IPv4 nexthop tests"
465
466         echo "<<< write me >>>"
467 }
468
469 fib6_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
536 fib_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
582 run_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
606 add_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
635 add_initial_route6()
636 {
637         add_route6 "2001:db8:104::/64" "$1"
638 }
639
640 check_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
675 route_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
685 route_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
721 ipv6_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
778 ipv6_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
821 ipv6_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
859 ipv6_rt_replace()
860 {
861         echo
862         echo "IPv6 route replace tests"
863
864         ipv6_rt_replace_single
865         ipv6_rt_replace_mpath
866 }
867
868 ipv6_route_test()
869 {
870         route_setup
871
872         ipv6_rt_add
873         ipv6_rt_replace
874
875         route_cleanup
876 }
877
878 ip_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
889 ipv6_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
972 add_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
1001 add_initial_route()
1002 {
1003         add_route "172.16.104.0/24" "$1"
1004 }
1005
1006 check_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
1043 ipv4_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
1129 ipv4_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
1179 ipv4_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
1223 ipv4_rt_replace()
1224 {
1225         echo
1226         echo "IPv4 route replace tests"
1227
1228         ipv4_rt_replace_single
1229         ipv4_rt_replace_mpath
1230 }
1231
1232 ipv4_route_test()
1233 {
1234         route_setup
1235
1236         ipv4_rt_add
1237         ipv4_rt_replace
1238
1239         route_cleanup
1240 }
1241
1242 ipv4_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
1325 usage()
1326 {
1327         cat <<EOF
1328 usage: ${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)
1335 EOF
1336 }
1337
1338 ################################################################################
1339 # main
1340
1341 while getopts :t:pPhv o
1342 do
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
1351 done
1352
1353 PEER_CMD="ip netns exec ${PEER_NS}"
1354
1355 # make sure we don't pause twice
1356 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1357
1358 if [ "$(id -u)" -ne 0 ];then
1359         echo "SKIP: Need root privileges"
1360         exit $ksft_skip;
1361 fi
1362
1363 if [ ! -x "$(command -v ip)" ]; then
1364         echo "SKIP: Could not run test without ip tool"
1365         exit $ksft_skip
1366 fi
1367
1368 ip route help 2>&1 | grep -q fibmatch
1369 if [ $? -ne 0 ]; then
1370         echo "SKIP: iproute2 too old, missing fibmatch"
1371         exit $ksft_skip
1372 fi
1373
1374 # start clean
1375 cleanup &> /dev/null
1376
1377 for t in $TESTS
1378 do
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
1391 done
1392
1393 if [ "$TESTS" != "none" ]; then
1394         printf "\nTests passed: %3d\n" ${nsuccess}
1395         printf "Tests failed: %3d\n"   ${nfail}
1396 fi
1397
1398 exit $ret