Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # redirect test
0005 #
0006 #                     .253 +----+
0007 #                     +----| r1 |
0008 #                     |    +----+
0009 # +----+              |       |.1
0010 # | h1 |--------------+       |   10.1.1.0/30 2001:db8:1::0/126
0011 # +----+ .1           |       |.2
0012 #         172.16.1/24 |    +----+                   +----+
0013 #    2001:db8:16:1/64 +----| r2 |-------------------| h2 |
0014 #                     .254 +----+ .254           .2 +----+
0015 #                                    172.16.2/24
0016 #                                  2001:db8:16:2/64
0017 #
0018 # Route from h1 to h2 goes through r1, eth1 - connection between r1 and r2.
0019 # Route on r1 changed to go to r2 via eth0. This causes a redirect to be sent
0020 # from r1 to h1 telling h1 to use r2 when talking to h2.
0021 
0022 VERBOSE=0
0023 PAUSE_ON_FAIL=no
0024 
0025 H1_N1_IP=172.16.1.1
0026 R1_N1_IP=172.16.1.253
0027 R2_N1_IP=172.16.1.254
0028 
0029 H1_N1_IP6=2001:db8:16:1::1
0030 R1_N1_IP6=2001:db8:16:1::253
0031 R2_N1_IP6=2001:db8:16:1::254
0032 
0033 R1_R2_N1_IP=10.1.1.1
0034 R2_R1_N1_IP=10.1.1.2
0035 
0036 R1_R2_N1_IP6=2001:db8:1::1
0037 R2_R1_N1_IP6=2001:db8:1::2
0038 
0039 H2_N2=172.16.2.0/24
0040 H2_N2_6=2001:db8:16:2::/64
0041 H2_N2_IP=172.16.2.2
0042 R2_N2_IP=172.16.2.254
0043 H2_N2_IP6=2001:db8:16:2::2
0044 R2_N2_IP6=2001:db8:16:2::254
0045 
0046 VRF=red
0047 VRF_TABLE=1111
0048 
0049 ################################################################################
0050 # helpers
0051 
0052 log_section()
0053 {
0054         echo
0055         echo "###########################################################################"
0056         echo "$*"
0057         echo "###########################################################################"
0058         echo
0059 }
0060 
0061 log_test()
0062 {
0063         local rc=$1
0064         local expected=$2
0065         local msg="$3"
0066         local xfail=$4
0067 
0068         if [ ${rc} -eq ${expected} ]; then
0069                 printf "TEST: %-60s  [ OK ]\n" "${msg}"
0070                 nsuccess=$((nsuccess+1))
0071         elif [ ${rc} -eq ${xfail} ]; then
0072                 printf "TEST: %-60s  [XFAIL]\n" "${msg}"
0073                 nxfail=$((nxfail+1))
0074         else
0075                 ret=1
0076                 nfail=$((nfail+1))
0077                 printf "TEST: %-60s  [FAIL]\n" "${msg}"
0078                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
0079                         echo
0080                         echo "hit enter to continue, 'q' to quit"
0081                         read a
0082                         [ "$a" = "q" ] && exit 1
0083                 fi
0084         fi
0085 }
0086 
0087 log_debug()
0088 {
0089         if [ "$VERBOSE" = "1" ]; then
0090                 echo "$*"
0091         fi
0092 }
0093 
0094 run_cmd()
0095 {
0096         local cmd="$*"
0097         local out
0098         local rc
0099 
0100         if [ "$VERBOSE" = "1" ]; then
0101                 echo "COMMAND: $cmd"
0102         fi
0103 
0104         out=$(eval $cmd 2>&1)
0105         rc=$?
0106         if [ "$VERBOSE" = "1" -a -n "$out" ]; then
0107                 echo "$out"
0108         fi
0109 
0110         [ "$VERBOSE" = "1" ] && echo
0111 
0112         return $rc
0113 }
0114 
0115 get_linklocal()
0116 {
0117         local ns=$1
0118         local dev=$2
0119         local addr
0120 
0121         addr=$(ip -netns $ns -6 -br addr show dev ${dev} | \
0122         awk '{
0123                 for (i = 3; i <= NF; ++i) {
0124                         if ($i ~ /^fe80/)
0125                                 print $i
0126                 }
0127         }'
0128         )
0129         addr=${addr/\/*}
0130 
0131         [ -z "$addr" ] && return 1
0132 
0133         echo $addr
0134 
0135         return 0
0136 }
0137 
0138 ################################################################################
0139 # setup and teardown
0140 
0141 cleanup()
0142 {
0143         local ns
0144 
0145         for ns in h1 h2 r1 r2; do
0146                 ip netns del $ns 2>/dev/null
0147         done
0148 }
0149 
0150 create_vrf()
0151 {
0152         local ns=$1
0153 
0154         ip -netns ${ns} link add ${VRF} type vrf table ${VRF_TABLE}
0155         ip -netns ${ns} link set ${VRF} up
0156         ip -netns ${ns} route add vrf ${VRF} unreachable default metric 8192
0157         ip -netns ${ns} -6 route add vrf ${VRF} unreachable default metric 8192
0158 
0159         ip -netns ${ns} addr add 127.0.0.1/8 dev ${VRF}
0160         ip -netns ${ns} -6 addr add ::1 dev ${VRF} nodad
0161 
0162         ip -netns ${ns} ru del pref 0
0163         ip -netns ${ns} ru add pref 32765 from all lookup local
0164         ip -netns ${ns} -6 ru del pref 0
0165         ip -netns ${ns} -6 ru add pref 32765 from all lookup local
0166 }
0167 
0168 setup()
0169 {
0170         local ns
0171 
0172         #
0173         # create nodes as namespaces
0174         #
0175         for ns in h1 h2 r1 r2; do
0176                 ip netns add $ns
0177                 ip -netns $ns li set lo up
0178 
0179                 case "${ns}" in
0180                 h[12]) ip netns exec $ns sysctl -q -w net.ipv4.conf.all.accept_redirects=1
0181                        ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
0182                        ip netns exec $ns sysctl -q -w net.ipv6.conf.all.accept_redirects=1
0183                        ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
0184                         ;;
0185                 r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
0186                        ip netns exec $ns sysctl -q -w net.ipv4.conf.all.send_redirects=1
0187                        ip netns exec $ns sysctl -q -w net.ipv4.conf.default.rp_filter=0
0188                        ip netns exec $ns sysctl -q -w net.ipv4.conf.all.rp_filter=0
0189 
0190                        ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
0191                        ip netns exec $ns sysctl -q -w net.ipv6.route.mtu_expires=10
0192                 esac
0193         done
0194 
0195         #
0196         # create interconnects
0197         #
0198         ip -netns h1 li add eth0 type veth peer name r1h1
0199         ip -netns h1 li set r1h1 netns r1 name eth0 up
0200 
0201         ip -netns h1 li add eth1 type veth peer name r2h1
0202         ip -netns h1 li set r2h1 netns r2 name eth0 up
0203 
0204         ip -netns h2 li add eth0 type veth peer name r2h2
0205         ip -netns h2 li set eth0 up
0206         ip -netns h2 li set r2h2 netns r2 name eth2 up
0207 
0208         ip -netns r1 li add eth1 type veth peer name r2r1
0209         ip -netns r1 li set eth1 up
0210         ip -netns r1 li set r2r1 netns r2 name eth1 up
0211 
0212         #
0213         # h1
0214         #
0215         if [ "${WITH_VRF}" = "yes" ]; then
0216                 create_vrf "h1"
0217                 H1_VRF_ARG="vrf ${VRF}"
0218                 H1_PING_ARG="-I ${VRF}"
0219         else
0220                 H1_VRF_ARG=
0221                 H1_PING_ARG=
0222         fi
0223         ip -netns h1 li add br0 type bridge
0224         if [ "${WITH_VRF}" = "yes" ]; then
0225                 ip -netns h1 li set br0 vrf ${VRF} up
0226         else
0227                 ip -netns h1 li set br0 up
0228         fi
0229         ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
0230         ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
0231         ip -netns h1 li set eth0 master br0 up
0232         ip -netns h1 li set eth1 master br0 up
0233 
0234         #
0235         # h2
0236         #
0237         ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
0238         ip -netns h2 ro add default via ${R2_N2_IP} dev eth0
0239         ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
0240         ip -netns h2 -6 ro add default via ${R2_N2_IP6} dev eth0
0241 
0242         #
0243         # r1
0244         #
0245         ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
0246         ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
0247         ip -netns r1 addr add dev eth1 ${R1_R2_N1_IP}/30
0248         ip -netns r1 -6 addr add dev eth1 ${R1_R2_N1_IP6}/126 nodad
0249 
0250         #
0251         # r2
0252         #
0253         ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
0254         ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
0255         ip -netns r2 addr add dev eth1 ${R2_R1_N1_IP}/30
0256         ip -netns r2 -6 addr add dev eth1 ${R2_R1_N1_IP6}/126 nodad
0257         ip -netns r2 addr add dev eth2 ${R2_N2_IP}/24
0258         ip -netns r2 -6 addr add dev eth2 ${R2_N2_IP6}/64 nodad
0259 
0260         sleep 2
0261 
0262         R1_LLADDR=$(get_linklocal r1 eth0)
0263         if [ $? -ne 0 ]; then
0264                 echo "Error: Failed to get link-local address of r1's eth0"
0265                 exit 1
0266         fi
0267         log_debug "initial gateway is R1's lladdr = ${R1_LLADDR}"
0268 
0269         R2_LLADDR=$(get_linklocal r2 eth0)
0270         if [ $? -ne 0 ]; then
0271                 echo "Error: Failed to get link-local address of r2's eth0"
0272                 exit 1
0273         fi
0274         log_debug "initial gateway is R2's lladdr = ${R2_LLADDR}"
0275 }
0276 
0277 change_h2_mtu()
0278 {
0279         local mtu=$1
0280 
0281         run_cmd ip -netns h2 li set eth0 mtu ${mtu}
0282         run_cmd ip -netns r2 li set eth2 mtu ${mtu}
0283 }
0284 
0285 check_exception()
0286 {
0287         local mtu="$1"
0288         local with_redirect="$2"
0289         local desc="$3"
0290 
0291         # From 172.16.1.101: icmp_seq=1 Redirect Host(New nexthop: 172.16.1.102)
0292         if [ "$VERBOSE" = "1" ]; then
0293                 echo "Commands to check for exception:"
0294                 run_cmd ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP}
0295                 run_cmd ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6}
0296         fi
0297 
0298         if [ -n "${mtu}" ]; then
0299                 mtu=" mtu ${mtu}"
0300         fi
0301         if [ "$with_redirect" = "yes" ]; then
0302                 ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
0303                 grep -q "cache <redirected> expires [0-9]*sec${mtu}"
0304         elif [ -n "${mtu}" ]; then
0305                 ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
0306                 grep -q "cache expires [0-9]*sec${mtu}"
0307         else
0308                 # want to verify that neither mtu nor redirected appears in
0309                 # the route get output. The -v will wipe out the cache line
0310                 # if either are set so the last grep -q will not find a match
0311                 ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
0312                 grep -E -v 'mtu|redirected' | grep -q "cache"
0313         fi
0314         log_test $? 0 "IPv4: ${desc}" 0
0315 
0316         # No PMTU info for test "redirect" and "mtu exception plus redirect"
0317         if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then
0318                 ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
0319                 grep -v "mtu" | grep -q "${H2_N2_IP6} .*via ${R2_LLADDR} dev br0"
0320         elif [ -n "${mtu}" ]; then
0321                 ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
0322                 grep -q "${mtu}"
0323         else
0324                 # IPv6 is a bit harder. First strip out the match if it
0325                 # contains an mtu exception and then look for the first
0326                 # gateway - R1's lladdr
0327                 ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
0328                 grep -v "mtu" | grep -q "${R1_LLADDR}"
0329         fi
0330         log_test $? 0 "IPv6: ${desc}" 1
0331 }
0332 
0333 run_ping()
0334 {
0335         local sz=$1
0336 
0337         run_cmd ip netns exec h1 ping -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP}
0338         run_cmd ip netns exec h1 ${ping6} -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP6}
0339 }
0340 
0341 replace_route_new()
0342 {
0343         # r1 to h2 via r2 and eth0
0344         run_cmd ip -netns r1 nexthop replace id 1 via ${R2_N1_IP} dev eth0
0345         run_cmd ip -netns r1 nexthop replace id 2 via ${R2_LLADDR} dev eth0
0346 }
0347 
0348 reset_route_new()
0349 {
0350         run_cmd ip -netns r1 nexthop flush
0351         run_cmd ip -netns h1 nexthop flush
0352 
0353         initial_route_new
0354 }
0355 
0356 initial_route_new()
0357 {
0358         # r1 to h2 via r2 and eth1
0359         run_cmd ip -netns r1 nexthop add id 1 via ${R2_R1_N1_IP} dev eth1
0360         run_cmd ip -netns r1 ro add ${H2_N2} nhid 1
0361 
0362         run_cmd ip -netns r1 nexthop add id 2 via ${R2_R1_N1_IP6} dev eth1
0363         run_cmd ip -netns r1 -6 ro add ${H2_N2_6} nhid 2
0364 
0365         # h1 to h2 via r1
0366         run_cmd ip -netns h1 nexthop add id 1 via ${R1_N1_IP} dev br0
0367         run_cmd ip -netns h1 ro add ${H1_VRF_ARG} ${H2_N2} nhid 1
0368 
0369         run_cmd ip -netns h1 nexthop add id 2 via ${R1_LLADDR} dev br0
0370         run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} nhid 2
0371 }
0372 
0373 replace_route_legacy()
0374 {
0375         # r1 to h2 via r2 and eth0
0376         run_cmd ip -netns r1    ro replace ${H2_N2}   via ${R2_N1_IP}  dev eth0
0377         run_cmd ip -netns r1 -6 ro replace ${H2_N2_6} via ${R2_LLADDR} dev eth0
0378 }
0379 
0380 reset_route_legacy()
0381 {
0382         run_cmd ip -netns r1    ro del ${H2_N2}
0383         run_cmd ip -netns r1 -6 ro del ${H2_N2_6}
0384 
0385         run_cmd ip -netns h1    ro del ${H1_VRF_ARG} ${H2_N2}
0386         run_cmd ip -netns h1 -6 ro del ${H1_VRF_ARG} ${H2_N2_6}
0387 
0388         initial_route_legacy
0389 }
0390 
0391 initial_route_legacy()
0392 {
0393         # r1 to h2 via r2 and eth1
0394         run_cmd ip -netns r1    ro add ${H2_N2}   via ${R2_R1_N1_IP}  dev eth1
0395         run_cmd ip -netns r1 -6 ro add ${H2_N2_6} via ${R2_R1_N1_IP6} dev eth1
0396 
0397         # h1 to h2 via r1
0398         # - IPv6 redirect only works if gateway is the LLA
0399         run_cmd ip -netns h1    ro add ${H1_VRF_ARG} ${H2_N2} via ${R1_N1_IP} dev br0
0400         run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} via ${R1_LLADDR} dev br0
0401 }
0402 
0403 check_connectivity()
0404 {
0405         local rc
0406 
0407         run_cmd ip netns exec h1 ping -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP}
0408         rc=$?
0409         run_cmd ip netns exec h1 ${ping6} -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP6}
0410         [ $? -ne 0 ] && rc=$?
0411 
0412         return $rc
0413 }
0414 
0415 do_test()
0416 {
0417         local ttype="$1"
0418 
0419         eval initial_route_${ttype}
0420 
0421         # verify connectivity
0422         check_connectivity
0423         if [ $? -ne 0 ]; then
0424                 echo "Error: Basic connectivity is broken"
0425                 ret=1
0426                 return
0427         fi
0428 
0429         # redirect exception followed by mtu
0430         eval replace_route_${ttype}
0431         run_ping 64
0432         check_exception "" "yes" "redirect exception"
0433 
0434         check_connectivity
0435         if [ $? -ne 0 ]; then
0436                 echo "Error: Basic connectivity is broken after redirect"
0437                 ret=1
0438                 return
0439         fi
0440 
0441         change_h2_mtu 1300
0442         run_ping 1350
0443         check_exception "1300" "yes" "redirect exception plus mtu"
0444 
0445         # remove exceptions and restore routing
0446         change_h2_mtu 1500
0447         eval reset_route_${ttype}
0448 
0449         check_connectivity
0450         if [ $? -ne 0 ]; then
0451                 echo "Error: Basic connectivity is broken after reset"
0452                 ret=1
0453                 return
0454         fi
0455         check_exception "" "no" "routing reset"
0456 
0457         # MTU exception followed by redirect
0458         change_h2_mtu 1300
0459         run_ping 1350
0460         check_exception "1300" "no" "mtu exception"
0461 
0462         eval replace_route_${ttype}
0463         run_ping 64
0464         check_exception "1300" "yes" "mtu exception plus redirect"
0465 
0466         check_connectivity
0467         if [ $? -ne 0 ]; then
0468                 echo "Error: Basic connectivity is broken after redirect"
0469                 ret=1
0470                 return
0471         fi
0472 }
0473 
0474 ################################################################################
0475 # usage
0476 
0477 usage()
0478 {
0479         cat <<EOF
0480 usage: ${0##*/} OPTS
0481 
0482         -p          Pause on fail
0483         -v          verbose mode (show commands and output)
0484 EOF
0485 }
0486 
0487 ################################################################################
0488 # main
0489 
0490 # Some systems don't have a ping6 binary anymore
0491 which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
0492 
0493 ret=0
0494 nsuccess=0
0495 nfail=0
0496 nxfail=0
0497 
0498 while getopts :pv o
0499 do
0500         case $o in
0501                 p) PAUSE_ON_FAIL=yes;;
0502                 v) VERBOSE=$(($VERBOSE + 1));;
0503                 *) usage; exit 1;;
0504         esac
0505 done
0506 
0507 trap cleanup EXIT
0508 
0509 cleanup
0510 WITH_VRF=no
0511 setup
0512 
0513 log_section "Legacy routing"
0514 do_test "legacy"
0515 
0516 cleanup
0517 log_section "Legacy routing with VRF"
0518 WITH_VRF=yes
0519 setup
0520 do_test "legacy"
0521 
0522 cleanup
0523 log_section "Routing with nexthop objects"
0524 ip nexthop ls >/dev/null 2>&1
0525 if [ $? -eq 0 ]; then
0526         WITH_VRF=no
0527         setup
0528         do_test "new"
0529 
0530         cleanup
0531         log_section "Routing with nexthop objects and VRF"
0532         WITH_VRF=yes
0533         setup
0534         do_test "new"
0535 else
0536         echo "Nexthop objects not supported; skipping tests"
0537 fi
0538 
0539 printf "\nTests passed: %3d\n" ${nsuccess}
0540 printf "Tests failed: %3d\n"   ${nfail}
0541 printf "Tests xfailed: %3d\n"  ${nxfail}
0542 
0543 exit $ret