Skip to content

Commit 1a418cb

Browse files
Paolo Abenidavem330
authored andcommitted
mptcp: simult flow self-tests
Add a bunch of test-cases for multiple subflow xmit: create multiple subflows simulating different links condition via netem and verify that the msk is able to use completely the aggregated bandwidth. Signed-off-by: Paolo Abeni <[email protected]> Reviewed-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c76c695 commit 1a418cb

File tree

2 files changed

+295
-1
lines changed

2 files changed

+295
-1
lines changed

tools/testing/selftests/net/mptcp/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ KSFT_KHDR_INSTALL := 1
55

66
CFLAGS = -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include
77

8-
TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh
8+
TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
9+
simult_flows.sh
910

1011
TEST_GEN_FILES = mptcp_connect pm_nl_ctl
1112

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
5+
ns1="ns1-$rndh"
6+
ns2="ns2-$rndh"
7+
ns3="ns3-$rndh"
8+
capture=false
9+
ksft_skip=4
10+
timeout=30
11+
test_cnt=1
12+
ret=0
13+
bail=0
14+
15+
usage() {
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+
22+
cleanup()
23+
{
24+
rm -f "$cin" "$cout"
25+
rm -f "$sin" "$sout"
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+
34+
ip -Version > /dev/null 2>&1
35+
if [ $? -ne 0 ];then
36+
echo "SKIP: Could not run test without ip tool"
37+
exit $ksft_skip
38+
fi
39+
40+
# "$ns1" ns2 ns3
41+
# ns1eth1 ns2eth1 ns2eth3 ns3eth1
42+
# netem
43+
# ns1eth2 ns2eth2
44+
# netem
45+
46+
setup()
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
108+
wait_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+
124+
do_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 "\nnetns ${ns3} socket stat for $port:" 1>&2
204+
ip netns exec ${ns3} ss -nita 1>&2 -o "sport = :$port"
205+
echo "\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+
214+
run_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+
263+
while 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
283+
done
284+
285+
setup
286+
run_test 10 10 0 0 "balanced bwidth"
287+
run_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"
293+
exit $ret

0 commit comments

Comments
 (0)