18c2ecf20Sopenharmony_ci#!/bin/bash
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci. "$(dirname "${0}")/mptcp_lib.sh"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_cirndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
78c2ecf20Sopenharmony_cins1="ns1-$rndh"
88c2ecf20Sopenharmony_cins2="ns2-$rndh"
98c2ecf20Sopenharmony_cins3="ns3-$rndh"
108c2ecf20Sopenharmony_cicapture=false
118c2ecf20Sopenharmony_ciksft_skip=4
128c2ecf20Sopenharmony_citimeout=30
138c2ecf20Sopenharmony_citest_cnt=1
148c2ecf20Sopenharmony_ciret=0
158c2ecf20Sopenharmony_cibail=0
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciusage() {
188c2ecf20Sopenharmony_ci	echo "Usage: $0 [ -b ] [ -c ] [ -d ]"
198c2ecf20Sopenharmony_ci	echo -e "\t-b: bail out after first error, otherwise runs al testcases"
208c2ecf20Sopenharmony_ci	echo -e "\t-c: capture packets for each test using tcpdump (default: no capture)"
218c2ecf20Sopenharmony_ci	echo -e "\t-d: debug this script"
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cicleanup()
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	rm -f "$cout" "$sout"
278c2ecf20Sopenharmony_ci	rm -f "$large" "$small"
288c2ecf20Sopenharmony_ci	rm -f "$capout"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	local netns
318c2ecf20Sopenharmony_ci	for netns in "$ns1" "$ns2" "$ns3";do
328c2ecf20Sopenharmony_ci		ip netns del $netns
338c2ecf20Sopenharmony_ci	done
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cimptcp_lib_check_mptcp
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciip -Version > /dev/null 2>&1
398c2ecf20Sopenharmony_ciif [ $? -ne 0 ];then
408c2ecf20Sopenharmony_ci	echo "SKIP: Could not run test without ip tool"
418c2ecf20Sopenharmony_ci	exit $ksft_skip
428c2ecf20Sopenharmony_cifi
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#  "$ns1"              ns2                    ns3
458c2ecf20Sopenharmony_ci#     ns1eth1    ns2eth1   ns2eth3      ns3eth1
468c2ecf20Sopenharmony_ci#            netem
478c2ecf20Sopenharmony_ci#     ns1eth2    ns2eth2
488c2ecf20Sopenharmony_ci#            netem
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cisetup()
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	large=$(mktemp)
538c2ecf20Sopenharmony_ci	small=$(mktemp)
548c2ecf20Sopenharmony_ci	sout=$(mktemp)
558c2ecf20Sopenharmony_ci	cout=$(mktemp)
568c2ecf20Sopenharmony_ci	capout=$(mktemp)
578c2ecf20Sopenharmony_ci	size=$((2048 * 4096))
588c2ecf20Sopenharmony_ci	dd if=/dev/zero of=$small bs=4096 count=20 >/dev/null 2>&1
598c2ecf20Sopenharmony_ci	dd if=/dev/zero of=$large bs=4096 count=$((size / 4096)) >/dev/null 2>&1
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	trap cleanup EXIT
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	for i in "$ns1" "$ns2" "$ns3";do
648c2ecf20Sopenharmony_ci		ip netns add $i || exit $ksft_skip
658c2ecf20Sopenharmony_ci		ip -net $i link set lo up
668c2ecf20Sopenharmony_ci	done
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ip link add ns1eth1 netns "$ns1" type veth peer name ns2eth1 netns "$ns2"
698c2ecf20Sopenharmony_ci	ip link add ns1eth2 netns "$ns1" type veth peer name ns2eth2 netns "$ns2"
708c2ecf20Sopenharmony_ci	ip link add ns2eth3 netns "$ns2" type veth peer name ns3eth1 netns "$ns3"
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	ip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth1
738c2ecf20Sopenharmony_ci	ip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth1 nodad
748c2ecf20Sopenharmony_ci	ip -net "$ns1" link set ns1eth1 up mtu 1500
758c2ecf20Sopenharmony_ci	ip -net "$ns1" route add default via 10.0.1.2
768c2ecf20Sopenharmony_ci	ip -net "$ns1" route add default via dead:beef:1::2
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	ip -net "$ns1" addr add 10.0.2.1/24 dev ns1eth2
798c2ecf20Sopenharmony_ci	ip -net "$ns1" addr add dead:beef:2::1/64 dev ns1eth2 nodad
808c2ecf20Sopenharmony_ci	ip -net "$ns1" link set ns1eth2 up mtu 1500
818c2ecf20Sopenharmony_ci	ip -net "$ns1" route add default via 10.0.2.2 metric 101
828c2ecf20Sopenharmony_ci	ip -net "$ns1" route add default via dead:beef:2::2 metric 101
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	ip netns exec "$ns1" ./pm_nl_ctl limits 1 1
858c2ecf20Sopenharmony_ci	ip netns exec "$ns1" ./pm_nl_ctl add 10.0.2.1 dev ns1eth2 flags subflow
868c2ecf20Sopenharmony_ci	ip netns exec "$ns1" sysctl -q net.ipv4.conf.all.rp_filter=0
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1
898c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad
908c2ecf20Sopenharmony_ci	ip -net "$ns2" link set ns2eth1 up mtu 1500
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add 10.0.2.2/24 dev ns2eth2
938c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add dead:beef:2::2/64 dev ns2eth2 nodad
948c2ecf20Sopenharmony_ci	ip -net "$ns2" link set ns2eth2 up mtu 1500
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add 10.0.3.2/24 dev ns2eth3
978c2ecf20Sopenharmony_ci	ip -net "$ns2" addr add dead:beef:3::2/64 dev ns2eth3 nodad
988c2ecf20Sopenharmony_ci	ip -net "$ns2" link set ns2eth3 up mtu 1500
998c2ecf20Sopenharmony_ci	ip netns exec "$ns2" sysctl -q net.ipv4.ip_forward=1
1008c2ecf20Sopenharmony_ci	ip netns exec "$ns2" sysctl -q net.ipv6.conf.all.forwarding=1
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	ip -net "$ns3" addr add 10.0.3.3/24 dev ns3eth1
1038c2ecf20Sopenharmony_ci	ip -net "$ns3" addr add dead:beef:3::3/64 dev ns3eth1 nodad
1048c2ecf20Sopenharmony_ci	ip -net "$ns3" link set ns3eth1 up mtu 1500
1058c2ecf20Sopenharmony_ci	ip -net "$ns3" route add default via 10.0.3.2
1068c2ecf20Sopenharmony_ci	ip -net "$ns3" route add default via dead:beef:3::2
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	ip netns exec "$ns3" ./pm_nl_ctl limits 1 1
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci# $1: ns, $2: port
1128c2ecf20Sopenharmony_ciwait_local_port_listen()
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	local listener_ns="${1}"
1158c2ecf20Sopenharmony_ci	local port="${2}"
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	local port_hex i
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	port_hex="$(printf "%04X" "${port}")"
1208c2ecf20Sopenharmony_ci	for i in $(seq 10); do
1218c2ecf20Sopenharmony_ci		ip netns exec "${listener_ns}" cat /proc/net/tcp* | \
1228c2ecf20Sopenharmony_ci			awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" &&
1238c2ecf20Sopenharmony_ci			break
1248c2ecf20Sopenharmony_ci		sleep 0.1
1258c2ecf20Sopenharmony_ci	done
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cido_transfer()
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	local cin=$1
1318c2ecf20Sopenharmony_ci	local sin=$2
1328c2ecf20Sopenharmony_ci	local max_time=$3
1338c2ecf20Sopenharmony_ci	local port
1348c2ecf20Sopenharmony_ci	port=$((10000+$test_cnt))
1358c2ecf20Sopenharmony_ci	test_cnt=$((test_cnt+1))
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	:> "$cout"
1388c2ecf20Sopenharmony_ci	:> "$sout"
1398c2ecf20Sopenharmony_ci	:> "$capout"
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	local addr_port
1428c2ecf20Sopenharmony_ci	addr_port=$(printf "%s:%d" ${connect_addr} ${port})
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if $capture; then
1458c2ecf20Sopenharmony_ci		local capuser
1468c2ecf20Sopenharmony_ci		if [ -z $SUDO_USER ] ; then
1478c2ecf20Sopenharmony_ci			capuser=""
1488c2ecf20Sopenharmony_ci		else
1498c2ecf20Sopenharmony_ci			capuser="-Z $SUDO_USER"
1508c2ecf20Sopenharmony_ci		fi
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		local capfile="${rndh}-${port}"
1538c2ecf20Sopenharmony_ci		local capopt="-i any -s 65535 -B 32768 ${capuser}"
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		ip netns exec ${ns3}  tcpdump ${capopt} -w "${capfile}-listener.pcap"  >> "${capout}" 2>&1 &
1568c2ecf20Sopenharmony_ci		local cappid_listener=$!
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		ip netns exec ${ns1} tcpdump ${capopt} -w "${capfile}-connector.pcap" >> "${capout}" 2>&1 &
1598c2ecf20Sopenharmony_ci		local cappid_connector=$!
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		sleep 1
1628c2ecf20Sopenharmony_ci	fi
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	ip netns exec ${ns3} ./mptcp_connect -jt $timeout -l -p $port 0.0.0.0 < "$sin" > "$sout" &
1658c2ecf20Sopenharmony_ci	local spid=$!
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	wait_local_port_listen "${ns3}" "${port}"
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	local start
1708c2ecf20Sopenharmony_ci	start=$(date +%s%3N)
1718c2ecf20Sopenharmony_ci	ip netns exec ${ns1} ./mptcp_connect -jt $timeout -p $port 10.0.3.3 < "$cin" > "$cout" &
1728c2ecf20Sopenharmony_ci	local cpid=$!
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	wait $cpid
1758c2ecf20Sopenharmony_ci	local retc=$?
1768c2ecf20Sopenharmony_ci	wait $spid
1778c2ecf20Sopenharmony_ci	local rets=$?
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	local stop
1808c2ecf20Sopenharmony_ci	stop=$(date +%s%3N)
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if $capture; then
1838c2ecf20Sopenharmony_ci		sleep 1
1848c2ecf20Sopenharmony_ci		kill ${cappid_listener}
1858c2ecf20Sopenharmony_ci		kill ${cappid_connector}
1868c2ecf20Sopenharmony_ci	fi
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	local duration
1898c2ecf20Sopenharmony_ci	duration=$((stop-start))
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	cmp $sin $cout > /dev/null 2>&1
1928c2ecf20Sopenharmony_ci	local cmps=$?
1938c2ecf20Sopenharmony_ci	cmp $cin $sout > /dev/null 2>&1
1948c2ecf20Sopenharmony_ci	local cmpc=$?
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	printf "%16s" "$duration max $max_time "
1978c2ecf20Sopenharmony_ci	if [ $retc -eq 0 ] && [ $rets -eq 0 ] && \
1988c2ecf20Sopenharmony_ci	   [ $cmpc -eq 0 ] && [ $cmps -eq 0 ] && \
1998c2ecf20Sopenharmony_ci	   [ $duration -lt $max_time ]; then
2008c2ecf20Sopenharmony_ci		echo "[ OK ]"
2018c2ecf20Sopenharmony_ci		cat "$capout"
2028c2ecf20Sopenharmony_ci		return 0
2038c2ecf20Sopenharmony_ci	fi
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	echo " [ fail ]"
2068c2ecf20Sopenharmony_ci	echo "client exit code $retc, server $rets" 1>&2
2078c2ecf20Sopenharmony_ci	echo -e "\nnetns ${ns3} socket stat for $port:" 1>&2
2088c2ecf20Sopenharmony_ci	ip netns exec ${ns3} ss -nita 1>&2 -o "sport = :$port"
2098c2ecf20Sopenharmony_ci	echo -e "\nnetns ${ns1} socket stat for $port:" 1>&2
2108c2ecf20Sopenharmony_ci	ip netns exec ${ns1} ss -nita 1>&2 -o "dport = :$port"
2118c2ecf20Sopenharmony_ci	ls -l $sin $cout
2128c2ecf20Sopenharmony_ci	ls -l $cin $sout
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	cat "$capout"
2158c2ecf20Sopenharmony_ci	return 1
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cirun_test()
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	local rate1=$1
2218c2ecf20Sopenharmony_ci	local rate2=$2
2228c2ecf20Sopenharmony_ci	local delay1=$3
2238c2ecf20Sopenharmony_ci	local delay2=$4
2248c2ecf20Sopenharmony_ci	local lret
2258c2ecf20Sopenharmony_ci	local dev
2268c2ecf20Sopenharmony_ci	shift 4
2278c2ecf20Sopenharmony_ci	local msg=$*
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	[ $delay1 -gt 0 ] && delay1="delay $delay1" || delay1=""
2308c2ecf20Sopenharmony_ci	[ $delay2 -gt 0 ] && delay2="delay $delay2" || delay2=""
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for dev in ns1eth1 ns1eth2; do
2338c2ecf20Sopenharmony_ci		tc -n $ns1 qdisc del dev $dev root >/dev/null 2>&1
2348c2ecf20Sopenharmony_ci	done
2358c2ecf20Sopenharmony_ci	for dev in ns2eth1 ns2eth2; do
2368c2ecf20Sopenharmony_ci		tc -n $ns2 qdisc del dev $dev root >/dev/null 2>&1
2378c2ecf20Sopenharmony_ci	done
2388c2ecf20Sopenharmony_ci	tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1
2398c2ecf20Sopenharmony_ci	tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2
2408c2ecf20Sopenharmony_ci	tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1
2418c2ecf20Sopenharmony_ci	tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	# time is measure in ms
2448c2ecf20Sopenharmony_ci	local time=$((size * 8 * 1000 / (( $rate1 + $rate2) * 1024 *1024) ))
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	# mptcp_connect will do some sleeps to allow the mp_join handshake
2478c2ecf20Sopenharmony_ci	# completion
2488c2ecf20Sopenharmony_ci	time=$((time + 1350))
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	printf "%-50s" "$msg"
2518c2ecf20Sopenharmony_ci	do_transfer $small $large $((time * 11 / 10))
2528c2ecf20Sopenharmony_ci	lret=$?
2538c2ecf20Sopenharmony_ci	if [ $lret -ne 0 ]; then
2548c2ecf20Sopenharmony_ci		ret=$lret
2558c2ecf20Sopenharmony_ci		[ $bail -eq 0 ] || exit $ret
2568c2ecf20Sopenharmony_ci	fi
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	printf "%-50s" "$msg - reverse direction"
2598c2ecf20Sopenharmony_ci	do_transfer $large $small $((time * 11 / 10))
2608c2ecf20Sopenharmony_ci	lret=$?
2618c2ecf20Sopenharmony_ci	if [ $lret -ne 0 ]; then
2628c2ecf20Sopenharmony_ci		ret=$lret
2638c2ecf20Sopenharmony_ci		[ $bail -eq 0 ] || exit $ret
2648c2ecf20Sopenharmony_ci	fi
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ciwhile getopts "bcdh" option;do
2688c2ecf20Sopenharmony_ci	case "$option" in
2698c2ecf20Sopenharmony_ci	"h")
2708c2ecf20Sopenharmony_ci		usage $0
2718c2ecf20Sopenharmony_ci		exit 0
2728c2ecf20Sopenharmony_ci		;;
2738c2ecf20Sopenharmony_ci	"b")
2748c2ecf20Sopenharmony_ci		bail=1
2758c2ecf20Sopenharmony_ci		;;
2768c2ecf20Sopenharmony_ci	"c")
2778c2ecf20Sopenharmony_ci		capture=true
2788c2ecf20Sopenharmony_ci		;;
2798c2ecf20Sopenharmony_ci	"d")
2808c2ecf20Sopenharmony_ci		set -x
2818c2ecf20Sopenharmony_ci		;;
2828c2ecf20Sopenharmony_ci	"?")
2838c2ecf20Sopenharmony_ci		usage $0
2848c2ecf20Sopenharmony_ci		exit 1
2858c2ecf20Sopenharmony_ci		;;
2868c2ecf20Sopenharmony_ci	esac
2878c2ecf20Sopenharmony_cidone
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cisetup
2908c2ecf20Sopenharmony_cirun_test 10 10 0 0 "balanced bwidth"
2918c2ecf20Sopenharmony_cirun_test 10 10 1 50 "balanced bwidth with unbalanced delay"
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci# we still need some additional infrastructure to pass the following test-cases
2948c2ecf20Sopenharmony_ci# run_test 30 10 0 0 "unbalanced bwidth"
2958c2ecf20Sopenharmony_ci# run_test 30 10 1 50 "unbalanced bwidth with unbalanced delay"
2968c2ecf20Sopenharmony_ci# run_test 30 10 50 1 "unbalanced bwidth with opposed, unbalanced delay"
2978c2ecf20Sopenharmony_ciexit $ret
298