0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 VERBOSE=0
0062 PAUSE_ON_FAIL=no
0063 DEFAULT_TTYPE=sym
0064
0065 H1_N1=172.16.1.0/24
0066 H1_N1_6=2001:db8:16:1::/64
0067
0068 H1_N1_IP=172.16.1.1
0069 R1_N1_IP=172.16.1.253
0070 R2_N1_IP=172.16.1.254
0071
0072 H1_N1_IP6=2001:db8:16:1::1
0073 R1_N1_IP6=2001:db8:16:1::253
0074 R2_N1_IP6=2001:db8:16:1::254
0075
0076 H2_N2=172.16.2.0/24
0077 H2_N2_6=2001:db8:16:2::/64
0078
0079 H2_N2_IP=172.16.2.2
0080 R1_N2_IP=172.16.2.253
0081 R2_N2_IP=172.16.2.254
0082
0083 H2_N2_IP6=2001:db8:16:2::2
0084 R1_N2_IP6=2001:db8:16:2::253
0085 R2_N2_IP6=2001:db8:16:2::254
0086
0087
0088
0089
0090 log_section()
0091 {
0092 echo
0093 echo "###########################################################################"
0094 echo "$*"
0095 echo "###########################################################################"
0096 echo
0097 }
0098
0099 log_test()
0100 {
0101 local rc=$1
0102 local expected=$2
0103 local msg="$3"
0104
0105 if [ "${rc}" -eq "${expected}" ]; then
0106 printf "TEST: %-60s [ OK ]\n" "${msg}"
0107 nsuccess=$((nsuccess+1))
0108 else
0109 ret=1
0110 nfail=$((nfail+1))
0111 printf "TEST: %-60s [FAIL]\n" "${msg}"
0112 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
0113 echo
0114 echo "hit enter to continue, 'q' to quit"
0115 read -r a
0116 [ "$a" = "q" ] && exit 1
0117 fi
0118 fi
0119 }
0120
0121 run_cmd()
0122 {
0123 local cmd="$*"
0124 local out
0125 local rc
0126
0127 if [ "$VERBOSE" = "1" ]; then
0128 echo "COMMAND: $cmd"
0129 fi
0130
0131
0132 out=$(eval $cmd 2>&1)
0133 rc=$?
0134 if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
0135 echo "$out"
0136 fi
0137
0138 [ "$VERBOSE" = "1" ] && echo
0139
0140 return $rc
0141 }
0142
0143 run_cmd_grep()
0144 {
0145 local grep_pattern="$1"
0146 shift
0147 local cmd="$*"
0148 local out
0149 local rc
0150
0151 if [ "$VERBOSE" = "1" ]; then
0152 echo "COMMAND: $cmd"
0153 fi
0154
0155
0156 out=$(eval $cmd 2>&1)
0157 if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
0158 echo "$out"
0159 fi
0160
0161 echo "$out" | grep -q "$grep_pattern"
0162 rc=$?
0163
0164 [ "$VERBOSE" = "1" ] && echo
0165
0166 return $rc
0167 }
0168
0169
0170
0171
0172 cleanup()
0173 {
0174 local ns
0175
0176 for ns in h1 h2 r1 r2; do
0177 ip netns del $ns 2>/dev/null
0178 done
0179 }
0180
0181 setup_vrf()
0182 {
0183 local ns=$1
0184
0185 ip -netns "${ns}" rule del pref 0
0186 ip -netns "${ns}" rule add pref 32765 from all lookup local
0187 ip -netns "${ns}" -6 rule del pref 0
0188 ip -netns "${ns}" -6 rule add pref 32765 from all lookup local
0189 }
0190
0191 create_vrf()
0192 {
0193 local ns=$1
0194 local vrf=$2
0195 local table=$3
0196
0197 ip -netns "${ns}" link add "${vrf}" type vrf table "${table}"
0198 ip -netns "${ns}" link set "${vrf}" up
0199 ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192
0200 ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192
0201
0202 ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}"
0203 ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad
0204 }
0205
0206 setup_sym()
0207 {
0208 local ns
0209
0210
0211 cleanup
0212
0213
0214
0215
0216 for ns in h1 h2 r1; do
0217 ip netns add $ns
0218 ip -netns $ns link set lo up
0219
0220 case "${ns}" in
0221 h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
0222 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
0223 ;;
0224 r1) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
0225 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
0226 esac
0227 done
0228
0229
0230
0231
0232 ip -netns h1 link add eth0 type veth peer name r1h1
0233 ip -netns h1 link set r1h1 netns r1 name eth0 up
0234
0235 ip -netns h2 link add eth0 type veth peer name r1h2
0236 ip -netns h2 link set r1h2 netns r1 name eth1 up
0237
0238
0239
0240
0241 ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24
0242 ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
0243 ip -netns h1 link set eth0 up
0244
0245
0246 ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0
0247 ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
0248
0249
0250
0251
0252 ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
0253 ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
0254 ip -netns h2 link set eth0 up
0255
0256
0257 ip -netns h2 route add default via ${R1_N2_IP} dev eth0
0258 ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0
0259
0260
0261
0262
0263 setup_vrf r1
0264 create_vrf r1 blue 1101
0265 create_vrf r1 red 1102
0266 ip -netns r1 link set mtu 1400 dev eth1
0267 ip -netns r1 link set eth0 vrf blue up
0268 ip -netns r1 link set eth1 vrf red up
0269 ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
0270 ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
0271 ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
0272 ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
0273
0274
0275 ip -netns r1 route add vrf blue ${H2_N2} dev red
0276 ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
0277
0278
0279 ip -netns r1 route add vrf red ${H1_N1} dev blue
0280 ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue
0281
0282
0283
0284 sleep 2
0285 }
0286
0287 setup_asym()
0288 {
0289 local ns
0290
0291
0292 cleanup
0293
0294
0295
0296
0297 for ns in h1 h2 r1 r2; do
0298 ip netns add $ns
0299 ip -netns $ns link set lo up
0300
0301 case "${ns}" in
0302 h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
0303 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
0304 ;;
0305 r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
0306 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
0307 esac
0308 done
0309
0310
0311
0312
0313 ip -netns h1 link add eth0 type veth peer name r1h1
0314 ip -netns h1 link set r1h1 netns r1 name eth0 up
0315
0316 ip -netns h1 link add eth1 type veth peer name r2h1
0317 ip -netns h1 link set r2h1 netns r2 name eth0 up
0318
0319 ip -netns h2 link add eth0 type veth peer name r1h2
0320 ip -netns h2 link set r1h2 netns r1 name eth1 up
0321
0322 ip -netns h2 link add eth1 type veth peer name r2h2
0323 ip -netns h2 link set r2h2 netns r2 name eth1 up
0324
0325
0326
0327
0328 ip -netns h1 link add br0 type bridge
0329 ip -netns h1 link set br0 up
0330 ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
0331 ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
0332 ip -netns h1 link set eth0 master br0 up
0333 ip -netns h1 link set eth1 master br0 up
0334
0335
0336 ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev br0
0337 ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
0338
0339
0340
0341
0342 ip -netns h2 link add br0 type bridge
0343 ip -netns h2 link set br0 up
0344 ip -netns h2 addr add dev br0 ${H2_N2_IP}/24
0345 ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
0346 ip -netns h2 link set eth0 master br0 up
0347 ip -netns h2 link set eth1 master br0 up
0348
0349
0350 ip -netns h2 route add default via ${R2_N2_IP} dev br0
0351 ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0
0352
0353
0354
0355
0356 setup_vrf r1
0357 create_vrf r1 blue 1101
0358 create_vrf r1 red 1102
0359 ip -netns r1 link set mtu 1400 dev eth1
0360 ip -netns r1 link set eth0 vrf blue up
0361 ip -netns r1 link set eth1 vrf red up
0362 ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
0363 ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
0364 ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
0365 ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
0366
0367
0368 ip -netns r1 route add vrf blue ${H2_N2} dev red
0369 ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
0370
0371
0372
0373
0374
0375
0376 ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
0377 ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
0378 ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24
0379 ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
0380
0381
0382 sleep 2
0383 }
0384
0385 check_connectivity()
0386 {
0387 ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
0388 log_test $? 0 "Basic IPv4 connectivity"
0389 return $?
0390 }
0391
0392 check_connectivity6()
0393 {
0394 ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
0395 log_test $? 0 "Basic IPv6 connectivity"
0396 return $?
0397 }
0398
0399 check_traceroute()
0400 {
0401 if [ ! -x "$(command -v traceroute)" ]; then
0402 echo "SKIP: Could not run IPV4 test without traceroute"
0403 return 1
0404 fi
0405 }
0406
0407 check_traceroute6()
0408 {
0409 if [ ! -x "$(command -v traceroute6)" ]; then
0410 echo "SKIP: Could not run IPV6 test without traceroute6"
0411 return 1
0412 fi
0413 }
0414
0415 ipv4_traceroute()
0416 {
0417 local ttype="$1"
0418
0419 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0420
0421 log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute"
0422
0423 check_traceroute || return
0424
0425 setup_"$ttype"
0426
0427 check_connectivity || return
0428
0429 run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP}
0430 log_test $? 0 "Traceroute reports a hop on r1"
0431 }
0432
0433 ipv4_traceroute_asym()
0434 {
0435 ipv4_traceroute asym
0436 }
0437
0438 ipv6_traceroute()
0439 {
0440 local ttype="$1"
0441
0442 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0443
0444 log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute"
0445
0446 check_traceroute6 || return
0447
0448 setup_"$ttype"
0449
0450 check_connectivity6 || return
0451
0452 run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6}
0453 log_test $? 0 "Traceroute6 reports a hop on r1"
0454 }
0455
0456 ipv6_traceroute_asym()
0457 {
0458 ipv6_traceroute asym
0459 }
0460
0461 ipv4_ping_ttl()
0462 {
0463 local ttype="$1"
0464
0465 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0466
0467 log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping"
0468
0469 setup_"$ttype"
0470
0471 check_connectivity || return
0472
0473 run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP}
0474 log_test $? 0 "Ping received ICMP ttl exceeded"
0475 }
0476
0477 ipv4_ping_ttl_asym()
0478 {
0479 ipv4_ping_ttl asym
0480 }
0481
0482 ipv4_ping_frag()
0483 {
0484 local ttype="$1"
0485
0486 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0487
0488 log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping"
0489
0490 setup_"$ttype"
0491
0492 check_connectivity || return
0493
0494 run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
0495 log_test $? 0 "Ping received ICMP Frag needed"
0496 }
0497
0498 ipv4_ping_frag_asym()
0499 {
0500 ipv4_ping_frag asym
0501 }
0502
0503 ipv6_ping_ttl()
0504 {
0505 local ttype="$1"
0506
0507 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0508
0509 log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping"
0510
0511 setup_"$ttype"
0512
0513 check_connectivity6 || return
0514
0515 run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
0516 log_test $? 0 "Ping received ICMP Hop limit"
0517 }
0518
0519 ipv6_ping_ttl_asym()
0520 {
0521 ipv6_ping_ttl asym
0522 }
0523
0524 ipv6_ping_frag()
0525 {
0526 local ttype="$1"
0527
0528 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
0529
0530 log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping"
0531
0532 setup_"$ttype"
0533
0534 check_connectivity6 || return
0535
0536 run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
0537 log_test $? 0 "Ping received ICMP Packet too big"
0538 }
0539
0540 ipv6_ping_frag_asym()
0541 {
0542 ipv6_ping_frag asym
0543 }
0544
0545
0546
0547
0548 usage()
0549 {
0550 cat <<EOF
0551 usage: ${0
0552
0553 -4 Run IPv4 tests only
0554 -6 Run IPv6 tests only
0555 -t TEST Run only TEST
0556 -p Pause on fail
0557 -v verbose mode (show commands and output)
0558 EOF
0559 }
0560
0561
0562
0563
0564
0565 command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping)
0566
0567 TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym"
0568 TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_frag ipv6_ping_ttl_asym ipv6_traceroute_asym"
0569
0570 ret=0
0571 nsuccess=0
0572 nfail=0
0573
0574 while getopts :46t:pvh o
0575 do
0576 case $o in
0577 4) TESTS=ipv4;;
0578 6) TESTS=ipv6;;
0579 t) TESTS=$OPTARG;;
0580 p) PAUSE_ON_FAIL=yes;;
0581 v) VERBOSE=1;;
0582 h) usage; exit 0;;
0583 *) usage; exit 1;;
0584 esac
0585 done
0586
0587
0588
0589
0590 if [ -z "$TESTS" ]; then
0591 TESTS="$TESTS_IPV4 $TESTS_IPV6"
0592 elif [ "$TESTS" = "ipv4" ]; then
0593 TESTS="$TESTS_IPV4"
0594 elif [ "$TESTS" = "ipv6" ]; then
0595 TESTS="$TESTS_IPV6"
0596 fi
0597
0598 for t in $TESTS
0599 do
0600 case $t in
0601 ipv4_ping_ttl|ping) ipv4_ping_ttl;;&
0602 ipv4_ping_ttl_asym|ping) ipv4_ping_ttl_asym;;&
0603 ipv4_traceroute|traceroute) ipv4_traceroute;;&
0604 ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
0605 ipv4_ping_frag|ping) ipv4_ping_frag;;&
0606
0607 ipv6_ping_ttl|ping) ipv6_ping_ttl;;&
0608 ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;&
0609 ipv6_traceroute|traceroute) ipv6_traceroute;;&
0610 ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
0611 ipv6_ping_frag|ping) ipv6_ping_frag;;&
0612
0613
0614 setup_sym|setup) setup_sym; exit 0;;
0615 setup_asym) setup_asym; exit 0;;
0616
0617 help) echo "Test names: $TESTS"; exit 0;;
0618 esac
0619 done
0620
0621 cleanup
0622
0623 printf "\nTests passed: %3d\n" ${nsuccess}
0624 printf "Tests failed: %3d\n" ${nfail}
0625
0626 exit $ret