1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# Double quotes to prevent globbing and word splitting is recommended in new 5# code but we accept it, especially because there were too many before having 6# address all other issues detected by shellcheck. 7#shellcheck disable=SC2086 8 9. "$(dirname "${0}")/mptcp_lib.sh" 10 11ns1="" 12ns2="" 13ns3="" 14capture=false 15timeout_poll=30 16timeout_test=$((timeout_poll * 2 + 1)) 17# a bit more space: because we have more to display 18MPTCP_LIB_TEST_FORMAT="%02u %-60s" 19ret=0 20bail=0 21slack=50 22large="" 23small="" 24sout="" 25cout="" 26capout="" 27capprefix="" 28size=0 29 30usage() { 31 echo "Usage: $0 [ -b ] [ -c ] [ -d ] [ -i]" 32 echo -e "\t-b: bail out after first error, otherwise runs all testcases" 33 echo -e "\t-c: capture packets for each test using tcpdump (default: no capture)" 34 echo -e "\t-d: debug this script" 35 echo -e "\t-i: use 'ip mptcp' instead of 'pm_nl_ctl'" 36} 37 38# This function is used in the cleanup trap 39#shellcheck disable=SC2317,SC2329 40cleanup() 41{ 42 rm -f "$cout" "$sout" 43 rm -f "$large" "$small" 44 rm -f "$capout" 45 46 mptcp_lib_ns_exit "${ns1}" "${ns2}" "${ns3}" 47} 48 49mptcp_lib_check_mptcp 50mptcp_lib_check_tools ip tc 51 52# "$ns1" ns2 ns3 53# ns1eth1 ns2eth1 ns2eth3 ns3eth1 54# netem 55# ns1eth2 ns2eth2 56# netem 57 58setup() 59{ 60 large=$(mktemp) 61 small=$(mktemp) 62 sout=$(mktemp) 63 cout=$(mktemp) 64 capout=$(mktemp) 65 size=$((2 * 2048 * 4096)) 66 67 dd if=/dev/zero of=$small bs=4096 count=20 >/dev/null 2>&1 68 dd if=/dev/zero of=$large bs=4096 count=$((size / 4096)) >/dev/null 2>&1 69 70 trap cleanup EXIT 71 72 mptcp_lib_ns_init ns1 ns2 ns3 73 74 if $capture; then 75 capprefix="simult_flows-${ns1:4}" 76 mptcp_lib_pr_info "pcap will have this prefix: ${capprefix}-" 77 fi 78 79 ip link add ns1eth1 netns "$ns1" type veth peer name ns2eth1 netns "$ns2" 80 ip link add ns1eth2 netns "$ns1" type veth peer name ns2eth2 netns "$ns2" 81 ip link add ns2eth3 netns "$ns2" type veth peer name ns3eth1 netns "$ns3" 82 83 ip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth1 84 ip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth1 nodad 85 ip -net "$ns1" link set ns1eth1 up mtu 1500 gso_max_segs 0 86 ip -net "$ns1" route add default via 10.0.1.2 87 ip -net "$ns1" route add default via dead:beef:1::2 88 89 ip -net "$ns1" addr add 10.0.2.1/24 dev ns1eth2 90 ip -net "$ns1" addr add dead:beef:2::1/64 dev ns1eth2 nodad 91 ip -net "$ns1" link set ns1eth2 up mtu 1500 gso_max_segs 0 92 ip -net "$ns1" route add default via 10.0.2.2 metric 101 93 ip -net "$ns1" route add default via dead:beef:2::2 metric 101 94 95 mptcp_lib_pm_nl_set_limits "${ns1}" 1 1 96 mptcp_lib_pm_nl_add_endpoint "${ns1}" 10.0.2.1 dev ns1eth2 flags subflow 97 98 ip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1 99 ip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad 100 ip -net "$ns2" link set ns2eth1 up mtu 1500 gso_max_segs 0 101 102 ip -net "$ns2" addr add 10.0.2.2/24 dev ns2eth2 103 ip -net "$ns2" addr add dead:beef:2::2/64 dev ns2eth2 nodad 104 ip -net "$ns2" link set ns2eth2 up mtu 1500 gso_max_segs 0 105 106 ip -net "$ns2" addr add 10.0.3.2/24 dev ns2eth3 107 ip -net "$ns2" addr add dead:beef:3::2/64 dev ns2eth3 nodad 108 ip -net "$ns2" link set ns2eth3 up mtu 1500 gso_max_segs 0 109 ip netns exec "$ns2" sysctl -q net.ipv4.ip_forward=1 110 ip netns exec "$ns2" sysctl -q net.ipv6.conf.all.forwarding=1 111 112 ip -net "$ns3" addr add 10.0.3.3/24 dev ns3eth1 113 ip -net "$ns3" addr add dead:beef:3::3/64 dev ns3eth1 nodad 114 ip -net "$ns3" link set ns3eth1 up mtu 1500 gso_max_segs 0 115 ip -net "$ns3" route add default via 10.0.3.2 116 ip -net "$ns3" route add default via dead:beef:3::2 117 118 mptcp_lib_pm_nl_set_limits "${ns3}" 1 1 119 120 # debug build can slow down measurably the test program 121 # we use quite tight time limit on the run-time, to ensure 122 # maximum B/W usage. 123 # Use kmemleak/lockdep/kasan/prove_locking presence as a rough 124 # estimate for this being a debug kernel and increase the 125 # maximum run-time accordingly. Observed run times for CI builds 126 # running selftests, including kbuild, were used to determine the 127 # amount of time to add. 128 grep -q ' kmemleak_init$\| lockdep_init$\| kasan_init$\| prove_locking$' /proc/kallsyms && slack=$((slack+550)) 129} 130 131do_transfer() 132{ 133 local cin=$1 134 local sin=$2 135 local max_time=$3 136 local port 137 port=$((10000+MPTCP_LIB_TEST_COUNTER)) 138 139 :> "$cout" 140 :> "$sout" 141 :> "$capout" 142 143 if $capture; then 144 local capuser 145 if [ -z $SUDO_USER ] ; then 146 capuser="" 147 else 148 capuser="-Z $SUDO_USER" 149 fi 150 151 local capfile="${capprefix}-${port}" 152 local capopt="-i any -s 108 -B 32768 ${capuser}" 153 154 ip netns exec ${ns3} tcpdump ${capopt} -w "${capfile}-listener.pcap" >> "${capout}" 2>&1 & 155 local cappid_listener=$! 156 157 ip netns exec ${ns1} tcpdump ${capopt} -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 & 158 local cappid_connector=$! 159 160 sleep 1 161 fi 162 163 mptcp_lib_nstat_init "${ns3}" 164 mptcp_lib_nstat_init "${ns1}" 165 166 ip netns exec ${ns3} \ 167 ./mptcp_connect -jt ${timeout_poll} -l -p $port -T $max_time \ 168 0.0.0.0 < "$sin" > "$sout" & 169 local spid=$! 170 171 mptcp_lib_wait_local_port_listen "${ns3}" "${port}" 172 173 ip netns exec ${ns1} \ 174 ./mptcp_connect -jt ${timeout_poll} -p $port -T $max_time \ 175 10.0.3.3 < "$cin" > "$cout" & 176 local cpid=$! 177 178 mptcp_lib_wait_timeout "${timeout_test}" "${ns3}" "${ns1}" "${port}" \ 179 "${cpid}" "${spid}" & 180 local timeout_pid=$! 181 182 wait $cpid 183 local retc=$? 184 wait $spid 185 local rets=$? 186 187 if kill -0 $timeout_pid; then 188 # Finished before the timeout: kill the background job 189 mptcp_lib_kill_group_wait $timeout_pid 190 timeout_pid=0 191 fi 192 193 if $capture; then 194 sleep 1 195 kill ${cappid_listener} 196 kill ${cappid_connector} 197 fi 198 199 mptcp_lib_nstat_get "${ns3}" 200 mptcp_lib_nstat_get "${ns1}" 201 202 cmp $sin $cout > /dev/null 2>&1 203 local cmps=$? 204 cmp $cin $sout > /dev/null 2>&1 205 local cmpc=$? 206 207 if [ $retc -eq 0 ] && [ $rets -eq 0 ] && 208 [ $cmpc -eq 0 ] && [ $cmps -eq 0 ] && 209 [ $timeout_pid -eq 0 ]; then 210 printf "%-16s" " max $max_time " 211 mptcp_lib_pr_ok 212 cat "$capout" 213 return 0 214 fi 215 216 mptcp_lib_pr_fail "client exit code $retc, server $rets" 217 mptcp_lib_pr_err_stats "${ns3}" "${ns1}" "${port}" 218 ls -l $sin $cout 219 ls -l $cin $sout 220 221 cat "$capout" 222 return 1 223} 224 225run_test() 226{ 227 local rate1=$1 228 local rate2=$2 229 local delay1=$3 230 local delay2=$4 231 local limit1=$5 232 local limit2=$6 233 local lret 234 local dev 235 shift 6 236 local msg=$* 237 238 [ $delay1 -gt 0 ] && delay1="delay ${delay1}ms" || delay1="" 239 [ $delay2 -gt 0 ] && delay2="delay ${delay2}ms" || delay2="" 240 241 for dev in ns1eth1 ns1eth2; do 242 tc -n $ns1 qdisc del dev $dev root >/dev/null 2>&1 243 done 244 for dev in ns2eth1 ns2eth2; do 245 tc -n $ns2 qdisc del dev $dev root >/dev/null 2>&1 246 done 247 248 # keep the queued pkts number low, or the RTT estimator will see 249 # increasing latency over time. 250 tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1 limit ${limit1} 251 tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2 limit ${limit2} 252 tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1 limit ${limit1} 253 tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2 limit ${limit2} 254 255 # time is measured in ms, account for transfer size, aggregated link speed 256 # and header overhead (10%) 257 # ms byte -> bit 10% mbit -> kbit -> bit 10% 258 local time=$((1000 * size * 8 * 10 / ((rate1 + rate2) * 1000 * 1000 * 9) )) 259 260 # mptcp_connect will do some sleeps to allow the mp_join handshake 261 # completion (see mptcp_connect): 200ms on each side, add some slack 262 time=$((time + 400 + slack)) 263 264 mptcp_lib_print_title "$msg" 265 do_transfer $small $large $time 266 lret=$? 267 mptcp_lib_result_code "${lret}" "${msg}" 268 if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then 269 ret=$lret 270 [ $bail -eq 0 ] || exit $ret 271 fi 272 273 msg+=" - reverse direction" 274 mptcp_lib_print_title "${msg}" 275 do_transfer $large $small $time 276 lret=$? 277 mptcp_lib_result_code "${lret}" "${msg}" 278 if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then 279 ret=$lret 280 [ $bail -eq 0 ] || exit $ret 281 fi 282} 283 284while getopts "bcdhi" option;do 285 case "$option" in 286 "h") 287 usage $0 288 exit ${KSFT_PASS} 289 ;; 290 "b") 291 bail=1 292 ;; 293 "c") 294 capture=true 295 ;; 296 "d") 297 set -x 298 ;; 299 "i") 300 mptcp_lib_set_ip_mptcp 301 ;; 302 "?") 303 usage $0 304 exit ${KSFT_FAIL} 305 ;; 306 esac 307done 308 309setup 310mptcp_lib_subtests_last_ts_reset 311run_test 10 10 0 0 20 20 "balanced bwidth" 312run_test 10 10 1 25 20 50 "balanced bwidth with unbalanced delay" 313 314# we still need some additional infrastructure to pass the following test-cases 315MPTCP_LIB_SUBTEST_FLAKY=1 run_test 10 3 0 0 30 20 "unbalanced bwidth" 316run_test 10 3 1 25 40 30 "unbalanced bwidth with unbalanced delay" 317run_test 10 3 25 1 50 30 "unbalanced bwidth with opposed, unbalanced delay" 318 319mptcp_lib_result_print_all_tap 320exit $ret 321