]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/testing/selftests/net/fib_tests.sh
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[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 check_expected()
611 {
612         local out="$1"
613         local expected="$2"
614         local rc=0
615
616         [ "${out}" = "${expected}" ] && return 0
617
618         if [ -z "${out}" ]; then
619                 if [ "$VERBOSE" = "1" ]; then
620                         printf "\nNo route entry found\n"
621                         printf "Expected:\n"
622                         printf "    ${expected}\n"
623                 fi
624                 return 1
625         fi
626
627         # tricky way to convert output to 1-line without ip's
628         # messy '\'; this drops all extra white space
629         out=$(echo ${out})
630         if [ "${out}" != "${expected}" ]; then
631                 rc=1
632                 if [ "${VERBOSE}" = "1" ]; then
633                         printf "    Unexpected route entry. Have:\n"
634                         printf "        ${out}\n"
635                         printf "    Expected:\n"
636                         printf "        ${expected}\n\n"
637                 fi
638         fi
639
640         return $rc
641 }
642
643 # add route for a prefix, flushing any existing routes first
644 # expected to be the first step of a test
645 add_route6()
646 {
647         local pfx="$1"
648         local nh="$2"
649         local out
650
651         if [ "$VERBOSE" = "1" ]; then
652                 echo
653                 echo "    ##################################################"
654                 echo
655         fi
656
657         run_cmd "$IP -6 ro flush ${pfx}"
658         [ $? -ne 0 ] && exit 1
659
660         out=$($IP -6 ro ls match ${pfx})
661         if [ -n "$out" ]; then
662                 echo "Failed to flush routes for prefix used for tests."
663                 exit 1
664         fi
665
666         run_cmd "$IP -6 ro add ${pfx} ${nh}"
667         if [ $? -ne 0 ]; then
668                 echo "Failed to add initial route for test."
669                 exit 1
670         fi
671 }
672
673 # add initial route - used in replace route tests
674 add_initial_route6()
675 {
676         add_route6 "2001:db8:104::/64" "$1"
677 }
678
679 check_route6()
680 {
681         local pfx
682         local expected="$1"
683         local out
684         local rc=0
685
686         set -- $expected
687         pfx=$1
688
689         out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
690         check_expected "${out}" "${expected}"
691 }
692
693 route_cleanup()
694 {
695         $IP li del red 2>/dev/null
696         $IP li del dummy1 2>/dev/null
697         $IP li del veth1 2>/dev/null
698         $IP li del veth3 2>/dev/null
699
700         cleanup &> /dev/null
701 }
702
703 route_setup()
704 {
705         route_cleanup
706         setup
707
708         [ "${VERBOSE}" = "1" ] && set -x
709         set -e
710
711         ip netns add ns2
712         ip netns set ns2 auto
713         ip -netns ns2 link set dev lo up
714         ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
715         ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
716
717         $IP li add veth1 type veth peer name veth2
718         $IP li add veth3 type veth peer name veth4
719
720         $IP li set veth1 up
721         $IP li set veth3 up
722         $IP li set veth2 netns ns2 up
723         $IP li set veth4 netns ns2 up
724         ip -netns ns2 li add dummy1 type dummy
725         ip -netns ns2 li set dummy1 up
726
727         $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
728         $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
729         $IP addr add 172.16.101.1/24 dev veth1
730         $IP addr add 172.16.103.1/24 dev veth3
731
732         ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
733         ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
734         ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
735
736         ip -netns ns2 addr add 172.16.101.2/24 dev veth2
737         ip -netns ns2 addr add 172.16.103.2/24 dev veth4
738         ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
739
740         set +e
741 }
742
743 # assumption is that basic add of a single path route works
744 # otherwise just adding an address on an interface is broken
745 ipv6_rt_add()
746 {
747         local rc
748
749         echo
750         echo "IPv6 route add / append tests"
751
752         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
753         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
754         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
755         log_test $? 2 "Attempt to add duplicate route - gw"
756
757         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
758         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
759         run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
760         log_test $? 2 "Attempt to add duplicate route - dev only"
761
762         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
763         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
764         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
765         log_test $? 2 "Attempt to add duplicate route - reject route"
766
767         # route append with same prefix adds a new route
768         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
769         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
770         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
771         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"
772         log_test $? 0 "Append nexthop to existing route - gw"
773
774         # insert mpath directly
775         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
776         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"
777         log_test $? 0 "Add multipath route"
778
779         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
780         run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
781         log_test $? 2 "Attempt to add duplicate multipath route"
782
783         # insert of a second route without append but different metric
784         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
785         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
786         rc=$?
787         if [ $rc -eq 0 ]; then
788                 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
789                 rc=$?
790         fi
791         log_test $rc 0 "Route add with different metrics"
792
793         run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
794         rc=$?
795         if [ $rc -eq 0 ]; then
796                 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"
797                 rc=$?
798         fi
799         log_test $rc 0 "Route delete with metric"
800 }
801
802 ipv6_rt_replace_single()
803 {
804         # single path with single path
805         #
806         add_initial_route6 "via 2001:db8:101::2"
807         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
808         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
809         log_test $? 0 "Single path with single path"
810
811         # single path with multipath
812         #
813         add_initial_route6 "nexthop via 2001:db8:101::2"
814         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
815         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"
816         log_test $? 0 "Single path with multipath"
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         # route replace fails - invalid nexthop 1
866         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
867         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
868         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"
869         log_test $? 0 "Multipath - invalid first nexthop"
870
871         # route replace fails - invalid nexthop 2
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:101::3 nexthop via 2001:db8:113::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 second nexthop"
876
877         # multipath non-existent route
878         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
879         run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
880         log_test $? 2 "Multipath - replace of non-existent route"
881 }
882
883 ipv6_rt_replace()
884 {
885         echo
886         echo "IPv6 route replace tests"
887
888         ipv6_rt_replace_single
889         ipv6_rt_replace_mpath
890 }
891
892 ipv6_route_test()
893 {
894         route_setup
895
896         ipv6_rt_add
897         ipv6_rt_replace
898
899         route_cleanup
900 }
901
902 ip_addr_metric_check()
903 {
904         ip addr help 2>&1 | grep -q metric
905         if [ $? -ne 0 ]; then
906                 echo "iproute2 command does not support metric for addresses. Skipping test"
907                 return 1
908         fi
909
910         return 0
911 }
912
913 ipv6_addr_metric_test()
914 {
915         local rc
916
917         echo
918         echo "IPv6 prefix route tests"
919
920         ip_addr_metric_check || return 1
921
922         setup
923
924         set -e
925         $IP li add dummy1 type dummy
926         $IP li add dummy2 type dummy
927         $IP li set dummy1 up
928         $IP li set dummy2 up
929
930         # default entry is metric 256
931         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
932         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
933         set +e
934
935         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
936         log_test $? 0 "Default metric"
937
938         set -e
939         run_cmd "$IP -6 addr flush dev dummy1"
940         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
941         set +e
942
943         check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
944         log_test $? 0 "User specified metric on first device"
945
946         set -e
947         run_cmd "$IP -6 addr flush dev dummy2"
948         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
949         set +e
950
951         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
952         log_test $? 0 "User specified metric on second device"
953
954         run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
955         rc=$?
956         if [ $rc -eq 0 ]; then
957                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
958                 rc=$?
959         fi
960         log_test $rc 0 "Delete of address on first device"
961
962         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
963         rc=$?
964         if [ $rc -eq 0 ]; then
965                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
966                 rc=$?
967         fi
968         log_test $rc 0 "Modify metric of address"
969
970         # verify prefix route removed on down
971         run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
972         run_cmd "$IP li set dev dummy2 down"
973         rc=$?
974         if [ $rc -eq 0 ]; then
975                 out=$($IP -6 ro ls match 2001:db8:104::/64)
976                 check_expected "${out}" ""
977                 rc=$?
978         fi
979         log_test $rc 0 "Prefix route removed on link down"
980
981         # verify prefix route re-inserted with assigned metric
982         run_cmd "$IP li set dev dummy2 up"
983         rc=$?
984         if [ $rc -eq 0 ]; then
985                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
986                 rc=$?
987         fi
988         log_test $rc 0 "Prefix route with metric on link up"
989
990         $IP li del dummy1
991         $IP li del dummy2
992         cleanup
993 }
994
995 ipv6_route_metrics_test()
996 {
997         local rc
998
999         echo
1000         echo "IPv6 routes with metrics"
1001
1002         route_setup
1003
1004         #
1005         # single path with metrics
1006         #
1007         run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1008         rc=$?
1009         if [ $rc -eq 0 ]; then
1010                 check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1011                 rc=$?
1012         fi
1013         log_test $rc 0 "Single path route with mtu metric"
1014
1015
1016         #
1017         # multipath via separate routes with metrics
1018         #
1019         run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1020         run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1021         rc=$?
1022         if [ $rc -eq 0 ]; then
1023                 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"
1024                 rc=$?
1025         fi
1026         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1027
1028         # second route is coalesced to first to make a multipath route.
1029         # MTU of the second path is hidden from display!
1030         run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1031         run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1032         rc=$?
1033         if [ $rc -eq 0 ]; then
1034                 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"
1035                 rc=$?
1036         fi
1037         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1038
1039         run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1040         if [ $? -eq 0 ]; then
1041                 check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1042                 log_test $? 0 "    MTU of second leg"
1043         fi
1044
1045         #
1046         # multipath with metrics
1047         #
1048         run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1049         rc=$?
1050         if [ $rc -eq 0 ]; then
1051                 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"
1052                 rc=$?
1053         fi
1054         log_test $rc 0 "Multipath route with mtu metric"
1055
1056         $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1057         run_cmd "ip netns exec ns1 ping6 -w1 -c1 -s 1500 2001:db8:104::1"
1058         log_test $? 0 "Using route with mtu metric"
1059
1060         run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1061         log_test $? 2 "Invalid metric (fails metric_convert)"
1062
1063         route_cleanup
1064 }
1065
1066 # add route for a prefix, flushing any existing routes first
1067 # expected to be the first step of a test
1068 add_route()
1069 {
1070         local pfx="$1"
1071         local nh="$2"
1072         local out
1073
1074         if [ "$VERBOSE" = "1" ]; then
1075                 echo
1076                 echo "    ##################################################"
1077                 echo
1078         fi
1079
1080         run_cmd "$IP ro flush ${pfx}"
1081         [ $? -ne 0 ] && exit 1
1082
1083         out=$($IP ro ls match ${pfx})
1084         if [ -n "$out" ]; then
1085                 echo "Failed to flush routes for prefix used for tests."
1086                 exit 1
1087         fi
1088
1089         run_cmd "$IP ro add ${pfx} ${nh}"
1090         if [ $? -ne 0 ]; then
1091                 echo "Failed to add initial route for test."
1092                 exit 1
1093         fi
1094 }
1095
1096 # add initial route - used in replace route tests
1097 add_initial_route()
1098 {
1099         add_route "172.16.104.0/24" "$1"
1100 }
1101
1102 check_route()
1103 {
1104         local pfx
1105         local expected="$1"
1106         local out
1107
1108         set -- $expected
1109         pfx=$1
1110         [ "${pfx}" = "unreachable" ] && pfx=$2
1111
1112         out=$($IP ro ls match ${pfx})
1113         check_expected "${out}" "${expected}"
1114 }
1115
1116 # assumption is that basic add of a single path route works
1117 # otherwise just adding an address on an interface is broken
1118 ipv4_rt_add()
1119 {
1120         local rc
1121
1122         echo
1123         echo "IPv4 route add / append tests"
1124
1125         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1126         add_route "172.16.104.0/24" "via 172.16.101.2"
1127         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1128         log_test $? 2 "Attempt to add duplicate route - gw"
1129
1130         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1131         add_route "172.16.104.0/24" "via 172.16.101.2"
1132         run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1133         log_test $? 2 "Attempt to add duplicate route - dev only"
1134
1135         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1136         add_route "172.16.104.0/24" "via 172.16.101.2"
1137         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1138         log_test $? 2 "Attempt to add duplicate route - reject route"
1139
1140         # iproute2 prepend only sets NLM_F_CREATE
1141         # - adds a new route; does NOT convert existing route to ECMP
1142         add_route "172.16.104.0/24" "via 172.16.101.2"
1143         run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1144         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"
1145         log_test $? 0 "Add new nexthop for existing prefix"
1146
1147         # route append with same prefix adds a new route
1148         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1149         add_route "172.16.104.0/24" "via 172.16.101.2"
1150         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1151         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"
1152         log_test $? 0 "Append nexthop to existing route - gw"
1153
1154         add_route "172.16.104.0/24" "via 172.16.101.2"
1155         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1156         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1157         log_test $? 0 "Append nexthop to existing route - dev only"
1158
1159         add_route "172.16.104.0/24" "via 172.16.101.2"
1160         run_cmd "$IP ro append unreachable 172.16.104.0/24"
1161         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1162         log_test $? 0 "Append nexthop to existing route - reject route"
1163
1164         run_cmd "$IP ro flush 172.16.104.0/24"
1165         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1166         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1167         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1168         log_test $? 0 "Append nexthop to existing reject route - gw"
1169
1170         run_cmd "$IP ro flush 172.16.104.0/24"
1171         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1172         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1173         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1174         log_test $? 0 "Append nexthop to existing reject route - dev only"
1175
1176         # insert mpath directly
1177         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1178         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"
1179         log_test $? 0 "add multipath route"
1180
1181         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1182         run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1183         log_test $? 2 "Attempt to add duplicate multipath route"
1184
1185         # insert of a second route without append but different metric
1186         add_route "172.16.104.0/24" "via 172.16.101.2"
1187         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1188         rc=$?
1189         if [ $rc -eq 0 ]; then
1190                 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1191                 rc=$?
1192         fi
1193         log_test $rc 0 "Route add with different metrics"
1194
1195         run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1196         rc=$?
1197         if [ $rc -eq 0 ]; then
1198                 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"
1199                 rc=$?
1200         fi
1201         log_test $rc 0 "Route delete with metric"
1202 }
1203
1204 ipv4_rt_replace_single()
1205 {
1206         # single path with single path
1207         #
1208         add_initial_route "via 172.16.101.2"
1209         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1210         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1211         log_test $? 0 "Single path with single path"
1212
1213         # single path with multipath
1214         #
1215         add_initial_route "nexthop via 172.16.101.2"
1216         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1217         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"
1218         log_test $? 0 "Single path with multipath"
1219
1220         # single path with reject
1221         #
1222         add_initial_route "nexthop via 172.16.101.2"
1223         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1224         check_route "unreachable 172.16.104.0/24"
1225         log_test $? 0 "Single path with reject route"
1226
1227         # single path with single path using MULTIPATH attribute
1228         #
1229         add_initial_route "via 172.16.101.2"
1230         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1231         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1232         log_test $? 0 "Single path with single path via multipath attribute"
1233
1234         # route replace fails - invalid nexthop
1235         add_initial_route "via 172.16.101.2"
1236         run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1237         if [ $? -eq 0 ]; then
1238                 # previous command is expected to fail so if it returns 0
1239                 # that means the test failed.
1240                 log_test 0 1 "Invalid nexthop"
1241         else
1242                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1243                 log_test $? 0 "Invalid nexthop"
1244         fi
1245
1246         # replace non-existent route
1247         # - note use of change versus replace since ip adds NLM_F_CREATE
1248         #   for replace
1249         add_initial_route "via 172.16.101.2"
1250         run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1251         log_test $? 2 "Single path - replace of non-existent route"
1252 }
1253
1254 ipv4_rt_replace_mpath()
1255 {
1256         # multipath with multipath
1257         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1258         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1259         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"
1260         log_test $? 0 "Multipath with multipath"
1261
1262         # multipath with single
1263         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1264         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1265         check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1266         log_test $? 0 "Multipath with single path"
1267
1268         # multipath with single
1269         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1270         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1271         check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1272         log_test $? 0 "Multipath with single path via multipath attribute"
1273
1274         # multipath with reject
1275         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1276         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1277         check_route "unreachable 172.16.104.0/24"
1278         log_test $? 0 "Multipath with reject route"
1279
1280         # route replace fails - invalid nexthop 1
1281         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1282         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1283         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"
1284         log_test $? 0 "Multipath - invalid first nexthop"
1285
1286         # route replace fails - invalid nexthop 2
1287         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1288         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1289         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"
1290         log_test $? 0 "Multipath - invalid second nexthop"
1291
1292         # multipath non-existent route
1293         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1294         run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1295         log_test $? 2 "Multipath - replace of non-existent route"
1296 }
1297
1298 ipv4_rt_replace()
1299 {
1300         echo
1301         echo "IPv4 route replace tests"
1302
1303         ipv4_rt_replace_single
1304         ipv4_rt_replace_mpath
1305 }
1306
1307 ipv4_route_test()
1308 {
1309         route_setup
1310
1311         ipv4_rt_add
1312         ipv4_rt_replace
1313
1314         route_cleanup
1315 }
1316
1317 ipv4_addr_metric_test()
1318 {
1319         local rc
1320
1321         echo
1322         echo "IPv4 prefix route tests"
1323
1324         ip_addr_metric_check || return 1
1325
1326         setup
1327
1328         set -e
1329         $IP li add dummy1 type dummy
1330         $IP li add dummy2 type dummy
1331         $IP li set dummy1 up
1332         $IP li set dummy2 up
1333
1334         # default entry is metric 256
1335         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1336         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1337         set +e
1338
1339         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"
1340         log_test $? 0 "Default metric"
1341
1342         set -e
1343         run_cmd "$IP addr flush dev dummy1"
1344         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1345         set +e
1346
1347         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"
1348         log_test $? 0 "User specified metric on first device"
1349
1350         set -e
1351         run_cmd "$IP addr flush dev dummy2"
1352         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1353         set +e
1354
1355         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"
1356         log_test $? 0 "User specified metric on second device"
1357
1358         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1359         rc=$?
1360         if [ $rc -eq 0 ]; then
1361                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1362                 rc=$?
1363         fi
1364         log_test $rc 0 "Delete of address on first device"
1365
1366         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1367         rc=$?
1368         if [ $rc -eq 0 ]; then
1369                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1370                 rc=$?
1371         fi
1372         log_test $rc 0 "Modify metric of address"
1373
1374         # verify prefix route removed on down
1375         run_cmd "$IP li set dev dummy2 down"
1376         rc=$?
1377         if [ $rc -eq 0 ]; then
1378                 out=$($IP ro ls match 172.16.104.0/24)
1379                 check_expected "${out}" ""
1380                 rc=$?
1381         fi
1382         log_test $rc 0 "Prefix route removed on link down"
1383
1384         # verify prefix route re-inserted with assigned metric
1385         run_cmd "$IP li set dev dummy2 up"
1386         rc=$?
1387         if [ $rc -eq 0 ]; then
1388                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1389                 rc=$?
1390         fi
1391         log_test $rc 0 "Prefix route with metric on link up"
1392
1393         $IP li del dummy1
1394         $IP li del dummy2
1395         cleanup
1396 }
1397
1398 ipv4_route_metrics_test()
1399 {
1400         local rc
1401
1402         echo
1403         echo "IPv4 route add / append tests"
1404
1405         route_setup
1406
1407         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1408         rc=$?
1409         if [ $rc -eq 0 ]; then
1410                 check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1411                 rc=$?
1412         fi
1413         log_test $rc 0 "Single path route with mtu metric"
1414
1415
1416         run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1417         rc=$?
1418         if [ $rc -eq 0 ]; then
1419                 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"
1420                 rc=$?
1421         fi
1422         log_test $rc 0 "Multipath route with mtu metric"
1423
1424         $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1425         run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1426         log_test $? 0 "Using route with mtu metric"
1427
1428         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1429         log_test $? 2 "Invalid metric (fails metric_convert)"
1430
1431         route_cleanup
1432 }
1433
1434 ipv4_route_v6_gw_test()
1435 {
1436         local rc
1437
1438         echo
1439         echo "IPv4 route with IPv6 gateway tests"
1440
1441         route_setup
1442         sleep 2
1443
1444         #
1445         # single path route
1446         #
1447         run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1448         rc=$?
1449         log_test $rc 0 "Single path route with IPv6 gateway"
1450         if [ $rc -eq 0 ]; then
1451                 check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1452         fi
1453
1454         run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1455         log_test $rc 0 "Single path route with IPv6 gateway - ping"
1456
1457         run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1458         rc=$?
1459         log_test $rc 0 "Single path route delete"
1460         if [ $rc -eq 0 ]; then
1461                 check_route "172.16.112.0/24"
1462         fi
1463
1464         #
1465         # multipath - v6 then v4
1466         #
1467         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"
1468         rc=$?
1469         log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1470         if [ $rc -eq 0 ]; then
1471                 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"
1472         fi
1473
1474         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"
1475         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1476
1477         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"
1478         log_test $? 0 "    Multipath route delete exact match"
1479
1480         #
1481         # multipath - v4 then v6
1482         #
1483         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"
1484         rc=$?
1485         log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1486         if [ $rc -eq 0 ]; then
1487                 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"
1488         fi
1489
1490         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"
1491         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1492
1493         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"
1494         log_test $? 0 "    Multipath route delete exact match"
1495
1496         route_cleanup
1497 }
1498
1499 ################################################################################
1500 # usage
1501
1502 usage()
1503 {
1504         cat <<EOF
1505 usage: ${0##*/} OPTS
1506
1507         -t <test>   Test(s) to run (default: all)
1508                     (options: $TESTS)
1509         -p          Pause on fail
1510         -P          Pause after each test before cleanup
1511         -v          verbose mode (show commands and output)
1512 EOF
1513 }
1514
1515 ################################################################################
1516 # main
1517
1518 while getopts :t:pPhv o
1519 do
1520         case $o in
1521                 t) TESTS=$OPTARG;;
1522                 p) PAUSE_ON_FAIL=yes;;
1523                 P) PAUSE=yes;;
1524                 v) VERBOSE=$(($VERBOSE + 1));;
1525                 h) usage; exit 0;;
1526                 *) usage; exit 1;;
1527         esac
1528 done
1529
1530 PEER_CMD="ip netns exec ${PEER_NS}"
1531
1532 # make sure we don't pause twice
1533 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1534
1535 if [ "$(id -u)" -ne 0 ];then
1536         echo "SKIP: Need root privileges"
1537         exit $ksft_skip;
1538 fi
1539
1540 if [ ! -x "$(command -v ip)" ]; then
1541         echo "SKIP: Could not run test without ip tool"
1542         exit $ksft_skip
1543 fi
1544
1545 ip route help 2>&1 | grep -q fibmatch
1546 if [ $? -ne 0 ]; then
1547         echo "SKIP: iproute2 too old, missing fibmatch"
1548         exit $ksft_skip
1549 fi
1550
1551 # start clean
1552 cleanup &> /dev/null
1553
1554 for t in $TESTS
1555 do
1556         case $t in
1557         fib_unreg_test|unregister)      fib_unreg_test;;
1558         fib_down_test|down)             fib_down_test;;
1559         fib_carrier_test|carrier)       fib_carrier_test;;
1560         fib_nexthop_test|nexthop)       fib_nexthop_test;;
1561         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
1562         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
1563         ipv6_addr_metric)               ipv6_addr_metric_test;;
1564         ipv4_addr_metric)               ipv4_addr_metric_test;;
1565         ipv6_route_metrics)             ipv6_route_metrics_test;;
1566         ipv4_route_metrics)             ipv4_route_metrics_test;;
1567         ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
1568
1569         help) echo "Test names: $TESTS"; exit 0;;
1570         esac
1571 done
1572
1573 if [ "$TESTS" != "none" ]; then
1574         printf "\nTests passed: %3d\n" ${nsuccess}
1575         printf "Tests failed: %3d\n"   ${nfail}
1576 fi
1577
1578 exit $ret