1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Run traceroute/traceroute6 tests 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunVERBOSE=0 8*4882a593SmuzhiyunPAUSE_ON_FAIL=no 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun################################################################################ 11*4882a593Smuzhiyun# 12*4882a593Smuzhiyunlog_test() 13*4882a593Smuzhiyun{ 14*4882a593Smuzhiyun local rc=$1 15*4882a593Smuzhiyun local expected=$2 16*4882a593Smuzhiyun local msg="$3" 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun if [ ${rc} -eq ${expected} ]; then 19*4882a593Smuzhiyun printf "TEST: %-60s [ OK ]\n" "${msg}" 20*4882a593Smuzhiyun nsuccess=$((nsuccess+1)) 21*4882a593Smuzhiyun else 22*4882a593Smuzhiyun ret=1 23*4882a593Smuzhiyun nfail=$((nfail+1)) 24*4882a593Smuzhiyun printf "TEST: %-60s [FAIL]\n" "${msg}" 25*4882a593Smuzhiyun if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 26*4882a593Smuzhiyun echo 27*4882a593Smuzhiyun echo "hit enter to continue, 'q' to quit" 28*4882a593Smuzhiyun read a 29*4882a593Smuzhiyun [ "$a" = "q" ] && exit 1 30*4882a593Smuzhiyun fi 31*4882a593Smuzhiyun fi 32*4882a593Smuzhiyun} 33*4882a593Smuzhiyun 34*4882a593Smuzhiyunrun_cmd() 35*4882a593Smuzhiyun{ 36*4882a593Smuzhiyun local ns 37*4882a593Smuzhiyun local cmd 38*4882a593Smuzhiyun local out 39*4882a593Smuzhiyun local rc 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun ns="$1" 42*4882a593Smuzhiyun shift 43*4882a593Smuzhiyun cmd="$*" 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun if [ "$VERBOSE" = "1" ]; then 46*4882a593Smuzhiyun printf " COMMAND: $cmd\n" 47*4882a593Smuzhiyun fi 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun out=$(eval ip netns exec ${ns} ${cmd} 2>&1) 50*4882a593Smuzhiyun rc=$? 51*4882a593Smuzhiyun if [ "$VERBOSE" = "1" -a -n "$out" ]; then 52*4882a593Smuzhiyun echo " $out" 53*4882a593Smuzhiyun fi 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun [ "$VERBOSE" = "1" ] && echo 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun return $rc 58*4882a593Smuzhiyun} 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun################################################################################ 61*4882a593Smuzhiyun# create namespaces and interconnects 62*4882a593Smuzhiyun 63*4882a593Smuzhiyuncreate_ns() 64*4882a593Smuzhiyun{ 65*4882a593Smuzhiyun local ns=$1 66*4882a593Smuzhiyun local addr=$2 67*4882a593Smuzhiyun local addr6=$3 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun [ -z "${addr}" ] && addr="-" 70*4882a593Smuzhiyun [ -z "${addr6}" ] && addr6="-" 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun ip netns add ${ns} 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun ip netns exec ${ns} ip link set lo up 75*4882a593Smuzhiyun if [ "${addr}" != "-" ]; then 76*4882a593Smuzhiyun ip netns exec ${ns} ip addr add dev lo ${addr} 77*4882a593Smuzhiyun fi 78*4882a593Smuzhiyun if [ "${addr6}" != "-" ]; then 79*4882a593Smuzhiyun ip netns exec ${ns} ip -6 addr add dev lo ${addr6} 80*4882a593Smuzhiyun fi 81*4882a593Smuzhiyun 82*4882a593Smuzhiyun ip netns exec ${ns} ip ro add unreachable default metric 8192 83*4882a593Smuzhiyun ip netns exec ${ns} ip -6 ro add unreachable default metric 8192 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1 86*4882a593Smuzhiyun ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 87*4882a593Smuzhiyun ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1 88*4882a593Smuzhiyun ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1 89*4882a593Smuzhiyun ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.accept_dad=0 90*4882a593Smuzhiyun} 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun# create veth pair to connect namespaces and apply addresses. 93*4882a593Smuzhiyunconnect_ns() 94*4882a593Smuzhiyun{ 95*4882a593Smuzhiyun local ns1=$1 96*4882a593Smuzhiyun local ns1_dev=$2 97*4882a593Smuzhiyun local ns1_addr=$3 98*4882a593Smuzhiyun local ns1_addr6=$4 99*4882a593Smuzhiyun local ns2=$5 100*4882a593Smuzhiyun local ns2_dev=$6 101*4882a593Smuzhiyun local ns2_addr=$7 102*4882a593Smuzhiyun local ns2_addr6=$8 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun ip netns exec ${ns1} ip li add ${ns1_dev} type veth peer name tmp 105*4882a593Smuzhiyun ip netns exec ${ns1} ip li set ${ns1_dev} up 106*4882a593Smuzhiyun ip netns exec ${ns1} ip li set tmp netns ${ns2} name ${ns2_dev} 107*4882a593Smuzhiyun ip netns exec ${ns2} ip li set ${ns2_dev} up 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun if [ "${ns1_addr}" != "-" ]; then 110*4882a593Smuzhiyun ip netns exec ${ns1} ip addr add dev ${ns1_dev} ${ns1_addr} 111*4882a593Smuzhiyun fi 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun if [ "${ns2_addr}" != "-" ]; then 114*4882a593Smuzhiyun ip netns exec ${ns2} ip addr add dev ${ns2_dev} ${ns2_addr} 115*4882a593Smuzhiyun fi 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun if [ "${ns1_addr6}" != "-" ]; then 118*4882a593Smuzhiyun ip netns exec ${ns1} ip addr add dev ${ns1_dev} ${ns1_addr6} 119*4882a593Smuzhiyun fi 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun if [ "${ns2_addr6}" != "-" ]; then 122*4882a593Smuzhiyun ip netns exec ${ns2} ip addr add dev ${ns2_dev} ${ns2_addr6} 123*4882a593Smuzhiyun fi 124*4882a593Smuzhiyun} 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun################################################################################ 127*4882a593Smuzhiyun# traceroute6 test 128*4882a593Smuzhiyun# 129*4882a593Smuzhiyun# Verify that in this scenario 130*4882a593Smuzhiyun# 131*4882a593Smuzhiyun# ------------------------ N2 132*4882a593Smuzhiyun# | | 133*4882a593Smuzhiyun# ------ ------ N3 ---- 134*4882a593Smuzhiyun# | R1 | | R2 |------|H2| 135*4882a593Smuzhiyun# ------ ------ ---- 136*4882a593Smuzhiyun# | | 137*4882a593Smuzhiyun# ------------------------ N1 138*4882a593Smuzhiyun# | 139*4882a593Smuzhiyun# ---- 140*4882a593Smuzhiyun# |H1| 141*4882a593Smuzhiyun# ---- 142*4882a593Smuzhiyun# 143*4882a593Smuzhiyun# where H1's default route goes through R1 and R1's default route goes 144*4882a593Smuzhiyun# through R2 over N2, traceroute6 from H1 to H2 reports R2's address 145*4882a593Smuzhiyun# on N2 and not N1. 146*4882a593Smuzhiyun# 147*4882a593Smuzhiyun# Addresses are assigned as follows: 148*4882a593Smuzhiyun# 149*4882a593Smuzhiyun# N1: 2000:101::/64 150*4882a593Smuzhiyun# N2: 2000:102::/64 151*4882a593Smuzhiyun# N3: 2000:103::/64 152*4882a593Smuzhiyun# 153*4882a593Smuzhiyun# R1's host part of address: 1 154*4882a593Smuzhiyun# R2's host part of address: 2 155*4882a593Smuzhiyun# H1's host part of address: 3 156*4882a593Smuzhiyun# H2's host part of address: 4 157*4882a593Smuzhiyun# 158*4882a593Smuzhiyun# For example: 159*4882a593Smuzhiyun# the IPv6 address of R1's interface on N2 is 2000:102::1/64 160*4882a593Smuzhiyun 161*4882a593Smuzhiyuncleanup_traceroute6() 162*4882a593Smuzhiyun{ 163*4882a593Smuzhiyun local ns 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun for ns in host-1 host-2 router-1 router-2 166*4882a593Smuzhiyun do 167*4882a593Smuzhiyun ip netns del ${ns} 2>/dev/null 168*4882a593Smuzhiyun done 169*4882a593Smuzhiyun} 170*4882a593Smuzhiyun 171*4882a593Smuzhiyunsetup_traceroute6() 172*4882a593Smuzhiyun{ 173*4882a593Smuzhiyun brdev=br0 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun # start clean 176*4882a593Smuzhiyun cleanup_traceroute6 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun set -e 179*4882a593Smuzhiyun create_ns host-1 180*4882a593Smuzhiyun create_ns host-2 181*4882a593Smuzhiyun create_ns router-1 182*4882a593Smuzhiyun create_ns router-2 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun # Setup N3 185*4882a593Smuzhiyun connect_ns router-2 eth3 - 2000:103::2/64 host-2 eth3 - 2000:103::4/64 186*4882a593Smuzhiyun ip netns exec host-2 ip route add default via 2000:103::2 187*4882a593Smuzhiyun 188*4882a593Smuzhiyun # Setup N2 189*4882a593Smuzhiyun connect_ns router-1 eth2 - 2000:102::1/64 router-2 eth2 - 2000:102::2/64 190*4882a593Smuzhiyun ip netns exec router-1 ip route add default via 2000:102::2 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun # Setup N1. host-1 and router-2 connect to a bridge in router-1. 193*4882a593Smuzhiyun ip netns exec router-1 ip link add name ${brdev} type bridge 194*4882a593Smuzhiyun ip netns exec router-1 ip link set ${brdev} up 195*4882a593Smuzhiyun ip netns exec router-1 ip addr add 2000:101::1/64 dev ${brdev} 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun connect_ns host-1 eth0 - 2000:101::3/64 router-1 eth0 - - 198*4882a593Smuzhiyun ip netns exec router-1 ip link set dev eth0 master ${brdev} 199*4882a593Smuzhiyun ip netns exec host-1 ip route add default via 2000:101::1 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun connect_ns router-2 eth1 - 2000:101::2/64 router-1 eth1 - - 202*4882a593Smuzhiyun ip netns exec router-1 ip link set dev eth1 master ${brdev} 203*4882a593Smuzhiyun 204*4882a593Smuzhiyun # Prime the network 205*4882a593Smuzhiyun ip netns exec host-1 ping6 -c5 2000:103::4 >/dev/null 2>&1 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun set +e 208*4882a593Smuzhiyun} 209*4882a593Smuzhiyun 210*4882a593Smuzhiyunrun_traceroute6() 211*4882a593Smuzhiyun{ 212*4882a593Smuzhiyun if [ ! -x "$(command -v traceroute6)" ]; then 213*4882a593Smuzhiyun echo "SKIP: Could not run IPV6 test without traceroute6" 214*4882a593Smuzhiyun return 215*4882a593Smuzhiyun fi 216*4882a593Smuzhiyun 217*4882a593Smuzhiyun setup_traceroute6 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun # traceroute6 host-2 from host-1 (expects 2000:102::2) 220*4882a593Smuzhiyun run_cmd host-1 "traceroute6 2000:103::4 | grep -q 2000:102::2" 221*4882a593Smuzhiyun log_test $? 0 "IPV6 traceroute" 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun cleanup_traceroute6 224*4882a593Smuzhiyun} 225*4882a593Smuzhiyun 226*4882a593Smuzhiyun################################################################################ 227*4882a593Smuzhiyun# traceroute test 228*4882a593Smuzhiyun# 229*4882a593Smuzhiyun# Verify that traceroute from H1 to H2 shows 1.0.1.1 in this scenario 230*4882a593Smuzhiyun# 231*4882a593Smuzhiyun# 1.0.3.1/24 232*4882a593Smuzhiyun# ---- 1.0.1.3/24 1.0.1.1/24 ---- 1.0.2.1/24 1.0.2.4/24 ---- 233*4882a593Smuzhiyun# |H1|--------------------------|R1|--------------------------|H2| 234*4882a593Smuzhiyun# ---- N1 ---- N2 ---- 235*4882a593Smuzhiyun# 236*4882a593Smuzhiyun# where net.ipv4.icmp_errors_use_inbound_ifaddr is set on R1 and 237*4882a593Smuzhiyun# 1.0.3.1/24 and 1.0.1.1/24 are respectively R1's primary and secondary 238*4882a593Smuzhiyun# address on N1. 239*4882a593Smuzhiyun# 240*4882a593Smuzhiyun 241*4882a593Smuzhiyuncleanup_traceroute() 242*4882a593Smuzhiyun{ 243*4882a593Smuzhiyun local ns 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun for ns in host-1 host-2 router 246*4882a593Smuzhiyun do 247*4882a593Smuzhiyun ip netns del ${ns} 2>/dev/null 248*4882a593Smuzhiyun done 249*4882a593Smuzhiyun} 250*4882a593Smuzhiyun 251*4882a593Smuzhiyunsetup_traceroute() 252*4882a593Smuzhiyun{ 253*4882a593Smuzhiyun # start clean 254*4882a593Smuzhiyun cleanup_traceroute 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun set -e 257*4882a593Smuzhiyun create_ns host-1 258*4882a593Smuzhiyun create_ns host-2 259*4882a593Smuzhiyun create_ns router 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun connect_ns host-1 eth0 1.0.1.3/24 - \ 262*4882a593Smuzhiyun router eth1 1.0.3.1/24 - 263*4882a593Smuzhiyun ip netns exec host-1 ip route add default via 1.0.1.1 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun ip netns exec router ip addr add 1.0.1.1/24 dev eth1 266*4882a593Smuzhiyun ip netns exec router sysctl -qw \ 267*4882a593Smuzhiyun net.ipv4.icmp_errors_use_inbound_ifaddr=1 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun connect_ns host-2 eth0 1.0.2.4/24 - \ 270*4882a593Smuzhiyun router eth2 1.0.2.1/24 - 271*4882a593Smuzhiyun ip netns exec host-2 ip route add default via 1.0.2.1 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun # Prime the network 274*4882a593Smuzhiyun ip netns exec host-1 ping -c5 1.0.2.4 >/dev/null 2>&1 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun set +e 277*4882a593Smuzhiyun} 278*4882a593Smuzhiyun 279*4882a593Smuzhiyunrun_traceroute() 280*4882a593Smuzhiyun{ 281*4882a593Smuzhiyun if [ ! -x "$(command -v traceroute)" ]; then 282*4882a593Smuzhiyun echo "SKIP: Could not run IPV4 test without traceroute" 283*4882a593Smuzhiyun return 284*4882a593Smuzhiyun fi 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun setup_traceroute 287*4882a593Smuzhiyun 288*4882a593Smuzhiyun # traceroute host-2 from host-1 (expects 1.0.1.1). Takes a while. 289*4882a593Smuzhiyun run_cmd host-1 "traceroute 1.0.2.4 | grep -q 1.0.1.1" 290*4882a593Smuzhiyun log_test $? 0 "IPV4 traceroute" 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun cleanup_traceroute 293*4882a593Smuzhiyun} 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun################################################################################ 296*4882a593Smuzhiyun# Run tests 297*4882a593Smuzhiyun 298*4882a593Smuzhiyunrun_tests() 299*4882a593Smuzhiyun{ 300*4882a593Smuzhiyun run_traceroute6 301*4882a593Smuzhiyun run_traceroute 302*4882a593Smuzhiyun} 303*4882a593Smuzhiyun 304*4882a593Smuzhiyun################################################################################ 305*4882a593Smuzhiyun# main 306*4882a593Smuzhiyun 307*4882a593Smuzhiyundeclare -i nfail=0 308*4882a593Smuzhiyundeclare -i nsuccess=0 309*4882a593Smuzhiyun 310*4882a593Smuzhiyunwhile getopts :pv o 311*4882a593Smuzhiyundo 312*4882a593Smuzhiyun case $o in 313*4882a593Smuzhiyun p) PAUSE_ON_FAIL=yes;; 314*4882a593Smuzhiyun v) VERBOSE=$(($VERBOSE + 1));; 315*4882a593Smuzhiyun *) exit 1;; 316*4882a593Smuzhiyun esac 317*4882a593Smuzhiyundone 318*4882a593Smuzhiyun 319*4882a593Smuzhiyunrun_tests 320*4882a593Smuzhiyun 321*4882a593Smuzhiyunprintf "\nTests passed: %3d\n" ${nsuccess} 322*4882a593Smuzhiyunprintf "Tests failed: %3d\n" ${nfail} 323