162306a36Sopenharmony_ci#! /bin/bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_cireadonly KSFT_PASS=0
562306a36Sopenharmony_cireadonly KSFT_FAIL=1
662306a36Sopenharmony_cireadonly KSFT_SKIP=4
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci# shellcheck disable=SC2155 # declare and assign separately
962306a36Sopenharmony_cireadonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciMPTCP_LIB_SUBTESTS=()
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci# only if supported (or forced) and not disabled, see no-color.org
1462306a36Sopenharmony_ciif { [ -t 1 ] || [ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } &&
1562306a36Sopenharmony_ci   [ "${NO_COLOR:-}" != "1" ]; then
1662306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_RED="\E[1;31m"
1762306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_GREEN="\E[1;32m"
1862306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_YELLOW="\E[1;33m"
1962306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_BLUE="\E[1;34m"
2062306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_RESET="\E[0m"
2162306a36Sopenharmony_cielse
2262306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_RED=
2362306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_GREEN=
2462306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_YELLOW=
2562306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_BLUE=
2662306a36Sopenharmony_ci	readonly MPTCP_LIB_COLOR_RESET=
2762306a36Sopenharmony_cifi
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci# $1: color, $2: text
3062306a36Sopenharmony_cimptcp_lib_print_color() {
3162306a36Sopenharmony_ci	echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}"
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cimptcp_lib_print_ok() {
3562306a36Sopenharmony_ci	mptcp_lib_print_color "${MPTCP_LIB_COLOR_GREEN}${*}"
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cimptcp_lib_print_warn() {
3962306a36Sopenharmony_ci	mptcp_lib_print_color "${MPTCP_LIB_COLOR_YELLOW}${*}"
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cimptcp_lib_print_info() {
4362306a36Sopenharmony_ci	mptcp_lib_print_color "${MPTCP_LIB_COLOR_BLUE}${*}"
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cimptcp_lib_print_err() {
4762306a36Sopenharmony_ci	mptcp_lib_print_color "${MPTCP_LIB_COLOR_RED}${*}"
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
5162306a36Sopenharmony_ci# features using the last version of the kernel and the selftests to make sure
5262306a36Sopenharmony_ci# a test is not being skipped by mistake.
5362306a36Sopenharmony_cimptcp_lib_expect_all_features() {
5462306a36Sopenharmony_ci	[ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci# $1: msg
5862306a36Sopenharmony_cimptcp_lib_fail_if_expected_feature() {
5962306a36Sopenharmony_ci	if mptcp_lib_expect_all_features; then
6062306a36Sopenharmony_ci		echo "ERROR: missing feature: ${*}"
6162306a36Sopenharmony_ci		exit ${KSFT_FAIL}
6262306a36Sopenharmony_ci	fi
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return 1
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci# $1: file
6862306a36Sopenharmony_cimptcp_lib_has_file() {
6962306a36Sopenharmony_ci	local f="${1}"
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if [ -f "${f}" ]; then
7262306a36Sopenharmony_ci		return 0
7362306a36Sopenharmony_ci	fi
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	mptcp_lib_fail_if_expected_feature "${f} file not found"
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cimptcp_lib_check_mptcp() {
7962306a36Sopenharmony_ci	if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then
8062306a36Sopenharmony_ci		echo "SKIP: MPTCP support is not available"
8162306a36Sopenharmony_ci		exit ${KSFT_SKIP}
8262306a36Sopenharmony_ci	fi
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cimptcp_lib_check_kallsyms() {
8662306a36Sopenharmony_ci	if ! mptcp_lib_has_file "/proc/kallsyms"; then
8762306a36Sopenharmony_ci		echo "SKIP: CONFIG_KALLSYMS is missing"
8862306a36Sopenharmony_ci		exit ${KSFT_SKIP}
8962306a36Sopenharmony_ci	fi
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci# Internal: use mptcp_lib_kallsyms_has() instead
9362306a36Sopenharmony_ci__mptcp_lib_kallsyms_has() {
9462306a36Sopenharmony_ci	local sym="${1}"
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	mptcp_lib_check_kallsyms
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	grep -q " ${sym}" /proc/kallsyms
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci# $1: part of a symbol to look at, add '$' at the end for full name
10262306a36Sopenharmony_cimptcp_lib_kallsyms_has() {
10362306a36Sopenharmony_ci	local sym="${1}"
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if __mptcp_lib_kallsyms_has "${sym}"; then
10662306a36Sopenharmony_ci		return 0
10762306a36Sopenharmony_ci	fi
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci# $1: part of a symbol to look at, add '$' at the end for full name
11362306a36Sopenharmony_cimptcp_lib_kallsyms_doesnt_have() {
11462306a36Sopenharmony_ci	local sym="${1}"
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if ! __mptcp_lib_kallsyms_has "${sym}"; then
11762306a36Sopenharmony_ci		return 0
11862306a36Sopenharmony_ci	fi
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci# !!!AVOID USING THIS!!!
12462306a36Sopenharmony_ci# Features might not land in the expected version and features can be backported
12562306a36Sopenharmony_ci#
12662306a36Sopenharmony_ci# $1: kernel version, e.g. 6.3
12762306a36Sopenharmony_cimptcp_lib_kversion_ge() {
12862306a36Sopenharmony_ci	local exp_maj="${1%.*}"
12962306a36Sopenharmony_ci	local exp_min="${1#*.}"
13062306a36Sopenharmony_ci	local v maj min
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	# If the kernel has backported features, set this env var to 1:
13362306a36Sopenharmony_ci	if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
13462306a36Sopenharmony_ci		return 0
13562306a36Sopenharmony_ci	fi
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	v=$(uname -r | cut -d'.' -f1,2)
13862306a36Sopenharmony_ci	maj=${v%.*}
13962306a36Sopenharmony_ci	min=${v#*.}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if   [ "${maj}" -gt "${exp_maj}" ] ||
14262306a36Sopenharmony_ci	   { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
14362306a36Sopenharmony_ci		return 0
14462306a36Sopenharmony_ci	fi
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci__mptcp_lib_result_add() {
15062306a36Sopenharmony_ci	local result="${1}"
15162306a36Sopenharmony_ci	shift
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*}")
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci# $1: test name
15962306a36Sopenharmony_cimptcp_lib_result_pass() {
16062306a36Sopenharmony_ci	__mptcp_lib_result_add "ok" "${1}"
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci# $1: test name
16462306a36Sopenharmony_cimptcp_lib_result_fail() {
16562306a36Sopenharmony_ci	__mptcp_lib_result_add "not ok" "${1}"
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci# $1: test name
16962306a36Sopenharmony_cimptcp_lib_result_skip() {
17062306a36Sopenharmony_ci	__mptcp_lib_result_add "ok" "${1} # SKIP"
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci# $1: result code ; $2: test name
17462306a36Sopenharmony_cimptcp_lib_result_code() {
17562306a36Sopenharmony_ci	local ret="${1}"
17662306a36Sopenharmony_ci	local name="${2}"
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	case "${ret}" in
17962306a36Sopenharmony_ci		"${KSFT_PASS}")
18062306a36Sopenharmony_ci			mptcp_lib_result_pass "${name}"
18162306a36Sopenharmony_ci			;;
18262306a36Sopenharmony_ci		"${KSFT_FAIL}")
18362306a36Sopenharmony_ci			mptcp_lib_result_fail "${name}"
18462306a36Sopenharmony_ci			;;
18562306a36Sopenharmony_ci		"${KSFT_SKIP}")
18662306a36Sopenharmony_ci			mptcp_lib_result_skip "${name}"
18762306a36Sopenharmony_ci			;;
18862306a36Sopenharmony_ci		*)
18962306a36Sopenharmony_ci			echo "ERROR: wrong result code: ${ret}"
19062306a36Sopenharmony_ci			exit ${KSFT_FAIL}
19162306a36Sopenharmony_ci			;;
19262306a36Sopenharmony_ci	esac
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cimptcp_lib_result_print_all_tap() {
19662306a36Sopenharmony_ci	local subtest
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] ||
19962306a36Sopenharmony_ci	   [ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then
20062306a36Sopenharmony_ci		return
20162306a36Sopenharmony_ci	fi
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	printf "\nTAP version 13\n"
20462306a36Sopenharmony_ci	printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}"
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do
20762306a36Sopenharmony_ci		printf "%s\n" "${subtest}"
20862306a36Sopenharmony_ci	done
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci# get the value of keyword $1 in the line marked by keyword $2
21262306a36Sopenharmony_cimptcp_lib_get_info_value() {
21362306a36Sopenharmony_ci	grep "${2}" | sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q'
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci# $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]]
21762306a36Sopenharmony_cimptcp_lib_evts_get_info() {
21862306a36Sopenharmony_ci	grep "${4:-}" "${2}" | mptcp_lib_get_info_value "${1}" "^type:${3:-1},"
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci# $1: PID
22262306a36Sopenharmony_cimptcp_lib_kill_wait() {
22362306a36Sopenharmony_ci	[ "${1}" -eq 0 ] && return 0
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	kill -SIGUSR1 "${1}" > /dev/null 2>&1
22662306a36Sopenharmony_ci	kill "${1}" > /dev/null 2>&1
22762306a36Sopenharmony_ci	wait "${1}" 2>/dev/null
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci# $1: IP address
23162306a36Sopenharmony_cimptcp_lib_is_v6() {
23262306a36Sopenharmony_ci	[ -z "${1##*:*}" ]
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci# $1: ns, $2: MIB counter
23662306a36Sopenharmony_cimptcp_lib_get_counter() {
23762306a36Sopenharmony_ci	local ns="${1}"
23862306a36Sopenharmony_ci	local counter="${2}"
23962306a36Sopenharmony_ci	local count
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	count=$(ip netns exec "${ns}" nstat -asz "${counter}" |
24262306a36Sopenharmony_ci		awk 'NR==1 {next} {print $2}')
24362306a36Sopenharmony_ci	if [ -z "${count}" ]; then
24462306a36Sopenharmony_ci		mptcp_lib_fail_if_expected_feature "${counter} counter"
24562306a36Sopenharmony_ci		return 1
24662306a36Sopenharmony_ci	fi
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	echo "${count}"
24962306a36Sopenharmony_ci}
250