1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ret=0
5sin=""
6sout=""
7cin=""
8cout=""
9ksft_skip=4
10timeout=30
11mptcp_connect=""
12capture=0
13
14TEST_COUNT=0
15
16init()
17{
18	capout=$(mktemp)
19
20	rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
21
22	ns1="ns1-$rndh"
23	ns2="ns2-$rndh"
24
25	for netns in "$ns1" "$ns2";do
26		ip netns add $netns || exit $ksft_skip
27		ip -net $netns link set lo up
28		ip netns exec $netns sysctl -q net.mptcp.enabled=1
29		ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0
30		ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0
31	done
32
33	#  ns1              ns2
34	# ns1eth1    ns2eth1
35	# ns1eth2    ns2eth2
36	# ns1eth3    ns2eth3
37	# ns1eth4    ns2eth4
38
39	for i in `seq 1 4`; do
40		ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2"
41		ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i
42		ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad
43		ip -net "$ns1" link set ns1eth$i up
44
45		ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i
46		ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad
47		ip -net "$ns2" link set ns2eth$i up
48
49		# let $ns2 reach any $ns1 address from any interface
50		ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
51	done
52}
53
54cleanup_partial()
55{
56	rm -f "$capout"
57
58	for netns in "$ns1" "$ns2"; do
59		ip netns del $netns
60	done
61}
62
63cleanup()
64{
65	rm -f "$cin" "$cout"
66	rm -f "$sin" "$sout"
67	cleanup_partial
68}
69
70reset()
71{
72	cleanup_partial
73	init
74}
75
76reset_with_cookies()
77{
78	reset
79
80	for netns in "$ns1" "$ns2";do
81		ip netns exec $netns sysctl -q net.ipv4.tcp_syncookies=2
82	done
83}
84
85for arg in "$@"; do
86	if [ "$arg" = "-c" ]; then
87		capture=1
88	fi
89done
90
91ip -Version > /dev/null 2>&1
92if [ $? -ne 0 ];then
93	echo "SKIP: Could not run test without ip tool"
94	exit $ksft_skip
95fi
96
97
98check_transfer()
99{
100	in=$1
101	out=$2
102	what=$3
103
104	cmp "$in" "$out" > /dev/null 2>&1
105	if [ $? -ne 0 ] ;then
106		echo "[ FAIL ] $what does not match (in, out):"
107		print_file_err "$in"
108		print_file_err "$out"
109
110		return 1
111	fi
112
113	return 0
114}
115
116do_ping()
117{
118	listener_ns="$1"
119	connector_ns="$2"
120	connect_addr="$3"
121
122	ip netns exec ${connector_ns} ping -q -c 1 $connect_addr >/dev/null
123	if [ $? -ne 0 ] ; then
124		echo "$listener_ns -> $connect_addr connectivity [ FAIL ]" 1>&2
125		ret=1
126	fi
127}
128
129do_transfer()
130{
131	listener_ns="$1"
132	connector_ns="$2"
133	cl_proto="$3"
134	srv_proto="$4"
135	connect_addr="$5"
136	rm_nr_ns1="$6"
137	rm_nr_ns2="$7"
138
139	port=$((10000+$TEST_COUNT))
140	TEST_COUNT=$((TEST_COUNT+1))
141
142	:> "$cout"
143	:> "$sout"
144	:> "$capout"
145
146	if [ $capture -eq 1 ]; then
147		if [ -z $SUDO_USER ] ; then
148			capuser=""
149		else
150			capuser="-Z $SUDO_USER"
151		fi
152
153		capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}")
154
155		echo "Capturing traffic for test $TEST_COUNT into $capfile"
156		ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 &
157		cappid=$!
158
159		sleep 1
160	fi
161
162	if [[ $rm_nr_ns1 -eq 0 && $rm_nr_ns2 -eq 0 ]]; then
163		mptcp_connect="./mptcp_connect -j"
164	else
165		mptcp_connect="./mptcp_connect -r"
166	fi
167
168	ip netns exec ${listener_ns} $mptcp_connect -t $timeout -l -p $port -s ${srv_proto} 0.0.0.0 < "$sin" > "$sout" &
169	spid=$!
170
171	sleep 1
172
173	ip netns exec ${connector_ns} $mptcp_connect -t $timeout -p $port -s ${cl_proto} $connect_addr < "$cin" > "$cout" &
174	cpid=$!
175
176	if [ $rm_nr_ns1 -gt 0 ]; then
177		counter=1
178		sleep 1
179
180		while [ $counter -le $rm_nr_ns1 ]
181		do
182			ip netns exec ${listener_ns} ./pm_nl_ctl del $counter
183			sleep 1
184			let counter+=1
185		done
186	fi
187
188	if [ $rm_nr_ns2 -gt 0 ]; then
189		counter=1
190		sleep 1
191
192		while [ $counter -le $rm_nr_ns2 ]
193		do
194			ip netns exec ${connector_ns} ./pm_nl_ctl del $counter
195			sleep 1
196			let counter+=1
197		done
198	fi
199
200	wait $cpid
201	retc=$?
202	wait $spid
203	rets=$?
204
205	if [ $capture -eq 1 ]; then
206	    sleep 1
207	    kill $cappid
208	fi
209
210	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
211		echo " client exit code $retc, server $rets" 1>&2
212		echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2
213		ip netns exec ${listener_ns} ss -nita 1>&2 -o "sport = :$port"
214		echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2
215		ip netns exec ${connector_ns} ss -nita 1>&2 -o "dport = :$port"
216
217		cat "$capout"
218		return 1
219	fi
220
221	check_transfer $sin $cout "file received by client"
222	retc=$?
223	check_transfer $cin $sout "file received by server"
224	rets=$?
225
226	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
227		cat "$capout"
228		return 0
229	fi
230
231	cat "$capout"
232	return 1
233}
234
235make_file()
236{
237	name=$1
238	who=$2
239
240	SIZE=1
241
242	dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
243	echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name"
244
245	echo "Created $name (size $SIZE KB) containing data sent by $who"
246}
247
248run_tests()
249{
250	listener_ns="$1"
251	connector_ns="$2"
252	connect_addr="$3"
253	lret=0
254
255	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} 0 0
256	lret=$?
257	if [ $lret -ne 0 ]; then
258		ret=$lret
259		return
260	fi
261}
262
263run_remove_tests()
264{
265	listener_ns="$1"
266	connector_ns="$2"
267	connect_addr="$3"
268	rm_nr_ns1="$4"
269	rm_nr_ns2="$5"
270	lret=0
271
272	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} ${rm_nr_ns1} ${rm_nr_ns2}
273	lret=$?
274	if [ $lret -ne 0 ]; then
275		ret=$lret
276		return
277	fi
278}
279
280chk_join_nr()
281{
282	local msg="$1"
283	local syn_nr=$2
284	local syn_ack_nr=$3
285	local ack_nr=$4
286	local count
287	local dump_stats
288
289	printf "%02u %-36s %s" "$TEST_COUNT" "$msg" "syn"
290	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}'`
291	[ -z "$count" ] && count=0
292	if [ "$count" != "$syn_nr" ]; then
293		echo "[fail] got $count JOIN[s] syn expected $syn_nr"
294		ret=1
295		dump_stats=1
296	else
297		echo -n "[ ok ]"
298	fi
299
300	echo -n " - synack"
301	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}'`
302	[ -z "$count" ] && count=0
303	if [ "$count" != "$syn_ack_nr" ]; then
304		echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr"
305		ret=1
306		dump_stats=1
307	else
308		echo -n "[ ok ]"
309	fi
310
311	echo -n " - ack"
312	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinAckRx | awk '{print $2}'`
313	[ -z "$count" ] && count=0
314	if [ "$count" != "$ack_nr" ]; then
315		echo "[fail] got $count JOIN[s] ack expected $ack_nr"
316		ret=1
317		dump_stats=1
318	else
319		echo "[ ok ]"
320	fi
321	if [ "${dump_stats}" = 1 ]; then
322		echo Server ns stats
323		ip netns exec $ns1 nstat -as | grep MPTcp
324		echo Client ns stats
325		ip netns exec $ns2 nstat -as | grep MPTcp
326	fi
327}
328
329chk_add_nr()
330{
331	local add_nr=$1
332	local echo_nr=$2
333	local count
334	local dump_stats
335
336	printf "%-39s %s" " " "add"
337	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtAddAddr | awk '{print $2}'`
338	[ -z "$count" ] && count=0
339	if [ "$count" != "$add_nr" ]; then
340		echo "[fail] got $count ADD_ADDR[s] expected $add_nr"
341		ret=1
342		dump_stats=1
343	else
344		echo -n "[ ok ]"
345	fi
346
347	echo -n " - echo  "
348	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtEchoAdd | awk '{print $2}'`
349	[ -z "$count" ] && count=0
350	if [ "$count" != "$echo_nr" ]; then
351		echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr"
352		ret=1
353		dump_stats=1
354	else
355		echo "[ ok ]"
356	fi
357
358	if [ "${dump_stats}" = 1 ]; then
359		echo Server ns stats
360		ip netns exec $ns1 nstat -as | grep MPTcp
361		echo Client ns stats
362		ip netns exec $ns2 nstat -as | grep MPTcp
363	fi
364}
365
366chk_rm_nr()
367{
368	local rm_addr_nr=$1
369	local rm_subflow_nr=$2
370	local count
371	local dump_stats
372
373	printf "%-39s %s" " " "rm "
374	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtRmAddr | awk '{print $2}'`
375	[ -z "$count" ] && count=0
376	if [ "$count" != "$rm_addr_nr" ]; then
377		echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr"
378		ret=1
379		dump_stats=1
380	else
381		echo -n "[ ok ]"
382	fi
383
384	echo -n " - sf    "
385	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtRmSubflow | awk '{print $2}'`
386	[ -z "$count" ] && count=0
387	if [ "$count" != "$rm_subflow_nr" ]; then
388		echo "[fail] got $count RM_SUBFLOW[s] expected $rm_subflow_nr"
389		ret=1
390		dump_stats=1
391	else
392		echo "[ ok ]"
393	fi
394
395	if [ "${dump_stats}" = 1 ]; then
396		echo Server ns stats
397		ip netns exec $ns1 nstat -as | grep MPTcp
398		echo Client ns stats
399		ip netns exec $ns2 nstat -as | grep MPTcp
400	fi
401}
402
403sin=$(mktemp)
404sout=$(mktemp)
405cin=$(mktemp)
406cout=$(mktemp)
407init
408make_file "$cin" "client"
409make_file "$sin" "server"
410trap cleanup EXIT
411
412run_tests $ns1 $ns2 10.0.1.1
413chk_join_nr "no JOIN" "0" "0" "0"
414
415# subflow limted by client
416reset
417ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
418run_tests $ns1 $ns2 10.0.1.1
419chk_join_nr "single subflow, limited by client" 0 0 0
420
421# subflow limted by server
422reset
423ip netns exec $ns2 ./pm_nl_ctl limits 0 1
424ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
425run_tests $ns1 $ns2 10.0.1.1
426chk_join_nr "single subflow, limited by server" 1 1 0
427
428# subflow
429reset
430ip netns exec $ns1 ./pm_nl_ctl limits 0 1
431ip netns exec $ns2 ./pm_nl_ctl limits 0 1
432ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
433run_tests $ns1 $ns2 10.0.1.1
434chk_join_nr "single subflow" 1 1 1
435
436# multiple subflows
437reset
438ip netns exec $ns1 ./pm_nl_ctl limits 0 2
439ip netns exec $ns2 ./pm_nl_ctl limits 0 2
440ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
441ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
442run_tests $ns1 $ns2 10.0.1.1
443chk_join_nr "multiple subflows" 2 2 2
444
445# multiple subflows limited by serverf
446reset
447ip netns exec $ns1 ./pm_nl_ctl limits 0 1
448ip netns exec $ns2 ./pm_nl_ctl limits 0 2
449ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
450ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
451run_tests $ns1 $ns2 10.0.1.1
452chk_join_nr "multiple subflows, limited by server" 2 2 1
453
454# add_address, unused
455reset
456ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
457run_tests $ns1 $ns2 10.0.1.1
458chk_join_nr "unused signal address" 0 0 0
459chk_add_nr 1 1
460
461# accept and use add_addr
462reset
463ip netns exec $ns1 ./pm_nl_ctl limits 0 1
464ip netns exec $ns2 ./pm_nl_ctl limits 1 1
465ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
466run_tests $ns1 $ns2 10.0.1.1
467chk_join_nr "signal address" 1 1 1
468chk_add_nr 1 1
469
470# accept and use add_addr with an additional subflow
471# note: signal address in server ns and local addresses in client ns must
472# belong to different subnets or one of the listed local address could be
473# used for 'add_addr' subflow
474reset
475ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
476ip netns exec $ns1 ./pm_nl_ctl limits 0 2
477ip netns exec $ns2 ./pm_nl_ctl limits 1 2
478ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
479run_tests $ns1 $ns2 10.0.1.1
480chk_join_nr "subflow and signal" 2 2 2
481chk_add_nr 1 1
482
483# accept and use add_addr with additional subflows
484reset
485ip netns exec $ns1 ./pm_nl_ctl limits 0 3
486ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
487ip netns exec $ns2 ./pm_nl_ctl limits 1 3
488ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
489ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
490run_tests $ns1 $ns2 10.0.1.1
491chk_join_nr "multiple subflows and signal" 3 3 3
492chk_add_nr 1 1
493
494# single subflow, remove
495reset
496ip netns exec $ns1 ./pm_nl_ctl limits 0 1
497ip netns exec $ns2 ./pm_nl_ctl limits 0 1
498ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
499run_remove_tests $ns1 $ns2 10.0.1.1 0 1
500chk_join_nr "remove single subflow" 1 1 1
501chk_rm_nr 1 1
502
503# multiple subflows, remove
504reset
505ip netns exec $ns1 ./pm_nl_ctl limits 0 2
506ip netns exec $ns2 ./pm_nl_ctl limits 0 2
507ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
508ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
509run_remove_tests $ns1 $ns2 10.0.1.1 0 2
510chk_join_nr "remove multiple subflows" 2 2 2
511chk_rm_nr 2 2
512
513# single address, remove
514reset
515ip netns exec $ns1 ./pm_nl_ctl limits 0 1
516ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
517ip netns exec $ns2 ./pm_nl_ctl limits 1 1
518run_remove_tests $ns1 $ns2 10.0.1.1 1 0
519chk_join_nr "remove single address" 1 1 1
520chk_add_nr 1 1
521chk_rm_nr 0 0
522
523# subflow and signal, remove
524reset
525ip netns exec $ns1 ./pm_nl_ctl limits 0 2
526ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
527ip netns exec $ns2 ./pm_nl_ctl limits 1 2
528ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
529run_remove_tests $ns1 $ns2 10.0.1.1 1 1
530chk_join_nr "remove subflow and signal" 2 2 2
531chk_add_nr 1 1
532chk_rm_nr 1 1
533
534# subflows and signal, remove
535reset
536ip netns exec $ns1 ./pm_nl_ctl limits 0 3
537ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
538ip netns exec $ns2 ./pm_nl_ctl limits 1 3
539ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
540ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
541run_remove_tests $ns1 $ns2 10.0.1.1 1 2
542chk_join_nr "remove subflows and signal" 3 3 3
543chk_add_nr 1 1
544chk_rm_nr 2 2
545
546# single subflow, syncookies
547reset_with_cookies
548ip netns exec $ns1 ./pm_nl_ctl limits 0 1
549ip netns exec $ns2 ./pm_nl_ctl limits 0 1
550ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
551run_tests $ns1 $ns2 10.0.1.1
552chk_join_nr "single subflow with syn cookies" 1 1 1
553
554# multiple subflows with syn cookies
555reset_with_cookies
556ip netns exec $ns1 ./pm_nl_ctl limits 0 2
557ip netns exec $ns2 ./pm_nl_ctl limits 0 2
558ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
559ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
560run_tests $ns1 $ns2 10.0.1.1
561chk_join_nr "multiple subflows with syn cookies" 2 2 2
562
563# multiple subflows limited by server
564reset_with_cookies
565ip netns exec $ns1 ./pm_nl_ctl limits 0 1
566ip netns exec $ns2 ./pm_nl_ctl limits 0 2
567ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
568ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
569run_tests $ns1 $ns2 10.0.1.1
570chk_join_nr "subflows limited by server w cookies" 2 2 1
571
572# test signal address with cookies
573reset_with_cookies
574ip netns exec $ns1 ./pm_nl_ctl limits 0 1
575ip netns exec $ns2 ./pm_nl_ctl limits 1 1
576ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
577run_tests $ns1 $ns2 10.0.1.1
578chk_join_nr "signal address with syn cookies" 1 1 1
579chk_add_nr 1 1
580
581# test cookie with subflow and signal
582reset_with_cookies
583ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
584ip netns exec $ns1 ./pm_nl_ctl limits 0 2
585ip netns exec $ns2 ./pm_nl_ctl limits 1 2
586ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
587run_tests $ns1 $ns2 10.0.1.1
588chk_join_nr "subflow and signal w cookies" 2 2 2
589chk_add_nr 1 1
590
591# accept and use add_addr with additional subflows
592reset_with_cookies
593ip netns exec $ns1 ./pm_nl_ctl limits 0 3
594ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
595ip netns exec $ns2 ./pm_nl_ctl limits 1 3
596ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
597ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
598run_tests $ns1 $ns2 10.0.1.1
599chk_join_nr "subflows and signal w. cookies" 3 3 3
600chk_add_nr 1 1
601
602exit $ret
603