mptcp_connect.sh 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. # Double quotes to prevent globbing and word splitting is recommended in new
  4. # code but we accept it, especially because there were too many before having
  5. # address all other issues detected by shellcheck.
  6. #shellcheck disable=SC2086
  7. . "$(dirname "${0}")/mptcp_lib.sh"
  8. time_start=$(date +%s)
  9. optstring="S:R:d:e:l:r:h4cm:f:tC"
  10. ret=0
  11. final_ret=0
  12. sin=""
  13. sout=""
  14. cin_disconnect=""
  15. cin=""
  16. cout=""
  17. capture=false
  18. timeout_poll=30
  19. timeout_test=$((timeout_poll * 2 + 1))
  20. ipv6=true
  21. ethtool_random_on=true
  22. tc_delay="$((RANDOM%50))"
  23. tc_loss=$((RANDOM%101))
  24. testmode=""
  25. sndbuf=0
  26. rcvbuf=0
  27. options_log=true
  28. do_tcp=0
  29. checksum=false
  30. filesize=0
  31. connect_per_transfer=1
  32. port=$((10000 - 1))
  33. if [ $tc_loss -eq 100 ];then
  34. tc_loss=1%
  35. elif [ $tc_loss -ge 10 ]; then
  36. tc_loss=0.$tc_loss%
  37. elif [ $tc_loss -ge 1 ]; then
  38. tc_loss=0.0$tc_loss%
  39. else
  40. tc_loss=""
  41. fi
  42. usage() {
  43. echo "Usage: $0 [ -a ]"
  44. echo -e "\t-d: tc/netem delay in milliseconds, e.g. \"-d 10\" (default random)"
  45. echo -e "\t-l: tc/netem loss percentage, e.g. \"-l 0.02\" (default random)"
  46. echo -e "\t-r: tc/netem reorder mode, e.g. \"-r 25% 50% gap 5\", use "-r 0" to disable reordering (default random)"
  47. echo -e "\t-e: ethtool features to disable, e.g.: \"-e tso -e gso\" (default: randomly disable any of tso/gso/gro)"
  48. echo -e "\t-4: IPv4 only: disable IPv6 tests (default: test both IPv4 and IPv6)"
  49. echo -e "\t-c: capture packets for each test using tcpdump (default: no capture)"
  50. echo -e "\t-f: size of file to transfer in bytes (default random)"
  51. echo -e "\t-S: set sndbuf value (default: use kernel default)"
  52. echo -e "\t-R: set rcvbuf value (default: use kernel default)"
  53. echo -e "\t-m: test mode (poll, sendfile; default: poll)"
  54. echo -e "\t-t: also run tests with TCP (use twice to non-fallback tcp)"
  55. echo -e "\t-C: enable the MPTCP data checksum"
  56. }
  57. while getopts "$optstring" option;do
  58. case "$option" in
  59. "h")
  60. usage $0
  61. exit ${KSFT_PASS}
  62. ;;
  63. "d")
  64. if [ $OPTARG -ge 0 ];then
  65. tc_delay="$OPTARG"
  66. else
  67. echo "-d requires numeric argument, got \"$OPTARG\"" 1>&2
  68. exit ${KSFT_FAIL}
  69. fi
  70. ;;
  71. "e")
  72. ethtool_args="$ethtool_args $OPTARG off"
  73. ethtool_random_on=false
  74. ;;
  75. "l")
  76. tc_loss="$OPTARG"
  77. ;;
  78. "r")
  79. tc_reorder="$OPTARG"
  80. ;;
  81. "4")
  82. ipv6=false
  83. ;;
  84. "c")
  85. capture=true
  86. ;;
  87. "S")
  88. if [ $OPTARG -ge 0 ];then
  89. sndbuf="$OPTARG"
  90. else
  91. echo "-S requires numeric argument, got \"$OPTARG\"" 1>&2
  92. exit ${KSFT_FAIL}
  93. fi
  94. ;;
  95. "R")
  96. if [ $OPTARG -ge 0 ];then
  97. rcvbuf="$OPTARG"
  98. else
  99. echo "-R requires numeric argument, got \"$OPTARG\"" 1>&2
  100. exit ${KSFT_FAIL}
  101. fi
  102. ;;
  103. "m")
  104. testmode="$OPTARG"
  105. ;;
  106. "f")
  107. filesize="$OPTARG"
  108. ;;
  109. "t")
  110. do_tcp=$((do_tcp+1))
  111. ;;
  112. "C")
  113. checksum=true
  114. ;;
  115. "?")
  116. usage $0
  117. exit ${KSFT_FAIL}
  118. ;;
  119. esac
  120. done
  121. ns1=""
  122. ns2=""
  123. ns3=""
  124. ns4=""
  125. TEST_GROUP=""
  126. # This function is used in the cleanup trap
  127. #shellcheck disable=SC2317,SC2329
  128. cleanup()
  129. {
  130. rm -f "$cin_disconnect"
  131. rm -f "$cin" "$cout"
  132. rm -f "$sin" "$sout"
  133. rm -f "$capout"
  134. mptcp_lib_ns_exit "${ns1}" "${ns2}" "${ns3}" "${ns4}"
  135. }
  136. mptcp_lib_check_mptcp
  137. mptcp_lib_check_kallsyms
  138. mptcp_lib_check_tools ip tc
  139. sin=$(mktemp)
  140. sout=$(mktemp)
  141. cin=$(mktemp)
  142. cout=$(mktemp)
  143. capout=$(mktemp)
  144. cin_disconnect="$cin".disconnect
  145. trap cleanup EXIT
  146. mptcp_lib_ns_init ns1 ns2 ns3 ns4
  147. # "$ns1" ns2 ns3 ns4
  148. # ns1eth2 ns2eth1 ns2eth3 ns3eth2 ns3eth4 ns4eth3
  149. # - drop 1% -> reorder 25%
  150. # <- TSO off -
  151. ip link add ns1eth2 netns "$ns1" type veth peer name ns2eth1 netns "$ns2"
  152. ip link add ns2eth3 netns "$ns2" type veth peer name ns3eth2 netns "$ns3"
  153. ip link add ns3eth4 netns "$ns3" type veth peer name ns4eth3 netns "$ns4"
  154. ip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth2
  155. ip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth2 nodad
  156. ip -net "$ns1" link set ns1eth2 up
  157. ip -net "$ns1" route add default via 10.0.1.2
  158. ip -net "$ns1" route add default via dead:beef:1::2
  159. ip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1
  160. ip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad
  161. ip -net "$ns2" link set ns2eth1 up
  162. ip -net "$ns2" addr add 10.0.2.1/24 dev ns2eth3
  163. ip -net "$ns2" addr add dead:beef:2::1/64 dev ns2eth3 nodad
  164. ip -net "$ns2" link set ns2eth3 up
  165. ip -net "$ns2" route add default via 10.0.2.2
  166. ip -net "$ns2" route add default via dead:beef:2::2
  167. ip netns exec "$ns2" sysctl -q net.ipv4.ip_forward=1
  168. ip netns exec "$ns2" sysctl -q net.ipv6.conf.all.forwarding=1
  169. ip -net "$ns3" addr add 10.0.2.2/24 dev ns3eth2
  170. ip -net "$ns3" addr add dead:beef:2::2/64 dev ns3eth2 nodad
  171. ip -net "$ns3" link set ns3eth2 up
  172. ip -net "$ns3" addr add 10.0.3.2/24 dev ns3eth4
  173. ip -net "$ns3" addr add dead:beef:3::2/64 dev ns3eth4 nodad
  174. ip -net "$ns3" link set ns3eth4 up
  175. ip -net "$ns3" route add default via 10.0.2.1
  176. ip -net "$ns3" route add default via dead:beef:2::1
  177. ip netns exec "$ns3" sysctl -q net.ipv4.ip_forward=1
  178. ip netns exec "$ns3" sysctl -q net.ipv6.conf.all.forwarding=1
  179. ip -net "$ns4" addr add 10.0.3.1/24 dev ns4eth3
  180. ip -net "$ns4" addr add dead:beef:3::1/64 dev ns4eth3 nodad
  181. ip -net "$ns4" link set ns4eth3 up
  182. ip -net "$ns4" route add default via 10.0.3.2
  183. ip -net "$ns4" route add default via dead:beef:3::2
  184. if $checksum; then
  185. for i in "$ns1" "$ns2" "$ns3" "$ns4";do
  186. ip netns exec $i sysctl -q net.mptcp.checksum_enabled=1
  187. done
  188. fi
  189. if $capture; then
  190. rndh="${ns1:4}"
  191. mptcp_lib_pr_info "Packet capture files will have this prefix: ${rndh}-"
  192. fi
  193. set_ethtool_flags() {
  194. local ns="$1"
  195. local dev="$2"
  196. local flags="$3"
  197. if ip netns exec $ns ethtool -K $dev $flags 2>/dev/null; then
  198. mptcp_lib_pr_info "set $ns dev $dev: ethtool -K $flags"
  199. fi
  200. }
  201. set_random_ethtool_flags() {
  202. local flags=""
  203. local r=$RANDOM
  204. local pick1=$((r & 1))
  205. local pick2=$((r & 2))
  206. local pick3=$((r & 4))
  207. [ $pick1 -ne 0 ] && flags="tso off"
  208. [ $pick2 -ne 0 ] && flags="$flags gso off"
  209. [ $pick3 -ne 0 ] && flags="$flags gro off"
  210. [ -z "$flags" ] && return
  211. set_ethtool_flags "$1" "$2" "$flags"
  212. }
  213. if $ethtool_random_on;then
  214. set_random_ethtool_flags "$ns3" ns3eth2
  215. set_random_ethtool_flags "$ns4" ns4eth3
  216. else
  217. set_ethtool_flags "$ns3" ns3eth2 "$ethtool_args"
  218. set_ethtool_flags "$ns4" ns4eth3 "$ethtool_args"
  219. fi
  220. print_larger_title() {
  221. # here we don't have the time, a bit longer for the alignment
  222. MPTCP_LIB_TEST_FORMAT="%02u %-69s" \
  223. mptcp_lib_print_title "${@}"
  224. }
  225. check_mptcp_disabled()
  226. {
  227. local disabled_ns
  228. mptcp_lib_ns_init disabled_ns
  229. print_larger_title "New MPTCP socket can be blocked via sysctl"
  230. # mainly to cover more code
  231. if ! ip netns exec ${disabled_ns} sysctl net.mptcp >/dev/null; then
  232. mptcp_lib_pr_fail "not able to list net.mptcp sysctl knobs"
  233. mptcp_lib_result_fail "not able to list net.mptcp sysctl knobs"
  234. ret=${KSFT_FAIL}
  235. return 1
  236. fi
  237. # net.mptcp.enabled should be enabled by default
  238. if [ "$(ip netns exec ${disabled_ns} sysctl net.mptcp.enabled | awk '{ print $3 }')" -ne 1 ]; then
  239. mptcp_lib_pr_fail "net.mptcp.enabled sysctl is not 1 by default"
  240. mptcp_lib_result_fail "net.mptcp.enabled sysctl is not 1 by default"
  241. ret=${KSFT_FAIL}
  242. return 1
  243. fi
  244. ip netns exec ${disabled_ns} sysctl -q net.mptcp.enabled=0
  245. local err=0
  246. LC_ALL=C ip netns exec ${disabled_ns} ./mptcp_connect -p 10000 -s MPTCP 127.0.0.1 < "$cin" 2>&1 | \
  247. grep -q "^socket: Protocol not available$" && err=1
  248. mptcp_lib_ns_exit "${disabled_ns}"
  249. if [ ${err} -eq 0 ]; then
  250. mptcp_lib_pr_fail "New MPTCP socket cannot be blocked via sysctl"
  251. mptcp_lib_result_fail "New MPTCP socket cannot be blocked via sysctl"
  252. ret=${KSFT_FAIL}
  253. return 1
  254. fi
  255. mptcp_lib_pr_ok
  256. mptcp_lib_result_pass "New MPTCP socket can be blocked via sysctl"
  257. return 0
  258. }
  259. do_ping()
  260. {
  261. local listener_ns="$1"
  262. local connector_ns="$2"
  263. local connect_addr="$3"
  264. local ping_args="-q -c 1"
  265. local rc=0
  266. if mptcp_lib_is_v6 "${connect_addr}"; then
  267. $ipv6 || return 0
  268. ping_args="${ping_args} -6"
  269. fi
  270. ip netns exec ${connector_ns} ping ${ping_args} $connect_addr >/dev/null || rc=1
  271. if [ $rc -ne 0 ] ; then
  272. mptcp_lib_pr_fail "$listener_ns -> $connect_addr connectivity"
  273. ret=${KSFT_FAIL}
  274. return 1
  275. fi
  276. return 0
  277. }
  278. do_transfer()
  279. {
  280. local listener_ns="$1"
  281. local connector_ns="$2"
  282. local cl_proto="$3"
  283. local srv_proto="$4"
  284. local connect_addr="$5"
  285. local local_addr="$6"
  286. local extra_args="$7"
  287. port=$((port + 1))
  288. if [ "$rcvbuf" -gt 0 ]; then
  289. extra_args+=" -R $rcvbuf"
  290. fi
  291. if [ "$sndbuf" -gt 0 ]; then
  292. extra_args+=" -S $sndbuf"
  293. fi
  294. if [ -n "$testmode" ]; then
  295. extra_args+=" -m $testmode"
  296. fi
  297. if [ -n "$extra_args" ] && $options_log; then
  298. mptcp_lib_pr_info "extra options: $extra_args"
  299. fi
  300. options_log=false
  301. :> "$cout"
  302. :> "$sout"
  303. :> "$capout"
  304. local addr_port
  305. addr_port=$(printf "%s:%d" ${connect_addr} ${port})
  306. local pretty_title
  307. pretty_title="$(printf "%.3s %-5s -> %.3s (%-20s) %-5s" ${connector_ns} ${cl_proto} ${listener_ns} ${addr_port} ${srv_proto})"
  308. mptcp_lib_print_title "${pretty_title}"
  309. local tap_title="${connector_ns:0:3} ${cl_proto} -> ${listener_ns:0:3} (${addr_port}) ${srv_proto}"
  310. if $capture; then
  311. local capuser
  312. if [ -z $SUDO_USER ] ; then
  313. capuser=""
  314. else
  315. capuser="-Z $SUDO_USER"
  316. fi
  317. local capfile="${rndh}-${connector_ns:0:3}-${listener_ns:0:3}-${cl_proto}-${srv_proto}-${connect_addr}-${port}"
  318. local capopt="-i any -s 65535 -B 32768 ${capuser}"
  319. ip netns exec ${listener_ns} tcpdump ${capopt} \
  320. -w "${capfile}-listener.pcap" >> "${capout}" 2>&1 &
  321. local cappid_listener=$!
  322. if [ ${listener_ns} != ${connector_ns} ]; then
  323. ip netns exec ${connector_ns} tcpdump ${capopt} \
  324. -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 &
  325. local cappid_connector=$!
  326. fi
  327. sleep 1
  328. fi
  329. mptcp_lib_nstat_init "${listener_ns}"
  330. if [ ${listener_ns} != ${connector_ns} ]; then
  331. mptcp_lib_nstat_init "${connector_ns}"
  332. fi
  333. ip netns exec ${listener_ns} \
  334. ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \
  335. $extra_args $local_addr < "$sin" > "$sout" &
  336. local spid=$!
  337. mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}"
  338. local start
  339. start=$(date +%s%3N)
  340. ip netns exec ${connector_ns} \
  341. ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \
  342. $extra_args $connect_addr < "$cin" > "$cout" &
  343. local cpid=$!
  344. mptcp_lib_wait_timeout "${timeout_test}" "${listener_ns}" \
  345. "${connector_ns}" "${port}" "${cpid}" "${spid}" &
  346. local timeout_pid=$!
  347. wait $cpid
  348. local retc=$?
  349. wait $spid
  350. local rets=$?
  351. if kill -0 $timeout_pid; then
  352. # Finished before the timeout: kill the background job
  353. mptcp_lib_kill_group_wait $timeout_pid
  354. timeout_pid=0
  355. fi
  356. local stop
  357. stop=$(date +%s%3N)
  358. if $capture; then
  359. sleep 1
  360. kill ${cappid_listener}
  361. if [ ${listener_ns} != ${connector_ns} ]; then
  362. kill ${cappid_connector}
  363. fi
  364. fi
  365. mptcp_lib_nstat_get "${listener_ns}"
  366. if [ ${listener_ns} != ${connector_ns} ]; then
  367. mptcp_lib_nstat_get "${connector_ns}"
  368. fi
  369. local duration
  370. duration=$((stop-start))
  371. printf "(duration %05sms) " "${duration}"
  372. if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ] || [ ${timeout_pid} -ne 0 ]; then
  373. mptcp_lib_pr_fail "client exit code $retc, server $rets"
  374. mptcp_lib_pr_err_stats "${listener_ns}" "${connector_ns}" "${port}"
  375. echo
  376. cat "$capout"
  377. mptcp_lib_result_fail "${TEST_GROUP}: ${tap_title}"
  378. return 1
  379. fi
  380. mptcp_lib_check_transfer $sin $cout "file received by client"
  381. retc=$?
  382. mptcp_lib_check_transfer $cin $sout "file received by server"
  383. rets=$?
  384. local extra=""
  385. local stat_synrx
  386. local stat_ackrx
  387. local stat_cookietx
  388. local stat_cookierx
  389. local stat_ooo
  390. local stat_tcpfb
  391. stat_synrx=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX")
  392. stat_ackrx=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX")
  393. stat_cookietx=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent")
  394. stat_cookierx=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv")
  395. stat_ooo=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtTCPOFOQueue")
  396. stat_tcpfb=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableFallbackACK")
  397. expect_synrx=0
  398. expect_ackrx=0
  399. cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies)
  400. cookies=${cookies##*=}
  401. if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then
  402. expect_synrx=${connect_per_transfer}
  403. expect_ackrx=${connect_per_transfer}
  404. fi
  405. if [ ${stat_synrx} -lt ${expect_synrx} ]; then
  406. mptcp_lib_pr_fail "lower MPC SYN rx (${stat_synrx})" \
  407. "than expected (${expect_synrx})"
  408. retc=1
  409. fi
  410. if [ ${stat_ackrx} -lt ${expect_ackrx} ]; then
  411. if [ ${stat_ooo} -eq 0 ]; then
  412. mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx})" \
  413. "than expected (${expect_ackrx})"
  414. rets=1
  415. else
  416. extra+=" [ Note ] fallback due to TCP OoO"
  417. fi
  418. fi
  419. if $checksum; then
  420. local csum_err_s
  421. local csum_err_c
  422. csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr")
  423. csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr")
  424. if [ $csum_err_s -gt 0 ]; then
  425. mptcp_lib_pr_fail "server got ${csum_err_s} data checksum error[s]"
  426. rets=1
  427. fi
  428. if [ $csum_err_c -gt 0 ]; then
  429. mptcp_lib_pr_fail "client got ${csum_err_c} data checksum error[s]"
  430. retc=1
  431. fi
  432. fi
  433. if [ ${stat_ooo} -eq 0 ] && [ ${stat_tcpfb} -gt 0 ]; then
  434. mptcp_lib_pr_fail "unexpected fallback to TCP"
  435. rets=1
  436. fi
  437. if [ $cookies -eq 2 ];then
  438. if [ $stat_cookietx -eq 0 ] ;then
  439. extra+=" WARN: CookieSent: did not advance"
  440. fi
  441. if [ $stat_cookierx -eq 0 ] ;then
  442. extra+=" WARN: CookieRecv: did not advance"
  443. fi
  444. else
  445. if [ $stat_cookietx -gt 0 ] ;then
  446. extra+=" WARN: CookieSent: changed"
  447. fi
  448. if [ $stat_cookierx -gt 0 ] ;then
  449. extra+=" WARN: CookieRecv: changed"
  450. fi
  451. fi
  452. if [ ${stat_synrx} -gt ${expect_synrx} ]; then
  453. extra+=" WARN: SYNRX: expect ${expect_synrx},"
  454. extra+=" got ${stat_synrx} (probably retransmissions)"
  455. fi
  456. if [ ${stat_ackrx} -gt ${expect_ackrx} ]; then
  457. extra+=" WARN: ACKRX: expect ${expect_ackrx},"
  458. extra+=" got ${stat_ackrx} (probably retransmissions)"
  459. fi
  460. if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then
  461. mptcp_lib_pr_ok "${extra:1}"
  462. mptcp_lib_result_pass "${TEST_GROUP}: ${tap_title}"
  463. else
  464. if [ -n "${extra}" ]; then
  465. mptcp_lib_print_warn "${extra:1}"
  466. fi
  467. mptcp_lib_result_fail "${TEST_GROUP}: ${tap_title}"
  468. fi
  469. cat "$capout"
  470. [ $retc -eq 0 ] && [ $rets -eq 0 ]
  471. }
  472. make_file()
  473. {
  474. local name=$1
  475. local who=$2
  476. local SIZE=$filesize
  477. local ksize
  478. local rem
  479. if [ $SIZE -eq 0 ]; then
  480. local MAXSIZE=$((1024 * 1024 * 8))
  481. local MINSIZE=$((1024 * 256))
  482. SIZE=$(((RANDOM * RANDOM + MINSIZE) % MAXSIZE))
  483. fi
  484. ksize=$((SIZE / 1024))
  485. rem=$((SIZE - (ksize * 1024)))
  486. mptcp_lib_make_file $name 1024 $ksize
  487. dd if=/dev/urandom conv=notrunc of="$name" oflag=append bs=1 count=$rem 2> /dev/null
  488. echo "Created $name (size $(stat -c "%s" "$name") B) containing data sent by $who"
  489. }
  490. run_tests_lo()
  491. {
  492. local listener_ns="$1"
  493. local connector_ns="$2"
  494. local connect_addr="$3"
  495. local loopback="$4"
  496. local extra_args="$5"
  497. local lret=0
  498. # skip if test programs are running inside same netns for subsequent runs.
  499. if [ $loopback -eq 0 ] && [ ${listener_ns} = ${connector_ns} ]; then
  500. return 0
  501. fi
  502. # skip if we don't want v6
  503. if ! $ipv6 && mptcp_lib_is_v6 "${connect_addr}"; then
  504. return 0
  505. fi
  506. local local_addr
  507. if mptcp_lib_is_v6 "${connect_addr}"; then
  508. local_addr="::"
  509. else
  510. local_addr="0.0.0.0"
  511. fi
  512. do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \
  513. ${connect_addr} ${local_addr} "${extra_args}"
  514. lret=$?
  515. if [ $lret -ne 0 ]; then
  516. ret=$lret
  517. return 1
  518. fi
  519. if [ $do_tcp -eq 0 ]; then
  520. # don't bother testing fallback tcp except for loopback case.
  521. if [ ${listener_ns} != ${connector_ns} ]; then
  522. return 0
  523. fi
  524. fi
  525. do_transfer ${listener_ns} ${connector_ns} MPTCP TCP \
  526. ${connect_addr} ${local_addr} "${extra_args}"
  527. lret=$?
  528. if [ $lret -ne 0 ]; then
  529. ret=$lret
  530. return 1
  531. fi
  532. do_transfer ${listener_ns} ${connector_ns} TCP MPTCP \
  533. ${connect_addr} ${local_addr} "${extra_args}"
  534. lret=$?
  535. if [ $lret -ne 0 ]; then
  536. ret=$lret
  537. return 1
  538. fi
  539. if [ $do_tcp -gt 1 ] ;then
  540. do_transfer ${listener_ns} ${connector_ns} TCP TCP \
  541. ${connect_addr} ${local_addr} "${extra_args}"
  542. lret=$?
  543. if [ $lret -ne 0 ]; then
  544. ret=$lret
  545. return 1
  546. fi
  547. fi
  548. return 0
  549. }
  550. run_tests()
  551. {
  552. run_tests_lo $1 $2 $3 0
  553. }
  554. run_test_transparent()
  555. {
  556. local connect_addr="$1"
  557. local msg="$2"
  558. local connector_ns="$ns1"
  559. local listener_ns="$ns2"
  560. local lret=0
  561. local r6flag=""
  562. TEST_GROUP="${msg}"
  563. # skip if we don't want v6
  564. if ! $ipv6 && mptcp_lib_is_v6 "${connect_addr}"; then
  565. return 0
  566. fi
  567. # IP(V6)_TRANSPARENT has been added after TOS support which came with
  568. # the required infrastructure in MPTCP sockopt code. To support TOS, the
  569. # following function has been exported (T). Not great but better than
  570. # checking for a specific kernel version.
  571. if ! mptcp_lib_kallsyms_has "T __ip_sock_set_tos$"; then
  572. mptcp_lib_pr_skip "${msg} not supported by the kernel"
  573. mptcp_lib_result_skip "${TEST_GROUP}"
  574. return
  575. fi
  576. if ! ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF"
  577. flush ruleset
  578. table inet mangle {
  579. chain divert {
  580. type filter hook prerouting priority -150;
  581. meta l4proto tcp socket transparent 1 meta mark set 1 accept
  582. tcp dport 20000 tproxy to :20000 meta mark set 1 accept
  583. }
  584. }
  585. EOF
  586. then
  587. mptcp_lib_pr_skip "$msg, could not load nft ruleset"
  588. mptcp_lib_fail_if_expected_feature "nft rules"
  589. mptcp_lib_result_skip "${TEST_GROUP}"
  590. return
  591. fi
  592. local local_addr
  593. if mptcp_lib_is_v6 "${connect_addr}"; then
  594. local_addr="::"
  595. r6flag="-6"
  596. else
  597. local_addr="0.0.0.0"
  598. fi
  599. if ! ip -net "$listener_ns" $r6flag rule add fwmark 1 lookup 100; then
  600. ip netns exec "$listener_ns" nft flush ruleset
  601. mptcp_lib_pr_skip "$msg, ip $r6flag rule failed"
  602. mptcp_lib_fail_if_expected_feature "ip rule"
  603. mptcp_lib_result_skip "${TEST_GROUP}"
  604. return
  605. fi
  606. if ! ip -net "$listener_ns" route add local $local_addr/0 dev lo table 100; then
  607. ip netns exec "$listener_ns" nft flush ruleset
  608. ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100
  609. mptcp_lib_pr_skip "$msg, ip route add local $local_addr failed"
  610. mptcp_lib_fail_if_expected_feature "ip route"
  611. mptcp_lib_result_skip "${TEST_GROUP}"
  612. return
  613. fi
  614. mptcp_lib_pr_info "test $msg"
  615. port=$((20000 - 1))
  616. local extra_args="-o TRANSPARENT"
  617. do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \
  618. ${connect_addr} ${local_addr} "${extra_args}"
  619. lret=$?
  620. ip netns exec "$listener_ns" nft flush ruleset
  621. ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100
  622. ip -net "$listener_ns" route del local $local_addr/0 dev lo table 100
  623. if [ $lret -ne 0 ]; then
  624. mptcp_lib_pr_fail "$msg, mptcp connection error"
  625. ret=$lret
  626. return 1
  627. fi
  628. mptcp_lib_pr_info "$msg pass"
  629. return 0
  630. }
  631. run_tests_peekmode()
  632. {
  633. local peekmode="$1"
  634. TEST_GROUP="peek mode: ${peekmode}"
  635. mptcp_lib_pr_info "with peek mode: ${peekmode}"
  636. run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-P ${peekmode}"
  637. run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-P ${peekmode}"
  638. }
  639. run_tests_mptfo()
  640. {
  641. TEST_GROUP="MPTFO"
  642. if ! mptcp_lib_kallsyms_has "mptcp_fastopen_"; then
  643. mptcp_lib_pr_skip "TFO not supported by the kernel"
  644. mptcp_lib_result_skip "${TEST_GROUP}"
  645. return
  646. fi
  647. mptcp_lib_pr_info "with MPTFO start"
  648. ip netns exec "$ns1" sysctl -q net.ipv4.tcp_fastopen=2
  649. ip netns exec "$ns2" sysctl -q net.ipv4.tcp_fastopen=1
  650. run_tests_lo "$ns1" "$ns2" 10.0.1.1 0 "-o MPTFO"
  651. run_tests_lo "$ns1" "$ns2" 10.0.1.1 0 "-o MPTFO"
  652. run_tests_lo "$ns1" "$ns2" dead:beef:1::1 0 "-o MPTFO"
  653. run_tests_lo "$ns1" "$ns2" dead:beef:1::1 0 "-o MPTFO"
  654. ip netns exec "$ns1" sysctl -q net.ipv4.tcp_fastopen=0
  655. ip netns exec "$ns2" sysctl -q net.ipv4.tcp_fastopen=0
  656. mptcp_lib_pr_info "with MPTFO end"
  657. }
  658. run_tests_disconnect()
  659. {
  660. local old_cin=$cin
  661. local old_sin=$sin
  662. TEST_GROUP="full disconnect"
  663. if ! mptcp_lib_kallsyms_has "mptcp_pm_data_reset$"; then
  664. mptcp_lib_pr_skip "Full disconnect not supported"
  665. mptcp_lib_result_skip "${TEST_GROUP}"
  666. return
  667. fi
  668. cat $cin $cin $cin > "$cin".disconnect
  669. # force do_transfer to cope with the multiple transmissions
  670. sin="$cin.disconnect"
  671. cin="$cin.disconnect"
  672. cin_disconnect="$old_cin"
  673. connect_per_transfer=3
  674. mptcp_lib_pr_info "disconnect"
  675. run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-I 3 -i $old_cin"
  676. run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-I 3 -i $old_cin"
  677. # restore previous status
  678. sin=$old_sin
  679. cin=$old_cin
  680. cin_disconnect="$cin".disconnect
  681. connect_per_transfer=1
  682. }
  683. display_time()
  684. {
  685. time_end=$(date +%s)
  686. time_run=$((time_end-time_start))
  687. echo "Time: ${time_run} seconds"
  688. }
  689. log_if_error()
  690. {
  691. local msg="$1"
  692. if [ ${ret} -ne 0 ]; then
  693. mptcp_lib_pr_fail "${msg}"
  694. final_ret=${ret}
  695. ret=${KSFT_PASS}
  696. return ${final_ret}
  697. fi
  698. }
  699. stop_if_error()
  700. {
  701. if ! log_if_error "${@}"; then
  702. display_time
  703. mptcp_lib_result_print_all_tap
  704. exit ${final_ret}
  705. fi
  706. }
  707. make_file "$cin" "client"
  708. make_file "$sin" "server"
  709. mptcp_lib_subtests_last_ts_reset
  710. check_mptcp_disabled
  711. stop_if_error "The kernel configuration is not valid for MPTCP"
  712. print_larger_title "Validating network environment with pings"
  713. for sender in "$ns1" "$ns2" "$ns3" "$ns4";do
  714. do_ping "$ns1" $sender 10.0.1.1
  715. do_ping "$ns1" $sender dead:beef:1::1
  716. do_ping "$ns2" $sender 10.0.1.2
  717. do_ping "$ns2" $sender dead:beef:1::2
  718. do_ping "$ns2" $sender 10.0.2.1
  719. do_ping "$ns2" $sender dead:beef:2::1
  720. do_ping "$ns3" $sender 10.0.2.2
  721. do_ping "$ns3" $sender dead:beef:2::2
  722. do_ping "$ns3" $sender 10.0.3.2
  723. do_ping "$ns3" $sender dead:beef:3::2
  724. do_ping "$ns4" $sender 10.0.3.1
  725. do_ping "$ns4" $sender dead:beef:3::1
  726. done
  727. mptcp_lib_result_code "${ret}" "ping tests"
  728. stop_if_error "Could not even run ping tests"
  729. mptcp_lib_pr_ok
  730. [ -n "$tc_loss" ] && tc -net "$ns2" qdisc add dev ns2eth3 root netem loss random $tc_loss delay ${tc_delay}ms
  731. tc_info="loss of $tc_loss "
  732. test "$tc_delay" -gt 0 && tc_info+="delay $tc_delay ms "
  733. reorder_delay=$((tc_delay / 4))
  734. if [ -z "${tc_reorder}" ]; then
  735. reorder1=$((RANDOM%10))
  736. reorder1=$((100 - reorder1))
  737. reorder2=$((RANDOM%100))
  738. if [ $reorder_delay -gt 0 ] && [ $reorder1 -lt 100 ] && [ $reorder2 -gt 0 ]; then
  739. tc_reorder="reorder ${reorder1}% ${reorder2}%"
  740. tc_info+="$tc_reorder with delay ${reorder_delay}ms "
  741. fi
  742. elif [ "$tc_reorder" = "0" ];then
  743. tc_reorder=""
  744. elif [ "$reorder_delay" -gt 0 ];then
  745. # reordering requires some delay
  746. tc_reorder="reorder $tc_reorder"
  747. tc_info+="$tc_reorder with delay ${reorder_delay}ms "
  748. fi
  749. mptcp_lib_pr_info "Using ${tc_info}on ns3eth4"
  750. tc -net "$ns3" qdisc add dev ns3eth4 root netem delay ${reorder_delay}ms $tc_reorder
  751. TEST_GROUP="loopback v4"
  752. run_tests_lo "$ns1" "$ns1" 10.0.1.1 1
  753. stop_if_error "Could not even run loopback test"
  754. TEST_GROUP="loopback v6"
  755. run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1
  756. stop_if_error "Could not even run loopback v6 test"
  757. TEST_GROUP="multihosts"
  758. for sender in $ns1 $ns2 $ns3 $ns4;do
  759. # ns1<->ns2 is not subject to reordering/tc delays. Use it to test
  760. # mptcp syncookie support.
  761. if [ $sender = $ns1 ]; then
  762. ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2
  763. else
  764. ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=1
  765. fi
  766. run_tests "$ns1" $sender 10.0.1.1
  767. run_tests "$ns1" $sender dead:beef:1::1
  768. run_tests "$ns2" $sender 10.0.1.2
  769. run_tests "$ns2" $sender dead:beef:1::2
  770. run_tests "$ns2" $sender 10.0.2.1
  771. run_tests "$ns2" $sender dead:beef:2::1
  772. run_tests "$ns3" $sender 10.0.2.2
  773. run_tests "$ns3" $sender dead:beef:2::2
  774. run_tests "$ns3" $sender 10.0.3.2
  775. run_tests "$ns3" $sender dead:beef:3::2
  776. run_tests "$ns4" $sender 10.0.3.1
  777. run_tests "$ns4" $sender dead:beef:3::1
  778. log_if_error "Tests with $sender as a sender have failed"
  779. done
  780. run_tests_peekmode "saveWithPeek"
  781. run_tests_peekmode "saveAfterPeek"
  782. log_if_error "Tests with peek mode have failed"
  783. # MPTFO (MultiPath TCP Fatopen tests)
  784. run_tests_mptfo
  785. log_if_error "Tests with MPTFO have failed"
  786. # connect to ns4 ip address, ns2 should intercept/proxy
  787. run_test_transparent 10.0.3.1 "tproxy ipv4"
  788. run_test_transparent dead:beef:3::1 "tproxy ipv6"
  789. log_if_error "Tests with tproxy have failed"
  790. run_tests_disconnect
  791. log_if_error "Tests of the full disconnection have failed"
  792. display_time
  793. mptcp_lib_result_print_all_tap
  794. exit ${final_ret}