xref: /linux/tools/testing/selftests/net/lib.sh (revision f72aa1b276281b4e4f75261af8425bc99d903f3e)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4net_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
5source "$net_dir/lib/sh/defer.sh"
6
7##############################################################################
8# Defines
9
10: "${WAIT_TIMEOUT:=20}"
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##############################################################################
24# Helpers
25
26__ksft_status_merge()
27{
28	local a=$1; shift
29	local b=$1; shift
30	local -A weights
31	local weight=0
32
33	local i
34	for i in "$@"; do
35		weights[$i]=$((weight++))
36	done
37
38	if [[ ${weights[$a]} > ${weights[$b]} ]]; then
39		echo "$a"
40		return 0
41	else
42		echo "$b"
43		return 1
44	fi
45}
46
47ksft_status_merge()
48{
49	local a=$1; shift
50	local b=$1; shift
51
52	__ksft_status_merge "$a" "$b" \
53		$ksft_pass $ksft_xfail $ksft_skip $ksft_fail
54}
55
56ksft_exit_status_merge()
57{
58	local a=$1; shift
59	local b=$1; shift
60
61	__ksft_status_merge "$a" "$b" \
62		$ksft_xfail $ksft_pass $ksft_skip $ksft_fail
63}
64
65loopy_wait()
66{
67	local sleep_cmd=$1; shift
68	local timeout_ms=$1; shift
69
70	local start_time="$(date -u +%s%3N)"
71	while true
72	do
73		local out
74		if out=$("$@"); then
75			echo -n "$out"
76			return 0
77		fi
78
79		local current_time="$(date -u +%s%3N)"
80		if ((current_time - start_time > timeout_ms)); then
81			echo -n "$out"
82			return 1
83		fi
84
85		$sleep_cmd
86	done
87}
88
89busywait()
90{
91	local timeout_ms=$1; shift
92
93	loopy_wait : "$timeout_ms" "$@"
94}
95
96# timeout in seconds
97slowwait()
98{
99	local timeout_sec=$1; shift
100
101	loopy_wait "sleep 0.1" "$((timeout_sec * 1000))" "$@"
102}
103
104until_counter_is()
105{
106	local expr=$1; shift
107	local current=$("$@")
108
109	echo $((current))
110	((current $expr))
111}
112
113busywait_for_counter()
114{
115	local timeout=$1; shift
116	local delta=$1; shift
117
118	local base=$("$@")
119	busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
120}
121
122slowwait_for_counter()
123{
124	local timeout=$1; shift
125	local delta=$1; shift
126
127	local base=$("$@")
128	slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@"
129}
130
131# Check for existence of tools which are built as part of selftests
132# but may also already exist in $PATH
133check_gen_prog()
134{
135	local prog_name=$1; shift
136
137	if ! which $prog_name >/dev/null 2>/dev/null; then
138		PATH=$PWD:$PATH
139		if ! which $prog_name >/dev/null; then
140			echo "'$prog_name' command not found; skipping tests"
141			exit $ksft_skip
142		fi
143	fi
144}
145
146remove_ns_list()
147{
148	local item=$1
149	local ns
150	local ns_list=("${NS_LIST[@]}")
151	NS_LIST=()
152
153	for ns in "${ns_list[@]}"; do
154		if [ "${ns}" != "${item}" ]; then
155			NS_LIST+=("${ns}")
156		fi
157	done
158}
159
160cleanup_ns()
161{
162	local ns=""
163	local ret=0
164
165	for ns in "$@"; do
166		[ -z "${ns}" ] && continue
167		ip netns pids "${ns}" 2> /dev/null | xargs -r kill || true
168		ip netns delete "${ns}" &> /dev/null || true
169		if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
170			echo "Warn: Failed to remove namespace $ns"
171			ret=1
172		else
173			remove_ns_list "${ns}"
174		fi
175	done
176
177	return $ret
178}
179
180cleanup_all_ns()
181{
182	cleanup_ns "${NS_LIST[@]}"
183}
184
185# setup netns with given names as prefix. e.g
186# setup_ns local remote
187setup_ns()
188{
189	local ns_name=""
190	local ns_list=()
191	for ns_name in "$@"; do
192		# avoid conflicts with local var: internal error
193		if [ "${ns_name}" = "ns_name" ]; then
194			echo "Failed to setup namespace '${ns_name}': invalid name"
195			cleanup_ns "${ns_list[@]}"
196			exit $ksft_fail
197		fi
198
199		# Some test may setup/remove same netns multi times
200		if [ -z "${!ns_name}" ]; then
201			eval "${ns_name}=${ns_name,,}-$(mktemp -u XXXXXX)"
202		else
203			cleanup_ns "${!ns_name}"
204		fi
205
206		if ! ip netns add "${!ns_name}"; then
207			echo "Failed to create namespace $ns_name"
208			cleanup_ns "${ns_list[@]}"
209			return $ksft_skip
210		fi
211		ip -n "${!ns_name}" link set lo up
212		ns_list+=("${!ns_name}")
213	done
214	NS_LIST+=("${ns_list[@]}")
215}
216
217tc_rule_stats_get()
218{
219	local dev=$1; shift
220	local pref=$1; shift
221	local dir=${1:-ingress}; shift
222	local selector=${1:-.packets}; shift
223
224	tc -j -s filter show dev $dev $dir pref $pref \
225	    | jq ".[1].options.actions[].stats$selector"
226}
227
228tc_rule_handle_stats_get()
229{
230	local id=$1; shift
231	local handle=$1; shift
232	local selector=${1:-.packets}; shift
233	local netns=${1:-""}; shift
234
235	tc $netns -j -s filter show $id \
236	    | jq ".[] | select(.options.handle == $handle) | \
237		  .options.actions[0].stats$selector"
238}
239