test_lwt_ip_encap.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # Setup/topology:
  5. #
  6. # NS1 NS2 NS3
  7. # veth1 <---> veth2 veth3 <---> veth4 (the top route)
  8. # veth5 <---> veth6 veth7 <---> veth8 (the bottom route)
  9. #
  10. # each vethN gets IPv[4|6]_N address
  11. #
  12. # IPv*_SRC = IPv*_1
  13. # IPv*_DST = IPv*_4
  14. #
  15. # all tests test pings from IPv*_SRC to IPv*_DST
  16. #
  17. # by default, routes are configured to allow packets to go
  18. # IP*_1 <=> IP*_2 <=> IP*_3 <=> IP*_4 (the top route)
  19. #
  20. # a GRE device is installed in NS3 with IPv*_GRE, and
  21. # NS1/NS2 are configured to route packets to IPv*_GRE via IP*_8
  22. # (the bottom route)
  23. #
  24. # Tests:
  25. #
  26. # 1. routes NS2->IPv*_DST are brought down, so the only way a ping
  27. # from IP*_SRC to IP*_DST can work is via IPv*_GRE
  28. #
  29. # 2a. in an egress test, a bpf LWT_XMIT program is installed on veth1
  30. # that encaps the packets with an IP/GRE header to route to IPv*_GRE
  31. #
  32. # ping: SRC->[encap at veth1:egress]->GRE:decap->DST
  33. # ping replies go DST->SRC directly
  34. #
  35. # 2b. in an ingress test, a bpf LWT_IN program is installed on veth2
  36. # that encaps the packets with an IP/GRE header to route to IPv*_GRE
  37. #
  38. # ping: SRC->[encap at veth2:ingress]->GRE:decap->DST
  39. # ping replies go DST->SRC directly
  40. BPF_FILE="test_lwt_ip_encap.bpf.o"
  41. if [[ $EUID -ne 0 ]]; then
  42. echo "This script must be run as root"
  43. echo "FAIL"
  44. exit 1
  45. fi
  46. readonly NS1="ns1-$(mktemp -u XXXXXX)"
  47. readonly NS2="ns2-$(mktemp -u XXXXXX)"
  48. readonly NS3="ns3-$(mktemp -u XXXXXX)"
  49. readonly IPv4_1="172.16.1.100"
  50. readonly IPv4_2="172.16.2.100"
  51. readonly IPv4_3="172.16.3.100"
  52. readonly IPv4_4="172.16.4.100"
  53. readonly IPv4_5="172.16.5.100"
  54. readonly IPv4_6="172.16.6.100"
  55. readonly IPv4_7="172.16.7.100"
  56. readonly IPv4_8="172.16.8.100"
  57. readonly IPv4_GRE="172.16.16.100"
  58. readonly IPv4_SRC=$IPv4_1
  59. readonly IPv4_DST=$IPv4_4
  60. readonly IPv6_1="fb01::1"
  61. readonly IPv6_2="fb02::1"
  62. readonly IPv6_3="fb03::1"
  63. readonly IPv6_4="fb04::1"
  64. readonly IPv6_5="fb05::1"
  65. readonly IPv6_6="fb06::1"
  66. readonly IPv6_7="fb07::1"
  67. readonly IPv6_8="fb08::1"
  68. readonly IPv6_GRE="fb10::1"
  69. readonly IPv6_SRC=$IPv6_1
  70. readonly IPv6_DST=$IPv6_4
  71. TEST_STATUS=0
  72. TESTS_SUCCEEDED=0
  73. TESTS_FAILED=0
  74. TMPFILE=""
  75. process_test_results()
  76. {
  77. if [[ "${TEST_STATUS}" -eq 0 ]] ; then
  78. echo "PASS"
  79. TESTS_SUCCEEDED=$((TESTS_SUCCEEDED+1))
  80. else
  81. echo "FAIL"
  82. TESTS_FAILED=$((TESTS_FAILED+1))
  83. fi
  84. }
  85. print_test_summary_and_exit()
  86. {
  87. echo "passed tests: ${TESTS_SUCCEEDED}"
  88. echo "failed tests: ${TESTS_FAILED}"
  89. if [ "${TESTS_FAILED}" -eq "0" ] ; then
  90. exit 0
  91. else
  92. exit 1
  93. fi
  94. }
  95. setup()
  96. {
  97. set -e # exit on error
  98. TEST_STATUS=0
  99. # create devices and namespaces
  100. ip netns add "${NS1}"
  101. ip netns add "${NS2}"
  102. ip netns add "${NS3}"
  103. # rp_filter gets confused by what these tests are doing, so disable it
  104. ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0
  105. ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0
  106. ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0
  107. ip netns exec ${NS1} sysctl -wq net.ipv4.conf.default.rp_filter=0
  108. ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=0
  109. ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=0
  110. # disable IPv6 DAD because it sometimes takes too long and fails tests
  111. ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=0
  112. ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=0
  113. ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=0
  114. ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=0
  115. ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=0
  116. ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=0
  117. ip link add veth1 type veth peer name veth2
  118. ip link add veth3 type veth peer name veth4
  119. ip link add veth5 type veth peer name veth6
  120. ip link add veth7 type veth peer name veth8
  121. ip netns exec ${NS2} sysctl -wq net.ipv4.ip_forward=1
  122. ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.forwarding=1
  123. ip link set veth1 netns ${NS1}
  124. ip link set veth2 netns ${NS2}
  125. ip link set veth3 netns ${NS2}
  126. ip link set veth4 netns ${NS3}
  127. ip link set veth5 netns ${NS1}
  128. ip link set veth6 netns ${NS2}
  129. ip link set veth7 netns ${NS2}
  130. ip link set veth8 netns ${NS3}
  131. if [ ! -z "${VRF}" ] ; then
  132. ip -netns ${NS1} link add red type vrf table 1001
  133. ip -netns ${NS1} link set red up
  134. ip -netns ${NS1} route add table 1001 unreachable default metric 8192
  135. ip -netns ${NS1} -6 route add table 1001 unreachable default metric 8192
  136. ip -netns ${NS1} link set veth1 vrf red
  137. ip -netns ${NS1} link set veth5 vrf red
  138. ip -netns ${NS2} link add red type vrf table 1001
  139. ip -netns ${NS2} link set red up
  140. ip -netns ${NS2} route add table 1001 unreachable default metric 8192
  141. ip -netns ${NS2} -6 route add table 1001 unreachable default metric 8192
  142. ip -netns ${NS2} link set veth2 vrf red
  143. ip -netns ${NS2} link set veth3 vrf red
  144. ip -netns ${NS2} link set veth6 vrf red
  145. ip -netns ${NS2} link set veth7 vrf red
  146. fi
  147. # configure addesses: the top route (1-2-3-4)
  148. ip -netns ${NS1} addr add ${IPv4_1}/24 dev veth1
  149. ip -netns ${NS2} addr add ${IPv4_2}/24 dev veth2
  150. ip -netns ${NS2} addr add ${IPv4_3}/24 dev veth3
  151. ip -netns ${NS3} addr add ${IPv4_4}/24 dev veth4
  152. ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1
  153. ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2
  154. ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3
  155. ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4
  156. # configure addresses: the bottom route (5-6-7-8)
  157. ip -netns ${NS1} addr add ${IPv4_5}/24 dev veth5
  158. ip -netns ${NS2} addr add ${IPv4_6}/24 dev veth6
  159. ip -netns ${NS2} addr add ${IPv4_7}/24 dev veth7
  160. ip -netns ${NS3} addr add ${IPv4_8}/24 dev veth8
  161. ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5
  162. ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6
  163. ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7
  164. ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8
  165. ip -netns ${NS1} link set dev veth1 up
  166. ip -netns ${NS2} link set dev veth2 up
  167. ip -netns ${NS2} link set dev veth3 up
  168. ip -netns ${NS3} link set dev veth4 up
  169. ip -netns ${NS1} link set dev veth5 up
  170. ip -netns ${NS2} link set dev veth6 up
  171. ip -netns ${NS2} link set dev veth7 up
  172. ip -netns ${NS3} link set dev veth8 up
  173. # configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;
  174. # the bottom route to specific bottom addresses
  175. # NS1
  176. # top route
  177. ip -netns ${NS1} route add ${IPv4_2}/32 dev veth1 ${VRF}
  178. ip -netns ${NS1} route add default dev veth1 via ${IPv4_2} ${VRF} # go top by default
  179. ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1 ${VRF}
  180. ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} ${VRF} # go top by default
  181. # bottom route
  182. ip -netns ${NS1} route add ${IPv4_6}/32 dev veth5 ${VRF}
  183. ip -netns ${NS1} route add ${IPv4_7}/32 dev veth5 via ${IPv4_6} ${VRF}
  184. ip -netns ${NS1} route add ${IPv4_8}/32 dev veth5 via ${IPv4_6} ${VRF}
  185. ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5 ${VRF}
  186. ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6} ${VRF}
  187. ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6} ${VRF}
  188. # NS2
  189. # top route
  190. ip -netns ${NS2} route add ${IPv4_1}/32 dev veth2 ${VRF}
  191. ip -netns ${NS2} route add ${IPv4_4}/32 dev veth3 ${VRF}
  192. ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2 ${VRF}
  193. ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3 ${VRF}
  194. # bottom route
  195. ip -netns ${NS2} route add ${IPv4_5}/32 dev veth6 ${VRF}
  196. ip -netns ${NS2} route add ${IPv4_8}/32 dev veth7 ${VRF}
  197. ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6 ${VRF}
  198. ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7 ${VRF}
  199. # NS3
  200. # top route
  201. ip -netns ${NS3} route add ${IPv4_3}/32 dev veth4
  202. ip -netns ${NS3} route add ${IPv4_1}/32 dev veth4 via ${IPv4_3}
  203. ip -netns ${NS3} route add ${IPv4_2}/32 dev veth4 via ${IPv4_3}
  204. ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4
  205. ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}
  206. ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}
  207. # bottom route
  208. ip -netns ${NS3} route add ${IPv4_7}/32 dev veth8
  209. ip -netns ${NS3} route add ${IPv4_5}/32 dev veth8 via ${IPv4_7}
  210. ip -netns ${NS3} route add ${IPv4_6}/32 dev veth8 via ${IPv4_7}
  211. ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8
  212. ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}
  213. ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}
  214. # configure IPv4 GRE device in NS3, and a route to it via the "bottom" route
  215. ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255
  216. ip -netns ${NS3} link set gre_dev up
  217. ip -netns ${NS3} addr add ${IPv4_GRE} dev gre_dev
  218. ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6} ${VRF}
  219. ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8} ${VRF}
  220. # configure IPv6 GRE device in NS3, and a route to it via the "bottom" route
  221. ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255
  222. ip -netns ${NS3} link set gre6_dev up
  223. ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev
  224. ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6} ${VRF}
  225. ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8} ${VRF}
  226. TMPFILE=$(mktemp /tmp/test_lwt_ip_encap.XXXXXX)
  227. sleep 1 # reduce flakiness
  228. set +e
  229. }
  230. cleanup()
  231. {
  232. if [ -f ${TMPFILE} ] ; then
  233. rm ${TMPFILE}
  234. fi
  235. ip netns del ${NS1} 2> /dev/null
  236. ip netns del ${NS2} 2> /dev/null
  237. ip netns del ${NS3} 2> /dev/null
  238. }
  239. trap cleanup EXIT
  240. remove_routes_to_gredev()
  241. {
  242. ip -netns ${NS1} route del ${IPv4_GRE} dev veth5 ${VRF}
  243. ip -netns ${NS2} route del ${IPv4_GRE} dev veth7 ${VRF}
  244. ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5 ${VRF}
  245. ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7 ${VRF}
  246. }
  247. add_unreachable_routes_to_gredev()
  248. {
  249. ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32 ${VRF}
  250. ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32 ${VRF}
  251. ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
  252. ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
  253. }
  254. test_ping()
  255. {
  256. local readonly PROTO=$1
  257. local readonly EXPECTED=$2
  258. local RET=0
  259. if [ "${PROTO}" == "IPv4" ] ; then
  260. ip netns exec ${NS1} ping -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null
  261. RET=$?
  262. elif [ "${PROTO}" == "IPv6" ] ; then
  263. ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/null
  264. RET=$?
  265. else
  266. echo " test_ping: unknown PROTO: ${PROTO}"
  267. TEST_STATUS=1
  268. fi
  269. if [ "0" != "${RET}" ]; then
  270. RET=1
  271. fi
  272. if [ "${EXPECTED}" != "${RET}" ] ; then
  273. echo " test_ping failed: expected: ${EXPECTED}; got ${RET}"
  274. TEST_STATUS=1
  275. fi
  276. }
  277. test_gso()
  278. {
  279. local readonly PROTO=$1
  280. local readonly PKT_SZ=5000
  281. local IP_DST=""
  282. : > ${TMPFILE} # trim the capture file
  283. # check that nc is present
  284. command -v nc >/dev/null 2>&1 || \
  285. { echo >&2 "nc is not available: skipping TSO tests"; return; }
  286. # listen on port 9000, capture TCP into $TMPFILE
  287. if [ "${PROTO}" == "IPv4" ] ; then
  288. IP_DST=${IPv4_DST}
  289. ip netns exec ${NS3} bash -c \
  290. "nc -4 -l -p 9000 > ${TMPFILE} &"
  291. elif [ "${PROTO}" == "IPv6" ] ; then
  292. IP_DST=${IPv6_DST}
  293. ip netns exec ${NS3} bash -c \
  294. "nc -6 -l -p 9000 > ${TMPFILE} &"
  295. RET=$?
  296. else
  297. echo " test_gso: unknown PROTO: ${PROTO}"
  298. TEST_STATUS=1
  299. fi
  300. sleep 1 # let nc start listening
  301. # send a packet larger than MTU
  302. ip netns exec ${NS1} bash -c \
  303. "dd if=/dev/zero bs=$PKT_SZ count=1 > /dev/tcp/${IP_DST}/9000 2>/dev/null"
  304. sleep 2 # let the packet get delivered
  305. # verify we received all expected bytes
  306. SZ=$(stat -c %s ${TMPFILE})
  307. if [ "$SZ" != "$PKT_SZ" ] ; then
  308. echo " test_gso failed: ${PROTO}"
  309. TEST_STATUS=1
  310. fi
  311. }
  312. test_egress()
  313. {
  314. local readonly ENCAP=$1
  315. echo "starting egress ${ENCAP} encap test ${VRF}"
  316. setup
  317. # by default, pings work
  318. test_ping IPv4 0
  319. test_ping IPv6 0
  320. # remove NS2->DST routes, ping fails
  321. ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3 ${VRF}
  322. ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
  323. test_ping IPv4 1
  324. test_ping IPv6 1
  325. # install replacement routes (LWT/eBPF), pings succeed
  326. if [ "${ENCAP}" == "IPv4" ] ; then
  327. ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
  328. ${BPF_FILE} sec encap_gre dev veth1 ${VRF}
  329. ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
  330. ${BPF_FILE} sec encap_gre dev veth1 ${VRF}
  331. elif [ "${ENCAP}" == "IPv6" ] ; then
  332. ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
  333. ${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}
  334. ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
  335. ${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}
  336. else
  337. echo " unknown encap ${ENCAP}"
  338. TEST_STATUS=1
  339. fi
  340. test_ping IPv4 0
  341. test_ping IPv6 0
  342. # skip GSO tests with VRF: VRF routing needs properly assigned
  343. # source IP/device, which is easy to do with ping and hard with dd/nc.
  344. if [ -z "${VRF}" ] ; then
  345. test_gso IPv4
  346. test_gso IPv6
  347. fi
  348. # a negative test: remove routes to GRE devices: ping fails
  349. remove_routes_to_gredev
  350. test_ping IPv4 1
  351. test_ping IPv6 1
  352. # another negative test
  353. add_unreachable_routes_to_gredev
  354. test_ping IPv4 1
  355. test_ping IPv6 1
  356. cleanup
  357. process_test_results
  358. }
  359. test_ingress()
  360. {
  361. local readonly ENCAP=$1
  362. echo "starting ingress ${ENCAP} encap test ${VRF}"
  363. setup
  364. # need to wait a bit for IPv6 to autoconf, otherwise
  365. # ping6 sometimes fails with "unable to bind to address"
  366. # by default, pings work
  367. test_ping IPv4 0
  368. test_ping IPv6 0
  369. # remove NS2->DST routes, pings fail
  370. ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3 ${VRF}
  371. ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
  372. test_ping IPv4 1
  373. test_ping IPv6 1
  374. # install replacement routes (LWT/eBPF), pings succeed
  375. if [ "${ENCAP}" == "IPv4" ] ; then
  376. ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
  377. ${BPF_FILE} sec encap_gre dev veth2 ${VRF}
  378. ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
  379. ${BPF_FILE} sec encap_gre dev veth2 ${VRF}
  380. elif [ "${ENCAP}" == "IPv6" ] ; then
  381. ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
  382. ${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}
  383. ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
  384. ${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}
  385. else
  386. echo "FAIL: unknown encap ${ENCAP}"
  387. TEST_STATUS=1
  388. fi
  389. test_ping IPv4 0
  390. test_ping IPv6 0
  391. # a negative test: remove routes to GRE devices: ping fails
  392. remove_routes_to_gredev
  393. test_ping IPv4 1
  394. test_ping IPv6 1
  395. # another negative test
  396. add_unreachable_routes_to_gredev
  397. test_ping IPv4 1
  398. test_ping IPv6 1
  399. cleanup
  400. process_test_results
  401. }
  402. VRF=""
  403. test_egress IPv4
  404. test_egress IPv6
  405. test_ingress IPv4
  406. test_ingress IPv6
  407. VRF="vrf red"
  408. test_egress IPv4
  409. test_egress IPv6
  410. test_ingress IPv4
  411. test_ingress IPv6
  412. print_test_summary_and_exit