1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4sec=$(date +%s)
5rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
6ns="ns1-$rndh"
7ksft_skip=4
8test_cnt=1
9timeout_poll=100
10timeout_test=$((timeout_poll * 2 + 1))
11ret=0
12
13flush_pids()
14{
15	# mptcp_connect in join mode will sleep a bit before completing,
16	# give it some time
17	sleep 1.1
18
19	ip netns pids "${ns}" | xargs --no-run-if-empty kill -SIGUSR1 &>/dev/null
20}
21
22cleanup()
23{
24	ip netns pids "${ns}" | xargs --no-run-if-empty kill -SIGKILL &>/dev/null
25
26	ip netns del $ns
27}
28
29ip -Version > /dev/null 2>&1
30if [ $? -ne 0 ];then
31	echo "SKIP: Could not run test without ip tool"
32	exit $ksft_skip
33fi
34ss -h | grep -q MPTCP
35if [ $? -ne 0 ];then
36	echo "SKIP: ss tool does not support MPTCP"
37	exit $ksft_skip
38fi
39
40__chk_nr()
41{
42	local condition="$1"
43	local expected=$2
44	local msg nr
45
46	shift 2
47	msg=$*
48	nr=$(ss -inmHMN $ns | $condition)
49
50	printf "%-50s" "$msg"
51	if [ $nr != $expected ]; then
52		echo "[ fail ] expected $expected found $nr"
53		ret=$test_cnt
54	else
55		echo "[  ok  ]"
56	fi
57	test_cnt=$((test_cnt+1))
58}
59
60chk_msk_nr()
61{
62	__chk_nr "grep -c token:" $*
63}
64
65wait_msk_nr()
66{
67	local condition="grep -c token:"
68	local expected=$1
69	local timeout=20
70	local msg nr
71	local max=0
72	local i=0
73
74	shift 1
75	msg=$*
76
77	while [ $i -lt $timeout ]; do
78		nr=$(ss -inmHMN $ns | $condition)
79		[ $nr == $expected ] && break;
80		[ $nr -gt $max ] && max=$nr
81		i=$((i + 1))
82		sleep 1
83	done
84
85	printf "%-50s" "$msg"
86	if [ $i -ge $timeout ]; then
87		echo "[ fail ] timeout while expecting $expected max $max last $nr"
88		ret=$test_cnt
89	elif [ $nr != $expected ]; then
90		echo "[ fail ] expected $expected found $nr"
91		ret=$test_cnt
92	else
93		echo "[  ok  ]"
94	fi
95	test_cnt=$((test_cnt+1))
96}
97
98chk_msk_fallback_nr()
99{
100		__chk_nr "grep -c fallback" $*
101}
102
103chk_msk_remote_key_nr()
104{
105		__chk_nr "grep -c remote_key" $*
106}
107
108__chk_listen()
109{
110	local filter="$1"
111	local expected=$2
112
113	shift 2
114	msg=$*
115
116	nr=$(ss -N $ns -Ml "$filter" | grep -c LISTEN)
117	printf "%-50s" "$msg"
118
119	if [ $nr != $expected ]; then
120		echo "[ fail ] expected $expected found $nr"
121		ret=$test_cnt
122	else
123		echo "[  ok  ]"
124	fi
125}
126
127chk_msk_listen()
128{
129	lport=$1
130	local msg="check for listen socket"
131
132	# destination port search should always return empty list
133	__chk_listen "dport $lport" 0 "listen match for dport $lport"
134
135	# should return 'our' mptcp listen socket
136	__chk_listen "sport $lport" 1 "listen match for sport $lport"
137
138	__chk_listen "src inet:0.0.0.0:$lport" 1 "listen match for saddr and sport"
139
140	__chk_listen "" 1 "all listen sockets"
141
142	nr=$(ss -Ml $filter | wc -l)
143}
144
145# $1: ns, $2: port
146wait_local_port_listen()
147{
148	local listener_ns="${1}"
149	local port="${2}"
150
151	local port_hex i
152
153	port_hex="$(printf "%04X" "${port}")"
154	for i in $(seq 10); do
155		ip netns exec "${listener_ns}" cat /proc/net/tcp | \
156			awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" &&
157			break
158		sleep 0.1
159	done
160}
161
162wait_connected()
163{
164	local listener_ns="${1}"
165	local port="${2}"
166
167	local port_hex i
168
169	port_hex="$(printf "%04X" "${port}")"
170	for i in $(seq 10); do
171		ip netns exec ${listener_ns} grep -q " 0100007F:${port_hex} " /proc/net/tcp && break
172		sleep 0.1
173	done
174}
175
176trap cleanup EXIT
177ip netns add $ns
178ip -n $ns link set dev lo up
179
180echo "a" | \
181	timeout ${timeout_test} \
182		ip netns exec $ns \
183			./mptcp_connect -p 10000 -l -t ${timeout_poll} -w 20 \
184				0.0.0.0 >/dev/null &
185wait_local_port_listen $ns 10000
186chk_msk_nr 0 "no msk on netns creation"
187chk_msk_listen 10000
188
189echo "b" | \
190	timeout ${timeout_test} \
191		ip netns exec $ns \
192			./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} -w 20 \
193				127.0.0.1 >/dev/null &
194wait_connected $ns 10000
195chk_msk_nr 2 "after MPC handshake "
196chk_msk_remote_key_nr 2 "....chk remote_key"
197chk_msk_fallback_nr 0 "....chk no fallback"
198flush_pids
199
200
201echo "a" | \
202	timeout ${timeout_test} \
203		ip netns exec $ns \
204			./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} -w 20 \
205				0.0.0.0 >/dev/null &
206wait_local_port_listen $ns 10001
207echo "b" | \
208	timeout ${timeout_test} \
209		ip netns exec $ns \
210			./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} -w 20 \
211				127.0.0.1 >/dev/null &
212wait_connected $ns 10001
213chk_msk_fallback_nr 1 "check fallback"
214flush_pids
215
216NR_CLIENTS=100
217for I in `seq 1 $NR_CLIENTS`; do
218	echo "a" | \
219		timeout ${timeout_test} \
220			ip netns exec $ns \
221				./mptcp_connect -p $((I+10001)) -l -w 20 \
222					-t ${timeout_poll} 0.0.0.0 >/dev/null &
223done
224wait_local_port_listen $ns $((NR_CLIENTS + 10001))
225
226for I in `seq 1 $NR_CLIENTS`; do
227	echo "b" | \
228		timeout ${timeout_test} \
229			ip netns exec $ns \
230				./mptcp_connect -p $((I+10001)) -w 20 \
231					-t ${timeout_poll} 127.0.0.1 >/dev/null &
232done
233
234wait_msk_nr $((NR_CLIENTS*2)) "many msk socket present"
235flush_pids
236
237exit $ret
238