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 436 timeout ${timeout_test} \ 437 ip netns exec ${listener_ns} \ 438 ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ 439 $extra_args $local_addr < "$sin" > "$sout" & 440 local spid=$! 441 442 wait_local_port_listen "${listener_ns}" "${port}" 443 444 local start 445 start=$(date +%s%3N) 446 timeout ${timeout_test} \ 447 ip netns exec ${connector_ns} \ 448 ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ 449 $extra_args $connect_addr < "$cin" > "$cout" & 450 local cpid=$! 451 452 wait $cpid 453 local retc=$? 454 wait $spid 455 local rets=$? 456 457 local stop 458 stop=$(date +%s%3N) 459 460 if $capture; then 461 sleep 1 462 kill ${cappid_listener} 463 kill ${cappid_connector} 464 fi 465 466 NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ 467 nstat | grep Tcp > /tmp/${listener_ns}.out 468 if [ ${listener_ns} != ${connector_ns} ]; then 469 NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ 470 nstat | grep Tcp > /tmp/${connector_ns}.out 471 fi 472 473 local duration 474 duration=$((stop-start)) 475 printf "(duration %05sms) " "${duration}" 476 if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 477 echo "[ FAIL ] client exit code $retc, server $rets" 1>&2 478 echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 479 ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port" 480 cat /tmp/${listener_ns}.out 481 echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 482 ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port" 483 [ ${listener_ns} != ${connector_ns} ] && cat /tmp/${connector_ns}.out 484 485 echo 486 cat "$capout" 487 return 1 488 fi 489 490 check_transfer $sin $cout "file received by client" 491 retc=$? 492 check_transfer $cin $sout "file received by server" 493 rets=$? 494 495 local stat_synrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") 496 local stat_ackrx_now_l=$(get_mib_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") 497 local stat_cookietx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesSent") 498 local stat_cookierx_now=$(get_mib_counter "${listener_ns}" "TcpExtSyncookiesRecv") 499 local stat_ooo_now=$(get_mib_counter "${listener_ns}" "TcpExtTCPOFOQueue") 500 501 expect_synrx=$((stat_synrx_last_l)) 502 expect_ackrx=$((stat_ackrx_last_l)) 503 504 cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies) 505 cookies=${cookies##*=} 506 507 if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then 508 expect_synrx=$((stat_synrx_last_l+$connect_per_transfer)) 509 expect_ackrx=$((stat_ackrx_last_l+$connect_per_transfer)) 510 fi 511 512 if [ ${stat_synrx_now_l} -lt ${expect_synrx} ]; then 513 printf "[ FAIL ] lower MPC SYN rx (%d) than expected (%d)\n" \ 514 "${stat_synrx_now_l}" "${expect_synrx}" 1>&2 515 retc=1 516 fi 517 if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} -a ${stat_ooo_now} -eq 0 ]; then 518 if [ ${stat_ooo_now} -eq 0 ]; then 519 printf "[ FAIL ] lower MPC ACK rx (%d) than expected (%d)\n" \ 520 "${stat_ackrx_now_l}" "${expect_ackrx}" 1>&2 521 rets=1 522 else 523 printf "[ Note ] fallback due to TCP OoO" 524 fi 525 fi 526 527 if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then 528 printf "[ OK ]" 529 fi 530 531 if [ $cookies -eq 2 ];then 532 if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then 533 printf " WARN: CookieSent: did not advance" 534 fi 535 if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then 536 printf " WARN: CookieRecv: did not advance" 537 fi 538 else 539 if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then 540 printf " WARN: CookieSent: changed" 541 fi 542 if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then 543 printf " WARN: CookieRecv: changed" 544 fi 545 fi 546 547 if [ ${stat_synrx_now_l} -gt ${expect_synrx} ]; then 548 printf " WARN: SYNRX: expect %d, got %d (probably retransmissions)" \ 549 "${expect_synrx}" "${stat_synrx_now_l}" 550 fi 551 if [ ${stat_ackrx_now_l} -gt ${expect_ackrx} ]; then 552 printf " WARN: ACKRX: expect %d, got %d (probably retransmissions)" \ 553 "${expect_ackrx}" "${stat_ackrx_now_l}" 554 fi 555 556 echo 557 cat "$capout" 558 [ $retc -eq 0 ] && [ $rets -eq 0 ] 559} 560 561make_file() 562{ 563 local name=$1 564 local who=$2 565 local SIZE=$filesize 566 local ksize 567 local rem 568 569 if [ $SIZE -eq 0 ]; then 570 local MAXSIZE=$((1024 * 1024 * 8)) 571 local MINSIZE=$((1024 * 256)) 572 573 SIZE=$(((RANDOM * RANDOM + MINSIZE) % MAXSIZE)) 574 fi 575 576 ksize=$((SIZE / 1024)) 577 rem=$((SIZE - (ksize * 1024))) 578 579 dd if=/dev/urandom of="$name" bs=1024 count=$ksize 2> /dev/null 580 dd if=/dev/urandom conv=notrunc of="$name" bs=1 count=$rem 2> /dev/null 581 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" 582 583 echo "Created $name (size $(du -b "$name")) containing data sent by $who" 584} 585 586run_tests_lo() 587{ 588 local listener_ns="$1" 589 local connector_ns="$2" 590 local connect_addr="$3" 591 local loopback="$4" 592 local extra_args="$5" 593 local lret=0 594 595 # skip if test programs are running inside same netns for subsequent runs. 596 if [ $loopback -eq 0 ] && [ ${listener_ns} = ${connector_ns} ]; then 597 return 0 598 fi 599 600 # skip if we don't want v6 601 if ! $ipv6 && is_v6 "${connect_addr}"; then 602 return 0 603 fi 604 605 local local_addr 606 if is_v6 "${connect_addr}"; then 607 local_addr="::" 608 else 609 local_addr="0.0.0.0" 610 fi 611 612 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \ 613 ${connect_addr} ${local_addr} "${extra_args}" 614 lret=$? 615 if [ $lret -ne 0 ]; then 616 ret=$lret 617 return 1 618 fi 619 620 if [ $do_tcp -eq 0 ]; then 621 # don't bother testing fallback tcp except for loopback case. 622 if [ ${listener_ns} != ${connector_ns} ]; then 623 return 0 624 fi 625 fi 626 627 do_transfer ${listener_ns} ${connector_ns} MPTCP TCP \ 628 ${connect_addr} ${local_addr} "${extra_args}" 629 lret=$? 630 if [ $lret -ne 0 ]; then 631 ret=$lret 632 return 1 633 fi 634 635 do_transfer ${listener_ns} ${connector_ns} TCP MPTCP \ 636 ${connect_addr} ${local_addr} "${extra_args}" 637 lret=$? 638 if [ $lret -ne 0 ]; then 639 ret=$lret 640 return 1 641 fi 642 643 if [ $do_tcp -gt 1 ] ;then 644 do_transfer ${listener_ns} ${connector_ns} TCP TCP \ 645 ${connect_addr} ${local_addr} "${extra_args}" 646 lret=$? 647 if [ $lret -ne 0 ]; then 648 ret=$lret 649 return 1 650 fi 651 fi 652 653 return 0 654} 655 656run_tests() 657{ 658 run_tests_lo $1 $2 $3 0 659} 660 661run_test_transparent() 662{ 663 local connect_addr="$1" 664 local msg="$2" 665 666 local connector_ns="$ns1" 667 local listener_ns="$ns2" 668 local lret=0 669 local r6flag="" 670 671 # skip if we don't want v6 672 if ! $ipv6 && is_v6 "${connect_addr}"; then 673 return 0 674 fi 675 676ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF" 677flush ruleset 678table inet mangle { 679 chain divert { 680 type filter hook prerouting priority -150; 681 682 meta l4proto tcp socket transparent 1 meta mark set 1 accept 683 tcp dport 20000 tproxy to :20000 meta mark set 1 accept 684 } 685} 686EOF 687 if [ $? -ne 0 ]; then 688 echo "SKIP: $msg, could not load nft ruleset" 689 return 690 fi 691 692 local local_addr 693 if is_v6 "${connect_addr}"; then 694 local_addr="::" 695 r6flag="-6" 696 else 697 local_addr="0.0.0.0" 698 fi 699 700 ip -net "$listener_ns" $r6flag rule add fwmark 1 lookup 100 701 if [ $? -ne 0 ]; then 702 ip netns exec "$listener_ns" nft flush ruleset 703 echo "SKIP: $msg, ip $r6flag rule failed" 704 return 705 fi 706 707 ip -net "$listener_ns" route add local $local_addr/0 dev lo table 100 708 if [ $? -ne 0 ]; then 709 ip netns exec "$listener_ns" nft flush ruleset 710 ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100 711 echo "SKIP: $msg, ip route add local $local_addr failed" 712 return 713 fi 714 715 echo "INFO: test $msg" 716 717 TEST_COUNT=10000 718 local extra_args="-o TRANSPARENT" 719 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP \ 720 ${connect_addr} ${local_addr} "${extra_args}" 721 lret=$? 722 723 ip netns exec "$listener_ns" nft flush ruleset 724 ip -net "$listener_ns" $r6flag rule del fwmark 1 lookup 100 725 ip -net "$listener_ns" route del local $local_addr/0 dev lo table 100 726 727 if [ $lret -ne 0 ]; then 728 echo "FAIL: $msg, mptcp connection error" 1>&2 729 ret=$lret 730 return 1 731 fi 732 733 echo "PASS: $msg" 734 return 0 735} 736 737run_tests_peekmode() 738{ 739 local peekmode="$1" 740 741 echo "INFO: with peek mode: ${peekmode}" 742 run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-P ${peekmode}" 743 run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-P ${peekmode}" 744} 745 746run_tests_disconnect() 747{ 748 local peekmode="$1" 749 local old_cin=$cin 750 local old_sin=$sin 751 752 cat $cin $cin $cin > "$cin".disconnect 753 754 # force do_transfer to cope with the multiple tranmissions 755 sin="$cin.disconnect" 756 sin_disconnect=$old_sin 757 cin="$cin.disconnect" 758 cin_disconnect="$old_cin" 759 connect_per_transfer=3 760 761 echo "INFO: disconnect" 762 run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 "-I 3 -i $old_cin" 763 run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-I 3 -i $old_cin" 764 765 # restore previous status 766 sin=$old_sin 767 sin_disconnect="$cout".disconnect 768 cin=$old_cin 769 cin_disconnect="$cin".disconnect 770 connect_per_transfer=1 771} 772 773display_time() 774{ 775 time_end=$(date +%s) 776 time_run=$((time_end-time_start)) 777 778 echo "Time: ${time_run} seconds" 779} 780 781stop_if_error() 782{ 783 local msg="$1" 784 785 if [ ${ret} -ne 0 ]; then 786 echo "FAIL: ${msg}" 1>&2 787 display_time 788 exit ${ret} 789 fi 790} 791 792make_file "$cin" "client" 793make_file "$sin" "server" 794 795check_mptcp_disabled 796 797stop_if_error "The kernel configuration is not valid for MPTCP" 798 799echo "INFO: validating network environment with pings" 800for sender in "$ns1" "$ns2" "$ns3" "$ns4";do 801 do_ping "$ns1" $sender 10.0.1.1 802 do_ping "$ns1" $sender dead:beef:1::1 803 804 do_ping "$ns2" $sender 10.0.1.2 805 do_ping "$ns2" $sender dead:beef:1::2 806 do_ping "$ns2" $sender 10.0.2.1 807 do_ping "$ns2" $sender dead:beef:2::1 808 809 do_ping "$ns3" $sender 10.0.2.2 810 do_ping "$ns3" $sender dead:beef:2::2 811 do_ping "$ns3" $sender 10.0.3.2 812 do_ping "$ns3" $sender dead:beef:3::2 813 814 do_ping "$ns4" $sender 10.0.3.1 815 do_ping "$ns4" $sender dead:beef:3::1 816done 817 818stop_if_error "Could not even run ping tests" 819 820[ -n "$tc_loss" ] && tc -net "$ns2" qdisc add dev ns2eth3 root netem loss random $tc_loss delay ${tc_delay}ms 821echo -n "INFO: Using loss of $tc_loss " 822test "$tc_delay" -gt 0 && echo -n "delay $tc_delay ms " 823 824reorder_delay=$(($tc_delay / 4)) 825 826if [ -z "${tc_reorder}" ]; then 827 reorder1=$((RANDOM%10)) 828 reorder1=$((100 - reorder1)) 829 reorder2=$((RANDOM%100)) 830 831 if [ $reorder_delay -gt 0 ] && [ $reorder1 -lt 100 ] && [ $reorder2 -gt 0 ]; then 832 tc_reorder="reorder ${reorder1}% ${reorder2}%" 833 echo -n "$tc_reorder with delay ${reorder_delay}ms " 834 fi 835elif [ "$tc_reorder" = "0" ];then 836 tc_reorder="" 837elif [ "$reorder_delay" -gt 0 ];then 838 # reordering requires some delay 839 tc_reorder="reorder $tc_reorder" 840 echo -n "$tc_reorder with delay ${reorder_delay}ms " 841fi 842 843echo "on ns3eth4" 844 845tc -net "$ns3" qdisc add dev ns3eth4 root netem delay ${reorder_delay}ms $tc_reorder 846 847run_tests_lo "$ns1" "$ns1" 10.0.1.1 1 848stop_if_error "Could not even run loopback test" 849 850run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 851stop_if_error "Could not even run loopback v6 test" 852 853for sender in $ns1 $ns2 $ns3 $ns4;do 854 # ns1<->ns2 is not subject to reordering/tc delays. Use it to test 855 # mptcp syncookie support. 856 if [ $sender = $ns1 ]; then 857 ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2 858 else 859 ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=1 860 fi 861 862 run_tests "$ns1" $sender 10.0.1.1 863 run_tests "$ns1" $sender dead:beef:1::1 864 865 run_tests "$ns2" $sender 10.0.1.2 866 run_tests "$ns2" $sender dead:beef:1::2 867 run_tests "$ns2" $sender 10.0.2.1 868 run_tests "$ns2" $sender dead:beef:2::1 869 870 run_tests "$ns3" $sender 10.0.2.2 871 run_tests "$ns3" $sender dead:beef:2::2 872 run_tests "$ns3" $sender 10.0.3.2 873 run_tests "$ns3" $sender dead:beef:3::2 874 875 run_tests "$ns4" $sender 10.0.3.1 876 run_tests "$ns4" $sender dead:beef:3::1 877 878 stop_if_error "Tests with $sender as a sender have failed" 879done 880 881run_tests_peekmode "saveWithPeek" 882run_tests_peekmode "saveAfterPeek" 883stop_if_error "Tests with peek mode have failed" 884 885# connect to ns4 ip address, ns2 should intercept/proxy 886run_test_transparent 10.0.3.1 "tproxy ipv4" 887run_test_transparent dead:beef:3::1 "tproxy ipv6" 888stop_if_error "Tests with tproxy have failed" 889 890run_tests_disconnect 891 892display_time 893exit $ret 894