1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ret=0
5sin=""
6sout=""
7cin=""
8cout=""
9ksft_skip=4
10timeout=30
11capture=0
12
13TEST_COUNT=0
14
15init()
16{
17	capout=$(mktemp)
18
19	rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
20
21	ns1="ns1-$rndh"
22	ns2="ns2-$rndh"
23
24	for netns in "$ns1" "$ns2";do
25		ip netns add $netns || exit $ksft_skip
26		ip -net $netns link set lo up
27		ip netns exec $netns sysctl -q net.mptcp.enabled=1
28		ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0
29		ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0
30	done
31
32	#  ns1              ns2
33	# ns1eth1    ns2eth1
34	# ns1eth2    ns2eth2
35	# ns1eth3    ns2eth3
36	# ns1eth4    ns2eth4
37
38	for i in `seq 1 4`; do
39		ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2"
40		ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i
41		ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad
42		ip -net "$ns1" link set ns1eth$i up
43
44		ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i
45		ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad
46		ip -net "$ns2" link set ns2eth$i up
47
48		# let $ns2 reach any $ns1 address from any interface
49		ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
50	done
51}
52
53cleanup_partial()
54{
55	rm -f "$capout"
56
57	for netns in "$ns1" "$ns2"; do
58		ip netns del $netns
59	done
60}
61
62cleanup()
63{
64	rm -f "$cin" "$cout"
65	rm -f "$sin" "$sout"
66	cleanup_partial
67}
68
69reset()
70{
71	cleanup_partial
72	init
73}
74
75for arg in "$@"; do
76	if [ "$arg" = "-c" ]; then
77		capture=1
78	fi
79done
80
81ip -Version > /dev/null 2>&1
82if [ $? -ne 0 ];then
83	echo "SKIP: Could not run test without ip tool"
84	exit $ksft_skip
85fi
86
87
88check_transfer()
89{
90	in=$1
91	out=$2
92	what=$3
93
94	cmp "$in" "$out" > /dev/null 2>&1
95	if [ $? -ne 0 ] ;then
96		echo "[ FAIL ] $what does not match (in, out):"
97		print_file_err "$in"
98		print_file_err "$out"
99
100		return 1
101	fi
102
103	return 0
104}
105
106do_ping()
107{
108	listener_ns="$1"
109	connector_ns="$2"
110	connect_addr="$3"
111
112	ip netns exec ${connector_ns} ping -q -c 1 $connect_addr >/dev/null
113	if [ $? -ne 0 ] ; then
114		echo "$listener_ns -> $connect_addr connectivity [ FAIL ]" 1>&2
115		ret=1
116	fi
117}
118
119do_transfer()
120{
121	listener_ns="$1"
122	connector_ns="$2"
123	cl_proto="$3"
124	srv_proto="$4"
125	connect_addr="$5"
126
127	port=$((10000+$TEST_COUNT))
128	TEST_COUNT=$((TEST_COUNT+1))
129
130	:> "$cout"
131	:> "$sout"
132	:> "$capout"
133
134	if [ $capture -eq 1 ]; then
135		if [ -z $SUDO_USER ] ; then
136			capuser=""
137		else
138			capuser="-Z $SUDO_USER"
139		fi
140
141		capfile="mp_join-${listener_ns}.pcap"
142
143		echo "Capturing traffic for test $TEST_COUNT into $capfile"
144		ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 &
145		cappid=$!
146
147		sleep 1
148	fi
149
150	ip netns exec ${listener_ns} ./mptcp_connect -j -t $timeout -l -p $port -s ${srv_proto} 0.0.0.0 < "$sin" > "$sout" &
151	spid=$!
152
153	sleep 1
154
155	ip netns exec ${connector_ns} ./mptcp_connect -j -t $timeout -p $port -s ${cl_proto} $connect_addr < "$cin" > "$cout" &
156	cpid=$!
157
158	wait $cpid
159	retc=$?
160	wait $spid
161	rets=$?
162
163	if [ $capture -eq 1 ]; then
164	    sleep 1
165	    kill $cappid
166	fi
167
168	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
169		echo " client exit code $retc, server $rets" 1>&2
170		echo "\nnetns ${listener_ns} socket stat for $port:" 1>&2
171		ip netns exec ${listener_ns} ss -nita 1>&2 -o "sport = :$port"
172		echo "\nnetns ${connector_ns} socket stat for $port:" 1>&2
173		ip netns exec ${connector_ns} ss -nita 1>&2 -o "dport = :$port"
174
175		cat "$capout"
176		return 1
177	fi
178
179	check_transfer $sin $cout "file received by client"
180	retc=$?
181	check_transfer $cin $sout "file received by server"
182	rets=$?
183
184	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
185		cat "$capout"
186		return 0
187	fi
188
189	cat "$capout"
190	return 1
191}
192
193make_file()
194{
195	name=$1
196	who=$2
197
198	SIZE=1
199
200	dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
201	echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name"
202
203	echo "Created $name (size $SIZE KB) containing data sent by $who"
204}
205
206run_tests()
207{
208	listener_ns="$1"
209	connector_ns="$2"
210	connect_addr="$3"
211	lret=0
212
213	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr}
214	lret=$?
215	if [ $lret -ne 0 ]; then
216		ret=$lret
217		return
218	fi
219}
220
221chk_join_nr()
222{
223	local msg="$1"
224	local syn_nr=$2
225	local syn_ack_nr=$3
226	local ack_nr=$4
227	local count
228	local dump_stats
229
230	printf "%-36s %s" "$msg" "syn"
231	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}'`
232	[ -z "$count" ] && count=0
233	if [ "$count" != "$syn_nr" ]; then
234		echo "[fail] got $count JOIN[s] syn expected $syn_nr"
235		ret=1
236		dump_stats=1
237	else
238		echo -n "[ ok ]"
239	fi
240
241	echo -n " - synack"
242	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}'`
243	[ -z "$count" ] && count=0
244	if [ "$count" != "$syn_ack_nr" ]; then
245		echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr"
246		ret=1
247		dump_stats=1
248	else
249		echo -n "[ ok ]"
250	fi
251
252	echo -n " - ack"
253	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinAckRx | awk '{print $2}'`
254	[ -z "$count" ] && count=0
255	if [ "$count" != "$ack_nr" ]; then
256		echo "[fail] got $count JOIN[s] ack expected $ack_nr"
257		ret=1
258		dump_stats=1
259	else
260		echo "[ ok ]"
261	fi
262	if [ "${dump_stats}" = 1 ]; then
263		echo Server ns stats
264		ip netns exec $ns1 nstat -as | grep MPTcp
265		echo Client ns stats
266		ip netns exec $ns2 nstat -as | grep MPTcp
267	fi
268}
269
270sin=$(mktemp)
271sout=$(mktemp)
272cin=$(mktemp)
273cout=$(mktemp)
274init
275make_file "$cin" "client"
276make_file "$sin" "server"
277trap cleanup EXIT
278
279run_tests $ns1 $ns2 10.0.1.1
280chk_join_nr "no JOIN" "0" "0" "0"
281
282# subflow limted by client
283reset
284ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
285run_tests $ns1 $ns2 10.0.1.1
286chk_join_nr "single subflow, limited by client" 0 0 0
287
288# subflow limted by server
289reset
290ip netns exec $ns2 ./pm_nl_ctl limits 0 1
291ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
292run_tests $ns1 $ns2 10.0.1.1
293chk_join_nr "single subflow, limited by server" 1 1 0
294
295# subflow
296reset
297ip netns exec $ns1 ./pm_nl_ctl limits 0 1
298ip netns exec $ns2 ./pm_nl_ctl limits 0 1
299ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
300run_tests $ns1 $ns2 10.0.1.1
301chk_join_nr "single subflow" 1 1 1
302
303# multiple subflows
304reset
305ip netns exec $ns1 ./pm_nl_ctl limits 0 2
306ip netns exec $ns2 ./pm_nl_ctl limits 0 2
307ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
308ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
309run_tests $ns1 $ns2 10.0.1.1
310chk_join_nr "multiple subflows" 2 2 2
311
312# multiple subflows limited by serverf
313reset
314ip netns exec $ns1 ./pm_nl_ctl limits 0 1
315ip netns exec $ns2 ./pm_nl_ctl limits 0 2
316ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
317ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
318run_tests $ns1 $ns2 10.0.1.1
319chk_join_nr "multiple subflows, limited by server" 2 2 1
320
321# add_address, unused
322reset
323ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
324run_tests $ns1 $ns2 10.0.1.1
325chk_join_nr "unused signal address" 0 0 0
326
327# accept and use add_addr
328reset
329ip netns exec $ns1 ./pm_nl_ctl limits 0 1
330ip netns exec $ns2 ./pm_nl_ctl limits 1 1
331ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
332run_tests $ns1 $ns2 10.0.1.1
333chk_join_nr "signal address" 1 1 1
334
335# accept and use add_addr with an additional subflow
336# note: signal address in server ns and local addresses in client ns must
337# belong to different subnets or one of the listed local address could be
338# used for 'add_addr' subflow
339reset
340ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
341ip netns exec $ns1 ./pm_nl_ctl limits 0 2
342ip netns exec $ns2 ./pm_nl_ctl limits 1 2
343ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
344run_tests $ns1 $ns2 10.0.1.1
345chk_join_nr "subflow and signal" 2 2 2
346
347# accept and use add_addr with additional subflows
348reset
349ip netns exec $ns1 ./pm_nl_ctl limits 0 3
350ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
351ip netns exec $ns2 ./pm_nl_ctl limits 1 3
352ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
353ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
354run_tests $ns1 $ns2 10.0.1.1
355chk_join_nr "multiple subflows and signal" 3 3 3
356
357exit $ret
358