1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun 4*4882a593Smuzhiyunrndh=$(printf %x $sec)-$(mktemp -u XXXXXX) 5*4882a593Smuzhiyunns1="ns1-$rndh" 6*4882a593Smuzhiyunns2="ns2-$rndh" 7*4882a593Smuzhiyunns3="ns3-$rndh" 8*4882a593Smuzhiyuncapture=false 9*4882a593Smuzhiyunksft_skip=4 10*4882a593Smuzhiyuntimeout=30 11*4882a593Smuzhiyuntest_cnt=1 12*4882a593Smuzhiyunret=0 13*4882a593Smuzhiyunbail=0 14*4882a593Smuzhiyun 15*4882a593Smuzhiyunusage() { 16*4882a593Smuzhiyun echo "Usage: $0 [ -b ] [ -c ] [ -d ]" 17*4882a593Smuzhiyun echo -e "\t-b: bail out after first error, otherwise runs al testcases" 18*4882a593Smuzhiyun echo -e "\t-c: capture packets for each test using tcpdump (default: no capture)" 19*4882a593Smuzhiyun echo -e "\t-d: debug this script" 20*4882a593Smuzhiyun} 21*4882a593Smuzhiyun 22*4882a593Smuzhiyuncleanup() 23*4882a593Smuzhiyun{ 24*4882a593Smuzhiyun rm -f "$cout" "$sout" 25*4882a593Smuzhiyun rm -f "$large" "$small" 26*4882a593Smuzhiyun rm -f "$capout" 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun local netns 29*4882a593Smuzhiyun for netns in "$ns1" "$ns2" "$ns3";do 30*4882a593Smuzhiyun ip netns del $netns 31*4882a593Smuzhiyun done 32*4882a593Smuzhiyun} 33*4882a593Smuzhiyun 34*4882a593Smuzhiyunip -Version > /dev/null 2>&1 35*4882a593Smuzhiyunif [ $? -ne 0 ];then 36*4882a593Smuzhiyun echo "SKIP: Could not run test without ip tool" 37*4882a593Smuzhiyun exit $ksft_skip 38*4882a593Smuzhiyunfi 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun# "$ns1" ns2 ns3 41*4882a593Smuzhiyun# ns1eth1 ns2eth1 ns2eth3 ns3eth1 42*4882a593Smuzhiyun# netem 43*4882a593Smuzhiyun# ns1eth2 ns2eth2 44*4882a593Smuzhiyun# netem 45*4882a593Smuzhiyun 46*4882a593Smuzhiyunsetup() 47*4882a593Smuzhiyun{ 48*4882a593Smuzhiyun large=$(mktemp) 49*4882a593Smuzhiyun small=$(mktemp) 50*4882a593Smuzhiyun sout=$(mktemp) 51*4882a593Smuzhiyun cout=$(mktemp) 52*4882a593Smuzhiyun capout=$(mktemp) 53*4882a593Smuzhiyun size=$((2048 * 4096)) 54*4882a593Smuzhiyun dd if=/dev/zero of=$small bs=4096 count=20 >/dev/null 2>&1 55*4882a593Smuzhiyun dd if=/dev/zero of=$large bs=4096 count=$((size / 4096)) >/dev/null 2>&1 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun trap cleanup EXIT 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun for i in "$ns1" "$ns2" "$ns3";do 60*4882a593Smuzhiyun ip netns add $i || exit $ksft_skip 61*4882a593Smuzhiyun ip -net $i link set lo up 62*4882a593Smuzhiyun done 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun ip link add ns1eth1 netns "$ns1" type veth peer name ns2eth1 netns "$ns2" 65*4882a593Smuzhiyun ip link add ns1eth2 netns "$ns1" type veth peer name ns2eth2 netns "$ns2" 66*4882a593Smuzhiyun ip link add ns2eth3 netns "$ns2" type veth peer name ns3eth1 netns "$ns3" 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun ip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth1 69*4882a593Smuzhiyun ip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth1 nodad 70*4882a593Smuzhiyun ip -net "$ns1" link set ns1eth1 up mtu 1500 71*4882a593Smuzhiyun ip -net "$ns1" route add default via 10.0.1.2 72*4882a593Smuzhiyun ip -net "$ns1" route add default via dead:beef:1::2 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun ip -net "$ns1" addr add 10.0.2.1/24 dev ns1eth2 75*4882a593Smuzhiyun ip -net "$ns1" addr add dead:beef:2::1/64 dev ns1eth2 nodad 76*4882a593Smuzhiyun ip -net "$ns1" link set ns1eth2 up mtu 1500 77*4882a593Smuzhiyun ip -net "$ns1" route add default via 10.0.2.2 metric 101 78*4882a593Smuzhiyun ip -net "$ns1" route add default via dead:beef:2::2 metric 101 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun ip netns exec "$ns1" ./pm_nl_ctl limits 1 1 81*4882a593Smuzhiyun ip netns exec "$ns1" ./pm_nl_ctl add 10.0.2.1 dev ns1eth2 flags subflow 82*4882a593Smuzhiyun ip netns exec "$ns1" sysctl -q net.ipv4.conf.all.rp_filter=0 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun ip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1 85*4882a593Smuzhiyun ip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad 86*4882a593Smuzhiyun ip -net "$ns2" link set ns2eth1 up mtu 1500 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun ip -net "$ns2" addr add 10.0.2.2/24 dev ns2eth2 89*4882a593Smuzhiyun ip -net "$ns2" addr add dead:beef:2::2/64 dev ns2eth2 nodad 90*4882a593Smuzhiyun ip -net "$ns2" link set ns2eth2 up mtu 1500 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun ip -net "$ns2" addr add 10.0.3.2/24 dev ns2eth3 93*4882a593Smuzhiyun ip -net "$ns2" addr add dead:beef:3::2/64 dev ns2eth3 nodad 94*4882a593Smuzhiyun ip -net "$ns2" link set ns2eth3 up mtu 1500 95*4882a593Smuzhiyun ip netns exec "$ns2" sysctl -q net.ipv4.ip_forward=1 96*4882a593Smuzhiyun ip netns exec "$ns2" sysctl -q net.ipv6.conf.all.forwarding=1 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun ip -net "$ns3" addr add 10.0.3.3/24 dev ns3eth1 99*4882a593Smuzhiyun ip -net "$ns3" addr add dead:beef:3::3/64 dev ns3eth1 nodad 100*4882a593Smuzhiyun ip -net "$ns3" link set ns3eth1 up mtu 1500 101*4882a593Smuzhiyun ip -net "$ns3" route add default via 10.0.3.2 102*4882a593Smuzhiyun ip -net "$ns3" route add default via dead:beef:3::2 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun ip netns exec "$ns3" ./pm_nl_ctl limits 1 1 105*4882a593Smuzhiyun} 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun# $1: ns, $2: port 108*4882a593Smuzhiyunwait_local_port_listen() 109*4882a593Smuzhiyun{ 110*4882a593Smuzhiyun local listener_ns="${1}" 111*4882a593Smuzhiyun local port="${2}" 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun local port_hex i 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun port_hex="$(printf "%04X" "${port}")" 116*4882a593Smuzhiyun for i in $(seq 10); do 117*4882a593Smuzhiyun ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ 118*4882a593Smuzhiyun awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && 119*4882a593Smuzhiyun break 120*4882a593Smuzhiyun sleep 0.1 121*4882a593Smuzhiyun done 122*4882a593Smuzhiyun} 123*4882a593Smuzhiyun 124*4882a593Smuzhiyundo_transfer() 125*4882a593Smuzhiyun{ 126*4882a593Smuzhiyun local cin=$1 127*4882a593Smuzhiyun local sin=$2 128*4882a593Smuzhiyun local max_time=$3 129*4882a593Smuzhiyun local port 130*4882a593Smuzhiyun port=$((10000+$test_cnt)) 131*4882a593Smuzhiyun test_cnt=$((test_cnt+1)) 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun :> "$cout" 134*4882a593Smuzhiyun :> "$sout" 135*4882a593Smuzhiyun :> "$capout" 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun local addr_port 138*4882a593Smuzhiyun addr_port=$(printf "%s:%d" ${connect_addr} ${port}) 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun if $capture; then 141*4882a593Smuzhiyun local capuser 142*4882a593Smuzhiyun if [ -z $SUDO_USER ] ; then 143*4882a593Smuzhiyun capuser="" 144*4882a593Smuzhiyun else 145*4882a593Smuzhiyun capuser="-Z $SUDO_USER" 146*4882a593Smuzhiyun fi 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun local capfile="${rndh}-${port}" 149*4882a593Smuzhiyun local capopt="-i any -s 65535 -B 32768 ${capuser}" 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun ip netns exec ${ns3} tcpdump ${capopt} -w "${capfile}-listener.pcap" >> "${capout}" 2>&1 & 152*4882a593Smuzhiyun local cappid_listener=$! 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun ip netns exec ${ns1} tcpdump ${capopt} -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 & 155*4882a593Smuzhiyun local cappid_connector=$! 156*4882a593Smuzhiyun 157*4882a593Smuzhiyun sleep 1 158*4882a593Smuzhiyun fi 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun ip netns exec ${ns3} ./mptcp_connect -jt $timeout -l -p $port 0.0.0.0 < "$sin" > "$sout" & 161*4882a593Smuzhiyun local spid=$! 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun wait_local_port_listen "${ns3}" "${port}" 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun local start 166*4882a593Smuzhiyun start=$(date +%s%3N) 167*4882a593Smuzhiyun ip netns exec ${ns1} ./mptcp_connect -jt $timeout -p $port 10.0.3.3 < "$cin" > "$cout" & 168*4882a593Smuzhiyun local cpid=$! 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun wait $cpid 171*4882a593Smuzhiyun local retc=$? 172*4882a593Smuzhiyun wait $spid 173*4882a593Smuzhiyun local rets=$? 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun local stop 176*4882a593Smuzhiyun stop=$(date +%s%3N) 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun if $capture; then 179*4882a593Smuzhiyun sleep 1 180*4882a593Smuzhiyun kill ${cappid_listener} 181*4882a593Smuzhiyun kill ${cappid_connector} 182*4882a593Smuzhiyun fi 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun local duration 185*4882a593Smuzhiyun duration=$((stop-start)) 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun cmp $sin $cout > /dev/null 2>&1 188*4882a593Smuzhiyun local cmps=$? 189*4882a593Smuzhiyun cmp $cin $sout > /dev/null 2>&1 190*4882a593Smuzhiyun local cmpc=$? 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun printf "%16s" "$duration max $max_time " 193*4882a593Smuzhiyun if [ $retc -eq 0 ] && [ $rets -eq 0 ] && \ 194*4882a593Smuzhiyun [ $cmpc -eq 0 ] && [ $cmps -eq 0 ] && \ 195*4882a593Smuzhiyun [ $duration -lt $max_time ]; then 196*4882a593Smuzhiyun echo "[ OK ]" 197*4882a593Smuzhiyun cat "$capout" 198*4882a593Smuzhiyun return 0 199*4882a593Smuzhiyun fi 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun echo " [ fail ]" 202*4882a593Smuzhiyun echo "client exit code $retc, server $rets" 1>&2 203*4882a593Smuzhiyun echo -e "\nnetns ${ns3} socket stat for $port:" 1>&2 204*4882a593Smuzhiyun ip netns exec ${ns3} ss -nita 1>&2 -o "sport = :$port" 205*4882a593Smuzhiyun echo -e "\nnetns ${ns1} socket stat for $port:" 1>&2 206*4882a593Smuzhiyun ip netns exec ${ns1} ss -nita 1>&2 -o "dport = :$port" 207*4882a593Smuzhiyun ls -l $sin $cout 208*4882a593Smuzhiyun ls -l $cin $sout 209*4882a593Smuzhiyun 210*4882a593Smuzhiyun cat "$capout" 211*4882a593Smuzhiyun return 1 212*4882a593Smuzhiyun} 213*4882a593Smuzhiyun 214*4882a593Smuzhiyunrun_test() 215*4882a593Smuzhiyun{ 216*4882a593Smuzhiyun local rate1=$1 217*4882a593Smuzhiyun local rate2=$2 218*4882a593Smuzhiyun local delay1=$3 219*4882a593Smuzhiyun local delay2=$4 220*4882a593Smuzhiyun local lret 221*4882a593Smuzhiyun local dev 222*4882a593Smuzhiyun shift 4 223*4882a593Smuzhiyun local msg=$* 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun [ $delay1 -gt 0 ] && delay1="delay $delay1" || delay1="" 226*4882a593Smuzhiyun [ $delay2 -gt 0 ] && delay2="delay $delay2" || delay2="" 227*4882a593Smuzhiyun 228*4882a593Smuzhiyun for dev in ns1eth1 ns1eth2; do 229*4882a593Smuzhiyun tc -n $ns1 qdisc del dev $dev root >/dev/null 2>&1 230*4882a593Smuzhiyun done 231*4882a593Smuzhiyun for dev in ns2eth1 ns2eth2; do 232*4882a593Smuzhiyun tc -n $ns2 qdisc del dev $dev root >/dev/null 2>&1 233*4882a593Smuzhiyun done 234*4882a593Smuzhiyun tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1 235*4882a593Smuzhiyun tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2 236*4882a593Smuzhiyun tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1 237*4882a593Smuzhiyun tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2 238*4882a593Smuzhiyun 239*4882a593Smuzhiyun # time is measure in ms 240*4882a593Smuzhiyun local time=$((size * 8 * 1000 / (( $rate1 + $rate2) * 1024 *1024) )) 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun # mptcp_connect will do some sleeps to allow the mp_join handshake 243*4882a593Smuzhiyun # completion 244*4882a593Smuzhiyun time=$((time + 1350)) 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun printf "%-50s" "$msg" 247*4882a593Smuzhiyun do_transfer $small $large $((time * 11 / 10)) 248*4882a593Smuzhiyun lret=$? 249*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 250*4882a593Smuzhiyun ret=$lret 251*4882a593Smuzhiyun [ $bail -eq 0 ] || exit $ret 252*4882a593Smuzhiyun fi 253*4882a593Smuzhiyun 254*4882a593Smuzhiyun printf "%-50s" "$msg - reverse direction" 255*4882a593Smuzhiyun do_transfer $large $small $((time * 11 / 10)) 256*4882a593Smuzhiyun lret=$? 257*4882a593Smuzhiyun if [ $lret -ne 0 ]; then 258*4882a593Smuzhiyun ret=$lret 259*4882a593Smuzhiyun [ $bail -eq 0 ] || exit $ret 260*4882a593Smuzhiyun fi 261*4882a593Smuzhiyun} 262*4882a593Smuzhiyun 263*4882a593Smuzhiyunwhile getopts "bcdh" option;do 264*4882a593Smuzhiyun case "$option" in 265*4882a593Smuzhiyun "h") 266*4882a593Smuzhiyun usage $0 267*4882a593Smuzhiyun exit 0 268*4882a593Smuzhiyun ;; 269*4882a593Smuzhiyun "b") 270*4882a593Smuzhiyun bail=1 271*4882a593Smuzhiyun ;; 272*4882a593Smuzhiyun "c") 273*4882a593Smuzhiyun capture=true 274*4882a593Smuzhiyun ;; 275*4882a593Smuzhiyun "d") 276*4882a593Smuzhiyun set -x 277*4882a593Smuzhiyun ;; 278*4882a593Smuzhiyun "?") 279*4882a593Smuzhiyun usage $0 280*4882a593Smuzhiyun exit 1 281*4882a593Smuzhiyun ;; 282*4882a593Smuzhiyun esac 283*4882a593Smuzhiyundone 284*4882a593Smuzhiyun 285*4882a593Smuzhiyunsetup 286*4882a593Smuzhiyunrun_test 10 10 0 0 "balanced bwidth" 287*4882a593Smuzhiyunrun_test 10 10 1 50 "balanced bwidth with unbalanced delay" 288*4882a593Smuzhiyun 289*4882a593Smuzhiyun# we still need some additional infrastructure to pass the following test-cases 290*4882a593Smuzhiyun# run_test 30 10 0 0 "unbalanced bwidth" 291*4882a593Smuzhiyun# run_test 30 10 1 50 "unbalanced bwidth with unbalanced delay" 292*4882a593Smuzhiyun# run_test 30 10 50 1 "unbalanced bwidth with opposed, unbalanced delay" 293*4882a593Smuzhiyunexit $ret 294