Merge branch 'selftests-mptcp-skip-tests-not-supported-by-old-kernels-part-2'
Matthieu Baerts says: ==================== selftests: mptcp: skip tests not supported by old kernels (part 2) After a few years of increasing test coverage in the MPTCP selftests, we realised [1] the last version of the selftests is supposed to run on old kernels without issues. Supporting older versions is not that easy for this MPTCP case: these selftests are often validating the internals by checking packets that are exchanged, when some MIB counters are incremented after some actions, how connections are getting opened and closed in some cases, etc. In other words, it is not limited to the socket interface between the userspace and the kernelspace. In addition to that, the current MPTCP selftests run a lot of different sub-tests but the TAP13 protocol used in the selftests don't support sub-tests: one failure in sub-tests implies that the whole selftest is seen as failed at the end because sub-tests are not tracked. It is then important to skip sub-tests not supported by old kernels. To minimise the modifications and reduce the complexity to support old versions, the idea is to look at external signs and skip the whole selftests or just some sub-tests before starting them. This cannot be applied in all cases. This second part focuses on marking different sub-tests as skipped if some MPTCP features are not supported. A few techniques are used here: - Before starting some tests: - Check if a file (sysctl knob) is present: that's what patch 13/14 is doing for the userspace PM feature. - Check if a symbol is present in /proc/kallsyms: patch 1/14 adds some helpers in mptcp_lib.sh to ease its use. Then these helpers are used in patches 2, 3, 4, 10, 11 and 14/14. - Set a flag and get the status to check if a feature is supported: patch 8/14 is doing that with the 'fullmesh' flag. - After having launched the tests: - Retrieve the counters after a test and check if they are different than 0. Similar to the check with the flag, that's not ideal but in this case, the counters were already present before the introduction of MPTCP but they have been supported by MPTCP sockets only later. Patches 5 and 6/14 are using this technique. Before skipping tests, SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var value is checked: if it is set to 1, the test is marked as "failed" instead of "skipped". MPTCP public CI expects to have all features supported and it sets this env var to 1 to catch regressions in these new checks. Patches 7/14 and 9/14 are a bit different because they don't skip tests: - Patch 7/14 retrieves the default values instead of using hardcoded ones because these default values have been modified at some points. Then the comparisons are done with the default values. - patch 9/14 relaxes the expected returned size from MPTCP's getsockopt because the different structures gathering various info can get new fields and get bigger over time. We cannot expect that the userspace is using the same structure as the kernel. Patch 12/14 marks the test as "skipped" instead of "failed" if the "ip" tool is not available. In this second part, the "mptcp_join" selftest is not modified yet. This will come soon after in the third part with quite a few patches. Link: https://lore.kernel.org/stable/CA+G9fYtDGpgT4dckXD-y-N92nqUxuvue_7AtDdBcHrbOMsDZLg@mail.gmail.com/ [1] Link: https://github.com/multipath-tcp/mptcp_net-next/issues/368 ==================== Link: https://lore.kernel.org/r/20230608-upstream-net-20230608-mptcp-selftests-support-old-kernels-part-2-v1-0-20997a6fd841@tessares.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
bc51d371bc
@ -1,3 +1,4 @@
|
||||
CONFIG_KALLSYMS=y
|
||||
CONFIG_MPTCP=y
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_MPTCP_IPV6=y
|
||||
|
@ -55,16 +55,20 @@ __chk_nr()
|
||||
{
|
||||
local command="$1"
|
||||
local expected=$2
|
||||
local msg nr
|
||||
local msg="$3"
|
||||
local skip="${4:-SKIP}"
|
||||
local nr
|
||||
|
||||
shift 2
|
||||
msg=$*
|
||||
nr=$(eval $command)
|
||||
|
||||
printf "%-50s" "$msg"
|
||||
if [ $nr != $expected ]; then
|
||||
echo "[ fail ] expected $expected found $nr"
|
||||
ret=$test_cnt
|
||||
if [ $nr = "$skip" ] && ! mptcp_lib_expect_all_features; then
|
||||
echo "[ skip ] Feature probably not supported"
|
||||
else
|
||||
echo "[ fail ] expected $expected found $nr"
|
||||
ret=$test_cnt
|
||||
fi
|
||||
else
|
||||
echo "[ ok ]"
|
||||
fi
|
||||
@ -76,12 +80,12 @@ __chk_msk_nr()
|
||||
local condition=$1
|
||||
shift 1
|
||||
|
||||
__chk_nr "ss -inmHMN $ns | $condition" $*
|
||||
__chk_nr "ss -inmHMN $ns | $condition" "$@"
|
||||
}
|
||||
|
||||
chk_msk_nr()
|
||||
{
|
||||
__chk_msk_nr "grep -c token:" $*
|
||||
__chk_msk_nr "grep -c token:" "$@"
|
||||
}
|
||||
|
||||
wait_msk_nr()
|
||||
@ -119,37 +123,26 @@ wait_msk_nr()
|
||||
|
||||
chk_msk_fallback_nr()
|
||||
{
|
||||
__chk_msk_nr "grep -c fallback" $*
|
||||
__chk_msk_nr "grep -c fallback" "$@"
|
||||
}
|
||||
|
||||
chk_msk_remote_key_nr()
|
||||
{
|
||||
__chk_msk_nr "grep -c remote_key" $*
|
||||
__chk_msk_nr "grep -c remote_key" "$@"
|
||||
}
|
||||
|
||||
__chk_listen()
|
||||
{
|
||||
local filter="$1"
|
||||
local expected=$2
|
||||
local msg="$3"
|
||||
|
||||
shift 2
|
||||
msg=$*
|
||||
|
||||
nr=$(ss -N $ns -Ml "$filter" | grep -c LISTEN)
|
||||
printf "%-50s" "$msg"
|
||||
|
||||
if [ $nr != $expected ]; then
|
||||
echo "[ fail ] expected $expected found $nr"
|
||||
ret=$test_cnt
|
||||
else
|
||||
echo "[ ok ]"
|
||||
fi
|
||||
__chk_nr "ss -N $ns -Ml '$filter' | grep -c LISTEN" "$expected" "$msg" 0
|
||||
}
|
||||
|
||||
chk_msk_listen()
|
||||
{
|
||||
lport=$1
|
||||
local msg="check for listen socket"
|
||||
|
||||
# destination port search should always return empty list
|
||||
__chk_listen "dport $lport" 0 "listen match for dport $lport"
|
||||
@ -167,10 +160,9 @@ chk_msk_listen()
|
||||
chk_msk_inuse()
|
||||
{
|
||||
local expected=$1
|
||||
local msg="$2"
|
||||
local listen_nr
|
||||
|
||||
shift 1
|
||||
|
||||
listen_nr=$(ss -N "${ns}" -Ml | grep -c LISTEN)
|
||||
expected=$((expected + listen_nr))
|
||||
|
||||
@ -181,7 +173,7 @@ chk_msk_inuse()
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
__chk_nr get_msk_inuse $expected $*
|
||||
__chk_nr get_msk_inuse $expected "$msg" 0
|
||||
}
|
||||
|
||||
# $1: ns, $2: port
|
||||
|
@ -144,6 +144,7 @@ cleanup()
|
||||
}
|
||||
|
||||
mptcp_lib_check_mptcp
|
||||
mptcp_lib_check_kallsyms
|
||||
|
||||
ip -Version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
@ -695,6 +696,15 @@ run_test_transparent()
|
||||
return 0
|
||||
fi
|
||||
|
||||
# IP(V6)_TRANSPARENT has been added after TOS support which came with
|
||||
# the required infrastructure in MPTCP sockopt code. To support TOS, the
|
||||
# following function has been exported (T). Not great but better than
|
||||
# checking for a specific kernel version.
|
||||
if ! mptcp_lib_kallsyms_has "T __ip_sock_set_tos$"; then
|
||||
echo "INFO: ${msg} not supported by the kernel: SKIP"
|
||||
return
|
||||
fi
|
||||
|
||||
ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF"
|
||||
flush ruleset
|
||||
table inet mangle {
|
||||
@ -767,6 +777,11 @@ run_tests_peekmode()
|
||||
|
||||
run_tests_mptfo()
|
||||
{
|
||||
if ! mptcp_lib_kallsyms_has "mptcp_fastopen_"; then
|
||||
echo "INFO: TFO not supported by the kernel: SKIP"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "INFO: with MPTFO start"
|
||||
ip netns exec "$ns1" sysctl -q net.ipv4.tcp_fastopen=2
|
||||
ip netns exec "$ns2" sysctl -q net.ipv4.tcp_fastopen=1
|
||||
@ -787,6 +802,11 @@ run_tests_disconnect()
|
||||
local old_cin=$cin
|
||||
local old_sin=$sin
|
||||
|
||||
if ! mptcp_lib_kallsyms_has "mptcp_pm_data_reset$"; then
|
||||
echo "INFO: Full disconnect not supported: SKIP"
|
||||
return
|
||||
fi
|
||||
|
||||
cat $cin $cin $cin > "$cin".disconnect
|
||||
|
||||
# force do_transfer to cope with the multiple tranmissions
|
||||
|
@ -38,3 +38,41 @@ mptcp_lib_check_mptcp() {
|
||||
exit ${KSFT_SKIP}
|
||||
fi
|
||||
}
|
||||
|
||||
mptcp_lib_check_kallsyms() {
|
||||
if ! mptcp_lib_has_file "/proc/kallsyms"; then
|
||||
echo "SKIP: CONFIG_KALLSYMS is missing"
|
||||
exit ${KSFT_SKIP}
|
||||
fi
|
||||
}
|
||||
|
||||
# Internal: use mptcp_lib_kallsyms_has() instead
|
||||
__mptcp_lib_kallsyms_has() {
|
||||
local sym="${1}"
|
||||
|
||||
mptcp_lib_check_kallsyms
|
||||
|
||||
grep -q " ${sym}" /proc/kallsyms
|
||||
}
|
||||
|
||||
# $1: part of a symbol to look at, add '$' at the end for full name
|
||||
mptcp_lib_kallsyms_has() {
|
||||
local sym="${1}"
|
||||
|
||||
if __mptcp_lib_kallsyms_has "${sym}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
|
||||
}
|
||||
|
||||
# $1: part of a symbol to look at, add '$' at the end for full name
|
||||
mptcp_lib_kallsyms_doesnt_have() {
|
||||
local sym="${1}"
|
||||
|
||||
if ! __mptcp_lib_kallsyms_has "${sym}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
|
||||
}
|
||||
|
@ -87,6 +87,10 @@ struct so_state {
|
||||
uint64_t tcpi_rcv_delta;
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static void die_perror(const char *msg)
|
||||
{
|
||||
perror(msg);
|
||||
@ -349,13 +353,14 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t
|
||||
xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
|
||||
|
||||
assert(olen <= sizeof(ti));
|
||||
assert(ti.d.size_user == ti.d.size_kernel);
|
||||
assert(ti.d.size_user == sizeof(struct tcp_info));
|
||||
assert(ti.d.size_kernel > 0);
|
||||
assert(ti.d.size_user ==
|
||||
MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
|
||||
assert(ti.d.num_subflows == 1);
|
||||
|
||||
assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
|
||||
olen -= sizeof(struct mptcp_subflow_data);
|
||||
assert(olen == sizeof(struct tcp_info));
|
||||
assert(olen == ti.d.size_user);
|
||||
|
||||
if (ti.ti[0].tcpi_bytes_sent == w &&
|
||||
ti.ti[0].tcpi_bytes_received == r)
|
||||
@ -401,13 +406,14 @@ static void do_getsockopt_subflow_addrs(int fd)
|
||||
die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
|
||||
|
||||
assert(olen <= sizeof(addrs));
|
||||
assert(addrs.d.size_user == addrs.d.size_kernel);
|
||||
assert(addrs.d.size_user == sizeof(struct mptcp_subflow_addrs));
|
||||
assert(addrs.d.size_kernel > 0);
|
||||
assert(addrs.d.size_user ==
|
||||
MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
|
||||
assert(addrs.d.num_subflows == 1);
|
||||
|
||||
assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
|
||||
olen -= sizeof(struct mptcp_subflow_data);
|
||||
assert(olen == sizeof(struct mptcp_subflow_addrs));
|
||||
assert(olen == addrs.d.size_user);
|
||||
|
||||
llen = sizeof(local);
|
||||
ret = getsockname(fd, (struct sockaddr *)&local, &llen);
|
||||
|
@ -87,6 +87,7 @@ cleanup()
|
||||
}
|
||||
|
||||
mptcp_lib_check_mptcp
|
||||
mptcp_lib_check_kallsyms
|
||||
|
||||
ip -Version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
@ -186,9 +187,14 @@ do_transfer()
|
||||
local_addr="0.0.0.0"
|
||||
fi
|
||||
|
||||
cmsg="TIMESTAMPNS"
|
||||
if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
|
||||
cmsg+=",TCPINQ"
|
||||
fi
|
||||
|
||||
timeout ${timeout_test} \
|
||||
ip netns exec ${listener_ns} \
|
||||
$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c TIMESTAMPNS,TCPINQ \
|
||||
$mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
|
||||
${local_addr} < "$sin" > "$sout" &
|
||||
local spid=$!
|
||||
|
||||
@ -196,7 +202,7 @@ do_transfer()
|
||||
|
||||
timeout ${timeout_test} \
|
||||
ip netns exec ${connector_ns} \
|
||||
$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMESTAMPNS,TCPINQ \
|
||||
$mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
|
||||
$connect_addr < "$cin" > "$cout" &
|
||||
|
||||
local cpid=$!
|
||||
@ -253,6 +259,11 @@ do_mptcp_sockopt_tests()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
|
||||
echo "INFO: MPTCP sockopt not supported: SKIP"
|
||||
return
|
||||
fi
|
||||
|
||||
ip netns exec "$ns_sbox" ./mptcp_sockopt
|
||||
lret=$?
|
||||
|
||||
@ -307,6 +318,11 @@ do_tcpinq_tests()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
|
||||
echo "INFO: TCP_INQ not supported: SKIP"
|
||||
return
|
||||
fi
|
||||
|
||||
local args
|
||||
for args in "-t tcp" "-r tcp"; do
|
||||
do_tcpinq_test $args
|
||||
|
@ -73,8 +73,12 @@ check()
|
||||
}
|
||||
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "defaults addr list"
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
|
||||
|
||||
default_limits="$(ip netns exec $ns1 ./pm_nl_ctl limits)"
|
||||
if mptcp_lib_expect_all_features; then
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
|
||||
subflows 2" "defaults limits"
|
||||
fi
|
||||
|
||||
ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.1
|
||||
ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.2 flags subflow dev lo
|
||||
@ -121,12 +125,10 @@ ip netns exec $ns1 ./pm_nl_ctl flush
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "flush addrs"
|
||||
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 9 1
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
|
||||
subflows 2" "rcv addrs above hard limit"
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "rcv addrs above hard limit"
|
||||
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 1 9
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
|
||||
subflows 2" "subflows above hard limit"
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "subflows above hard limit"
|
||||
|
||||
ip netns exec $ns1 ./pm_nl_ctl limits 8 8
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 8
|
||||
@ -176,14 +178,19 @@ subflow,backup 10.0.1.1" "set flags (backup)"
|
||||
ip netns exec $ns1 ./pm_nl_ctl set 10.0.1.1 flags nobackup
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
subflow 10.0.1.1" " (nobackup)"
|
||||
|
||||
# fullmesh support has been added later
|
||||
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags fullmesh
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
if ip netns exec $ns1 ./pm_nl_ctl dump | grep -q "fullmesh" ||
|
||||
mptcp_lib_expect_all_features; then
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
subflow,fullmesh 10.0.1.1" " (fullmesh)"
|
||||
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
subflow 10.0.1.1" " (nofullmesh)"
|
||||
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
|
||||
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
|
||||
subflow,backup,fullmesh 10.0.1.1" " (backup,fullmesh)"
|
||||
fi
|
||||
|
||||
exit $ret
|
||||
|
@ -4,11 +4,17 @@
|
||||
. "$(dirname "${0}")/mptcp_lib.sh"
|
||||
|
||||
mptcp_lib_check_mptcp
|
||||
mptcp_lib_check_kallsyms
|
||||
|
||||
if ! mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
|
||||
echo "userspace pm tests are not supported by the kernel: SKIP"
|
||||
exit ${KSFT_SKIP}
|
||||
fi
|
||||
|
||||
ip -Version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP: Cannot not run test without ip tool"
|
||||
exit 1
|
||||
exit ${KSFT_SKIP}
|
||||
fi
|
||||
|
||||
ANNOUNCED=6 # MPTCP_EVENT_ANNOUNCED
|
||||
@ -909,6 +915,11 @@ test_listener()
|
||||
{
|
||||
print_title "Listener tests"
|
||||
|
||||
if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
|
||||
stdbuf -o0 -e0 printf "LISTENER events \t[SKIP] Not supported\n"
|
||||
return
|
||||
fi
|
||||
|
||||
# Capture events on the network namespace running the client
|
||||
:>$client_evts
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user