ipv4: Fix incorrect route flushing when source address is deleted
[platform/kernel/linux-rpi.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 suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh"
13
14 VERBOSE=0
15 PAUSE_ON_FAIL=no
16 PAUSE=no
17 IP="ip -netns ns1"
18 NS_EXEC="ip netns exec ns1"
19
20 which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
21
22 log_test()
23 {
24         local rc=$1
25         local expected=$2
26         local msg="$3"
27
28         if [ ${rc} -eq ${expected} ]; then
29                 printf "    TEST: %-60s  [ OK ]\n" "${msg}"
30                 nsuccess=$((nsuccess+1))
31         else
32                 ret=1
33                 nfail=$((nfail+1))
34                 printf "    TEST: %-60s  [FAIL]\n" "${msg}"
35                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
36                 echo
37                         echo "hit enter to continue, 'q' to quit"
38                         read a
39                         [ "$a" = "q" ] && exit 1
40                 fi
41         fi
42
43         if [ "${PAUSE}" = "yes" ]; then
44                 echo
45                 echo "hit enter to continue, 'q' to quit"
46                 read a
47                 [ "$a" = "q" ] && exit 1
48         fi
49 }
50
51 setup()
52 {
53         set -e
54         ip netns add ns1
55         ip netns set ns1 auto
56         $IP link set dev lo up
57         ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
58         ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
59
60         $IP link add dummy0 type dummy
61         $IP link set dev dummy0 up
62         $IP address add 198.51.100.1/24 dev dummy0
63         $IP -6 address add 2001:db8:1::1/64 dev dummy0
64         set +e
65
66 }
67
68 cleanup()
69 {
70         $IP link del dev dummy0 &> /dev/null
71         ip netns del ns1
72         ip netns del ns2 &> /dev/null
73 }
74
75 get_linklocal()
76 {
77         local dev=$1
78         local addr
79
80         addr=$($IP -6 -br addr show dev ${dev} | \
81         awk '{
82                 for (i = 3; i <= NF; ++i) {
83                         if ($i ~ /^fe80/)
84                                 print $i
85                 }
86         }'
87         )
88         addr=${addr/\/*}
89
90         [ -z "$addr" ] && return 1
91
92         echo $addr
93
94         return 0
95 }
96
97 fib_unreg_unicast_test()
98 {
99         echo
100         echo "Single path route test"
101
102         setup
103
104         echo "    Start point"
105         $IP route get fibmatch 198.51.100.2 &> /dev/null
106         log_test $? 0 "IPv4 fibmatch"
107         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
108         log_test $? 0 "IPv6 fibmatch"
109
110         set -e
111         $IP link del dev dummy0
112         set +e
113
114         echo "    Nexthop device deleted"
115         $IP route get fibmatch 198.51.100.2 &> /dev/null
116         log_test $? 2 "IPv4 fibmatch - no route"
117         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
118         log_test $? 2 "IPv6 fibmatch - no route"
119
120         cleanup
121 }
122
123 fib_unreg_multipath_test()
124 {
125
126         echo
127         echo "Multipath route test"
128
129         setup
130
131         set -e
132         $IP link add dummy1 type dummy
133         $IP link set dev dummy1 up
134         $IP address add 192.0.2.1/24 dev dummy1
135         $IP -6 address add 2001:db8:2::1/64 dev dummy1
136
137         $IP route add 203.0.113.0/24 \
138                 nexthop via 198.51.100.2 dev dummy0 \
139                 nexthop via 192.0.2.2 dev dummy1
140         $IP -6 route add 2001:db8:3::/64 \
141                 nexthop via 2001:db8:1::2 dev dummy0 \
142                 nexthop via 2001:db8:2::2 dev dummy1
143         set +e
144
145         echo "    Start point"
146         $IP route get fibmatch 203.0.113.1 &> /dev/null
147         log_test $? 0 "IPv4 fibmatch"
148         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
149         log_test $? 0 "IPv6 fibmatch"
150
151         set -e
152         $IP link del dev dummy0
153         set +e
154
155         echo "    One nexthop device deleted"
156         $IP route get fibmatch 203.0.113.1 &> /dev/null
157         log_test $? 2 "IPv4 - multipath route removed on delete"
158
159         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
160         # In IPv6 we do not flush the entire multipath route.
161         log_test $? 0 "IPv6 - multipath down to single path"
162
163         set -e
164         $IP link del dev dummy1
165         set +e
166
167         echo "    Second nexthop device deleted"
168         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
169         log_test $? 2 "IPv6 - no route"
170
171         cleanup
172 }
173
174 fib_unreg_test()
175 {
176         fib_unreg_unicast_test
177         fib_unreg_multipath_test
178 }
179
180 fib_down_unicast_test()
181 {
182         echo
183         echo "Single path, admin down"
184
185         setup
186
187         echo "    Start point"
188         $IP route get fibmatch 198.51.100.2 &> /dev/null
189         log_test $? 0 "IPv4 fibmatch"
190         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
191         log_test $? 0 "IPv6 fibmatch"
192
193         set -e
194         $IP link set dev dummy0 down
195         set +e
196
197         echo "    Route deleted on down"
198         $IP route get fibmatch 198.51.100.2 &> /dev/null
199         log_test $? 2 "IPv4 fibmatch"
200         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
201         log_test $? 2 "IPv6 fibmatch"
202
203         cleanup
204 }
205
206 fib_down_multipath_test_do()
207 {
208         local down_dev=$1
209         local up_dev=$2
210
211         $IP route get fibmatch 203.0.113.1 \
212                 oif $down_dev &> /dev/null
213         log_test $? 2 "IPv4 fibmatch on down device"
214         $IP -6 route get fibmatch 2001:db8:3::1 \
215                 oif $down_dev &> /dev/null
216         log_test $? 2 "IPv6 fibmatch on down device"
217
218         $IP route get fibmatch 203.0.113.1 \
219                 oif $up_dev &> /dev/null
220         log_test $? 0 "IPv4 fibmatch on up device"
221         $IP -6 route get fibmatch 2001:db8:3::1 \
222                 oif $up_dev &> /dev/null
223         log_test $? 0 "IPv6 fibmatch on up device"
224
225         $IP route get fibmatch 203.0.113.1 | \
226                 grep $down_dev | grep -q "dead linkdown"
227         log_test $? 0 "IPv4 flags on down device"
228         $IP -6 route get fibmatch 2001:db8:3::1 | \
229                 grep $down_dev | grep -q "dead linkdown"
230         log_test $? 0 "IPv6 flags on down device"
231
232         $IP route get fibmatch 203.0.113.1 | \
233                 grep $up_dev | grep -q "dead linkdown"
234         log_test $? 1 "IPv4 flags on up device"
235         $IP -6 route get fibmatch 2001:db8:3::1 | \
236                 grep $up_dev | grep -q "dead linkdown"
237         log_test $? 1 "IPv6 flags on up device"
238 }
239
240 fib_down_multipath_test()
241 {
242         echo
243         echo "Admin down multipath"
244
245         setup
246
247         set -e
248         $IP link add dummy1 type dummy
249         $IP link set dev dummy1 up
250
251         $IP address add 192.0.2.1/24 dev dummy1
252         $IP -6 address add 2001:db8:2::1/64 dev dummy1
253
254         $IP route add 203.0.113.0/24 \
255                 nexthop via 198.51.100.2 dev dummy0 \
256                 nexthop via 192.0.2.2 dev dummy1
257         $IP -6 route add 2001:db8:3::/64 \
258                 nexthop via 2001:db8:1::2 dev dummy0 \
259                 nexthop via 2001:db8:2::2 dev dummy1
260         set +e
261
262         echo "    Verify start point"
263         $IP route get fibmatch 203.0.113.1 &> /dev/null
264         log_test $? 0 "IPv4 fibmatch"
265
266         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
267         log_test $? 0 "IPv6 fibmatch"
268
269         set -e
270         $IP link set dev dummy0 down
271         set +e
272
273         echo "    One device down, one up"
274         fib_down_multipath_test_do "dummy0" "dummy1"
275
276         set -e
277         $IP link set dev dummy0 up
278         $IP link set dev dummy1 down
279         set +e
280
281         echo "    Other device down and up"
282         fib_down_multipath_test_do "dummy1" "dummy0"
283
284         set -e
285         $IP link set dev dummy0 down
286         set +e
287
288         echo "    Both devices down"
289         $IP route get fibmatch 203.0.113.1 &> /dev/null
290         log_test $? 2 "IPv4 fibmatch"
291         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
292         log_test $? 2 "IPv6 fibmatch"
293
294         $IP link del dev dummy1
295         cleanup
296 }
297
298 fib_down_test()
299 {
300         fib_down_unicast_test
301         fib_down_multipath_test
302 }
303
304 # Local routes should not be affected when carrier changes.
305 fib_carrier_local_test()
306 {
307         echo
308         echo "Local carrier tests - single path"
309
310         setup
311
312         set -e
313         $IP link set dev dummy0 carrier on
314         set +e
315
316         echo "    Start point"
317         $IP route get fibmatch 198.51.100.1 &> /dev/null
318         log_test $? 0 "IPv4 fibmatch"
319         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
320         log_test $? 0 "IPv6 fibmatch"
321
322         $IP route get fibmatch 198.51.100.1 | \
323                 grep -q "linkdown"
324         log_test $? 1 "IPv4 - no linkdown flag"
325         $IP -6 route get fibmatch 2001:db8:1::1 | \
326                 grep -q "linkdown"
327         log_test $? 1 "IPv6 - no linkdown flag"
328
329         set -e
330         $IP link set dev dummy0 carrier off
331         sleep 1
332         set +e
333
334         echo "    Carrier off on nexthop"
335         $IP route get fibmatch 198.51.100.1 &> /dev/null
336         log_test $? 0 "IPv4 fibmatch"
337         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
338         log_test $? 0 "IPv6 fibmatch"
339
340         $IP route get fibmatch 198.51.100.1 | \
341                 grep -q "linkdown"
342         log_test $? 1 "IPv4 - linkdown flag set"
343         $IP -6 route get fibmatch 2001:db8:1::1 | \
344                 grep -q "linkdown"
345         log_test $? 1 "IPv6 - linkdown flag set"
346
347         set -e
348         $IP address add 192.0.2.1/24 dev dummy0
349         $IP -6 address add 2001:db8:2::1/64 dev dummy0
350         set +e
351
352         echo "    Route to local address with carrier down"
353         $IP route get fibmatch 192.0.2.1 &> /dev/null
354         log_test $? 0 "IPv4 fibmatch"
355         $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
356         log_test $? 0 "IPv6 fibmatch"
357
358         $IP route get fibmatch 192.0.2.1 | \
359                 grep -q "linkdown"
360         log_test $? 1 "IPv4 linkdown flag set"
361         $IP -6 route get fibmatch 2001:db8:2::1 | \
362                 grep -q "linkdown"
363         log_test $? 1 "IPv6 linkdown flag set"
364
365         cleanup
366 }
367
368 fib_carrier_unicast_test()
369 {
370         ret=0
371
372         echo
373         echo "Single path route carrier test"
374
375         setup
376
377         set -e
378         $IP link set dev dummy0 carrier on
379         set +e
380
381         echo "    Start point"
382         $IP route get fibmatch 198.51.100.2 &> /dev/null
383         log_test $? 0 "IPv4 fibmatch"
384         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
385         log_test $? 0 "IPv6 fibmatch"
386
387         $IP route get fibmatch 198.51.100.2 | \
388                 grep -q "linkdown"
389         log_test $? 1 "IPv4 no linkdown flag"
390         $IP -6 route get fibmatch 2001:db8:1::2 | \
391                 grep -q "linkdown"
392         log_test $? 1 "IPv6 no linkdown flag"
393
394         set -e
395         $IP link set dev dummy0 carrier off
396         sleep 1
397         set +e
398
399         echo "    Carrier down"
400         $IP route get fibmatch 198.51.100.2 &> /dev/null
401         log_test $? 0 "IPv4 fibmatch"
402         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
403         log_test $? 0 "IPv6 fibmatch"
404
405         $IP route get fibmatch 198.51.100.2 | \
406                 grep -q "linkdown"
407         log_test $? 0 "IPv4 linkdown flag set"
408         $IP -6 route get fibmatch 2001:db8:1::2 | \
409                 grep -q "linkdown"
410         log_test $? 0 "IPv6 linkdown flag set"
411
412         set -e
413         $IP address add 192.0.2.1/24 dev dummy0
414         $IP -6 address add 2001:db8:2::1/64 dev dummy0
415         set +e
416
417         echo "    Second address added with carrier down"
418         $IP route get fibmatch 192.0.2.2 &> /dev/null
419         log_test $? 0 "IPv4 fibmatch"
420         $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
421         log_test $? 0 "IPv6 fibmatch"
422
423         $IP route get fibmatch 192.0.2.2 | \
424                 grep -q "linkdown"
425         log_test $? 0 "IPv4 linkdown flag set"
426         $IP -6 route get fibmatch 2001:db8:2::2 | \
427                 grep -q "linkdown"
428         log_test $? 0 "IPv6 linkdown flag set"
429
430         cleanup
431 }
432
433 fib_carrier_test()
434 {
435         fib_carrier_local_test
436         fib_carrier_unicast_test
437 }
438
439 fib_rp_filter_test()
440 {
441         echo
442         echo "IPv4 rp_filter tests"
443
444         setup
445
446         set -e
447         ip netns add ns2
448         ip netns set ns2 auto
449
450         ip -netns ns2 link set dev lo up
451
452         $IP link add name veth1 type veth peer name veth2
453         $IP link set dev veth2 netns ns2
454         $IP address add 192.0.2.1/24 dev veth1
455         ip -netns ns2 address add 192.0.2.1/24 dev veth2
456         $IP link set dev veth1 up
457         ip -netns ns2 link set dev veth2 up
458
459         $IP link set dev lo address 52:54:00:6a:c7:5e
460         $IP link set dev veth1 address 52:54:00:6a:c7:5e
461         ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
462         ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
463
464         # 1. (ns2) redirect lo's egress to veth2's egress
465         ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
466         ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
467                 action mirred egress redirect dev veth2
468         ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
469                 action mirred egress redirect dev veth2
470
471         # 2. (ns1) redirect veth1's ingress to lo's ingress
472         $NS_EXEC tc qdisc add dev veth1 ingress
473         $NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
474                 action mirred ingress redirect dev lo
475         $NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
476                 action mirred ingress redirect dev lo
477
478         # 3. (ns1) redirect lo's egress to veth1's egress
479         $NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
480         $NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
481                 action mirred egress redirect dev veth1
482         $NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
483                 action mirred egress redirect dev veth1
484
485         # 4. (ns2) redirect veth2's ingress to lo's ingress
486         ip netns exec ns2 tc qdisc add dev veth2 ingress
487         ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
488                 action mirred ingress redirect dev lo
489         ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
490                 action mirred ingress redirect dev lo
491
492         $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
493         $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
494         $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
495         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
496         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
497         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
498         set +e
499
500         run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
501         log_test $? 0 "rp_filter passes local packets"
502
503         run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
504         log_test $? 0 "rp_filter passes loopback packets"
505
506         cleanup
507 }
508
509 ################################################################################
510 # Tests on nexthop spec
511
512 # run 'ip route add' with given spec
513 add_rt()
514 {
515         local desc="$1"
516         local erc=$2
517         local vrf=$3
518         local pfx=$4
519         local gw=$5
520         local dev=$6
521         local cmd out rc
522
523         [ "$vrf" = "-" ] && vrf="default"
524         [ -n "$gw" ] && gw="via $gw"
525         [ -n "$dev" ] && dev="dev $dev"
526
527         cmd="$IP route add vrf $vrf $pfx $gw $dev"
528         if [ "$VERBOSE" = "1" ]; then
529                 printf "\n    COMMAND: $cmd\n"
530         fi
531
532         out=$(eval $cmd 2>&1)
533         rc=$?
534         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
535                 echo "    $out"
536         fi
537         log_test $rc $erc "$desc"
538 }
539
540 fib4_nexthop()
541 {
542         echo
543         echo "IPv4 nexthop tests"
544
545         echo "<<< write me >>>"
546 }
547
548 fib6_nexthop()
549 {
550         local lldummy=$(get_linklocal dummy0)
551         local llv1=$(get_linklocal dummy0)
552
553         if [ -z "$lldummy" ]; then
554                 echo "Failed to get linklocal address for dummy0"
555                 return 1
556         fi
557         if [ -z "$llv1" ]; then
558                 echo "Failed to get linklocal address for veth1"
559                 return 1
560         fi
561
562         echo
563         echo "IPv6 nexthop tests"
564
565         add_rt "Directly connected nexthop, unicast address" 0 \
566                 - 2001:db8:101::/64 2001:db8:1::2
567         add_rt "Directly connected nexthop, unicast address with device" 0 \
568                 - 2001:db8:102::/64 2001:db8:1::2 "dummy0"
569         add_rt "Gateway is linklocal address" 0 \
570                 - 2001:db8:103::1/64 $llv1 "veth0"
571
572         # fails because LL address requires a device
573         add_rt "Gateway is linklocal address, no device" 2 \
574                 - 2001:db8:104::1/64 $llv1
575
576         # local address can not be a gateway
577         add_rt "Gateway can not be local unicast address" 2 \
578                 - 2001:db8:105::/64 2001:db8:1::1
579         add_rt "Gateway can not be local unicast address, with device" 2 \
580                 - 2001:db8:106::/64 2001:db8:1::1 "dummy0"
581         add_rt "Gateway can not be a local linklocal address" 2 \
582                 - 2001:db8:107::1/64 $lldummy "dummy0"
583
584         # VRF tests
585         add_rt "Gateway can be local address in a VRF" 0 \
586                 - 2001:db8:108::/64 2001:db8:51::2
587         add_rt "Gateway can be local address in a VRF, with device" 0 \
588                 - 2001:db8:109::/64 2001:db8:51::2 "veth0"
589         add_rt "Gateway can be local linklocal address in a VRF" 0 \
590                 - 2001:db8:110::1/64 $llv1 "veth0"
591
592         add_rt "Redirect to VRF lookup" 0 \
593                 - 2001:db8:111::/64 "" "red"
594
595         add_rt "VRF route, gateway can be local address in default VRF" 0 \
596                 red 2001:db8:112::/64 2001:db8:51::1
597
598         # local address in same VRF fails
599         add_rt "VRF route, gateway can not be a local address" 2 \
600                 red 2001:db8:113::1/64 2001:db8:2::1
601         add_rt "VRF route, gateway can not be a local addr with device" 2 \
602                 red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
603 }
604
605 # Default VRF:
606 #   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
607 #   veth0  - 192.0.2.1/24    2001:db8:51::1/64
608 #
609 # VRF red:
610 #   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
611 #   veth1  - 192.0.2.2/24   2001:db8:51::2/64
612 #
613 #  [ dummy0   veth0 ]--[ veth1   dummy1 ]
614
615 fib_nexthop_test()
616 {
617         setup
618
619         set -e
620
621         $IP -4 rule add pref 32765 table local
622         $IP -4 rule del pref 0
623         $IP -6 rule add pref 32765 table local
624         $IP -6 rule del pref 0
625
626         $IP link add red type vrf table 1
627         $IP link set red up
628         $IP -4 route add vrf red unreachable default metric 4278198272
629         $IP -6 route add vrf red unreachable default metric 4278198272
630
631         $IP link add veth0 type veth peer name veth1
632         $IP link set dev veth0 up
633         $IP address add 192.0.2.1/24 dev veth0
634         $IP -6 address add 2001:db8:51::1/64 dev veth0
635
636         $IP link set dev veth1 vrf red up
637         $IP address add 192.0.2.2/24 dev veth1
638         $IP -6 address add 2001:db8:51::2/64 dev veth1
639
640         $IP link add dummy1 type dummy
641         $IP link set dev dummy1 vrf red up
642         $IP address add 192.168.2.1/24 dev dummy1
643         $IP -6 address add 2001:db8:2::1/64 dev dummy1
644         set +e
645
646         sleep 1
647         fib4_nexthop
648         fib6_nexthop
649
650         (
651         $IP link del dev dummy1
652         $IP link del veth0
653         $IP link del red
654         ) 2>/dev/null
655         cleanup
656 }
657
658 fib_suppress_test()
659 {
660         echo
661         echo "FIB rule with suppress_prefixlength"
662         setup
663
664         $IP link add dummy1 type dummy
665         $IP link set dummy1 up
666         $IP -6 route add default dev dummy1
667         $IP -6 rule add table main suppress_prefixlength 0
668         ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
669         $IP -6 rule del table main suppress_prefixlength 0
670         $IP link del dummy1
671
672         # If we got here without crashing, we're good.
673         log_test 0 0 "FIB rule suppress test"
674
675         cleanup
676 }
677
678 ################################################################################
679 # Tests on route add and replace
680
681 run_cmd()
682 {
683         local cmd="$1"
684         local out
685         local stderr="2>/dev/null"
686
687         if [ "$VERBOSE" = "1" ]; then
688                 printf "    COMMAND: $cmd\n"
689                 stderr=
690         fi
691
692         out=$(eval $cmd $stderr)
693         rc=$?
694         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
695                 echo "    $out"
696         fi
697
698         [ "$VERBOSE" = "1" ] && echo
699
700         return $rc
701 }
702
703 check_expected()
704 {
705         local out="$1"
706         local expected="$2"
707         local rc=0
708
709         [ "${out}" = "${expected}" ] && return 0
710
711         if [ -z "${out}" ]; then
712                 if [ "$VERBOSE" = "1" ]; then
713                         printf "\nNo route entry found\n"
714                         printf "Expected:\n"
715                         printf "    ${expected}\n"
716                 fi
717                 return 1
718         fi
719
720         # tricky way to convert output to 1-line without ip's
721         # messy '\'; this drops all extra white space
722         out=$(echo ${out})
723         if [ "${out}" != "${expected}" ]; then
724                 rc=1
725                 if [ "${VERBOSE}" = "1" ]; then
726                         printf "    Unexpected route entry. Have:\n"
727                         printf "        ${out}\n"
728                         printf "    Expected:\n"
729                         printf "        ${expected}\n\n"
730                 fi
731         fi
732
733         return $rc
734 }
735
736 # add route for a prefix, flushing any existing routes first
737 # expected to be the first step of a test
738 add_route6()
739 {
740         local pfx="$1"
741         local nh="$2"
742         local out
743
744         if [ "$VERBOSE" = "1" ]; then
745                 echo
746                 echo "    ##################################################"
747                 echo
748         fi
749
750         run_cmd "$IP -6 ro flush ${pfx}"
751         [ $? -ne 0 ] && exit 1
752
753         out=$($IP -6 ro ls match ${pfx})
754         if [ -n "$out" ]; then
755                 echo "Failed to flush routes for prefix used for tests."
756                 exit 1
757         fi
758
759         run_cmd "$IP -6 ro add ${pfx} ${nh}"
760         if [ $? -ne 0 ]; then
761                 echo "Failed to add initial route for test."
762                 exit 1
763         fi
764 }
765
766 # add initial route - used in replace route tests
767 add_initial_route6()
768 {
769         add_route6 "2001:db8:104::/64" "$1"
770 }
771
772 check_route6()
773 {
774         local pfx
775         local expected="$1"
776         local out
777         local rc=0
778
779         set -- $expected
780         pfx=$1
781
782         out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
783         check_expected "${out}" "${expected}"
784 }
785
786 route_cleanup()
787 {
788         $IP li del red 2>/dev/null
789         $IP li del dummy1 2>/dev/null
790         $IP li del veth1 2>/dev/null
791         $IP li del veth3 2>/dev/null
792
793         cleanup &> /dev/null
794 }
795
796 route_setup()
797 {
798         route_cleanup
799         setup
800
801         [ "${VERBOSE}" = "1" ] && set -x
802         set -e
803
804         ip netns add ns2
805         ip netns set ns2 auto
806         ip -netns ns2 link set dev lo up
807         ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
808         ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
809
810         $IP li add veth1 type veth peer name veth2
811         $IP li add veth3 type veth peer name veth4
812
813         $IP li set veth1 up
814         $IP li set veth3 up
815         $IP li set veth2 netns ns2 up
816         $IP li set veth4 netns ns2 up
817         ip -netns ns2 li add dummy1 type dummy
818         ip -netns ns2 li set dummy1 up
819
820         $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
821         $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
822         $IP addr add 172.16.101.1/24 dev veth1
823         $IP addr add 172.16.103.1/24 dev veth3
824
825         ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
826         ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
827         ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
828
829         ip -netns ns2 addr add 172.16.101.2/24 dev veth2
830         ip -netns ns2 addr add 172.16.103.2/24 dev veth4
831         ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
832
833         set +e
834 }
835
836 # assumption is that basic add of a single path route works
837 # otherwise just adding an address on an interface is broken
838 ipv6_rt_add()
839 {
840         local rc
841
842         echo
843         echo "IPv6 route add / append tests"
844
845         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
846         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
847         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
848         log_test $? 2 "Attempt to add duplicate route - gw"
849
850         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
851         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
852         run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
853         log_test $? 2 "Attempt to add duplicate route - dev only"
854
855         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
856         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
857         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
858         log_test $? 2 "Attempt to add duplicate route - reject route"
859
860         # route append with same prefix adds a new route
861         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
862         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
863         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
864         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"
865         log_test $? 0 "Append nexthop to existing route - gw"
866
867         # insert mpath directly
868         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
869         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"
870         log_test $? 0 "Add multipath route"
871
872         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
873         run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
874         log_test $? 2 "Attempt to add duplicate multipath route"
875
876         # insert of a second route without append but different metric
877         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
878         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
879         rc=$?
880         if [ $rc -eq 0 ]; then
881                 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
882                 rc=$?
883         fi
884         log_test $rc 0 "Route add with different metrics"
885
886         run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
887         rc=$?
888         if [ $rc -eq 0 ]; then
889                 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"
890                 rc=$?
891         fi
892         log_test $rc 0 "Route delete with metric"
893 }
894
895 ipv6_rt_replace_single()
896 {
897         # single path with single path
898         #
899         add_initial_route6 "via 2001:db8:101::2"
900         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
901         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
902         log_test $? 0 "Single path with single path"
903
904         # single path with multipath
905         #
906         add_initial_route6 "nexthop via 2001:db8:101::2"
907         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
908         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"
909         log_test $? 0 "Single path with multipath"
910
911         # single path with single path using MULTIPATH attribute
912         #
913         add_initial_route6 "via 2001:db8:101::2"
914         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
915         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
916         log_test $? 0 "Single path with single path via multipath attribute"
917
918         # route replace fails - invalid nexthop
919         add_initial_route6 "via 2001:db8:101::2"
920         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
921         if [ $? -eq 0 ]; then
922                 # previous command is expected to fail so if it returns 0
923                 # that means the test failed.
924                 log_test 0 1 "Invalid nexthop"
925         else
926                 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
927                 log_test $? 0 "Invalid nexthop"
928         fi
929
930         # replace non-existent route
931         # - note use of change versus replace since ip adds NLM_F_CREATE
932         #   for replace
933         add_initial_route6 "via 2001:db8:101::2"
934         run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
935         log_test $? 2 "Single path - replace of non-existent route"
936 }
937
938 ipv6_rt_replace_mpath()
939 {
940         # multipath with multipath
941         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
942         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
943         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"
944         log_test $? 0 "Multipath with multipath"
945
946         # multipath with single
947         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
948         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
949         check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
950         log_test $? 0 "Multipath with single path"
951
952         # multipath with single
953         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
954         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
955         check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
956         log_test $? 0 "Multipath with single path via multipath attribute"
957
958         # multipath with dev-only
959         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
960         run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
961         check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
962         log_test $? 0 "Multipath with dev-only"
963
964         # route replace fails - invalid nexthop 1
965         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
966         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
967         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"
968         log_test $? 0 "Multipath - invalid first nexthop"
969
970         # route replace fails - invalid nexthop 2
971         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
972         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
973         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"
974         log_test $? 0 "Multipath - invalid second nexthop"
975
976         # multipath non-existent route
977         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
978         run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
979         log_test $? 2 "Multipath - replace of non-existent route"
980 }
981
982 ipv6_rt_replace()
983 {
984         echo
985         echo "IPv6 route replace tests"
986
987         ipv6_rt_replace_single
988         ipv6_rt_replace_mpath
989 }
990
991 ipv6_rt_dsfield()
992 {
993         echo
994         echo "IPv6 route with dsfield tests"
995
996         run_cmd "$IP -6 route flush 2001:db8:102::/64"
997
998         # IPv6 doesn't support routing based on dsfield
999         run_cmd "$IP -6 route add 2001:db8:102::/64 dsfield 0x04 via 2001:db8:101::2"
1000         log_test $? 2 "Reject route with dsfield"
1001 }
1002
1003 ipv6_route_test()
1004 {
1005         route_setup
1006
1007         ipv6_rt_add
1008         ipv6_rt_replace
1009         ipv6_rt_dsfield
1010
1011         route_cleanup
1012 }
1013
1014 ip_addr_metric_check()
1015 {
1016         ip addr help 2>&1 | grep -q metric
1017         if [ $? -ne 0 ]; then
1018                 echo "iproute2 command does not support metric for addresses. Skipping test"
1019                 return 1
1020         fi
1021
1022         return 0
1023 }
1024
1025 ipv6_addr_metric_test()
1026 {
1027         local rc
1028
1029         echo
1030         echo "IPv6 prefix route tests"
1031
1032         ip_addr_metric_check || return 1
1033
1034         setup
1035
1036         set -e
1037         $IP li add dummy1 type dummy
1038         $IP li add dummy2 type dummy
1039         $IP li set dummy1 up
1040         $IP li set dummy2 up
1041
1042         # default entry is metric 256
1043         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1044         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1045         set +e
1046
1047         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1048         log_test $? 0 "Default metric"
1049
1050         set -e
1051         run_cmd "$IP -6 addr flush dev dummy1"
1052         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1053         set +e
1054
1055         check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1056         log_test $? 0 "User specified metric on first device"
1057
1058         set -e
1059         run_cmd "$IP -6 addr flush dev dummy2"
1060         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1061         set +e
1062
1063         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1064         log_test $? 0 "User specified metric on second device"
1065
1066         run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1067         rc=$?
1068         if [ $rc -eq 0 ]; then
1069                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1070                 rc=$?
1071         fi
1072         log_test $rc 0 "Delete of address on first device"
1073
1074         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1075         rc=$?
1076         if [ $rc -eq 0 ]; then
1077                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1078                 rc=$?
1079         fi
1080         log_test $rc 0 "Modify metric of address"
1081
1082         # verify prefix route removed on down
1083         run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1084         run_cmd "$IP li set dev dummy2 down"
1085         rc=$?
1086         if [ $rc -eq 0 ]; then
1087                 out=$($IP -6 ro ls match 2001:db8:104::/64)
1088                 check_expected "${out}" ""
1089                 rc=$?
1090         fi
1091         log_test $rc 0 "Prefix route removed on link down"
1092
1093         # verify prefix route re-inserted with assigned metric
1094         run_cmd "$IP li set dev dummy2 up"
1095         rc=$?
1096         if [ $rc -eq 0 ]; then
1097                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1098                 rc=$?
1099         fi
1100         log_test $rc 0 "Prefix route with metric on link up"
1101
1102         # verify peer metric added correctly
1103         set -e
1104         run_cmd "$IP -6 addr flush dev dummy2"
1105         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1106         set +e
1107
1108         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1109         log_test $? 0 "Set metric with peer route on local side"
1110         check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1111         log_test $? 0 "Set metric with peer route on peer side"
1112
1113         set -e
1114         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1115         set +e
1116
1117         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1118         log_test $? 0 "Modify metric and peer address on local side"
1119         check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1120         log_test $? 0 "Modify metric and peer address on peer side"
1121
1122         $IP li del dummy1
1123         $IP li del dummy2
1124         cleanup
1125 }
1126
1127 ipv6_route_metrics_test()
1128 {
1129         local rc
1130
1131         echo
1132         echo "IPv6 routes with metrics"
1133
1134         route_setup
1135
1136         #
1137         # single path with metrics
1138         #
1139         run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1140         rc=$?
1141         if [ $rc -eq 0 ]; then
1142                 check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1143                 rc=$?
1144         fi
1145         log_test $rc 0 "Single path route with mtu metric"
1146
1147
1148         #
1149         # multipath via separate routes with metrics
1150         #
1151         run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1152         run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1153         rc=$?
1154         if [ $rc -eq 0 ]; then
1155                 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"
1156                 rc=$?
1157         fi
1158         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1159
1160         # second route is coalesced to first to make a multipath route.
1161         # MTU of the second path is hidden from display!
1162         run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1163         run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1164         rc=$?
1165         if [ $rc -eq 0 ]; then
1166                 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"
1167                 rc=$?
1168         fi
1169         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1170
1171         run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1172         if [ $? -eq 0 ]; then
1173                 check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1174                 log_test $? 0 "    MTU of second leg"
1175         fi
1176
1177         #
1178         # multipath with metrics
1179         #
1180         run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1181         rc=$?
1182         if [ $rc -eq 0 ]; then
1183                 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"
1184                 rc=$?
1185         fi
1186         log_test $rc 0 "Multipath route with mtu metric"
1187
1188         $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1189         run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1190         log_test $? 0 "Using route with mtu metric"
1191
1192         run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1193         log_test $? 2 "Invalid metric (fails metric_convert)"
1194
1195         route_cleanup
1196 }
1197
1198 # add route for a prefix, flushing any existing routes first
1199 # expected to be the first step of a test
1200 add_route()
1201 {
1202         local pfx="$1"
1203         local nh="$2"
1204         local out
1205
1206         if [ "$VERBOSE" = "1" ]; then
1207                 echo
1208                 echo "    ##################################################"
1209                 echo
1210         fi
1211
1212         run_cmd "$IP ro flush ${pfx}"
1213         [ $? -ne 0 ] && exit 1
1214
1215         out=$($IP ro ls match ${pfx})
1216         if [ -n "$out" ]; then
1217                 echo "Failed to flush routes for prefix used for tests."
1218                 exit 1
1219         fi
1220
1221         run_cmd "$IP ro add ${pfx} ${nh}"
1222         if [ $? -ne 0 ]; then
1223                 echo "Failed to add initial route for test."
1224                 exit 1
1225         fi
1226 }
1227
1228 # add initial route - used in replace route tests
1229 add_initial_route()
1230 {
1231         add_route "172.16.104.0/24" "$1"
1232 }
1233
1234 check_route()
1235 {
1236         local pfx
1237         local expected="$1"
1238         local out
1239
1240         set -- $expected
1241         pfx=$1
1242         [ "${pfx}" = "unreachable" ] && pfx=$2
1243
1244         out=$($IP ro ls match ${pfx})
1245         check_expected "${out}" "${expected}"
1246 }
1247
1248 # assumption is that basic add of a single path route works
1249 # otherwise just adding an address on an interface is broken
1250 ipv4_rt_add()
1251 {
1252         local rc
1253
1254         echo
1255         echo "IPv4 route add / append tests"
1256
1257         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1258         add_route "172.16.104.0/24" "via 172.16.101.2"
1259         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1260         log_test $? 2 "Attempt to add duplicate route - gw"
1261
1262         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1263         add_route "172.16.104.0/24" "via 172.16.101.2"
1264         run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1265         log_test $? 2 "Attempt to add duplicate route - dev only"
1266
1267         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1268         add_route "172.16.104.0/24" "via 172.16.101.2"
1269         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1270         log_test $? 2 "Attempt to add duplicate route - reject route"
1271
1272         # iproute2 prepend only sets NLM_F_CREATE
1273         # - adds a new route; does NOT convert existing route to ECMP
1274         add_route "172.16.104.0/24" "via 172.16.101.2"
1275         run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1276         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"
1277         log_test $? 0 "Add new nexthop for existing prefix"
1278
1279         # route append with same prefix adds a new route
1280         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1281         add_route "172.16.104.0/24" "via 172.16.101.2"
1282         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1283         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"
1284         log_test $? 0 "Append nexthop to existing route - gw"
1285
1286         add_route "172.16.104.0/24" "via 172.16.101.2"
1287         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1288         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1289         log_test $? 0 "Append nexthop to existing route - dev only"
1290
1291         add_route "172.16.104.0/24" "via 172.16.101.2"
1292         run_cmd "$IP ro append unreachable 172.16.104.0/24"
1293         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1294         log_test $? 0 "Append nexthop to existing route - reject route"
1295
1296         run_cmd "$IP ro flush 172.16.104.0/24"
1297         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1298         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1299         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1300         log_test $? 0 "Append nexthop to existing reject route - gw"
1301
1302         run_cmd "$IP ro flush 172.16.104.0/24"
1303         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1304         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1305         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1306         log_test $? 0 "Append nexthop to existing reject route - dev only"
1307
1308         # insert mpath directly
1309         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1310         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"
1311         log_test $? 0 "add multipath route"
1312
1313         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1314         run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1315         log_test $? 2 "Attempt to add duplicate multipath route"
1316
1317         # insert of a second route without append but different metric
1318         add_route "172.16.104.0/24" "via 172.16.101.2"
1319         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1320         rc=$?
1321         if [ $rc -eq 0 ]; then
1322                 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1323                 rc=$?
1324         fi
1325         log_test $rc 0 "Route add with different metrics"
1326
1327         run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1328         rc=$?
1329         if [ $rc -eq 0 ]; then
1330                 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"
1331                 rc=$?
1332         fi
1333         log_test $rc 0 "Route delete with metric"
1334 }
1335
1336 ipv4_rt_replace_single()
1337 {
1338         # single path with single path
1339         #
1340         add_initial_route "via 172.16.101.2"
1341         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1342         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1343         log_test $? 0 "Single path with single path"
1344
1345         # single path with multipath
1346         #
1347         add_initial_route "nexthop via 172.16.101.2"
1348         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1349         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"
1350         log_test $? 0 "Single path with multipath"
1351
1352         # single path with reject
1353         #
1354         add_initial_route "nexthop via 172.16.101.2"
1355         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1356         check_route "unreachable 172.16.104.0/24"
1357         log_test $? 0 "Single path with reject route"
1358
1359         # single path with single path using MULTIPATH attribute
1360         #
1361         add_initial_route "via 172.16.101.2"
1362         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1363         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1364         log_test $? 0 "Single path with single path via multipath attribute"
1365
1366         # route replace fails - invalid nexthop
1367         add_initial_route "via 172.16.101.2"
1368         run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1369         if [ $? -eq 0 ]; then
1370                 # previous command is expected to fail so if it returns 0
1371                 # that means the test failed.
1372                 log_test 0 1 "Invalid nexthop"
1373         else
1374                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1375                 log_test $? 0 "Invalid nexthop"
1376         fi
1377
1378         # replace non-existent route
1379         # - note use of change versus replace since ip adds NLM_F_CREATE
1380         #   for replace
1381         add_initial_route "via 172.16.101.2"
1382         run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1383         log_test $? 2 "Single path - replace of non-existent route"
1384 }
1385
1386 ipv4_rt_replace_mpath()
1387 {
1388         # multipath with multipath
1389         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1390         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1391         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"
1392         log_test $? 0 "Multipath with multipath"
1393
1394         # multipath with single
1395         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1396         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1397         check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1398         log_test $? 0 "Multipath with single path"
1399
1400         # multipath with single
1401         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1402         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1403         check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1404         log_test $? 0 "Multipath with single path via multipath attribute"
1405
1406         # multipath with reject
1407         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1408         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1409         check_route "unreachable 172.16.104.0/24"
1410         log_test $? 0 "Multipath with reject route"
1411
1412         # route replace fails - invalid nexthop 1
1413         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1414         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1415         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"
1416         log_test $? 0 "Multipath - invalid first nexthop"
1417
1418         # route replace fails - invalid nexthop 2
1419         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1420         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1421         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"
1422         log_test $? 0 "Multipath - invalid second nexthop"
1423
1424         # multipath non-existent route
1425         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1426         run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1427         log_test $? 2 "Multipath - replace of non-existent route"
1428 }
1429
1430 ipv4_rt_replace()
1431 {
1432         echo
1433         echo "IPv4 route replace tests"
1434
1435         ipv4_rt_replace_single
1436         ipv4_rt_replace_mpath
1437 }
1438
1439 # checks that cached input route on VRF port is deleted
1440 # when VRF is deleted
1441 ipv4_local_rt_cache()
1442 {
1443         run_cmd "ip addr add 10.0.0.1/32 dev lo"
1444         run_cmd "ip netns add test-ns"
1445         run_cmd "ip link add veth-outside type veth peer name veth-inside"
1446         run_cmd "ip link add vrf-100 type vrf table 1100"
1447         run_cmd "ip link set veth-outside master vrf-100"
1448         run_cmd "ip link set veth-inside netns test-ns"
1449         run_cmd "ip link set veth-outside up"
1450         run_cmd "ip link set vrf-100 up"
1451         run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1452         run_cmd "ip netns exec test-ns ip link set veth-inside up"
1453         run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1454         run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
1455         run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
1456         run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
1457         run_cmd "ip link delete vrf-100"
1458
1459         # if we do not hang test is a success
1460         log_test $? 0 "Cached route removed from VRF port device"
1461 }
1462
1463 ipv4_rt_dsfield()
1464 {
1465         echo
1466         echo "IPv4 route with dsfield tests"
1467
1468         run_cmd "$IP route flush 172.16.102.0/24"
1469
1470         # New routes should reject dsfield options that interfere with ECN
1471         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
1472         log_test $? 2 "Reject route with dsfield 0x01"
1473
1474         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
1475         log_test $? 2 "Reject route with dsfield 0x02"
1476
1477         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
1478         log_test $? 2 "Reject route with dsfield 0x03"
1479
1480         # A generic route that doesn't take DSCP into account
1481         run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
1482
1483         # A more specific route for DSCP 0x10
1484         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
1485
1486         # DSCP 0x10 should match the specific route, no matter the ECN bits
1487         $IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
1488                 grep -q "via 172.16.103.2"
1489         log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
1490
1491         $IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
1492                 grep -q "via 172.16.103.2"
1493         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
1494
1495         $IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
1496                 grep -q "via 172.16.103.2"
1497         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
1498
1499         $IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
1500                 grep -q "via 172.16.103.2"
1501         log_test $? 0 "IPv4 route with DSCP and ECN:CE"
1502
1503         # Unknown DSCP should match the generic route, no matter the ECN bits
1504         $IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
1505                 grep -q "via 172.16.101.2"
1506         log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
1507
1508         $IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
1509                 grep -q "via 172.16.101.2"
1510         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
1511
1512         $IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
1513                 grep -q "via 172.16.101.2"
1514         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
1515
1516         $IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
1517                 grep -q "via 172.16.101.2"
1518         log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
1519
1520         # Null DSCP should match the generic route, no matter the ECN bits
1521         $IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
1522                 grep -q "via 172.16.101.2"
1523         log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
1524
1525         $IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
1526                 grep -q "via 172.16.101.2"
1527         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
1528
1529         $IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
1530                 grep -q "via 172.16.101.2"
1531         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
1532
1533         $IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
1534                 grep -q "via 172.16.101.2"
1535         log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
1536 }
1537
1538 ipv4_route_test()
1539 {
1540         route_setup
1541
1542         ipv4_rt_add
1543         ipv4_rt_replace
1544         ipv4_local_rt_cache
1545         ipv4_rt_dsfield
1546
1547         route_cleanup
1548 }
1549
1550 ipv4_addr_metric_test()
1551 {
1552         local rc
1553
1554         echo
1555         echo "IPv4 prefix route tests"
1556
1557         ip_addr_metric_check || return 1
1558
1559         setup
1560
1561         set -e
1562         $IP li add dummy1 type dummy
1563         $IP li add dummy2 type dummy
1564         $IP li set dummy1 up
1565         $IP li set dummy2 up
1566
1567         # default entry is metric 256
1568         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1569         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1570         set +e
1571
1572         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"
1573         log_test $? 0 "Default metric"
1574
1575         set -e
1576         run_cmd "$IP addr flush dev dummy1"
1577         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1578         set +e
1579
1580         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"
1581         log_test $? 0 "User specified metric on first device"
1582
1583         set -e
1584         run_cmd "$IP addr flush dev dummy2"
1585         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1586         set +e
1587
1588         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"
1589         log_test $? 0 "User specified metric on second device"
1590
1591         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1592         rc=$?
1593         if [ $rc -eq 0 ]; then
1594                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1595                 rc=$?
1596         fi
1597         log_test $rc 0 "Delete of address on first device"
1598
1599         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1600         rc=$?
1601         if [ $rc -eq 0 ]; then
1602                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1603                 rc=$?
1604         fi
1605         log_test $rc 0 "Modify metric of address"
1606
1607         # verify prefix route removed on down
1608         run_cmd "$IP li set dev dummy2 down"
1609         rc=$?
1610         if [ $rc -eq 0 ]; then
1611                 out=$($IP ro ls match 172.16.104.0/24)
1612                 check_expected "${out}" ""
1613                 rc=$?
1614         fi
1615         log_test $rc 0 "Prefix route removed on link down"
1616
1617         # verify prefix route re-inserted with assigned metric
1618         run_cmd "$IP li set dev dummy2 up"
1619         rc=$?
1620         if [ $rc -eq 0 ]; then
1621                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1622                 rc=$?
1623         fi
1624         log_test $rc 0 "Prefix route with metric on link up"
1625
1626         # explicitly check for metric changes on edge scenarios
1627         run_cmd "$IP addr flush dev dummy2"
1628         run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1629         run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1630         rc=$?
1631         if [ $rc -eq 0 ]; then
1632                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1633                 rc=$?
1634         fi
1635         log_test $rc 0 "Modify metric of .0/24 address"
1636
1637         run_cmd "$IP addr flush dev dummy2"
1638         run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1639         rc=$?
1640         if [ $rc -eq 0 ]; then
1641                 check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1642                 rc=$?
1643         fi
1644         log_test $rc 0 "Set metric of address with peer route"
1645
1646         run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1647         rc=$?
1648         if [ $rc -eq 0 ]; then
1649                 check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1650                 rc=$?
1651         fi
1652         log_test $rc 0 "Modify metric and peer address for peer route"
1653
1654         $IP li del dummy1
1655         $IP li del dummy2
1656         cleanup
1657 }
1658
1659 ipv4_route_metrics_test()
1660 {
1661         local rc
1662
1663         echo
1664         echo "IPv4 route add / append tests"
1665
1666         route_setup
1667
1668         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1669         rc=$?
1670         if [ $rc -eq 0 ]; then
1671                 check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1672                 rc=$?
1673         fi
1674         log_test $rc 0 "Single path route with mtu metric"
1675
1676
1677         run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1678         rc=$?
1679         if [ $rc -eq 0 ]; then
1680                 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"
1681                 rc=$?
1682         fi
1683         log_test $rc 0 "Multipath route with mtu metric"
1684
1685         $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1686         run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1687         log_test $? 0 "Using route with mtu metric"
1688
1689         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1690         log_test $? 2 "Invalid metric (fails metric_convert)"
1691
1692         route_cleanup
1693 }
1694
1695 ipv4_del_addr_test()
1696 {
1697         echo
1698         echo "IPv4 delete address route tests"
1699
1700         setup
1701
1702         set -e
1703         $IP li add dummy1 type dummy
1704         $IP li set dummy1 up
1705         $IP li add dummy2 type dummy
1706         $IP li set dummy2 up
1707         $IP li add red type vrf table 1111
1708         $IP li set red up
1709         $IP ro add vrf red unreachable default
1710         $IP li set dummy2 vrf red
1711
1712         $IP addr add dev dummy1 172.16.104.1/24
1713         $IP addr add dev dummy1 172.16.104.11/24
1714         $IP addr add dev dummy1 172.16.104.12/24
1715         $IP addr add dev dummy2 172.16.104.1/24
1716         $IP addr add dev dummy2 172.16.104.11/24
1717         $IP addr add dev dummy2 172.16.104.12/24
1718         $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1719         $IP route add 172.16.106.0/24 dev lo src 172.16.104.12
1720         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1721         $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1722         set +e
1723
1724         # removing address from device in vrf should only remove route from vrf table
1725         echo "    Regular FIB info"
1726
1727         $IP addr del dev dummy2 172.16.104.11/24
1728         $IP ro ls vrf red | grep -q 172.16.105.0/24
1729         log_test $? 1 "Route removed from VRF when source address deleted"
1730
1731         $IP ro ls | grep -q 172.16.105.0/24
1732         log_test $? 0 "Route in default VRF not removed"
1733
1734         $IP addr add dev dummy2 172.16.104.11/24
1735         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1736
1737         $IP addr del dev dummy1 172.16.104.11/24
1738         $IP ro ls | grep -q 172.16.105.0/24
1739         log_test $? 1 "Route removed in default VRF when source address deleted"
1740
1741         $IP ro ls vrf red | grep -q 172.16.105.0/24
1742         log_test $? 0 "Route in VRF is not removed by address delete"
1743
1744         # removing address from device in vrf should only remove route from vrf
1745         # table even when the associated fib info only differs in table ID
1746         echo "    Identical FIB info with different table ID"
1747
1748         $IP addr del dev dummy2 172.16.104.12/24
1749         $IP ro ls vrf red | grep -q 172.16.106.0/24
1750         log_test $? 1 "Route removed from VRF when source address deleted"
1751
1752         $IP ro ls | grep -q 172.16.106.0/24
1753         log_test $? 0 "Route in default VRF not removed"
1754
1755         $IP addr add dev dummy2 172.16.104.12/24
1756         $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1757
1758         $IP addr del dev dummy1 172.16.104.12/24
1759         $IP ro ls | grep -q 172.16.106.0/24
1760         log_test $? 1 "Route removed in default VRF when source address deleted"
1761
1762         $IP ro ls vrf red | grep -q 172.16.106.0/24
1763         log_test $? 0 "Route in VRF is not removed by address delete"
1764
1765         $IP li del dummy1
1766         $IP li del dummy2
1767         cleanup
1768 }
1769
1770
1771 ipv4_route_v6_gw_test()
1772 {
1773         local rc
1774
1775         echo
1776         echo "IPv4 route with IPv6 gateway tests"
1777
1778         route_setup
1779         sleep 2
1780
1781         #
1782         # single path route
1783         #
1784         run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1785         rc=$?
1786         log_test $rc 0 "Single path route with IPv6 gateway"
1787         if [ $rc -eq 0 ]; then
1788                 check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1789         fi
1790
1791         run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1792         log_test $rc 0 "Single path route with IPv6 gateway - ping"
1793
1794         run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1795         rc=$?
1796         log_test $rc 0 "Single path route delete"
1797         if [ $rc -eq 0 ]; then
1798                 check_route "172.16.112.0/24"
1799         fi
1800
1801         #
1802         # multipath - v6 then v4
1803         #
1804         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"
1805         rc=$?
1806         log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1807         if [ $rc -eq 0 ]; then
1808                 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"
1809         fi
1810
1811         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"
1812         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1813
1814         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"
1815         log_test $? 0 "    Multipath route delete exact match"
1816
1817         #
1818         # multipath - v4 then v6
1819         #
1820         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"
1821         rc=$?
1822         log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1823         if [ $rc -eq 0 ]; then
1824                 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"
1825         fi
1826
1827         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"
1828         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1829
1830         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"
1831         log_test $? 0 "    Multipath route delete exact match"
1832
1833         route_cleanup
1834 }
1835
1836 socat_check()
1837 {
1838         if [ ! -x "$(command -v socat)" ]; then
1839                 echo "socat command not found. Skipping test"
1840                 return 1
1841         fi
1842
1843         return 0
1844 }
1845
1846 iptables_check()
1847 {
1848         iptables -t mangle -L OUTPUT &> /dev/null
1849         if [ $? -ne 0 ]; then
1850                 echo "iptables configuration not supported. Skipping test"
1851                 return 1
1852         fi
1853
1854         return 0
1855 }
1856
1857 ip6tables_check()
1858 {
1859         ip6tables -t mangle -L OUTPUT &> /dev/null
1860         if [ $? -ne 0 ]; then
1861                 echo "ip6tables configuration not supported. Skipping test"
1862                 return 1
1863         fi
1864
1865         return 0
1866 }
1867
1868 ipv4_mangle_test()
1869 {
1870         local rc
1871
1872         echo
1873         echo "IPv4 mangling tests"
1874
1875         socat_check || return 1
1876         iptables_check || return 1
1877
1878         route_setup
1879         sleep 2
1880
1881         local tmp_file=$(mktemp)
1882         ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
1883
1884         # Add a FIB rule and a route that will direct our connection to the
1885         # listening server.
1886         $IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1887         $IP route add table 123 172.16.101.0/24 dev veth1
1888
1889         # Add an unreachable route to the main table that will block our
1890         # connection in case the FIB rule is not hit.
1891         $IP route add unreachable 172.16.101.2/32
1892
1893         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1894         log_test $? 0 "    Connection with correct parameters"
1895
1896         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
1897         log_test $? 1 "    Connection with incorrect parameters"
1898
1899         # Add a mangling rule and make sure connection is still successful.
1900         $NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
1901
1902         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1903         log_test $? 0 "    Connection with correct parameters - mangling"
1904
1905         # Delete the mangling rule and make sure connection is still
1906         # successful.
1907         $NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
1908
1909         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1910         log_test $? 0 "    Connection with correct parameters - no mangling"
1911
1912         # Verify connections were indeed successful on server side.
1913         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1914         log_test $? 0 "    Connection check - server side"
1915
1916         $IP route del unreachable 172.16.101.2/32
1917         $IP route del table 123 172.16.101.0/24 dev veth1
1918         $IP rule del pref 100
1919
1920         { kill %% && wait %%; } 2>/dev/null
1921         rm $tmp_file
1922
1923         route_cleanup
1924 }
1925
1926 ipv6_mangle_test()
1927 {
1928         local rc
1929
1930         echo
1931         echo "IPv6 mangling tests"
1932
1933         socat_check || return 1
1934         ip6tables_check || return 1
1935
1936         route_setup
1937         sleep 2
1938
1939         local tmp_file=$(mktemp)
1940         ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
1941
1942         # Add a FIB rule and a route that will direct our connection to the
1943         # listening server.
1944         $IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1945         $IP -6 route add table 123 2001:db8:101::/64 dev veth1
1946
1947         # Add an unreachable route to the main table that will block our
1948         # connection in case the FIB rule is not hit.
1949         $IP -6 route add unreachable 2001:db8:101::2/128
1950
1951         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1952         log_test $? 0 "    Connection with correct parameters"
1953
1954         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
1955         log_test $? 1 "    Connection with incorrect parameters"
1956
1957         # Add a mangling rule and make sure connection is still successful.
1958         $NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
1959
1960         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1961         log_test $? 0 "    Connection with correct parameters - mangling"
1962
1963         # Delete the mangling rule and make sure connection is still
1964         # successful.
1965         $NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
1966
1967         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1968         log_test $? 0 "    Connection with correct parameters - no mangling"
1969
1970         # Verify connections were indeed successful on server side.
1971         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1972         log_test $? 0 "    Connection check - server side"
1973
1974         $IP -6 route del unreachable 2001:db8:101::2/128
1975         $IP -6 route del table 123 2001:db8:101::/64 dev veth1
1976         $IP -6 rule del pref 100
1977
1978         { kill %% && wait %%; } 2>/dev/null
1979         rm $tmp_file
1980
1981         route_cleanup
1982 }
1983
1984 ip_neigh_get_check()
1985 {
1986         ip neigh help 2>&1 | grep -q 'ip neigh get'
1987         if [ $? -ne 0 ]; then
1988                 echo "iproute2 command does not support neigh get. Skipping test"
1989                 return 1
1990         fi
1991
1992         return 0
1993 }
1994
1995 ipv4_bcast_neigh_test()
1996 {
1997         local rc
1998
1999         echo
2000         echo "IPv4 broadcast neighbour tests"
2001
2002         ip_neigh_get_check || return 1
2003
2004         setup
2005
2006         set -e
2007         run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2008         run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2009
2010         run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2011         run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2012
2013         run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"
2014
2015         run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
2016         run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"
2017
2018         run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2019         run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2020
2021         run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
2022         set +e
2023
2024         run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2025         log_test $? 0 "Resolved neighbour for broadcast address"
2026
2027         run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2028         log_test $? 0 "Resolved neighbour for network broadcast address"
2029
2030         run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2031         log_test $? 2 "Unresolved neighbour for broadcast address"
2032
2033         run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2034         log_test $? 2 "Unresolved neighbour for network broadcast address"
2035
2036         cleanup
2037 }
2038
2039 ################################################################################
2040 # usage
2041
2042 usage()
2043 {
2044         cat <<EOF
2045 usage: ${0##*/} OPTS
2046
2047         -t <test>   Test(s) to run (default: all)
2048                     (options: $TESTS)
2049         -p          Pause on fail
2050         -P          Pause after each test before cleanup
2051         -v          verbose mode (show commands and output)
2052 EOF
2053 }
2054
2055 ################################################################################
2056 # main
2057
2058 while getopts :t:pPhv o
2059 do
2060         case $o in
2061                 t) TESTS=$OPTARG;;
2062                 p) PAUSE_ON_FAIL=yes;;
2063                 P) PAUSE=yes;;
2064                 v) VERBOSE=$(($VERBOSE + 1));;
2065                 h) usage; exit 0;;
2066                 *) usage; exit 1;;
2067         esac
2068 done
2069
2070 PEER_CMD="ip netns exec ${PEER_NS}"
2071
2072 # make sure we don't pause twice
2073 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2074
2075 if [ "$(id -u)" -ne 0 ];then
2076         echo "SKIP: Need root privileges"
2077         exit $ksft_skip;
2078 fi
2079
2080 if [ ! -x "$(command -v ip)" ]; then
2081         echo "SKIP: Could not run test without ip tool"
2082         exit $ksft_skip
2083 fi
2084
2085 ip route help 2>&1 | grep -q fibmatch
2086 if [ $? -ne 0 ]; then
2087         echo "SKIP: iproute2 too old, missing fibmatch"
2088         exit $ksft_skip
2089 fi
2090
2091 # start clean
2092 cleanup &> /dev/null
2093
2094 for t in $TESTS
2095 do
2096         case $t in
2097         fib_unreg_test|unregister)      fib_unreg_test;;
2098         fib_down_test|down)             fib_down_test;;
2099         fib_carrier_test|carrier)       fib_carrier_test;;
2100         fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
2101         fib_nexthop_test|nexthop)       fib_nexthop_test;;
2102         fib_suppress_test|suppress)     fib_suppress_test;;
2103         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
2104         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
2105         ipv6_addr_metric)               ipv6_addr_metric_test;;
2106         ipv4_addr_metric)               ipv4_addr_metric_test;;
2107         ipv4_del_addr)                  ipv4_del_addr_test;;
2108         ipv6_route_metrics)             ipv6_route_metrics_test;;
2109         ipv4_route_metrics)             ipv4_route_metrics_test;;
2110         ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
2111         ipv4_mangle)                    ipv4_mangle_test;;
2112         ipv6_mangle)                    ipv6_mangle_test;;
2113         ipv4_bcast_neigh)               ipv4_bcast_neigh_test;;
2114
2115         help) echo "Test names: $TESTS"; exit 0;;
2116         esac
2117 done
2118
2119 if [ "$TESTS" != "none" ]; then
2120         printf "\nTests passed: %3d\n" ${nsuccess}
2121         printf "Tests failed: %3d\n"   ${nfail}
2122 fi
2123
2124 exit $ret