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