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