Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 
0004 # This test is for checking IPv4 and IPv6 FIB behavior in response to
0005 # different events.
0006 
0007 ret=0
0008 # Kselftest framework requirement - SKIP code is 4.
0009 ksft_skip=4
0010 
0011 # all tests in this script. Can be overridden with -t option
0012 TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh"
0013 
0014 VERBOSE=0
0015 PAUSE_ON_FAIL=no
0016 PAUSE=no
0017 IP="ip -netns ns1"
0018 NS_EXEC="ip netns exec ns1"
0019 
0020 which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
0021 
0022 log_test()
0023 {
0024         local rc=$1
0025         local expected=$2
0026         local msg="$3"
0027 
0028         if [ ${rc} -eq ${expected} ]; then
0029                 printf "    TEST: %-60s  [ OK ]\n" "${msg}"
0030                 nsuccess=$((nsuccess+1))
0031         else
0032                 ret=1
0033                 nfail=$((nfail+1))
0034                 printf "    TEST: %-60s  [FAIL]\n" "${msg}"
0035                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
0036                 echo
0037                         echo "hit enter to continue, 'q' to quit"
0038                         read a
0039                         [ "$a" = "q" ] && exit 1
0040                 fi
0041         fi
0042 
0043         if [ "${PAUSE}" = "yes" ]; then
0044                 echo
0045                 echo "hit enter to continue, 'q' to quit"
0046                 read a
0047                 [ "$a" = "q" ] && exit 1
0048         fi
0049 }
0050 
0051 setup()
0052 {
0053         set -e
0054         ip netns add ns1
0055         ip netns set ns1 auto
0056         $IP link set dev lo up
0057         ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
0058         ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
0059 
0060         $IP link add dummy0 type dummy
0061         $IP link set dev dummy0 up
0062         $IP address add 198.51.100.1/24 dev dummy0
0063         $IP -6 address add 2001:db8:1::1/64 dev dummy0
0064         set +e
0065 
0066 }
0067 
0068 cleanup()
0069 {
0070         $IP link del dev dummy0 &> /dev/null
0071         ip netns del ns1
0072         ip netns del ns2 &> /dev/null
0073 }
0074 
0075 get_linklocal()
0076 {
0077         local dev=$1
0078         local addr
0079 
0080         addr=$($IP -6 -br addr show dev ${dev} | \
0081         awk '{
0082                 for (i = 3; i <= NF; ++i) {
0083                         if ($i ~ /^fe80/)
0084                                 print $i
0085                 }
0086         }'
0087         )
0088         addr=${addr/\/*}
0089 
0090         [ -z "$addr" ] && return 1
0091 
0092         echo $addr
0093 
0094         return 0
0095 }
0096 
0097 fib_unreg_unicast_test()
0098 {
0099         echo
0100         echo "Single path route test"
0101 
0102         setup
0103 
0104         echo "    Start point"
0105         $IP route get fibmatch 198.51.100.2 &> /dev/null
0106         log_test $? 0 "IPv4 fibmatch"
0107         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0108         log_test $? 0 "IPv6 fibmatch"
0109 
0110         set -e
0111         $IP link del dev dummy0
0112         set +e
0113 
0114         echo "    Nexthop device deleted"
0115         $IP route get fibmatch 198.51.100.2 &> /dev/null
0116         log_test $? 2 "IPv4 fibmatch - no route"
0117         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0118         log_test $? 2 "IPv6 fibmatch - no route"
0119 
0120         cleanup
0121 }
0122 
0123 fib_unreg_multipath_test()
0124 {
0125 
0126         echo
0127         echo "Multipath route test"
0128 
0129         setup
0130 
0131         set -e
0132         $IP link add dummy1 type dummy
0133         $IP link set dev dummy1 up
0134         $IP address add 192.0.2.1/24 dev dummy1
0135         $IP -6 address add 2001:db8:2::1/64 dev dummy1
0136 
0137         $IP route add 203.0.113.0/24 \
0138                 nexthop via 198.51.100.2 dev dummy0 \
0139                 nexthop via 192.0.2.2 dev dummy1
0140         $IP -6 route add 2001:db8:3::/64 \
0141                 nexthop via 2001:db8:1::2 dev dummy0 \
0142                 nexthop via 2001:db8:2::2 dev dummy1
0143         set +e
0144 
0145         echo "    Start point"
0146         $IP route get fibmatch 203.0.113.1 &> /dev/null
0147         log_test $? 0 "IPv4 fibmatch"
0148         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
0149         log_test $? 0 "IPv6 fibmatch"
0150 
0151         set -e
0152         $IP link del dev dummy0
0153         set +e
0154 
0155         echo "    One nexthop device deleted"
0156         $IP route get fibmatch 203.0.113.1 &> /dev/null
0157         log_test $? 2 "IPv4 - multipath route removed on delete"
0158 
0159         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
0160         # In IPv6 we do not flush the entire multipath route.
0161         log_test $? 0 "IPv6 - multipath down to single path"
0162 
0163         set -e
0164         $IP link del dev dummy1
0165         set +e
0166 
0167         echo "    Second nexthop device deleted"
0168         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
0169         log_test $? 2 "IPv6 - no route"
0170 
0171         cleanup
0172 }
0173 
0174 fib_unreg_test()
0175 {
0176         fib_unreg_unicast_test
0177         fib_unreg_multipath_test
0178 }
0179 
0180 fib_down_unicast_test()
0181 {
0182         echo
0183         echo "Single path, admin down"
0184 
0185         setup
0186 
0187         echo "    Start point"
0188         $IP route get fibmatch 198.51.100.2 &> /dev/null
0189         log_test $? 0 "IPv4 fibmatch"
0190         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0191         log_test $? 0 "IPv6 fibmatch"
0192 
0193         set -e
0194         $IP link set dev dummy0 down
0195         set +e
0196 
0197         echo "    Route deleted on down"
0198         $IP route get fibmatch 198.51.100.2 &> /dev/null
0199         log_test $? 2 "IPv4 fibmatch"
0200         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0201         log_test $? 2 "IPv6 fibmatch"
0202 
0203         cleanup
0204 }
0205 
0206 fib_down_multipath_test_do()
0207 {
0208         local down_dev=$1
0209         local up_dev=$2
0210 
0211         $IP route get fibmatch 203.0.113.1 \
0212                 oif $down_dev &> /dev/null
0213         log_test $? 2 "IPv4 fibmatch on down device"
0214         $IP -6 route get fibmatch 2001:db8:3::1 \
0215                 oif $down_dev &> /dev/null
0216         log_test $? 2 "IPv6 fibmatch on down device"
0217 
0218         $IP route get fibmatch 203.0.113.1 \
0219                 oif $up_dev &> /dev/null
0220         log_test $? 0 "IPv4 fibmatch on up device"
0221         $IP -6 route get fibmatch 2001:db8:3::1 \
0222                 oif $up_dev &> /dev/null
0223         log_test $? 0 "IPv6 fibmatch on up device"
0224 
0225         $IP route get fibmatch 203.0.113.1 | \
0226                 grep $down_dev | grep -q "dead linkdown"
0227         log_test $? 0 "IPv4 flags on down device"
0228         $IP -6 route get fibmatch 2001:db8:3::1 | \
0229                 grep $down_dev | grep -q "dead linkdown"
0230         log_test $? 0 "IPv6 flags on down device"
0231 
0232         $IP route get fibmatch 203.0.113.1 | \
0233                 grep $up_dev | grep -q "dead linkdown"
0234         log_test $? 1 "IPv4 flags on up device"
0235         $IP -6 route get fibmatch 2001:db8:3::1 | \
0236                 grep $up_dev | grep -q "dead linkdown"
0237         log_test $? 1 "IPv6 flags on up device"
0238 }
0239 
0240 fib_down_multipath_test()
0241 {
0242         echo
0243         echo "Admin down multipath"
0244 
0245         setup
0246 
0247         set -e
0248         $IP link add dummy1 type dummy
0249         $IP link set dev dummy1 up
0250 
0251         $IP address add 192.0.2.1/24 dev dummy1
0252         $IP -6 address add 2001:db8:2::1/64 dev dummy1
0253 
0254         $IP route add 203.0.113.0/24 \
0255                 nexthop via 198.51.100.2 dev dummy0 \
0256                 nexthop via 192.0.2.2 dev dummy1
0257         $IP -6 route add 2001:db8:3::/64 \
0258                 nexthop via 2001:db8:1::2 dev dummy0 \
0259                 nexthop via 2001:db8:2::2 dev dummy1
0260         set +e
0261 
0262         echo "    Verify start point"
0263         $IP route get fibmatch 203.0.113.1 &> /dev/null
0264         log_test $? 0 "IPv4 fibmatch"
0265 
0266         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
0267         log_test $? 0 "IPv6 fibmatch"
0268 
0269         set -e
0270         $IP link set dev dummy0 down
0271         set +e
0272 
0273         echo "    One device down, one up"
0274         fib_down_multipath_test_do "dummy0" "dummy1"
0275 
0276         set -e
0277         $IP link set dev dummy0 up
0278         $IP link set dev dummy1 down
0279         set +e
0280 
0281         echo "    Other device down and up"
0282         fib_down_multipath_test_do "dummy1" "dummy0"
0283 
0284         set -e
0285         $IP link set dev dummy0 down
0286         set +e
0287 
0288         echo "    Both devices down"
0289         $IP route get fibmatch 203.0.113.1 &> /dev/null
0290         log_test $? 2 "IPv4 fibmatch"
0291         $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
0292         log_test $? 2 "IPv6 fibmatch"
0293 
0294         $IP link del dev dummy1
0295         cleanup
0296 }
0297 
0298 fib_down_test()
0299 {
0300         fib_down_unicast_test
0301         fib_down_multipath_test
0302 }
0303 
0304 # Local routes should not be affected when carrier changes.
0305 fib_carrier_local_test()
0306 {
0307         echo
0308         echo "Local carrier tests - single path"
0309 
0310         setup
0311 
0312         set -e
0313         $IP link set dev dummy0 carrier on
0314         set +e
0315 
0316         echo "    Start point"
0317         $IP route get fibmatch 198.51.100.1 &> /dev/null
0318         log_test $? 0 "IPv4 fibmatch"
0319         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
0320         log_test $? 0 "IPv6 fibmatch"
0321 
0322         $IP route get fibmatch 198.51.100.1 | \
0323                 grep -q "linkdown"
0324         log_test $? 1 "IPv4 - no linkdown flag"
0325         $IP -6 route get fibmatch 2001:db8:1::1 | \
0326                 grep -q "linkdown"
0327         log_test $? 1 "IPv6 - no linkdown flag"
0328 
0329         set -e
0330         $IP link set dev dummy0 carrier off
0331         sleep 1
0332         set +e
0333 
0334         echo "    Carrier off on nexthop"
0335         $IP route get fibmatch 198.51.100.1 &> /dev/null
0336         log_test $? 0 "IPv4 fibmatch"
0337         $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
0338         log_test $? 0 "IPv6 fibmatch"
0339 
0340         $IP route get fibmatch 198.51.100.1 | \
0341                 grep -q "linkdown"
0342         log_test $? 1 "IPv4 - linkdown flag set"
0343         $IP -6 route get fibmatch 2001:db8:1::1 | \
0344                 grep -q "linkdown"
0345         log_test $? 1 "IPv6 - linkdown flag set"
0346 
0347         set -e
0348         $IP address add 192.0.2.1/24 dev dummy0
0349         $IP -6 address add 2001:db8:2::1/64 dev dummy0
0350         set +e
0351 
0352         echo "    Route to local address with carrier down"
0353         $IP route get fibmatch 192.0.2.1 &> /dev/null
0354         log_test $? 0 "IPv4 fibmatch"
0355         $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
0356         log_test $? 0 "IPv6 fibmatch"
0357 
0358         $IP route get fibmatch 192.0.2.1 | \
0359                 grep -q "linkdown"
0360         log_test $? 1 "IPv4 linkdown flag set"
0361         $IP -6 route get fibmatch 2001:db8:2::1 | \
0362                 grep -q "linkdown"
0363         log_test $? 1 "IPv6 linkdown flag set"
0364 
0365         cleanup
0366 }
0367 
0368 fib_carrier_unicast_test()
0369 {
0370         ret=0
0371 
0372         echo
0373         echo "Single path route carrier test"
0374 
0375         setup
0376 
0377         set -e
0378         $IP link set dev dummy0 carrier on
0379         set +e
0380 
0381         echo "    Start point"
0382         $IP route get fibmatch 198.51.100.2 &> /dev/null
0383         log_test $? 0 "IPv4 fibmatch"
0384         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0385         log_test $? 0 "IPv6 fibmatch"
0386 
0387         $IP route get fibmatch 198.51.100.2 | \
0388                 grep -q "linkdown"
0389         log_test $? 1 "IPv4 no linkdown flag"
0390         $IP -6 route get fibmatch 2001:db8:1::2 | \
0391                 grep -q "linkdown"
0392         log_test $? 1 "IPv6 no linkdown flag"
0393 
0394         set -e
0395         $IP link set dev dummy0 carrier off
0396         sleep 1
0397         set +e
0398 
0399         echo "    Carrier down"
0400         $IP route get fibmatch 198.51.100.2 &> /dev/null
0401         log_test $? 0 "IPv4 fibmatch"
0402         $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
0403         log_test $? 0 "IPv6 fibmatch"
0404 
0405         $IP route get fibmatch 198.51.100.2 | \
0406                 grep -q "linkdown"
0407         log_test $? 0 "IPv4 linkdown flag set"
0408         $IP -6 route get fibmatch 2001:db8:1::2 | \
0409                 grep -q "linkdown"
0410         log_test $? 0 "IPv6 linkdown flag set"
0411 
0412         set -e
0413         $IP address add 192.0.2.1/24 dev dummy0
0414         $IP -6 address add 2001:db8:2::1/64 dev dummy0
0415         set +e
0416 
0417         echo "    Second address added with carrier down"
0418         $IP route get fibmatch 192.0.2.2 &> /dev/null
0419         log_test $? 0 "IPv4 fibmatch"
0420         $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
0421         log_test $? 0 "IPv6 fibmatch"
0422 
0423         $IP route get fibmatch 192.0.2.2 | \
0424                 grep -q "linkdown"
0425         log_test $? 0 "IPv4 linkdown flag set"
0426         $IP -6 route get fibmatch 2001:db8:2::2 | \
0427                 grep -q "linkdown"
0428         log_test $? 0 "IPv6 linkdown flag set"
0429 
0430         cleanup
0431 }
0432 
0433 fib_carrier_test()
0434 {
0435         fib_carrier_local_test
0436         fib_carrier_unicast_test
0437 }
0438 
0439 fib_rp_filter_test()
0440 {
0441         echo
0442         echo "IPv4 rp_filter tests"
0443 
0444         setup
0445 
0446         set -e
0447         ip netns add ns2
0448         ip netns set ns2 auto
0449 
0450         ip -netns ns2 link set dev lo up
0451 
0452         $IP link add name veth1 type veth peer name veth2
0453         $IP link set dev veth2 netns ns2
0454         $IP address add 192.0.2.1/24 dev veth1
0455         ip -netns ns2 address add 192.0.2.1/24 dev veth2
0456         $IP link set dev veth1 up
0457         ip -netns ns2 link set dev veth2 up
0458 
0459         $IP link set dev lo address 52:54:00:6a:c7:5e
0460         $IP link set dev veth1 address 52:54:00:6a:c7:5e
0461         ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
0462         ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
0463 
0464         # 1. (ns2) redirect lo's egress to veth2's egress
0465         ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
0466         ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
0467                 action mirred egress redirect dev veth2
0468         ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
0469                 action mirred egress redirect dev veth2
0470 
0471         # 2. (ns1) redirect veth1's ingress to lo's ingress
0472         $NS_EXEC tc qdisc add dev veth1 ingress
0473         $NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
0474                 action mirred ingress redirect dev lo
0475         $NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
0476                 action mirred ingress redirect dev lo
0477 
0478         # 3. (ns1) redirect lo's egress to veth1's egress
0479         $NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
0480         $NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
0481                 action mirred egress redirect dev veth1
0482         $NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
0483                 action mirred egress redirect dev veth1
0484 
0485         # 4. (ns2) redirect veth2's ingress to lo's ingress
0486         ip netns exec ns2 tc qdisc add dev veth2 ingress
0487         ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
0488                 action mirred ingress redirect dev lo
0489         ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
0490                 action mirred ingress redirect dev lo
0491 
0492         $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
0493         $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
0494         $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
0495         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
0496         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
0497         ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
0498         set +e
0499 
0500         run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
0501         log_test $? 0 "rp_filter passes local packets"
0502 
0503         run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
0504         log_test $? 0 "rp_filter passes loopback packets"
0505 
0506         cleanup
0507 }
0508 
0509 ################################################################################
0510 # Tests on nexthop spec
0511 
0512 # run 'ip route add' with given spec
0513 add_rt()
0514 {
0515         local desc="$1"
0516         local erc=$2
0517         local vrf=$3
0518         local pfx=$4
0519         local gw=$5
0520         local dev=$6
0521         local cmd out rc
0522 
0523         [ "$vrf" = "-" ] && vrf="default"
0524         [ -n "$gw" ] && gw="via $gw"
0525         [ -n "$dev" ] && dev="dev $dev"
0526 
0527         cmd="$IP route add vrf $vrf $pfx $gw $dev"
0528         if [ "$VERBOSE" = "1" ]; then
0529                 printf "\n    COMMAND: $cmd\n"
0530         fi
0531 
0532         out=$(eval $cmd 2>&1)
0533         rc=$?
0534         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
0535                 echo "    $out"
0536         fi
0537         log_test $rc $erc "$desc"
0538 }
0539 
0540 fib4_nexthop()
0541 {
0542         echo
0543         echo "IPv4 nexthop tests"
0544 
0545         echo "<<< write me >>>"
0546 }
0547 
0548 fib6_nexthop()
0549 {
0550         local lldummy=$(get_linklocal dummy0)
0551         local llv1=$(get_linklocal dummy0)
0552 
0553         if [ -z "$lldummy" ]; then
0554                 echo "Failed to get linklocal address for dummy0"
0555                 return 1
0556         fi
0557         if [ -z "$llv1" ]; then
0558                 echo "Failed to get linklocal address for veth1"
0559                 return 1
0560         fi
0561 
0562         echo
0563         echo "IPv6 nexthop tests"
0564 
0565         add_rt "Directly connected nexthop, unicast address" 0 \
0566                 - 2001:db8:101::/64 2001:db8:1::2
0567         add_rt "Directly connected nexthop, unicast address with device" 0 \
0568                 - 2001:db8:102::/64 2001:db8:1::2 "dummy0"
0569         add_rt "Gateway is linklocal address" 0 \
0570                 - 2001:db8:103::1/64 $llv1 "veth0"
0571 
0572         # fails because LL address requires a device
0573         add_rt "Gateway is linklocal address, no device" 2 \
0574                 - 2001:db8:104::1/64 $llv1
0575 
0576         # local address can not be a gateway
0577         add_rt "Gateway can not be local unicast address" 2 \
0578                 - 2001:db8:105::/64 2001:db8:1::1
0579         add_rt "Gateway can not be local unicast address, with device" 2 \
0580                 - 2001:db8:106::/64 2001:db8:1::1 "dummy0"
0581         add_rt "Gateway can not be a local linklocal address" 2 \
0582                 - 2001:db8:107::1/64 $lldummy "dummy0"
0583 
0584         # VRF tests
0585         add_rt "Gateway can be local address in a VRF" 0 \
0586                 - 2001:db8:108::/64 2001:db8:51::2
0587         add_rt "Gateway can be local address in a VRF, with device" 0 \
0588                 - 2001:db8:109::/64 2001:db8:51::2 "veth0"
0589         add_rt "Gateway can be local linklocal address in a VRF" 0 \
0590                 - 2001:db8:110::1/64 $llv1 "veth0"
0591 
0592         add_rt "Redirect to VRF lookup" 0 \
0593                 - 2001:db8:111::/64 "" "red"
0594 
0595         add_rt "VRF route, gateway can be local address in default VRF" 0 \
0596                 red 2001:db8:112::/64 2001:db8:51::1
0597 
0598         # local address in same VRF fails
0599         add_rt "VRF route, gateway can not be a local address" 2 \
0600                 red 2001:db8:113::1/64 2001:db8:2::1
0601         add_rt "VRF route, gateway can not be a local addr with device" 2 \
0602                 red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
0603 }
0604 
0605 # Default VRF:
0606 #   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
0607 #   veth0  - 192.0.2.1/24    2001:db8:51::1/64
0608 #
0609 # VRF red:
0610 #   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
0611 #   veth1  - 192.0.2.2/24   2001:db8:51::2/64
0612 #
0613 #  [ dummy0   veth0 ]--[ veth1   dummy1 ]
0614 
0615 fib_nexthop_test()
0616 {
0617         setup
0618 
0619         set -e
0620 
0621         $IP -4 rule add pref 32765 table local
0622         $IP -4 rule del pref 0
0623         $IP -6 rule add pref 32765 table local
0624         $IP -6 rule del pref 0
0625 
0626         $IP link add red type vrf table 1
0627         $IP link set red up
0628         $IP -4 route add vrf red unreachable default metric 4278198272
0629         $IP -6 route add vrf red unreachable default metric 4278198272
0630 
0631         $IP link add veth0 type veth peer name veth1
0632         $IP link set dev veth0 up
0633         $IP address add 192.0.2.1/24 dev veth0
0634         $IP -6 address add 2001:db8:51::1/64 dev veth0
0635 
0636         $IP link set dev veth1 vrf red up
0637         $IP address add 192.0.2.2/24 dev veth1
0638         $IP -6 address add 2001:db8:51::2/64 dev veth1
0639 
0640         $IP link add dummy1 type dummy
0641         $IP link set dev dummy1 vrf red up
0642         $IP address add 192.168.2.1/24 dev dummy1
0643         $IP -6 address add 2001:db8:2::1/64 dev dummy1
0644         set +e
0645 
0646         sleep 1
0647         fib4_nexthop
0648         fib6_nexthop
0649 
0650         (
0651         $IP link del dev dummy1
0652         $IP link del veth0
0653         $IP link del red
0654         ) 2>/dev/null
0655         cleanup
0656 }
0657 
0658 fib_suppress_test()
0659 {
0660         echo
0661         echo "FIB rule with suppress_prefixlength"
0662         setup
0663 
0664         $IP link add dummy1 type dummy
0665         $IP link set dummy1 up
0666         $IP -6 route add default dev dummy1
0667         $IP -6 rule add table main suppress_prefixlength 0
0668         ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
0669         $IP -6 rule del table main suppress_prefixlength 0
0670         $IP link del dummy1
0671 
0672         # If we got here without crashing, we're good.
0673         log_test 0 0 "FIB rule suppress test"
0674 
0675         cleanup
0676 }
0677 
0678 ################################################################################
0679 # Tests on route add and replace
0680 
0681 run_cmd()
0682 {
0683         local cmd="$1"
0684         local out
0685         local stderr="2>/dev/null"
0686 
0687         if [ "$VERBOSE" = "1" ]; then
0688                 printf "    COMMAND: $cmd\n"
0689                 stderr=
0690         fi
0691 
0692         out=$(eval $cmd $stderr)
0693         rc=$?
0694         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
0695                 echo "    $out"
0696         fi
0697 
0698         [ "$VERBOSE" = "1" ] && echo
0699 
0700         return $rc
0701 }
0702 
0703 check_expected()
0704 {
0705         local out="$1"
0706         local expected="$2"
0707         local rc=0
0708 
0709         [ "${out}" = "${expected}" ] && return 0
0710 
0711         if [ -z "${out}" ]; then
0712                 if [ "$VERBOSE" = "1" ]; then
0713                         printf "\nNo route entry found\n"
0714                         printf "Expected:\n"
0715                         printf "    ${expected}\n"
0716                 fi
0717                 return 1
0718         fi
0719 
0720         # tricky way to convert output to 1-line without ip's
0721         # messy '\'; this drops all extra white space
0722         out=$(echo ${out})
0723         if [ "${out}" != "${expected}" ]; then
0724                 rc=1
0725                 if [ "${VERBOSE}" = "1" ]; then
0726                         printf "    Unexpected route entry. Have:\n"
0727                         printf "        ${out}\n"
0728                         printf "    Expected:\n"
0729                         printf "        ${expected}\n\n"
0730                 fi
0731         fi
0732 
0733         return $rc
0734 }
0735 
0736 # add route for a prefix, flushing any existing routes first
0737 # expected to be the first step of a test
0738 add_route6()
0739 {
0740         local pfx="$1"
0741         local nh="$2"
0742         local out
0743 
0744         if [ "$VERBOSE" = "1" ]; then
0745                 echo
0746                 echo "    ##################################################"
0747                 echo
0748         fi
0749 
0750         run_cmd "$IP -6 ro flush ${pfx}"
0751         [ $? -ne 0 ] && exit 1
0752 
0753         out=$($IP -6 ro ls match ${pfx})
0754         if [ -n "$out" ]; then
0755                 echo "Failed to flush routes for prefix used for tests."
0756                 exit 1
0757         fi
0758 
0759         run_cmd "$IP -6 ro add ${pfx} ${nh}"
0760         if [ $? -ne 0 ]; then
0761                 echo "Failed to add initial route for test."
0762                 exit 1
0763         fi
0764 }
0765 
0766 # add initial route - used in replace route tests
0767 add_initial_route6()
0768 {
0769         add_route6 "2001:db8:104::/64" "$1"
0770 }
0771 
0772 check_route6()
0773 {
0774         local pfx
0775         local expected="$1"
0776         local out
0777         local rc=0
0778 
0779         set -- $expected
0780         pfx=$1
0781 
0782         out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
0783         check_expected "${out}" "${expected}"
0784 }
0785 
0786 route_cleanup()
0787 {
0788         $IP li del red 2>/dev/null
0789         $IP li del dummy1 2>/dev/null
0790         $IP li del veth1 2>/dev/null
0791         $IP li del veth3 2>/dev/null
0792 
0793         cleanup &> /dev/null
0794 }
0795 
0796 route_setup()
0797 {
0798         route_cleanup
0799         setup
0800 
0801         [ "${VERBOSE}" = "1" ] && set -x
0802         set -e
0803 
0804         ip netns add ns2
0805         ip netns set ns2 auto
0806         ip -netns ns2 link set dev lo up
0807         ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
0808         ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
0809 
0810         $IP li add veth1 type veth peer name veth2
0811         $IP li add veth3 type veth peer name veth4
0812 
0813         $IP li set veth1 up
0814         $IP li set veth3 up
0815         $IP li set veth2 netns ns2 up
0816         $IP li set veth4 netns ns2 up
0817         ip -netns ns2 li add dummy1 type dummy
0818         ip -netns ns2 li set dummy1 up
0819 
0820         $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
0821         $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
0822         $IP addr add 172.16.101.1/24 dev veth1
0823         $IP addr add 172.16.103.1/24 dev veth3
0824 
0825         ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
0826         ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
0827         ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
0828 
0829         ip -netns ns2 addr add 172.16.101.2/24 dev veth2
0830         ip -netns ns2 addr add 172.16.103.2/24 dev veth4
0831         ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
0832 
0833         set +e
0834 }
0835 
0836 # assumption is that basic add of a single path route works
0837 # otherwise just adding an address on an interface is broken
0838 ipv6_rt_add()
0839 {
0840         local rc
0841 
0842         echo
0843         echo "IPv6 route add / append tests"
0844 
0845         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
0846         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
0847         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
0848         log_test $? 2 "Attempt to add duplicate route - gw"
0849 
0850         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
0851         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
0852         run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
0853         log_test $? 2 "Attempt to add duplicate route - dev only"
0854 
0855         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
0856         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
0857         run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
0858         log_test $? 2 "Attempt to add duplicate route - reject route"
0859 
0860         # route append with same prefix adds a new route
0861         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
0862         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
0863         run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
0864         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"
0865         log_test $? 0 "Append nexthop to existing route - gw"
0866 
0867         # insert mpath directly
0868         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0869         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"
0870         log_test $? 0 "Add multipath route"
0871 
0872         add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0873         run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0874         log_test $? 2 "Attempt to add duplicate multipath route"
0875 
0876         # insert of a second route without append but different metric
0877         add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
0878         run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
0879         rc=$?
0880         if [ $rc -eq 0 ]; then
0881                 run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
0882                 rc=$?
0883         fi
0884         log_test $rc 0 "Route add with different metrics"
0885 
0886         run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
0887         rc=$?
0888         if [ $rc -eq 0 ]; then
0889                 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"
0890                 rc=$?
0891         fi
0892         log_test $rc 0 "Route delete with metric"
0893 }
0894 
0895 ipv6_rt_replace_single()
0896 {
0897         # single path with single path
0898         #
0899         add_initial_route6 "via 2001:db8:101::2"
0900         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
0901         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
0902         log_test $? 0 "Single path with single path"
0903 
0904         # single path with multipath
0905         #
0906         add_initial_route6 "nexthop via 2001:db8:101::2"
0907         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
0908         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"
0909         log_test $? 0 "Single path with multipath"
0910 
0911         # single path with single path using MULTIPATH attribute
0912         #
0913         add_initial_route6 "via 2001:db8:101::2"
0914         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
0915         check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
0916         log_test $? 0 "Single path with single path via multipath attribute"
0917 
0918         # route replace fails - invalid nexthop
0919         add_initial_route6 "via 2001:db8:101::2"
0920         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
0921         if [ $? -eq 0 ]; then
0922                 # previous command is expected to fail so if it returns 0
0923                 # that means the test failed.
0924                 log_test 0 1 "Invalid nexthop"
0925         else
0926                 check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
0927                 log_test $? 0 "Invalid nexthop"
0928         fi
0929 
0930         # replace non-existent route
0931         # - note use of change versus replace since ip adds NLM_F_CREATE
0932         #   for replace
0933         add_initial_route6 "via 2001:db8:101::2"
0934         run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
0935         log_test $? 2 "Single path - replace of non-existent route"
0936 }
0937 
0938 ipv6_rt_replace_mpath()
0939 {
0940         # multipath with multipath
0941         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0942         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
0943         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"
0944         log_test $? 0 "Multipath with multipath"
0945 
0946         # multipath with single
0947         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0948         run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
0949         check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
0950         log_test $? 0 "Multipath with single path"
0951 
0952         # multipath with single
0953         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0954         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
0955         check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
0956         log_test $? 0 "Multipath with single path via multipath attribute"
0957 
0958         # multipath with dev-only
0959         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0960         run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
0961         check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
0962         log_test $? 0 "Multipath with dev-only"
0963 
0964         # route replace fails - invalid nexthop 1
0965         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0966         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
0967         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"
0968         log_test $? 0 "Multipath - invalid first nexthop"
0969 
0970         # route replace fails - invalid nexthop 2
0971         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0972         run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
0973         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"
0974         log_test $? 0 "Multipath - invalid second nexthop"
0975 
0976         # multipath non-existent route
0977         add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
0978         run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
0979         log_test $? 2 "Multipath - replace of non-existent route"
0980 }
0981 
0982 ipv6_rt_replace()
0983 {
0984         echo
0985         echo "IPv6 route replace tests"
0986 
0987         ipv6_rt_replace_single
0988         ipv6_rt_replace_mpath
0989 }
0990 
0991 ipv6_rt_dsfield()
0992 {
0993         echo
0994         echo "IPv6 route with dsfield tests"
0995 
0996         run_cmd "$IP -6 route flush 2001:db8:102::/64"
0997 
0998         # IPv6 doesn't support routing based on dsfield
0999         run_cmd "$IP -6 route add 2001:db8:102::/64 dsfield 0x04 via 2001:db8:101::2"
1000         log_test $? 2 "Reject route with dsfield"
1001 }
1002 
1003 ipv6_route_test()
1004 {
1005         route_setup
1006 
1007         ipv6_rt_add
1008         ipv6_rt_replace
1009         ipv6_rt_dsfield
1010 
1011         route_cleanup
1012 }
1013 
1014 ip_addr_metric_check()
1015 {
1016         ip addr help 2>&1 | grep -q metric
1017         if [ $? -ne 0 ]; then
1018                 echo "iproute2 command does not support metric for addresses. Skipping test"
1019                 return 1
1020         fi
1021 
1022         return 0
1023 }
1024 
1025 ipv6_addr_metric_test()
1026 {
1027         local rc
1028 
1029         echo
1030         echo "IPv6 prefix route tests"
1031 
1032         ip_addr_metric_check || return 1
1033 
1034         setup
1035 
1036         set -e
1037         $IP li add dummy1 type dummy
1038         $IP li add dummy2 type dummy
1039         $IP li set dummy1 up
1040         $IP li set dummy2 up
1041 
1042         # default entry is metric 256
1043         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1044         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1045         set +e
1046 
1047         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1048         log_test $? 0 "Default metric"
1049 
1050         set -e
1051         run_cmd "$IP -6 addr flush dev dummy1"
1052         run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1053         set +e
1054 
1055         check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1056         log_test $? 0 "User specified metric on first device"
1057 
1058         set -e
1059         run_cmd "$IP -6 addr flush dev dummy2"
1060         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1061         set +e
1062 
1063         check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1064         log_test $? 0 "User specified metric on second device"
1065 
1066         run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1067         rc=$?
1068         if [ $rc -eq 0 ]; then
1069                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1070                 rc=$?
1071         fi
1072         log_test $rc 0 "Delete of address on first device"
1073 
1074         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1075         rc=$?
1076         if [ $rc -eq 0 ]; then
1077                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1078                 rc=$?
1079         fi
1080         log_test $rc 0 "Modify metric of address"
1081 
1082         # verify prefix route removed on down
1083         run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1084         run_cmd "$IP li set dev dummy2 down"
1085         rc=$?
1086         if [ $rc -eq 0 ]; then
1087                 out=$($IP -6 ro ls match 2001:db8:104::/64)
1088                 check_expected "${out}" ""
1089                 rc=$?
1090         fi
1091         log_test $rc 0 "Prefix route removed on link down"
1092 
1093         # verify prefix route re-inserted with assigned metric
1094         run_cmd "$IP li set dev dummy2 up"
1095         rc=$?
1096         if [ $rc -eq 0 ]; then
1097                 check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1098                 rc=$?
1099         fi
1100         log_test $rc 0 "Prefix route with metric on link up"
1101 
1102         # verify peer metric added correctly
1103         set -e
1104         run_cmd "$IP -6 addr flush dev dummy2"
1105         run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1106         set +e
1107 
1108         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1109         log_test $? 0 "Set metric with peer route on local side"
1110         check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1111         log_test $? 0 "Set metric with peer route on peer side"
1112 
1113         set -e
1114         run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1115         set +e
1116 
1117         check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1118         log_test $? 0 "Modify metric and peer address on local side"
1119         check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1120         log_test $? 0 "Modify metric and peer address on peer side"
1121 
1122         $IP li del dummy1
1123         $IP li del dummy2
1124         cleanup
1125 }
1126 
1127 ipv6_route_metrics_test()
1128 {
1129         local rc
1130 
1131         echo
1132         echo "IPv6 routes with metrics"
1133 
1134         route_setup
1135 
1136         #
1137         # single path with metrics
1138         #
1139         run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1140         rc=$?
1141         if [ $rc -eq 0 ]; then
1142                 check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1143                 rc=$?
1144         fi
1145         log_test $rc 0 "Single path route with mtu metric"
1146 
1147 
1148         #
1149         # multipath via separate routes with metrics
1150         #
1151         run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1152         run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1153         rc=$?
1154         if [ $rc -eq 0 ]; then
1155                 check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1156                 rc=$?
1157         fi
1158         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1159 
1160         # second route is coalesced to first to make a multipath route.
1161         # MTU of the second path is hidden from display!
1162         run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1163         run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1164         rc=$?
1165         if [ $rc -eq 0 ]; then
1166                 check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1167                 rc=$?
1168         fi
1169         log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1170 
1171         run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1172         if [ $? -eq 0 ]; then
1173                 check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1174                 log_test $? 0 "    MTU of second leg"
1175         fi
1176 
1177         #
1178         # multipath with metrics
1179         #
1180         run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1181         rc=$?
1182         if [ $rc -eq 0 ]; then
1183                 check_route6  "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1184                 rc=$?
1185         fi
1186         log_test $rc 0 "Multipath route with mtu metric"
1187 
1188         $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1189         run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1190         log_test $? 0 "Using route with mtu metric"
1191 
1192         run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1193         log_test $? 2 "Invalid metric (fails metric_convert)"
1194 
1195         route_cleanup
1196 }
1197 
1198 # add route for a prefix, flushing any existing routes first
1199 # expected to be the first step of a test
1200 add_route()
1201 {
1202         local pfx="$1"
1203         local nh="$2"
1204         local out
1205 
1206         if [ "$VERBOSE" = "1" ]; then
1207                 echo
1208                 echo "    ##################################################"
1209                 echo
1210         fi
1211 
1212         run_cmd "$IP ro flush ${pfx}"
1213         [ $? -ne 0 ] && exit 1
1214 
1215         out=$($IP ro ls match ${pfx})
1216         if [ -n "$out" ]; then
1217                 echo "Failed to flush routes for prefix used for tests."
1218                 exit 1
1219         fi
1220 
1221         run_cmd "$IP ro add ${pfx} ${nh}"
1222         if [ $? -ne 0 ]; then
1223                 echo "Failed to add initial route for test."
1224                 exit 1
1225         fi
1226 }
1227 
1228 # add initial route - used in replace route tests
1229 add_initial_route()
1230 {
1231         add_route "172.16.104.0/24" "$1"
1232 }
1233 
1234 check_route()
1235 {
1236         local pfx
1237         local expected="$1"
1238         local out
1239 
1240         set -- $expected
1241         pfx=$1
1242         [ "${pfx}" = "unreachable" ] && pfx=$2
1243 
1244         out=$($IP ro ls match ${pfx})
1245         check_expected "${out}" "${expected}"
1246 }
1247 
1248 # assumption is that basic add of a single path route works
1249 # otherwise just adding an address on an interface is broken
1250 ipv4_rt_add()
1251 {
1252         local rc
1253 
1254         echo
1255         echo "IPv4 route add / append tests"
1256 
1257         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1258         add_route "172.16.104.0/24" "via 172.16.101.2"
1259         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1260         log_test $? 2 "Attempt to add duplicate route - gw"
1261 
1262         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1263         add_route "172.16.104.0/24" "via 172.16.101.2"
1264         run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1265         log_test $? 2 "Attempt to add duplicate route - dev only"
1266 
1267         # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1268         add_route "172.16.104.0/24" "via 172.16.101.2"
1269         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1270         log_test $? 2 "Attempt to add duplicate route - reject route"
1271 
1272         # iproute2 prepend only sets NLM_F_CREATE
1273         # - adds a new route; does NOT convert existing route to ECMP
1274         add_route "172.16.104.0/24" "via 172.16.101.2"
1275         run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1276         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3 172.16.104.0/24 via 172.16.101.2 dev veth1"
1277         log_test $? 0 "Add new nexthop for existing prefix"
1278 
1279         # route append with same prefix adds a new route
1280         # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1281         add_route "172.16.104.0/24" "via 172.16.101.2"
1282         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1283         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.2 dev veth3"
1284         log_test $? 0 "Append nexthop to existing route - gw"
1285 
1286         add_route "172.16.104.0/24" "via 172.16.101.2"
1287         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1288         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1289         log_test $? 0 "Append nexthop to existing route - dev only"
1290 
1291         add_route "172.16.104.0/24" "via 172.16.101.2"
1292         run_cmd "$IP ro append unreachable 172.16.104.0/24"
1293         check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1294         log_test $? 0 "Append nexthop to existing route - reject route"
1295 
1296         run_cmd "$IP ro flush 172.16.104.0/24"
1297         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1298         run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1299         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1300         log_test $? 0 "Append nexthop to existing reject route - gw"
1301 
1302         run_cmd "$IP ro flush 172.16.104.0/24"
1303         run_cmd "$IP ro add unreachable 172.16.104.0/24"
1304         run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1305         check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1306         log_test $? 0 "Append nexthop to existing reject route - dev only"
1307 
1308         # insert mpath directly
1309         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1310         check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1311         log_test $? 0 "add multipath route"
1312 
1313         add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1314         run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1315         log_test $? 2 "Attempt to add duplicate multipath route"
1316 
1317         # insert of a second route without append but different metric
1318         add_route "172.16.104.0/24" "via 172.16.101.2"
1319         run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1320         rc=$?
1321         if [ $rc -eq 0 ]; then
1322                 run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1323                 rc=$?
1324         fi
1325         log_test $rc 0 "Route add with different metrics"
1326 
1327         run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1328         rc=$?
1329         if [ $rc -eq 0 ]; then
1330                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.3 dev veth3 metric 256"
1331                 rc=$?
1332         fi
1333         log_test $rc 0 "Route delete with metric"
1334 }
1335 
1336 ipv4_rt_replace_single()
1337 {
1338         # single path with single path
1339         #
1340         add_initial_route "via 172.16.101.2"
1341         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1342         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1343         log_test $? 0 "Single path with single path"
1344 
1345         # single path with multipath
1346         #
1347         add_initial_route "nexthop via 172.16.101.2"
1348         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1349         check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1350         log_test $? 0 "Single path with multipath"
1351 
1352         # single path with reject
1353         #
1354         add_initial_route "nexthop via 172.16.101.2"
1355         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1356         check_route "unreachable 172.16.104.0/24"
1357         log_test $? 0 "Single path with reject route"
1358 
1359         # single path with single path using MULTIPATH attribute
1360         #
1361         add_initial_route "via 172.16.101.2"
1362         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1363         check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1364         log_test $? 0 "Single path with single path via multipath attribute"
1365 
1366         # route replace fails - invalid nexthop
1367         add_initial_route "via 172.16.101.2"
1368         run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1369         if [ $? -eq 0 ]; then
1370                 # previous command is expected to fail so if it returns 0
1371                 # that means the test failed.
1372                 log_test 0 1 "Invalid nexthop"
1373         else
1374                 check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1375                 log_test $? 0 "Invalid nexthop"
1376         fi
1377 
1378         # replace non-existent route
1379         # - note use of change versus replace since ip adds NLM_F_CREATE
1380         #   for replace
1381         add_initial_route "via 172.16.101.2"
1382         run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1383         log_test $? 2 "Single path - replace of non-existent route"
1384 }
1385 
1386 ipv4_rt_replace_mpath()
1387 {
1388         # multipath with multipath
1389         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1390         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1391         check_route  "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.3 dev veth3 weight 1"
1392         log_test $? 0 "Multipath with multipath"
1393 
1394         # multipath with single
1395         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1396         run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1397         check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1398         log_test $? 0 "Multipath with single path"
1399 
1400         # multipath with single
1401         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1402         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1403         check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1404         log_test $? 0 "Multipath with single path via multipath attribute"
1405 
1406         # multipath with reject
1407         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1408         run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1409         check_route "unreachable 172.16.104.0/24"
1410         log_test $? 0 "Multipath with reject route"
1411 
1412         # route replace fails - invalid nexthop 1
1413         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1414         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1415         check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1416         log_test $? 0 "Multipath - invalid first nexthop"
1417 
1418         # route replace fails - invalid nexthop 2
1419         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1420         run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1421         check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1422         log_test $? 0 "Multipath - invalid second nexthop"
1423 
1424         # multipath non-existent route
1425         add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1426         run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1427         log_test $? 2 "Multipath - replace of non-existent route"
1428 }
1429 
1430 ipv4_rt_replace()
1431 {
1432         echo
1433         echo "IPv4 route replace tests"
1434 
1435         ipv4_rt_replace_single
1436         ipv4_rt_replace_mpath
1437 }
1438 
1439 # checks that cached input route on VRF port is deleted
1440 # when VRF is deleted
1441 ipv4_local_rt_cache()
1442 {
1443         run_cmd "ip addr add 10.0.0.1/32 dev lo"
1444         run_cmd "ip netns add test-ns"
1445         run_cmd "ip link add veth-outside type veth peer name veth-inside"
1446         run_cmd "ip link add vrf-100 type vrf table 1100"
1447         run_cmd "ip link set veth-outside master vrf-100"
1448         run_cmd "ip link set veth-inside netns test-ns"
1449         run_cmd "ip link set veth-outside up"
1450         run_cmd "ip link set vrf-100 up"
1451         run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1452         run_cmd "ip netns exec test-ns ip link set veth-inside up"
1453         run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1454         run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
1455         run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
1456         run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
1457         run_cmd "ip link delete vrf-100"
1458 
1459         # if we do not hang test is a success
1460         log_test $? 0 "Cached route removed from VRF port device"
1461 }
1462 
1463 ipv4_rt_dsfield()
1464 {
1465         echo
1466         echo "IPv4 route with dsfield tests"
1467 
1468         run_cmd "$IP route flush 172.16.102.0/24"
1469 
1470         # New routes should reject dsfield options that interfere with ECN
1471         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
1472         log_test $? 2 "Reject route with dsfield 0x01"
1473 
1474         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
1475         log_test $? 2 "Reject route with dsfield 0x02"
1476 
1477         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
1478         log_test $? 2 "Reject route with dsfield 0x03"
1479 
1480         # A generic route that doesn't take DSCP into account
1481         run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
1482 
1483         # A more specific route for DSCP 0x10
1484         run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
1485 
1486         # DSCP 0x10 should match the specific route, no matter the ECN bits
1487         $IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
1488                 grep -q "via 172.16.103.2"
1489         log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
1490 
1491         $IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
1492                 grep -q "via 172.16.103.2"
1493         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
1494 
1495         $IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
1496                 grep -q "via 172.16.103.2"
1497         log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
1498 
1499         $IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
1500                 grep -q "via 172.16.103.2"
1501         log_test $? 0 "IPv4 route with DSCP and ECN:CE"
1502 
1503         # Unknown DSCP should match the generic route, no matter the ECN bits
1504         $IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
1505                 grep -q "via 172.16.101.2"
1506         log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
1507 
1508         $IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
1509                 grep -q "via 172.16.101.2"
1510         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
1511 
1512         $IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
1513                 grep -q "via 172.16.101.2"
1514         log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
1515 
1516         $IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
1517                 grep -q "via 172.16.101.2"
1518         log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
1519 
1520         # Null DSCP should match the generic route, no matter the ECN bits
1521         $IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
1522                 grep -q "via 172.16.101.2"
1523         log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
1524 
1525         $IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
1526                 grep -q "via 172.16.101.2"
1527         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
1528 
1529         $IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
1530                 grep -q "via 172.16.101.2"
1531         log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
1532 
1533         $IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
1534                 grep -q "via 172.16.101.2"
1535         log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
1536 }
1537 
1538 ipv4_route_test()
1539 {
1540         route_setup
1541 
1542         ipv4_rt_add
1543         ipv4_rt_replace
1544         ipv4_local_rt_cache
1545         ipv4_rt_dsfield
1546 
1547         route_cleanup
1548 }
1549 
1550 ipv4_addr_metric_test()
1551 {
1552         local rc
1553 
1554         echo
1555         echo "IPv4 prefix route tests"
1556 
1557         ip_addr_metric_check || return 1
1558 
1559         setup
1560 
1561         set -e
1562         $IP li add dummy1 type dummy
1563         $IP li add dummy2 type dummy
1564         $IP li set dummy1 up
1565         $IP li set dummy2 up
1566 
1567         # default entry is metric 256
1568         run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1569         run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1570         set +e
1571 
1572         check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2"
1573         log_test $? 0 "Default metric"
1574 
1575         set -e
1576         run_cmd "$IP addr flush dev dummy1"
1577         run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1578         set +e
1579 
1580         check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257"
1581         log_test $? 0 "User specified metric on first device"
1582 
1583         set -e
1584         run_cmd "$IP addr flush dev dummy2"
1585         run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1586         set +e
1587 
1588         check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1589         log_test $? 0 "User specified metric on second device"
1590 
1591         run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1592         rc=$?
1593         if [ $rc -eq 0 ]; then
1594                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1595                 rc=$?
1596         fi
1597         log_test $rc 0 "Delete of address on first device"
1598 
1599         run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1600         rc=$?
1601         if [ $rc -eq 0 ]; then
1602                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1603                 rc=$?
1604         fi
1605         log_test $rc 0 "Modify metric of address"
1606 
1607         # verify prefix route removed on down
1608         run_cmd "$IP li set dev dummy2 down"
1609         rc=$?
1610         if [ $rc -eq 0 ]; then
1611                 out=$($IP ro ls match 172.16.104.0/24)
1612                 check_expected "${out}" ""
1613                 rc=$?
1614         fi
1615         log_test $rc 0 "Prefix route removed on link down"
1616 
1617         # verify prefix route re-inserted with assigned metric
1618         run_cmd "$IP li set dev dummy2 up"
1619         rc=$?
1620         if [ $rc -eq 0 ]; then
1621                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1622                 rc=$?
1623         fi
1624         log_test $rc 0 "Prefix route with metric on link up"
1625 
1626         # explicitly check for metric changes on edge scenarios
1627         run_cmd "$IP addr flush dev dummy2"
1628         run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1629         run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1630         rc=$?
1631         if [ $rc -eq 0 ]; then
1632                 check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1633                 rc=$?
1634         fi
1635         log_test $rc 0 "Modify metric of .0/24 address"
1636 
1637         run_cmd "$IP addr flush dev dummy2"
1638         run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1639         rc=$?
1640         if [ $rc -eq 0 ]; then
1641                 check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1642                 rc=$?
1643         fi
1644         log_test $rc 0 "Set metric of address with peer route"
1645 
1646         run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1647         rc=$?
1648         if [ $rc -eq 0 ]; then
1649                 check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1650                 rc=$?
1651         fi
1652         log_test $rc 0 "Modify metric and peer address for peer route"
1653 
1654         $IP li del dummy1
1655         $IP li del dummy2
1656         cleanup
1657 }
1658 
1659 ipv4_route_metrics_test()
1660 {
1661         local rc
1662 
1663         echo
1664         echo "IPv4 route add / append tests"
1665 
1666         route_setup
1667 
1668         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1669         rc=$?
1670         if [ $rc -eq 0 ]; then
1671                 check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1672                 rc=$?
1673         fi
1674         log_test $rc 0 "Single path route with mtu metric"
1675 
1676 
1677         run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1678         rc=$?
1679         if [ $rc -eq 0 ]; then
1680                 check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1681                 rc=$?
1682         fi
1683         log_test $rc 0 "Multipath route with mtu metric"
1684 
1685         $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1686         run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1687         log_test $? 0 "Using route with mtu metric"
1688 
1689         run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1690         log_test $? 2 "Invalid metric (fails metric_convert)"
1691 
1692         route_cleanup
1693 }
1694 
1695 ipv4_del_addr_test()
1696 {
1697         echo
1698         echo "IPv4 delete address route tests"
1699 
1700         setup
1701 
1702         set -e
1703         $IP li add dummy1 type dummy
1704         $IP li set dummy1 up
1705         $IP li add dummy2 type dummy
1706         $IP li set dummy2 up
1707         $IP li add red type vrf table 1111
1708         $IP li set red up
1709         $IP ro add vrf red unreachable default
1710         $IP li set dummy2 vrf red
1711 
1712         $IP addr add dev dummy1 172.16.104.1/24
1713         $IP addr add dev dummy1 172.16.104.11/24
1714         $IP addr add dev dummy2 172.16.104.1/24
1715         $IP addr add dev dummy2 172.16.104.11/24
1716         $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1717         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1718         set +e
1719 
1720         # removing address from device in vrf should only remove route from vrf table
1721         $IP addr del dev dummy2 172.16.104.11/24
1722         $IP ro ls vrf red | grep -q 172.16.105.0/24
1723         log_test $? 1 "Route removed from VRF when source address deleted"
1724 
1725         $IP ro ls | grep -q 172.16.105.0/24
1726         log_test $? 0 "Route in default VRF not removed"
1727 
1728         $IP addr add dev dummy2 172.16.104.11/24
1729         $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1730 
1731         $IP addr del dev dummy1 172.16.104.11/24
1732         $IP ro ls | grep -q 172.16.105.0/24
1733         log_test $? 1 "Route removed in default VRF when source address deleted"
1734 
1735         $IP ro ls vrf red | grep -q 172.16.105.0/24
1736         log_test $? 0 "Route in VRF is not removed by address delete"
1737 
1738         $IP li del dummy1
1739         $IP li del dummy2
1740         cleanup
1741 }
1742 
1743 
1744 ipv4_route_v6_gw_test()
1745 {
1746         local rc
1747 
1748         echo
1749         echo "IPv4 route with IPv6 gateway tests"
1750 
1751         route_setup
1752         sleep 2
1753 
1754         #
1755         # single path route
1756         #
1757         run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1758         rc=$?
1759         log_test $rc 0 "Single path route with IPv6 gateway"
1760         if [ $rc -eq 0 ]; then
1761                 check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1762         fi
1763 
1764         run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1765         log_test $rc 0 "Single path route with IPv6 gateway - ping"
1766 
1767         run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1768         rc=$?
1769         log_test $rc 0 "Single path route delete"
1770         if [ $rc -eq 0 ]; then
1771                 check_route "172.16.112.0/24"
1772         fi
1773 
1774         #
1775         # multipath - v6 then v4
1776         #
1777         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"
1778         rc=$?
1779         log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1780         if [ $rc -eq 0 ]; then
1781                 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"
1782         fi
1783 
1784         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"
1785         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1786 
1787         run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
1788         log_test $? 0 "    Multipath route delete exact match"
1789 
1790         #
1791         # multipath - v4 then v6
1792         #
1793         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"
1794         rc=$?
1795         log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1796         if [ $rc -eq 0 ]; then
1797                 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"
1798         fi
1799 
1800         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"
1801         log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1802 
1803         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"
1804         log_test $? 0 "    Multipath route delete exact match"
1805 
1806         route_cleanup
1807 }
1808 
1809 socat_check()
1810 {
1811         if [ ! -x "$(command -v socat)" ]; then
1812                 echo "socat command not found. Skipping test"
1813                 return 1
1814         fi
1815 
1816         return 0
1817 }
1818 
1819 iptables_check()
1820 {
1821         iptables -t mangle -L OUTPUT &> /dev/null
1822         if [ $? -ne 0 ]; then
1823                 echo "iptables configuration not supported. Skipping test"
1824                 return 1
1825         fi
1826 
1827         return 0
1828 }
1829 
1830 ip6tables_check()
1831 {
1832         ip6tables -t mangle -L OUTPUT &> /dev/null
1833         if [ $? -ne 0 ]; then
1834                 echo "ip6tables configuration not supported. Skipping test"
1835                 return 1
1836         fi
1837 
1838         return 0
1839 }
1840 
1841 ipv4_mangle_test()
1842 {
1843         local rc
1844 
1845         echo
1846         echo "IPv4 mangling tests"
1847 
1848         socat_check || return 1
1849         iptables_check || return 1
1850 
1851         route_setup
1852         sleep 2
1853 
1854         local tmp_file=$(mktemp)
1855         ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
1856 
1857         # Add a FIB rule and a route that will direct our connection to the
1858         # listening server.
1859         $IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1860         $IP route add table 123 172.16.101.0/24 dev veth1
1861 
1862         # Add an unreachable route to the main table that will block our
1863         # connection in case the FIB rule is not hit.
1864         $IP route add unreachable 172.16.101.2/32
1865 
1866         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1867         log_test $? 0 "    Connection with correct parameters"
1868 
1869         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
1870         log_test $? 1 "    Connection with incorrect parameters"
1871 
1872         # Add a mangling rule and make sure connection is still successful.
1873         $NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
1874 
1875         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1876         log_test $? 0 "    Connection with correct parameters - mangling"
1877 
1878         # Delete the mangling rule and make sure connection is still
1879         # successful.
1880         $NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
1881 
1882         run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1883         log_test $? 0 "    Connection with correct parameters - no mangling"
1884 
1885         # Verify connections were indeed successful on server side.
1886         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1887         log_test $? 0 "    Connection check - server side"
1888 
1889         $IP route del unreachable 172.16.101.2/32
1890         $IP route del table 123 172.16.101.0/24 dev veth1
1891         $IP rule del pref 100
1892 
1893         { kill %% && wait %%; } 2>/dev/null
1894         rm $tmp_file
1895 
1896         route_cleanup
1897 }
1898 
1899 ipv6_mangle_test()
1900 {
1901         local rc
1902 
1903         echo
1904         echo "IPv6 mangling tests"
1905 
1906         socat_check || return 1
1907         ip6tables_check || return 1
1908 
1909         route_setup
1910         sleep 2
1911 
1912         local tmp_file=$(mktemp)
1913         ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
1914 
1915         # Add a FIB rule and a route that will direct our connection to the
1916         # listening server.
1917         $IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1918         $IP -6 route add table 123 2001:db8:101::/64 dev veth1
1919 
1920         # Add an unreachable route to the main table that will block our
1921         # connection in case the FIB rule is not hit.
1922         $IP -6 route add unreachable 2001:db8:101::2/128
1923 
1924         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1925         log_test $? 0 "    Connection with correct parameters"
1926 
1927         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
1928         log_test $? 1 "    Connection with incorrect parameters"
1929 
1930         # Add a mangling rule and make sure connection is still successful.
1931         $NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
1932 
1933         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1934         log_test $? 0 "    Connection with correct parameters - mangling"
1935 
1936         # Delete the mangling rule and make sure connection is still
1937         # successful.
1938         $NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
1939 
1940         run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1941         log_test $? 0 "    Connection with correct parameters - no mangling"
1942 
1943         # Verify connections were indeed successful on server side.
1944         [[ $(cat $tmp_file | wc -l) -eq 3 ]]
1945         log_test $? 0 "    Connection check - server side"
1946 
1947         $IP -6 route del unreachable 2001:db8:101::2/128
1948         $IP -6 route del table 123 2001:db8:101::/64 dev veth1
1949         $IP -6 rule del pref 100
1950 
1951         { kill %% && wait %%; } 2>/dev/null
1952         rm $tmp_file
1953 
1954         route_cleanup
1955 }
1956 
1957 ip_neigh_get_check()
1958 {
1959         ip neigh help 2>&1 | grep -q 'ip neigh get'
1960         if [ $? -ne 0 ]; then
1961                 echo "iproute2 command does not support neigh get. Skipping test"
1962                 return 1
1963         fi
1964 
1965         return 0
1966 }
1967 
1968 ipv4_bcast_neigh_test()
1969 {
1970         local rc
1971 
1972         echo
1973         echo "IPv4 broadcast neighbour tests"
1974 
1975         ip_neigh_get_check || return 1
1976 
1977         setup
1978 
1979         set -e
1980         run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
1981         run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
1982 
1983         run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
1984         run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
1985 
1986         run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"
1987 
1988         run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
1989         run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"
1990 
1991         run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
1992         run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
1993 
1994         run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
1995         set +e
1996 
1997         run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
1998         log_test $? 0 "Resolved neighbour for broadcast address"
1999 
2000         run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2001         log_test $? 0 "Resolved neighbour for network broadcast address"
2002 
2003         run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2004         log_test $? 2 "Unresolved neighbour for broadcast address"
2005 
2006         run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2007         log_test $? 2 "Unresolved neighbour for network broadcast address"
2008 
2009         cleanup
2010 }
2011 
2012 ################################################################################
2013 # usage
2014 
2015 usage()
2016 {
2017         cat <<EOF
2018 usage: ${0##*/} OPTS
2019 
2020         -t <test>   Test(s) to run (default: all)
2021                     (options: $TESTS)
2022         -p          Pause on fail
2023         -P          Pause after each test before cleanup
2024         -v          verbose mode (show commands and output)
2025 EOF
2026 }
2027 
2028 ################################################################################
2029 # main
2030 
2031 while getopts :t:pPhv o
2032 do
2033         case $o in
2034                 t) TESTS=$OPTARG;;
2035                 p) PAUSE_ON_FAIL=yes;;
2036                 P) PAUSE=yes;;
2037                 v) VERBOSE=$(($VERBOSE + 1));;
2038                 h) usage; exit 0;;
2039                 *) usage; exit 1;;
2040         esac
2041 done
2042 
2043 PEER_CMD="ip netns exec ${PEER_NS}"
2044 
2045 # make sure we don't pause twice
2046 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2047 
2048 if [ "$(id -u)" -ne 0 ];then
2049         echo "SKIP: Need root privileges"
2050         exit $ksft_skip;
2051 fi
2052 
2053 if [ ! -x "$(command -v ip)" ]; then
2054         echo "SKIP: Could not run test without ip tool"
2055         exit $ksft_skip
2056 fi
2057 
2058 ip route help 2>&1 | grep -q fibmatch
2059 if [ $? -ne 0 ]; then
2060         echo "SKIP: iproute2 too old, missing fibmatch"
2061         exit $ksft_skip
2062 fi
2063 
2064 # start clean
2065 cleanup &> /dev/null
2066 
2067 for t in $TESTS
2068 do
2069         case $t in
2070         fib_unreg_test|unregister)      fib_unreg_test;;
2071         fib_down_test|down)             fib_down_test;;
2072         fib_carrier_test|carrier)       fib_carrier_test;;
2073         fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
2074         fib_nexthop_test|nexthop)       fib_nexthop_test;;
2075         fib_suppress_test|suppress)     fib_suppress_test;;
2076         ipv6_route_test|ipv6_rt)        ipv6_route_test;;
2077         ipv4_route_test|ipv4_rt)        ipv4_route_test;;
2078         ipv6_addr_metric)               ipv6_addr_metric_test;;
2079         ipv4_addr_metric)               ipv4_addr_metric_test;;
2080         ipv4_del_addr)                  ipv4_del_addr_test;;
2081         ipv6_route_metrics)             ipv6_route_metrics_test;;
2082         ipv4_route_metrics)             ipv4_route_metrics_test;;
2083         ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
2084         ipv4_mangle)                    ipv4_mangle_test;;
2085         ipv6_mangle)                    ipv6_mangle_test;;
2086         ipv4_bcast_neigh)               ipv4_bcast_neigh_test;;
2087 
2088         help) echo "Test names: $TESTS"; exit 0;;
2089         esac
2090 done
2091 
2092 if [ "$TESTS" != "none" ]; then
2093         printf "\nTests passed: %3d\n" ${nsuccess}
2094         printf "Tests failed: %3d\n"   ${nfail}
2095 fi
2096 
2097 exit $ret