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
75reset_with_cookies()
76{
77	reset
78
79	for netns in "$ns1" "$ns2";do
80		ip netns exec $netns sysctl -q net.ipv4.tcp_syncookies=2
81	done
82}
83
84for arg in "$@"; do
85	if [ "$arg" = "-c" ]; then
86		capture=1
87	fi
88done
89
90ip -Version > /dev/null 2>&1
91if [ $? -ne 0 ];then
92	echo "SKIP: Could not run test without ip tool"
93	exit $ksft_skip
94fi
95
96
97check_transfer()
98{
99	in=$1
100	out=$2
101	what=$3
102
103	cmp "$in" "$out" > /dev/null 2>&1
104	if [ $? -ne 0 ] ;then
105		echo "[ FAIL ] $what does not match (in, out):"
106		print_file_err "$in"
107		print_file_err "$out"
108
109		return 1
110	fi
111
112	return 0
113}
114
115do_ping()
116{
117	listener_ns="$1"
118	connector_ns="$2"
119	connect_addr="$3"
120
121	ip netns exec ${connector_ns} ping -q -c 1 $connect_addr >/dev/null
122	if [ $? -ne 0 ] ; then
123		echo "$listener_ns -> $connect_addr connectivity [ FAIL ]" 1>&2
124		ret=1
125	fi
126}
127
128do_transfer()
129{
130	listener_ns="$1"
131	connector_ns="$2"
132	cl_proto="$3"
133	srv_proto="$4"
134	connect_addr="$5"
135
136	port=$((10000+$TEST_COUNT))
137	TEST_COUNT=$((TEST_COUNT+1))
138
139	:> "$cout"
140	:> "$sout"
141	:> "$capout"
142
143	if [ $capture -eq 1 ]; then
144		if [ -z $SUDO_USER ] ; then
145			capuser=""
146		else
147			capuser="-Z $SUDO_USER"
148		fi
149
150		capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}")
151
152		echo "Capturing traffic for test $TEST_COUNT into $capfile"
153		ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 &
154		cappid=$!
155
156		sleep 1
157	fi
158
159	ip netns exec ${listener_ns} ./mptcp_connect -j -t $timeout -l -p $port -s ${srv_proto} 0.0.0.0 < "$sin" > "$sout" &
160	spid=$!
161
162	sleep 1
163
164	ip netns exec ${connector_ns} ./mptcp_connect -j -t $timeout -p $port -s ${cl_proto} $connect_addr < "$cin" > "$cout" &
165	cpid=$!
166
167	wait $cpid
168	retc=$?
169	wait $spid
170	rets=$?
171
172	if [ $capture -eq 1 ]; then
173	    sleep 1
174	    kill $cappid
175	fi
176
177	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
178		echo " client exit code $retc, server $rets" 1>&2
179		echo "\nnetns ${listener_ns} socket stat for $port:" 1>&2
180		ip netns exec ${listener_ns} ss -nita 1>&2 -o "sport = :$port"
181		echo "\nnetns ${connector_ns} socket stat for $port:" 1>&2
182		ip netns exec ${connector_ns} ss -nita 1>&2 -o "dport = :$port"
183
184		cat "$capout"
185		return 1
186	fi
187
188	check_transfer $sin $cout "file received by client"
189	retc=$?
190	check_transfer $cin $sout "file received by server"
191	rets=$?
192
193	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
194		cat "$capout"
195		return 0
196	fi
197
198	cat "$capout"
199	return 1
200}
201
202make_file()
203{
204	name=$1
205	who=$2
206
207	SIZE=1
208
209	dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
210	echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name"
211
212	echo "Created $name (size $SIZE KB) containing data sent by $who"
213}
214
215run_tests()
216{
217	listener_ns="$1"
218	connector_ns="$2"
219	connect_addr="$3"
220	lret=0
221
222	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr}
223	lret=$?
224	if [ $lret -ne 0 ]; then
225		ret=$lret
226		return
227	fi
228}
229
230chk_join_nr()
231{
232	local msg="$1"
233	local syn_nr=$2
234	local syn_ack_nr=$3
235	local ack_nr=$4
236	local count
237	local dump_stats
238
239	printf "%02u %-36s %s" "$TEST_COUNT" "$msg" "syn"
240	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}'`
241	[ -z "$count" ] && count=0
242	if [ "$count" != "$syn_nr" ]; then
243		echo "[fail] got $count JOIN[s] syn expected $syn_nr"
244		ret=1
245		dump_stats=1
246	else
247		echo -n "[ ok ]"
248	fi
249
250	echo -n " - synack"
251	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}'`
252	[ -z "$count" ] && count=0
253	if [ "$count" != "$syn_ack_nr" ]; then
254		echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr"
255		ret=1
256		dump_stats=1
257	else
258		echo -n "[ ok ]"
259	fi
260
261	echo -n " - ack"
262	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinAckRx | awk '{print $2}'`
263	[ -z "$count" ] && count=0
264	if [ "$count" != "$ack_nr" ]; then
265		echo "[fail] got $count JOIN[s] ack expected $ack_nr"
266		ret=1
267		dump_stats=1
268	else
269		echo "[ ok ]"
270	fi
271	if [ "${dump_stats}" = 1 ]; then
272		echo Server ns stats
273		ip netns exec $ns1 nstat -as | grep MPTcp
274		echo Client ns stats
275		ip netns exec $ns2 nstat -as | grep MPTcp
276	fi
277}
278
279sin=$(mktemp)
280sout=$(mktemp)
281cin=$(mktemp)
282cout=$(mktemp)
283init
284make_file "$cin" "client"
285make_file "$sin" "server"
286trap cleanup EXIT
287
288run_tests $ns1 $ns2 10.0.1.1
289chk_join_nr "no JOIN" "0" "0" "0"
290
291# subflow limted by client
292reset
293ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
294run_tests $ns1 $ns2 10.0.1.1
295chk_join_nr "single subflow, limited by client" 0 0 0
296
297# subflow limted by server
298reset
299ip netns exec $ns2 ./pm_nl_ctl limits 0 1
300ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
301run_tests $ns1 $ns2 10.0.1.1
302chk_join_nr "single subflow, limited by server" 1 1 0
303
304# subflow
305reset
306ip netns exec $ns1 ./pm_nl_ctl limits 0 1
307ip netns exec $ns2 ./pm_nl_ctl limits 0 1
308ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
309run_tests $ns1 $ns2 10.0.1.1
310chk_join_nr "single subflow" 1 1 1
311
312# multiple subflows
313reset
314ip netns exec $ns1 ./pm_nl_ctl limits 0 2
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" 2 2 2
320
321# multiple subflows limited by serverf
322reset
323ip netns exec $ns1 ./pm_nl_ctl limits 0 1
324ip netns exec $ns2 ./pm_nl_ctl limits 0 2
325ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
326ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
327run_tests $ns1 $ns2 10.0.1.1
328chk_join_nr "multiple subflows, limited by server" 2 2 1
329
330# add_address, unused
331reset
332ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
333run_tests $ns1 $ns2 10.0.1.1
334chk_join_nr "unused signal address" 0 0 0
335
336# accept and use add_addr
337reset
338ip netns exec $ns1 ./pm_nl_ctl limits 0 1
339ip netns exec $ns2 ./pm_nl_ctl limits 1 1
340ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
341run_tests $ns1 $ns2 10.0.1.1
342chk_join_nr "signal address" 1 1 1
343
344# accept and use add_addr with an additional subflow
345# note: signal address in server ns and local addresses in client ns must
346# belong to different subnets or one of the listed local address could be
347# used for 'add_addr' subflow
348reset
349ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
350ip netns exec $ns1 ./pm_nl_ctl limits 0 2
351ip netns exec $ns2 ./pm_nl_ctl limits 1 2
352ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
353run_tests $ns1 $ns2 10.0.1.1
354chk_join_nr "subflow and signal" 2 2 2
355
356# accept and use add_addr with additional subflows
357reset
358ip netns exec $ns1 ./pm_nl_ctl limits 0 3
359ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
360ip netns exec $ns2 ./pm_nl_ctl limits 1 3
361ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
362ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
363run_tests $ns1 $ns2 10.0.1.1
364chk_join_nr "multiple subflows and signal" 3 3 3
365
366# single subflow, syncookies
367reset_with_cookies
368ip netns exec $ns1 ./pm_nl_ctl limits 0 1
369ip netns exec $ns2 ./pm_nl_ctl limits 0 1
370ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
371run_tests $ns1 $ns2 10.0.1.1
372chk_join_nr "single subflow with syn cookies" 1 1 1
373
374# multiple subflows with syn cookies
375reset_with_cookies
376ip netns exec $ns1 ./pm_nl_ctl limits 0 2
377ip netns exec $ns2 ./pm_nl_ctl limits 0 2
378ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
379ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
380run_tests $ns1 $ns2 10.0.1.1
381chk_join_nr "multiple subflows with syn cookies" 2 2 2
382
383# multiple subflows limited by server
384reset_with_cookies
385ip netns exec $ns1 ./pm_nl_ctl limits 0 1
386ip netns exec $ns2 ./pm_nl_ctl limits 0 2
387ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
388ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
389run_tests $ns1 $ns2 10.0.1.1
390chk_join_nr "subflows limited by server w cookies" 2 2 1
391
392# test signal address with cookies
393reset_with_cookies
394ip netns exec $ns1 ./pm_nl_ctl limits 0 1
395ip netns exec $ns2 ./pm_nl_ctl limits 1 1
396ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
397run_tests $ns1 $ns2 10.0.1.1
398chk_join_nr "signal address with syn cookies" 1 1 1
399
400# test cookie with subflow and signal
401reset_with_cookies
402ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
403ip netns exec $ns1 ./pm_nl_ctl limits 0 2
404ip netns exec $ns2 ./pm_nl_ctl limits 1 2
405ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
406run_tests $ns1 $ns2 10.0.1.1
407chk_join_nr "subflow and signal w cookies" 2 2 2
408
409# accept and use add_addr with additional subflows
410reset_with_cookies
411ip netns exec $ns1 ./pm_nl_ctl limits 0 3
412ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
413ip netns exec $ns2 ./pm_nl_ctl limits 1 3
414ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
415ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
416run_tests $ns1 $ns2 10.0.1.1
417chk_join_nr "subflows and signal w. cookies" 3 3 3
418
419exit $ret
420