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