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