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