ipv4: Reject routes specifying ECN bits in rtm_tos
[linux-2.6-microblaze.git] / tools / testing / selftests / net / fib_tests.sh
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3
4 # This test is for checking IPv4 and IPv6 FIB behavior in response to
5 # different events.
6
7 ret=0
8 # 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"
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_route_test()
992 {
993         route_setup
994
995         ipv6_rt_add
996         ipv6_rt_replace
997
998         route_cleanup
999 }
1000
1001 ip_addr_metric_check()
1002 {
1003         ip addr help 2>&1 | grep -q metric
1004         if [ $? -ne 0 ]; then
1005                 echo "iproute2 command does not support metric for addresses. Skipping test"
1006                 return 1
1007         fi
1008
1009         return 0
1010 }
1011
1012 ipv6_addr_metric_test()
1013 {
1014         local rc
1015
1016         echo
1017         echo "IPv6 prefix route tests"
1018
1019         ip_addr_metric_check || return 1
1020
1021         setup
1022
1023         set -e
1024         $IP li add dummy1 type dummy
1025         $IP li add dummy2 type dummy
1026         $IP li set dummy1 up
1027         $IP li set dummy2 up
1028
1029         # default entry is metric 256
1030         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1031         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1032         set +e
1033
1034         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1035         log_test $? 0 "Default metric"
1036
1037         set -e
1038         run_cmd "$IP -6 addr flush dev dummy1"
1039         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1040         set +e
1041
1042         check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1043         log_test $? 0 "User specified metric on first device"
1044
1045         set -e
1046         run_cmd "$IP -6 addr flush dev dummy2"
1047         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1048         set +e
1049
1050         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1051         log_test $? 0 "User specified metric on second device"
1052
1053         run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1054         rc=$?
1055         if [ $rc -eq 0 ]; then
1056                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1057                 rc=$?
1058         fi
1059         log_test $rc 0 "Delete of address on first device"
1060
1061         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1062         rc=$?
1063         if [ $rc -eq 0 ]; then
1064                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1065                 rc=$?
1066         fi
1067         log_test $rc 0 "Modify metric of address"
1068
1069         # verify prefix route removed on down
1070         run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1071         run_cmd "$IP li set dev dummy2 down"
1072         rc=$?
1073         if [ $rc -eq 0 ]; then
1074                 out=$($IP -6 ro ls match 2001:db8:104::/64)
1075                 check_expected "${out}" ""
1076                 rc=$?
1077         fi
1078         log_test $rc 0 "Prefix route removed on link down"
1079
1080         # verify prefix route re-inserted with assigned metric
1081         run_cmd "$IP li set dev dummy2 up"
1082         rc=$?
1083         if [ $rc -eq 0 ]; then
1084                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1085                 rc=$?
1086         fi
1087         log_test $rc 0 "Prefix route with metric on link up"
1088
1089         # verify peer metric added correctly
1090         set -e
1091         run_cmd "$IP -6 addr flush dev dummy2"
1092         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1093         set +e
1094
1095         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1096         log_test $? 0 "Set metric with peer route on local side"
1097         check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1098         log_test $? 0 "Set metric with peer route on peer side"
1099
1100         set -e
1101         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1102         set +e
1103
1104         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1105         log_test $? 0 "Modify metric and peer address on local side"
1106         check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1107         log_test $? 0 "Modify metric and peer address on peer side"
1108
1109         $IP li del dummy1
1110         $IP li del dummy2
1111         cleanup
1112 }
1113
1114 ipv6_route_metrics_test()
1115 {
1116         local rc
1117
1118         echo
1119         echo "IPv6 routes with metrics"
1120
1121         route_setup
1122
1123         #
1124         # single path with metrics
1125         #
1126         run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1127         rc=$?
1128         if [ $rc -eq 0 ]; then
1129                 check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1130                 rc=$?
1131         fi
1132         log_test $rc 0 "Single path route with mtu metric"
1133
1134
1135         #
1136         # multipath via separate routes with metrics
1137         #
1138         run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1139         run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1140         rc=$?
1141         if [ $rc -eq 0 ]; then
1142                 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"
1143                 rc=$?
1144         fi
1145         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1146
1147         # second route is coalesced to first to make a multipath route.
1148         # MTU of the second path is hidden from display!
1149         run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1150         run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1151         rc=$?
1152         if [ $rc -eq 0 ]; then
1153                 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"
1154                 rc=$?
1155         fi
1156         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1157
1158         run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1159         if [ $? -eq 0 ]; then
1160                 check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1161                 log_test $? 0 "    MTU of second leg"
1162         fi
1163
1164         #
1165         # multipath with metrics
1166         #
1167         run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1168         rc=$?
1169         if [ $rc -eq 0 ]; then
1170                 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"
1171                 rc=$?
1172         fi
1173         log_test $rc 0 "Multipath route with mtu metric"
1174
1175         $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1176         run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1177         log_test $? 0 "Using route with mtu metric"
1178
1179         run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1180         log_test $? 2 "Invalid metric (fails metric_convert)"
1181
1182         route_cleanup
1183 }
1184
1185 # add route for a prefix, flushing any existing routes first
1186 # expected to be the first step of a test
1187 add_route()
1188 {
1189         local pfx="$1"
1190         local nh="$2"
1191         local out
1192
1193         if [ "$VERBOSE" = "1" ]; then
1194                 echo
1195                 echo "    ##################################################"
1196                 echo
1197         fi
1198
1199         run_cmd "$IP ro flush ${pfx}"
1200         [ $? -ne 0 ] && exit 1
1201
1202         out=$($IP ro ls match ${pfx})
1203         if [ -n "$out" ]; then
1204                 echo "Failed to flush routes for prefix used for tests."
1205                 exit 1
1206         fi
1207
1208         run_cmd "$IP ro add ${pfx} ${nh}"
1209         if [ $? -ne 0 ]; then
1210                 echo "Failed to add initial route for test."
1211                 exit 1
1212         fi
1213 }
1214
1215 # add initial route - used in replace route tests
1216 add_initial_route()
1217 {
1218         add_route "172.16.104.0/24" "$1"
1219 }
1220
1221 check_route()
1222 {
1223         local pfx
1224         local expected="$1"
1225         local out
1226
1227         set -- $expected
1228         pfx=$1
1229         [ "${pfx}" = "unreachable" ] && pfx=$2
1230
1231         out=$($IP ro ls match ${pfx})
1232         check_expected "${out}" "${expected}"
1233 }
1234
1235 # assumption is that basic add of a single path route works
1236 # otherwise just adding an address on an interface is broken
1237 ipv4_rt_add()
1238 {
1239         local rc
1240
1241         echo
1242         echo "IPv4 route add / append tests"
1243
1244         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1245         add_route "172.16.104.0/24" "via 172.16.101.2"
1246         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1247         log_test $? 2 "Attempt to add duplicate route - gw"
1248
1249         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1250         add_route "172.16.104.0/24" "via 172.16.101.2"
1251         run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1252         log_test $? 2 "Attempt to add duplicate route - dev only"
1253
1254         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1255         add_route "172.16.104.0/24" "via 172.16.101.2"
1256         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1257         log_test $? 2 "Attempt to add duplicate route - reject route"
1258
1259         # iproute2 prepend only sets NLM_F_CREATE
1260         # - adds a new route; does NOT convert existing route to ECMP
1261         add_route "172.16.104.0/24" "via 172.16.101.2"
1262         run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1263         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"
1264         log_test $? 0 "Add new nexthop for existing prefix"
1265
1266         # route append with same prefix adds a new route
1267         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1268         add_route "172.16.104.0/24" "via 172.16.101.2"
1269         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1270         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"
1271         log_test $? 0 "Append nexthop to existing route - gw"
1272
1273         add_route "172.16.104.0/24" "via 172.16.101.2"
1274         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1275         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1276         log_test $? 0 "Append nexthop to existing route - dev only"
1277
1278         add_route "172.16.104.0/24" "via 172.16.101.2"
1279         run_cmd "$IP ro append unreachable 172.16.104.0/24"
1280         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1281         log_test $? 0 "Append nexthop to existing route - reject route"
1282
1283         run_cmd "$IP ro flush 172.16.104.0/24"
1284         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1285         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1286         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1287         log_test $? 0 "Append nexthop to existing reject route - gw"
1288
1289         run_cmd "$IP ro flush 172.16.104.0/24"
1290         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1291         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1292         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1293         log_test $? 0 "Append nexthop to existing reject route - dev only"
1294
1295         # insert mpath directly
1296         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1297         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"
1298         log_test $? 0 "add multipath route"
1299
1300         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1301         run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1302         log_test $? 2 "Attempt to add duplicate multipath route"
1303
1304         # insert of a second route without append but different metric
1305         add_route "172.16.104.0/24" "via 172.16.101.2"
1306         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1307         rc=$?
1308         if [ $rc -eq 0 ]; then
1309                 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1310                 rc=$?
1311         fi
1312         log_test $rc 0 "Route add with different metrics"
1313
1314         run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1315         rc=$?
1316         if [ $rc -eq 0 ]; then
1317                 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"
1318                 rc=$?
1319         fi
1320         log_test $rc 0 "Route delete with metric"
1321 }
1322
1323 ipv4_rt_replace_single()
1324 {
1325         # single path with single path
1326         #
1327         add_initial_route "via 172.16.101.2"
1328         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1329         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1330         log_test $? 0 "Single path with single path"
1331
1332         # single path with multipath
1333         #
1334         add_initial_route "nexthop via 172.16.101.2"
1335         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1336         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"
1337         log_test $? 0 "Single path with multipath"
1338
1339         # single path with reject
1340         #
1341         add_initial_route "nexthop via 172.16.101.2"
1342         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1343         check_route "unreachable 172.16.104.0/24"
1344         log_test $? 0 "Single path with reject route"
1345
1346         # single path with single path using MULTIPATH attribute
1347         #
1348         add_initial_route "via 172.16.101.2"
1349         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1350         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1351         log_test $? 0 "Single path with single path via multipath attribute"
1352
1353         # route replace fails - invalid nexthop
1354         add_initial_route "via 172.16.101.2"
1355         run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1356         if [ $? -eq 0 ]; then
1357                 # previous command is expected to fail so if it returns 0
1358                 # that means the test failed.
1359                 log_test 0 1 "Invalid nexthop"
1360         else
1361                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1362                 log_test $? 0 "Invalid nexthop"
1363         fi
1364
1365         # replace non-existent route
1366         # - note use of change versus replace since ip adds NLM_F_CREATE
1367         #   for replace
1368         add_initial_route "via 172.16.101.2"
1369         run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1370         log_test $? 2 "Single path - replace of non-existent route"
1371 }
1372
1373 ipv4_rt_replace_mpath()
1374 {
1375         # multipath with multipath
1376         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1377         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1378         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"
1379         log_test $? 0 "Multipath with multipath"
1380
1381         # multipath with single
1382         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1383         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1384         check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1385         log_test $? 0 "Multipath with single path"
1386
1387         # multipath with single
1388         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1389         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1390         check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1391         log_test $? 0 "Multipath with single path via multipath attribute"
1392
1393         # multipath with reject
1394         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1395         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1396         check_route "unreachable 172.16.104.0/24"
1397         log_test $? 0 "Multipath with reject route"
1398
1399         # route replace fails - invalid nexthop 1
1400         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1401         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1402         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"
1403         log_test $? 0 "Multipath - invalid first nexthop"
1404
1405         # route replace fails - invalid nexthop 2
1406         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1407         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1408         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"
1409         log_test $? 0 "Multipath - invalid second nexthop"
1410
1411         # multipath non-existent route
1412         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1413         run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1414         log_test $? 2 "Multipath - replace of non-existent route"
1415 }
1416
1417 ipv4_rt_replace()
1418 {
1419         echo
1420         echo "IPv4 route replace tests"
1421
1422         ipv4_rt_replace_single
1423         ipv4_rt_replace_mpath
1424 }
1425
1426 # checks that cached input route on VRF port is deleted
1427 # when VRF is deleted
1428 ipv4_local_rt_cache()
1429 {
1430         run_cmd "ip addr add 10.0.0.1/32 dev lo"
1431         run_cmd "ip netns add test-ns"
1432         run_cmd "ip link add veth-outside type veth peer name veth-inside"
1433         run_cmd "ip link add vrf-100 type vrf table 1100"
1434         run_cmd "ip link set veth-outside master vrf-100"
1435         run_cmd "ip link set veth-inside netns test-ns"
1436         run_cmd "ip link set veth-outside up"
1437         run_cmd "ip link set vrf-100 up"
1438         run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1439         run_cmd "ip netns exec test-ns ip link set veth-inside up"
1440         run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1441         run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
1442         run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
1443         run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
1444         run_cmd "ip link delete vrf-100"
1445
1446         # if we do not hang test is a success
1447         log_test $? 0 "Cached route removed from VRF port device"
1448 }
1449
1450 ipv4_rt_dsfield()
1451 {
1452         echo
1453         echo "IPv4 route with dsfield tests"
1454
1455         run_cmd "$IP route flush 172.16.102.0/24"
1456
1457         # New routes should reject dsfield options that interfere with ECN
1458         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
1459         log_test $? 2 "Reject route with dsfield 0x01"
1460
1461         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
1462         log_test $? 2 "Reject route with dsfield 0x02"
1463
1464         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
1465         log_test $? 2 "Reject route with dsfield 0x03"
1466
1467         # A generic route that doesn't take DSCP into account
1468         run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
1469
1470         # A more specific route for DSCP 0x10
1471         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
1472
1473         # DSCP 0x10 should match the specific route, no matter the ECN bits
1474         $IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
1475                 grep -q "via 172.16.103.2"
1476         log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
1477
1478         $IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
1479                 grep -q "via 172.16.103.2"
1480         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
1481
1482         $IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
1483                 grep -q "via 172.16.103.2"
1484         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
1485
1486         $IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
1487                 grep -q "via 172.16.103.2"
1488         log_test $? 0 "IPv4 route with DSCP and ECN:CE"
1489
1490         # Unknown DSCP should match the generic route, no matter the ECN bits
1491         $IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
1492                 grep -q "via 172.16.101.2"
1493         log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
1494
1495         $IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
1496                 grep -q "via 172.16.101.2"
1497         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
1498
1499         $IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
1500                 grep -q "via 172.16.101.2"
1501         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
1502
1503         $IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
1504                 grep -q "via 172.16.101.2"
1505         log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
1506
1507         # Null DSCP should match the generic route, no matter the ECN bits
1508         $IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
1509                 grep -q "via 172.16.101.2"
1510         log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
1511
1512         $IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
1513                 grep -q "via 172.16.101.2"
1514         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
1515
1516         $IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
1517                 grep -q "via 172.16.101.2"
1518         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
1519
1520         $IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
1521                 grep -q "via 172.16.101.2"
1522         log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
1523 }
1524
1525 ipv4_route_test()
1526 {
1527         route_setup
1528
1529         ipv4_rt_add
1530         ipv4_rt_replace
1531         ipv4_local_rt_cache
1532         ipv4_rt_dsfield
1533
1534         route_cleanup
1535 }
1536
1537 ipv4_addr_metric_test()
1538 {
1539         local rc
1540
1541         echo
1542         echo "IPv4 prefix route tests"
1543
1544         ip_addr_metric_check || return 1
1545
1546         setup
1547
1548         set -e
1549         $IP li add dummy1 type dummy
1550         $IP li add dummy2 type dummy
1551         $IP li set dummy1 up
1552         $IP li set dummy2 up
1553
1554         # default entry is metric 256
1555         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1556         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1557         set +e
1558
1559         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"
1560         log_test $? 0 "Default metric"
1561
1562         set -e
1563         run_cmd "$IP addr flush dev dummy1"
1564         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1565         set +e
1566
1567         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"
1568         log_test $? 0 "User specified metric on first device"
1569
1570         set -e
1571         run_cmd "$IP addr flush dev dummy2"
1572         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1573         set +e
1574
1575         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"
1576         log_test $? 0 "User specified metric on second device"
1577
1578         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1579         rc=$?
1580         if [ $rc -eq 0 ]; then
1581                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1582                 rc=$?
1583         fi
1584         log_test $rc 0 "Delete of address on first device"
1585
1586         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1587         rc=$?
1588         if [ $rc -eq 0 ]; then
1589                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1590                 rc=$?
1591         fi
1592         log_test $rc 0 "Modify metric of address"
1593
1594         # verify prefix route removed on down
1595         run_cmd "$IP li set dev dummy2 down"
1596         rc=$?
1597         if [ $rc -eq 0 ]; then
1598                 out=$($IP ro ls match 172.16.104.0/24)
1599                 check_expected "${out}" ""
1600                 rc=$?
1601         fi
1602         log_test $rc 0 "Prefix route removed on link down"
1603
1604         # verify prefix route re-inserted with assigned metric
1605         run_cmd "$IP li set dev dummy2 up"
1606         rc=$?
1607         if [ $rc -eq 0 ]; then
1608                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1609                 rc=$?
1610         fi
1611         log_test $rc 0 "Prefix route with metric on link up"
1612
1613         # explicitly check for metric changes on edge scenarios
1614         run_cmd "$IP addr flush dev dummy2"
1615         run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1616         run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1617         rc=$?
1618         if [ $rc -eq 0 ]; then
1619                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1620                 rc=$?
1621         fi
1622         log_test $rc 0 "Modify metric of .0/24 address"
1623
1624         run_cmd "$IP addr flush dev dummy2"
1625         run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1626         rc=$?
1627         if [ $rc -eq 0 ]; then
1628                 check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1629                 rc=$?
1630         fi
1631         log_test $rc 0 "Set metric of address with peer route"
1632
1633         run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1634         rc=$?
1635         if [ $rc -eq 0 ]; then
1636                 check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1637                 rc=$?
1638         fi
1639         log_test $rc 0 "Modify metric and peer address for peer route"
1640
1641         $IP li del dummy1
1642         $IP li del dummy2
1643         cleanup
1644 }
1645
1646 ipv4_route_metrics_test()
1647 {
1648         local rc
1649
1650         echo
1651         echo "IPv4 route add / append tests"
1652
1653         route_setup
1654
1655         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1656         rc=$?
1657         if [ $rc -eq 0 ]; then
1658                 check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1659                 rc=$?
1660         fi
1661         log_test $rc 0 "Single path route with mtu metric"
1662
1663
1664         run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1665         rc=$?
1666         if [ $rc -eq 0 ]; then
1667                 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"
1668                 rc=$?
1669         fi
1670         log_test $rc 0 "Multipath route with mtu metric"
1671
1672         $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1673         run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1674         log_test $? 0 "Using route with mtu metric"
1675
1676         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1677         log_test $? 2 "Invalid metric (fails metric_convert)"
1678
1679         route_cleanup
1680 }
1681
1682 ipv4_del_addr_test()
1683 {
1684         echo
1685         echo "IPv4 delete address route tests"
1686
1687         setup
1688
1689         set -e
1690         $IP li add dummy1 type dummy
1691         $IP li set dummy1 up
1692         $IP li add dummy2 type dummy
1693         $IP li set dummy2 up
1694         $IP li add red type vrf table 1111
1695         $IP li set red up
1696         $IP ro add vrf red unreachable default
1697         $IP li set dummy2 vrf red
1698
1699         $IP addr add dev dummy1 172.16.104.1/24
1700         $IP addr add dev dummy1 172.16.104.11/24
1701         $IP addr add dev dummy2 172.16.104.1/24
1702         $IP addr add dev dummy2 172.16.104.11/24
1703         $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1704         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1705         set +e
1706
1707         # removing address from device in vrf should only remove route from vrf table
1708         $IP addr del dev dummy2 172.16.104.11/24
1709         $IP ro ls vrf red | grep -q 172.16.105.0/24
1710         log_test $? 1 "Route removed from VRF when source address deleted"
1711
1712         $IP ro ls | grep -q 172.16.105.0/24
1713         log_test $? 0 "Route in default VRF not removed"
1714
1715         $IP addr add dev dummy2 172.16.104.11/24
1716         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1717
1718         $IP addr del dev dummy1 172.16.104.11/24
1719         $IP ro ls | grep -q 172.16.105.0/24
1720         log_test $? 1 "Route removed in default VRF when source address deleted"
1721
1722         $IP ro ls vrf red | grep -q 172.16.105.0/24
1723         log_test $? 0 "Route in VRF is not removed by address delete"
1724
1725         $IP li del dummy1
1726         $IP li del dummy2
1727         cleanup
1728 }
1729
1730
1731 ipv4_route_v6_gw_test()
1732 {
1733         local rc
1734
1735         echo
1736         echo "IPv4 route with IPv6 gateway tests"
1737
1738         route_setup
1739         sleep 2
1740
1741         #
1742         # single path route
1743         #
1744         run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1745         rc=$?
1746         log_test $rc 0 "Single path route with IPv6 gateway"
1747         if [ $rc -eq 0 ]; then
1748                 check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1749         fi
1750
1751         run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1752         log_test $rc 0 "Single path route with IPv6 gateway - ping"
1753
1754         run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1755         rc=$?
1756         log_test $rc 0 "Single path route delete"
1757         if [ $rc -eq 0 ]; then
1758                 check_route "172.16.112.0/24"
1759         fi
1760
1761         #
1762         # multipath - v6 then v4
1763         #
1764         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"
1765         rc=$?
1766         log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1767         if [ $rc -eq 0 ]; then
1768                 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"
1769         fi
1770
1771         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"
1772         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1773
1774         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"
1775         log_test $? 0 "    Multipath route delete exact match"
1776
1777         #
1778         # multipath - v4 then v6
1779         #
1780         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"
1781         rc=$?
1782         log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1783         if [ $rc -eq 0 ]; then
1784                 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"
1785         fi
1786
1787         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"
1788         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1789
1790         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"
1791         log_test $? 0 "    Multipath route delete exact match"
1792
1793         route_cleanup
1794 }
1795
1796 socat_check()
1797 {
1798         if [ ! -x "$(command -v socat)" ]; then
1799                 echo "socat command not found. Skipping test"
1800                 return 1
1801         fi
1802
1803         return 0
1804 }
1805
1806 iptables_check()
1807 {
1808         iptables -t mangle -L OUTPUT &> /dev/null
1809         if [ $? -ne 0 ]; then
1810                 echo "iptables configuration not supported. Skipping test"
1811                 return 1
1812         fi
1813
1814         return 0
1815 }
1816
1817 ip6tables_check()
1818 {
1819         ip6tables -t mangle -L OUTPUT &> /dev/null
1820         if [ $? -ne 0 ]; then
1821                 echo "ip6tables configuration not supported. Skipping test"
1822                 return 1
1823         fi
1824
1825         return 0
1826 }
1827
1828 ipv4_mangle_test()
1829 {
1830         local rc
1831
1832         echo
1833         echo "IPv4 mangling tests"
1834
1835         socat_check || return 1
1836         iptables_check || return 1
1837
1838         route_setup
1839         sleep 2
1840
1841         local tmp_file=$(mktemp)
1842         ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
1843
1844         # Add a FIB rule and a route that will direct our connection to the
1845         # listening server.
1846         $IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1847         $IP route add table 123 172.16.101.0/24 dev veth1
1848
1849         # Add an unreachable route to the main table that will block our
1850         # connection in case the FIB rule is not hit.
1851         $IP route add unreachable 172.16.101.2/32
1852
1853         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1854         log_test $? 0 "    Connection with correct parameters"
1855
1856         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
1857         log_test $? 1 "    Connection with incorrect parameters"
1858
1859         # Add a mangling rule and make sure connection is still successful.
1860         $NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
1861
1862         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1863         log_test $? 0 "    Connection with correct parameters - mangling"
1864
1865         # Delete the mangling rule and make sure connection is still
1866         # successful.
1867         $NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
1868
1869         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1870         log_test $? 0 "    Connection with correct parameters - no mangling"
1871
1872         # Verify connections were indeed successful on server side.
1873         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1874         log_test $? 0 "    Connection check - server side"
1875
1876         $IP route del unreachable 172.16.101.2/32
1877         $IP route del table 123 172.16.101.0/24 dev veth1
1878         $IP rule del pref 100
1879
1880         { kill %% && wait %%; } 2>/dev/null
1881         rm $tmp_file
1882
1883         route_cleanup
1884 }
1885
1886 ipv6_mangle_test()
1887 {
1888         local rc
1889
1890         echo
1891         echo "IPv6 mangling tests"
1892
1893         socat_check || return 1
1894         ip6tables_check || return 1
1895
1896         route_setup
1897         sleep 2
1898
1899         local tmp_file=$(mktemp)
1900         ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
1901
1902         # Add a FIB rule and a route that will direct our connection to the
1903         # listening server.
1904         $IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1905         $IP -6 route add table 123 2001:db8:101::/64 dev veth1
1906
1907         # Add an unreachable route to the main table that will block our
1908         # connection in case the FIB rule is not hit.
1909         $IP -6 route add unreachable 2001:db8:101::2/128
1910
1911         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1912         log_test $? 0 "    Connection with correct parameters"
1913
1914         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
1915         log_test $? 1 "    Connection with incorrect parameters"
1916
1917         # Add a mangling rule and make sure connection is still successful.
1918         $NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
1919
1920         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1921         log_test $? 0 "    Connection with correct parameters - mangling"
1922
1923         # Delete the mangling rule and make sure connection is still
1924         # successful.
1925         $NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
1926
1927         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1928         log_test $? 0 "    Connection with correct parameters - no mangling"
1929
1930         # Verify connections were indeed successful on server side.
1931         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1932         log_test $? 0 "    Connection check - server side"
1933
1934         $IP -6 route del unreachable 2001:db8:101::2/128
1935         $IP -6 route del table 123 2001:db8:101::/64 dev veth1
1936         $IP -6 rule del pref 100
1937
1938         { kill %% && wait %%; } 2>/dev/null
1939         rm $tmp_file
1940
1941         route_cleanup
1942 }
1943
1944 ################################################################################
1945 # usage
1946
1947 usage()
1948 {
1949         cat <<EOF
1950 usage: ${0##*/} OPTS
1951
1952         -t <test>   Test(s) to run (default: all)
1953                     (options: $TESTS)
1954         -p          Pause on fail
1955         -P          Pause after each test before cleanup
1956         -v          verbose mode (show commands and output)
1957 EOF
1958 }
1959
1960 ################################################################################
1961 # main
1962
1963 while getopts :t:pPhv o
1964 do
1965         case $o in
1966                 t) TESTS=$OPTARG;;
1967                 p) PAUSE_ON_FAIL=yes;;
1968                 P) PAUSE=yes;;
1969                 v) VERBOSE=$(($VERBOSE + 1));;
1970                 h) usage; exit 0;;
1971                 *) usage; exit 1;;
1972         esac
1973 done
1974
1975 PEER_CMD="ip netns exec ${PEER_NS}"
1976
1977 # make sure we don't pause twice
1978 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1979
1980 if [ "$(id -u)" -ne 0 ];then
1981         echo "SKIP: Need root privileges"
1982         exit $ksft_skip;
1983 fi
1984
1985 if [ ! -x "$(command -v ip)" ]; then
1986         echo "SKIP: Could not run test without ip tool"
1987         exit $ksft_skip
1988 fi
1989
1990 ip route help 2>&1 | grep -q fibmatch
1991 if [ $? -ne 0 ]; then
1992         echo "SKIP: iproute2 too old, missing fibmatch"
1993         exit $ksft_skip
1994 fi
1995
1996 # start clean
1997 cleanup &> /dev/null
1998
1999 for t in $TESTS
2000 do
2001         case $t in
2002         fib_unreg_test|unregister)      fib_unreg_test;;
2003         fib_down_test|down)             fib_down_test;;
2004         fib_carrier_test|carrier)       fib_carrier_test;;
2005         fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
2006         fib_nexthop_test|nexthop)       fib_nexthop_test;;
2007         fib_suppress_test|suppress)     fib_suppress_test;;
2008         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
2009         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
2010         ipv6_addr_metric)               ipv6_addr_metric_test;;
2011         ipv4_addr_metric)               ipv4_addr_metric_test;;
2012         ipv4_del_addr)                  ipv4_del_addr_test;;
2013         ipv6_route_metrics)             ipv6_route_metrics_test;;
2014         ipv4_route_metrics)             ipv4_route_metrics_test;;
2015         ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
2016         ipv4_mangle)                    ipv4_mangle_test;;
2017         ipv6_mangle)                    ipv6_mangle_test;;
2018
2019         help) echo "Test names: $TESTS"; exit 0;;
2020         esac
2021 done
2022
2023 if [ "$TESTS" != "none" ]; then
2024         printf "\nTests passed: %3d\n" ${nsuccess}
2025         printf "Tests failed: %3d\n"   ${nfail}
2026 fi
2027
2028 exit $ret