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