1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved. 5*4882a593Smuzhiyun# Copyright (c) 2020 Michael Jeanson <mjeanson@efficios.com>. All rights reserved. 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# Requires CONFIG_NET_VRF, CONFIG_VETH, CONFIG_BRIDGE and CONFIG_NET_NS. 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# 10*4882a593Smuzhiyun# Symmetric routing topology 11*4882a593Smuzhiyun# 12*4882a593Smuzhiyun# blue red 13*4882a593Smuzhiyun# +----+ .253 +----+ .253 +----+ 14*4882a593Smuzhiyun# | h1 |-------------------| r1 |-------------------| h2 | 15*4882a593Smuzhiyun# +----+ .1 +----+ .2 +----+ 16*4882a593Smuzhiyun# 172.16.1/24 172.16.2/24 17*4882a593Smuzhiyun# 2001:db8:16:1/64 2001:db8:16:2/64 18*4882a593Smuzhiyun# 19*4882a593Smuzhiyun# 20*4882a593Smuzhiyun# Route from h1 to h2 and back goes through r1, incoming vrf blue has a route 21*4882a593Smuzhiyun# to the outgoing vrf red for the n2 network and red has a route back to n1. 22*4882a593Smuzhiyun# The red VRF interface has a MTU of 1400. 23*4882a593Smuzhiyun# 24*4882a593Smuzhiyun# The first test sends a ping with a ttl of 1 from h1 to h2 and parses the 25*4882a593Smuzhiyun# output of the command to check that a ttl expired error is received. 26*4882a593Smuzhiyun# 27*4882a593Smuzhiyun# The second test runs traceroute from h1 to h2 and parses the output to check 28*4882a593Smuzhiyun# for a hop on r1. 29*4882a593Smuzhiyun# 30*4882a593Smuzhiyun# The third test sends a ping with a packet size of 1450 from h1 to h2 and 31*4882a593Smuzhiyun# parses the output of the command to check that a fragmentation error is 32*4882a593Smuzhiyun# received. 33*4882a593Smuzhiyun# 34*4882a593Smuzhiyun# 35*4882a593Smuzhiyun# Asymmetric routing topology 36*4882a593Smuzhiyun# 37*4882a593Smuzhiyun# This topology represents a customer setup where the issue with icmp errors 38*4882a593Smuzhiyun# and VRF route leaking was initialy reported. The MTU test isn't done here 39*4882a593Smuzhiyun# because of the lack of a return route in the red VRF. 40*4882a593Smuzhiyun# 41*4882a593Smuzhiyun# blue red 42*4882a593Smuzhiyun# .253 +----+ .253 43*4882a593Smuzhiyun# +----| r1 |----+ 44*4882a593Smuzhiyun# | +----+ | 45*4882a593Smuzhiyun# +----+ | | +----+ 46*4882a593Smuzhiyun# | h1 |--------------+ +--------------| h2 | 47*4882a593Smuzhiyun# +----+ .1 | | .2 +----+ 48*4882a593Smuzhiyun# 172.16.1/24 | +----+ | 172.16.2/24 49*4882a593Smuzhiyun# 2001:db8:16:1/64 +----| r2 |----+ 2001:db8:16:2/64 50*4882a593Smuzhiyun# .254 +----+ .254 51*4882a593Smuzhiyun# 52*4882a593Smuzhiyun# 53*4882a593Smuzhiyun# Route from h1 to h2 goes through r1, incoming vrf blue has a route to the 54*4882a593Smuzhiyun# outgoing vrf red for the n2 network but red doesn't have a route back to n1. 55*4882a593Smuzhiyun# Route from h2 to h1 goes through r2. 56*4882a593Smuzhiyun# 57*4882a593Smuzhiyun# The objective is to check that the incoming vrf routing table is selected 58*4882a593Smuzhiyun# to send an ICMP error back to the source when the ttl of a packet reaches 1 59*4882a593Smuzhiyun# while it is forwarded between different vrfs. 60*4882a593Smuzhiyun 61*4882a593SmuzhiyunVERBOSE=0 62*4882a593SmuzhiyunPAUSE_ON_FAIL=no 63*4882a593SmuzhiyunDEFAULT_TTYPE=sym 64*4882a593Smuzhiyun 65*4882a593SmuzhiyunH1_N1=172.16.1.0/24 66*4882a593SmuzhiyunH1_N1_6=2001:db8:16:1::/64 67*4882a593Smuzhiyun 68*4882a593SmuzhiyunH1_N1_IP=172.16.1.1 69*4882a593SmuzhiyunR1_N1_IP=172.16.1.253 70*4882a593SmuzhiyunR2_N1_IP=172.16.1.254 71*4882a593Smuzhiyun 72*4882a593SmuzhiyunH1_N1_IP6=2001:db8:16:1::1 73*4882a593SmuzhiyunR1_N1_IP6=2001:db8:16:1::253 74*4882a593SmuzhiyunR2_N1_IP6=2001:db8:16:1::254 75*4882a593Smuzhiyun 76*4882a593SmuzhiyunH2_N2=172.16.2.0/24 77*4882a593SmuzhiyunH2_N2_6=2001:db8:16:2::/64 78*4882a593Smuzhiyun 79*4882a593SmuzhiyunH2_N2_IP=172.16.2.2 80*4882a593SmuzhiyunR1_N2_IP=172.16.2.253 81*4882a593SmuzhiyunR2_N2_IP=172.16.2.254 82*4882a593Smuzhiyun 83*4882a593SmuzhiyunH2_N2_IP6=2001:db8:16:2::2 84*4882a593SmuzhiyunR1_N2_IP6=2001:db8:16:2::253 85*4882a593SmuzhiyunR2_N2_IP6=2001:db8:16:2::254 86*4882a593Smuzhiyun 87*4882a593Smuzhiyun################################################################################ 88*4882a593Smuzhiyun# helpers 89*4882a593Smuzhiyun 90*4882a593Smuzhiyunlog_section() 91*4882a593Smuzhiyun{ 92*4882a593Smuzhiyun echo 93*4882a593Smuzhiyun echo "###########################################################################" 94*4882a593Smuzhiyun echo "$*" 95*4882a593Smuzhiyun echo "###########################################################################" 96*4882a593Smuzhiyun echo 97*4882a593Smuzhiyun} 98*4882a593Smuzhiyun 99*4882a593Smuzhiyunlog_test() 100*4882a593Smuzhiyun{ 101*4882a593Smuzhiyun local rc=$1 102*4882a593Smuzhiyun local expected=$2 103*4882a593Smuzhiyun local msg="$3" 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun if [ "${rc}" -eq "${expected}" ]; then 106*4882a593Smuzhiyun printf "TEST: %-60s [ OK ]\n" "${msg}" 107*4882a593Smuzhiyun nsuccess=$((nsuccess+1)) 108*4882a593Smuzhiyun else 109*4882a593Smuzhiyun ret=1 110*4882a593Smuzhiyun nfail=$((nfail+1)) 111*4882a593Smuzhiyun printf "TEST: %-60s [FAIL]\n" "${msg}" 112*4882a593Smuzhiyun if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 113*4882a593Smuzhiyun echo 114*4882a593Smuzhiyun echo "hit enter to continue, 'q' to quit" 115*4882a593Smuzhiyun read -r a 116*4882a593Smuzhiyun [ "$a" = "q" ] && exit 1 117*4882a593Smuzhiyun fi 118*4882a593Smuzhiyun fi 119*4882a593Smuzhiyun} 120*4882a593Smuzhiyun 121*4882a593Smuzhiyunrun_cmd() 122*4882a593Smuzhiyun{ 123*4882a593Smuzhiyun local cmd="$*" 124*4882a593Smuzhiyun local out 125*4882a593Smuzhiyun local rc 126*4882a593Smuzhiyun 127*4882a593Smuzhiyun if [ "$VERBOSE" = "1" ]; then 128*4882a593Smuzhiyun echo "COMMAND: $cmd" 129*4882a593Smuzhiyun fi 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun # shellcheck disable=SC2086 132*4882a593Smuzhiyun out=$(eval $cmd 2>&1) 133*4882a593Smuzhiyun rc=$? 134*4882a593Smuzhiyun if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then 135*4882a593Smuzhiyun echo "$out" 136*4882a593Smuzhiyun fi 137*4882a593Smuzhiyun 138*4882a593Smuzhiyun [ "$VERBOSE" = "1" ] && echo 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun return $rc 141*4882a593Smuzhiyun} 142*4882a593Smuzhiyun 143*4882a593Smuzhiyunrun_cmd_grep() 144*4882a593Smuzhiyun{ 145*4882a593Smuzhiyun local grep_pattern="$1" 146*4882a593Smuzhiyun shift 147*4882a593Smuzhiyun local cmd="$*" 148*4882a593Smuzhiyun local out 149*4882a593Smuzhiyun local rc 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun if [ "$VERBOSE" = "1" ]; then 152*4882a593Smuzhiyun echo "COMMAND: $cmd" 153*4882a593Smuzhiyun fi 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun # shellcheck disable=SC2086 156*4882a593Smuzhiyun out=$(eval $cmd 2>&1) 157*4882a593Smuzhiyun if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then 158*4882a593Smuzhiyun echo "$out" 159*4882a593Smuzhiyun fi 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun echo "$out" | grep -q "$grep_pattern" 162*4882a593Smuzhiyun rc=$? 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun [ "$VERBOSE" = "1" ] && echo 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun return $rc 167*4882a593Smuzhiyun} 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun################################################################################ 170*4882a593Smuzhiyun# setup and teardown 171*4882a593Smuzhiyun 172*4882a593Smuzhiyuncleanup() 173*4882a593Smuzhiyun{ 174*4882a593Smuzhiyun local ns 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun for ns in h1 h2 r1 r2; do 177*4882a593Smuzhiyun ip netns del $ns 2>/dev/null 178*4882a593Smuzhiyun done 179*4882a593Smuzhiyun} 180*4882a593Smuzhiyun 181*4882a593Smuzhiyunsetup_vrf() 182*4882a593Smuzhiyun{ 183*4882a593Smuzhiyun local ns=$1 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun ip -netns "${ns}" rule del pref 0 186*4882a593Smuzhiyun ip -netns "${ns}" rule add pref 32765 from all lookup local 187*4882a593Smuzhiyun ip -netns "${ns}" -6 rule del pref 0 188*4882a593Smuzhiyun ip -netns "${ns}" -6 rule add pref 32765 from all lookup local 189*4882a593Smuzhiyun} 190*4882a593Smuzhiyun 191*4882a593Smuzhiyuncreate_vrf() 192*4882a593Smuzhiyun{ 193*4882a593Smuzhiyun local ns=$1 194*4882a593Smuzhiyun local vrf=$2 195*4882a593Smuzhiyun local table=$3 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun ip -netns "${ns}" link add "${vrf}" type vrf table "${table}" 198*4882a593Smuzhiyun ip -netns "${ns}" link set "${vrf}" up 199*4882a593Smuzhiyun ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192 200*4882a593Smuzhiyun ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192 201*4882a593Smuzhiyun 202*4882a593Smuzhiyun ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}" 203*4882a593Smuzhiyun ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad 204*4882a593Smuzhiyun} 205*4882a593Smuzhiyun 206*4882a593Smuzhiyunsetup_sym() 207*4882a593Smuzhiyun{ 208*4882a593Smuzhiyun local ns 209*4882a593Smuzhiyun 210*4882a593Smuzhiyun # make sure we are starting with a clean slate 211*4882a593Smuzhiyun cleanup 212*4882a593Smuzhiyun 213*4882a593Smuzhiyun # 214*4882a593Smuzhiyun # create nodes as namespaces 215*4882a593Smuzhiyun # 216*4882a593Smuzhiyun for ns in h1 h2 r1; do 217*4882a593Smuzhiyun ip netns add $ns 218*4882a593Smuzhiyun ip -netns $ns link set lo up 219*4882a593Smuzhiyun 220*4882a593Smuzhiyun case "${ns}" in 221*4882a593Smuzhiyun h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 222*4882a593Smuzhiyun ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 223*4882a593Smuzhiyun ;; 224*4882a593Smuzhiyun r1) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 225*4882a593Smuzhiyun ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 226*4882a593Smuzhiyun esac 227*4882a593Smuzhiyun done 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun # 230*4882a593Smuzhiyun # create interconnects 231*4882a593Smuzhiyun # 232*4882a593Smuzhiyun ip -netns h1 link add eth0 type veth peer name r1h1 233*4882a593Smuzhiyun ip -netns h1 link set r1h1 netns r1 name eth0 up 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun ip -netns h2 link add eth0 type veth peer name r1h2 236*4882a593Smuzhiyun ip -netns h2 link set r1h2 netns r1 name eth1 up 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun # 239*4882a593Smuzhiyun # h1 240*4882a593Smuzhiyun # 241*4882a593Smuzhiyun ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24 242*4882a593Smuzhiyun ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad 243*4882a593Smuzhiyun ip -netns h1 link set eth0 up 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun # h1 to h2 via r1 246*4882a593Smuzhiyun ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0 247*4882a593Smuzhiyun ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0 248*4882a593Smuzhiyun 249*4882a593Smuzhiyun # 250*4882a593Smuzhiyun # h2 251*4882a593Smuzhiyun # 252*4882a593Smuzhiyun ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24 253*4882a593Smuzhiyun ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad 254*4882a593Smuzhiyun ip -netns h2 link set eth0 up 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun # h2 to h1 via r1 257*4882a593Smuzhiyun ip -netns h2 route add default via ${R1_N2_IP} dev eth0 258*4882a593Smuzhiyun ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun # 261*4882a593Smuzhiyun # r1 262*4882a593Smuzhiyun # 263*4882a593Smuzhiyun setup_vrf r1 264*4882a593Smuzhiyun create_vrf r1 blue 1101 265*4882a593Smuzhiyun create_vrf r1 red 1102 266*4882a593Smuzhiyun ip -netns r1 link set mtu 1400 dev eth1 267*4882a593Smuzhiyun ip -netns r1 link set eth0 vrf blue up 268*4882a593Smuzhiyun ip -netns r1 link set eth1 vrf red up 269*4882a593Smuzhiyun ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24 270*4882a593Smuzhiyun ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad 271*4882a593Smuzhiyun ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24 272*4882a593Smuzhiyun ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad 273*4882a593Smuzhiyun 274*4882a593Smuzhiyun # Route leak from blue to red 275*4882a593Smuzhiyun ip -netns r1 route add vrf blue ${H2_N2} dev red 276*4882a593Smuzhiyun ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun # Route leak from red to blue 279*4882a593Smuzhiyun ip -netns r1 route add vrf red ${H1_N1} dev blue 280*4882a593Smuzhiyun ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun 283*4882a593Smuzhiyun # Wait for ip config to settle 284*4882a593Smuzhiyun sleep 2 285*4882a593Smuzhiyun} 286*4882a593Smuzhiyun 287*4882a593Smuzhiyunsetup_asym() 288*4882a593Smuzhiyun{ 289*4882a593Smuzhiyun local ns 290*4882a593Smuzhiyun 291*4882a593Smuzhiyun # make sure we are starting with a clean slate 292*4882a593Smuzhiyun cleanup 293*4882a593Smuzhiyun 294*4882a593Smuzhiyun # 295*4882a593Smuzhiyun # create nodes as namespaces 296*4882a593Smuzhiyun # 297*4882a593Smuzhiyun for ns in h1 h2 r1 r2; do 298*4882a593Smuzhiyun ip netns add $ns 299*4882a593Smuzhiyun ip -netns $ns link set lo up 300*4882a593Smuzhiyun 301*4882a593Smuzhiyun case "${ns}" in 302*4882a593Smuzhiyun h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 303*4882a593Smuzhiyun ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 304*4882a593Smuzhiyun ;; 305*4882a593Smuzhiyun r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 306*4882a593Smuzhiyun ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 307*4882a593Smuzhiyun esac 308*4882a593Smuzhiyun done 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun # 311*4882a593Smuzhiyun # create interconnects 312*4882a593Smuzhiyun # 313*4882a593Smuzhiyun ip -netns h1 link add eth0 type veth peer name r1h1 314*4882a593Smuzhiyun ip -netns h1 link set r1h1 netns r1 name eth0 up 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun ip -netns h1 link add eth1 type veth peer name r2h1 317*4882a593Smuzhiyun ip -netns h1 link set r2h1 netns r2 name eth0 up 318*4882a593Smuzhiyun 319*4882a593Smuzhiyun ip -netns h2 link add eth0 type veth peer name r1h2 320*4882a593Smuzhiyun ip -netns h2 link set r1h2 netns r1 name eth1 up 321*4882a593Smuzhiyun 322*4882a593Smuzhiyun ip -netns h2 link add eth1 type veth peer name r2h2 323*4882a593Smuzhiyun ip -netns h2 link set r2h2 netns r2 name eth1 up 324*4882a593Smuzhiyun 325*4882a593Smuzhiyun # 326*4882a593Smuzhiyun # h1 327*4882a593Smuzhiyun # 328*4882a593Smuzhiyun ip -netns h1 link add br0 type bridge 329*4882a593Smuzhiyun ip -netns h1 link set br0 up 330*4882a593Smuzhiyun ip -netns h1 addr add dev br0 ${H1_N1_IP}/24 331*4882a593Smuzhiyun ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad 332*4882a593Smuzhiyun ip -netns h1 link set eth0 master br0 up 333*4882a593Smuzhiyun ip -netns h1 link set eth1 master br0 up 334*4882a593Smuzhiyun 335*4882a593Smuzhiyun # h1 to h2 via r1 336*4882a593Smuzhiyun ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev br0 337*4882a593Smuzhiyun ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0 338*4882a593Smuzhiyun 339*4882a593Smuzhiyun # 340*4882a593Smuzhiyun # h2 341*4882a593Smuzhiyun # 342*4882a593Smuzhiyun ip -netns h2 link add br0 type bridge 343*4882a593Smuzhiyun ip -netns h2 link set br0 up 344*4882a593Smuzhiyun ip -netns h2 addr add dev br0 ${H2_N2_IP}/24 345*4882a593Smuzhiyun ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad 346*4882a593Smuzhiyun ip -netns h2 link set eth0 master br0 up 347*4882a593Smuzhiyun ip -netns h2 link set eth1 master br0 up 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun # h2 to h1 via r2 350*4882a593Smuzhiyun ip -netns h2 route add default via ${R2_N2_IP} dev br0 351*4882a593Smuzhiyun ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0 352*4882a593Smuzhiyun 353*4882a593Smuzhiyun # 354*4882a593Smuzhiyun # r1 355*4882a593Smuzhiyun # 356*4882a593Smuzhiyun setup_vrf r1 357*4882a593Smuzhiyun create_vrf r1 blue 1101 358*4882a593Smuzhiyun create_vrf r1 red 1102 359*4882a593Smuzhiyun ip -netns r1 link set mtu 1400 dev eth1 360*4882a593Smuzhiyun ip -netns r1 link set eth0 vrf blue up 361*4882a593Smuzhiyun ip -netns r1 link set eth1 vrf red up 362*4882a593Smuzhiyun ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24 363*4882a593Smuzhiyun ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad 364*4882a593Smuzhiyun ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24 365*4882a593Smuzhiyun ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun # Route leak from blue to red 368*4882a593Smuzhiyun ip -netns r1 route add vrf blue ${H2_N2} dev red 369*4882a593Smuzhiyun ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red 370*4882a593Smuzhiyun 371*4882a593Smuzhiyun # No route leak from red to blue 372*4882a593Smuzhiyun 373*4882a593Smuzhiyun # 374*4882a593Smuzhiyun # r2 375*4882a593Smuzhiyun # 376*4882a593Smuzhiyun ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24 377*4882a593Smuzhiyun ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad 378*4882a593Smuzhiyun ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24 379*4882a593Smuzhiyun ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun # Wait for ip config to settle 382*4882a593Smuzhiyun sleep 2 383*4882a593Smuzhiyun} 384*4882a593Smuzhiyun 385*4882a593Smuzhiyuncheck_connectivity() 386*4882a593Smuzhiyun{ 387*4882a593Smuzhiyun ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1 388*4882a593Smuzhiyun log_test $? 0 "Basic IPv4 connectivity" 389*4882a593Smuzhiyun return $? 390*4882a593Smuzhiyun} 391*4882a593Smuzhiyun 392*4882a593Smuzhiyuncheck_connectivity6() 393*4882a593Smuzhiyun{ 394*4882a593Smuzhiyun ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1 395*4882a593Smuzhiyun log_test $? 0 "Basic IPv6 connectivity" 396*4882a593Smuzhiyun return $? 397*4882a593Smuzhiyun} 398*4882a593Smuzhiyun 399*4882a593Smuzhiyuncheck_traceroute() 400*4882a593Smuzhiyun{ 401*4882a593Smuzhiyun if [ ! -x "$(command -v traceroute)" ]; then 402*4882a593Smuzhiyun echo "SKIP: Could not run IPV4 test without traceroute" 403*4882a593Smuzhiyun return 1 404*4882a593Smuzhiyun fi 405*4882a593Smuzhiyun} 406*4882a593Smuzhiyun 407*4882a593Smuzhiyuncheck_traceroute6() 408*4882a593Smuzhiyun{ 409*4882a593Smuzhiyun if [ ! -x "$(command -v traceroute6)" ]; then 410*4882a593Smuzhiyun echo "SKIP: Could not run IPV6 test without traceroute6" 411*4882a593Smuzhiyun return 1 412*4882a593Smuzhiyun fi 413*4882a593Smuzhiyun} 414*4882a593Smuzhiyun 415*4882a593Smuzhiyunipv4_traceroute() 416*4882a593Smuzhiyun{ 417*4882a593Smuzhiyun local ttype="$1" 418*4882a593Smuzhiyun 419*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 420*4882a593Smuzhiyun 421*4882a593Smuzhiyun log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute" 422*4882a593Smuzhiyun 423*4882a593Smuzhiyun check_traceroute || return 424*4882a593Smuzhiyun 425*4882a593Smuzhiyun setup_"$ttype" 426*4882a593Smuzhiyun 427*4882a593Smuzhiyun check_connectivity || return 428*4882a593Smuzhiyun 429*4882a593Smuzhiyun run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP} 430*4882a593Smuzhiyun log_test $? 0 "Traceroute reports a hop on r1" 431*4882a593Smuzhiyun} 432*4882a593Smuzhiyun 433*4882a593Smuzhiyunipv4_traceroute_asym() 434*4882a593Smuzhiyun{ 435*4882a593Smuzhiyun ipv4_traceroute asym 436*4882a593Smuzhiyun} 437*4882a593Smuzhiyun 438*4882a593Smuzhiyunipv6_traceroute() 439*4882a593Smuzhiyun{ 440*4882a593Smuzhiyun local ttype="$1" 441*4882a593Smuzhiyun 442*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 443*4882a593Smuzhiyun 444*4882a593Smuzhiyun log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute" 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun check_traceroute6 || return 447*4882a593Smuzhiyun 448*4882a593Smuzhiyun setup_"$ttype" 449*4882a593Smuzhiyun 450*4882a593Smuzhiyun check_connectivity6 || return 451*4882a593Smuzhiyun 452*4882a593Smuzhiyun run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6} 453*4882a593Smuzhiyun log_test $? 0 "Traceroute6 reports a hop on r1" 454*4882a593Smuzhiyun} 455*4882a593Smuzhiyun 456*4882a593Smuzhiyunipv6_traceroute_asym() 457*4882a593Smuzhiyun{ 458*4882a593Smuzhiyun ipv6_traceroute asym 459*4882a593Smuzhiyun} 460*4882a593Smuzhiyun 461*4882a593Smuzhiyunipv4_ping_ttl() 462*4882a593Smuzhiyun{ 463*4882a593Smuzhiyun local ttype="$1" 464*4882a593Smuzhiyun 465*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 466*4882a593Smuzhiyun 467*4882a593Smuzhiyun log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping" 468*4882a593Smuzhiyun 469*4882a593Smuzhiyun setup_"$ttype" 470*4882a593Smuzhiyun 471*4882a593Smuzhiyun check_connectivity || return 472*4882a593Smuzhiyun 473*4882a593Smuzhiyun run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP} 474*4882a593Smuzhiyun log_test $? 0 "Ping received ICMP ttl exceeded" 475*4882a593Smuzhiyun} 476*4882a593Smuzhiyun 477*4882a593Smuzhiyunipv4_ping_ttl_asym() 478*4882a593Smuzhiyun{ 479*4882a593Smuzhiyun ipv4_ping_ttl asym 480*4882a593Smuzhiyun} 481*4882a593Smuzhiyun 482*4882a593Smuzhiyunipv4_ping_frag() 483*4882a593Smuzhiyun{ 484*4882a593Smuzhiyun local ttype="$1" 485*4882a593Smuzhiyun 486*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 487*4882a593Smuzhiyun 488*4882a593Smuzhiyun log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping" 489*4882a593Smuzhiyun 490*4882a593Smuzhiyun setup_"$ttype" 491*4882a593Smuzhiyun 492*4882a593Smuzhiyun check_connectivity || return 493*4882a593Smuzhiyun 494*4882a593Smuzhiyun run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP} 495*4882a593Smuzhiyun log_test $? 0 "Ping received ICMP Frag needed" 496*4882a593Smuzhiyun} 497*4882a593Smuzhiyun 498*4882a593Smuzhiyunipv4_ping_frag_asym() 499*4882a593Smuzhiyun{ 500*4882a593Smuzhiyun ipv4_ping_frag asym 501*4882a593Smuzhiyun} 502*4882a593Smuzhiyun 503*4882a593Smuzhiyunipv6_ping_ttl() 504*4882a593Smuzhiyun{ 505*4882a593Smuzhiyun local ttype="$1" 506*4882a593Smuzhiyun 507*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 508*4882a593Smuzhiyun 509*4882a593Smuzhiyun log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping" 510*4882a593Smuzhiyun 511*4882a593Smuzhiyun setup_"$ttype" 512*4882a593Smuzhiyun 513*4882a593Smuzhiyun check_connectivity6 || return 514*4882a593Smuzhiyun 515*4882a593Smuzhiyun run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6} 516*4882a593Smuzhiyun log_test $? 0 "Ping received ICMP Hop limit" 517*4882a593Smuzhiyun} 518*4882a593Smuzhiyun 519*4882a593Smuzhiyunipv6_ping_ttl_asym() 520*4882a593Smuzhiyun{ 521*4882a593Smuzhiyun ipv6_ping_ttl asym 522*4882a593Smuzhiyun} 523*4882a593Smuzhiyun 524*4882a593Smuzhiyunipv6_ping_frag() 525*4882a593Smuzhiyun{ 526*4882a593Smuzhiyun local ttype="$1" 527*4882a593Smuzhiyun 528*4882a593Smuzhiyun [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 529*4882a593Smuzhiyun 530*4882a593Smuzhiyun log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping" 531*4882a593Smuzhiyun 532*4882a593Smuzhiyun setup_"$ttype" 533*4882a593Smuzhiyun 534*4882a593Smuzhiyun check_connectivity6 || return 535*4882a593Smuzhiyun 536*4882a593Smuzhiyun run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6} 537*4882a593Smuzhiyun log_test $? 0 "Ping received ICMP Packet too big" 538*4882a593Smuzhiyun} 539*4882a593Smuzhiyun 540*4882a593Smuzhiyunipv6_ping_frag_asym() 541*4882a593Smuzhiyun{ 542*4882a593Smuzhiyun ipv6_ping_frag asym 543*4882a593Smuzhiyun} 544*4882a593Smuzhiyun 545*4882a593Smuzhiyun################################################################################ 546*4882a593Smuzhiyun# usage 547*4882a593Smuzhiyun 548*4882a593Smuzhiyunusage() 549*4882a593Smuzhiyun{ 550*4882a593Smuzhiyun cat <<EOF 551*4882a593Smuzhiyunusage: ${0##*/} OPTS 552*4882a593Smuzhiyun 553*4882a593Smuzhiyun -4 Run IPv4 tests only 554*4882a593Smuzhiyun -6 Run IPv6 tests only 555*4882a593Smuzhiyun -t TEST Run only TEST 556*4882a593Smuzhiyun -p Pause on fail 557*4882a593Smuzhiyun -v verbose mode (show commands and output) 558*4882a593SmuzhiyunEOF 559*4882a593Smuzhiyun} 560*4882a593Smuzhiyun 561*4882a593Smuzhiyun################################################################################ 562*4882a593Smuzhiyun# main 563*4882a593Smuzhiyun 564*4882a593Smuzhiyun# Some systems don't have a ping6 binary anymore 565*4882a593Smuzhiyuncommand -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping) 566*4882a593Smuzhiyun 567*4882a593SmuzhiyunTESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym" 568*4882a593SmuzhiyunTESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_frag ipv6_ping_ttl_asym ipv6_traceroute_asym" 569*4882a593Smuzhiyun 570*4882a593Smuzhiyunret=0 571*4882a593Smuzhiyunnsuccess=0 572*4882a593Smuzhiyunnfail=0 573*4882a593Smuzhiyun 574*4882a593Smuzhiyunwhile getopts :46t:pvh o 575*4882a593Smuzhiyundo 576*4882a593Smuzhiyun case $o in 577*4882a593Smuzhiyun 4) TESTS=ipv4;; 578*4882a593Smuzhiyun 6) TESTS=ipv6;; 579*4882a593Smuzhiyun t) TESTS=$OPTARG;; 580*4882a593Smuzhiyun p) PAUSE_ON_FAIL=yes;; 581*4882a593Smuzhiyun v) VERBOSE=1;; 582*4882a593Smuzhiyun h) usage; exit 0;; 583*4882a593Smuzhiyun *) usage; exit 1;; 584*4882a593Smuzhiyun esac 585*4882a593Smuzhiyundone 586*4882a593Smuzhiyun 587*4882a593Smuzhiyun# 588*4882a593Smuzhiyun# show user test config 589*4882a593Smuzhiyun# 590*4882a593Smuzhiyunif [ -z "$TESTS" ]; then 591*4882a593Smuzhiyun TESTS="$TESTS_IPV4 $TESTS_IPV6" 592*4882a593Smuzhiyunelif [ "$TESTS" = "ipv4" ]; then 593*4882a593Smuzhiyun TESTS="$TESTS_IPV4" 594*4882a593Smuzhiyunelif [ "$TESTS" = "ipv6" ]; then 595*4882a593Smuzhiyun TESTS="$TESTS_IPV6" 596*4882a593Smuzhiyunfi 597*4882a593Smuzhiyun 598*4882a593Smuzhiyunfor t in $TESTS 599*4882a593Smuzhiyundo 600*4882a593Smuzhiyun case $t in 601*4882a593Smuzhiyun ipv4_ping_ttl|ping) ipv4_ping_ttl;;& 602*4882a593Smuzhiyun ipv4_ping_ttl_asym|ping) ipv4_ping_ttl_asym;;& 603*4882a593Smuzhiyun ipv4_traceroute|traceroute) ipv4_traceroute;;& 604*4882a593Smuzhiyun ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;& 605*4882a593Smuzhiyun ipv4_ping_frag|ping) ipv4_ping_frag;;& 606*4882a593Smuzhiyun 607*4882a593Smuzhiyun ipv6_ping_ttl|ping) ipv6_ping_ttl;;& 608*4882a593Smuzhiyun ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;& 609*4882a593Smuzhiyun ipv6_traceroute|traceroute) ipv6_traceroute;;& 610*4882a593Smuzhiyun ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;& 611*4882a593Smuzhiyun ipv6_ping_frag|ping) ipv6_ping_frag;;& 612*4882a593Smuzhiyun 613*4882a593Smuzhiyun # setup namespaces and config, but do not run any tests 614*4882a593Smuzhiyun setup_sym|setup) setup_sym; exit 0;; 615*4882a593Smuzhiyun setup_asym) setup_asym; exit 0;; 616*4882a593Smuzhiyun 617*4882a593Smuzhiyun help) echo "Test names: $TESTS"; exit 0;; 618*4882a593Smuzhiyun esac 619*4882a593Smuzhiyundone 620*4882a593Smuzhiyun 621*4882a593Smuzhiyuncleanup 622*4882a593Smuzhiyun 623*4882a593Smuzhiyunprintf "\nTests passed: %3d\n" ${nsuccess} 624*4882a593Smuzhiyunprintf "Tests failed: %3d\n" ${nfail} 625*4882a593Smuzhiyun 626*4882a593Smuzhiyunexit $ret 627