mirror of
https://github.com/torvalds/linux.git
synced 2026-04-19 07:13:56 -04:00
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>
761 lines
17 KiB
Bash
761 lines
17 KiB
Bash
#! /bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
. "$(dirname "${0}")/../lib.sh"
|
|
|
|
readonly KSFT_PASS=0
|
|
readonly KSFT_FAIL=1
|
|
readonly KSFT_SKIP=4
|
|
|
|
# shellcheck disable=SC2155 # declare and assign separately
|
|
readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}"
|
|
|
|
# These variables are used in some selftests, read-only
|
|
declare -rx MPTCP_LIB_EVENT_CREATED=1 # MPTCP_EVENT_CREATED
|
|
declare -rx MPTCP_LIB_EVENT_ESTABLISHED=2 # MPTCP_EVENT_ESTABLISHED
|
|
declare -rx MPTCP_LIB_EVENT_CLOSED=3 # MPTCP_EVENT_CLOSED
|
|
declare -rx MPTCP_LIB_EVENT_ANNOUNCED=6 # MPTCP_EVENT_ANNOUNCED
|
|
declare -rx MPTCP_LIB_EVENT_REMOVED=7 # MPTCP_EVENT_REMOVED
|
|
declare -rx MPTCP_LIB_EVENT_SUB_ESTABLISHED=10 # MPTCP_EVENT_SUB_ESTABLISHED
|
|
declare -rx MPTCP_LIB_EVENT_SUB_CLOSED=11 # MPTCP_EVENT_SUB_CLOSED
|
|
declare -rx MPTCP_LIB_EVENT_SUB_PRIORITY=13 # MPTCP_EVENT_SUB_PRIORITY
|
|
declare -rx MPTCP_LIB_EVENT_LISTENER_CREATED=15 # MPTCP_EVENT_LISTENER_CREATED
|
|
declare -rx MPTCP_LIB_EVENT_LISTENER_CLOSED=16 # MPTCP_EVENT_LISTENER_CLOSED
|
|
|
|
declare -rx MPTCP_LIB_AF_INET=2
|
|
declare -rx MPTCP_LIB_AF_INET6=10
|
|
|
|
MPTCP_LIB_SUBTESTS=()
|
|
MPTCP_LIB_SUBTESTS_DUPLICATED=0
|
|
MPTCP_LIB_SUBTEST_FLAKY=0
|
|
MPTCP_LIB_SUBTESTS_LAST_TS_MS=
|
|
MPTCP_LIB_TEST_COUNTER=0
|
|
MPTCP_LIB_TEST_FORMAT="%02u %-50s"
|
|
MPTCP_LIB_IP_MPTCP=0
|
|
|
|
# only if supported (or forced) and not disabled, see no-color.org
|
|
if { [ -t 1 ] || [ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } &&
|
|
[ "${NO_COLOR:-}" != "1" ]; then
|
|
readonly MPTCP_LIB_COLOR_RED="\E[1;31m"
|
|
readonly MPTCP_LIB_COLOR_GREEN="\E[1;32m"
|
|
readonly MPTCP_LIB_COLOR_YELLOW="\E[1;33m"
|
|
readonly MPTCP_LIB_COLOR_BLUE="\E[1;34m"
|
|
readonly MPTCP_LIB_COLOR_RESET="\E[0m"
|
|
else
|
|
readonly MPTCP_LIB_COLOR_RED=
|
|
readonly MPTCP_LIB_COLOR_GREEN=
|
|
readonly MPTCP_LIB_COLOR_YELLOW=
|
|
readonly MPTCP_LIB_COLOR_BLUE=
|
|
readonly MPTCP_LIB_COLOR_RESET=
|
|
fi
|
|
|
|
# SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY env var can be set not to ignore errors
|
|
# from subtests marked as flaky
|
|
mptcp_lib_override_flaky() {
|
|
[ "${SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:-}" = 1 ]
|
|
}
|
|
|
|
mptcp_lib_subtest_is_flaky() {
|
|
[ "${MPTCP_LIB_SUBTEST_FLAKY}" = 1 ] && ! mptcp_lib_override_flaky
|
|
}
|
|
|
|
# $1: color, $2: text
|
|
mptcp_lib_print_color() {
|
|
echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}"
|
|
}
|
|
|
|
mptcp_lib_print_ok() {
|
|
mptcp_lib_print_color "${MPTCP_LIB_COLOR_GREEN}${*}"
|
|
}
|
|
|
|
mptcp_lib_print_warn() {
|
|
mptcp_lib_print_color "${MPTCP_LIB_COLOR_YELLOW}${*}"
|
|
}
|
|
|
|
mptcp_lib_print_info() {
|
|
mptcp_lib_print_color "${MPTCP_LIB_COLOR_BLUE}${*}"
|
|
}
|
|
|
|
mptcp_lib_print_err() {
|
|
mptcp_lib_print_color "${MPTCP_LIB_COLOR_RED}${*}"
|
|
}
|
|
|
|
# shellcheck disable=SC2120 # parameters are optional
|
|
mptcp_lib_pr_ok() {
|
|
mptcp_lib_print_ok "[ OK ]${1:+ ${*}}"
|
|
}
|
|
|
|
mptcp_lib_pr_skip() {
|
|
mptcp_lib_print_warn "[SKIP]${1:+ ${*}}"
|
|
}
|
|
|
|
mptcp_lib_pr_fail() {
|
|
local title cmt
|
|
|
|
if mptcp_lib_subtest_is_flaky; then
|
|
title="IGNO"
|
|
cmt=" (flaky)"
|
|
else
|
|
title="FAIL"
|
|
fi
|
|
|
|
mptcp_lib_print_err "[${title}]${cmt}${1:+ ${*}}"
|
|
}
|
|
|
|
mptcp_lib_pr_info() {
|
|
mptcp_lib_print_info "INFO: ${*}"
|
|
}
|
|
|
|
mptcp_lib_pr_nstat() {
|
|
local ns="${1}"
|
|
local hist="/tmp/${ns}.out"
|
|
|
|
if [ -f "${hist}" ]; then
|
|
awk '$2 != 0 { print " "$0 }' "${hist}"
|
|
else
|
|
ip netns exec "${ns}" nstat -as | grep Tcp
|
|
fi
|
|
}
|
|
|
|
# $1-2: listener/connector ns ; $3 port
|
|
mptcp_lib_pr_err_stats() {
|
|
local lns="${1}"
|
|
local cns="${2}"
|
|
local port="${3}"
|
|
|
|
echo -en "${MPTCP_LIB_COLOR_RED}"
|
|
{
|
|
printf "\nnetns %s (listener) socket stat for %d:\n" "${lns}" "${port}"
|
|
ip netns exec "${lns}" ss -Menitam -o "sport = :${port}"
|
|
mptcp_lib_pr_nstat "${lns}"
|
|
|
|
printf "\nnetns %s (connector) socket stat for %d:\n" "${cns}" "${port}"
|
|
ip netns exec "${cns}" ss -Menitam -o "dport = :${port}"
|
|
[ "${lns}" != "${cns}" ] && mptcp_lib_pr_nstat "${cns}"
|
|
} 1>&2
|
|
echo -en "${MPTCP_LIB_COLOR_RESET}"
|
|
}
|
|
|
|
# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
|
|
# features using the last version of the kernel and the selftests to make sure
|
|
# a test is not being skipped by mistake.
|
|
mptcp_lib_expect_all_features() {
|
|
[ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
|
|
}
|
|
|
|
# $1: msg
|
|
mptcp_lib_fail_if_expected_feature() {
|
|
if mptcp_lib_expect_all_features; then
|
|
echo "ERROR: missing feature: ${*}"
|
|
exit ${KSFT_FAIL}
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# $1: file
|
|
mptcp_lib_has_file() {
|
|
local f="${1}"
|
|
|
|
if [ -f "${f}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
mptcp_lib_fail_if_expected_feature "${f} file not found"
|
|
}
|
|
|
|
mptcp_lib_check_mptcp() {
|
|
if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then
|
|
mptcp_lib_pr_skip "MPTCP support is not available"
|
|
exit ${KSFT_SKIP}
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_check_kallsyms() {
|
|
if ! mptcp_lib_has_file "/proc/kallsyms"; then
|
|
mptcp_lib_pr_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"
|
|
}
|
|
|
|
# !!!AVOID USING THIS!!!
|
|
# Features might not land in the expected version and features can be backported
|
|
#
|
|
# $1: kernel version, e.g. 6.3
|
|
mptcp_lib_kversion_ge() {
|
|
local exp_maj="${1%.*}"
|
|
local exp_min="${1#*.}"
|
|
local v maj min
|
|
|
|
# If the kernel has backported features, set this env var to 1:
|
|
if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
|
|
return 0
|
|
fi
|
|
|
|
v=$(uname -r | cut -d'.' -f1,2)
|
|
maj=${v%.*}
|
|
min=${v#*.}
|
|
|
|
if [ "${maj}" -gt "${exp_maj}" ] ||
|
|
{ [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
|
|
return 0
|
|
fi
|
|
|
|
mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
|
|
}
|
|
|
|
mptcp_lib_subtests_last_ts_reset() {
|
|
MPTCP_LIB_SUBTESTS_LAST_TS_MS="$(date +%s%3N)"
|
|
}
|
|
mptcp_lib_subtests_last_ts_reset
|
|
|
|
__mptcp_lib_result_check_duplicated() {
|
|
local subtest
|
|
|
|
for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do
|
|
if [[ "${subtest}" == *" - ${KSFT_TEST}: ${*%% #*}" ]]; then
|
|
MPTCP_LIB_SUBTESTS_DUPLICATED=1
|
|
mptcp_lib_print_err "Duplicated entry: ${*}"
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
__mptcp_lib_result_add() {
|
|
local result="${1}"
|
|
local time="time="
|
|
local ts_prev_ms
|
|
shift
|
|
|
|
local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))
|
|
|
|
__mptcp_lib_result_check_duplicated "${*}"
|
|
|
|
# not to add two '#'
|
|
[[ "${*}" != *"#"* ]] && time="# ${time}"
|
|
|
|
ts_prev_ms="${MPTCP_LIB_SUBTESTS_LAST_TS_MS}"
|
|
mptcp_lib_subtests_last_ts_reset
|
|
time+="$((MPTCP_LIB_SUBTESTS_LAST_TS_MS - ts_prev_ms))ms"
|
|
|
|
MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*} ${time}")
|
|
}
|
|
|
|
# $1: test name
|
|
mptcp_lib_result_pass() {
|
|
__mptcp_lib_result_add "ok" "${1}"
|
|
}
|
|
|
|
# $1: test name
|
|
mptcp_lib_result_fail() {
|
|
if mptcp_lib_subtest_is_flaky; then
|
|
# It might sound better to use 'not ok # TODO' or 'ok # SKIP',
|
|
# but some CIs don't understand 'TODO' and treat SKIP as errors.
|
|
__mptcp_lib_result_add "ok" "${1} # IGNORE Flaky"
|
|
else
|
|
__mptcp_lib_result_add "not ok" "${1}"
|
|
fi
|
|
}
|
|
|
|
# $1: test name
|
|
mptcp_lib_result_skip() {
|
|
__mptcp_lib_result_add "ok" "${1} # SKIP"
|
|
}
|
|
|
|
# $1: result code ; $2: test name
|
|
mptcp_lib_result_code() {
|
|
local ret="${1}"
|
|
local name="${2}"
|
|
|
|
case "${ret}" in
|
|
"${KSFT_PASS}")
|
|
mptcp_lib_result_pass "${name}"
|
|
;;
|
|
"${KSFT_FAIL}")
|
|
mptcp_lib_result_fail "${name}"
|
|
;;
|
|
"${KSFT_SKIP}")
|
|
mptcp_lib_result_skip "${name}"
|
|
;;
|
|
*)
|
|
echo "ERROR: wrong result code: ${ret}"
|
|
exit ${KSFT_FAIL}
|
|
;;
|
|
esac
|
|
}
|
|
|
|
mptcp_lib_result_print_all_tap() {
|
|
local subtest
|
|
|
|
if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] ||
|
|
[ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then
|
|
return
|
|
fi
|
|
|
|
printf "\nTAP version 13\n"
|
|
printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}"
|
|
|
|
for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do
|
|
printf "%s\n" "${subtest}"
|
|
done
|
|
|
|
if [ "${MPTCP_LIB_SUBTESTS_DUPLICATED}" = 1 ] &&
|
|
mptcp_lib_expect_all_features; then
|
|
mptcp_lib_print_err "Duplicated test entries"
|
|
exit ${KSFT_FAIL}
|
|
fi
|
|
}
|
|
|
|
# get the value of keyword $1 in the line marked by keyword $2
|
|
mptcp_lib_get_info_value() {
|
|
grep "${2}" 2>/dev/null |
|
|
sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q'
|
|
# the ';q' at the end limits to the first matched entry.
|
|
}
|
|
|
|
# $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]]
|
|
mptcp_lib_evts_get_info() {
|
|
grep "${4:-}" "${2}" 2>/dev/null |
|
|
mptcp_lib_get_info_value "${1}" "^type:${3:-1},"
|
|
}
|
|
|
|
mptcp_lib_wait_timeout() {
|
|
local timeout_test="${1}"
|
|
local listener_ns="${2}"
|
|
local connector_ns="${3}"
|
|
local port="${4}"
|
|
shift 4 # rest are PIDs
|
|
|
|
sleep "${timeout_test}"
|
|
mptcp_lib_print_err "timeout"
|
|
mptcp_lib_pr_err_stats "${listener_ns}" "${connector_ns}" "${port}"
|
|
kill "${@}" 2>/dev/null
|
|
}
|
|
|
|
# $1: PID
|
|
mptcp_lib_kill_wait() {
|
|
[ "${1}" -eq 0 ] && return 0
|
|
|
|
kill -SIGUSR1 "${1}" > /dev/null 2>&1
|
|
kill "${1}" > /dev/null 2>&1
|
|
wait "${1}" 2>/dev/null
|
|
}
|
|
|
|
# $1: PID
|
|
mptcp_lib_pid_list_children() {
|
|
local curr="${1}"
|
|
# evoke 'ps' only once
|
|
local pids="${2:-"$(ps o pid,ppid)"}"
|
|
|
|
echo "${curr}"
|
|
|
|
local pid
|
|
for pid in $(echo "${pids}" | awk "\$2 == ${curr} { print \$1 }"); do
|
|
mptcp_lib_pid_list_children "${pid}" "${pids}"
|
|
done
|
|
}
|
|
|
|
# $1: PID
|
|
mptcp_lib_kill_group_wait() {
|
|
# Some users might not have procps-ng: cannot use "kill -- -PID"
|
|
mptcp_lib_pid_list_children "${1}" | xargs -r kill &>/dev/null
|
|
wait "${1}" 2>/dev/null
|
|
}
|
|
|
|
# $1: IP address
|
|
mptcp_lib_is_v6() {
|
|
[ -z "${1##*:*}" ]
|
|
}
|
|
|
|
mptcp_lib_nstat_init() {
|
|
local ns="${1}"
|
|
|
|
rm -f "/tmp/${ns}."{nstat,out}
|
|
NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat -n
|
|
}
|
|
|
|
mptcp_lib_nstat_get() {
|
|
local ns="${1}"
|
|
|
|
# filter out non-*TCP stats, and the rate (last column)
|
|
NSTAT_HISTORY="/tmp/${ns}.nstat" ip netns exec "${ns}" nstat -sz |
|
|
grep -o ".*Tcp\S\+\s\+[0-9]\+" > "/tmp/${ns}.out"
|
|
}
|
|
|
|
# $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() {
|
|
local ns="${1}"
|
|
local counter="${2}"
|
|
local hist="/tmp/${ns}.out"
|
|
local count
|
|
|
|
if [[ -s "${hist}" && "${counter}" == *"Tcp"* ]]; then
|
|
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
|
|
mptcp_lib_fail_if_expected_feature "${counter} counter"
|
|
return 1
|
|
fi
|
|
|
|
echo "${count}"
|
|
}
|
|
|
|
mptcp_lib_make_file() {
|
|
local name="${1}"
|
|
local bs="${2}"
|
|
local size="${3}"
|
|
|
|
dd if=/dev/urandom of="${name}" bs="${bs}" count="${size}" 2> /dev/null
|
|
echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}"
|
|
}
|
|
|
|
# $1: file
|
|
mptcp_lib_print_file_err() {
|
|
ls -l "${1}" 1>&2
|
|
echo "Trailing bytes are: "
|
|
tail -c 32 "${1}" | od -x | head -n2
|
|
}
|
|
|
|
# $1: input file ; $2: output file ; $3: what kind of file
|
|
mptcp_lib_check_transfer() {
|
|
local in="${1}"
|
|
local out="${2}"
|
|
local what="${3}"
|
|
|
|
if ! cmp "$in" "$out" > /dev/null 2>&1; then
|
|
mptcp_lib_pr_fail "$what does not match (in, out):"
|
|
mptcp_lib_print_file_err "$in"
|
|
mptcp_lib_print_file_err "$out"
|
|
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# $1: ns, $2: port
|
|
mptcp_lib_wait_local_port_listen() {
|
|
wait_local_port_listen "${@}" "tcp"
|
|
}
|
|
|
|
mptcp_lib_check_output() {
|
|
local err="${1}"
|
|
local cmd="${2}"
|
|
local expected="${3}"
|
|
local cmd_ret=0
|
|
local out
|
|
|
|
if ! out=$(${cmd} 2>"${err}"); then
|
|
cmd_ret=${?}
|
|
fi
|
|
|
|
if [ ${cmd_ret} -ne 0 ]; then
|
|
mptcp_lib_pr_fail "command execution '${cmd}' stderr"
|
|
cat "${err}"
|
|
return 2
|
|
elif [ "${out}" = "${expected}" ]; then
|
|
return 0
|
|
else
|
|
mptcp_lib_pr_fail "expected '${expected}' got '${out}'"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_check_tools() {
|
|
local tool
|
|
|
|
for tool in "${@}"; do
|
|
case "${tool}" in
|
|
"ip")
|
|
if ! ip -Version &> /dev/null; then
|
|
mptcp_lib_pr_skip "Could not run test without ip tool"
|
|
exit ${KSFT_SKIP}
|
|
fi
|
|
;;
|
|
"tc")
|
|
if ! tc -help &> /dev/null; then
|
|
mptcp_lib_pr_skip "Could not run test without tc tool"
|
|
exit ${KSFT_SKIP}
|
|
fi
|
|
;;
|
|
"ss")
|
|
if ! ss -h | grep -q MPTCP; then
|
|
mptcp_lib_pr_skip "ss tool does not support MPTCP"
|
|
exit ${KSFT_SKIP}
|
|
fi
|
|
;;
|
|
"iptables"* | "ip6tables"*)
|
|
if ! "${tool}" -V &> /dev/null; then
|
|
mptcp_lib_pr_skip "Could not run all tests without ${tool}"
|
|
exit ${KSFT_SKIP}
|
|
fi
|
|
;;
|
|
*)
|
|
mptcp_lib_pr_fail "Internal error: unsupported tool: ${tool}"
|
|
exit ${KSFT_FAIL}
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
mptcp_lib_ns_init() {
|
|
if ! setup_ns "${@}"; then
|
|
mptcp_lib_pr_fail "Failed to setup namespaces ${*}"
|
|
exit ${KSFT_FAIL}
|
|
fi
|
|
|
|
local netns
|
|
for netns in "${@}"; do
|
|
ip netns exec "${!netns}" sysctl -q net.mptcp.enabled=1
|
|
done
|
|
}
|
|
|
|
mptcp_lib_ns_exit() {
|
|
cleanup_ns "${@}"
|
|
|
|
local netns
|
|
for netns in "${@}"; do
|
|
rm -f /tmp/"${netns}".{nstat,out}
|
|
done
|
|
}
|
|
|
|
mptcp_lib_events() {
|
|
local ns="${1}"
|
|
local evts="${2}"
|
|
declare -n pid="${3}"
|
|
|
|
:>"${evts}"
|
|
|
|
mptcp_lib_kill_wait "${pid:-0}"
|
|
ip netns exec "${ns}" ./pm_nl_ctl events >> "${evts}" 2>&1 &
|
|
pid=$!
|
|
}
|
|
|
|
mptcp_lib_print_title() {
|
|
: "${MPTCP_LIB_TEST_COUNTER:?}"
|
|
: "${MPTCP_LIB_TEST_FORMAT:?}"
|
|
|
|
# shellcheck disable=SC2059 # the format is in a variable
|
|
printf "${MPTCP_LIB_TEST_FORMAT}" "$((++MPTCP_LIB_TEST_COUNTER))" "${*}"
|
|
}
|
|
|
|
# $1: var name ; $2: prev ret
|
|
mptcp_lib_check_expected_one() {
|
|
local var="${1}"
|
|
local exp="e_${var}"
|
|
local prev_ret="${2}"
|
|
|
|
if [ "${!var}" = "${!exp}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ "${prev_ret}" = "0" ]; then
|
|
mptcp_lib_pr_fail
|
|
fi
|
|
|
|
mptcp_lib_print_err "Expected value for '${var}': '${!exp}', got '${!var}'."
|
|
return 1
|
|
}
|
|
|
|
# $@: all var names to check
|
|
mptcp_lib_check_expected() {
|
|
local rc=0
|
|
local var
|
|
|
|
for var in "${@}"; do
|
|
mptcp_lib_check_expected_one "${var}" "${rc}" || rc=1
|
|
done
|
|
|
|
return "${rc}"
|
|
}
|
|
|
|
# shellcheck disable=SC2034 # Some variables are used below but indirectly
|
|
mptcp_lib_verify_listener_events() {
|
|
local evt=${1}
|
|
local e_type=${2}
|
|
local e_family=${3}
|
|
local e_saddr=${4}
|
|
local e_sport=${5}
|
|
local type
|
|
local family
|
|
local saddr
|
|
local sport
|
|
local rc=0
|
|
|
|
type=$(mptcp_lib_evts_get_info type "${evt}" "${e_type}")
|
|
family=$(mptcp_lib_evts_get_info family "${evt}" "${e_type}")
|
|
if [ "${family}" ] && [ "${family}" = "${AF_INET6}" ]; then
|
|
saddr=$(mptcp_lib_evts_get_info saddr6 "${evt}" "${e_type}")
|
|
else
|
|
saddr=$(mptcp_lib_evts_get_info saddr4 "${evt}" "${e_type}")
|
|
fi
|
|
sport=$(mptcp_lib_evts_get_info sport "${evt}" "${e_type}")
|
|
|
|
mptcp_lib_check_expected "type" "family" "saddr" "sport" || rc="${?}"
|
|
return "${rc}"
|
|
}
|
|
|
|
mptcp_lib_set_ip_mptcp() {
|
|
MPTCP_LIB_IP_MPTCP=1
|
|
}
|
|
|
|
mptcp_lib_is_ip_mptcp() {
|
|
[ "${MPTCP_LIB_IP_MPTCP}" = "1" ]
|
|
}
|
|
|
|
# format: <id>,<ip>,<flags>,<dev>
|
|
mptcp_lib_pm_nl_format_endpoints() {
|
|
local entry id ip flags dev port
|
|
|
|
for entry in "${@}"; do
|
|
IFS=, read -r id ip flags dev port <<< "${entry}"
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
echo -n "${ip}"
|
|
[ -n "${port}" ] && echo -n " port ${port}"
|
|
echo -n " id ${id}"
|
|
[ -n "${flags}" ] && echo -n " ${flags}"
|
|
[ -n "${dev}" ] && echo -n " dev ${dev}"
|
|
echo " " # always a space at the end
|
|
else
|
|
echo -n "id ${id}"
|
|
echo -n " flags ${flags//" "/","}"
|
|
[ -n "${dev}" ] && echo -n " dev ${dev}"
|
|
echo -n " ${ip}"
|
|
[ -n "${port}" ] && echo -n " ${port}"
|
|
echo ""
|
|
fi
|
|
done
|
|
}
|
|
|
|
mptcp_lib_pm_nl_get_endpoint() {
|
|
local ns=${1}
|
|
local id=${2}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
ip -n "${ns}" mptcp endpoint show id "${id}"
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl get "${id}"
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_set_limits() {
|
|
local ns=${1}
|
|
local addrs=${2}
|
|
local subflows=${3}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
ip -n "${ns}" mptcp limits set add_addr_accepted "${addrs}" subflows "${subflows}"
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl limits "${addrs}" "${subflows}"
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_add_endpoint() {
|
|
local ns=${1}
|
|
local addr=${2}
|
|
local flags dev id port
|
|
local nr=2
|
|
|
|
local p
|
|
for p in "${@}"; do
|
|
case "${p}" in
|
|
"flags" | "dev" | "id" | "port")
|
|
eval "${p}"=\$"${nr}"
|
|
;;
|
|
esac
|
|
|
|
nr=$((nr + 1))
|
|
done
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
# shellcheck disable=SC2086 # blanks in flags, no double quote
|
|
ip -n "${ns}" mptcp endpoint add "${addr}" ${flags//","/" "} \
|
|
${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl add "${addr}" ${flags:+flags "${flags}"} \
|
|
${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"}
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_del_endpoint() {
|
|
local ns=${1}
|
|
local id=${2}
|
|
local addr=${3}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
[ "${id}" -ne 0 ] && addr=''
|
|
ip -n "${ns}" mptcp endpoint delete id "${id}" ${addr:+"${addr}"}
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl del "${id}" "${addr}"
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_flush_endpoint() {
|
|
local ns=${1}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
ip -n "${ns}" mptcp endpoint flush
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl flush
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_show_endpoints() {
|
|
local ns=${1}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
ip -n "${ns}" mptcp endpoint show
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl dump
|
|
fi
|
|
}
|
|
|
|
mptcp_lib_pm_nl_change_endpoint() {
|
|
local ns=${1}
|
|
local id=${2}
|
|
local flags=${3}
|
|
|
|
if mptcp_lib_is_ip_mptcp; then
|
|
# shellcheck disable=SC2086 # blanks in flags, no double quote
|
|
ip -n "${ns}" mptcp endpoint change id "${id}" ${flags//","/" "}
|
|
else
|
|
ip netns exec "${ns}" ./pm_nl_ctl set id "${id}" flags "${flags}"
|
|
fi
|
|
}
|