2 # SPDX-License-Identifier: GPL-2.0
4 # This test is for checking IPv4 and IPv6 FIB behavior in response to
9 # all tests in this script. Can be overridden with -t option
10 TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric"
22 if [ ${rc} -eq ${expected} ]; then
23 printf " TEST: %-60s [ OK ]\n" "${msg}"
24 nsuccess=$((nsuccess+1))
28 printf " TEST: %-60s [FAIL]\n" "${msg}"
29 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
31 echo "hit enter to continue, 'q' to quit"
33 [ "$a" = "q" ] && exit 1
37 if [ "${PAUSE}" = "yes" ]; then
39 echo "hit enter to continue, 'q' to quit"
41 [ "$a" = "q" ] && exit 1
49 $IP link set dev lo up
51 $IP link add dummy0 type dummy
52 $IP link set dev dummy0 up
53 $IP address add 198.51.100.1/24 dev dummy0
54 $IP -6 address add 2001:db8:1::1/64 dev dummy0
61 $IP link del dev dummy0 &> /dev/null
70 addr=$($IP -6 -br addr show dev ${dev} | \
72 for (i = 3; i <= NF; ++i) {
80 [ -z "$addr" ] && return 1
87 fib_unreg_unicast_test()
90 echo "Single path route test"
95 $IP route get fibmatch 198.51.100.2 &> /dev/null
96 log_test $? 0 "IPv4 fibmatch"
97 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
98 log_test $? 0 "IPv6 fibmatch"
101 $IP link del dev dummy0
104 echo " Nexthop device deleted"
105 $IP route get fibmatch 198.51.100.2 &> /dev/null
106 log_test $? 2 "IPv4 fibmatch - no route"
107 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
108 log_test $? 2 "IPv6 fibmatch - no route"
113 fib_unreg_multipath_test()
117 echo "Multipath route test"
122 $IP link add dummy1 type dummy
123 $IP link set dev dummy1 up
124 $IP address add 192.0.2.1/24 dev dummy1
125 $IP -6 address add 2001:db8:2::1/64 dev dummy1
127 $IP route add 203.0.113.0/24 \
128 nexthop via 198.51.100.2 dev dummy0 \
129 nexthop via 192.0.2.2 dev dummy1
130 $IP -6 route add 2001:db8:3::/64 \
131 nexthop via 2001:db8:1::2 dev dummy0 \
132 nexthop via 2001:db8:2::2 dev dummy1
136 $IP route get fibmatch 203.0.113.1 &> /dev/null
137 log_test $? 0 "IPv4 fibmatch"
138 $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
139 log_test $? 0 "IPv6 fibmatch"
142 $IP link del dev dummy0
145 echo " One nexthop device deleted"
146 $IP route get fibmatch 203.0.113.1 &> /dev/null
147 log_test $? 2 "IPv4 - multipath route removed on delete"
149 $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
150 # In IPv6 we do not flush the entire multipath route.
151 log_test $? 0 "IPv6 - multipath down to single path"
154 $IP link del dev dummy1
157 echo " Second nexthop device deleted"
158 $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
159 log_test $? 2 "IPv6 - no route"
166 fib_unreg_unicast_test
167 fib_unreg_multipath_test
170 fib_down_unicast_test()
173 echo "Single path, admin down"
178 $IP route get fibmatch 198.51.100.2 &> /dev/null
179 log_test $? 0 "IPv4 fibmatch"
180 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
181 log_test $? 0 "IPv6 fibmatch"
184 $IP link set dev dummy0 down
187 echo " Route deleted on down"
188 $IP route get fibmatch 198.51.100.2 &> /dev/null
189 log_test $? 2 "IPv4 fibmatch"
190 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
191 log_test $? 2 "IPv6 fibmatch"
196 fib_down_multipath_test_do()
201 $IP route get fibmatch 203.0.113.1 \
202 oif $down_dev &> /dev/null
203 log_test $? 2 "IPv4 fibmatch on down device"
204 $IP -6 route get fibmatch 2001:db8:3::1 \
205 oif $down_dev &> /dev/null
206 log_test $? 2 "IPv6 fibmatch on down device"
208 $IP route get fibmatch 203.0.113.1 \
209 oif $up_dev &> /dev/null
210 log_test $? 0 "IPv4 fibmatch on up device"
211 $IP -6 route get fibmatch 2001:db8:3::1 \
212 oif $up_dev &> /dev/null
213 log_test $? 0 "IPv6 fibmatch on up device"
215 $IP route get fibmatch 203.0.113.1 | \
216 grep $down_dev | grep -q "dead linkdown"
217 log_test $? 0 "IPv4 flags on down device"
218 $IP -6 route get fibmatch 2001:db8:3::1 | \
219 grep $down_dev | grep -q "dead linkdown"
220 log_test $? 0 "IPv6 flags on down device"
222 $IP route get fibmatch 203.0.113.1 | \
223 grep $up_dev | grep -q "dead linkdown"
224 log_test $? 1 "IPv4 flags on up device"
225 $IP -6 route get fibmatch 2001:db8:3::1 | \
226 grep $up_dev | grep -q "dead linkdown"
227 log_test $? 1 "IPv6 flags on up device"
230 fib_down_multipath_test()
233 echo "Admin down multipath"
238 $IP link add dummy1 type dummy
239 $IP link set dev dummy1 up
241 $IP address add 192.0.2.1/24 dev dummy1
242 $IP -6 address add 2001:db8:2::1/64 dev dummy1
244 $IP route add 203.0.113.0/24 \
245 nexthop via 198.51.100.2 dev dummy0 \
246 nexthop via 192.0.2.2 dev dummy1
247 $IP -6 route add 2001:db8:3::/64 \
248 nexthop via 2001:db8:1::2 dev dummy0 \
249 nexthop via 2001:db8:2::2 dev dummy1
252 echo " Verify start point"
253 $IP route get fibmatch 203.0.113.1 &> /dev/null
254 log_test $? 0 "IPv4 fibmatch"
256 $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
257 log_test $? 0 "IPv6 fibmatch"
260 $IP link set dev dummy0 down
263 echo " One device down, one up"
264 fib_down_multipath_test_do "dummy0" "dummy1"
267 $IP link set dev dummy0 up
268 $IP link set dev dummy1 down
271 echo " Other device down and up"
272 fib_down_multipath_test_do "dummy1" "dummy0"
275 $IP link set dev dummy0 down
278 echo " Both devices down"
279 $IP route get fibmatch 203.0.113.1 &> /dev/null
280 log_test $? 2 "IPv4 fibmatch"
281 $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
282 log_test $? 2 "IPv6 fibmatch"
284 $IP link del dev dummy1
290 fib_down_unicast_test
291 fib_down_multipath_test
294 # Local routes should not be affected when carrier changes.
295 fib_carrier_local_test()
298 echo "Local carrier tests - single path"
303 $IP link set dev dummy0 carrier on
307 $IP route get fibmatch 198.51.100.1 &> /dev/null
308 log_test $? 0 "IPv4 fibmatch"
309 $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
310 log_test $? 0 "IPv6 fibmatch"
312 $IP route get fibmatch 198.51.100.1 | \
314 log_test $? 1 "IPv4 - no linkdown flag"
315 $IP -6 route get fibmatch 2001:db8:1::1 | \
317 log_test $? 1 "IPv6 - no linkdown flag"
320 $IP link set dev dummy0 carrier off
324 echo " Carrier off on nexthop"
325 $IP route get fibmatch 198.51.100.1 &> /dev/null
326 log_test $? 0 "IPv4 fibmatch"
327 $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
328 log_test $? 0 "IPv6 fibmatch"
330 $IP route get fibmatch 198.51.100.1 | \
332 log_test $? 1 "IPv4 - linkdown flag set"
333 $IP -6 route get fibmatch 2001:db8:1::1 | \
335 log_test $? 1 "IPv6 - linkdown flag set"
338 $IP address add 192.0.2.1/24 dev dummy0
339 $IP -6 address add 2001:db8:2::1/64 dev dummy0
342 echo " Route to local address with carrier down"
343 $IP route get fibmatch 192.0.2.1 &> /dev/null
344 log_test $? 0 "IPv4 fibmatch"
345 $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
346 log_test $? 0 "IPv6 fibmatch"
348 $IP route get fibmatch 192.0.2.1 | \
350 log_test $? 1 "IPv4 linkdown flag set"
351 $IP -6 route get fibmatch 2001:db8:2::1 | \
353 log_test $? 1 "IPv6 linkdown flag set"
358 fib_carrier_unicast_test()
363 echo "Single path route carrier test"
368 $IP link set dev dummy0 carrier on
372 $IP route get fibmatch 198.51.100.2 &> /dev/null
373 log_test $? 0 "IPv4 fibmatch"
374 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
375 log_test $? 0 "IPv6 fibmatch"
377 $IP route get fibmatch 198.51.100.2 | \
379 log_test $? 1 "IPv4 no linkdown flag"
380 $IP -6 route get fibmatch 2001:db8:1::2 | \
382 log_test $? 1 "IPv6 no linkdown flag"
385 $IP link set dev dummy0 carrier off
389 $IP route get fibmatch 198.51.100.2 &> /dev/null
390 log_test $? 0 "IPv4 fibmatch"
391 $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
392 log_test $? 0 "IPv6 fibmatch"
394 $IP route get fibmatch 198.51.100.2 | \
396 log_test $? 0 "IPv4 linkdown flag set"
397 $IP -6 route get fibmatch 2001:db8:1::2 | \
399 log_test $? 0 "IPv6 linkdown flag set"
402 $IP address add 192.0.2.1/24 dev dummy0
403 $IP -6 address add 2001:db8:2::1/64 dev dummy0
406 echo " Second address added with carrier down"
407 $IP route get fibmatch 192.0.2.2 &> /dev/null
408 log_test $? 0 "IPv4 fibmatch"
409 $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
410 log_test $? 0 "IPv6 fibmatch"
412 $IP route get fibmatch 192.0.2.2 | \
414 log_test $? 0 "IPv4 linkdown flag set"
415 $IP -6 route get fibmatch 2001:db8:2::2 | \
417 log_test $? 0 "IPv6 linkdown flag set"
424 fib_carrier_local_test
425 fib_carrier_unicast_test
428 ################################################################################
429 # Tests on nexthop spec
431 # run 'ip route add' with given spec
442 [ "$vrf" = "-" ] && vrf="default"
443 [ -n "$gw" ] && gw="via $gw"
444 [ -n "$dev" ] && dev="dev $dev"
446 cmd="$IP route add vrf $vrf $pfx $gw $dev"
447 if [ "$VERBOSE" = "1" ]; then
448 printf "\n COMMAND: $cmd\n"
451 out=$(eval $cmd 2>&1)
453 if [ "$VERBOSE" = "1" -a -n "$out" ]; then
456 log_test $rc $erc "$desc"
462 echo "IPv4 nexthop tests"
464 echo "<<< write me >>>"
469 local lldummy=$(get_linklocal dummy0)
470 local llv1=$(get_linklocal dummy0)
472 if [ -z "$lldummy" ]; then
473 echo "Failed to get linklocal address for dummy0"
476 if [ -z "$llv1" ]; then
477 echo "Failed to get linklocal address for veth1"
482 echo "IPv6 nexthop tests"
484 add_rt "Directly connected nexthop, unicast address" 0 \
485 - 2001:db8:101::/64 2001:db8:1::2
486 add_rt "Directly connected nexthop, unicast address with device" 0 \
487 - 2001:db8:102::/64 2001:db8:1::2 "dummy0"
488 add_rt "Gateway is linklocal address" 0 \
489 - 2001:db8:103::1/64 $llv1 "veth0"
491 # fails because LL address requires a device
492 add_rt "Gateway is linklocal address, no device" 2 \
493 - 2001:db8:104::1/64 $llv1
495 # local address can not be a gateway
496 add_rt "Gateway can not be local unicast address" 2 \
497 - 2001:db8:105::/64 2001:db8:1::1
498 add_rt "Gateway can not be local unicast address, with device" 2 \
499 - 2001:db8:106::/64 2001:db8:1::1 "dummy0"
500 add_rt "Gateway can not be a local linklocal address" 2 \
501 - 2001:db8:107::1/64 $lldummy "dummy0"
504 add_rt "Gateway can be local address in a VRF" 0 \
505 - 2001:db8:108::/64 2001:db8:51::2
506 add_rt "Gateway can be local address in a VRF, with device" 0 \
507 - 2001:db8:109::/64 2001:db8:51::2 "veth0"
508 add_rt "Gateway can be local linklocal address in a VRF" 0 \
509 - 2001:db8:110::1/64 $llv1 "veth0"
511 add_rt "Redirect to VRF lookup" 0 \
512 - 2001:db8:111::/64 "" "red"
514 add_rt "VRF route, gateway can be local address in default VRF" 0 \
515 red 2001:db8:112::/64 2001:db8:51::1
517 # local address in same VRF fails
518 add_rt "VRF route, gateway can not be a local address" 2 \
519 red 2001:db8:113::1/64 2001:db8:2::1
520 add_rt "VRF route, gateway can not be a local addr with device" 2 \
521 red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
525 # dummy0 - 198.51.100.1/24 2001:db8:1::1/64
526 # veth0 - 192.0.2.1/24 2001:db8:51::1/64
529 # dummy1 - 192.168.2.1/24 2001:db8:2::1/64
530 # veth1 - 192.0.2.2/24 2001:db8:51::2/64
532 # [ dummy0 veth0 ]--[ veth1 dummy1 ]
540 $IP -4 rule add pref 32765 table local
541 $IP -4 rule del pref 0
542 $IP -6 rule add pref 32765 table local
543 $IP -6 rule del pref 0
545 $IP link add red type vrf table 1
547 $IP -4 route add vrf red unreachable default metric 4278198272
548 $IP -6 route add vrf red unreachable default metric 4278198272
550 $IP link add veth0 type veth peer name veth1
551 $IP link set dev veth0 up
552 $IP address add 192.0.2.1/24 dev veth0
553 $IP -6 address add 2001:db8:51::1/64 dev veth0
555 $IP link set dev veth1 vrf red up
556 $IP address add 192.0.2.2/24 dev veth1
557 $IP -6 address add 2001:db8:51::2/64 dev veth1
559 $IP link add dummy1 type dummy
560 $IP link set dev dummy1 vrf red up
561 $IP address add 192.168.2.1/24 dev dummy1
562 $IP -6 address add 2001:db8:2::1/64 dev dummy1
570 $IP link del dev dummy1
577 ################################################################################
578 # Tests on route add and replace
584 local stderr="2>/dev/null"
586 if [ "$VERBOSE" = "1" ]; then
587 printf " COMMAND: $cmd\n"
591 out=$(eval $cmd $stderr)
593 if [ "$VERBOSE" = "1" -a -n "$out" ]; then
597 [ "$VERBOSE" = "1" ] && echo
602 # add route for a prefix, flushing any existing routes first
603 # expected to be the first step of a test
610 if [ "$VERBOSE" = "1" ]; then
612 echo " ##################################################"
616 run_cmd "$IP -6 ro flush ${pfx}"
617 [ $? -ne 0 ] && exit 1
619 out=$($IP -6 ro ls match ${pfx})
620 if [ -n "$out" ]; then
621 echo "Failed to flush routes for prefix used for tests."
625 run_cmd "$IP -6 ro add ${pfx} ${nh}"
626 if [ $? -ne 0 ]; then
627 echo "Failed to add initial route for test."
632 # add initial route - used in replace route tests
635 add_route6 "2001:db8:104::/64" "$1"
640 local pfx="2001:db8:104::/64"
645 out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
646 [ "${out}" = "${expected}" ] && return 0
648 if [ -z "${out}" ]; then
649 if [ "$VERBOSE" = "1" ]; then
650 printf "\nNo route entry found\n"
652 printf " ${expected}\n"
657 # tricky way to convert output to 1-line without ip's
658 # messy '\'; this drops all extra white space
660 if [ "${out}" != "${expected}" ]; then
662 if [ "${VERBOSE}" = "1" ]; then
663 printf " Unexpected route entry. Have:\n"
665 printf " Expected:\n"
666 printf " ${expected}\n\n"
675 $IP li del red 2>/dev/null
676 $IP li del dummy1 2>/dev/null
677 $IP li del veth1 2>/dev/null
678 $IP li del veth3 2>/dev/null
688 [ "${VERBOSE}" = "1" ] && set -x
691 $IP li add red up type vrf table 101
692 $IP li add veth1 type veth peer name veth2
693 $IP li add veth3 type veth peer name veth4
697 $IP li set veth2 vrf red up
698 $IP li set veth4 vrf red up
699 $IP li add dummy1 type dummy
700 $IP li set dummy1 vrf red up
702 $IP -6 addr add 2001:db8:101::1/64 dev veth1
703 $IP -6 addr add 2001:db8:101::2/64 dev veth2
704 $IP -6 addr add 2001:db8:103::1/64 dev veth3
705 $IP -6 addr add 2001:db8:103::2/64 dev veth4
706 $IP -6 addr add 2001:db8:104::1/64 dev dummy1
708 $IP addr add 172.16.101.1/24 dev veth1
709 $IP addr add 172.16.101.2/24 dev veth2
710 $IP addr add 172.16.103.1/24 dev veth3
711 $IP addr add 172.16.103.2/24 dev veth4
712 $IP addr add 172.16.104.1/24 dev dummy1
717 # assumption is that basic add of a single path route works
718 # otherwise just adding an address on an interface is broken
724 echo "IPv6 route add / append tests"
726 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
727 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
728 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
729 log_test $? 2 "Attempt to add duplicate route - gw"
731 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
732 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
733 run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
734 log_test $? 2 "Attempt to add duplicate route - dev only"
736 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
737 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
738 run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
739 log_test $? 2 "Attempt to add duplicate route - reject route"
741 # iproute2 prepend only sets NLM_F_CREATE
742 # - adds a new route; does NOT convert existing route to ECMP
743 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
744 run_cmd "$IP -6 ro prepend 2001:db8:104::/64 via 2001:db8:103::2"
745 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024 2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
746 log_test $? 0 "Add new route for existing prefix (w/o NLM_F_EXCL)"
748 # route append with same prefix adds a new route
749 # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
750 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
751 run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
752 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"
753 log_test $? 0 "Append nexthop to existing route - gw"
755 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
756 run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
757 check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop dev veth3 weight 1"
758 log_test $? 0 "Append nexthop to existing route - dev only"
760 # multipath route can not have a nexthop that is a reject route
761 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
762 run_cmd "$IP -6 ro append unreachable 2001:db8:104::/64"
763 log_test $? 2 "Append nexthop to existing route - reject route"
765 # reject route can not be converted to multipath route
766 run_cmd "$IP -6 ro flush 2001:db8:104::/64"
767 run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
768 run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
769 log_test $? 2 "Append nexthop to existing reject route - gw"
771 run_cmd "$IP -6 ro flush 2001:db8:104::/64"
772 run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
773 run_cmd "$IP -6 ro append 2001:db8:104::/64 dev veth3"
774 log_test $? 2 "Append nexthop to existing reject route - dev only"
776 # insert mpath directly
777 add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
778 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"
779 log_test $? 0 "Add multipath route"
781 add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
782 run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
783 log_test $? 2 "Attempt to add duplicate multipath route"
785 # insert of a second route without append but different metric
786 add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
787 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
789 if [ $rc -eq 0 ]; then
790 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
793 log_test $rc 0 "Route add with different metrics"
795 run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
797 if [ $rc -eq 0 ]; then
798 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"
801 log_test $rc 0 "Route delete with metric"
804 ipv6_rt_replace_single()
806 # single path with single path
808 add_initial_route6 "via 2001:db8:101::2"
809 run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
810 check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
811 log_test $? 0 "Single path with single path"
813 # single path with multipath
815 add_initial_route6 "nexthop via 2001:db8:101::2"
816 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
817 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"
818 log_test $? 0 "Single path with multipath"
820 # single path with reject
822 add_initial_route6 "nexthop via 2001:db8:101::2"
823 run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
824 check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
825 log_test $? 0 "Single path with reject route"
827 # single path with single path using MULTIPATH attribute
829 add_initial_route6 "via 2001:db8:101::2"
830 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
831 check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
832 log_test $? 0 "Single path with single path via multipath attribute"
834 # route replace fails - invalid nexthop
835 add_initial_route6 "via 2001:db8:101::2"
836 run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
837 if [ $? -eq 0 ]; then
838 # previous command is expected to fail so if it returns 0
839 # that means the test failed.
840 log_test 0 1 "Invalid nexthop"
842 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
843 log_test $? 0 "Invalid nexthop"
846 # replace non-existent route
847 # - note use of change versus replace since ip adds NLM_F_CREATE
849 add_initial_route6 "via 2001:db8:101::2"
850 run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
851 log_test $? 2 "Single path - replace of non-existent route"
854 ipv6_rt_replace_mpath()
856 # multipath with multipath
857 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
858 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
859 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"
860 log_test $? 0 "Multipath with multipath"
862 # multipath with single
863 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
864 run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
865 check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
866 log_test $? 0 "Multipath with single path"
868 # multipath with single
869 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
870 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
871 check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
872 log_test $? 0 "Multipath with single path via multipath attribute"
874 # multipath with reject
875 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
876 run_cmd "$IP -6 ro replace unreachable 2001:db8:104::/64"
877 check_route6 "unreachable 2001:db8:104::/64 dev lo metric 1024"
878 log_test $? 0 "Multipath with reject route"
880 # route replace fails - invalid nexthop 1
881 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
882 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
883 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"
884 log_test $? 0 "Multipath - invalid first nexthop"
886 # route replace fails - invalid nexthop 2
887 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
888 run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
889 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"
890 log_test $? 0 "Multipath - invalid second nexthop"
892 # multipath non-existent route
893 add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
894 run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
895 log_test $? 2 "Multipath - replace of non-existent route"
901 echo "IPv6 route replace tests"
903 ipv6_rt_replace_single
904 ipv6_rt_replace_mpath
917 ip_addr_metric_check()
919 ip addr help 2>&1 | grep -q metric
920 if [ $? -ne 0 ]; then
921 echo "iproute2 command does not support metric for addresses. Skipping test"
928 ipv6_addr_metric_test()
933 echo "IPv6 prefix route tests"
935 ip_addr_metric_check || return 1
940 $IP li add dummy1 type dummy
941 $IP li add dummy2 type dummy
945 # default entry is metric 256
946 run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
947 run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
950 check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
951 log_test $? 0 "Default metric"
954 run_cmd "$IP -6 addr flush dev dummy1"
955 run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
958 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
959 log_test $? 0 "User specified metric on first device"
962 run_cmd "$IP -6 addr flush dev dummy2"
963 run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
966 check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
967 log_test $? 0 "User specified metric on second device"
969 run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
971 if [ $rc -eq 0 ]; then
972 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
975 log_test $rc 0 "Delete of address on first device"
977 run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
979 if [ $rc -eq 0 ]; then
980 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
983 log_test $rc 0 "Modify metric of address"
985 # verify prefix route removed on down
986 run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
987 run_cmd "$IP li set dev dummy2 down"
989 if [ $rc -eq 0 ]; then
993 log_test $rc 0 "Prefix route removed on link down"
995 # verify prefix route re-inserted with assigned metric
996 run_cmd "$IP li set dev dummy2 up"
998 if [ $rc -eq 0 ]; then
999 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1002 log_test $rc 0 "Prefix route with metric on link up"
1009 # add route for a prefix, flushing any existing routes first
1010 # expected to be the first step of a test
1017 if [ "$VERBOSE" = "1" ]; then
1019 echo " ##################################################"
1023 run_cmd "$IP ro flush ${pfx}"
1024 [ $? -ne 0 ] && exit 1
1026 out=$($IP ro ls match ${pfx})
1027 if [ -n "$out" ]; then
1028 echo "Failed to flush routes for prefix used for tests."
1032 run_cmd "$IP ro add ${pfx} ${nh}"
1033 if [ $? -ne 0 ]; then
1034 echo "Failed to add initial route for test."
1039 # add initial route - used in replace route tests
1042 add_route "172.16.104.0/24" "$1"
1047 local pfx="172.16.104.0/24"
1052 out=$($IP ro ls match ${pfx})
1053 [ "${out}" = "${expected}" ] && return 0
1055 if [ -z "${out}" ]; then
1056 if [ "$VERBOSE" = "1" ]; then
1057 printf "\nNo route entry found\n"
1058 printf "Expected:\n"
1059 printf " ${expected}\n"
1064 # tricky way to convert output to 1-line without ip's
1065 # messy '\'; this drops all extra white space
1067 if [ "${out}" != "${expected}" ]; then
1069 if [ "${VERBOSE}" = "1" ]; then
1070 printf " Unexpected route entry. Have:\n"
1072 printf " Expected:\n"
1073 printf " ${expected}\n\n"
1080 # assumption is that basic add of a single path route works
1081 # otherwise just adding an address on an interface is broken
1087 echo "IPv4 route add / append tests"
1089 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1090 add_route "172.16.104.0/24" "via 172.16.101.2"
1091 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1092 log_test $? 2 "Attempt to add duplicate route - gw"
1094 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1095 add_route "172.16.104.0/24" "via 172.16.101.2"
1096 run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1097 log_test $? 2 "Attempt to add duplicate route - dev only"
1099 # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1100 add_route "172.16.104.0/24" "via 172.16.101.2"
1101 run_cmd "$IP ro add unreachable 172.16.104.0/24"
1102 log_test $? 2 "Attempt to add duplicate route - reject route"
1104 # iproute2 prepend only sets NLM_F_CREATE
1105 # - adds a new route; does NOT convert existing route to ECMP
1106 add_route "172.16.104.0/24" "via 172.16.101.2"
1107 run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1108 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"
1109 log_test $? 0 "Add new nexthop for existing prefix"
1111 # route append with same prefix adds a new route
1112 # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1113 add_route "172.16.104.0/24" "via 172.16.101.2"
1114 run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1115 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"
1116 log_test $? 0 "Append nexthop to existing route - gw"
1118 add_route "172.16.104.0/24" "via 172.16.101.2"
1119 run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1120 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1121 log_test $? 0 "Append nexthop to existing route - dev only"
1123 add_route "172.16.104.0/24" "via 172.16.101.2"
1124 run_cmd "$IP ro append unreachable 172.16.104.0/24"
1125 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1126 log_test $? 0 "Append nexthop to existing route - reject route"
1128 run_cmd "$IP ro flush 172.16.104.0/24"
1129 run_cmd "$IP ro add unreachable 172.16.104.0/24"
1130 run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1131 check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1132 log_test $? 0 "Append nexthop to existing reject route - gw"
1134 run_cmd "$IP ro flush 172.16.104.0/24"
1135 run_cmd "$IP ro add unreachable 172.16.104.0/24"
1136 run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1137 check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1138 log_test $? 0 "Append nexthop to existing reject route - dev only"
1140 # insert mpath directly
1141 add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1142 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"
1143 log_test $? 0 "add multipath route"
1145 add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1146 run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1147 log_test $? 2 "Attempt to add duplicate multipath route"
1149 # insert of a second route without append but different metric
1150 add_route "172.16.104.0/24" "via 172.16.101.2"
1151 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1153 if [ $rc -eq 0 ]; then
1154 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1157 log_test $rc 0 "Route add with different metrics"
1159 run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1161 if [ $rc -eq 0 ]; then
1162 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"
1165 log_test $rc 0 "Route delete with metric"
1168 ipv4_rt_replace_single()
1170 # single path with single path
1172 add_initial_route "via 172.16.101.2"
1173 run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1174 check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1175 log_test $? 0 "Single path with single path"
1177 # single path with multipath
1179 add_initial_route "nexthop via 172.16.101.2"
1180 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1181 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"
1182 log_test $? 0 "Single path with multipath"
1184 # single path with reject
1186 add_initial_route "nexthop via 172.16.101.2"
1187 run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1188 check_route "unreachable 172.16.104.0/24"
1189 log_test $? 0 "Single path with reject route"
1191 # single path with single path using MULTIPATH attribute
1193 add_initial_route "via 172.16.101.2"
1194 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1195 check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1196 log_test $? 0 "Single path with single path via multipath attribute"
1198 # route replace fails - invalid nexthop
1199 add_initial_route "via 172.16.101.2"
1200 run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1201 if [ $? -eq 0 ]; then
1202 # previous command is expected to fail so if it returns 0
1203 # that means the test failed.
1204 log_test 0 1 "Invalid nexthop"
1206 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1207 log_test $? 0 "Invalid nexthop"
1210 # replace non-existent route
1211 # - note use of change versus replace since ip adds NLM_F_CREATE
1213 add_initial_route "via 172.16.101.2"
1214 run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1215 log_test $? 2 "Single path - replace of non-existent route"
1218 ipv4_rt_replace_mpath()
1220 # multipath with multipath
1221 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1222 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1223 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"
1224 log_test $? 0 "Multipath with multipath"
1226 # multipath with single
1227 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1228 run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1229 check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1230 log_test $? 0 "Multipath with single path"
1232 # multipath with single
1233 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1234 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1235 check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1236 log_test $? 0 "Multipath with single path via multipath attribute"
1238 # multipath with reject
1239 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1240 run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1241 check_route "unreachable 172.16.104.0/24"
1242 log_test $? 0 "Multipath with reject route"
1244 # route replace fails - invalid nexthop 1
1245 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1246 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1247 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"
1248 log_test $? 0 "Multipath - invalid first nexthop"
1250 # route replace fails - invalid nexthop 2
1251 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1252 run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1253 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"
1254 log_test $? 0 "Multipath - invalid second nexthop"
1256 # multipath non-existent route
1257 add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1258 run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1259 log_test $? 2 "Multipath - replace of non-existent route"
1265 echo "IPv4 route replace tests"
1267 ipv4_rt_replace_single
1268 ipv4_rt_replace_mpath
1281 ipv4_addr_metric_test()
1286 echo "IPv4 prefix route tests"
1288 ip_addr_metric_check || return 1
1293 $IP li add dummy1 type dummy
1294 $IP li add dummy2 type dummy
1295 $IP li set dummy1 up
1296 $IP li set dummy2 up
1298 # default entry is metric 256
1299 run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1300 run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1303 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"
1304 log_test $? 0 "Default metric"
1307 run_cmd "$IP addr flush dev dummy1"
1308 run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1311 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"
1312 log_test $? 0 "User specified metric on first device"
1315 run_cmd "$IP addr flush dev dummy2"
1316 run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1319 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"
1320 log_test $? 0 "User specified metric on second device"
1322 run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1324 if [ $rc -eq 0 ]; then
1325 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1328 log_test $rc 0 "Delete of address on first device"
1330 run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1332 if [ $rc -eq 0 ]; then
1333 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1336 log_test $rc 0 "Modify metric of address"
1338 # verify prefix route removed on down
1339 run_cmd "$IP li set dev dummy2 down"
1341 if [ $rc -eq 0 ]; then
1345 log_test $rc 0 "Prefix route removed on link down"
1347 # verify prefix route re-inserted with assigned metric
1348 run_cmd "$IP li set dev dummy2 up"
1350 if [ $rc -eq 0 ]; then
1351 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1354 log_test $rc 0 "Prefix route with metric on link up"
1361 ################################################################################
1367 usage: ${0##*/} OPTS
1369 -t <test> Test(s) to run (default: all)
1372 -P Pause after each test before cleanup
1373 -v verbose mode (show commands and output)
1377 ################################################################################
1380 while getopts :t:pPhv o
1384 p) PAUSE_ON_FAIL=yes;;
1386 v) VERBOSE=$(($VERBOSE + 1));;
1392 PEER_CMD="ip netns exec ${PEER_NS}"
1394 # make sure we don't pause twice
1395 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1397 if [ "$(id -u)" -ne 0 ];then
1398 echo "SKIP: Need root privileges"
1402 if [ ! -x "$(command -v ip)" ]; then
1403 echo "SKIP: Could not run test without ip tool"
1407 ip route help 2>&1 | grep -q fibmatch
1408 if [ $? -ne 0 ]; then
1409 echo "SKIP: iproute2 too old, missing fibmatch"
1414 cleanup &> /dev/null
1419 fib_unreg_test|unregister) fib_unreg_test;;
1420 fib_down_test|down) fib_down_test;;
1421 fib_carrier_test|carrier) fib_carrier_test;;
1422 fib_nexthop_test|nexthop) fib_nexthop_test;;
1423 ipv6_route_test|ipv6_rt) ipv6_route_test;;
1424 ipv4_route_test|ipv4_rt) ipv4_route_test;;
1425 ipv6_addr_metric) ipv6_addr_metric_test;;
1426 ipv4_addr_metric) ipv4_addr_metric_test;;
1428 help) echo "Test names: $TESTS"; exit 0;;
1432 if [ "$TESTS" != "none" ]; then
1433 printf "\nTests passed: %3d\n" ${nsuccess}
1434 printf "Tests failed: %3d\n" ${nfail}