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 278 disabled_ns="ns_disabled-$sech-$(mktemp -u XXXXXX)" 279 ip netns add ${disabled_ns} || exit $ksft_skip 280 281 # net.mptcp.enabled should be enabled by default 282 if [ "$(ip netns exec ${disabled_ns} sysctl net.mptcp.enabled | awk '{ print $3 }')" -ne 1 ]; then 283 echo -e "net.mptcp.enabled sysctl is not 1 by default\t\t[ FAIL ]" 284 ret=1 285 return 1 286 fi 287 ip netns exec ${disabled_ns} sysctl -q net.mptcp.enabled=0 288 289 local err=0 290 LC_ALL=C ip netns exec ${disabled_ns} ./mptcp_connect -p 10000 -s MPTCP 127.0.0.1 < "$cin" 2>&1 | \ 291 grep -q "^socket: Protocol not available$" && err=1 292 ip netns delete ${disabled_ns} 293 294 if [ ${err} -eq 0 ]; then 295 echo -e "New MPTCP socket cannot be blocked via sysctl\t\t[ FAIL ]" 296 ret=1 297 return 1 298 fi 299 300 echo -e "New MPTCP socket can be blocked via sysctl\t\t[ OK ]" 301 return 0 302} 303 304# $1: IP address 305is_v6() 306{ 307 [ -z "${1##*:*}" ] 308} 309 310do_ping() 311{ 312 local listener_ns="$1" 313 local connector_ns="$2" 314 local connect_addr="$3" 315 local ping_args="-q -c 1" 316 317 if is_v6 "${connect_addr}"; then 318 $ipv6 || return 0 319 ping_args="${ping_args} -6" 320 fi 321 322 ip netns exec ${connector_ns} ping ${ping_args} $connect_addr >/dev/null 323 if [ $? -ne 0 ] ; then 324 echo "$listener_ns -> $connect_addr connectivity [ FAIL ]" 1>&2 325 ret=1 326 327 return 1 328 fi 329 330 return 0 331} 332 333# $1: ns, $2: MIB counter 334get_mib_counter() 335{ 336 local listener_ns="${1}" 337 local mib="${2}" 338 339 # strip the header 340 ip netns exec "${listener_ns}" \ 341 nstat -z -a "${mib}" | \ 342 tail -n+2 | \ 343 while read a count c rest; do 344 echo $count 345 done 346} 347 348# $1: ns, $2: port 349wait_local_port_listen() 350{ 351 local listener_ns="${1}" 352 local port="${2}" 353 354 local port_hex i 355 356 port_hex="$(printf "%04X" "${port}")" 357 for i in $(seq 10); do 358 ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ 359 awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && 360 break 361 sleep 0.1 362 done 363} 364 365do_transfer() 366{ 367 local listener_ns="$1" 368 local connector_ns="$2" 369 local cl_proto="$3" 370 local srv_proto="$4" 371 local connect_addr="$5" 372 local local_addr="$6" 373 local extra_args="$7" 374 375 local port 376 port=$((10000+$TEST_COUNT)) 377 TEST_COUNT=$((TEST_COUNT+1)) 378 379 if [ "$rcvbuf" -gt 0 ]; then 380 extra_args="$extra_args -R $rcvbuf" 381 fi 382 383 if [ "$sndbuf" -gt 0 ]; then 384 extra_args="$extra_args -S $sndbuf" 385 fi 386 387 if [ -n "$testmode" ]; then 388 extra_args="$extra_args -m $testmode" 389 fi 390 391 if [ -n "$extra_args" ] && $options_log; then 392 echo "INFO: extra options: $extra_args" 393 fi 394 options_log=false 395 396 :> "$cout" 397 :> "$sout" 398 :> "$capout" 399 400 local addr_port 401 addr_port=$(printf "%s:%d" ${connect_addr} ${port}) 402 printf "%.3s %-5s -> %.3s (%-20s) %-5s\t" ${connector_ns} ${cl_proto} ${listener_ns} ${addr_port} ${srv_proto} 403 404 if $capture; then 405 local capuser 406 if [ -z $SUDO_USER ] ; then 407 capuser="" 408 else 409 capuser="-Z $SUDO_USER" 410 fi 411 412 local capfile="${rndh}-${connector_ns:0:3}-${listener_ns:0:3}-${cl_proto}-${srv_proto}-${connect_addr}-${port}" 413 local capopt="-i any -s 65535 -B 32768 ${capuser}" 414 415 ip netns exec ${listener_ns} tcpdump ${capopt} -w "${capfile}-listener.pcap" >> "${capout}" 2>&1 & 416 local cappid_listener=$! 417 418 ip netns exec ${connector_ns} tcpdump ${capopt} -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 & 419 local cappid_connector=$! 420 421 sleep 1 422 fi 423 424 NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ 425 nstat -n 426 if [ ${listener_ns} != ${connector_ns} ]; then 427 NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ 428 nstat -n 429 fi 430 431 local stat_synrx_last_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") 432 local stat_ackrx_last_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") 433 local stat_cookietx_last=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesSent") 434 local stat_cookierx_last=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesRecv") 435 local stat_csum_err_s=$(get_mib_counter "${listener_ns}" "MPTcpExtDataCsumErr") 436 local stat_csum_err_c=$(get_mib_counter "${connector_ns}" "MPTcpExtDataCsumErr") 437 438 timeout ${timeout_test} \ 439 ip netns exec ${listener_ns} \ 440 ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ 441 $extra_args $local_addr < "$sin" > "$sout" & 442 local spid=$! 443 444 wait_local_port_listen "${listener_ns}" "${port}" 445 446 local start 447 start=$(date +%s%3N) 448 timeout ${timeout_test} \ 449 ip netns exec ${connector_ns} \ 450 ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ 451 $extra_args $connect_addr < "$cin" > "$cout" & 452 local cpid=$! 453 454 wait $cpid 455 local retc=$? 456 wait $spid 457 local rets=$? 458 459 local stop 460 stop=$(date +%s%3N) 461 462 if $capture; then 463 sleep 1 464 kill ${cappid_listener} 465 kill ${cappid_connector} 466 fi 467 468 NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ 469 nstat | grep Tcp > /tmp/${listener_ns}.out 470 if [ ${listener_ns} != ${connector_ns} ]; then 471 NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ 472 nstat | grep Tcp > /tmp/${connector_ns}.out 473 fi 474 475 local duration 476 duration=$((stop-start)) 477 printf "(duration %05sms) " "${duration}" 478 if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 479 echo "[ FAIL ] client exit code $retc, server $rets" 1>&2 480 echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 481 ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port" 482 cat /tmp/${listener_ns}.out 483 echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 484 ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port" 485 [ ${listener_ns} != ${connector_ns} ] && cat /tmp/${connector_ns}.out 486 487 echo 488 cat "$capout" 489 return 1 490 fi 491 492 check_transfer $sin $cout "file received by client" 493 retc=$? 494 check_transfer $cin $sout "file received by server" 495 rets=$? 496 497 local stat_synrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") 498 local stat_ackrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") 499 local stat_cookietx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesSent") 500 local stat_cookierx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesRecv") 501 local stat_ooo_now=$(get_mib_counter "${listener_ns}" "TcpExtTCPOFOQueue") 502 503 expect_synrx=$((stat_synrx_last_l)) 504 expect_ackrx=$((stat_ackrx_last_l)) 505 506 cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies) 507 cookies=${cookies##*=} 508 509 if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then 510 expect_synrx=$((stat_synrx_last_l+$connect_per_transfer)) 511 expect_ackrx=$((stat_ackrx_last_l+$connect_per_transfer)) 512 fi 513 514 if [ ${stat_synrx_now_l} -lt ${expect_synrx} ]; then 515 printf "[ FAIL ] lower MPC SYN rx (%d) than expected (%d)\n" \ 516 "${stat_synrx_now_l}" "${expect_synrx}" 1>&2 517 retc=1 518 fi 519 if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} -a ${stat_ooo_now} -eq 0 ]; then 520 if [ ${stat_ooo_now} -eq 0 ]; then 521 printf "[ FAIL ] lower MPC ACK rx (%d) than expected (%d)\n" \ 522 "${stat_ackrx_now_l}" "${expect_ackrx}" 1>&2 523 rets=1 524 else 525 printf "[ Note ] fallback due to TCP OoO" 526 fi 527 fi 528 529 if $checksum; then 530 local csum_err_s=$(get_mib_counter "${listener_ns}" "MPTcpExtDataCsumErr") 531 local csum_err_c=$(get_mib_counter "${connector_ns}" "MPTcpExtDataCsumErr") 532 533 local csum_err_s_nr=$((csum_err_s - stat_csum_err_s)) 534 if [ $csum_err_s_nr -gt 0 ]; then 535 printf "[ FAIL ]\nserver got $csum_err_s_nr data checksum error[s]" 536 rets=1 537 fi 538 539 local csum_err_c_nr=$((csum_err_c - stat_csum_err_c)) 540 if [ $csum_err_c_nr -gt 0 ]; then 541 printf "[ FAIL ]\nclient got $csum_err_c_nr data checksum error[s]" 542 retc=1 543 fi 544 fi 545 546 if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then 547 printf "[ OK ]" 548 fi 549 550 if [ $cookies -eq 2 ];then 551 if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then 552 printf " WARN: CookieSent: did not advance" 553 fi 554 if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then 555 printf " WARN: CookieRecv: did not advance" 556 fi 557 else 558 if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then 559 printf " WARN: CookieSent: changed" 560 fi 561 if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then 562 printf " WARN: CookieRecv: changed" 563 fi 564 fi 565 566 if [ ${stat_synrx_now_l} -gt ${expect_synrx} ]; then 567 printf " WARN: SYNRX: expect %d, got %d (probably retransmissions)" \ 568 "${expect_synrx}" "${stat_synrx_now_l}" 569 fi 570 if [ ${stat_ackrx_now_l} -gt ${expect_ackrx} ]; then 571 printf " WARN: ACKRX: expect %d, got %d (probably retransmissions)" \ 572 "${expect_ackrx}" "${stat_ackrx_now_l}" 573 fi 574 575 echo 576 cat "$capout" 577 [ $retc -eq 0 ] && [ $rets -eq 0 ] 578} 579 580make_file() 581{ 582 local name=$1 583 local who=$2 584 local SIZE=$filesize 585 local ksize 586 local rem 587 588 if [ $SIZE -eq 0 ]; then 589 local MAXSIZE=$((1024 * 1024 * 8)) 590 local MINSIZE=$((1024 * 256)) 591 592 SIZE=$(((RANDOM * RANDOM + MINSIZE) % MAXSIZE)) 593 fi 594 595 ksize=$((SIZE / 1024)) 596 rem=$((SIZE - (ksize * 1024))) 597 598 dd if=/dev/urandom of="$name" bs=1024 count=$ksize 2> /dev/null 599 dd if=/dev/urandom conv=notrunc of="$name" bs=1 count=$rem 2> /dev/null 600 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" 601 602 echo "Created $name (size $(du -b "$name")) containing data sent by $who" 603} 604 605run_tests_lo() 606{ 607 local listener_ns="$1" 608 local connector_ns="$2" 609 local connect_addr="$3" 610 local loopback="$4" 611 local extra_args="$5" 612 local lret=0 613 614 # skip if test programs are running inside same netns for subsequent runs. 615 if [ $loopback -eq 0 ] && [ ${listener_ns} = ${connector_ns} ]; then 616 return 0 617 fi 618 619 # skip if we don't want v6 620 if ! $ipv6 && is_v6 "${connect_addr}"; then 621 return 0 622 fi 623 624 local local_addr 625 if is_v6 "${connect_addr}"; then 626 local_addr="::" 627 else 628 local_addr="0.0.0.0" 629 fi 630 631 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \ 632 ${connect_addr} ${local_addr} "${extra_args}" 633 lret=$? 634 if [ $lret -ne 0 ]; then 635 ret=$lret 636 return 1 637 fi 638 639 if [ $do_tcp -eq 0 ]; then 640 # don't bother testing fallback tcp except for loopback case. 641 if [ ${listener_ns} != ${connector_ns} ]; then 642 return 0 643 fi 644 fi 645 646 do_transfer ${listener_ns} ${connector_ns} MPTCP TCP \ 647 ${connect_addr} ${local_addr} "${extra_args}" 648 lret=$? 649 if [ $lret -ne 0 ]; then 650 ret=$lret 651 return 1 652 fi 653 654 do_transfer ${listener_ns} ${connector_ns} TCP MPTCP \ 655 ${connect_addr} ${local_addr} "${extra_args}" 656 lret=$? 657 if [ $lret -ne 0 ]; then 658 ret=$lret 659 return 1 660 fi 661 662 if [ $do_tcp -gt 1 ] ;then 663 do_transfer ${listener_ns} ${connector_ns} TCP TCP \ 664 ${connect_addr} ${local_addr} "${extra_args}" 665 lret=$? 666 if [ $lret -ne 0 ]; then 667 ret=$lret 668 return 1 669 fi 670 fi 671 672 return 0 673} 674 675run_tests() 676{ 677 run_tests_lo $1 $2 $3 0 678} 679 680run_test_transparent() 681{ 682 local connect_addr="$1" 683 local msg="$2" 684 685 local connector_ns="$ns1" 686 local listener_ns="$ns2" 687 local lret=0 688 local r6flag="" 689 690 # skip if we don't want v6 691 if ! $ipv6 && is_v6 "${connect_addr}"; then 692 return 0 693 fi 694 695ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF" 696flush ruleset 697table inet mangle { 698 chain divert { 699 type filter hook prerouting priority -150; 700 701 meta l4proto tcp socket transparent 1 meta mark set 1 accept 702 tcp dport 20000 tproxy to :20000 meta mark set 1 accept 703 } 704} 705EOF 706 if [ $? -ne 0 ]; then 707 echo "SKIP: $msg, could not load nft ruleset" 708 return 709 fi 710 711 local local_addr 712 if is_v6 "${connect_addr}"; then 713 local_addr="::" 714 r6flag="-6" 715 else 716 local_addr="0.0.0.0" 717 fi 718 719 ip -net "$listener_ns" $r6flag rule add fwmark 1 lookup 100 720 if [ $? -ne 0 ]; then 721 ip netns exec "$listener_ns" nft flush ruleset 722 echo "SKIP: $msg, ip $r6flag rule failed" 723 return 724 fi 725 726 ip -net "$listener_ns" route add local $local_addr/0 dev lo table 100 727 if [ $? -ne 0 ]; then 728 ip netns exec "$listener_ns" nft flush ruleset 729 ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100 730 echo "SKIP: $msg, ip route add local $local_addr failed" 731 return 732 fi 733 734 echo "INFO: test $msg" 735 736 TEST_COUNT=10000 737 local extra_args="-o TRANSPARENT" 738 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \ 739 ${connect_addr} ${local_addr} "${extra_args}" 740 lret=$? 741 742 ip netns exec "$listener_ns" nft flush ruleset 743 ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100 744 ip -net "$listener_ns" route del local $local_addr/0 dev lo table 100 745 746 if [ $lret -ne 0 ]; then 747 echo "FAIL: $msg, mptcp connection error" 1>&2 748 ret=$lret 749 return 1 750 fi 751 752 echo "PASS: $msg" 753 return 0 754} 755 756run_tests_peekmode() 757{ 758 local peekmode="$1" 759 760 echo "INFO: with peek mode: ${peekmode}" 761 run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-P ${peekmode}" 762 run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-P ${peekmode}" 763} 764 765run_tests_disconnect() 766{ 767 local peekmode="$1" 768 local old_cin=$cin 769 local old_sin=$sin 770 771 cat $cin $cin $cin > "$cin".disconnect 772 773 # force do_transfer to cope with the multiple tranmissions 774 sin="$cin.disconnect" 775 sin_disconnect=$old_sin 776 cin="$cin.disconnect" 777 cin_disconnect="$old_cin" 778 connect_per_transfer=3 779 780 echo "INFO: disconnect" 781 run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-I 3 -i $old_cin" 782 run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-I 3 -i $old_cin" 783 784 # restore previous status 785 sin=$old_sin 786 sin_disconnect="$cout".disconnect 787 cin=$old_cin 788 cin_disconnect="$cin".disconnect 789 connect_per_transfer=1 790} 791 792display_time() 793{ 794 time_end=$(date +%s) 795 time_run=$((time_end-time_start)) 796 797 echo "Time: ${time_run} seconds" 798} 799 800stop_if_error() 801{ 802 local msg="$1" 803 804 if [ ${ret} -ne 0 ]; then 805 echo "FAIL: ${msg}" 1>&2 806 display_time 807 exit ${ret} 808 fi 809} 810 811make_file "$cin" "client" 812make_file "$sin" "server" 813 814check_mptcp_disabled 815 816stop_if_error "The kernel configuration is not valid for MPTCP" 817 818echo "INFO: validating network environment with pings" 819for sender in "$ns1" "$ns2" "$ns3" "$ns4";do 820 do_ping "$ns1" $sender 10.0.1.1 821 do_ping "$ns1" $sender dead:beef:1::1 822 823 do_ping "$ns2" $sender 10.0.1.2 824 do_ping "$ns2" $sender dead:beef:1::2 825 do_ping "$ns2" $sender 10.0.2.1 826 do_ping "$ns2" $sender dead:beef:2::1 827 828 do_ping "$ns3" $sender 10.0.2.2 829 do_ping "$ns3" $sender dead:beef:2::2 830 do_ping "$ns3" $sender 10.0.3.2 831 do_ping "$ns3" $sender dead:beef:3::2 832 833 do_ping "$ns4" $sender 10.0.3.1 834 do_ping "$ns4" $sender dead:beef:3::1 835done 836 837stop_if_error "Could not even run ping tests" 838 839[ -n "$tc_loss" ] && tc -net "$ns2" qdisc add dev ns2eth3 root netem loss random $tc_loss delay ${tc_delay}ms 840echo -n "INFO: Using loss of $tc_loss " 841test "$tc_delay" -gt 0 && echo -n "delay $tc_delay ms " 842 843reorder_delay=$(($tc_delay / 4)) 844 845if [ -z "${tc_reorder}" ]; then 846 reorder1=$((RANDOM%10)) 847 reorder1=$((100 - reorder1)) 848 reorder2=$((RANDOM%100)) 849 850 if [ $reorder_delay -gt 0 ] && [ $reorder1 -lt 100 ] && [ $reorder2 -gt 0 ]; then 851 tc_reorder="reorder ${reorder1}% ${reorder2}%" 852 echo -n "$tc_reorder with delay ${reorder_delay}ms " 853 fi 854elif [ "$tc_reorder" = "0" ];then 855 tc_reorder="" 856elif [ "$reorder_delay" -gt 0 ];then 857 # reordering requires some delay 858 tc_reorder="reorder $tc_reorder" 859 echo -n "$tc_reorder with delay ${reorder_delay}ms " 860fi 861 862echo "on ns3eth4" 863 864tc -net "$ns3" qdisc add dev ns3eth4 root netem delay ${reorder_delay}ms $tc_reorder 865 866run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 867stop_if_error "Could not even run loopback test" 868 869run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 870stop_if_error "Could not even run loopback v6 test" 871 872for sender in $ns1 $ns2 $ns3 $ns4;do 873 # ns1<->ns2 is not subject to reordering/tc delays. Use it to test 874 # mptcp syncookie support. 875 if [ $sender = $ns1 ]; then 876 ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2 877 else 878 ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=1 879 fi 880 881 run_tests "$ns1" $sender 10.0.1.1 882 run_tests "$ns1" $sender dead:beef:1::1 883 884 run_tests "$ns2" $sender 10.0.1.2 885 run_tests "$ns2" $sender dead:beef:1::2 886 run_tests "$ns2" $sender 10.0.2.1 887 run_tests "$ns2" $sender dead:beef:2::1 888 889 run_tests "$ns3" $sender 10.0.2.2 890 run_tests "$ns3" $sender dead:beef:2::2 891 run_tests "$ns3" $sender 10.0.3.2 892 run_tests "$ns3" $sender dead:beef:3::2 893 894 run_tests "$ns4" $sender 10.0.3.1 895 run_tests "$ns4" $sender dead:beef:3::1 896 897 stop_if_error "Tests with $sender as a sender have failed" 898done 899 900run_tests_peekmode "saveWithPeek" 901run_tests_peekmode "saveAfterPeek" 902stop_if_error "Tests with peek mode have failed" 903 904# connect to ns4 ip address, ns2 should intercept/proxy 905run_test_transparent 10.0.3.1 "tproxy ipv4" 906run_test_transparent dead:beef:3::1 "tproxy ipv6" 907stop_if_error "Tests with tproxy have failed" 908 909run_tests_disconnect 910 911display_time 912exit $ret 913