kill dentry_update_name_case()
[sfrench/cifs-2.6.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         # iproute2 prepend only sets NLM_F_CREATE
744         # - adds a new route; does NOT convert existing route to ECMP
745         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
746         run_cmd "$IP -6 ro prepend 2001:db8:104::/64 via 2001:db8:103::2"
747         check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024 2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
748         log_test $? 0 "Add new route for existing prefix (w/o NLM_F_EXCL)"
749
750         # route append with same prefix adds a new route
751         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
752         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
753         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
754         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"
755         log_test $? 0 "Append nexthop to existing route - gw"
756
757         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
758         run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
759         check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop dev veth3 weight 1"
760         log_test $? 0 "Append nexthop to existing route - dev only"
761
762         # multipath route can not have a nexthop that is a reject route
763         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
764         run_cmd "$IP -6 ro append unreachable 2001:db8:104::/64"
765         log_test $? 2 "Append nexthop to existing route - reject route"
766
767         # reject route can not be converted to multipath route
768         run_cmd "$IP -6 ro flush 2001:db8:104::/64"
769         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
770         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
771         log_test $? 2 "Append nexthop to existing reject route - gw"
772
773         run_cmd "$IP -6 ro flush 2001:db8:104::/64"
774         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
775         run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
776         log_test $? 2 "Append nexthop to existing reject route - dev only"
777
778         # insert mpath directly
779         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
780         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"
781         log_test $? 0 "Add multipath route"
782
783         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
784         run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
785         log_test $? 2 "Attempt to add duplicate multipath route"
786
787         # insert of a second route without append but different metric
788         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
789         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
790         rc=$?
791         if [ $rc -eq 0 ]; then
792                 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
793                 rc=$?
794         fi
795         log_test $rc 0 "Route add with different metrics"
796
797         run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
798         rc=$?
799         if [ $rc -eq 0 ]; then
800                 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"
801                 rc=$?
802         fi
803         log_test $rc 0 "Route delete with metric"
804 }
805
806 ipv6_rt_replace_single()
807 {
808         # single path with single path
809         #
810         add_initial_route6 "via 2001:db8:101::2"
811         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
812         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
813         log_test $? 0 "Single path with single path"
814
815         # single path with multipath
816         #
817         add_initial_route6 "nexthop via 2001:db8:101::2"
818         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
819         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"
820         log_test $? 0 "Single path with multipath"
821
822         # single path with reject
823         #
824         add_initial_route6 "nexthop via 2001:db8:101::2"
825         run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
826         check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
827         log_test $? 0 "Single path with reject route"
828
829         # single path with single path using MULTIPATH attribute
830         #
831         add_initial_route6 "via 2001:db8:101::2"
832         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
833         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
834         log_test $? 0 "Single path with single path via multipath attribute"
835
836         # route replace fails - invalid nexthop
837         add_initial_route6 "via 2001:db8:101::2"
838         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
839         if [ $? -eq 0 ]; then
840                 # previous command is expected to fail so if it returns 0
841                 # that means the test failed.
842                 log_test 0 1 "Invalid nexthop"
843         else
844                 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
845                 log_test $? 0 "Invalid nexthop"
846         fi
847
848         # replace non-existent route
849         # - note use of change versus replace since ip adds NLM_F_CREATE
850         #   for replace
851         add_initial_route6 "via 2001:db8:101::2"
852         run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
853         log_test $? 2 "Single path - replace of non-existent route"
854 }
855
856 ipv6_rt_replace_mpath()
857 {
858         # multipath with multipath
859         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
860         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
861         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"
862         log_test $? 0 "Multipath with multipath"
863
864         # multipath with single
865         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
866         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
867         check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
868         log_test $? 0 "Multipath with single path"
869
870         # multipath with single
871         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
872         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
873         check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
874         log_test $? 0 "Multipath with single path via multipath attribute"
875
876         # multipath with reject
877         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
878         run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
879         check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
880         log_test $? 0 "Multipath with reject route"
881
882         # route replace fails - invalid nexthop 1
883         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
884         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
885         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"
886         log_test $? 0 "Multipath - invalid first nexthop"
887
888         # route replace fails - invalid nexthop 2
889         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
890         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
891         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"
892         log_test $? 0 "Multipath - invalid second nexthop"
893
894         # multipath non-existent route
895         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
896         run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
897         log_test $? 2 "Multipath - replace of non-existent route"
898 }
899
900 ipv6_rt_replace()
901 {
902         echo
903         echo "IPv6 route replace tests"
904
905         ipv6_rt_replace_single
906         ipv6_rt_replace_mpath
907 }
908
909 ipv6_route_test()
910 {
911         route_setup
912
913         ipv6_rt_add
914         ipv6_rt_replace
915
916         route_cleanup
917 }
918
919 ip_addr_metric_check()
920 {
921         ip addr help 2>&1 | grep -q metric
922         if [ $? -ne 0 ]; then
923                 echo "iproute2 command does not support metric for addresses. Skipping test"
924                 return 1
925         fi
926
927         return 0
928 }
929
930 ipv6_addr_metric_test()
931 {
932         local rc
933
934         echo
935         echo "IPv6 prefix route tests"
936
937         ip_addr_metric_check || return 1
938
939         setup
940
941         set -e
942         $IP li add dummy1 type dummy
943         $IP li add dummy2 type dummy
944         $IP li set dummy1 up
945         $IP li set dummy2 up
946
947         # default entry is metric 256
948         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
949         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
950         set +e
951
952         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
953         log_test $? 0 "Default metric"
954
955         set -e
956         run_cmd "$IP -6 addr flush dev dummy1"
957         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
958         set +e
959
960         check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
961         log_test $? 0 "User specified metric on first device"
962
963         set -e
964         run_cmd "$IP -6 addr flush dev dummy2"
965         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
966         set +e
967
968         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
969         log_test $? 0 "User specified metric on second device"
970
971         run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
972         rc=$?
973         if [ $rc -eq 0 ]; then
974                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
975                 rc=$?
976         fi
977         log_test $rc 0 "Delete of address on first device"
978
979         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
980         rc=$?
981         if [ $rc -eq 0 ]; then
982                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
983                 rc=$?
984         fi
985         log_test $rc 0 "Modify metric of address"
986
987         # verify prefix route removed on down
988         run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
989         run_cmd "$IP li set dev dummy2 down"
990         rc=$?
991         if [ $rc -eq 0 ]; then
992                 check_route6 ""
993                 rc=$?
994         fi
995         log_test $rc 0 "Prefix route removed on link down"
996
997         # verify prefix route re-inserted with assigned metric
998         run_cmd "$IP li set dev dummy2 up"
999         rc=$?
1000         if [ $rc -eq 0 ]; then
1001                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1002                 rc=$?
1003         fi
1004         log_test $rc 0 "Prefix route with metric on link up"
1005
1006         $IP li del dummy1
1007         $IP li del dummy2
1008         cleanup
1009 }
1010
1011 # add route for a prefix, flushing any existing routes first
1012 # expected to be the first step of a test
1013 add_route()
1014 {
1015         local pfx="$1"
1016         local nh="$2"
1017         local out
1018
1019         if [ "$VERBOSE" = "1" ]; then
1020                 echo
1021                 echo "    ##################################################"
1022                 echo
1023         fi
1024
1025         run_cmd "$IP ro flush ${pfx}"
1026         [ $? -ne 0 ] && exit 1
1027
1028         out=$($IP ro ls match ${pfx})
1029         if [ -n "$out" ]; then
1030                 echo "Failed to flush routes for prefix used for tests."
1031                 exit 1
1032         fi
1033
1034         run_cmd "$IP ro add ${pfx} ${nh}"
1035         if [ $? -ne 0 ]; then
1036                 echo "Failed to add initial route for test."
1037                 exit 1
1038         fi
1039 }
1040
1041 # add initial route - used in replace route tests
1042 add_initial_route()
1043 {
1044         add_route "172.16.104.0/24" "$1"
1045 }
1046
1047 check_route()
1048 {
1049         local pfx="172.16.104.0/24"
1050         local expected="$1"
1051         local out
1052         local rc=0
1053
1054         out=$($IP ro ls match ${pfx})
1055         [ "${out}" = "${expected}" ] && return 0
1056
1057         if [ -z "${out}" ]; then
1058                 if [ "$VERBOSE" = "1" ]; then
1059                         printf "\nNo route entry found\n"
1060                         printf "Expected:\n"
1061                         printf "    ${expected}\n"
1062                 fi
1063                 return 1
1064         fi
1065
1066         # tricky way to convert output to 1-line without ip's
1067         # messy '\'; this drops all extra white space
1068         out=$(echo ${out})
1069         if [ "${out}" != "${expected}" ]; then
1070                 rc=1
1071                 if [ "${VERBOSE}" = "1" ]; then
1072                         printf "    Unexpected route entry. Have:\n"
1073                         printf "        ${out}\n"
1074                         printf "    Expected:\n"
1075                         printf "        ${expected}\n\n"
1076                 fi
1077         fi
1078
1079         return $rc
1080 }
1081
1082 # assumption is that basic add of a single path route works
1083 # otherwise just adding an address on an interface is broken
1084 ipv4_rt_add()
1085 {
1086         local rc
1087
1088         echo
1089         echo "IPv4 route add / append tests"
1090
1091         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1092         add_route "172.16.104.0/24" "via 172.16.101.2"
1093         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1094         log_test $? 2 "Attempt to add duplicate route - gw"
1095
1096         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1097         add_route "172.16.104.0/24" "via 172.16.101.2"
1098         run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1099         log_test $? 2 "Attempt to add duplicate route - dev only"
1100
1101         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1102         add_route "172.16.104.0/24" "via 172.16.101.2"
1103         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1104         log_test $? 2 "Attempt to add duplicate route - reject route"
1105
1106         # iproute2 prepend only sets NLM_F_CREATE
1107         # - adds a new route; does NOT convert existing route to ECMP
1108         add_route "172.16.104.0/24" "via 172.16.101.2"
1109         run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1110         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"
1111         log_test $? 0 "Add new nexthop for existing prefix"
1112
1113         # route append with same prefix adds a new route
1114         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1115         add_route "172.16.104.0/24" "via 172.16.101.2"
1116         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1117         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"
1118         log_test $? 0 "Append nexthop to existing route - gw"
1119
1120         add_route "172.16.104.0/24" "via 172.16.101.2"
1121         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1122         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1123         log_test $? 0 "Append nexthop to existing route - dev only"
1124
1125         add_route "172.16.104.0/24" "via 172.16.101.2"
1126         run_cmd "$IP ro append unreachable 172.16.104.0/24"
1127         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1128         log_test $? 0 "Append nexthop to existing route - reject route"
1129
1130         run_cmd "$IP ro flush 172.16.104.0/24"
1131         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1132         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1133         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1134         log_test $? 0 "Append nexthop to existing reject route - gw"
1135
1136         run_cmd "$IP ro flush 172.16.104.0/24"
1137         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1138         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1139         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1140         log_test $? 0 "Append nexthop to existing reject route - dev only"
1141
1142         # insert mpath directly
1143         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1144         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"
1145         log_test $? 0 "add multipath route"
1146
1147         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1148         run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1149         log_test $? 2 "Attempt to add duplicate multipath route"
1150
1151         # insert of a second route without append but different metric
1152         add_route "172.16.104.0/24" "via 172.16.101.2"
1153         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1154         rc=$?
1155         if [ $rc -eq 0 ]; then
1156                 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1157                 rc=$?
1158         fi
1159         log_test $rc 0 "Route add with different metrics"
1160
1161         run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1162         rc=$?
1163         if [ $rc -eq 0 ]; then
1164                 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"
1165                 rc=$?
1166         fi
1167         log_test $rc 0 "Route delete with metric"
1168 }
1169
1170 ipv4_rt_replace_single()
1171 {
1172         # single path with single path
1173         #
1174         add_initial_route "via 172.16.101.2"
1175         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1176         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1177         log_test $? 0 "Single path with single path"
1178
1179         # single path with multipath
1180         #
1181         add_initial_route "nexthop via 172.16.101.2"
1182         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1183         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"
1184         log_test $? 0 "Single path with multipath"
1185
1186         # single path with reject
1187         #
1188         add_initial_route "nexthop via 172.16.101.2"
1189         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1190         check_route "unreachable 172.16.104.0/24"
1191         log_test $? 0 "Single path with reject route"
1192
1193         # single path with single path using MULTIPATH attribute
1194         #
1195         add_initial_route "via 172.16.101.2"
1196         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1197         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1198         log_test $? 0 "Single path with single path via multipath attribute"
1199
1200         # route replace fails - invalid nexthop
1201         add_initial_route "via 172.16.101.2"
1202         run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1203         if [ $? -eq 0 ]; then
1204                 # previous command is expected to fail so if it returns 0
1205                 # that means the test failed.
1206                 log_test 0 1 "Invalid nexthop"
1207         else
1208                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1209                 log_test $? 0 "Invalid nexthop"
1210         fi
1211
1212         # replace non-existent route
1213         # - note use of change versus replace since ip adds NLM_F_CREATE
1214         #   for replace
1215         add_initial_route "via 172.16.101.2"
1216         run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1217         log_test $? 2 "Single path - replace of non-existent route"
1218 }
1219
1220 ipv4_rt_replace_mpath()
1221 {
1222         # multipath with multipath
1223         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1224         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1225         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"
1226         log_test $? 0 "Multipath with multipath"
1227
1228         # multipath with single
1229         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1230         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1231         check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1232         log_test $? 0 "Multipath with single path"
1233
1234         # multipath with single
1235         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1236         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1237         check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1238         log_test $? 0 "Multipath with single path via multipath attribute"
1239
1240         # multipath with reject
1241         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1242         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1243         check_route "unreachable 172.16.104.0/24"
1244         log_test $? 0 "Multipath with reject route"
1245
1246         # route replace fails - invalid nexthop 1
1247         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1248         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1249         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"
1250         log_test $? 0 "Multipath - invalid first nexthop"
1251
1252         # route replace fails - invalid nexthop 2
1253         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1254         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1255         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"
1256         log_test $? 0 "Multipath - invalid second nexthop"
1257
1258         # multipath non-existent route
1259         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1260         run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1261         log_test $? 2 "Multipath - replace of non-existent route"
1262 }
1263
1264 ipv4_rt_replace()
1265 {
1266         echo
1267         echo "IPv4 route replace tests"
1268
1269         ipv4_rt_replace_single
1270         ipv4_rt_replace_mpath
1271 }
1272
1273 ipv4_route_test()
1274 {
1275         route_setup
1276
1277         ipv4_rt_add
1278         ipv4_rt_replace
1279
1280         route_cleanup
1281 }
1282
1283 ipv4_addr_metric_test()
1284 {
1285         local rc
1286
1287         echo
1288         echo "IPv4 prefix route tests"
1289
1290         ip_addr_metric_check || return 1
1291
1292         setup
1293
1294         set -e
1295         $IP li add dummy1 type dummy
1296         $IP li add dummy2 type dummy
1297         $IP li set dummy1 up
1298         $IP li set dummy2 up
1299
1300         # default entry is metric 256
1301         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1302         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1303         set +e
1304
1305         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"
1306         log_test $? 0 "Default metric"
1307
1308         set -e
1309         run_cmd "$IP addr flush dev dummy1"
1310         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1311         set +e
1312
1313         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"
1314         log_test $? 0 "User specified metric on first device"
1315
1316         set -e
1317         run_cmd "$IP addr flush dev dummy2"
1318         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1319         set +e
1320
1321         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"
1322         log_test $? 0 "User specified metric on second device"
1323
1324         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1325         rc=$?
1326         if [ $rc -eq 0 ]; then
1327                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1328                 rc=$?
1329         fi
1330         log_test $rc 0 "Delete of address on first device"
1331
1332         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1333         rc=$?
1334         if [ $rc -eq 0 ]; then
1335                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1336                 rc=$?
1337         fi
1338         log_test $rc 0 "Modify metric of address"
1339
1340         # verify prefix route removed on down
1341         run_cmd "$IP li set dev dummy2 down"
1342         rc=$?
1343         if [ $rc -eq 0 ]; then
1344                 check_route ""
1345                 rc=$?
1346         fi
1347         log_test $rc 0 "Prefix route removed on link down"
1348
1349         # verify prefix route re-inserted with assigned metric
1350         run_cmd "$IP li set dev dummy2 up"
1351         rc=$?
1352         if [ $rc -eq 0 ]; then
1353                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1354                 rc=$?
1355         fi
1356         log_test $rc 0 "Prefix route with metric on link up"
1357
1358         $IP li del dummy1
1359         $IP li del dummy2
1360         cleanup
1361 }
1362
1363 ################################################################################
1364 # usage
1365
1366 usage()
1367 {
1368         cat <<EOF
1369 usage: ${0##*/} OPTS
1370
1371         -t <test>   Test(s) to run (default: all)
1372                     (options: $TESTS)
1373         -p          Pause on fail
1374         -P          Pause after each test before cleanup
1375         -v          verbose mode (show commands and output)
1376 EOF
1377 }
1378
1379 ################################################################################
1380 # main
1381
1382 while getopts :t:pPhv o
1383 do
1384         case $o in
1385                 t) TESTS=$OPTARG;;
1386                 p) PAUSE_ON_FAIL=yes;;
1387                 P) PAUSE=yes;;
1388                 v) VERBOSE=$(($VERBOSE + 1));;
1389                 h) usage; exit 0;;
1390                 *) usage; exit 1;;
1391         esac
1392 done
1393
1394 PEER_CMD="ip netns exec ${PEER_NS}"
1395
1396 # make sure we don't pause twice
1397 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1398
1399 if [ "$(id -u)" -ne 0 ];then
1400         echo "SKIP: Need root privileges"
1401         exit $ksft_skip;
1402 fi
1403
1404 if [ ! -x "$(command -v ip)" ]; then
1405         echo "SKIP: Could not run test without ip tool"
1406         exit $ksft_skip
1407 fi
1408
1409 ip route help 2>&1 | grep -q fibmatch
1410 if [ $? -ne 0 ]; then
1411         echo "SKIP: iproute2 too old, missing fibmatch"
1412         exit $ksft_skip
1413 fi
1414
1415 # start clean
1416 cleanup &> /dev/null
1417
1418 for t in $TESTS
1419 do
1420         case $t in
1421         fib_unreg_test|unregister)      fib_unreg_test;;
1422         fib_down_test|down)             fib_down_test;;
1423         fib_carrier_test|carrier)       fib_carrier_test;;
1424         fib_nexthop_test|nexthop)       fib_nexthop_test;;
1425         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
1426         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
1427         ipv6_addr_metric)               ipv6_addr_metric_test;;
1428         ipv4_addr_metric)               ipv4_addr_metric_test;;
1429
1430         help) echo "Test names: $TESTS"; exit 0;;
1431         esac
1432 done
1433
1434 if [ "$TESTS" != "none" ]; then
1435         printf "\nTests passed: %3d\n" ${nsuccess}
1436         printf "Tests failed: %3d\n"   ${nfail}
1437 fi
1438
1439 exit $ret