selftests: mptcp: lib: get counters from nstat history

Before, 'nstat' was used to retrieve each individual counter: this means
querying 4 different sources from /proc/net and iterating over 100+
counters each time. Instead, the stats could be retrieved once, and the
output file could be parsed for each counter. Even better, such file is
already present: the nstat history file.

To be able to get this working, the nstat history file also needs to
contains zero counters too, so it is still possible to know if a counter
is missing or set to 0.

This also simplifies mptcp_connect.sh: instead of checking multiple
counters before and after a test to compute the difference, the stats
history files can be reset before each test, and nstat can display only
the difference.

mptcp_lib_get_counter() continues to work when no history file is
available: by fetching nstat directly, like before. This is the case in
diag.sh and userspace_pm.sh where there is no need to save the history
file. This is also the case in mptcp_join.sh, when 'run_tests' is
executed in the background: easier to continue fetching counters than
updating the history each time it is needed.

Note: 'nstat' is called with '-s' in mptcp_lib_nstat_get(), so this
helper can be called multiple times during the test if needed.

Acked-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20251114-net-next-mptcp-sft-count-cache-stats-timeout-v1-5-863cb04e1b7b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Matthieu Baerts (NGI0) 2025-11-14 19:12:09 +01:00 committed by Jakub Kicinski
parent 658e531417
commit 71388a9f33
2 changed files with 46 additions and 55 deletions

View File

@ -389,21 +389,6 @@ do_transfer()
mptcp_lib_nstat_init "${connector_ns}" mptcp_lib_nstat_init "${connector_ns}"
fi fi
local stat_synrx_last_l
local stat_ackrx_last_l
local stat_cookietx_last
local stat_cookierx_last
local stat_csum_err_s
local stat_csum_err_c
local stat_tcpfb_last_l
stat_synrx_last_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX")
stat_ackrx_last_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX")
stat_cookietx_last=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent")
stat_cookierx_last=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv")
stat_csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr")
stat_csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr")
stat_tcpfb_last_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableFallbackACK")
timeout ${timeout_test} \ timeout ${timeout_test} \
ip netns exec ${listener_ns} \ ip netns exec ${listener_ns} \
./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \
@ -458,38 +443,38 @@ do_transfer()
rets=$? rets=$?
local extra="" local extra=""
local stat_synrx_now_l local stat_synrx
local stat_ackrx_now_l local stat_ackrx
local stat_cookietx_now local stat_cookietx
local stat_cookierx_now local stat_cookierx
local stat_ooo_now local stat_ooo
local stat_tcpfb_now_l local stat_tcpfb
stat_synrx_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX") stat_synrx=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableSYNRX")
stat_ackrx_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX") stat_ackrx=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableACKRX")
stat_cookietx_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent") stat_cookietx=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesSent")
stat_cookierx_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv") stat_cookierx=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtSyncookiesRecv")
stat_ooo_now=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtTCPOFOQueue") stat_ooo=$(mptcp_lib_get_counter "${listener_ns}" "TcpExtTCPOFOQueue")
stat_tcpfb_now_l=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableFallbackACK") stat_tcpfb=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtMPCapableFallbackACK")
expect_synrx=$((stat_synrx_last_l)) expect_synrx=0
expect_ackrx=$((stat_ackrx_last_l)) expect_ackrx=0
cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies) cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies)
cookies=${cookies##*=} cookies=${cookies##*=}
if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then
expect_synrx=$((stat_synrx_last_l+connect_per_transfer)) expect_synrx=${connect_per_transfer}
expect_ackrx=$((stat_ackrx_last_l+connect_per_transfer)) expect_ackrx=${connect_per_transfer}
fi fi
if [ ${stat_synrx_now_l} -lt ${expect_synrx} ]; then if [ ${stat_synrx} -lt ${expect_synrx} ]; then
mptcp_lib_pr_fail "lower MPC SYN rx (${stat_synrx_now_l})" \ mptcp_lib_pr_fail "lower MPC SYN rx (${stat_synrx})" \
"than expected (${expect_synrx})" "than expected (${expect_synrx})"
retc=1 retc=1
fi fi
if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} ]; then if [ ${stat_ackrx} -lt ${expect_ackrx} ]; then
if [ ${stat_ooo_now} -eq 0 ]; then if [ ${stat_ooo} -eq 0 ]; then
mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx_now_l})" \ mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx})" \
"than expected (${expect_ackrx})" "than expected (${expect_ackrx})"
rets=1 rets=1
else else
@ -503,47 +488,45 @@ do_transfer()
csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr") csum_err_s=$(mptcp_lib_get_counter "${listener_ns}" "MPTcpExtDataCsumErr")
csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr") csum_err_c=$(mptcp_lib_get_counter "${connector_ns}" "MPTcpExtDataCsumErr")
local csum_err_s_nr=$((csum_err_s - stat_csum_err_s)) if [ $csum_err_s -gt 0 ]; then
if [ $csum_err_s_nr -gt 0 ]; then mptcp_lib_pr_fail "server got ${csum_err_s} data checksum error[s]"
mptcp_lib_pr_fail "server got ${csum_err_s_nr} data checksum error[s]"
rets=1 rets=1
fi fi
local csum_err_c_nr=$((csum_err_c - stat_csum_err_c)) if [ $csum_err_c -gt 0 ]; then
if [ $csum_err_c_nr -gt 0 ]; then mptcp_lib_pr_fail "client got ${csum_err_c} data checksum error[s]"
mptcp_lib_pr_fail "client got ${csum_err_c_nr} data checksum error[s]"
retc=1 retc=1
fi fi
fi fi
if [ ${stat_ooo_now} -eq 0 ] && [ ${stat_tcpfb_last_l} -ne ${stat_tcpfb_now_l} ]; then if [ ${stat_ooo} -eq 0 ] && [ ${stat_tcpfb} -gt 0 ]; then
mptcp_lib_pr_fail "unexpected fallback to TCP" mptcp_lib_pr_fail "unexpected fallback to TCP"
rets=1 rets=1
fi fi
if [ $cookies -eq 2 ];then if [ $cookies -eq 2 ];then
if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then if [ $stat_cookietx -eq 0 ] ;then
extra+=" WARN: CookieSent: did not advance" extra+=" WARN: CookieSent: did not advance"
fi fi
if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then if [ $stat_cookierx -eq 0 ] ;then
extra+=" WARN: CookieRecv: did not advance" extra+=" WARN: CookieRecv: did not advance"
fi fi
else else
if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then if [ $stat_cookietx -gt 0 ] ;then
extra+=" WARN: CookieSent: changed" extra+=" WARN: CookieSent: changed"
fi fi
if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then if [ $stat_cookierx -gt 0 ] ;then
extra+=" WARN: CookieRecv: changed" extra+=" WARN: CookieRecv: changed"
fi fi
fi fi
if [ ${stat_synrx_now_l} -gt ${expect_synrx} ]; then if [ ${stat_synrx} -gt ${expect_synrx} ]; then
extra+=" WARN: SYNRX: expect ${expect_synrx}," extra+=" WARN: SYNRX: expect ${expect_synrx},"
extra+=" got ${stat_synrx_now_l} (probably retransmissions)" extra+=" got ${stat_synrx} (probably retransmissions)"
fi fi
if [ ${stat_ackrx_now_l} -gt ${expect_ackrx} ]; then if [ ${stat_ackrx} -gt ${expect_ackrx} ]; then
extra+=" WARN: ACKRX: expect ${expect_ackrx}," extra+=" WARN: ACKRX: expect ${expect_ackrx},"
extra+=" got ${stat_ackrx_now_l} (probably retransmissions)" extra+=" got ${stat_ackrx} (probably retransmissions)"
fi fi
if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then if [ $retc -eq 0 ] && [ $rets -eq 0 ]; then

