selftests: fib_tests: Add ipv6 route add append replace tests
[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
9 TESTS="unregister down carrier nexthop ipv6_rt"
10 VERBOSE=0
11 PAUSE_ON_FAIL=no
12 PAUSE=no
13 IP="ip -netns testns"
14
15 log_test()
16 {
17         local rc=$1
18         local expected=$2
19         local msg="$3"
20
21         if [ ${rc} -eq ${expected} ]; then
22                 printf "    TEST: %-60s  [ OK ]\n" "${msg}"
23                 nsuccess=$((nsuccess+1))
24         else
25                 ret=1
26                 nfail=$((nfail+1))
27                 printf "    TEST: %-60s  [FAIL]\n" "${msg}"
28                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
29                 echo
30                         echo "hit enter to continue, 'q' to quit"
31                         read a
32                         [ "$a" = "q" ] && exit 1
33                 fi
34         fi
35
36         if [ "${PAUSE}" = "yes" ]; then
37                 echo
38                 echo "hit enter to continue, 'q' to quit"
39                 read a
40                 [ "$a" = "q" ] && exit 1
41         fi
42 }
43
44 setup()
45 {
46         set -e
47         ip netns add testns
48         $IP link set dev lo up
49
50         $IP link add dummy0 type dummy
51         $IP link set dev dummy0 up
52         $IP address add 198.51.100.1/24 dev dummy0
53         $IP -6 address add 2001:db8:1::1/64 dev dummy0
54         set +e
55
56 }
57
58 cleanup()
59 {
60         $IP link del dev dummy0 &> /dev/null
61         ip netns del testns
62 }
63
64 get_linklocal()
65 {
66         local dev=$1
67         local addr
68
69         addr=$($IP -6 -br addr show dev ${dev} | \
70         awk '{
71                 for (i = 3; i <= NF; ++i) {
72                         if ($i ~ /^fe80/)
73                                 print $i
74                 }
75         }'
76         )
77         addr=${addr/\/*}
78
79         [ -z "$addr" ] && return 1
80
81         echo $addr
82
83         return 0
84 }
85
86 fib_unreg_unicast_test()
87 {
88         echo
89         echo "Single path route test"
90
91         setup
92
93         echo "    Start point"
94         $IP route get fibmatch 198.51.100.2 &> /dev/null
95         log_test $? 0 "IPv4 fibmatch"
96         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
97         log_test $? 0 "IPv6 fibmatch"
98
99         set -e
100         $IP link del dev dummy0
101         set +e
102
103         echo "    Nexthop device deleted"
104         $IP route get fibmatch 198.51.100.2 &> /dev/null
105         log_test $? 2 "IPv4 fibmatch - no route"
106         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
107         log_test $? 2 "IPv6 fibmatch - no route"
108
109         cleanup
110 }
111
112 fib_unreg_multipath_test()
113 {
114
115         echo
116         echo "Multipath route test"
117
118         setup
119
120         set -e
121         $IP link add dummy1 type dummy
122         $IP link set dev dummy1 up
123         $IP address add 192.0.2.1/24 dev dummy1
124         $IP -6 address add 2001:db8:2::1/64 dev dummy1
125
126         $IP route add 203.0.113.0/24 \
127                 nexthop via 198.51.100.2 dev dummy0 \
128                 nexthop via 192.0.2.2 dev dummy1
129         $IP -6 route add 2001:db8:3::/64 \
130                 nexthop via 2001:db8:1::2 dev dummy0 \
131                 nexthop via 2001:db8:2::2 dev dummy1
132         set +e
133
134         echo "    Start point"
135         $IP route get fibmatch 203.0.113.1 &> /dev/null
136         log_test $? 0 "IPv4 fibmatch"
137         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
138         log_test $? 0 "IPv6 fibmatch"
139
140         set -e
141         $IP link del dev dummy0
142         set +e
143
144         echo "    One nexthop device deleted"
145         $IP route get fibmatch 203.0.113.1 &> /dev/null
146         log_test $? 2 "IPv4 - multipath route removed on delete"
147
148         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
149         # In IPv6 we do not flush the entire multipath route.
150         log_test $? 0 "IPv6 - multipath down to single path"
151
152         set -e
153         $IP link del dev dummy1
154         set +e
155
156         echo "    Second nexthop device deleted"
157         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
158         log_test $? 2 "IPv6 - no route"
159
160         cleanup
161 }
162
163 fib_unreg_test()
164 {
165         fib_unreg_unicast_test
166         fib_unreg_multipath_test
167 }
168
169 fib_down_unicast_test()
170 {
171         echo
172         echo "Single path, admin down"
173
174         setup
175
176         echo "    Start point"
177         $IP route get fibmatch 198.51.100.2 &> /dev/null
178         log_test $? 0 "IPv4 fibmatch"
179         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
180         log_test $? 0 "IPv6 fibmatch"
181
182         set -e
183         $IP link set dev dummy0 down
184         set +e
185
186         echo "    Route deleted on down"
187         $IP route get fibmatch 198.51.100.2 &> /dev/null
188         log_test $? 2 "IPv4 fibmatch"
189         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
190         log_test $? 2 "IPv6 fibmatch"
191
192         cleanup
193 }
194
195 fib_down_multipath_test_do()
196 {
197         local down_dev=$1
198         local up_dev=$2
199
200         $IP route get fibmatch 203.0.113.1 \
201                 oif $down_dev &> /dev/null
202         log_test $? 2 "IPv4 fibmatch on down device"
203         $IP -6 route get fibmatch 2001:db8:3::1 \
204                 oif $down_dev &> /dev/null
205         log_test $? 2 "IPv6 fibmatch on down device"
206
207         $IP route get fibmatch 203.0.113.1 \
208                 oif $up_dev &> /dev/null
209         log_test $? 0 "IPv4 fibmatch on up device"
210         $IP -6 route get fibmatch 2001:db8:3::1 \
211                 oif $up_dev &> /dev/null
212         log_test $? 0 "IPv6 fibmatch on up device"
213
214         $IP route get fibmatch 203.0.113.1 | \
215                 grep $down_dev | grep -q "dead linkdown"
216         log_test $? 0 "IPv4 flags on down device"
217         $IP -6 route get fibmatch 2001:db8:3::1 | \
218                 grep $down_dev | grep -q "dead linkdown"
219         log_test $? 0 "IPv6 flags on down device"
220
221         $IP route get fibmatch 203.0.113.1 | \
222                 grep $up_dev | grep -q "dead linkdown"
223         log_test $? 1 "IPv4 flags on up device"
224         $IP -6 route get fibmatch 2001:db8:3::1 | \
225                 grep $up_dev | grep -q "dead linkdown"
226         log_test $? 1 "IPv6 flags on up device"
227 }
228
229 fib_down_multipath_test()
230 {
231         echo
232         echo "Admin down multipath"
233
234         setup
235
236         set -e
237         $IP link add dummy1 type dummy
238         $IP link set dev dummy1 up
239
240         $IP address add 192.0.2.1/24 dev dummy1
241         $IP -6 address add 2001:db8:2::1/64 dev dummy1
242
243         $IP route add 203.0.113.0/24 \
244                 nexthop via 198.51.100.2 dev dummy0 \
245                 nexthop via 192.0.2.2 dev dummy1
246         $IP -6 route add 2001:db8:3::/64 \
247                 nexthop via 2001:db8:1::2 dev dummy0 \
248                 nexthop via 2001:db8:2::2 dev dummy1
249         set +e
250
251         echo "    Verify start point"
252         $IP route get fibmatch 203.0.113.1 &> /dev/null
253         log_test $? 0 "IPv4 fibmatch"
254
255         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
256         log_test $? 0 "IPv6 fibmatch"
257
258         set -e
259         $IP link set dev dummy0 down
260         set +e
261
262         echo "    One device down, one up"
263         fib_down_multipath_test_do "dummy0" "dummy1"
264
265         set -e
266         $IP link set dev dummy0 up
267         $IP link set dev dummy1 down
268         set +e
269
270         echo "    Other device down and up"
271         fib_down_multipath_test_do "dummy1" "dummy0"
272
273         set -e
274         $IP link set dev dummy0 down
275         set +e
276
277         echo "    Both devices down"
278         $IP route get fibmatch 203.0.113.1 &> /dev/null
279         log_test $? 2 "IPv4 fibmatch"
280         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
281         log_test $? 2 "IPv6 fibmatch"
282
283         $IP link del dev dummy1
284         cleanup
285 }
286
287 fib_down_test()
288 {
289         fib_down_unicast_test
290         fib_down_multipath_test
291 }
292
293 # Local routes should not be affected when carrier changes.
294 fib_carrier_local_test()
295 {
296         echo
297         echo "Local carrier tests - single path"
298
299         setup
300
301         set -e
302         $IP link set dev dummy0 carrier on
303         set +e
304
305         echo "    Start point"
306         $IP route get fibmatch 198.51.100.1 &> /dev/null
307         log_test $? 0 "IPv4 fibmatch"
308         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
309         log_test $? 0 "IPv6 fibmatch"
310
311         $IP route get fibmatch 198.51.100.1 | \
312                 grep -q "linkdown"
313         log_test $? 1 "IPv4 - no linkdown flag"
314         $IP -6 route get fibmatch 2001:db8:1::1 | \
315                 grep -q "linkdown"
316         log_test $? 1 "IPv6 - no linkdown flag"
317
318         set -e
319         $IP link set dev dummy0 carrier off
320         sleep 1
321         set +e
322
323         echo "    Carrier off on nexthop"
324         $IP route get fibmatch 198.51.100.1 &> /dev/null
325         log_test $? 0 "IPv4 fibmatch"
326         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
327         log_test $? 0 "IPv6 fibmatch"
328
329         $IP route get fibmatch 198.51.100.1 | \
330                 grep -q "linkdown"
331         log_test $? 1 "IPv4 - linkdown flag set"
332         $IP -6 route get fibmatch 2001:db8:1::1 | \
333                 grep -q "linkdown"
334         log_test $? 1 "IPv6 - linkdown flag set"
335
336         set -e
337         $IP address add 192.0.2.1/24 dev dummy0
338         $IP -6 address add 2001:db8:2::1/64 dev dummy0
339         set +e
340
341         echo "    Route to local address with carrier down"
342         $IP route get fibmatch 192.0.2.1 &> /dev/null
343         log_test $? 0 "IPv4 fibmatch"
344         $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
345         log_test $? 0 "IPv6 fibmatch"
346
347         $IP route get fibmatch 192.0.2.1 | \
348                 grep -q "linkdown"
349         log_test $? 1 "IPv4 linkdown flag set"
350         $IP -6 route get fibmatch 2001:db8:2::1 | \
351                 grep -q "linkdown"
352         log_test $? 1 "IPv6 linkdown flag set"
353
354         cleanup
355 }
356
357 fib_carrier_unicast_test()
358 {
359         ret=0
360
361         echo
362         echo "Single path route carrier test"
363
364         setup
365
366         set -e
367         $IP link set dev dummy0 carrier on
368         set +e
369
370         echo "    Start point"
371         $IP route get fibmatch 198.51.100.2 &> /dev/null
372         log_test $? 0 "IPv4 fibmatch"
373         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
374         log_test $? 0 "IPv6 fibmatch"
375
376         $IP route get fibmatch 198.51.100.2 | \
377                 grep -q "linkdown"
378         log_test $? 1 "IPv4 no linkdown flag"
379         $IP -6 route get fibmatch 2001:db8:1::2 | \
380                 grep -q "linkdown"
381         log_test $? 1 "IPv6 no linkdown flag"
382
383         set -e
384         $IP link set dev dummy0 carrier off
385         set +e
386
387         echo "    Carrier down"
388         $IP route get fibmatch 198.51.100.2 &> /dev/null
389         log_test $? 0 "IPv4 fibmatch"
390         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
391         log_test $? 0 "IPv6 fibmatch"
392
393         $IP route get fibmatch 198.51.100.2 | \
394                 grep -q "linkdown"
395         log_test $? 0 "IPv4 linkdown flag set"
396         $IP -6 route get fibmatch 2001:db8:1::2 | \
397                 grep -q "linkdown"
398         log_test $? 0 "IPv6 linkdown flag set"
399
400         set -e
401         $IP address add 192.0.2.1/24 dev dummy0
402         $IP -6 address add 2001:db8:2::1/64 dev dummy0
403         set +e
404
405         echo "    Second address added with carrier down"
406         $IP route get fibmatch 192.0.2.2 &> /dev/null
407         log_test $? 0 "IPv4 fibmatch"
408         $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
409         log_test $? 0 "IPv6 fibmatch"
410
411         $IP route get fibmatch 192.0.2.2 | \
412                 grep -q "linkdown"
413         log_test $? 0 "IPv4 linkdown flag set"
414         $IP -6 route get fibmatch 2001:db8:2::2 | \
415                 grep -q "linkdown"
416         log_test $? 0 "IPv6 linkdown flag set"
417
418         cleanup
419 }
420
421 fib_carrier_test()
422 {
423         fib_carrier_local_test
424         fib_carrier_unicast_test
425 }
426
427 ################################################################################
428 # Tests on nexthop spec
429
430 # run 'ip route add' with given spec
431 add_rt()
432 {
433         local desc="$1"
434         local erc=$2
435         local vrf=$3
436         local pfx=$4
437         local gw=$5
438         local dev=$6
439         local cmd out rc
440
441         [ "$vrf" = "-" ] && vrf="default"
442         [ -n "$gw" ] && gw="via $gw"
443         [ -n "$dev" ] && dev="dev $dev"
444
445         cmd="$IP route add vrf $vrf $pfx $gw $dev"
446         if [ "$VERBOSE" = "1" ]; then
447                 printf "\n    COMMAND: $cmd\n"
448         fi
449
450         out=$(eval $cmd 2>&1)
451         rc=$?
452         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
453                 echo "    $out"
454         fi
455         log_test $rc $erc "$desc"
456 }
457
458 fib4_nexthop()
459 {
460         echo
461         echo "IPv4 nexthop tests"
462
463         echo "<<< write me >>>"
464 }
465
466 fib6_nexthop()
467 {
468         local lldummy=$(get_linklocal dummy0)
469         local llv1=$(get_linklocal dummy0)
470
471         if [ -z "$lldummy" ]; then
472                 echo "Failed to get linklocal address for dummy0"
473                 return 1
474         fi
475         if [ -z "$llv1" ]; then
476                 echo "Failed to get linklocal address for veth1"
477                 return 1
478         fi
479
480         echo
481         echo "IPv6 nexthop tests"
482
483         add_rt "Directly connected nexthop, unicast address" 0 \
484                 - 2001:db8:101::/64 2001:db8:1::2
485         add_rt "Directly connected nexthop, unicast address with device" 0 \
486                 - 2001:db8:102::/64 2001:db8:1::2 "dummy0"
487         add_rt "Gateway is linklocal address" 0 \
488                 - 2001:db8:103::1/64 $llv1 "veth0"
489
490         # fails because LL address requires a device
491         add_rt "Gateway is linklocal address, no device" 2 \
492                 - 2001:db8:104::1/64 $llv1
493
494         # local address can not be a gateway
495         add_rt "Gateway can not be local unicast address" 2 \
496                 - 2001:db8:105::/64 2001:db8:1::1
497         add_rt "Gateway can not be local unicast address, with device" 2 \
498                 - 2001:db8:106::/64 2001:db8:1::1 "dummy0"
499         add_rt "Gateway can not be a local linklocal address" 2 \
500                 - 2001:db8:107::1/64 $lldummy "dummy0"
501
502         # VRF tests
503         add_rt "Gateway can be local address in a VRF" 0 \
504                 - 2001:db8:108::/64 2001:db8:51::2
505         add_rt "Gateway can be local address in a VRF, with device" 0 \
506                 - 2001:db8:109::/64 2001:db8:51::2 "veth0"
507         add_rt "Gateway can be local linklocal address in a VRF" 0 \
508                 - 2001:db8:110::1/64 $llv1 "veth0"
509
510         add_rt "Redirect to VRF lookup" 0 \
511                 - 2001:db8:111::/64 "" "red"
512
513         add_rt "VRF route, gateway can be local address in default VRF" 0 \
514                 red 2001:db8:112::/64 2001:db8:51::1
515
516         # local address in same VRF fails
517         add_rt "VRF route, gateway can not be a local address" 2 \
518                 red 2001:db8:113::1/64 2001:db8:2::1
519         add_rt "VRF route, gateway can not be a local addr with device" 2 \
520                 red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
521 }
522
523 # Default VRF:
524 #   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
525 #   veth0  - 192.0.2.1/24    2001:db8:51::1/64
526 #
527 # VRF red:
528 #   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
529 #   veth1  - 192.0.2.2/24   2001:db8:51::2/64
530 #
531 #  [ dummy0   veth0 ]--[ veth1   dummy1 ]
532
533 fib_nexthop_test()
534 {
535         setup
536
537         set -e
538
539         $IP -4 rule add pref 32765 table local
540         $IP -4 rule del pref 0
541         $IP -6 rule add pref 32765 table local
542         $IP -6 rule del pref 0
543
544         $IP link add red type vrf table 1
545         $IP link set red up
546         $IP -4 route add vrf red unreachable default metric 4278198272
547         $IP -6 route add vrf red unreachable default metric 4278198272
548
549         $IP link add veth0 type veth peer name veth1
550         $IP link set dev veth0 up
551         $IP address add 192.0.2.1/24 dev veth0
552         $IP -6 address add 2001:db8:51::1/64 dev veth0
553
554         $IP link set dev veth1 vrf red up
555         $IP address add 192.0.2.2/24 dev veth1
556         $IP -6 address add 2001:db8:51::2/64 dev veth1
557
558         $IP link add dummy1 type dummy
559         $IP link set dev dummy1 vrf red up
560         $IP address add 192.168.2.1/24 dev dummy1
561         $IP -6 address add 2001:db8:2::1/64 dev dummy1
562         set +e
563
564         sleep 1
565         fib4_nexthop
566         fib6_nexthop
567
568         (
569         $IP link del dev dummy1
570         $IP link del veth0
571         $IP link del red
572         ) 2>/dev/null
573         cleanup
574 }
575
576 ################################################################################
577 # Tests on route add and replace
578
579 run_cmd()
580 {
581         local cmd="$1"
582         local out
583         local stderr="2>/dev/null"
584
585         if [ "$VERBOSE" = "1" ]; then
586                 printf "    COMMAND: $cmd\n"
587                 stderr=
588         fi
589
590         out=$(eval $cmd $stderr)
591         rc=$?
592         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
593                 echo "    $out"
594         fi
595
596         [ "$VERBOSE" = "1" ] && echo
597
598         return $rc
599 }
600
601 # add route for a prefix, flushing any existing routes first
602 # expected to be the first step of a test
603 add_route6()
604 {
605         local pfx="$1"
606         local nh="$2"
607         local out
608
609         if [ "$VERBOSE" = "1" ]; then
610                 echo
611                 echo "    ##################################################"
612                 echo
613         fi
614
615         run_cmd "$IP -6 ro flush ${pfx}"
616         [ $? -ne 0 ] && exit 1
617
618         out=$($IP -6 ro ls match ${pfx})
619         if [ -n "$out" ]; then
620                 echo "Failed to flush routes for prefix used for tests."
621                 exit 1
622         fi
623
624         run_cmd "$IP -6 ro add ${pfx} ${nh}"
625         if [ $? -ne 0 ]; then
626                 echo "Failed to add initial route for test."
627                 exit 1
628         fi
629 }
630
631 # add initial route - used in replace route tests
632 add_initial_route6()
633 {
634         add_route6 "2001:db8:104::/64" "$1"
635 }
636
637 check_route6()
638 {
639         local pfx="2001:db8:104::/64"
640         local expected="$1"
641         local out
642         local rc=0
643
644         out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
645         if [ -z "${out}" ]; then
646                 if [ "$VERBOSE" = "1" ]; then
647                         printf "\nNo route entry found\n"
648                         printf "Expected:\n"
649                         printf "    ${expected}\n"
650                 fi
651                 return 1
652         fi
653
654         # tricky way to convert output to 1-line without ip's
655         # messy '\'; this drops all extra white space
656         out=$(echo ${out})
657         if [ "${out}" != "${expected}" ]; then
658                 rc=1
659                 if [ "${VERBOSE}" = "1" ]; then
660                         printf "    Unexpected route entry. Have:\n"
661                         printf "        ${out}\n"
662                         printf "    Expected:\n"
663                         printf "        ${expected}\n\n"
664                 fi
665         fi
666
667         return $rc
668 }
669
670 route_cleanup()
671 {
672         $IP li del red 2>/dev/null
673         $IP li del dummy1 2>/dev/null
674         $IP li del veth1 2>/dev/null
675         $IP li del veth3 2>/dev/null
676
677         cleanup &> /dev/null
678 }
679
680 route_setup()
681 {
682         route_cleanup
683         setup
684
685         [ "${VERBOSE}" = "1" ] && set -x
686         set -e
687
688         $IP li add red up type vrf table 101
689         $IP li add veth1 type veth peer name veth2
690         $IP li add veth3 type veth peer name veth4
691
692         $IP li set veth1 up
693         $IP li set veth3 up
694         $IP li set veth2 vrf red up
695         $IP li set veth4 vrf red up
696         $IP li add dummy1 type dummy
697         $IP li set dummy1 vrf red up
698
699         $IP -6 addr add 2001:db8:101::1/64 dev veth1
700         $IP -6 addr add 2001:db8:101::2/64 dev veth2
701         $IP -6 addr add 2001:db8:103::1/64 dev veth3
702         $IP -6 addr add 2001:db8:103::2/64 dev veth4
703         $IP -6 addr add 2001:db8:104::1/64 dev dummy1
704
705         set +ex
706 }
707
708 # assumption is that basic add of a single path route works
709 # otherwise just adding an address on an interface is broken
710 ipv6_rt_add()
711 {
712         local rc
713
714         echo
715         echo "IPv6 route add / append tests"
716
717         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
718         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
719         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
720         log_test $? 2 "Attempt to add duplicate route - gw"
721
722         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
723         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
724         run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
725         log_test $? 2 "Attempt to add duplicate route - dev only"
726
727         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
728         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
729         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
730         log_test $? 2 "Attempt to add duplicate route - reject route"
731
732         # iproute2 prepend only sets NLM_F_CREATE
733         # - adds a new route; does NOT convert existing route to ECMP
734         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
735         run_cmd "$IP -6 ro prepend 2001:db8:104::/64 via 2001:db8:103::2"
736         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"
737         log_test $? 0 "Add new route for existing prefix (w/o NLM_F_EXCL)"
738
739         # route append with same prefix adds a new route
740         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
741         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
742         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
743         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"
744         log_test $? 0 "Append nexthop to existing route - gw"
745
746         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
747         run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
748         check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop dev veth3 weight 1"
749         log_test $? 0 "Append nexthop to existing route - dev only"
750
751         # multipath route can not have a nexthop that is a reject route
752         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
753         run_cmd "$IP -6 ro append unreachable 2001:db8:104::/64"
754         log_test $? 2 "Append nexthop to existing route - reject route"
755
756         # reject route can not be converted to multipath route
757         run_cmd "$IP -6 ro flush 2001:db8:104::/64"
758         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
759         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
760         log_test $? 2 "Append nexthop to existing reject route - gw"
761
762         run_cmd "$IP -6 ro flush 2001:db8:104::/64"
763         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
764         run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
765         log_test $? 2 "Append nexthop to existing reject route - dev only"
766
767         # insert mpath directly
768         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
769         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"
770         log_test $? 0 "Add multipath route"
771
772         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
773         run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
774         log_test $? 2 "Attempt to add duplicate multipath route"
775
776         # insert of a second route without append but different metric
777         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
778         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
779         rc=$?
780         if [ $rc -eq 0 ]; then
781                 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
782                 rc=$?
783         fi
784         log_test $rc 0 "Route add with different metrics"
785
786         run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
787         rc=$?
788         if [ $rc -eq 0 ]; then
789                 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"
790                 rc=$?
791         fi
792         log_test $rc 0 "Route delete with metric"
793 }
794
795 ipv6_rt_replace_single()
796 {
797         # single path with single path
798         #
799         add_initial_route6 "via 2001:db8:101::2"
800         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
801         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
802         log_test $? 0 "Single path with single path"
803
804         # single path with multipath
805         #
806         add_initial_route6 "nexthop via 2001:db8:101::2"
807         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
808         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"
809         log_test $? 0 "Single path with multipath"
810
811         # single path with reject
812         #
813         add_initial_route6 "nexthop via 2001:db8:101::2"
814         run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
815         check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
816         log_test $? 0 "Single path with reject route"
817
818         # single path with single path using MULTIPATH attribute
819         #
820         add_initial_route6 "via 2001:db8:101::2"
821         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
822         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
823         log_test $? 0 "Single path with single path via multipath attribute"
824
825         # route replace fails - invalid nexthop
826         add_initial_route6 "via 2001:db8:101::2"
827         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
828         if [ $? -eq 0 ]; then
829                 # previous command is expected to fail so if it returns 0
830                 # that means the test failed.
831                 log_test 0 1 "Invalid nexthop"
832         else
833                 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
834                 log_test $? 0 "Invalid nexthop"
835         fi
836
837         # replace non-existent route
838         # - note use of change versus replace since ip adds NLM_F_CREATE
839         #   for replace
840         add_initial_route6 "via 2001:db8:101::2"
841         run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
842         log_test $? 2 "Single path - replace of non-existent route"
843 }
844
845 ipv6_rt_replace_mpath()
846 {
847         # multipath with multipath
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:103::3"
850         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"
851         log_test $? 0 "Multipath with multipath"
852
853         # multipath with single
854         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
855         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
856         check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
857         log_test $? 0 "Multipath with single path"
858
859         # multipath with single
860         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
861         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
862         check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
863         log_test $? 0 "Multipath with single path via multipath attribute"
864
865         # multipath with reject
866         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
867         run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
868         check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
869         log_test $? 0 "Multipath with reject route"
870
871         # route replace fails - invalid nexthop 1
872         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
873         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
874         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"
875         log_test $? 0 "Multipath - invalid first nexthop"
876
877         # route replace fails - invalid nexthop 2
878         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
879         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
880         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"
881         log_test $? 0 "Multipath - invalid second nexthop"
882
883         # multipath non-existent route
884         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
885         run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
886         log_test $? 2 "Multipath - replace of non-existent route"
887 }
888
889 ipv6_rt_replace()
890 {
891         echo
892         echo "IPv6 route replace tests"
893
894         ipv6_rt_replace_single
895         ipv6_rt_replace_mpath
896 }
897
898 ipv6_route_test()
899 {
900         route_setup
901
902         ipv6_rt_add
903         ipv6_rt_replace
904
905         route_cleanup
906 }
907
908 ################################################################################
909 # usage
910
911 usage()
912 {
913         cat <<EOF
914 usage: ${0##*/} OPTS
915
916         -t <test>   Test(s) to run (default: all)
917                     (options: $TESTS)
918         -p          Pause on fail
919         -P          Pause after each test before cleanup
920         -v          verbose mode (show commands and output)
921 EOF
922 }
923
924 ################################################################################
925 # main
926
927 while getopts :t:pPhv o
928 do
929         case $o in
930                 t) TESTS=$OPTARG;;
931                 p) PAUSE_ON_FAIL=yes;;
932                 P) PAUSE=yes;;
933                 v) VERBOSE=$(($VERBOSE + 1));;
934                 h) usage; exit 0;;
935                 *) usage; exit 1;;
936         esac
937 done
938
939 PEER_CMD="ip netns exec ${PEER_NS}"
940
941 # make sure we don't pause twice
942 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
943
944 if [ "$(id -u)" -ne 0 ];then
945         echo "SKIP: Need root privileges"
946         exit 0
947 fi
948
949 if [ ! -x "$(command -v ip)" ]; then
950         echo "SKIP: Could not run test without ip tool"
951         exit 0
952 fi
953
954 ip route help 2>&1 | grep -q fibmatch
955 if [ $? -ne 0 ]; then
956         echo "SKIP: iproute2 too old, missing fibmatch"
957         exit 0
958 fi
959
960 # start clean
961 cleanup &> /dev/null
962
963 for t in $TESTS
964 do
965         case $t in
966         fib_unreg_test|unregister)      fib_unreg_test;;
967         fib_down_test|down)             fib_down_test;;
968         fib_carrier_test|carrier)       fib_carrier_test;;
969         fib_nexthop_test|nexthop)       fib_nexthop_test;;
970         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
971
972         help) echo "Test names: $TESTS"; exit 0;;
973         esac
974 done
975
976 if [ "$TESTS" != "none" ]; then
977         printf "\nTests passed: %3d\n" ${nsuccess}
978         printf "Tests failed: %3d\n"   ${nfail}
979 fi
980
981 exit $ret