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