View File

@ -111,7 +111,7 @@ mptcp_lib_pr_nstat() {
local hist="/tmp/${ns}.out" local hist="/tmp/${ns}.out"
if [ -f "${hist}" ]; then if [ -f "${hist}" ]; then
awk '{ print " "$0 }' "${hist}" awk '$2 != 0 { print " "$0 }' "${hist}"
else else
ip netns exec "${ns}" nstat -as | grep Tcp ip netns exec "${ns}" nstat -as | grep Tcp
fi fi
@ -388,6 +388,7 @@ mptcp_lib_is_v6() {
mptcp_lib_nstat_init() { mptcp_lib_nstat_init() {
local ns="${1}" local ns="${1}"
rm -f "/tmp/${ns}."{nstat,out}
NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat -n NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat -n
} }
@ -395,18 +396,25 @@ mptcp_lib_nstat_get() {
local ns="${1}" local ns="${1}"
# filter out non-*TCP stats, and the rate (last column) # filter out non-*TCP stats, and the rate (last column)
NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat | NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat -sz |
grep -o ".*Tcp\S\+\s\+[0-9]\+" > "/tmp/${ns}.out" grep -o ".*Tcp\S\+\s\+[0-9]\+" > "/tmp/${ns}.out"
} }
# $1: ns, $2: MIB counter # $1: ns, $2: MIB counter
# Get the counter from the history (mptcp_lib_nstat_{init,get}()) if available.
# If not, get the counter from nstat ignoring any history.
mptcp_lib_get_counter() { mptcp_lib_get_counter() {
local ns="${1}" local ns="${1}"
local counter="${2}" local counter="${2}"
local hist="/tmp/${ns}.out"
local count local count
count=$(ip netns exec "${ns}" nstat -asz "${counter}" | if [[ -s "${hist}" && "${counter}" == *"Tcp"* ]]; then
awk 'NR==1 {next} {print $2}') count=$(awk "/^${counter} / {print \$2; exit}" "${hist}")
else
count=$(ip netns exec "${ns}" nstat -asz "${counter}" |
awk 'NR==1 {next} {print $2}')
fi
if [ -z "${count}" ]; then if [ -z "${count}" ]; then
mptcp_lib_fail_if_expected_feature "${counter} counter" mptcp_lib_fail_if_expected_feature "${counter} counter"
return 1 return 1