1#! /bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4readonly KSFT_PASS=0
5readonly KSFT_FAIL=1
6readonly KSFT_SKIP=4
7readonly KSFT_TEST=$(basename "${0}" | sed 's/\.sh$//g')
8
9MPTCP_LIB_SUBTESTS=()
10
11# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
12# features using the last version of the kernel and the selftests to make sure
13# a test is not being skipped by mistake.
14mptcp_lib_expect_all_features() {
15	[ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
16}
17
18# $1: msg
19mptcp_lib_fail_if_expected_feature() {
20	if mptcp_lib_expect_all_features; then
21		echo "ERROR: missing feature: ${*}"
22		exit ${KSFT_FAIL}
23	fi
24
25	return 1
26}
27
28# $1: file
29mptcp_lib_has_file() {
30	local f="${1}"
31
32	if [ -f "${f}" ]; then
33		return 0
34	fi
35
36	mptcp_lib_fail_if_expected_feature "${f} file not found"
37}
38
39mptcp_lib_check_mptcp() {
40	if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then
41		echo "SKIP: MPTCP support is not available"
42		exit ${KSFT_SKIP}
43	fi
44}
45
46mptcp_lib_check_kallsyms() {
47	if ! mptcp_lib_has_file "/proc/kallsyms"; then
48		echo "SKIP: CONFIG_KALLSYMS is missing"
49		exit ${KSFT_SKIP}
50	fi
51}
52
53# Internal: use mptcp_lib_kallsyms_has() instead
54__mptcp_lib_kallsyms_has() {
55	local sym="${1}"
56
57	mptcp_lib_check_kallsyms
58
59	grep -q " ${sym}" /proc/kallsyms
60}
61
62# $1: part of a symbol to look at, add '$' at the end for full name
63mptcp_lib_kallsyms_has() {
64	local sym="${1}"
65
66	if __mptcp_lib_kallsyms_has "${sym}"; then
67		return 0
68	fi
69
70	mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
71}
72
73# $1: part of a symbol to look at, add '$' at the end for full name
74mptcp_lib_kallsyms_doesnt_have() {
75	local sym="${1}"
76
77	if ! __mptcp_lib_kallsyms_has "${sym}"; then
78		return 0
79	fi
80
81	mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
82}
83
84# !!!AVOID USING THIS!!!
85# Features might not land in the expected version and features can be backported
86#
87# $1: kernel version, e.g. 6.3
88mptcp_lib_kversion_ge() {
89	local exp_maj="${1%.*}"
90	local exp_min="${1#*.}"
91	local v maj min
92
93	# If the kernel has backported features, set this env var to 1:
94	if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
95		return 0
96	fi
97
98	v=$(uname -r | cut -d'.' -f1,2)
99	maj=${v%.*}
100	min=${v#*.}
101
102	if   [ "${maj}" -gt "${exp_maj}" ] ||
103	   { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
104		return 0
105	fi
106
107	mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
108}
109
110__mptcp_lib_result_add() {
111	local result="${1}"
112	shift
113
114	local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))
115
116	MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*}")
117}
118
119# $1: test name
120mptcp_lib_result_pass() {
121	__mptcp_lib_result_add "ok" "${1}"
122}
123
124# $1: test name
125mptcp_lib_result_fail() {
126	__mptcp_lib_result_add "not ok" "${1}"
127}
128
129# $1: test name
130mptcp_lib_result_skip() {
131	__mptcp_lib_result_add "ok" "${1} # SKIP"
132}
133
134# $1: result code ; $2: test name
135mptcp_lib_result_code() {
136	local ret="${1}"
137	local name="${2}"
138
139	case "${ret}" in
140		"${KSFT_PASS}")
141			mptcp_lib_result_pass "${name}"
142			;;
143		"${KSFT_FAIL}")
144			mptcp_lib_result_fail "${name}"
145			;;
146		"${KSFT_SKIP}")
147			mptcp_lib_result_skip "${name}"
148			;;
149		*)
150			echo "ERROR: wrong result code: ${ret}"
151			exit ${KSFT_FAIL}
152			;;
153	esac
154}
155
156mptcp_lib_result_print_all_tap() {
157	local subtest
158
159	if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] ||
160	   [ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then
161		return
162	fi
163
164	printf "\nTAP version 13\n"
165	printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}"
166
167	for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do
168		printf "%s\n" "${subtest}"
169	done
170}
171