d238617b6ab5cde3dad43dc62815619ea4fbd884
[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"
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_route_test()
1451 {
1452         route_setup
1453
1454         ipv4_rt_add
1455         ipv4_rt_replace
1456         ipv4_local_rt_cache
1457
1458         route_cleanup
1459 }
1460
1461 ipv4_addr_metric_test()
1462 {
1463         local rc
1464
1465         echo
1466         echo "IPv4 prefix route tests"
1467
1468         ip_addr_metric_check || return 1
1469
1470         setup
1471
1472         set -e
1473         $IP li add dummy1 type dummy
1474         $IP li add dummy2 type dummy
1475         $IP li set dummy1 up
1476         $IP li set dummy2 up
1477
1478         # default entry is metric 256
1479         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1480         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1481         set +e
1482
1483         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"
1484         log_test $? 0 "Default metric"
1485
1486         set -e
1487         run_cmd "$IP addr flush dev dummy1"
1488         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1489         set +e
1490
1491         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"
1492         log_test $? 0 "User specified metric on first device"
1493
1494         set -e
1495         run_cmd "$IP addr flush dev dummy2"
1496         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1497         set +e
1498
1499         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"
1500         log_test $? 0 "User specified metric on second device"
1501
1502         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1503         rc=$?
1504         if [ $rc -eq 0 ]; then
1505                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1506                 rc=$?
1507         fi
1508         log_test $rc 0 "Delete of address on first device"
1509
1510         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1511         rc=$?
1512         if [ $rc -eq 0 ]; then
1513                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1514                 rc=$?
1515         fi
1516         log_test $rc 0 "Modify metric of address"
1517
1518         # verify prefix route removed on down
1519         run_cmd "$IP li set dev dummy2 down"
1520         rc=$?
1521         if [ $rc -eq 0 ]; then
1522                 out=$($IP ro ls match 172.16.104.0/24)
1523                 check_expected "${out}" ""
1524                 rc=$?
1525         fi
1526         log_test $rc 0 "Prefix route removed on link down"
1527
1528         # verify prefix route re-inserted with assigned metric
1529         run_cmd "$IP li set dev dummy2 up"
1530         rc=$?
1531         if [ $rc -eq 0 ]; then
1532                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1533                 rc=$?
1534         fi
1535         log_test $rc 0 "Prefix route with metric on link up"
1536
1537         # explicitly check for metric changes on edge scenarios
1538         run_cmd "$IP addr flush dev dummy2"
1539         run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1540         run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1541         rc=$?
1542         if [ $rc -eq 0 ]; then
1543                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1544                 rc=$?
1545         fi
1546         log_test $rc 0 "Modify metric of .0/24 address"
1547
1548         run_cmd "$IP addr flush dev dummy2"
1549         run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1550         rc=$?
1551         if [ $rc -eq 0 ]; then
1552                 check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1553                 rc=$?
1554         fi
1555         log_test $rc 0 "Set metric of address with peer route"
1556
1557         run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1558         rc=$?
1559         if [ $rc -eq 0 ]; then
1560                 check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1561                 rc=$?
1562         fi
1563         log_test $rc 0 "Modify metric and peer address for peer route"
1564
1565         $IP li del dummy1
1566         $IP li del dummy2
1567         cleanup
1568 }
1569
1570 ipv4_route_metrics_test()
1571 {
1572         local rc
1573
1574         echo
1575         echo "IPv4 route add / append tests"
1576
1577         route_setup
1578
1579         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1580         rc=$?
1581         if [ $rc -eq 0 ]; then
1582                 check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1583                 rc=$?
1584         fi
1585         log_test $rc 0 "Single path route with mtu metric"
1586
1587
1588         run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1589         rc=$?
1590         if [ $rc -eq 0 ]; then
1591                 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"
1592                 rc=$?
1593         fi
1594         log_test $rc 0 "Multipath route with mtu metric"
1595
1596         $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1597         run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1598         log_test $? 0 "Using route with mtu metric"
1599
1600         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1601         log_test $? 2 "Invalid metric (fails metric_convert)"
1602
1603         route_cleanup
1604 }
1605
1606 ipv4_del_addr_test()
1607 {
1608         echo
1609         echo "IPv4 delete address route tests"
1610
1611         setup
1612
1613         set -e
1614         $IP li add dummy1 type dummy
1615         $IP li set dummy1 up
1616         $IP li add dummy2 type dummy
1617         $IP li set dummy2 up
1618         $IP li add red type vrf table 1111
1619         $IP li set red up
1620         $IP ro add vrf red unreachable default
1621         $IP li set dummy2 vrf red
1622
1623         $IP addr add dev dummy1 172.16.104.1/24
1624         $IP addr add dev dummy1 172.16.104.11/24
1625         $IP addr add dev dummy1 172.16.104.12/24
1626         $IP addr add dev dummy2 172.16.104.1/24
1627         $IP addr add dev dummy2 172.16.104.11/24
1628         $IP addr add dev dummy2 172.16.104.12/24
1629         $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1630         $IP route add 172.16.106.0/24 dev lo src 172.16.104.12
1631         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1632         $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1633         set +e
1634
1635         # removing address from device in vrf should only remove route from vrf table
1636         echo "    Regular FIB info"
1637
1638         $IP addr del dev dummy2 172.16.104.11/24
1639         $IP ro ls vrf red | grep -q 172.16.105.0/24
1640         log_test $? 1 "Route removed from VRF when source address deleted"
1641
1642         $IP ro ls | grep -q 172.16.105.0/24
1643         log_test $? 0 "Route in default VRF not removed"
1644
1645         $IP addr add dev dummy2 172.16.104.11/24
1646         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1647
1648         $IP addr del dev dummy1 172.16.104.11/24
1649         $IP ro ls | grep -q 172.16.105.0/24
1650         log_test $? 1 "Route removed in default VRF when source address deleted"
1651
1652         $IP ro ls vrf red | grep -q 172.16.105.0/24
1653         log_test $? 0 "Route in VRF is not removed by address delete"
1654
1655         # removing address from device in vrf should only remove route from vrf
1656         # table even when the associated fib info only differs in table ID
1657         echo "    Identical FIB info with different table ID"
1658
1659         $IP addr del dev dummy2 172.16.104.12/24
1660         $IP ro ls vrf red | grep -q 172.16.106.0/24
1661         log_test $? 1 "Route removed from VRF when source address deleted"
1662
1663         $IP ro ls | grep -q 172.16.106.0/24
1664         log_test $? 0 "Route in default VRF not removed"
1665
1666         $IP addr add dev dummy2 172.16.104.12/24
1667         $IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1668
1669         $IP addr del dev dummy1 172.16.104.12/24
1670         $IP ro ls | grep -q 172.16.106.0/24
1671         log_test $? 1 "Route removed in default VRF when source address deleted"
1672
1673         $IP ro ls vrf red | grep -q 172.16.106.0/24
1674         log_test $? 0 "Route in VRF is not removed by address delete"
1675
1676         $IP li del dummy1
1677         $IP li del dummy2
1678         cleanup
1679 }
1680
1681
1682 ipv4_route_v6_gw_test()
1683 {
1684         local rc
1685
1686         echo
1687         echo "IPv4 route with IPv6 gateway tests"
1688
1689         route_setup
1690         sleep 2
1691
1692         #
1693         # single path route
1694         #
1695         run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1696         rc=$?
1697         log_test $rc 0 "Single path route with IPv6 gateway"
1698         if [ $rc -eq 0 ]; then
1699                 check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1700         fi
1701
1702         run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1703         log_test $rc 0 "Single path route with IPv6 gateway - ping"
1704
1705         run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1706         rc=$?
1707         log_test $rc 0 "Single path route delete"
1708         if [ $rc -eq 0 ]; then
1709                 check_route "172.16.112.0/24"
1710         fi
1711
1712         #
1713         # multipath - v6 then v4
1714         #
1715         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"
1716         rc=$?
1717         log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1718         if [ $rc -eq 0 ]; then
1719                 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"
1720         fi
1721
1722         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"
1723         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1724
1725         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"
1726         log_test $? 0 "    Multipath route delete exact match"
1727
1728         #
1729         # multipath - v4 then v6
1730         #
1731         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"
1732         rc=$?
1733         log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1734         if [ $rc -eq 0 ]; then
1735                 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"
1736         fi
1737
1738         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"
1739         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1740
1741         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"
1742         log_test $? 0 "    Multipath route delete exact match"
1743
1744         route_cleanup
1745 }
1746
1747 socat_check()
1748 {
1749         if [ ! -x "$(command -v socat)" ]; then
1750                 echo "socat command not found. Skipping test"
1751                 return 1
1752         fi
1753
1754         return 0
1755 }
1756
1757 iptables_check()
1758 {
1759         iptables -t mangle -L OUTPUT &> /dev/null
1760         if [ $? -ne 0 ]; then
1761                 echo "iptables configuration not supported. Skipping test"
1762                 return 1
1763         fi
1764
1765         return 0
1766 }
1767
1768 ip6tables_check()
1769 {
1770         ip6tables -t mangle -L OUTPUT &> /dev/null
1771         if [ $? -ne 0 ]; then
1772                 echo "ip6tables configuration not supported. Skipping test"
1773                 return 1
1774         fi
1775
1776         return 0
1777 }
1778
1779 ipv4_mangle_test()
1780 {
1781         local rc
1782
1783         echo
1784         echo "IPv4 mangling tests"
1785
1786         socat_check || return 1
1787         iptables_check || return 1
1788
1789         route_setup
1790         sleep 2
1791
1792         local tmp_file=$(mktemp)
1793         ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
1794
1795         # Add a FIB rule and a route that will direct our connection to the
1796         # listening server.
1797         $IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1798         $IP route add table 123 172.16.101.0/24 dev veth1
1799
1800         # Add an unreachable route to the main table that will block our
1801         # connection in case the FIB rule is not hit.
1802         $IP route add unreachable 172.16.101.2/32
1803
1804         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1805         log_test $? 0 "    Connection with correct parameters"
1806
1807         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
1808         log_test $? 1 "    Connection with incorrect parameters"
1809
1810         # Add a mangling rule and make sure connection is still successful.
1811         $NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
1812
1813         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1814         log_test $? 0 "    Connection with correct parameters - mangling"
1815
1816         # Delete the mangling rule and make sure connection is still
1817         # successful.
1818         $NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
1819
1820         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1821         log_test $? 0 "    Connection with correct parameters - no mangling"
1822
1823         # Verify connections were indeed successful on server side.
1824         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1825         log_test $? 0 "    Connection check - server side"
1826
1827         $IP route del unreachable 172.16.101.2/32
1828         $IP route del table 123 172.16.101.0/24 dev veth1
1829         $IP rule del pref 100
1830
1831         { kill %% && wait %%; } 2>/dev/null
1832         rm $tmp_file
1833
1834         route_cleanup
1835 }
1836
1837 ipv6_mangle_test()
1838 {
1839         local rc
1840
1841         echo
1842         echo "IPv6 mangling tests"
1843
1844         socat_check || return 1
1845         ip6tables_check || return 1
1846
1847         route_setup
1848         sleep 2
1849
1850         local tmp_file=$(mktemp)
1851         ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
1852
1853         # Add a FIB rule and a route that will direct our connection to the
1854         # listening server.
1855         $IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1856         $IP -6 route add table 123 2001:db8:101::/64 dev veth1
1857
1858         # Add an unreachable route to the main table that will block our
1859         # connection in case the FIB rule is not hit.
1860         $IP -6 route add unreachable 2001:db8:101::2/128
1861
1862         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1863         log_test $? 0 "    Connection with correct parameters"
1864
1865         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
1866         log_test $? 1 "    Connection with incorrect parameters"
1867
1868         # Add a mangling rule and make sure connection is still successful.
1869         $NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
1870
1871         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1872         log_test $? 0 "    Connection with correct parameters - mangling"
1873
1874         # Delete the mangling rule and make sure connection is still
1875         # successful.
1876         $NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
1877
1878         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1879         log_test $? 0 "    Connection with correct parameters - no mangling"
1880
1881         # Verify connections were indeed successful on server side.
1882         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1883         log_test $? 0 "    Connection check - server side"
1884
1885         $IP -6 route del unreachable 2001:db8:101::2/128
1886         $IP -6 route del table 123 2001:db8:101::/64 dev veth1
1887         $IP -6 rule del pref 100
1888
1889         { kill %% && wait %%; } 2>/dev/null
1890         rm $tmp_file
1891
1892         route_cleanup
1893 }
1894
1895 ################################################################################
1896 # usage
1897
1898 usage()
1899 {
1900         cat <<EOF
1901 usage: ${0##*/} OPTS
1902
1903         -t <test>   Test(s) to run (default: all)
1904                     (options: $TESTS)
1905         -p          Pause on fail
1906         -P          Pause after each test before cleanup
1907         -v          verbose mode (show commands and output)
1908 EOF
1909 }
1910
1911 ################################################################################
1912 # main
1913
1914 while getopts :t:pPhv o
1915 do
1916         case $o in
1917                 t) TESTS=$OPTARG;;
1918                 p) PAUSE_ON_FAIL=yes;;
1919                 P) PAUSE=yes;;
1920                 v) VERBOSE=$(($VERBOSE + 1));;
1921                 h) usage; exit 0;;
1922                 *) usage; exit 1;;
1923         esac
1924 done
1925
1926 PEER_CMD="ip netns exec ${PEER_NS}"
1927
1928 # make sure we don't pause twice
1929 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1930
1931 if [ "$(id -u)" -ne 0 ];then
1932         echo "SKIP: Need root privileges"
1933         exit $ksft_skip;
1934 fi
1935
1936 if [ ! -x "$(command -v ip)" ]; then
1937         echo "SKIP: Could not run test without ip tool"
1938         exit $ksft_skip
1939 fi
1940
1941 ip route help 2>&1 | grep -q fibmatch
1942 if [ $? -ne 0 ]; then
1943         echo "SKIP: iproute2 too old, missing fibmatch"
1944         exit $ksft_skip
1945 fi
1946
1947 # start clean
1948 cleanup &> /dev/null
1949
1950 for t in $TESTS
1951 do
1952         case $t in
1953         fib_unreg_test|unregister)      fib_unreg_test;;
1954         fib_down_test|down)             fib_down_test;;
1955         fib_carrier_test|carrier)       fib_carrier_test;;
1956         fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
1957         fib_nexthop_test|nexthop)       fib_nexthop_test;;
1958         fib_suppress_test|suppress)     fib_suppress_test;;
1959         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
1960         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
1961         ipv6_addr_metric)               ipv6_addr_metric_test;;
1962         ipv4_addr_metric)               ipv4_addr_metric_test;;
1963         ipv4_del_addr)                  ipv4_del_addr_test;;
1964         ipv6_route_metrics)             ipv6_route_metrics_test;;
1965         ipv4_route_metrics)             ipv4_route_metrics_test;;
1966         ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
1967         ipv4_mangle)                    ipv4_mangle_test;;
1968         ipv6_mangle)                    ipv6_mangle_test;;
1969
1970         help) echo "Test names: $TESTS"; exit 0;;
1971         esac
1972 done
1973
1974 if [ "$TESTS" != "none" ]; then
1975         printf "\nTests passed: %3d\n" ${nsuccess}
1976         printf "Tests failed: %3d\n"   ${nfail}
1977 fi
1978
1979 exit $ret