test_tc_tunnel.sh 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # In-place tunneling
  5. BPF_FILE="test_tc_tunnel.bpf.o"
  6. # must match the port that the bpf program filters on
  7. readonly port=8000
  8. readonly ns_prefix="ns-$$-"
  9. readonly ns1="${ns_prefix}1"
  10. readonly ns2="${ns_prefix}2"
  11. readonly ns1_v4=192.168.1.1
  12. readonly ns2_v4=192.168.1.2
  13. readonly ns1_v6=fd::1
  14. readonly ns2_v6=fd::2
  15. # Must match port used by bpf program
  16. readonly udpport=5555
  17. # MPLSoverUDP
  18. readonly mplsudpport=6635
  19. readonly mplsproto=137
  20. readonly infile="$(mktemp)"
  21. readonly outfile="$(mktemp)"
  22. setup() {
  23. ip netns add "${ns1}"
  24. ip netns add "${ns2}"
  25. ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \
  26. peer name veth2 mtu 1500 netns "${ns2}"
  27. ip netns exec "${ns1}" ethtool -K veth1 tso off
  28. ip -netns "${ns1}" link set veth1 up
  29. ip -netns "${ns2}" link set veth2 up
  30. ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1
  31. ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2
  32. ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad
  33. ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad
  34. # clamp route to reserve room for tunnel headers
  35. ip -netns "${ns1}" -4 route flush table main
  36. ip -netns "${ns1}" -6 route flush table main
  37. ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1450 dev veth1
  38. ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1430 dev veth1
  39. sleep 1
  40. dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none
  41. }
  42. cleanup() {
  43. ip netns del "${ns2}"
  44. ip netns del "${ns1}"
  45. if [[ -f "${outfile}" ]]; then
  46. rm "${outfile}"
  47. fi
  48. if [[ -f "${infile}" ]]; then
  49. rm "${infile}"
  50. fi
  51. if [[ -n $server_pid ]]; then
  52. kill $server_pid 2> /dev/null
  53. fi
  54. }
  55. server_listen() {
  56. ip netns exec "${ns2}" nc "${netcat_opt}" -l "${port}" > "${outfile}" &
  57. server_pid=$!
  58. }
  59. client_connect() {
  60. ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}"
  61. echo $?
  62. }
  63. verify_data() {
  64. wait "${server_pid}"
  65. server_pid=
  66. # sha1sum returns two fields [sha1] [filepath]
  67. # convert to bash array and access first elem
  68. insum=($(sha1sum ${infile}))
  69. outsum=($(sha1sum ${outfile}))
  70. if [[ "${insum[0]}" != "${outsum[0]}" ]]; then
  71. echo "data mismatch"
  72. exit 1
  73. fi
  74. }
  75. wait_for_port() {
  76. for i in $(seq 20); do
  77. if ip netns exec "${ns2}" ss ${2:--4}OHntl | grep -q "$1"; then
  78. return 0
  79. fi
  80. sleep 0.1
  81. done
  82. return 1
  83. }
  84. set -e
  85. # no arguments: automated test, run all
  86. if [[ "$#" -eq "0" ]]; then
  87. echo "ipip"
  88. $0 ipv4 ipip none 100
  89. echo "ipip6"
  90. $0 ipv4 ipip6 none 100
  91. echo "ip6ip6"
  92. $0 ipv6 ip6tnl none 100
  93. echo "sit"
  94. $0 ipv6 sit none 100
  95. echo "ip4 vxlan"
  96. $0 ipv4 vxlan eth 2000
  97. echo "ip6 vxlan"
  98. $0 ipv6 ip6vxlan eth 2000
  99. for mac in none mpls eth ; do
  100. echo "ip gre $mac"
  101. $0 ipv4 gre $mac 100
  102. echo "ip6 gre $mac"
  103. $0 ipv6 ip6gre $mac 100
  104. echo "ip gre $mac gso"
  105. $0 ipv4 gre $mac 2000
  106. echo "ip6 gre $mac gso"
  107. $0 ipv6 ip6gre $mac 2000
  108. echo "ip udp $mac"
  109. $0 ipv4 udp $mac 100
  110. echo "ip6 udp $mac"
  111. $0 ipv6 ip6udp $mac 100
  112. echo "ip udp $mac gso"
  113. $0 ipv4 udp $mac 2000
  114. echo "ip6 udp $mac gso"
  115. $0 ipv6 ip6udp $mac 2000
  116. done
  117. echo "OK. All tests passed"
  118. exit 0
  119. fi
  120. if [[ "$#" -ne "4" ]]; then
  121. echo "Usage: $0"
  122. echo " or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>"
  123. exit 1
  124. fi
  125. case "$1" in
  126. "ipv4")
  127. readonly addr1="${ns1_v4}"
  128. readonly addr2="${ns2_v4}"
  129. readonly ipproto=4
  130. readonly netcat_opt=-${ipproto}
  131. readonly foumod=fou
  132. readonly foutype=ipip
  133. readonly fouproto=4
  134. readonly fouproto_mpls=${mplsproto}
  135. readonly gretaptype=gretap
  136. ;;
  137. "ipv6")
  138. readonly addr1="${ns1_v6}"
  139. readonly addr2="${ns2_v6}"
  140. readonly ipproto=6
  141. readonly netcat_opt=-${ipproto}
  142. readonly foumod=fou6
  143. readonly foutype=ip6tnl
  144. readonly fouproto="41 -6"
  145. readonly fouproto_mpls="${mplsproto} -6"
  146. readonly gretaptype=ip6gretap
  147. ;;
  148. *)
  149. echo "unknown arg: $1"
  150. exit 1
  151. ;;
  152. esac
  153. readonly tuntype=$2
  154. readonly mac=$3
  155. readonly datalen=$4
  156. echo "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}"
  157. trap cleanup EXIT
  158. setup
  159. # basic communication works
  160. echo "test basic connectivity"
  161. server_listen
  162. wait_for_port ${port} ${netcat_opt}
  163. client_connect
  164. verify_data
  165. # clientside, insert bpf program to encap all TCP to port ${port}
  166. # client can no longer connect
  167. ip netns exec "${ns1}" tc qdisc add dev veth1 clsact
  168. ip netns exec "${ns1}" tc filter add dev veth1 egress \
  169. bpf direct-action object-file ${BPF_FILE} \
  170. section "encap_${tuntype}_${mac}"
  171. echo "test bpf encap without decap (expect failure)"
  172. server_listen
  173. wait_for_port ${port} ${netcat_opt}
  174. ! client_connect
  175. if [[ "$tuntype" =~ "udp" ]]; then
  176. # Set up fou tunnel.
  177. ttype="${foutype}"
  178. targs="encap fou encap-sport auto encap-dport $udpport"
  179. # fou may be a module; allow this to fail.
  180. modprobe "${foumod}" ||true
  181. if [[ "$mac" == "mpls" ]]; then
  182. dport=${mplsudpport}
  183. dproto=${fouproto_mpls}
  184. tmode="mode any ttl 255"
  185. else
  186. dport=${udpport}
  187. dproto=${fouproto}
  188. fi
  189. ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto}
  190. targs="encap fou encap-sport auto encap-dport $dport"
  191. elif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
  192. ttype=$gretaptype
  193. elif [[ "$tuntype" =~ "vxlan" && "$mac" == "eth" ]]; then
  194. ttype="vxlan"
  195. targs="id 1 dstport 8472 udp6zerocsumrx"
  196. elif [[ "$tuntype" == "ipip6" ]]; then
  197. ttype="ip6tnl"
  198. targs=""
  199. else
  200. ttype=$tuntype
  201. targs=""
  202. fi
  203. # tunnel address family differs from inner for SIT
  204. if [[ "${tuntype}" == "sit" ]]; then
  205. link_addr1="${ns1_v4}"
  206. link_addr2="${ns2_v4}"
  207. elif [[ "${tuntype}" == "ipip6" ]]; then
  208. link_addr1="${ns1_v6}"
  209. link_addr2="${ns2_v6}"
  210. else
  211. link_addr1="${addr1}"
  212. link_addr2="${addr2}"
  213. fi
  214. # serverside, insert decap module
  215. # server is still running
  216. # client can connect again
  217. ip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \
  218. ${tmode} remote "${link_addr1}" local "${link_addr2}" $targs
  219. expect_tun_fail=0
  220. if [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then
  221. # No support for MPLS IPv6 fou tunnel; expect failure.
  222. expect_tun_fail=1
  223. elif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then
  224. # No support for TEB fou tunnel; expect failure.
  225. expect_tun_fail=1
  226. elif [[ "$tuntype" =~ (gre|vxlan) && "$mac" == "eth" ]]; then
  227. # Share ethernet address between tunnel/veth2 so L2 decap works.
  228. ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \
  229. awk '/ether/ { print $2 }')
  230. ip netns exec "${ns2}" ip link set testtun0 address $ethaddr
  231. elif [[ "$mac" == "mpls" ]]; then
  232. modprobe mpls_iptunnel ||true
  233. modprobe mpls_gso ||true
  234. ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536
  235. ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo
  236. ip netns exec "${ns2}" ip link set lo up
  237. ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1
  238. ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0
  239. fi
  240. # Because packets are decapped by the tunnel they arrive on testtun0 from
  241. # the IP stack perspective. Ensure reverse path filtering is disabled
  242. # otherwise we drop the TCP SYN as arriving on testtun0 instead of the
  243. # expected veth2 (veth2 is where 192.168.1.2 is configured).
  244. ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0
  245. # rp needs to be disabled for both all and testtun0 as the rp value is
  246. # selected as the max of the "all" and device-specific values.
  247. ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0
  248. ip netns exec "${ns2}" ip link set dev testtun0 up
  249. if [[ "$expect_tun_fail" == 1 ]]; then
  250. # This tunnel mode is not supported, so we expect failure.
  251. echo "test bpf encap with tunnel device decap (expect failure)"
  252. ! client_connect
  253. else
  254. echo "test bpf encap with tunnel device decap"
  255. client_connect
  256. verify_data
  257. server_listen
  258. wait_for_port ${port} ${netcat_opt}
  259. fi
  260. # serverside, use BPF for decap
  261. ip netns exec "${ns2}" ip link del dev testtun0
  262. ip netns exec "${ns2}" tc qdisc add dev veth2 clsact
  263. ip netns exec "${ns2}" tc filter add dev veth2 ingress \
  264. bpf direct-action object-file ${BPF_FILE} section decap
  265. echo "test bpf encap with bpf decap"
  266. client_connect
  267. verify_data
  268. echo OK