xref: /linux/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh (revision 55d0969c451159cff86949b38c39171cab962069)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Double quotes to prevent globbing and word splitting is recommended in new
5# code but we accept it, especially because there were too many before having
6# address all other issues detected by shellcheck.
7#shellcheck disable=SC2086
8
9. "$(dirname "${0}")/mptcp_lib.sh"
10
11ret=0
12sin=""
13sout=""
14cin=""
15cout=""
16timeout_poll=30
17timeout_test=$((timeout_poll * 2 + 1))
18iptables="iptables"
19ip6tables="ip6tables"
20
21ns1=""
22ns2=""
23ns_sbox=""
24
25usage() {
26	echo "Usage: $0 [ -i ] [ -h ]"
27	echo -e "\t-i: use 'ip mptcp' instead of 'pm_nl_ctl'"
28	echo -e "\t-h: help"
29}
30
31while getopts "hi" option;do
32	case "$option" in
33	"h")
34		usage "$0"
35		exit ${KSFT_PASS}
36		;;
37	"i")
38		mptcp_lib_set_ip_mptcp
39		;;
40	"?")
41		usage "$0"
42		exit ${KSFT_FAIL}
43		;;
44	esac
45done
46
47add_mark_rules()
48{
49	local ns=$1
50	local m=$2
51
52	local t
53	for t in ${iptables} ${ip6tables}; do
54		# just to debug: check we have multiple subflows connection requests
55		ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT
56
57		# RST packets might be handled by a internal dummy socket
58		ip netns exec $ns $t -A OUTPUT -p tcp --tcp-flags RST RST -m mark --mark 0 -j ACCEPT
59
60		ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark $m -j ACCEPT
61		ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark 0 -j DROP
62	done
63}
64
65init()
66{
67	mptcp_lib_ns_init ns1 ns2 ns_sbox
68
69	local i
70	for i in $(seq 1 4); do
71		ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2"
72		ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i
73		ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad
74		ip -net "$ns1" link set ns1eth$i up
75
76		ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i
77		ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad
78		ip -net "$ns2" link set ns2eth$i up
79
80		# let $ns2 reach any $ns1 address from any interface
81		ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
82
83		mptcp_lib_pm_nl_add_endpoint "${ns1}" "10.0.${i}.1" flags signal
84		mptcp_lib_pm_nl_add_endpoint "${ns1}" "dead:beef:${i}::1" flags signal
85
86		mptcp_lib_pm_nl_add_endpoint "${ns2}" "10.0.${i}.2" flags signal
87		mptcp_lib_pm_nl_add_endpoint "${ns2}" "dead:beef:${i}::2" flags signal
88	done
89
90	mptcp_lib_pm_nl_set_limits "${ns1}" 8 8
91	mptcp_lib_pm_nl_set_limits "${ns2}" 8 8
92
93	add_mark_rules $ns1 1
94	add_mark_rules $ns2 2
95}
96
97# This function is used in the cleanup trap
98#shellcheck disable=SC2317
99cleanup()
100{
101	mptcp_lib_ns_exit "${ns1}" "${ns2}" "${ns_sbox}"
102	rm -f "$cin" "$cout"
103	rm -f "$sin" "$sout"
104}
105
106mptcp_lib_check_mptcp
107mptcp_lib_check_kallsyms
108mptcp_lib_check_tools ip "${iptables}" "${ip6tables}"
109
110check_mark()
111{
112	local ns=$1
113	local af=$2
114
115	local tables=${iptables}
116
117	if [ $af -eq 6 ];then
118		tables=${ip6tables}
119	fi
120
121	local counters values
122	counters=$(ip netns exec $ns $tables -v -L OUTPUT | grep DROP)
123	values=${counters%DROP*}
124
125	local v
126	for v in $values; do
127		if [ $v -ne 0 ]; then
128			mptcp_lib_pr_fail "got $tables $values in ns $ns," \
129					  "not 0 - not all expected packets marked"
130			ret=${KSFT_FAIL}
131			return 1
132		fi
133	done
134
135	return 0
136}
137
138print_title()
139{
140	mptcp_lib_print_title "${@}"
141}
142
143do_transfer()
144{
145	local listener_ns="$1"
146	local connector_ns="$2"
147	local cl_proto="$3"
148	local srv_proto="$4"
149	local connect_addr="$5"
150
151	local port=12001
152
153	:> "$cout"
154	:> "$sout"
155
156	local mptcp_connect="./mptcp_connect -r 20"
157
158	local local_addr ip
159	if mptcp_lib_is_v6 "${connect_addr}"; then
160		local_addr="::"
161		ip=ipv6
162	else
163		local_addr="0.0.0.0"
164		ip=ipv4
165	fi
166
167	cmsg="TIMESTAMPNS"
168	if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
169		cmsg+=",TCPINQ"
170	fi
171
172	timeout ${timeout_test} \
173		ip netns exec ${listener_ns} \
174			$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
175				${local_addr} < "$sin" > "$sout" &
176	local spid=$!
177
178	sleep 1
179
180	timeout ${timeout_test} \
181		ip netns exec ${connector_ns} \
182			$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
183				$connect_addr < "$cin" > "$cout" &
184
185	local cpid=$!
186
187	wait $cpid
188	local retc=$?
189	wait $spid
190	local rets=$?
191
192	print_title "Transfer ${ip:2}"
193	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
194		mptcp_lib_pr_fail "client exit code $retc, server $rets"
195		echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2
196		ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port"
197
198		echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2
199		ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port"
200
201		mptcp_lib_result_fail "transfer ${ip}"
202
203		ret=${KSFT_FAIL}
204		return 1
205	fi
206	if ! mptcp_lib_check_transfer $cin $sout "file received by server"; then
207		rets=1
208	else
209		mptcp_lib_pr_ok
210	fi
211	mptcp_lib_result_code "${rets}" "transfer ${ip}"
212
213	print_title "Mark ${ip:2}"
214	if [ $local_addr = "::" ];then
215		check_mark $listener_ns 6 || retc=1
216		check_mark $connector_ns 6 || retc=1
217	else
218		check_mark $listener_ns 4 || retc=1
219		check_mark $connector_ns 4 || retc=1
220	fi
221
222	mptcp_lib_result_code "${retc}" "mark ${ip}"
223
224	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
225		mptcp_lib_pr_ok
226		return 0
227	fi
228	mptcp_lib_pr_fail
229
230	return 1
231}
232
233make_file()
234{
235	local name=$1
236	local who=$2
237	local size=$3
238
239	mptcp_lib_make_file $name 1024 $size
240
241	echo "Created $name (size $size KB) containing data sent by $who"
242}
243
244do_mptcp_sockopt_tests()
245{
246	local lret=0
247
248	if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
249		mptcp_lib_pr_skip "MPTCP sockopt not supported"
250		mptcp_lib_result_skip "sockopt"
251		return
252	fi
253
254	ip netns exec "$ns_sbox" ./mptcp_sockopt
255	lret=$?
256
257	print_title "SOL_MPTCP sockopt v4"
258	if [ $lret -ne 0 ]; then
259		mptcp_lib_pr_fail
260		mptcp_lib_result_fail "sockopt v4"
261		ret=$lret
262		return
263	fi
264	mptcp_lib_pr_ok
265	mptcp_lib_result_pass "sockopt v4"
266
267	ip netns exec "$ns_sbox" ./mptcp_sockopt -6
268	lret=$?
269
270	print_title "SOL_MPTCP sockopt v6"
271	if [ $lret -ne 0 ]; then
272		mptcp_lib_pr_fail
273		mptcp_lib_result_fail "sockopt v6"
274		ret=$lret
275		return
276	fi
277	mptcp_lib_pr_ok
278	mptcp_lib_result_pass "sockopt v6"
279}
280
281run_tests()
282{
283	local listener_ns="$1"
284	local connector_ns="$2"
285	local connect_addr="$3"
286	local lret=0
287
288	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr}
289
290	lret=$?
291
292	if [ $lret -ne 0 ]; then
293		ret=$lret
294		return
295	fi
296}
297
298do_tcpinq_test()
299{
300	print_title "TCP_INQ cmsg/ioctl $*"
301	ip netns exec "$ns_sbox" ./mptcp_inq "$@"
302	local lret=$?
303	if [ $lret -ne 0 ];then
304		ret=$lret
305		mptcp_lib_pr_fail
306		mptcp_lib_result_fail "TCP_INQ: $*"
307		return $lret
308	fi
309
310	mptcp_lib_pr_ok
311	mptcp_lib_result_pass "TCP_INQ: $*"
312	return $lret
313}
314
315do_tcpinq_tests()
316{
317	local lret=0
318
319	if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
320		mptcp_lib_pr_skip "TCP_INQ not supported"
321		mptcp_lib_result_skip "TCP_INQ"
322		return
323	fi
324
325	local args
326	for args in "-t tcp" "-r tcp"; do
327		do_tcpinq_test $args
328		lret=$?
329		if [ $lret -ne 0 ] ; then
330			return $lret
331		fi
332		do_tcpinq_test -6 $args
333		lret=$?
334		if [ $lret -ne 0 ] ; then
335			return $lret
336		fi
337	done
338
339	do_tcpinq_test -r tcp -t tcp
340
341	return $?
342}
343
344sin=$(mktemp)
345sout=$(mktemp)
346cin=$(mktemp)
347cout=$(mktemp)
348init
349make_file "$cin" "client" 1
350make_file "$sin" "server" 1
351trap cleanup EXIT
352mptcp_lib_subtests_last_ts_reset
353
354run_tests $ns1 $ns2 10.0.1.1
355run_tests $ns1 $ns2 dead:beef:1::1
356
357do_mptcp_sockopt_tests
358do_tcpinq_tests
359
360mptcp_lib_result_print_all_tap
361exit $ret
362