xref: /linux/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh (revision 6aac2aa2dfae38b60f22c3dfe4103ceefbe2d761)
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,SC2329
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	mptcp_lib_nstat_init "${listener_ns}"
173	mptcp_lib_nstat_init "${connector_ns}"
174
175	ip netns exec ${listener_ns} \
176		$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
177			${local_addr} < "$sin" > "$sout" &
178	local spid=$!
179
180	mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}"
181
182	ip netns exec ${connector_ns} \
183		$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
184			$connect_addr < "$cin" > "$cout" &
185
186	local cpid=$!
187
188	mptcp_lib_wait_timeout "${timeout_test}" "${listener_ns}" \
189		"${connector_ns}" "${port}" "${cpid}" "${spid}" &
190	local timeout_pid=$!
191
192	wait $cpid
193	local retc=$?
194	wait $spid
195	local rets=$?
196
197	if kill -0 $timeout_pid; then
198		# Finished before the timeout: kill the background job
199		mptcp_lib_kill_group_wait $timeout_pid
200		timeout_pid=0
201	fi
202
203	mptcp_lib_nstat_get "${listener_ns}"
204	mptcp_lib_nstat_get "${connector_ns}"
205
206	print_title "Transfer ${ip:2}"
207	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ] || [ ${timeout_pid} -ne 0 ]; then
208		mptcp_lib_pr_fail "client exit code $retc, server $rets"
209		mptcp_lib_pr_err_stats "${listener_ns}" "${connector_ns}" "${port}"
210
211		mptcp_lib_result_fail "transfer ${ip}"
212
213		ret=${KSFT_FAIL}
214		return 1
215	fi
216	if ! mptcp_lib_check_transfer $cin $sout "file received by server"; then
217		rets=1
218	else
219		mptcp_lib_pr_ok
220	fi
221	mptcp_lib_result_code "${rets}" "transfer ${ip}"
222
223	print_title "Mark ${ip:2}"
224	if [ $local_addr = "::" ];then
225		check_mark $listener_ns 6 || retc=1
226		check_mark $connector_ns 6 || retc=1
227	else
228		check_mark $listener_ns 4 || retc=1
229		check_mark $connector_ns 4 || retc=1
230	fi
231
232	mptcp_lib_result_code "${retc}" "mark ${ip}"
233
234	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
235		mptcp_lib_pr_ok
236		return 0
237	fi
238	mptcp_lib_pr_fail
239
240	return 1
241}
242
243make_file()
244{
245	local name=$1
246	local who=$2
247	local size=$3
248
249	mptcp_lib_make_file $name 1024 $size
250
251	echo "Created $name (size $size KB) containing data sent by $who"
252}
253
254do_mptcp_sockopt_tests()
255{
256	local lret=0
257
258	if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
259		mptcp_lib_pr_skip "MPTCP sockopt not supported"
260		mptcp_lib_result_skip "sockopt"
261		return
262	fi
263
264	ip netns exec "$ns_sbox" ./mptcp_sockopt
265	lret=$?
266
267	print_title "SOL_MPTCP sockopt v4"
268	if [ $lret -ne 0 ]; then
269		mptcp_lib_pr_fail
270		mptcp_lib_result_fail "sockopt v4"
271		ret=$lret
272		return
273	fi
274	mptcp_lib_pr_ok
275	mptcp_lib_result_pass "sockopt v4"
276
277	ip netns exec "$ns_sbox" ./mptcp_sockopt -6
278	lret=$?
279
280	print_title "SOL_MPTCP sockopt v6"
281	if [ $lret -ne 0 ]; then
282		mptcp_lib_pr_fail
283		mptcp_lib_result_fail "sockopt v6"
284		ret=$lret
285		return
286	fi
287	mptcp_lib_pr_ok
288	mptcp_lib_result_pass "sockopt v6"
289}
290
291run_tests()
292{
293	local listener_ns="$1"
294	local connector_ns="$2"
295	local connect_addr="$3"
296	local lret=0
297
298	do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr}
299
300	lret=$?
301
302	if [ $lret -ne 0 ]; then
303		ret=$lret
304		return
305	fi
306}
307
308do_tcpinq_test()
309{
310	print_title "TCP_INQ cmsg/ioctl $*"
311	ip netns exec "$ns_sbox" ./mptcp_inq "$@"
312	local lret=$?
313	if [ $lret -ne 0 ];then
314		ret=$lret
315		mptcp_lib_pr_fail
316		mptcp_lib_result_fail "TCP_INQ: $*"
317		return $lret
318	fi
319
320	mptcp_lib_pr_ok
321	mptcp_lib_result_pass "TCP_INQ: $*"
322	return $lret
323}
324
325do_tcpinq_tests()
326{
327	local lret=0
328
329	if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
330		mptcp_lib_pr_skip "TCP_INQ not supported"
331		mptcp_lib_result_skip "TCP_INQ"
332		return
333	fi
334
335	local args
336	for args in "-t tcp" "-r tcp"; do
337		do_tcpinq_test $args
338		lret=$?
339		if [ $lret -ne 0 ] ; then
340			return $lret
341		fi
342		do_tcpinq_test -6 $args
343		lret=$?
344		if [ $lret -ne 0 ] ; then
345			return $lret
346		fi
347	done
348
349	do_tcpinq_test -r tcp -t tcp
350
351	return $?
352}
353
354sin=$(mktemp)
355sout=$(mktemp)
356cin=$(mktemp)
357cout=$(mktemp)
358init
359make_file "$cin" "client" 1
360make_file "$sin" "server" 1
361trap cleanup EXIT
362mptcp_lib_subtests_last_ts_reset
363
364run_tests $ns1 $ns2 10.0.1.1
365run_tests $ns1 $ns2 dead:beef:1::1
366
367do_mptcp_sockopt_tests
368do_tcpinq_tests
369
370mptcp_lib_result_print_all_tap
371exit $ret
372