0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
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
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
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
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
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
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
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
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
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
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
0309
0310
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
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
0325
0326
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
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
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
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
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
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
0398
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
0422 check_connectivity
0423 if [ $? -ne 0 ]; then
0424 echo "Error: Basic connectivity is broken"
0425 ret=1
0426 return
0427 fi
0428
0429
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
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
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
0476
0477 usage()
0478 {
0479 cat <<EOF
0480 usage: ${0
0481
0482 -p Pause on fail
0483 -v verbose mode (show commands and output)
0484 EOF
0485 }
0486
0487
0488
0489
0490
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