1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun 4*4882a593Smuzhiyuntime_start=$(date +%s) 5*4882a593Smuzhiyun 6*4882a593Smuzhiyunoptstring="S:R:d:e:l:r:h4cm:f:t" 7*4882a593Smuzhiyunret=0 8*4882a593Smuzhiyunsin="" 9*4882a593Smuzhiyunsout="" 10*4882a593Smuzhiyuncin="" 11*4882a593Smuzhiyuncout="" 12*4882a593Smuzhiyunksft_skip=4 13*4882a593Smuzhiyuncapture=false 14*4882a593Smuzhiyuntimeout=30 15*4882a593Smuzhiyunipv6=true 16*4882a593Smuzhiyunethtool_random_on=true 17*4882a593Smuzhiyuntc_delay="$((RANDOM%50))" 18*4882a593Smuzhiyuntc_loss=$((RANDOM%101)) 19*4882a593Smuzhiyuntestmode="" 20*4882a593Smuzhiyunsndbuf=0 21*4882a593Smuzhiyunrcvbuf=0 22*4882a593Smuzhiyunoptions_log=true 23*4882a593Smuzhiyundo_tcp=0 24*4882a593Smuzhiyunfilesize=0 25*4882a593Smuzhiyun 26*4882a593Smuzhiyunif [ $tc_loss -eq 100 ];then 27*4882a593Smuzhiyun tc_loss=1% 28*4882a593Smuzhiyunelif [ $tc_loss -ge 10 ]; then 29*4882a593Smuzhiyun tc_loss=0.$tc_loss% 30*4882a593Smuzhiyunelif [ $tc_loss -ge 1 ]; then 31*4882a593Smuzhiyun tc_loss=0.0$tc_loss% 32*4882a593Smuzhiyunelse 33*4882a593Smuzhiyun tc_loss="" 34*4882a593Smuzhiyunfi 35*4882a593Smuzhiyun 36*4882a593Smuzhiyunusage() { 37*4882a593Smuzhiyun echo "Usage: $0 [ -a ]" 38*4882a593Smuzhiyun echo -e "\t-d: tc/netem delay in milliseconds, e.g. \"-d 10\" (default random)" 39*4882a593Smuzhiyun echo -e "\t-l: tc/netem loss percentage, e.g. \"-l 0.02\" (default random)" 40*4882a593Smuzhiyun echo -e "\t-r: tc/netem reorder mode, e.g. \"-r 25% 50% gap 5\", use "-r 0" to disable reordering (default random)" 41*4882a593Smuzhiyun echo -e "\t-e: ethtool features to disable, e.g.: \"-e tso -e gso\" (default: randomly disable any of tso/gso/gro)" 42*4882a593Smuzhiyun echo -e "\t-4: IPv4 only: disable IPv6 tests (default: test both IPv4 and IPv6)" 43*4882a593Smuzhiyun echo -e "\t-c: capture packets for each test using tcpdump (default: no capture)" 44*4882a593Smuzhiyun echo -e "\t-f: size of file to transfer in bytes (default random)" 45*4882a593Smuzhiyun echo -e "\t-S: set sndbuf value (default: use kernel default)" 46*4882a593Smuzhiyun echo -e "\t-R: set rcvbuf value (default: use kernel default)" 47*4882a593Smuzhiyun echo -e "\t-m: test mode (poll, sendfile; default: poll)" 48*4882a593Smuzhiyun echo -e "\t-t: also run tests with TCP (use twice to non-fallback tcp)" 49*4882a593Smuzhiyun} 50*4882a593Smuzhiyun 51*4882a593Smuzhiyunwhile getopts "$optstring" option;do 52*4882a593Smuzhiyun case "$option" in 53*4882a593Smuzhiyun "h") 54*4882a593Smuzhiyun usage $0 55*4882a593Smuzhiyun exit 0 56*4882a593Smuzhiyun ;; 57*4882a593Smuzhiyun "d") 58*4882a593Smuzhiyun if [ $OPTARG -ge 0 ];then 59*4882a593Smuzhiyun tc_delay="$OPTARG" 60*4882a593Smuzhiyun else 61*4882a593Smuzhiyun echo "-d requires numeric argument, got \"$OPTARG\"" 1>&2 62*4882a593Smuzhiyun exit 1 63*4882a593Smuzhiyun fi 64*4882a593Smuzhiyun ;; 65*4882a593Smuzhiyun "e") 66*4882a593Smuzhiyun ethtool_args="$ethtool_args $OPTARG off" 67*4882a593Smuzhiyun ethtool_random_on=false 68*4882a593Smuzhiyun ;; 69*4882a593Smuzhiyun "l") 70*4882a593Smuzhiyun tc_loss="$OPTARG" 71*4882a593Smuzhiyun ;; 72*4882a593Smuzhiyun "r") 73*4882a593Smuzhiyun tc_reorder="$OPTARG" 74*4882a593Smuzhiyun ;; 75*4882a593Smuzhiyun "4") 76*4882a593Smuzhiyun ipv6=false 77*4882a593Smuzhiyun ;; 78*4882a593Smuzhiyun "c") 79*4882a593Smuzhiyun capture=true 80*4882a593Smuzhiyun ;; 81*4882a593Smuzhiyun "S") 82*4882a593Smuzhiyun if [ $OPTARG -ge 0 ];then 83*4882a593Smuzhiyun sndbuf="$OPTARG" 84*4882a593Smuzhiyun else 85*4882a593Smuzhiyun echo "-S requires numeric argument, got \"$OPTARG\"" 1>&2 86*4882a593Smuzhiyun exit 1 87*4882a593Smuzhiyun fi 88*4882a593Smuzhiyun ;; 89*4882a593Smuzhiyun "R") 90*4882a593Smuzhiyun if [ $OPTARG -ge 0 ];then 91*4882a593Smuzhiyun rcvbuf="$OPTARG" 92*4882a593Smuzhiyun else 93*4882a593Smuzhiyun echo "-R requires numeric argument, got \"$OPTARG\"" 1>&2 94*4882a593Smuzhiyun exit 1 95*4882a593Smuzhiyun fi 96*4882a593Smuzhiyun ;; 97*4882a593Smuzhiyun "m") 98*4882a593Smuzhiyun testmode="$OPTARG" 99*4882a593Smuzhiyun ;; 100*4882a593Smuzhiyun "f") 101*4882a593Smuzhiyun filesize="$OPTARG" 102*4882a593Smuzhiyun ;; 103*4882a593Smuzhiyun "t") 104*4882a593Smuzhiyun do_tcp=$((do_tcp+1)) 105*4882a593Smuzhiyun ;; 106*4882a593Smuzhiyun "?") 107*4882a593Smuzhiyun usage $0 108*4882a593Smuzhiyun exit 1 109*4882a593Smuzhiyun ;; 110*4882a593Smuzhiyun esac 111*4882a593Smuzhiyundone 112*4882a593Smuzhiyun 113*4882a593Smuzhiyunsec=$(date +%s) 114*4882a593Smuzhiyunrndh=$(printf %x $sec)-$(mktemp -u XXXXXX) 115*4882a593Smuzhiyunns1="ns1-$rndh" 116*4882a593Smuzhiyunns2="ns2-$rndh" 117*4882a593Smuzhiyunns3="ns3-$rndh" 118*4882a593Smuzhiyunns4="ns4-$rndh" 119*4882a593Smuzhiyun 120*4882a593SmuzhiyunTEST_COUNT=0 121*4882a593Smuzhiyun 122*4882a593Smuzhiyuncleanup() 123*4882a593Smuzhiyun{ 124*4882a593Smuzhiyun rm -f "$cin" "$cout" 125*4882a593Smuzhiyun rm -f "$sin" "$sout" 126*4882a593Smuzhiyun rm -f "$capout" 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun local netns 129*4882a593Smuzhiyun for netns in "$ns1" "$ns2" "$ns3" "$ns4";do 130*4882a593Smuzhiyun ip netns del $netns 131*4882a593Smuzhiyun done 132*4882a593Smuzhiyun} 133*4882a593Smuzhiyun 134*4882a593Smuzhiyunip -Version > /dev/null 2>&1 135*4882a593Smuzhiyunif [ $? -ne 0 ];then 136*4882a593Smuzhiyun echo "SKIP: Could not run test without ip tool" 137*4882a593Smuzhiyun exit $ksft_skip 138*4882a593Smuzhiyunfi 139*4882a593Smuzhiyun 140*4882a593Smuzhiyunsin=$(mktemp) 141*4882a593Smuzhiyunsout=$(mktemp) 142*4882a593Smuzhiyuncin=$(mktemp) 143*4882a593Smuzhiyuncout=$(mktemp) 144*4882a593Smuzhiyuncapout=$(mktemp) 145*4882a593Smuzhiyuntrap cleanup EXIT 146*4882a593Smuzhiyun 147*4882a593Smuzhiyunfor i in "$ns1" "$ns2" "$ns3" "$ns4";do 148*4882a593Smuzhiyun ip netns add $i || exit $ksft_skip 149*4882a593Smuzhiyun ip -net $i link set lo up 150*4882a593Smuzhiyundone 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun# "$ns1" ns2 ns3 ns4 153*4882a593Smuzhiyun# ns1eth2 ns2eth1 ns2eth3 ns3eth2 ns3eth4 ns4eth3 154*4882a593Smuzhiyun# - drop 1% -> reorder 25% 155*4882a593Smuzhiyun# <- TSO off - 156*4882a593Smuzhiyun 157*4882a593Smuzhiyunip link add ns1eth2 netns "$ns1" type veth peer name ns2eth1 netns "$ns2" 158*4882a593Smuzhiyunip link add ns2eth3 netns "$ns2" type veth peer name ns3eth2 netns "$ns3" 159*4882a593Smuzhiyunip link add ns3eth4 netns "$ns3" type veth peer name ns4eth3 netns "$ns4" 160*4882a593Smuzhiyun 161*4882a593Smuzhiyunip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth2 162*4882a593Smuzhiyunip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth2 nodad 163*4882a593Smuzhiyun 164*4882a593Smuzhiyunip -net "$ns1" link set ns1eth2 up 165*4882a593Smuzhiyunip -net "$ns1" route add default via 10.0.1.2 166*4882a593Smuzhiyunip -net "$ns1" route add default via dead:beef:1::2 167*4882a593Smuzhiyun 168*4882a593Smuzhiyunip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1 169*4882a593Smuzhiyunip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad 170*4882a593Smuzhiyunip -net "$ns2" link set ns2eth1 up 171*4882a593Smuzhiyun 172*4882a593Smuzhiyunip -net "$ns2" addr add 10.0.2.1/24 dev ns2eth3 173*4882a593Smuzhiyunip -net "$ns2" addr add dead:beef:2::1/64 dev ns2eth3 nodad 174*4882a593Smuzhiyunip -net "$ns2" link set ns2eth3 up 175*4882a593Smuzhiyunip -net "$ns2" route add default via 10.0.2.2 176*4882a593Smuzhiyunip -net "$ns2" route add default via dead:beef:2::2 177*4882a593Smuzhiyunip netns exec "$ns2" sysctl -q net.ipv4.ip_forward=1 178*4882a593Smuzhiyunip netns exec "$ns2" sysctl -q net.ipv6.conf.all.forwarding=1 179*4882a593Smuzhiyun 180*4882a593Smuzhiyunip -net "$ns3" addr add 10.0.2.2/24 dev ns3eth2 181*4882a593Smuzhiyunip -net "$ns3" addr add dead:beef:2::2/64 dev ns3eth2 nodad 182*4882a593Smuzhiyunip -net "$ns3" link set ns3eth2 up 183*4882a593Smuzhiyun 184*4882a593Smuzhiyunip -net "$ns3" addr add 10.0.3.2/24 dev ns3eth4 185*4882a593Smuzhiyunip -net "$ns3" addr add dead:beef:3::2/64 dev ns3eth4 nodad 186*4882a593Smuzhiyunip -net "$ns3" link set ns3eth4 up 187*4882a593Smuzhiyunip -net "$ns3" route add default via 10.0.2.1 188*4882a593Smuzhiyunip -net "$ns3" route add default via dead:beef:2::1 189*4882a593Smuzhiyunip netns exec "$ns3" sysctl -q net.ipv4.ip_forward=1 190*4882a593Smuzhiyunip netns exec "$ns3" sysctl -q net.ipv6.conf.all.forwarding=1 191*4882a593Smuzhiyun 192*4882a593Smuzhiyunip -net "$ns4" addr add 10.0.3.1/24 dev ns4eth3 193*4882a593Smuzhiyunip -net "$ns4" addr add dead:beef:3::1/64 dev ns4eth3 nodad 194*4882a593Smuzhiyunip -net "$ns4" link set ns4eth3 up 195*4882a593Smuzhiyunip -net "$ns4" route add default via 10.0.3.2 196*4882a593Smuzhiyunip -net "$ns4" route add default via dead:beef:3::2 197*4882a593Smuzhiyun 198*4882a593Smuzhiyunset_ethtool_flags() { 199*4882a593Smuzhiyun local ns="$1" 200*4882a593Smuzhiyun local dev="$2" 201*4882a593Smuzhiyun local flags="$3" 202*4882a593Smuzhiyun 203*4882a593Smuzhiyun ip netns exec $ns ethtool -K $dev $flags 2>/dev/null 204*4882a593Smuzhiyun [ $? -eq 0 ] && echo "INFO: set $ns dev $dev: ethtool -K $flags" 205*4882a593Smuzhiyun} 206*4882a593Smuzhiyun 207*4882a593Smuzhiyunset_random_ethtool_flags() { 208*4882a593Smuzhiyun local flags="" 209*4882a593Smuzhiyun local r=$RANDOM 210*4882a593Smuzhiyun 211*4882a593Smuzhiyun local pick1=$((r & 1)) 212*4882a593Smuzhiyun local pick2=$((r & 2)) 213*4882a593Smuzhiyun local pick3=$((r & 4)) 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun [ $pick1 -ne 0 ] && flags="tso off" 216*4882a593Smuzhiyun [ $pick2 -ne 0 ] && flags="$flags gso off" 217*4882a593Smuzhiyun [ $pick3 -ne 0 ] && flags="$flags gro off" 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun [ -z "$flags" ] && return 220*4882a593Smuzhiyun 221*4882a593Smuzhiyun set_ethtool_flags "$1" "$2" "$flags" 222*4882a593Smuzhiyun} 223*4882a593Smuzhiyun 224*4882a593Smuzhiyunif $ethtool_random_on;then 225*4882a593Smuzhiyun set_random_ethtool_flags "$ns3" ns3eth2 226*4882a593Smuzhiyun set_random_ethtool_flags "$ns4" ns4eth3 227*4882a593Smuzhiyunelse 228*4882a593Smuzhiyun set_ethtool_flags "$ns3" ns3eth2 "$ethtool_args" 229*4882a593Smuzhiyun set_ethtool_flags "$ns4" ns4eth3 "$ethtool_args" 230*4882a593Smuzhiyunfi 231*4882a593Smuzhiyun 232*4882a593Smuzhiyunprint_file_err() 233*4882a593Smuzhiyun{ 234*4882a593Smuzhiyun ls -l "$1" 1>&2 235*4882a593Smuzhiyun echo "Trailing bytes are: " 236*4882a593Smuzhiyun tail -c 27 "$1" 237*4882a593Smuzhiyun} 238*4882a593Smuzhiyun 239*4882a593Smuzhiyuncheck_transfer() 240*4882a593Smuzhiyun{ 241*4882a593Smuzhiyun local in=$1 242*4882a593Smuzhiyun local out=$2 243*4882a593Smuzhiyun local what=$3 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun cmp "$in" "$out" > /dev/null 2>&1 246*4882a593Smuzhiyun if [ $? -ne 0 ] ;then 247*4882a593Smuzhiyun echo "[ FAIL ] $what does not match (in, out):" 248*4882a593Smuzhiyun print_file_err "$in" 249*4882a593Smuzhiyun print_file_err "$out" 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun return 1 252*4882a593Smuzhiyun fi 253*4882a593Smuzhiyun 254*4882a593Smuzhiyun return 0 255*4882a593Smuzhiyun} 256*4882a593Smuzhiyun 257*4882a593Smuzhiyuncheck_mptcp_disabled() 258*4882a593Smuzhiyun{ 259*4882a593Smuzhiyun local disabled_ns 260*4882a593Smuzhiyun disabled_ns="ns_disabled-$sech-$(mktemp -u XXXXXX)" 261*4882a593Smuzhiyun ip netns add ${disabled_ns} || exit $ksft_skip 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun # net.mptcp.enabled should be enabled by default 264*4882a593Smuzhiyun if [ "$(ip netns exec ${disabled_ns} sysctl net.mptcp.enabled | awk '{ print $3 }')" -ne 1 ]; then 265*4882a593Smuzhiyun echo -e "net.mptcp.enabled sysctl is not 1 by default\t\t[ FAIL ]" 266*4882a593Smuzhiyun ret=1 267*4882a593Smuzhiyun return 1 268*4882a593Smuzhiyun fi 269*4882a593Smuzhiyun ip netns exec ${disabled_ns} sysctl -q net.mptcp.enabled=0 270*4882a593Smuzhiyun 271*4882a593Smuzhiyun local err=0 272*4882a593Smuzhiyun LANG=C ip netns exec ${disabled_ns} ./mptcp_connect -t $timeout -p 10000 -s MPTCP 127.0.0.1 < "$cin" 2>&1 | \ 273*4882a593Smuzhiyun grep -q "^socket: Protocol not available$" && err=1 274*4882a593Smuzhiyun ip netns delete ${disabled_ns} 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun if [ ${err} -eq 0 ]; then 277*4882a593Smuzhiyun echo -e "New MPTCP socket cannot be blocked via sysctl\t\t[ FAIL ]" 278*4882a593Smuzhiyun ret=1 279*4882a593Smuzhiyun return 1 280*4882a593Smuzhiyun fi 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun echo -e "New MPTCP socket can be blocked via sysctl\t\t[ OK ]" 283*4882a593Smuzhiyun return 0 284*4882a593Smuzhiyun} 285*4882a593Smuzhiyun 286*4882a593Smuzhiyuncheck_mptcp_ulp_setsockopt() 287*4882a593Smuzhiyun{ 288*4882a593Smuzhiyun local t retval 289*4882a593Smuzhiyun t="ns_ulp-$sech-$(mktemp -u XXXXXX)" 290*4882a593Smuzhiyun 291*4882a593Smuzhiyun ip netns add ${t} || exit $ksft_skip 292*4882a593Smuzhiyun if ! ip netns exec ${t} ./mptcp_connect -u -p 10000 -s TCP 127.0.0.1 2>&1; then 293*4882a593Smuzhiyun printf "setsockopt(..., TCP_ULP, \"mptcp\", ...) allowed\t[ FAIL ]\n" 294*4882a593Smuzhiyun retval=1 295*4882a593Smuzhiyun ret=$retval 296*4882a593Smuzhiyun else 297*4882a593Smuzhiyun printf "setsockopt(..., TCP_ULP, \"mptcp\", ...) blocked\t[ OK ]\n" 298*4882a593Smuzhiyun retval=0 299*4882a593Smuzhiyun fi 300*4882a593Smuzhiyun ip netns del ${t} 301*4882a593Smuzhiyun return $retval 302*4882a593Smuzhiyun} 303*4882a593Smuzhiyun 304*4882a593Smuzhiyun# $1: IP address 305*4882a593Smuzhiyunis_v6() 306*4882a593Smuzhiyun{ 307*4882a593Smuzhiyun [ -z "${1##*:*}" ] 308*4882a593Smuzhiyun} 309*4882a593Smuzhiyun 310*4882a593Smuzhiyundo_ping() 311*4882a593Smuzhiyun{ 312*4882a593Smuzhiyun local listener_ns="$1" 313*4882a593Smuzhiyun local connector_ns="$2" 314*4882a593Smuzhiyun local connect_addr="$3" 315*4882a593Smuzhiyun local ping_args="-q -c 1" 316*4882a593Smuzhiyun 317*4882a593Smuzhiyun if is_v6 "${connect_addr}"; then 318*4882a593Smuzhiyun $ipv6 || return 0 319*4882a593Smuzhiyun ping_args="${ping_args} -6" 320*4882a593Smuzhiyun fi 321*4882a593Smuzhiyun 322*4882a593Smuzhiyun ip netns exec ${connector_ns} ping ${ping_args} $connect_addr >/dev/null 323*4882a593Smuzhiyun if [ $? -ne 0 ] ; then 324*4882a593Smuzhiyun echo "$listener_ns -> $connect_addr connectivity [ FAIL ]" 1>&2 325*4882a593Smuzhiyun ret=1 326*4882a593Smuzhiyun 327*4882a593Smuzhiyun return 1 328*4882a593Smuzhiyun fi 329*4882a593Smuzhiyun 330*4882a593Smuzhiyun return 0 331*4882a593Smuzhiyun} 332*4882a593Smuzhiyun 333*4882a593Smuzhiyun# $1: ns, $2: port 334*4882a593Smuzhiyunwait_local_port_listen() 335*4882a593Smuzhiyun{ 336*4882a593Smuzhiyun local listener_ns="${1}" 337*4882a593Smuzhiyun local port="${2}" 338*4882a593Smuzhiyun 339*4882a593Smuzhiyun local port_hex i 340*4882a593Smuzhiyun 341*4882a593Smuzhiyun port_hex="$(printf "%04X" "${port}")" 342*4882a593Smuzhiyun for i in $(seq 10); do 343*4882a593Smuzhiyun ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ 344*4882a593Smuzhiyun awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && 345*4882a593Smuzhiyun break 346*4882a593Smuzhiyun sleep 0.1 347*4882a593Smuzhiyun done 348*4882a593Smuzhiyun} 349*4882a593Smuzhiyun 350*4882a593Smuzhiyundo_transfer() 351*4882a593Smuzhiyun{ 352*4882a593Smuzhiyun local listener_ns="$1" 353*4882a593Smuzhiyun local connector_ns="$2" 354*4882a593Smuzhiyun local cl_proto="$3" 355*4882a593Smuzhiyun local srv_proto="$4" 356*4882a593Smuzhiyun local connect_addr="$5" 357*4882a593Smuzhiyun local local_addr="$6" 358*4882a593Smuzhiyun local extra_args="" 359*4882a593Smuzhiyun 360*4882a593Smuzhiyun local port 361*4882a593Smuzhiyun port=$((10000+$TEST_COUNT)) 362*4882a593Smuzhiyun TEST_COUNT=$((TEST_COUNT+1)) 363*4882a593Smuzhiyun 364*4882a593Smuzhiyun if [ "$rcvbuf" -gt 0 ]; then 365*4882a593Smuzhiyun extra_args="$extra_args -R $rcvbuf" 366*4882a593Smuzhiyun fi 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun if [ "$sndbuf" -gt 0 ]; then 369*4882a593Smuzhiyun extra_args="$extra_args -S $sndbuf" 370*4882a593Smuzhiyun fi 371*4882a593Smuzhiyun 372*4882a593Smuzhiyun if [ -n "$testmode" ]; then 373*4882a593Smuzhiyun extra_args="$extra_args -m $testmode" 374*4882a593Smuzhiyun fi 375*4882a593Smuzhiyun 376*4882a593Smuzhiyun if [ -n "$extra_args" ] && $options_log; then 377*4882a593Smuzhiyun options_log=false 378*4882a593Smuzhiyun echo "INFO: extra options: $extra_args" 379*4882a593Smuzhiyun fi 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun :> "$cout" 382*4882a593Smuzhiyun :> "$sout" 383*4882a593Smuzhiyun :> "$capout" 384*4882a593Smuzhiyun 385*4882a593Smuzhiyun local addr_port 386*4882a593Smuzhiyun addr_port=$(printf "%s:%d" ${connect_addr} ${port}) 387*4882a593Smuzhiyun printf "%.3s %-5s -> %.3s (%-20s) %-5s\t" ${connector_ns} ${cl_proto} ${listener_ns} ${addr_port} ${srv_proto} 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun if $capture; then 390*4882a593Smuzhiyun local capuser 391*4882a593Smuzhiyun if [ -z $SUDO_USER ] ; then 392*4882a593Smuzhiyun capuser="" 393*4882a593Smuzhiyun else 394*4882a593Smuzhiyun capuser="-Z $SUDO_USER" 395*4882a593Smuzhiyun fi 396*4882a593Smuzhiyun 397*4882a593Smuzhiyun local capfile="${rndh}-${connector_ns:0:3}-${listener_ns:0:3}-${cl_proto}-${srv_proto}-${connect_addr}-${port}" 398*4882a593Smuzhiyun local capopt="-i any -s 65535 -B 32768 ${capuser}" 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun ip netns exec ${listener_ns} tcpdump ${capopt} -w "${capfile}-listener.pcap" >> "${capout}" 2>&1 & 401*4882a593Smuzhiyun local cappid_listener=$! 402*4882a593Smuzhiyun 403*4882a593Smuzhiyun ip netns exec ${connector_ns} tcpdump ${capopt} -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 & 404*4882a593Smuzhiyun local cappid_connector=$! 405*4882a593Smuzhiyun 406*4882a593Smuzhiyun sleep 1 407*4882a593Smuzhiyun fi 408*4882a593Smuzhiyun 409*4882a593Smuzhiyun local stat_synrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX | while read a count c rest ;do echo $count;done) 410*4882a593Smuzhiyun local stat_ackrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX | while read a count c rest ;do echo $count;done) 411*4882a593Smuzhiyun local stat_cookietx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do echo $count;done) 412*4882a593Smuzhiyun local stat_cookierx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do echo $count;done) 413*4882a593Smuzhiyun 414*4882a593Smuzhiyun ip netns exec ${listener_ns} ./mptcp_connect -t $timeout -l -p $port -s ${srv_proto} $extra_args $local_addr < "$sin" > "$sout" & 415*4882a593Smuzhiyun local spid=$! 416*4882a593Smuzhiyun 417*4882a593Smuzhiyun wait_local_port_listen "${listener_ns}" "${port}" 418*4882a593Smuzhiyun 419*4882a593Smuzhiyun local start 420*4882a593Smuzhiyun start=$(date +%s%3N) 421*4882a593Smuzhiyun ip netns exec ${connector_ns} ./mptcp_connect -t $timeout -p $port -s ${cl_proto} $extra_args $connect_addr < "$cin" > "$cout" & 422*4882a593Smuzhiyun local cpid=$! 423*4882a593Smuzhiyun 424*4882a593Smuzhiyun wait $cpid 425*4882a593Smuzhiyun local retc=$? 426*4882a593Smuzhiyun wait $spid 427*4882a593Smuzhiyun local rets=$? 428*4882a593Smuzhiyun 429*4882a593Smuzhiyun local stop 430*4882a593Smuzhiyun stop=$(date +%s%3N) 431*4882a593Smuzhiyun 432*4882a593Smuzhiyun if $capture; then 433*4882a593Smuzhiyun sleep 1 434*4882a593Smuzhiyun kill ${cappid_listener} 435*4882a593Smuzhiyun kill ${cappid_connector} 436*4882a593Smuzhiyun fi 437*4882a593Smuzhiyun 438*4882a593Smuzhiyun local duration 439*4882a593Smuzhiyun duration=$((stop-start)) 440*4882a593Smuzhiyun duration=$(printf "(duration %05sms)" $duration) 441*4882a593Smuzhiyun if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 442*4882a593Smuzhiyun echo "$duration [ FAIL ] client exit code $retc, server $rets" 1>&2 443*4882a593Smuzhiyun echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 444*4882a593Smuzhiyun ip netns exec ${listener_ns} ss -nita 1>&2 -o "sport = :$port" 445*4882a593Smuzhiyun echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 446*4882a593Smuzhiyun ip netns exec ${connector_ns} ss -nita 1>&2 -o "dport = :$port" 447*4882a593Smuzhiyun 448*4882a593Smuzhiyun cat "$capout" 449*4882a593Smuzhiyun return 1 450*4882a593Smuzhiyun fi 451*4882a593Smuzhiyun 452*4882a593Smuzhiyun check_transfer $sin $cout "file received by client" 453*4882a593Smuzhiyun retc=$? 454*4882a593Smuzhiyun check_transfer $cin $sout "file received by server" 455*4882a593Smuzhiyun rets=$? 456*4882a593Smuzhiyun 457*4882a593Smuzhiyun local stat_synrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX | while read a count c rest ;do echo $count;done) 458*4882a593Smuzhiyun local stat_ackrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX | while read a count c rest ;do echo $count;done) 459*4882a593Smuzhiyun 460*4882a593Smuzhiyun local stat_cookietx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do echo $count;done) 461*4882a593Smuzhiyun local stat_cookierx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do echo $count;done) 462*4882a593Smuzhiyun 463*4882a593Smuzhiyun expect_synrx=$((stat_synrx_last_l)) 464*4882a593Smuzhiyun expect_ackrx=$((stat_ackrx_last_l)) 465*4882a593Smuzhiyun 466*4882a593Smuzhiyun cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies) 467*4882a593Smuzhiyun cookies=${cookies##*=} 468*4882a593Smuzhiyun 469*4882a593Smuzhiyun if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then 470*4882a593Smuzhiyun expect_synrx=$((stat_synrx_last_l+1)) 471*4882a593Smuzhiyun expect_ackrx=$((stat_ackrx_last_l+1)) 472*4882a593Smuzhiyun fi 473*4882a593Smuzhiyun if [ $cookies -eq 2 ];then 474*4882a593Smuzhiyun if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then 475*4882a593Smuzhiyun echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: did not advance" 476*4882a593Smuzhiyun fi 477*4882a593Smuzhiyun if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then 478*4882a593Smuzhiyun echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: did not advance" 479*4882a593Smuzhiyun fi 480*4882a593Smuzhiyun else 481*4882a593Smuzhiyun if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then 482*4882a593Smuzhiyun echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: changed" 483*4882a593Smuzhiyun fi 484*4882a593Smuzhiyun if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then 485*4882a593Smuzhiyun echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: changed" 486*4882a593Smuzhiyun fi 487*4882a593Smuzhiyun fi 488*4882a593Smuzhiyun 489*4882a593Smuzhiyun if [ $expect_synrx -ne $stat_synrx_now_l ] ;then 490*4882a593Smuzhiyun echo "${listener_ns} SYNRX: ${cl_proto} -> ${srv_proto}: expect ${expect_synrx}, got ${stat_synrx_now_l}" 491*4882a593Smuzhiyun fi 492*4882a593Smuzhiyun if [ $expect_ackrx -ne $stat_ackrx_now_l ] ;then 493*4882a593Smuzhiyun echo "${listener_ns} ACKRX: ${cl_proto} -> ${srv_proto}: expect ${expect_ackrx}, got ${stat_ackrx_now_l} " 494*4882a593Smuzhiyun fi 495*4882a593Smuzhiyun 496*4882a593Smuzhiyun if [ $retc -eq 0 ] && [ $rets -eq 0 ];then 497*4882a593Smuzhiyun echo "$duration [ OK ]" 498*4882a593Smuzhiyun cat "$capout" 499*4882a593Smuzhiyun return 0 500*4882a593Smuzhiyun fi 501*4882a593Smuzhiyun 502*4882a593Smuzhiyun cat "$capout" 503*4882a593Smuzhiyun return 1 504*4882a593Smuzhiyun} 505*4882a593Smuzhiyun 506*4882a593Smuzhiyunmake_file() 507*4882a593Smuzhiyun{ 508*4882a593Smuzhiyun local name=$1 509*4882a593Smuzhiyun local who=$2 510*4882a593Smuzhiyun local SIZE=$filesize 511*4882a593Smuzhiyun local ksize 512*4882a593Smuzhiyun local rem 513*4882a593Smuzhiyun 514*4882a593Smuzhiyun if [ $SIZE -eq 0 ]; then 515*4882a593Smuzhiyun local MAXSIZE=$((1024 * 1024 * 8)) 516*4882a593Smuzhiyun local MINSIZE=$((1024 * 256)) 517*4882a593Smuzhiyun 518*4882a593Smuzhiyun SIZE=$(((RANDOM * RANDOM + MINSIZE) % MAXSIZE)) 519*4882a593Smuzhiyun fi 520*4882a593Smuzhiyun 521*4882a593Smuzhiyun ksize=$((SIZE / 1024)) 522*4882a593Smuzhiyun rem=$((SIZE - (ksize * 1024))) 523*4882a593Smuzhiyun 524*4882a593Smuzhiyun dd if=/dev/urandom of="$name" bs=1024 count=$ksize 2> /dev/null 525*4882a593Smuzhiyun dd if=/dev/urandom conv=notrunc of="$name" bs=1 count=$rem 2> /dev/null 526*4882a593Smuzhiyun echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" 527*4882a593Smuzhiyun 528*4882a593Smuzhiyun echo "Created $name (size $(du -b "$name")) containing data sent by $who" 529*4882a593Smuzhiyun} 530*4882a593Smuzhiyun 531*4882a593Smuzhiyunrun_tests_lo() 532*4882a593Smuzhiyun{ 533*4882a593Smuzhiyun local listener_ns="$1" 534*4882a593Smuzhiyun local connector_ns="$2" 535*4882a593Smuzhiyun local connect_addr="$3" 536*4882a593Smuzhiyun local loopback="$4" 537*4882a593Smuzhiyun local lret=0 538*4882a593Smuzhiyun 539*4882a593Smuzhiyun # skip if test programs are running inside same netns for subsequent runs. 540*4882a593Smuzhiyun if [ $loopback -eq 0 ] && [ ${listener_ns} = ${connector_ns} ]; then 541*4882a593Smuzhiyun return 0 542*4882a593Smuzhiyun fi 543*4882a593Smuzhiyun 544*4882a593Smuzhiyun # skip if we don't want v6 545*4882a593Smuzhiyun if ! $ipv6 && is_v6 "${connect_addr}"; then 546*4882a593Smuzhiyun return 0 547*4882a593Smuzhiyun fi 548*4882a593Smuzhiyun 549*4882a593Smuzhiyun local local_addr 550*4882a593Smuzhiyun if is_v6 "${connect_addr}"; then 551*4882a593Smuzhiyun local_addr="::" 552*4882a593Smuzhiyun else 553*4882a593Smuzhiyun local_addr="0.0.0.0" 554*4882a593Smuzhiyun fi 555*4882a593Smuzhiyun 556*4882a593Smuzhiyun do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} ${local_addr} 557*4882a593Smuzhiyun lret=$? 558*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 559*4882a593Smuzhiyun ret=$lret 560*4882a593Smuzhiyun return 1 561*4882a593Smuzhiyun fi 562*4882a593Smuzhiyun 563*4882a593Smuzhiyun if [ $do_tcp -eq 0 ]; then 564*4882a593Smuzhiyun # don't bother testing fallback tcp except for loopback case. 565*4882a593Smuzhiyun if [ ${listener_ns} != ${connector_ns} ]; then 566*4882a593Smuzhiyun return 0 567*4882a593Smuzhiyun fi 568*4882a593Smuzhiyun fi 569*4882a593Smuzhiyun 570*4882a593Smuzhiyun do_transfer ${listener_ns} ${connector_ns} MPTCP TCP ${connect_addr} ${local_addr} 571*4882a593Smuzhiyun lret=$? 572*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 573*4882a593Smuzhiyun ret=$lret 574*4882a593Smuzhiyun return 1 575*4882a593Smuzhiyun fi 576*4882a593Smuzhiyun 577*4882a593Smuzhiyun do_transfer ${listener_ns} ${connector_ns} TCP MPTCP ${connect_addr} ${local_addr} 578*4882a593Smuzhiyun lret=$? 579*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 580*4882a593Smuzhiyun ret=$lret 581*4882a593Smuzhiyun return 1 582*4882a593Smuzhiyun fi 583*4882a593Smuzhiyun 584*4882a593Smuzhiyun if [ $do_tcp -gt 1 ] ;then 585*4882a593Smuzhiyun do_transfer ${listener_ns} ${connector_ns} TCP TCP ${connect_addr} ${local_addr} 586*4882a593Smuzhiyun lret=$? 587*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 588*4882a593Smuzhiyun ret=$lret 589*4882a593Smuzhiyun return 1 590*4882a593Smuzhiyun fi 591*4882a593Smuzhiyun fi 592*4882a593Smuzhiyun 593*4882a593Smuzhiyun return 0 594*4882a593Smuzhiyun} 595*4882a593Smuzhiyun 596*4882a593Smuzhiyunrun_tests() 597*4882a593Smuzhiyun{ 598*4882a593Smuzhiyun run_tests_lo $1 $2 $3 0 599*4882a593Smuzhiyun} 600*4882a593Smuzhiyun 601*4882a593Smuzhiyunmake_file "$cin" "client" 602*4882a593Smuzhiyunmake_file "$sin" "server" 603*4882a593Smuzhiyun 604*4882a593Smuzhiyuncheck_mptcp_disabled 605*4882a593Smuzhiyun 606*4882a593Smuzhiyuncheck_mptcp_ulp_setsockopt 607*4882a593Smuzhiyun 608*4882a593Smuzhiyunecho "INFO: validating network environment with pings" 609*4882a593Smuzhiyunfor sender in "$ns1" "$ns2" "$ns3" "$ns4";do 610*4882a593Smuzhiyun do_ping "$ns1" $sender 10.0.1.1 611*4882a593Smuzhiyun do_ping "$ns1" $sender dead:beef:1::1 612*4882a593Smuzhiyun 613*4882a593Smuzhiyun do_ping "$ns2" $sender 10.0.1.2 614*4882a593Smuzhiyun do_ping "$ns2" $sender dead:beef:1::2 615*4882a593Smuzhiyun do_ping "$ns2" $sender 10.0.2.1 616*4882a593Smuzhiyun do_ping "$ns2" $sender dead:beef:2::1 617*4882a593Smuzhiyun 618*4882a593Smuzhiyun do_ping "$ns3" $sender 10.0.2.2 619*4882a593Smuzhiyun do_ping "$ns3" $sender dead:beef:2::2 620*4882a593Smuzhiyun do_ping "$ns3" $sender 10.0.3.2 621*4882a593Smuzhiyun do_ping "$ns3" $sender dead:beef:3::2 622*4882a593Smuzhiyun 623*4882a593Smuzhiyun do_ping "$ns4" $sender 10.0.3.1 624*4882a593Smuzhiyun do_ping "$ns4" $sender dead:beef:3::1 625*4882a593Smuzhiyundone 626*4882a593Smuzhiyun 627*4882a593Smuzhiyun[ -n "$tc_loss" ] && tc -net "$ns2" qdisc add dev ns2eth3 root netem loss random $tc_loss delay ${tc_delay}ms 628*4882a593Smuzhiyunecho -n "INFO: Using loss of $tc_loss " 629*4882a593Smuzhiyuntest "$tc_delay" -gt 0 && echo -n "delay $tc_delay ms " 630*4882a593Smuzhiyun 631*4882a593Smuzhiyunreorder_delay=$(($tc_delay / 4)) 632*4882a593Smuzhiyun 633*4882a593Smuzhiyunif [ -z "${tc_reorder}" ]; then 634*4882a593Smuzhiyun reorder1=$((RANDOM%10)) 635*4882a593Smuzhiyun reorder1=$((100 - reorder1)) 636*4882a593Smuzhiyun reorder2=$((RANDOM%100)) 637*4882a593Smuzhiyun 638*4882a593Smuzhiyun if [ $reorder_delay -gt 0 ] && [ $reorder1 -lt 100 ] && [ $reorder2 -gt 0 ]; then 639*4882a593Smuzhiyun tc_reorder="reorder ${reorder1}% ${reorder2}%" 640*4882a593Smuzhiyun echo -n "$tc_reorder with delay ${reorder_delay}ms " 641*4882a593Smuzhiyun fi 642*4882a593Smuzhiyunelif [ "$tc_reorder" = "0" ];then 643*4882a593Smuzhiyun tc_reorder="" 644*4882a593Smuzhiyunelif [ "$reorder_delay" -gt 0 ];then 645*4882a593Smuzhiyun # reordering requires some delay 646*4882a593Smuzhiyun tc_reorder="reorder $tc_reorder" 647*4882a593Smuzhiyun echo -n "$tc_reorder with delay ${reorder_delay}ms " 648*4882a593Smuzhiyunfi 649*4882a593Smuzhiyun 650*4882a593Smuzhiyunecho "on ns3eth4" 651*4882a593Smuzhiyun 652*4882a593Smuzhiyuntc -net "$ns3" qdisc add dev ns3eth4 root netem delay ${reorder_delay}ms $tc_reorder 653*4882a593Smuzhiyun 654*4882a593Smuzhiyunfor sender in $ns1 $ns2 $ns3 $ns4;do 655*4882a593Smuzhiyun run_tests_lo "$ns1" "$sender" 10.0.1.1 1 656*4882a593Smuzhiyun if [ $ret -ne 0 ] ;then 657*4882a593Smuzhiyun echo "FAIL: Could not even run loopback test" 1>&2 658*4882a593Smuzhiyun exit $ret 659*4882a593Smuzhiyun fi 660*4882a593Smuzhiyun run_tests_lo "$ns1" $sender dead:beef:1::1 1 661*4882a593Smuzhiyun if [ $ret -ne 0 ] ;then 662*4882a593Smuzhiyun echo "FAIL: Could not even run loopback v6 test" 2>&1 663*4882a593Smuzhiyun exit $ret 664*4882a593Smuzhiyun fi 665*4882a593Smuzhiyun 666*4882a593Smuzhiyun # ns1<->ns2 is not subject to reordering/tc delays. Use it to test 667*4882a593Smuzhiyun # mptcp syncookie support. 668*4882a593Smuzhiyun if [ $sender = $ns1 ]; then 669*4882a593Smuzhiyun ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2 670*4882a593Smuzhiyun else 671*4882a593Smuzhiyun ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=1 672*4882a593Smuzhiyun fi 673*4882a593Smuzhiyun 674*4882a593Smuzhiyun run_tests "$ns2" $sender 10.0.1.2 675*4882a593Smuzhiyun run_tests "$ns2" $sender dead:beef:1::2 676*4882a593Smuzhiyun run_tests "$ns2" $sender 10.0.2.1 677*4882a593Smuzhiyun run_tests "$ns2" $sender dead:beef:2::1 678*4882a593Smuzhiyun 679*4882a593Smuzhiyun run_tests "$ns3" $sender 10.0.2.2 680*4882a593Smuzhiyun run_tests "$ns3" $sender dead:beef:2::2 681*4882a593Smuzhiyun run_tests "$ns3" $sender 10.0.3.2 682*4882a593Smuzhiyun run_tests "$ns3" $sender dead:beef:3::2 683*4882a593Smuzhiyun 684*4882a593Smuzhiyun run_tests "$ns4" $sender 10.0.3.1 685*4882a593Smuzhiyun run_tests "$ns4" $sender dead:beef:3::1 686*4882a593Smuzhiyundone 687*4882a593Smuzhiyun 688*4882a593Smuzhiyuntime_end=$(date +%s) 689*4882a593Smuzhiyuntime_run=$((time_end-time_start)) 690*4882a593Smuzhiyun 691*4882a593Smuzhiyunecho "Time: ${time_run} seconds" 692*4882a593Smuzhiyun 693*4882a593Smuzhiyunexit $ret 694