2 # SPDX-License-Identifier: GPL-2.0
4 .
"$(dirname "${0}")/../lib.sh"
5 .
"$(dirname "${0}")/../net_helper.sh"
11 # shellcheck disable=SC2155 # declare and assign separately
12 readonly KSFT_TEST
="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}"
14 # These variables are used in some selftests, read-only
15 declare -rx MPTCP_LIB_EVENT_CREATED
=1 # MPTCP_EVENT_CREATED
16 declare -rx MPTCP_LIB_EVENT_ESTABLISHED
=2 # MPTCP_EVENT_ESTABLISHED
17 declare -rx MPTCP_LIB_EVENT_CLOSED
=3 # MPTCP_EVENT_CLOSED
18 declare -rx MPTCP_LIB_EVENT_ANNOUNCED
=6 # MPTCP_EVENT_ANNOUNCED
19 declare -rx MPTCP_LIB_EVENT_REMOVED
=7 # MPTCP_EVENT_REMOVED
20 declare -rx MPTCP_LIB_EVENT_SUB_ESTABLISHED
=10 # MPTCP_EVENT_SUB_ESTABLISHED
21 declare -rx MPTCP_LIB_EVENT_SUB_CLOSED
=11 # MPTCP_EVENT_SUB_CLOSED
22 declare -rx MPTCP_LIB_EVENT_SUB_PRIORITY
=13 # MPTCP_EVENT_SUB_PRIORITY
23 declare -rx MPTCP_LIB_EVENT_LISTENER_CREATED
=15 # MPTCP_EVENT_LISTENER_CREATED
24 declare -rx MPTCP_LIB_EVENT_LISTENER_CLOSED
=16 # MPTCP_EVENT_LISTENER_CLOSED
26 declare -rx MPTCP_LIB_AF_INET
=2
27 declare -rx MPTCP_LIB_AF_INET6
=10
30 MPTCP_LIB_SUBTESTS_DUPLICATED
=0
31 MPTCP_LIB_SUBTEST_FLAKY
=0
32 MPTCP_LIB_SUBTESTS_LAST_TS_MS
=
33 MPTCP_LIB_TEST_COUNTER
=0
34 MPTCP_LIB_TEST_FORMAT
="%02u %-50s"
37 # only if supported (or forced) and not disabled, see no-color.org
38 if { [ -t 1 ] ||
[ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } &&
39 [ "${NO_COLOR:-}" != "1" ]; then
40 readonly MPTCP_LIB_COLOR_RED
="\E[1;31m"
41 readonly MPTCP_LIB_COLOR_GREEN
="\E[1;32m"
42 readonly MPTCP_LIB_COLOR_YELLOW
="\E[1;33m"
43 readonly MPTCP_LIB_COLOR_BLUE
="\E[1;34m"
44 readonly MPTCP_LIB_COLOR_RESET
="\E[0m"
46 readonly MPTCP_LIB_COLOR_RED
=
47 readonly MPTCP_LIB_COLOR_GREEN
=
48 readonly MPTCP_LIB_COLOR_YELLOW
=
49 readonly MPTCP_LIB_COLOR_BLUE
=
50 readonly MPTCP_LIB_COLOR_RESET
=
53 # SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY env var can be set not to ignore errors
54 # from subtests marked as flaky
55 mptcp_lib_override_flaky
() {
56 [ "${SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:-}" = 1 ]
59 mptcp_lib_subtest_is_flaky
() {
60 [ "${MPTCP_LIB_SUBTEST_FLAKY}" = 1 ] && ! mptcp_lib_override_flaky
64 mptcp_lib_print_color
() {
65 echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}"
68 mptcp_lib_print_ok
() {
69 mptcp_lib_print_color
"${MPTCP_LIB_COLOR_GREEN}${*}"
72 mptcp_lib_print_warn
() {
73 mptcp_lib_print_color
"${MPTCP_LIB_COLOR_YELLOW}${*}"
76 mptcp_lib_print_info
() {
77 mptcp_lib_print_color
"${MPTCP_LIB_COLOR_BLUE}${*}"
80 mptcp_lib_print_err
() {
81 mptcp_lib_print_color
"${MPTCP_LIB_COLOR_RED}${*}"
84 # shellcheck disable=SC2120 # parameters are optional
86 mptcp_lib_print_ok
"[ OK ]${1:+ ${*}}"
90 mptcp_lib_print_warn
"[SKIP]${1:+ ${*}}"
96 if mptcp_lib_subtest_is_flaky
; then
103 mptcp_lib_print_err
"[${title}]${cmt}${1:+ ${*}}"
106 mptcp_lib_pr_info
() {
107 mptcp_lib_print_info
"INFO: ${*}"
110 # SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
111 # features using the last version of the kernel and the selftests to make sure
112 # a test is not being skipped by mistake.
113 mptcp_lib_expect_all_features
() {
114 [ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
118 mptcp_lib_fail_if_expected_feature
() {
119 if mptcp_lib_expect_all_features
; then
120 echo "ERROR: missing feature: ${*}"
128 mptcp_lib_has_file
() {
131 if [ -f "${f}" ]; then
135 mptcp_lib_fail_if_expected_feature
"${f} file not found"
138 mptcp_lib_check_mptcp
() {
139 if ! mptcp_lib_has_file
"/proc/sys/net/mptcp/enabled"; then
140 mptcp_lib_pr_skip
"MPTCP support is not available"
145 mptcp_lib_check_kallsyms
() {
146 if ! mptcp_lib_has_file
"/proc/kallsyms"; then
147 mptcp_lib_pr_skip
"CONFIG_KALLSYMS is missing"
152 # Internal: use mptcp_lib_kallsyms_has() instead
153 __mptcp_lib_kallsyms_has
() {
156 mptcp_lib_check_kallsyms
158 grep -q " ${sym}" /proc
/kallsyms
161 # $1: part of a symbol to look at, add '$' at the end for full name
162 mptcp_lib_kallsyms_has
() {
165 if __mptcp_lib_kallsyms_has
"${sym}"; then
169 mptcp_lib_fail_if_expected_feature
"${sym} symbol not found"
172 # $1: part of a symbol to look at, add '$' at the end for full name
173 mptcp_lib_kallsyms_doesnt_have
() {
176 if ! __mptcp_lib_kallsyms_has
"${sym}"; then
180 mptcp_lib_fail_if_expected_feature
"${sym} symbol has been found"
183 # !!!AVOID USING THIS!!!
184 # Features might not land in the expected version and features can be backported
186 # $1: kernel version, e.g. 6.3
187 mptcp_lib_kversion_ge
() {
188 local exp_maj
="${1%.*}"
189 local exp_min
="${1#*.}"
192 # If the kernel has backported features, set this env var to 1:
193 if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
197 v
=$
(uname
-r | cut
-d'.' -f1,2)
201 if [ "${maj}" -gt "${exp_maj}" ] ||
202 { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
206 mptcp_lib_fail_if_expected_feature "kernel version
${1} lower than
${v}"
209 mptcp_lib_subtests_last_ts_reset() {
210 MPTCP_LIB_SUBTESTS_LAST_TS_MS="$
(date +%s
%3N
)"
212 mptcp_lib_subtests_last_ts_reset
214 __mptcp_lib_result_check_duplicated() {
217 for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do
218 if [[ "${subtest}" == *" - ${KSFT_TEST}: ${*%% #*}" ]]; then
219 MPTCP_LIB_SUBTESTS_DUPLICATED=1
220 mptcp_lib_print_err "Duplicated entry
: ${*}"
226 __mptcp_lib_result_add() {
232 local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))
234 __mptcp_lib_result_check_duplicated "${*}"
237 [[ "${*}" != *"#"* ]] && time="# ${time}"
239 ts_prev_ms
="${MPTCP_LIB_SUBTESTS_LAST_TS_MS}"
240 mptcp_lib_subtests_last_ts_reset
241 time+="$((MPTCP_LIB_SUBTESTS_LAST_TS_MS - ts_prev_ms))ms"
243 MPTCP_LIB_SUBTESTS
+=("${result} ${id} - ${KSFT_TEST}: ${*} ${time}")
247 mptcp_lib_result_pass
() {
248 __mptcp_lib_result_add
"ok" "${1}"
252 mptcp_lib_result_fail
() {
253 if mptcp_lib_subtest_is_flaky
; then
254 # It might sound better to use 'not ok # TODO' or 'ok # SKIP',
255 # but some CIs don't understand 'TODO' and treat SKIP as errors.
256 __mptcp_lib_result_add
"ok" "${1} # IGNORE Flaky"
258 __mptcp_lib_result_add
"not ok" "${1}"
263 mptcp_lib_result_skip
() {
264 __mptcp_lib_result_add
"ok" "${1} # SKIP"
267 # $1: result code ; $2: test name
268 mptcp_lib_result_code
() {
274 mptcp_lib_result_pass
"${name}"
277 mptcp_lib_result_fail
"${name}"
280 mptcp_lib_result_skip
"${name}"
283 echo "ERROR: wrong result code: ${ret}"
289 mptcp_lib_result_print_all_tap
() {
292 if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] ||
293 [ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then
297 printf "\nTAP version 13\n"
298 printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}"
300 for subtest
in "${MPTCP_LIB_SUBTESTS[@]}"; do
301 printf "%s\n" "${subtest}"
304 if [ "${MPTCP_LIB_SUBTESTS_DUPLICATED}" = 1 ] &&
305 mptcp_lib_expect_all_features
; then
306 mptcp_lib_print_err
"Duplicated test entries"
311 # get the value of keyword $1 in the line marked by keyword $2
312 mptcp_lib_get_info_value
() {
313 grep "${2}" |
sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q'
316 # $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]]
317 mptcp_lib_evts_get_info
() {
318 grep "${4:-}" "${2}" | mptcp_lib_get_info_value "${1}" "^type:${3:-1},"
322 mptcp_lib_kill_wait
() {
323 [ "${1}" -eq 0 ] && return 0
325 kill -SIGUSR1 "${1}" > /dev
/null
2>&1
326 kill "${1}" > /dev
/null
2>&1
327 wait "${1}" 2>/dev
/null
335 # $1: ns, $2: MIB counter
336 mptcp_lib_get_counter
() {
341 count
=$
(ip netns
exec "${ns}" nstat
-asz "${counter}" |
342 awk 'NR==1 {next} {print $2}')
343 if [ -z "${count}" ]; then
344 mptcp_lib_fail_if_expected_feature
"${counter} counter"
351 mptcp_lib_make_file
() {
356 dd if=/dev
/urandom of
="${name}" bs="${bs}" count="${size}" 2> /dev
/null
357 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}"
361 mptcp_lib_print_file_err
() {
363 echo "Trailing bytes are: "
367 # $1: input file ; $2: output file ; $3: what kind of file
368 mptcp_lib_check_transfer
() {
373 if ! cmp "$in" "$out" > /dev
/null
2>&1; then
374 mptcp_lib_pr_fail
"$what does not match (in, out):"
375 mptcp_lib_print_file_err
"$in"
376 mptcp_lib_print_file_err
"$out"
385 mptcp_lib_wait_local_port_listen
() {
386 wait_local_port_listen
"${@}" "tcp"
389 mptcp_lib_check_output
() {
392 local expected
="${3}"
396 if ! out
=$
(${cmd} 2>"${err}"); then
400 if [ ${cmd_ret} -ne 0 ]; then
401 mptcp_lib_pr_fail
"command execution '${cmd}' stderr"
404 elif [ "${out}" = "${expected}" ]; then
407 mptcp_lib_pr_fail
"expected '${expected}' got '${out}'"
412 mptcp_lib_check_tools
() {
415 for tool
in "${@}"; do
418 if ! ip
-Version &> /dev
/null
; then
419 mptcp_lib_pr_skip
"Could not run test without ip tool"
424 if ! tc
-help &> /dev
/null
; then
425 mptcp_lib_pr_skip
"Could not run test without tc tool"
430 if ! ss
-h |
grep -q MPTCP
; then
431 mptcp_lib_pr_skip
"ss tool does not support MPTCP"
435 "iptables"* |
"ip6tables"*)
436 if ! "${tool}" -V &> /dev
/null
; then
437 mptcp_lib_pr_skip
"Could not run all tests without ${tool}"
442 mptcp_lib_pr_fail
"Internal error: unsupported tool: ${tool}"
449 mptcp_lib_ns_init
() {
450 if ! setup_ns
"${@}"; then
451 mptcp_lib_pr_fail
"Failed to setup namespaces ${*}"
456 for netns
in "${@}"; do
457 ip netns
exec "${!netns}" sysctl
-q net.mptcp.enabled
=1
458 ip netns
exec "${!netns}" sysctl
-q net.ipv4.conf.all.rp_filter
=0
459 ip netns
exec "${!netns}" sysctl
-q net.ipv4.conf.default.rp_filter
=0
463 mptcp_lib_ns_exit
() {
467 for netns
in "${@}"; do
468 rm -f /tmp
/"${netns}".
{nstat
,out
}
475 declare -n pid
="${3}"
479 mptcp_lib_kill_wait
"${pid:-0}"
480 ip netns
exec "${ns}" .
/pm_nl_ctl events
>> "${evts}" 2>&1 &
484 mptcp_lib_print_title
() {
485 : "${MPTCP_LIB_TEST_COUNTER:?}"
486 : "${MPTCP_LIB_TEST_FORMAT:?}"
488 # shellcheck disable=SC2059 # the format is in a variable
489 printf "${MPTCP_LIB_TEST_FORMAT}" "$((++MPTCP_LIB_TEST_COUNTER))" "${*}"
492 # $1: var name ; $2: prev ret
493 mptcp_lib_check_expected_one
() {
496 local prev_ret
="${2}"
498 if [ "${!var}" = "${!exp}" ]; then
502 if [ "${prev_ret}" = "0" ]; then
506 mptcp_lib_print_err
"Expected value for '${var}': '${!exp}', got '${!var}'."
510 # $@: all var names to check
511 mptcp_lib_check_expected
() {
515 for var
in "${@}"; do
516 mptcp_lib_check_expected_one
"${var}" "${rc}" || rc
=1
522 # shellcheck disable=SC2034 # Some variables are used below but indirectly
523 mptcp_lib_verify_listener_events
() {
535 type=$
(mptcp_lib_evts_get_info
type "${evt}" "${e_type}")
536 family
=$
(mptcp_lib_evts_get_info family
"${evt}" "${e_type}")
537 if [ "${family}" ] && [ "${family}" = "${AF_INET6}" ]; then
538 saddr
=$
(mptcp_lib_evts_get_info saddr6
"${evt}" "${e_type}")
540 saddr
=$
(mptcp_lib_evts_get_info saddr4
"${evt}" "${e_type}")
542 sport
=$
(mptcp_lib_evts_get_info sport
"${evt}" "${e_type}")
544 mptcp_lib_check_expected
"type" "family" "saddr" "sport" || rc
="${?}"
548 mptcp_lib_set_ip_mptcp
() {
552 mptcp_lib_is_ip_mptcp
() {
553 [ "${MPTCP_LIB_IP_MPTCP}" = "1" ]
556 # format: <id>,<ip>,<flags>,<dev>
557 mptcp_lib_pm_nl_format_endpoints
() {
558 local entry id ip flags dev port
560 for entry
in "${@}"; do
561 IFS
=, read -r id ip flags dev port
<<< "${entry}"
562 if mptcp_lib_is_ip_mptcp
; then
564 [ -n "${port}" ] && echo -n " port ${port}"
566 [ -n "${flags}" ] && echo -n " ${flags}"
567 [ -n "${dev}" ] && echo -n " dev ${dev}"
568 echo " " # always a space at the end
571 echo -n " flags ${flags//" "/","}"
572 [ -n "${dev}" ] && echo -n " dev ${dev}"
574 [ -n "${port}" ] && echo -n " ${port}"
580 mptcp_lib_pm_nl_get_endpoint
() {
584 if mptcp_lib_is_ip_mptcp
; then
585 ip
-n "${ns}" mptcp endpoint show id
"${id}"
587 ip netns
exec "${ns}" .
/pm_nl_ctl get
"${id}"
591 mptcp_lib_pm_nl_set_limits
() {
596 if mptcp_lib_is_ip_mptcp
; then
597 ip
-n "${ns}" mptcp limits set add_addr_accepted "${addrs}" subflows "${subflows}"
599 ip netns
exec "${ns}" ./pm_nl_ctl limits "${addrs}" "${subflows}"
603 mptcp_lib_pm_nl_add_endpoint
() {
606 local flags dev id port
612 "flags" |
"dev" |
"id" |
"port")
613 eval "${p}"=\$
"${nr}"
620 if mptcp_lib_is_ip_mptcp
; then
621 # shellcheck disable=SC2086 # blanks in flags, no double quote
622 ip
-n "${ns}" mptcp endpoint add "${addr}" ${flags//","/" "} \
623 ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
625 ip netns exec "${ns}" ./pm_nl_ctl add "${addr}" ${flags:+flags "${flags}"} \
626 ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
630 mptcp_lib_pm_nl_del_endpoint
() {
635 if mptcp_lib_is_ip_mptcp
; then
636 [ "${id}" -ne 0 ] && addr
=''
637 ip
-n "${ns}" mptcp endpoint delete id "${id}" ${addr:+"${addr}"}
639 ip netns exec "${ns}" ./pm_nl_ctl del "${id}" "${addr}"
643 mptcp_lib_pm_nl_flush_endpoint() {
646 if mptcp_lib_is_ip_mptcp; then
647 ip -n "${ns}" mptcp endpoint flush
649 ip netns exec "${ns}" ./pm_nl_ctl flush
653 mptcp_lib_pm_nl_show_endpoints() {
656 if mptcp_lib_is_ip_mptcp; then
657 ip -n "${ns}" mptcp endpoint show
659 ip netns exec "${ns}" ./pm_nl_ctl dump
663 mptcp_lib_pm_nl_change_endpoint() {
668 if mptcp_lib_is_ip_mptcp; then
669 # shellcheck disable=SC2086 # blanks in flags, no double quote
670 ip -n "${ns}" mptcp endpoint change id "${id}" ${flags//","/" "}
672 ip netns
exec "${ns}" ./pm_nl_ctl set id "${id}" flags "${flags}"