1
0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2026-01-11 17:10:13 +00:00
Matthieu Baerts (NGI0) eea2f44870 selftests: mptcp: get stats just before timing out
Recently, some debugging happened around a test that was timing out. The
stats were showing connections being closed which was confusing because
the closing state was caused by the timeout stopping the transfer.

To avoid such confusion, the timeout is no longer done per mptcp_connect
process, but separately. In case of timeout, the stats are now printed,
then the apps are killed.

The stats will still be printed after the kill, but that's fine, and
this might even be useful, just in case. Timeout should be exceptional.

Reviewed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20251114-net-next-mptcp-sft-count-cache-stats-timeout-v1-8-863cb04e1b7b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-11-17 19:27:47 -08:00

372 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Double quotes to prevent globbing and word splitting is recommended in new
# code but we accept it, especially because there were too many before having
# address all other issues detected by shellcheck.
#shellcheck disable=SC2086
. "$(dirname "${0}")/mptcp_lib.sh"
ret=0
sin=""
sout=""
cin=""
cout=""
timeout_poll=30
timeout_test=$((timeout_poll * 2 + 1))
iptables="iptables"
ip6tables="ip6tables"
ns1=""
ns2=""
ns_sbox=""
usage() {
echo "Usage: $0 [ -i ] [ -h ]"
echo -e "\t-i: use 'ip mptcp' instead of 'pm_nl_ctl'"
echo -e "\t-h: help"
}
while getopts "hi" option;do
case "$option" in
"h")
usage "$0"
exit ${KSFT_PASS}
;;
"i")
mptcp_lib_set_ip_mptcp
;;
"?")
usage "$0"
exit ${KSFT_FAIL}
;;
esac
done
add_mark_rules()
{
local ns=$1
local m=$2
local t
for t in ${iptables} ${ip6tables}; do
# just to debug: check we have multiple subflows connection requests
ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT
# RST packets might be handled by a internal dummy socket
ip netns exec $ns $t -A OUTPUT -p tcp --tcp-flags RST RST -m mark --mark 0 -j ACCEPT
ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark $m -j ACCEPT
ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark 0 -j DROP
done
}
init()
{
mptcp_lib_ns_init ns1 ns2 ns_sbox
local i
for i in $(seq 1 4); do
ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2"
ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i
ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad
ip -net "$ns1" link set ns1eth$i up
ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i
ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad
ip -net "$ns2" link set ns2eth$i up
# let $ns2 reach any $ns1 address from any interface
ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
mptcp_lib_pm_nl_add_endpoint "${ns1}" "10.0.${i}.1" flags signal
mptcp_lib_pm_nl_add_endpoint "${ns1}" "dead:beef:${i}::1" flags signal
mptcp_lib_pm_nl_add_endpoint "${ns2}" "10.0.${i}.2" flags signal
mptcp_lib_pm_nl_add_endpoint "${ns2}" "dead:beef:${i}::2" flags signal
done
mptcp_lib_pm_nl_set_limits "${ns1}" 8 8
mptcp_lib_pm_nl_set_limits "${ns2}" 8 8
add_mark_rules $ns1 1
add_mark_rules $ns2 2
}
# This function is used in the cleanup trap
#shellcheck disable=SC2317,SC2329
cleanup()
{
mptcp_lib_ns_exit "${ns1}" "${ns2}" "${ns_sbox}"
rm -f "$cin" "$cout"
rm -f "$sin" "$sout"
}
mptcp_lib_check_mptcp
mptcp_lib_check_kallsyms
mptcp_lib_check_tools ip "${iptables}" "${ip6tables}"
check_mark()
{
local ns=$1
local af=$2
local tables=${iptables}
if [ $af -eq 6 ];then
tables=${ip6tables}
fi
local counters values
counters=$(ip netns exec $ns $tables -v -L OUTPUT | grep DROP)
values=${counters%DROP*}
local v
for v in $values; do
if [ $v -ne 0 ]; then
mptcp_lib_pr_fail "got $tables $values in ns $ns," \
"not 0 - not all expected packets marked"
ret=${KSFT_FAIL}
return 1
fi
done
return 0
}
print_title()
{
mptcp_lib_print_title "${@}"
}
do_transfer()
{
local listener_ns="$1"
local connector_ns="$2"
local cl_proto="$3"
local srv_proto="$4"
local connect_addr="$5"
local port=12001
:> "$cout"
:> "$sout"
local mptcp_connect="./mptcp_connect -r 20"
local local_addr ip
if mptcp_lib_is_v6 "${connect_addr}"; then
local_addr="::"
ip=ipv6
else
local_addr="0.0.0.0"
ip=ipv4
fi
cmsg="TIMESTAMPNS"
if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
cmsg+=",TCPINQ"
fi
mptcp_lib_nstat_init "${listener_ns}"
mptcp_lib_nstat_init "${connector_ns}"
ip netns exec ${listener_ns} \
$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
${local_addr} < "$sin" > "$sout" &
local spid=$!
mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}"
ip netns exec ${connector_ns} \
$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
$connect_addr < "$cin" > "$cout" &
local cpid=$!
mptcp_lib_wait_timeout "${timeout_test}" "${listener_ns}" \
"${connector_ns}" "${port}" "${cpid}" "${spid}" &
local timeout_pid=$!
wait $cpid
local retc=$?
wait $spid
local rets=$?
if kill -0 $timeout_pid; then
# Finished before the timeout: kill the background job
mptcp_lib_kill_group_wait $timeout_pid
timeout_pid=0
fi
mptcp_lib_nstat_get "${listener_ns}"
mptcp_lib_nstat_get "${connector_ns}"
print_title "Transfer ${ip:2}"
if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ] || [ ${timeout_pid} -ne 0 ]; then
mptcp_lib_pr_fail "client exit code $retc, server $rets"
mptcp_lib_pr_err_stats "${listener_ns}" "${connector_ns}" "${port}"
mptcp_lib_result_fail "transfer ${ip}"
ret=${KSFT_FAIL}
return 1
fi
if ! mptcp_lib_check_transfer $cin $sout "file received by server"; then
rets=1
else
mptcp_lib_pr_ok
fi
mptcp_lib_result_code "${rets}" "transfer ${ip}"
print_title "Mark ${ip:2}"
if [ $local_addr = "::" ];then
check_mark $listener_ns 6 || retc=1
check_mark $connector_ns 6 || retc=1
else
check_mark $listener_ns 4 || retc=1
check_mark $connector_ns 4 || retc=1
fi
mptcp_lib_result_code "${retc}" "mark ${ip}"
if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
mptcp_lib_pr_ok
return 0
fi
mptcp_lib_pr_fail
return 1
}
make_file()
{
local name=$1
local who=$2
local size=$3
mptcp_lib_make_file $name 1024 $size
echo "Created $name (size $size KB) containing data sent by $who"
}
do_mptcp_sockopt_tests()
{
local lret=0
if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
mptcp_lib_pr_skip "MPTCP sockopt not supported"
mptcp_lib_result_skip "sockopt"
return
fi
ip netns exec "$ns_sbox" ./mptcp_sockopt
lret=$?
print_title "SOL_MPTCP sockopt v4"
if [ $lret -ne 0 ]; then
mptcp_lib_pr_fail
mptcp_lib_result_fail "sockopt v4"
ret=$lret
return
fi
mptcp_lib_pr_ok
mptcp_lib_result_pass "sockopt v4"
ip netns exec "$ns_sbox" ./mptcp_sockopt -6
lret=$?
print_title "SOL_MPTCP sockopt v6"
if [ $lret -ne 0 ]; then
mptcp_lib_pr_fail
mptcp_lib_result_fail "sockopt v6"
ret=$lret
return
fi
mptcp_lib_pr_ok
mptcp_lib_result_pass "sockopt v6"
}
run_tests()
{
local listener_ns="$1"
local connector_ns="$2"
local connect_addr="$3"
local lret=0
do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr}
lret=$?
if [ $lret -ne 0 ]; then
ret=$lret
return
fi
}
do_tcpinq_test()
{
print_title "TCP_INQ cmsg/ioctl $*"
ip netns exec "$ns_sbox" ./mptcp_inq "$@"
local lret=$?
if [ $lret -ne 0 ];then
ret=$lret
mptcp_lib_pr_fail
mptcp_lib_result_fail "TCP_INQ: $*"
return $lret
fi
mptcp_lib_pr_ok
mptcp_lib_result_pass "TCP_INQ: $*"
return $lret
}
do_tcpinq_tests()
{
local lret=0
if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
mptcp_lib_pr_skip "TCP_INQ not supported"
mptcp_lib_result_skip "TCP_INQ"
return
fi
local args
for args in "-t tcp" "-r tcp"; do
do_tcpinq_test $args
lret=$?
if [ $lret -ne 0 ] ; then
return $lret
fi
do_tcpinq_test -6 $args
lret=$?
if [ $lret -ne 0 ] ; then
return $lret
fi
done
do_tcpinq_test -r tcp -t tcp
return $?
}
sin=$(mktemp)
sout=$(mktemp)
cin=$(mktemp)
cout=$(mktemp)
init
make_file "$cin" "client" 1
make_file "$sin" "server" 1
trap cleanup EXIT
mptcp_lib_subtests_last_ts_reset
run_tests $ns1 $ns2 10.0.1.1
run_tests $ns1 $ns2 dead:beef:1::1
do_mptcp_sockopt_tests
do_tcpinq_tests
mptcp_lib_result_print_all_tap
exit $ret