linux/tools/testing/selftests/net/fib_tests.sh
<<
>>
Prefs
   1#!/bin/bash
   2# SPDX-License-Identifier: GPL-2.0
   3
   4# This test is for checking IPv4 and IPv6 FIB behavior in response to
   5# different events.
   6
   7ret=0
   8# Kselftest framework requirement - SKIP code is 4.
   9ksft_skip=4
  10
  11# all tests in this script. Can be overridden with -t option
  12TESTS="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"
  13
  14VERBOSE=0
  15PAUSE_ON_FAIL=no
  16PAUSE=no
  17IP="ip -netns ns1"
  18NS_EXEC="ip netns exec ns1"
  19
  20which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
  21
  22log_test()
  23{
  24        local rc=$1
  25        local expected=$2
  26        local msg="$3"
  27
  28        if [ ${rc} -eq ${expected} ]; then
  29                printf "    TEST: %-60s  [ OK ]\n" "${msg}"
  30                nsuccess=$((nsuccess+1))
  31        else
  32                ret=1
  33                nfail=$((nfail+1))
  34                printf "    TEST: %-60s  [FAIL]\n" "${msg}"
  35                if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
  36                echo
  37                        echo "hit enter to continue, 'q' to quit"
  38                        read a
  39                        [ "$a" = "q" ] && exit 1
  40                fi
  41        fi
  42
  43        if [ "${PAUSE}" = "yes" ]; then
  44                echo
  45                echo "hit enter to continue, 'q' to quit"
  46                read a
  47                [ "$a" = "q" ] && exit 1
  48        fi
  49}
  50
  51setup()
  52{
  53        set -e
  54        ip netns add ns1
  55        ip netns set ns1 auto
  56        $IP link set dev lo up
  57        ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
  58        ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
  59
  60        $IP link add dummy0 type dummy
  61        $IP link set dev dummy0 up
  62        $IP address add 198.51.100.1/24 dev dummy0
  63        $IP -6 address add 2001:db8:1::1/64 dev dummy0
  64        set +e
  65
  66}
  67
  68cleanup()
  69{
  70        $IP link del dev dummy0 &> /dev/null
  71        ip netns del ns1
  72        ip netns del ns2 &> /dev/null
  73}
  74
  75get_linklocal()
  76{
  77        local dev=$1
  78        local addr
  79
  80        addr=$($IP -6 -br addr show dev ${dev} | \
  81        awk '{
  82                for (i = 3; i <= NF; ++i) {
  83                        if ($i ~ /^fe80/)
  84                                print $i
  85                }
  86        }'
  87        )
  88        addr=${addr/\/*}
  89
  90        [ -z "$addr" ] && return 1
  91
  92        echo $addr
  93
  94        return 0
  95}
  96
  97fib_unreg_unicast_test()
  98{
  99        echo
 100        echo "Single path route test"
 101
 102        setup
 103
 104        echo "    Start point"
 105        $IP route get fibmatch 198.51.100.2 &> /dev/null
 106        log_test $? 0 "IPv4 fibmatch"
 107        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 108        log_test $? 0 "IPv6 fibmatch"
 109
 110        set -e
 111        $IP link del dev dummy0
 112        set +e
 113
 114        echo "    Nexthop device deleted"
 115        $IP route get fibmatch 198.51.100.2 &> /dev/null
 116        log_test $? 2 "IPv4 fibmatch - no route"
 117        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 118        log_test $? 2 "IPv6 fibmatch - no route"
 119
 120        cleanup
 121}
 122
 123fib_unreg_multipath_test()
 124{
 125
 126        echo
 127        echo "Multipath route test"
 128
 129        setup
 130
 131        set -e
 132        $IP link add dummy1 type dummy
 133        $IP link set dev dummy1 up
 134        $IP address add 192.0.2.1/24 dev dummy1
 135        $IP -6 address add 2001:db8:2::1/64 dev dummy1
 136
 137        $IP route add 203.0.113.0/24 \
 138                nexthop via 198.51.100.2 dev dummy0 \
 139                nexthop via 192.0.2.2 dev dummy1
 140        $IP -6 route add 2001:db8:3::/64 \
 141                nexthop via 2001:db8:1::2 dev dummy0 \
 142                nexthop via 2001:db8:2::2 dev dummy1
 143        set +e
 144
 145        echo "    Start point"
 146        $IP route get fibmatch 203.0.113.1 &> /dev/null
 147        log_test $? 0 "IPv4 fibmatch"
 148        $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 149        log_test $? 0 "IPv6 fibmatch"
 150
 151        set -e
 152        $IP link del dev dummy0
 153        set +e
 154
 155        echo "    One nexthop device deleted"
 156        $IP route get fibmatch 203.0.113.1 &> /dev/null
 157        log_test $? 2 "IPv4 - multipath route removed on delete"
 158
 159        $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 160        # In IPv6 we do not flush the entire multipath route.
 161        log_test $? 0 "IPv6 - multipath down to single path"
 162
 163        set -e
 164        $IP link del dev dummy1
 165        set +e
 166
 167        echo "    Second nexthop device deleted"
 168        $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 169        log_test $? 2 "IPv6 - no route"
 170
 171        cleanup
 172}
 173
 174fib_unreg_test()
 175{
 176        fib_unreg_unicast_test
 177        fib_unreg_multipath_test
 178}
 179
 180fib_down_unicast_test()
 181{
 182        echo
 183        echo "Single path, admin down"
 184
 185        setup
 186
 187        echo "    Start point"
 188        $IP route get fibmatch 198.51.100.2 &> /dev/null
 189        log_test $? 0 "IPv4 fibmatch"
 190        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 191        log_test $? 0 "IPv6 fibmatch"
 192
 193        set -e
 194        $IP link set dev dummy0 down
 195        set +e
 196
 197        echo "    Route deleted on down"
 198        $IP route get fibmatch 198.51.100.2 &> /dev/null
 199        log_test $? 2 "IPv4 fibmatch"
 200        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 201        log_test $? 2 "IPv6 fibmatch"
 202
 203        cleanup
 204}
 205
 206fib_down_multipath_test_do()
 207{
 208        local down_dev=$1
 209        local up_dev=$2
 210
 211        $IP route get fibmatch 203.0.113.1 \
 212                oif $down_dev &> /dev/null
 213        log_test $? 2 "IPv4 fibmatch on down device"
 214        $IP -6 route get fibmatch 2001:db8:3::1 \
 215                oif $down_dev &> /dev/null
 216        log_test $? 2 "IPv6 fibmatch on down device"
 217
 218        $IP route get fibmatch 203.0.113.1 \
 219                oif $up_dev &> /dev/null
 220        log_test $? 0 "IPv4 fibmatch on up device"
 221        $IP -6 route get fibmatch 2001:db8:3::1 \
 222                oif $up_dev &> /dev/null
 223        log_test $? 0 "IPv6 fibmatch on up device"
 224
 225        $IP route get fibmatch 203.0.113.1 | \
 226                grep $down_dev | grep -q "dead linkdown"
 227        log_test $? 0 "IPv4 flags on down device"
 228        $IP -6 route get fibmatch 2001:db8:3::1 | \
 229                grep $down_dev | grep -q "dead linkdown"
 230        log_test $? 0 "IPv6 flags on down device"
 231
 232        $IP route get fibmatch 203.0.113.1 | \
 233                grep $up_dev | grep -q "dead linkdown"
 234        log_test $? 1 "IPv4 flags on up device"
 235        $IP -6 route get fibmatch 2001:db8:3::1 | \
 236                grep $up_dev | grep -q "dead linkdown"
 237        log_test $? 1 "IPv6 flags on up device"
 238}
 239
 240fib_down_multipath_test()
 241{
 242        echo
 243        echo "Admin down multipath"
 244
 245        setup
 246
 247        set -e
 248        $IP link add dummy1 type dummy
 249        $IP link set dev dummy1 up
 250
 251        $IP address add 192.0.2.1/24 dev dummy1
 252        $IP -6 address add 2001:db8:2::1/64 dev dummy1
 253
 254        $IP route add 203.0.113.0/24 \
 255                nexthop via 198.51.100.2 dev dummy0 \
 256                nexthop via 192.0.2.2 dev dummy1
 257        $IP -6 route add 2001:db8:3::/64 \
 258                nexthop via 2001:db8:1::2 dev dummy0 \
 259                nexthop via 2001:db8:2::2 dev dummy1
 260        set +e
 261
 262        echo "    Verify start point"
 263        $IP route get fibmatch 203.0.113.1 &> /dev/null
 264        log_test $? 0 "IPv4 fibmatch"
 265
 266        $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 267        log_test $? 0 "IPv6 fibmatch"
 268
 269        set -e
 270        $IP link set dev dummy0 down
 271        set +e
 272
 273        echo "    One device down, one up"
 274        fib_down_multipath_test_do "dummy0" "dummy1"
 275
 276        set -e
 277        $IP link set dev dummy0 up
 278        $IP link set dev dummy1 down
 279        set +e
 280
 281        echo "    Other device down and up"
 282        fib_down_multipath_test_do "dummy1" "dummy0"
 283
 284        set -e
 285        $IP link set dev dummy0 down
 286        set +e
 287
 288        echo "    Both devices down"
 289        $IP route get fibmatch 203.0.113.1 &> /dev/null
 290        log_test $? 2 "IPv4 fibmatch"
 291        $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 292        log_test $? 2 "IPv6 fibmatch"
 293
 294        $IP link del dev dummy1
 295        cleanup
 296}
 297
 298fib_down_test()
 299{
 300        fib_down_unicast_test
 301        fib_down_multipath_test
 302}
 303
 304# Local routes should not be affected when carrier changes.
 305fib_carrier_local_test()
 306{
 307        echo
 308        echo "Local carrier tests - single path"
 309
 310        setup
 311
 312        set -e
 313        $IP link set dev dummy0 carrier on
 314        set +e
 315
 316        echo "    Start point"
 317        $IP route get fibmatch 198.51.100.1 &> /dev/null
 318        log_test $? 0 "IPv4 fibmatch"
 319        $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
 320        log_test $? 0 "IPv6 fibmatch"
 321
 322        $IP route get fibmatch 198.51.100.1 | \
 323                grep -q "linkdown"
 324        log_test $? 1 "IPv4 - no linkdown flag"
 325        $IP -6 route get fibmatch 2001:db8:1::1 | \
 326                grep -q "linkdown"
 327        log_test $? 1 "IPv6 - no linkdown flag"
 328
 329        set -e
 330        $IP link set dev dummy0 carrier off
 331        sleep 1
 332        set +e
 333
 334        echo "    Carrier off on nexthop"
 335        $IP route get fibmatch 198.51.100.1 &> /dev/null
 336        log_test $? 0 "IPv4 fibmatch"
 337        $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
 338        log_test $? 0 "IPv6 fibmatch"
 339
 340        $IP route get fibmatch 198.51.100.1 | \
 341                grep -q "linkdown"
 342        log_test $? 1 "IPv4 - linkdown flag set"
 343        $IP -6 route get fibmatch 2001:db8:1::1 | \
 344                grep -q "linkdown"
 345        log_test $? 1 "IPv6 - linkdown flag set"
 346
 347        set -e
 348        $IP address add 192.0.2.1/24 dev dummy0
 349        $IP -6 address add 2001:db8:2::1/64 dev dummy0
 350        set +e
 351
 352        echo "    Route to local address with carrier down"
 353        $IP route get fibmatch 192.0.2.1 &> /dev/null
 354        log_test $? 0 "IPv4 fibmatch"
 355        $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
 356        log_test $? 0 "IPv6 fibmatch"
 357
 358        $IP route get fibmatch 192.0.2.1 | \
 359                grep -q "linkdown"
 360        log_test $? 1 "IPv4 linkdown flag set"
 361        $IP -6 route get fibmatch 2001:db8:2::1 | \
 362                grep -q "linkdown"
 363        log_test $? 1 "IPv6 linkdown flag set"
 364
 365        cleanup
 366}
 367
 368fib_carrier_unicast_test()
 369{
 370        ret=0
 371
 372        echo
 373        echo "Single path route carrier test"
 374
 375        setup
 376
 377        set -e
 378        $IP link set dev dummy0 carrier on
 379        set +e
 380
 381        echo "    Start point"
 382        $IP route get fibmatch 198.51.100.2 &> /dev/null
 383        log_test $? 0 "IPv4 fibmatch"
 384        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 385        log_test $? 0 "IPv6 fibmatch"
 386
 387        $IP route get fibmatch 198.51.100.2 | \
 388                grep -q "linkdown"
 389        log_test $? 1 "IPv4 no linkdown flag"
 390        $IP -6 route get fibmatch 2001:db8:1::2 | \
 391                grep -q "linkdown"
 392        log_test $? 1 "IPv6 no linkdown flag"
 393
 394        set -e
 395        $IP link set dev dummy0 carrier off
 396        sleep 1
 397        set +e
 398
 399        echo "    Carrier down"
 400        $IP route get fibmatch 198.51.100.2 &> /dev/null
 401        log_test $? 0 "IPv4 fibmatch"
 402        $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
 403        log_test $? 0 "IPv6 fibmatch"
 404
 405        $IP route get fibmatch 198.51.100.2 | \
 406                grep -q "linkdown"
 407        log_test $? 0 "IPv4 linkdown flag set"
 408        $IP -6 route get fibmatch 2001:db8:1::2 | \
 409                grep -q "linkdown"
 410        log_test $? 0 "IPv6 linkdown flag set"
 411
 412        set -e
 413        $IP address add 192.0.2.1/24 dev dummy0
 414        $IP -6 address add 2001:db8:2::1/64 dev dummy0
 415        set +e
 416
 417        echo "    Second address added with carrier down"
 418        $IP route get fibmatch 192.0.2.2 &> /dev/null
 419        log_test $? 0 "IPv4 fibmatch"
 420        $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
 421        log_test $? 0 "IPv6 fibmatch"
 422
 423        $IP route get fibmatch 192.0.2.2 | \
 424                grep -q "linkdown"
 425        log_test $? 0 "IPv4 linkdown flag set"
 426        $IP -6 route get fibmatch 2001:db8:2::2 | \
 427                grep -q "linkdown"
 428        log_test $? 0 "IPv6 linkdown flag set"
 429
 430        cleanup
 431}
 432
 433fib_carrier_test()
 434{
 435        fib_carrier_local_test
 436        fib_carrier_unicast_test
 437}
 438
 439fib_rp_filter_test()
 440{
 441        echo
 442        echo "IPv4 rp_filter tests"
 443
 444        setup
 445
 446        set -e
 447        $IP link set dev lo address 52:54:00:6a:c7:5e
 448        $IP link set dummy0 address 52:54:00:6a:c7:5e
 449        $IP link add dummy1 type dummy
 450        $IP link set dummy1 address 52:54:00:6a:c7:5e
 451        $IP link set dev dummy1 up
 452        $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
 453        $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
 454        $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
 455
 456        $NS_EXEC tc qd add dev dummy1 parent root handle 1: fq_codel
 457        $NS_EXEC tc filter add dev dummy1 parent 1: protocol arp basic action mirred egress redirect dev lo
 458        $NS_EXEC tc filter add dev dummy1 parent 1: protocol ip basic action mirred egress redirect dev lo
 459        set +e
 460
 461        run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 198.51.100.1"
 462        log_test $? 0 "rp_filter passes local packets"
 463
 464        run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 127.0.0.1"
 465        log_test $? 0 "rp_filter passes loopback packets"
 466
 467        cleanup
 468}
 469
 470################################################################################
 471# Tests on nexthop spec
 472
 473# run 'ip route add' with given spec
 474add_rt()
 475{
 476        local desc="$1"
 477        local erc=$2
 478        local vrf=$3
 479        local pfx=$4
 480        local gw=$5
 481        local dev=$6
 482        local cmd out rc
 483
 484        [ "$vrf" = "-" ] && vrf="default"
 485        [ -n "$gw" ] && gw="via $gw"
 486        [ -n "$dev" ] && dev="dev $dev"
 487
 488        cmd="$IP route add vrf $vrf $pfx $gw $dev"
 489        if [ "$VERBOSE" = "1" ]; then
 490                printf "\n    COMMAND: $cmd\n"
 491        fi
 492
 493        out=$(eval $cmd 2>&1)
 494        rc=$?
 495        if [ "$VERBOSE" = "1" -a -n "$out" ]; then
 496                echo "    $out"
 497        fi
 498        log_test $rc $erc "$desc"
 499}
 500
 501fib4_nexthop()
 502{
 503        echo
 504        echo "IPv4 nexthop tests"
 505
 506        echo "<<< write me >>>"
 507}
 508
 509fib6_nexthop()
 510{
 511        local lldummy=$(get_linklocal dummy0)
 512        local llv1=$(get_linklocal dummy0)
 513
 514        if [ -z "$lldummy" ]; then
 515                echo "Failed to get linklocal address for dummy0"
 516                return 1
 517        fi
 518        if [ -z "$llv1" ]; then
 519                echo "Failed to get linklocal address for veth1"
 520                return 1
 521        fi
 522
 523        echo
 524        echo "IPv6 nexthop tests"
 525
 526        add_rt "Directly connected nexthop, unicast address" 0 \
 527                - 2001:db8:101::/64 2001:db8:1::2
 528        add_rt "Directly connected nexthop, unicast address with device" 0 \
 529                - 2001:db8:102::/64 2001:db8:1::2 "dummy0"
 530        add_rt "Gateway is linklocal address" 0 \
 531                - 2001:db8:103::1/64 $llv1 "veth0"
 532
 533        # fails because LL address requires a device
 534        add_rt "Gateway is linklocal address, no device" 2 \
 535                - 2001:db8:104::1/64 $llv1
 536
 537        # local address can not be a gateway
 538        add_rt "Gateway can not be local unicast address" 2 \
 539                - 2001:db8:105::/64 2001:db8:1::1
 540        add_rt "Gateway can not be local unicast address, with device" 2 \
 541                - 2001:db8:106::/64 2001:db8:1::1 "dummy0"
 542        add_rt "Gateway can not be a local linklocal address" 2 \
 543                - 2001:db8:107::1/64 $lldummy "dummy0"
 544
 545        # VRF tests
 546        add_rt "Gateway can be local address in a VRF" 0 \
 547                - 2001:db8:108::/64 2001:db8:51::2
 548        add_rt "Gateway can be local address in a VRF, with device" 0 \
 549                - 2001:db8:109::/64 2001:db8:51::2 "veth0"
 550        add_rt "Gateway can be local linklocal address in a VRF" 0 \
 551                - 2001:db8:110::1/64 $llv1 "veth0"
 552
 553        add_rt "Redirect to VRF lookup" 0 \
 554                - 2001:db8:111::/64 "" "red"
 555
 556        add_rt "VRF route, gateway can be local address in default VRF" 0 \
 557                red 2001:db8:112::/64 2001:db8:51::1
 558
 559        # local address in same VRF fails
 560        add_rt "VRF route, gateway can not be a local address" 2 \
 561                red 2001:db8:113::1/64 2001:db8:2::1
 562        add_rt "VRF route, gateway can not be a local addr with device" 2 \
 563                red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
 564}
 565
 566# Default VRF:
 567#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
 568#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
 569#
 570# VRF red:
 571#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
 572#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
 573#
 574#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
 575
 576fib_nexthop_test()
 577{
 578        setup
 579
 580        set -e
 581
 582        $IP -4 rule add pref 32765 table local
 583        $IP -4 rule del pref 0
 584        $IP -6 rule add pref 32765 table local
 585        $IP -6 rule del pref 0
 586
 587        $IP link add red type vrf table 1
 588        $IP link set red up
 589        $IP -4 route add vrf red unreachable default metric 4278198272
 590        $IP -6 route add vrf red unreachable default metric 4278198272
 591
 592        $IP link add veth0 type veth peer name veth1
 593        $IP link set dev veth0 up
 594        $IP address add 192.0.2.1/24 dev veth0
 595        $IP -6 address add 2001:db8:51::1/64 dev veth0
 596
 597        $IP link set dev veth1 vrf red up
 598        $IP address add 192.0.2.2/24 dev veth1
 599        $IP -6 address add 2001:db8:51::2/64 dev veth1
 600
 601        $IP link add dummy1 type dummy
 602        $IP link set dev dummy1 vrf red up
 603        $IP address add 192.168.2.1/24 dev dummy1
 604        $IP -6 address add 2001:db8:2::1/64 dev dummy1
 605        set +e
 606
 607        sleep 1
 608        fib4_nexthop
 609        fib6_nexthop
 610
 611        (
 612        $IP link del dev dummy1
 613        $IP link del veth0
 614        $IP link del red
 615        ) 2>/dev/null
 616        cleanup
 617}
 618
 619fib_suppress_test()
 620{
 621        $IP link add dummy1 type dummy
 622        $IP link set dummy1 up
 623        $IP -6 route add default dev dummy1
 624        $IP -6 rule add table main suppress_prefixlength 0
 625        ping -f -c 1000 -W 1 1234::1 || true
 626        $IP -6 rule del table main suppress_prefixlength 0
 627        $IP link del dummy1
 628
 629        # If we got here without crashing, we're good.
 630        return 0
 631}
 632
 633################################################################################
 634# Tests on route add and replace
 635
 636run_cmd()
 637{
 638        local cmd="$1"
 639        local out
 640        local stderr="2>/dev/null"
 641
 642        if [ "$VERBOSE" = "1" ]; then
 643                printf "    COMMAND: $cmd\n"
 644                stderr=
 645        fi
 646
 647        out=$(eval $cmd $stderr)
 648        rc=$?
 649        if [ "$VERBOSE" = "1" -a -n "$out" ]; then
 650                echo "    $out"
 651        fi
 652
 653        [ "$VERBOSE" = "1" ] && echo
 654
 655        return $rc
 656}
 657
 658check_expected()
 659{
 660        local out="$1"
 661        local expected="$2"
 662        local rc=0
 663
 664        [ "${out}" = "${expected}" ] && return 0
 665
 666        if [ -z "${out}" ]; then
 667                if [ "$VERBOSE" = "1" ]; then
 668                        printf "\nNo route entry found\n"
 669                        printf "Expected:\n"
 670                        printf "    ${expected}\n"
 671                fi
 672                return 1
 673        fi
 674
 675        # tricky way to convert output to 1-line without ip's
 676        # messy '\'; this drops all extra white space
 677        out=$(echo ${out})
 678        if [ "${out}" != "${expected}" ]; then
 679                rc=1
 680                if [ "${VERBOSE}" = "1" ]; then
 681                        printf "    Unexpected route entry. Have:\n"
 682                        printf "        ${out}\n"
 683                        printf "    Expected:\n"
 684                        printf "        ${expected}\n\n"
 685                fi
 686        fi
 687
 688        return $rc
 689}
 690
 691# add route for a prefix, flushing any existing routes first
 692# expected to be the first step of a test
 693add_route6()
 694{
 695        local pfx="$1"
 696        local nh="$2"
 697        local out
 698
 699        if [ "$VERBOSE" = "1" ]; then
 700                echo
 701                echo "    ##################################################"
 702                echo
 703        fi
 704
 705        run_cmd "$IP -6 ro flush ${pfx}"
 706        [ $? -ne 0 ] && exit 1
 707
 708        out=$($IP -6 ro ls match ${pfx})
 709        if [ -n "$out" ]; then
 710                echo "Failed to flush routes for prefix used for tests."
 711                exit 1
 712        fi
 713
 714        run_cmd "$IP -6 ro add ${pfx} ${nh}"
 715        if [ $? -ne 0 ]; then
 716                echo "Failed to add initial route for test."
 717                exit 1
 718        fi
 719}
 720
 721# add initial route - used in replace route tests
 722add_initial_route6()
 723{
 724        add_route6 "2001:db8:104::/64" "$1"
 725}
 726
 727check_route6()
 728{
 729        local pfx
 730        local expected="$1"
 731        local out
 732        local rc=0
 733
 734        set -- $expected
 735        pfx=$1
 736
 737        out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
 738        check_expected "${out}" "${expected}"
 739}
 740
 741route_cleanup()
 742{
 743        $IP li del red 2>/dev/null
 744        $IP li del dummy1 2>/dev/null
 745        $IP li del veth1 2>/dev/null
 746        $IP li del veth3 2>/dev/null
 747
 748        cleanup &> /dev/null
 749}
 750
 751route_setup()
 752{
 753        route_cleanup
 754        setup
 755
 756        [ "${VERBOSE}" = "1" ] && set -x
 757        set -e
 758
 759        ip netns add ns2
 760        ip netns set ns2 auto
 761        ip -netns ns2 link set dev lo up
 762        ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
 763        ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
 764
 765        $IP li add veth1 type veth peer name veth2
 766        $IP li add veth3 type veth peer name veth4
 767
 768        $IP li set veth1 up
 769        $IP li set veth3 up
 770        $IP li set veth2 netns ns2 up
 771        $IP li set veth4 netns ns2 up
 772        ip -netns ns2 li add dummy1 type dummy
 773        ip -netns ns2 li set dummy1 up
 774
 775        $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
 776        $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
 777        $IP addr add 172.16.101.1/24 dev veth1
 778        $IP addr add 172.16.103.1/24 dev veth3
 779
 780        ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
 781        ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
 782        ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
 783
 784        ip -netns ns2 addr add 172.16.101.2/24 dev veth2
 785        ip -netns ns2 addr add 172.16.103.2/24 dev veth4
 786        ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
 787
 788        set +e
 789}
 790
 791# assumption is that basic add of a single path route works
 792# otherwise just adding an address on an interface is broken
 793ipv6_rt_add()
 794{
 795        local rc
 796
 797        echo
 798        echo "IPv6 route add / append tests"
 799
 800        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
 801        add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
 802        run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
 803        log_test $? 2 "Attempt to add duplicate route - gw"
 804
 805        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
 806        add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
 807        run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
 808        log_test $? 2 "Attempt to add duplicate route - dev only"
 809
 810        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
 811        add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
 812        run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
 813        log_test $? 2 "Attempt to add duplicate route - reject route"
 814
 815        # route append with same prefix adds a new route
 816        # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
 817        add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
 818        run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
 819        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"
 820        log_test $? 0 "Append nexthop to existing route - gw"
 821
 822        # insert mpath directly
 823        add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 824        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"
 825        log_test $? 0 "Add multipath route"
 826
 827        add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 828        run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 829        log_test $? 2 "Attempt to add duplicate multipath route"
 830
 831        # insert of a second route without append but different metric
 832        add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
 833        run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
 834        rc=$?
 835        if [ $rc -eq 0 ]; then
 836                run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
 837                rc=$?
 838        fi
 839        log_test $rc 0 "Route add with different metrics"
 840
 841        run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
 842        rc=$?
 843        if [ $rc -eq 0 ]; then
 844                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"
 845                rc=$?
 846        fi
 847        log_test $rc 0 "Route delete with metric"
 848}
 849
 850ipv6_rt_replace_single()
 851{
 852        # single path with single path
 853        #
 854        add_initial_route6 "via 2001:db8:101::2"
 855        run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
 856        check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
 857        log_test $? 0 "Single path with single path"
 858
 859        # single path with multipath
 860        #
 861        add_initial_route6 "nexthop via 2001:db8:101::2"
 862        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
 863        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"
 864        log_test $? 0 "Single path with multipath"
 865
 866        # single path with single path using MULTIPATH attribute
 867        #
 868        add_initial_route6 "via 2001:db8:101::2"
 869        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
 870        check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
 871        log_test $? 0 "Single path with single path via multipath attribute"
 872
 873        # route replace fails - invalid nexthop
 874        add_initial_route6 "via 2001:db8:101::2"
 875        run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
 876        if [ $? -eq 0 ]; then
 877                # previous command is expected to fail so if it returns 0
 878                # that means the test failed.
 879                log_test 0 1 "Invalid nexthop"
 880        else
 881                check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
 882                log_test $? 0 "Invalid nexthop"
 883        fi
 884
 885        # replace non-existent route
 886        # - note use of change versus replace since ip adds NLM_F_CREATE
 887        #   for replace
 888        add_initial_route6 "via 2001:db8:101::2"
 889        run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
 890        log_test $? 2 "Single path - replace of non-existent route"
 891}
 892
 893ipv6_rt_replace_mpath()
 894{
 895        # multipath with multipath
 896        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 897        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
 898        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"
 899        log_test $? 0 "Multipath with multipath"
 900
 901        # multipath with single
 902        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 903        run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
 904        check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
 905        log_test $? 0 "Multipath with single path"
 906
 907        # multipath with single
 908        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 909        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
 910        check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
 911        log_test $? 0 "Multipath with single path via multipath attribute"
 912
 913        # route replace fails - invalid nexthop 1
 914        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 915        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
 916        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"
 917        log_test $? 0 "Multipath - invalid first nexthop"
 918
 919        # route replace fails - invalid nexthop 2
 920        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 921        run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
 922        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"
 923        log_test $? 0 "Multipath - invalid second nexthop"
 924
 925        # multipath non-existent route
 926        add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
 927        run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
 928        log_test $? 2 "Multipath - replace of non-existent route"
 929}
 930
 931ipv6_rt_replace()
 932{
 933        echo
 934        echo "IPv6 route replace tests"
 935
 936        ipv6_rt_replace_single
 937        ipv6_rt_replace_mpath
 938}
 939
 940ipv6_route_test()
 941{
 942        route_setup
 943
 944        ipv6_rt_add
 945        ipv6_rt_replace
 946
 947        route_cleanup
 948}
 949
 950ip_addr_metric_check()
 951{
 952        ip addr help 2>&1 | grep -q metric
 953        if [ $? -ne 0 ]; then
 954                echo "iproute2 command does not support metric for addresses. Skipping test"
 955                return 1
 956        fi
 957
 958        return 0
 959}
 960
 961ipv6_addr_metric_test()
 962{
 963        local rc
 964
 965        echo
 966        echo "IPv6 prefix route tests"
 967
 968        ip_addr_metric_check || return 1
 969
 970        setup
 971
 972        set -e
 973        $IP li add dummy1 type dummy
 974        $IP li add dummy2 type dummy
 975        $IP li set dummy1 up
 976        $IP li set dummy2 up
 977
 978        # default entry is metric 256
 979        run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
 980        run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
 981        set +e
 982
 983        check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
 984        log_test $? 0 "Default metric"
 985
 986        set -e
 987        run_cmd "$IP -6 addr flush dev dummy1"
 988        run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
 989        set +e
 990
 991        check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
 992        log_test $? 0 "User specified metric on first device"
 993
 994        set -e
 995        run_cmd "$IP -6 addr flush dev dummy2"
 996        run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
 997        set +e
 998
 999        check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1000        log_test $? 0 "User specified metric on second device"
1001
1002        run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1003        rc=$?
1004        if [ $rc -eq 0 ]; then
1005                check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1006                rc=$?
1007        fi
1008        log_test $rc 0 "Delete of address on first device"
1009
1010        run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1011        rc=$?
1012        if [ $rc -eq 0 ]; then
1013                check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1014                rc=$?
1015        fi
1016        log_test $rc 0 "Modify metric of address"
1017
1018        # verify prefix route removed on down
1019        run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1020        run_cmd "$IP li set dev dummy2 down"
1021        rc=$?
1022        if [ $rc -eq 0 ]; then
1023                out=$($IP -6 ro ls match 2001:db8:104::/64)
1024                check_expected "${out}" ""
1025                rc=$?
1026        fi
1027        log_test $rc 0 "Prefix route removed on link down"
1028
1029        # verify prefix route re-inserted with assigned metric
1030        run_cmd "$IP li set dev dummy2 up"
1031        rc=$?
1032        if [ $rc -eq 0 ]; then
1033                check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1034                rc=$?
1035        fi
1036        log_test $rc 0 "Prefix route with metric on link up"
1037
1038        $IP li del dummy1
1039        $IP li del dummy2
1040        cleanup
1041}
1042
1043ipv6_route_metrics_test()
1044{
1045        local rc
1046
1047        echo
1048        echo "IPv6 routes with metrics"
1049
1050        route_setup
1051
1052        #
1053        # single path with metrics
1054        #
1055        run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1056        rc=$?
1057        if [ $rc -eq 0 ]; then
1058                check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1059                rc=$?
1060        fi
1061        log_test $rc 0 "Single path route with mtu metric"
1062
1063
1064        #
1065        # multipath via separate routes with metrics
1066        #
1067        run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1068        run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1069        rc=$?
1070        if [ $rc -eq 0 ]; then
1071                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"
1072                rc=$?
1073        fi
1074        log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1075
1076        # second route is coalesced to first to make a multipath route.
1077        # MTU of the second path is hidden from display!
1078        run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1079        run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1080        rc=$?
1081        if [ $rc -eq 0 ]; then
1082                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"
1083                rc=$?
1084        fi
1085        log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1086
1087        run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1088        if [ $? -eq 0 ]; then
1089                check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1090                log_test $? 0 "    MTU of second leg"
1091        fi
1092
1093        #
1094        # multipath with metrics
1095        #
1096        run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1097        rc=$?
1098        if [ $rc -eq 0 ]; then
1099                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"
1100                rc=$?
1101        fi
1102        log_test $rc 0 "Multipath route with mtu metric"
1103
1104        $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1105        run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1106        log_test $? 0 "Using route with mtu metric"
1107
1108        run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1109        log_test $? 2 "Invalid metric (fails metric_convert)"
1110
1111        route_cleanup
1112}
1113
1114# add route for a prefix, flushing any existing routes first
1115# expected to be the first step of a test
1116add_route()
1117{
1118        local pfx="$1"
1119        local nh="$2"
1120        local out
1121
1122        if [ "$VERBOSE" = "1" ]; then
1123                echo
1124                echo "    ##################################################"
1125                echo
1126        fi
1127
1128        run_cmd "$IP ro flush ${pfx}"
1129        [ $? -ne 0 ] && exit 1
1130
1131        out=$($IP ro ls match ${pfx})
1132        if [ -n "$out" ]; then
1133                echo "Failed to flush routes for prefix used for tests."
1134                exit 1
1135        fi
1136
1137        run_cmd "$IP ro add ${pfx} ${nh}"
1138        if [ $? -ne 0 ]; then
1139                echo "Failed to add initial route for test."
1140                exit 1
1141        fi
1142}
1143
1144# add initial route - used in replace route tests
1145add_initial_route()
1146{
1147        add_route "172.16.104.0/24" "$1"
1148}
1149
1150check_route()
1151{
1152        local pfx
1153        local expected="$1"
1154        local out
1155
1156        set -- $expected
1157        pfx=$1
1158        [ "${pfx}" = "unreachable" ] && pfx=$2
1159
1160        out=$($IP ro ls match ${pfx})
1161        check_expected "${out}" "${expected}"
1162}
1163
1164# assumption is that basic add of a single path route works
1165# otherwise just adding an address on an interface is broken
1166ipv4_rt_add()
1167{
1168        local rc
1169
1170        echo
1171        echo "IPv4 route add / append tests"
1172
1173        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1174        add_route "172.16.104.0/24" "via 172.16.101.2"
1175        run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1176        log_test $? 2 "Attempt to add duplicate route - gw"
1177
1178        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1179        add_route "172.16.104.0/24" "via 172.16.101.2"
1180        run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1181        log_test $? 2 "Attempt to add duplicate route - dev only"
1182
1183        # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1184        add_route "172.16.104.0/24" "via 172.16.101.2"
1185        run_cmd "$IP ro add unreachable 172.16.104.0/24"
1186        log_test $? 2 "Attempt to add duplicate route - reject route"
1187
1188        # iproute2 prepend only sets NLM_F_CREATE
1189        # - adds a new route; does NOT convert existing route to ECMP
1190        add_route "172.16.104.0/24" "via 172.16.101.2"
1191        run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1192        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"
1193        log_test $? 0 "Add new nexthop for existing prefix"
1194
1195        # route append with same prefix adds a new route
1196        # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1197        add_route "172.16.104.0/24" "via 172.16.101.2"
1198        run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1199        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"
1200        log_test $? 0 "Append nexthop to existing route - gw"
1201
1202        add_route "172.16.104.0/24" "via 172.16.101.2"
1203        run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1204        check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1205        log_test $? 0 "Append nexthop to existing route - dev only"
1206
1207        add_route "172.16.104.0/24" "via 172.16.101.2"
1208        run_cmd "$IP ro append unreachable 172.16.104.0/24"
1209        check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1210        log_test $? 0 "Append nexthop to existing route - reject route"
1211
1212        run_cmd "$IP ro flush 172.16.104.0/24"
1213        run_cmd "$IP ro add unreachable 172.16.104.0/24"
1214        run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1215        check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1216        log_test $? 0 "Append nexthop to existing reject route - gw"
1217
1218        run_cmd "$IP ro flush 172.16.104.0/24"
1219        run_cmd "$IP ro add unreachable 172.16.104.0/24"
1220        run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1221        check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1222        log_test $? 0 "Append nexthop to existing reject route - dev only"
1223
1224        # insert mpath directly
1225        add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1226        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"
1227        log_test $? 0 "add multipath route"
1228
1229        add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1230        run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1231        log_test $? 2 "Attempt to add duplicate multipath route"
1232
1233        # insert of a second route without append but different metric
1234        add_route "172.16.104.0/24" "via 172.16.101.2"
1235        run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1236        rc=$?
1237        if [ $rc -eq 0 ]; then
1238                run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1239                rc=$?
1240        fi
1241        log_test $rc 0 "Route add with different metrics"
1242
1243        run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1244        rc=$?
1245        if [ $rc -eq 0 ]; then
1246                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"
1247                rc=$?
1248        fi
1249        log_test $rc 0 "Route delete with metric"
1250}
1251
1252ipv4_rt_replace_single()
1253{
1254        # single path with single path
1255        #
1256        add_initial_route "via 172.16.101.2"
1257        run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1258        check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1259        log_test $? 0 "Single path with single path"
1260
1261        # single path with multipath
1262        #
1263        add_initial_route "nexthop via 172.16.101.2"
1264        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1265        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"
1266        log_test $? 0 "Single path with multipath"
1267
1268        # single path with reject
1269        #
1270        add_initial_route "nexthop via 172.16.101.2"
1271        run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1272        check_route "unreachable 172.16.104.0/24"
1273        log_test $? 0 "Single path with reject route"
1274
1275        # single path with single path using MULTIPATH attribute
1276        #
1277        add_initial_route "via 172.16.101.2"
1278        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1279        check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1280        log_test $? 0 "Single path with single path via multipath attribute"
1281
1282        # route replace fails - invalid nexthop
1283        add_initial_route "via 172.16.101.2"
1284        run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1285        if [ $? -eq 0 ]; then
1286                # previous command is expected to fail so if it returns 0
1287                # that means the test failed.
1288                log_test 0 1 "Invalid nexthop"
1289        else
1290                check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1291                log_test $? 0 "Invalid nexthop"
1292        fi
1293
1294        # replace non-existent route
1295        # - note use of change versus replace since ip adds NLM_F_CREATE
1296        #   for replace
1297        add_initial_route "via 172.16.101.2"
1298        run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1299        log_test $? 2 "Single path - replace of non-existent route"
1300}
1301
1302ipv4_rt_replace_mpath()
1303{
1304        # multipath with multipath
1305        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1306        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1307        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"
1308        log_test $? 0 "Multipath with multipath"
1309
1310        # multipath with single
1311        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1312        run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1313        check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1314        log_test $? 0 "Multipath with single path"
1315
1316        # multipath with single
1317        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1318        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1319        check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1320        log_test $? 0 "Multipath with single path via multipath attribute"
1321
1322        # multipath with reject
1323        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1324        run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1325        check_route "unreachable 172.16.104.0/24"
1326        log_test $? 0 "Multipath with reject route"
1327
1328        # route replace fails - invalid nexthop 1
1329        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1330        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1331        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"
1332        log_test $? 0 "Multipath - invalid first nexthop"
1333
1334        # route replace fails - invalid nexthop 2
1335        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1336        run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1337        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"
1338        log_test $? 0 "Multipath - invalid second nexthop"
1339
1340        # multipath non-existent route
1341        add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1342        run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1343        log_test $? 2 "Multipath - replace of non-existent route"
1344}
1345
1346ipv4_rt_replace()
1347{
1348        echo
1349        echo "IPv4 route replace tests"
1350
1351        ipv4_rt_replace_single
1352        ipv4_rt_replace_mpath
1353}
1354
1355ipv4_route_test()
1356{
1357        route_setup
1358
1359        ipv4_rt_add
1360        ipv4_rt_replace
1361
1362        route_cleanup
1363}
1364
1365ipv4_addr_metric_test()
1366{
1367        local rc
1368
1369        echo
1370        echo "IPv4 prefix route tests"
1371
1372        ip_addr_metric_check || return 1
1373
1374        setup
1375
1376        set -e
1377        $IP li add dummy1 type dummy
1378        $IP li add dummy2 type dummy
1379        $IP li set dummy1 up
1380        $IP li set dummy2 up
1381
1382        # default entry is metric 256
1383        run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1384        run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1385        set +e
1386
1387        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"
1388        log_test $? 0 "Default metric"
1389
1390        set -e
1391        run_cmd "$IP addr flush dev dummy1"
1392        run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1393        set +e
1394
1395        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"
1396        log_test $? 0 "User specified metric on first device"
1397
1398        set -e
1399        run_cmd "$IP addr flush dev dummy2"
1400        run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1401        set +e
1402
1403        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"
1404        log_test $? 0 "User specified metric on second device"
1405
1406        run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1407        rc=$?
1408        if [ $rc -eq 0 ]; then
1409                check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1410                rc=$?
1411        fi
1412        log_test $rc 0 "Delete of address on first device"
1413
1414        run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1415        rc=$?
1416        if [ $rc -eq 0 ]; then
1417                check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1418                rc=$?
1419        fi
1420        log_test $rc 0 "Modify metric of address"
1421
1422        # verify prefix route removed on down
1423        run_cmd "$IP li set dev dummy2 down"
1424        rc=$?
1425        if [ $rc -eq 0 ]; then
1426                out=$($IP ro ls match 172.16.104.0/24)
1427                check_expected "${out}" ""
1428                rc=$?
1429        fi
1430        log_test $rc 0 "Prefix route removed on link down"
1431
1432        # verify prefix route re-inserted with assigned metric
1433        run_cmd "$IP li set dev dummy2 up"
1434        rc=$?
1435        if [ $rc -eq 0 ]; then
1436                check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1437                rc=$?
1438        fi
1439        log_test $rc 0 "Prefix route with metric on link up"
1440
1441        # explicitly check for metric changes on edge scenarios
1442        run_cmd "$IP addr flush dev dummy2"
1443        run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1444        run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1445        rc=$?
1446        if [ $rc -eq 0 ]; then
1447                check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1448                rc=$?
1449        fi
1450        log_test $rc 0 "Modify metric of .0/24 address"
1451
1452        run_cmd "$IP addr flush dev dummy2"
1453        run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1454        run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 261"
1455        rc=$?
1456        if [ $rc -eq 0 ]; then
1457                check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1458                rc=$?
1459        fi
1460        log_test $rc 0 "Modify metric of address with peer route"
1461
1462        $IP li del dummy1
1463        $IP li del dummy2
1464        cleanup
1465}
1466
1467ipv4_route_metrics_test()
1468{
1469        local rc
1470
1471        echo
1472        echo "IPv4 route add / append tests"
1473
1474        route_setup
1475
1476        run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1477        rc=$?
1478        if [ $rc -eq 0 ]; then
1479                check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1480                rc=$?
1481        fi
1482        log_test $rc 0 "Single path route with mtu metric"
1483
1484
1485        run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1486        rc=$?
1487        if [ $rc -eq 0 ]; then
1488                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"
1489                rc=$?
1490        fi
1491        log_test $rc 0 "Multipath route with mtu metric"
1492
1493        $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1494        run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1495        log_test $? 0 "Using route with mtu metric"
1496
1497        run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1498        log_test $? 2 "Invalid metric (fails metric_convert)"
1499
1500        route_cleanup
1501}
1502
1503ipv4_del_addr_test()
1504{
1505        echo
1506        echo "IPv4 delete address route tests"
1507
1508        setup
1509
1510        set -e
1511        $IP li add dummy1 type dummy
1512        $IP li set dummy1 up
1513        $IP li add dummy2 type dummy
1514        $IP li set dummy2 up
1515        $IP li add red type vrf table 1111
1516        $IP li set red up
1517        $IP ro add vrf red unreachable default
1518        $IP li set dummy2 vrf red
1519
1520        $IP addr add dev dummy1 172.16.104.1/24
1521        $IP addr add dev dummy1 172.16.104.11/24
1522        $IP addr add dev dummy2 172.16.104.1/24
1523        $IP addr add dev dummy2 172.16.104.11/24
1524        $IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1525        $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1526        set +e
1527
1528        # removing address from device in vrf should only remove route from vrf table
1529        $IP addr del dev dummy2 172.16.104.11/24
1530        $IP ro ls vrf red | grep -q 172.16.105.0/24
1531        log_test $? 1 "Route removed from VRF when source address deleted"
1532
1533        $IP ro ls | grep -q 172.16.105.0/24
1534        log_test $? 0 "Route in default VRF not removed"
1535
1536        $IP addr add dev dummy2 172.16.104.11/24
1537        $IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1538
1539        $IP addr del dev dummy1 172.16.104.11/24
1540        $IP ro ls | grep -q 172.16.105.0/24
1541        log_test $? 1 "Route removed in default VRF when source address deleted"
1542
1543        $IP ro ls vrf red | grep -q 172.16.105.0/24
1544        log_test $? 0 "Route in VRF is not removed by address delete"
1545
1546        $IP li del dummy1
1547        $IP li del dummy2
1548        cleanup
1549}
1550
1551
1552ipv4_route_v6_gw_test()
1553{
1554        local rc
1555
1556        echo
1557        echo "IPv4 route with IPv6 gateway tests"
1558
1559        route_setup
1560        sleep 2
1561
1562        #
1563        # single path route
1564        #
1565        run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1566        rc=$?
1567        log_test $rc 0 "Single path route with IPv6 gateway"
1568        if [ $rc -eq 0 ]; then
1569                check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1570        fi
1571
1572        run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1573        log_test $rc 0 "Single path route with IPv6 gateway - ping"
1574
1575        run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1576        rc=$?
1577        log_test $rc 0 "Single path route delete"
1578        if [ $rc -eq 0 ]; then
1579                check_route "172.16.112.0/24"
1580        fi
1581
1582        #
1583        # multipath - v6 then v4
1584        #
1585        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"
1586        rc=$?
1587        log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1588        if [ $rc -eq 0 ]; then
1589                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"
1590        fi
1591
1592        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"
1593        log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1594
1595        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"
1596        log_test $? 0 "    Multipath route delete exact match"
1597
1598        #
1599        # multipath - v4 then v6
1600        #
1601        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"
1602        rc=$?
1603        log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1604        if [ $rc -eq 0 ]; then
1605                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"
1606        fi
1607
1608        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"
1609        log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1610
1611        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"
1612        log_test $? 0 "    Multipath route delete exact match"
1613
1614        route_cleanup
1615}
1616
1617################################################################################
1618# usage
1619
1620usage()
1621{
1622        cat <<EOF
1623usage: ${0##*/} OPTS
1624
1625        -t <test>   Test(s) to run (default: all)
1626                    (options: $TESTS)
1627        -p          Pause on fail
1628        -P          Pause after each test before cleanup
1629        -v          verbose mode (show commands and output)
1630EOF
1631}
1632
1633################################################################################
1634# main
1635
1636while getopts :t:pPhv o
1637do
1638        case $o in
1639                t) TESTS=$OPTARG;;
1640                p) PAUSE_ON_FAIL=yes;;
1641                P) PAUSE=yes;;
1642                v) VERBOSE=$(($VERBOSE + 1));;
1643                h) usage; exit 0;;
1644                *) usage; exit 1;;
1645        esac
1646done
1647
1648PEER_CMD="ip netns exec ${PEER_NS}"
1649
1650# make sure we don't pause twice
1651[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1652
1653if [ "$(id -u)" -ne 0 ];then
1654        echo "SKIP: Need root privileges"
1655        exit $ksft_skip;
1656fi
1657
1658if [ ! -x "$(command -v ip)" ]; then
1659        echo "SKIP: Could not run test without ip tool"
1660        exit $ksft_skip
1661fi
1662
1663ip route help 2>&1 | grep -q fibmatch
1664if [ $? -ne 0 ]; then
1665        echo "SKIP: iproute2 too old, missing fibmatch"
1666        exit $ksft_skip
1667fi
1668
1669# start clean
1670cleanup &> /dev/null
1671
1672for t in $TESTS
1673do
1674        case $t in
1675        fib_unreg_test|unregister)      fib_unreg_test;;
1676        fib_down_test|down)             fib_down_test;;
1677        fib_carrier_test|carrier)       fib_carrier_test;;
1678        fib_rp_filter_test|rp_filter)   fib_rp_filter_test;;
1679        fib_nexthop_test|nexthop)       fib_nexthop_test;;
1680        fib_suppress_test|suppress)     fib_suppress_test;;
1681        ipv6_route_test|ipv6_rt)        ipv6_route_test;;
1682        ipv4_route_test|ipv4_rt)        ipv4_route_test;;
1683        ipv6_addr_metric)               ipv6_addr_metric_test;;
1684        ipv4_addr_metric)               ipv4_addr_metric_test;;
1685        ipv4_del_addr)                  ipv4_del_addr_test;;
1686        ipv6_route_metrics)             ipv6_route_metrics_test;;
1687        ipv4_route_metrics)             ipv4_route_metrics_test;;
1688        ipv4_route_v6_gw)               ipv4_route_v6_gw_test;;
1689
1690        help) echo "Test names: $TESTS"; exit 0;;
1691        esac
1692done
1693
1694if [ "$TESTS" != "none" ]; then
1695        printf "\nTests passed: %3d\n" ${nsuccess}
1696        printf "Tests failed: %3d\n"   ${nfail}
1697fi
1698
1699exit $ret
1700