traceroute.sh 6.9 KB

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