• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Defines
6
7: "${WAIT_TIMEOUT:=20}"
8
9# Whether to pause on after a failure.
10: "${PAUSE_ON_FAIL:=no}"
11
12BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms
13
14# Kselftest framework constants.
15ksft_pass=0
16ksft_fail=1
17ksft_xfail=2
18ksft_skip=4
19
20# namespace list created by setup_ns
21NS_LIST=()
22
23# Exit status to return at the end. Set in case one of the tests fails.
24EXIT_STATUS=0
25# Per-test return value. Clear at the beginning of each test.
26RET=0
27
28##############################################################################
29# Helpers
30
31__ksft_status_merge()
32{
33	local a=$1; shift
34	local b=$1; shift
35	local -A weights
36	local weight=0
37
38	local i
39	for i in "$@"; do
40		weights[$i]=$((weight++))
41	done
42
43	if [[ ${weights[$a]} > ${weights[$b]} ]]; then
44		echo "$a"
45		return 0
46	else
47		echo "$b"
48		return 1
49	fi
50}
51
52ksft_status_merge()
53{
54	local a=$1; shift
55	local b=$1; shift
56
57	__ksft_status_merge "$a" "$b" \
58		$ksft_pass $ksft_xfail $ksft_skip $ksft_fail
59}
60
61ksft_exit_status_merge()
62{
63	local a=$1; shift
64	local b=$1; shift
65
66	__ksft_status_merge "$a" "$b" \
67		$ksft_xfail $ksft_pass $ksft_skip $ksft_fail
68}
69
70loopy_wait()
71{
72	local sleep_cmd=$1; shift
73	local timeout_ms=$1; shift
74
75	local start_time="$(date -u +%s%3N)"
76	while true
77	do
78		local out
79		if out=$("$@"); then
80			echo -n "$out"
81			return 0
82		fi
83
84		local current_time="$(date -u +%s%3N)"
85		if ((current_time - start_time > timeout_ms)); then
86			echo -n "$out"
87			return 1
88		fi
89
90		$sleep_cmd
91	done
92}
93
94busywait()
95{
96	local timeout_ms=$1; shift
97
98	loopy_wait : "$timeout_ms" "$@"
99}
100
101# timeout in seconds
102slowwait()
103{
104	local timeout_sec=$1; shift
105
106	loopy_wait "sleep 0.1" "$((timeout_sec * 1000))" "$@"
107}
108
109until_counter_is()
110{
111	local expr=$1; shift
112	local current=$("$@")
113
114	echo $((current))
115	((current $expr))
116}
117
118busywait_for_counter()
119{
120	local timeout=$1; shift
121	local delta=$1; shift
122
123	local base=$("$@")
124	busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
125}
126
127slowwait_for_counter()
128{
129	local timeout=$1; shift
130	local delta=$1; shift
131
132	local base=$("$@")
133	slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@"
134}
135
136# Check for existence of tools which are built as part of selftests
137# but may also already exist in $PATH
138check_gen_prog()
139{
140	local prog_name=$1; shift
141
142	if ! which $prog_name >/dev/null 2>/dev/null; then
143		PATH=$PWD:$PATH
144		if ! which $prog_name >/dev/null; then
145			echo "'$prog_name' command not found; skipping tests"
146			exit $ksft_skip
147		fi
148	fi
149}
150
151remove_ns_list()
152{
153	local item=$1
154	local ns
155	local ns_list=("${NS_LIST[@]}")
156	NS_LIST=()
157
158	for ns in "${ns_list[@]}"; do
159		if [ "${ns}" != "${item}" ]; then
160			NS_LIST+=("${ns}")
161		fi
162	done
163}
164
165cleanup_ns()
166{
167	local ns=""
168	local ret=0
169
170	for ns in "$@"; do
171		[ -z "${ns}" ] && continue
172		ip netns pids "${ns}" 2> /dev/null | xargs -r kill || true
173		ip netns delete "${ns}" &> /dev/null || true
174		if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
175			echo "Warn: Failed to remove namespace $ns"
176			ret=1
177		else
178			remove_ns_list "${ns}"
179		fi
180	done
181
182	return $ret
183}
184
185cleanup_all_ns()
186{
187	cleanup_ns "${NS_LIST[@]}"
188}
189
190# setup netns with given names as prefix. e.g
191# setup_ns local remote
192setup_ns()
193{
194	local ns_name=""
195	local ns_list=()
196	for ns_name in "$@"; do
197		# avoid conflicts with local var: internal error
198		if [ "${ns_name}" = "ns_name" ]; then
199			echo "Failed to setup namespace '${ns_name}': invalid name"
200			cleanup_ns "${ns_list[@]}"
201			exit $ksft_fail
202		fi
203
204		# Some test may setup/remove same netns multi times
205		if [ -z "${!ns_name}" ]; then
206			eval "${ns_name}=${ns_name,,}-$(mktemp -u XXXXXX)"
207		else
208			cleanup_ns "${!ns_name}"
209		fi
210
211		if ! ip netns add "${!ns_name}"; then
212			echo "Failed to create namespace $ns_name"
213			cleanup_ns "${ns_list[@]}"
214			return $ksft_skip
215		fi
216		ip -n "${!ns_name}" link set lo up
217		ns_list+=("${!ns_name}")
218	done
219	NS_LIST+=("${ns_list[@]}")
220}
221
222tc_rule_stats_get()
223{
224	local dev=$1; shift
225	local pref=$1; shift
226	local dir=${1:-ingress}; shift
227	local selector=${1:-.packets}; shift
228
229	tc -j -s filter show dev $dev $dir pref $pref \
230	    | jq ".[1].options.actions[].stats$selector"
231}
232
233tc_rule_handle_stats_get()
234{
235	local id=$1; shift
236	local handle=$1; shift
237	local selector=${1:-.packets}; shift
238	local netns=${1:-""}; shift
239
240	tc $netns -j -s filter show $id \
241	    | jq ".[] | select(.options.handle == $handle) | \
242		  .options.actions[0].stats$selector"
243}
244
245ret_set_ksft_status()
246{
247	local ksft_status=$1; shift
248	local msg=$1; shift
249
250	RET=$(ksft_status_merge $RET $ksft_status)
251	if (( $? )); then
252		retmsg=$msg
253	fi
254}
255
256log_test_result()
257{
258	local test_name=$1; shift
259	local opt_str=$1; shift
260	local result=$1; shift
261	local retmsg=$1
262
263	printf "TEST: %-60s  [%s]\n" "$test_name $opt_str" "$result"
264	if [[ $retmsg ]]; then
265		printf "\t%s\n" "$retmsg"
266	fi
267}
268
269pause_on_fail()
270{
271	if [[ $PAUSE_ON_FAIL == yes ]]; then
272		echo "Hit enter to continue, 'q' to quit"
273		read a
274		[[ $a == q ]] && exit 1
275	fi
276}
277
278handle_test_result_pass()
279{
280	local test_name=$1; shift
281	local opt_str=$1; shift
282
283	log_test_result "$test_name" "$opt_str" " OK "
284}
285
286handle_test_result_fail()
287{
288	local test_name=$1; shift
289	local opt_str=$1; shift
290
291	log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
292	pause_on_fail
293}
294
295handle_test_result_xfail()
296{
297	local test_name=$1; shift
298	local opt_str=$1; shift
299
300	log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
301	pause_on_fail
302}
303
304handle_test_result_skip()
305{
306	local test_name=$1; shift
307	local opt_str=$1; shift
308
309	log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
310}
311
312log_test()
313{
314	local test_name=$1
315	local opt_str=$2
316
317	if [[ $# -eq 2 ]]; then
318		opt_str="($opt_str)"
319	fi
320
321	if ((RET == ksft_pass)); then
322		handle_test_result_pass "$test_name" "$opt_str"
323	elif ((RET == ksft_xfail)); then
324		handle_test_result_xfail "$test_name" "$opt_str"
325	elif ((RET == ksft_skip)); then
326		handle_test_result_skip "$test_name" "$opt_str"
327	else
328		handle_test_result_fail "$test_name" "$opt_str"
329	fi
330
331	EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
332	return $RET
333}
334
335log_test_skip()
336{
337	RET=$ksft_skip retmsg= log_test "$@"
338}
339
340log_test_xfail()
341{
342	RET=$ksft_xfail retmsg= log_test "$@"
343}
344
345log_info()
346{
347	local msg=$1
348
349	echo "INFO: $msg"
350}
351