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