1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is designed for testing the new VRF strict_mode functionality.
5
6source lib.sh
7ret=0
8
9# identifies the "init" network namespace which is often called root network
10# namespace.
11INIT_NETNS_NAME="init"
12
13PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
14
15TESTS="init testns mix"
16
17log_test()
18{
19	local rc=$1
20	local expected=$2
21	local msg="$3"
22
23	if [ ${rc} -eq ${expected} ]; then
24		nsuccess=$((nsuccess+1))
25		printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
26	else
27		ret=1
28		nfail=$((nfail+1))
29		printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
30		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
31			echo
32			echo "hit enter to continue, 'q' to quit"
33			read a
34			[ "$a" = "q" ] && exit 1
35		fi
36	fi
37}
38
39print_log_test_results()
40{
41	if [ "$TESTS" != "none" ]; then
42		printf "\nTests passed: %3d\n" ${nsuccess}
43		printf "Tests failed: %3d\n"   ${nfail}
44	fi
45}
46
47log_section()
48{
49	echo
50	echo "################################################################################"
51	echo "TEST SECTION: $*"
52	echo "################################################################################"
53}
54
55ip_expand_args()
56{
57	local nsname=$1
58	local nsarg=""
59
60	if [ "${nsname}" != "${INIT_NETNS_NAME}" ]; then
61		nsarg="-netns ${nsname}"
62	fi
63
64	echo "${nsarg}"
65}
66
67vrf_count()
68{
69	local nsname=$1
70	local nsarg="$(ip_expand_args ${nsname})"
71
72	ip ${nsarg} -o link show type vrf | wc -l
73}
74
75count_vrf_by_table_id()
76{
77	local nsname=$1
78	local tableid=$2
79	local nsarg="$(ip_expand_args ${nsname})"
80
81	ip ${nsarg} -d -o link show type vrf | grep "table ${tableid}" | wc -l
82}
83
84add_vrf()
85{
86	local nsname=$1
87	local vrfname=$2
88	local vrftable=$3
89	local nsarg="$(ip_expand_args ${nsname})"
90
91	ip ${nsarg} link add ${vrfname} type vrf table ${vrftable} &>/dev/null
92}
93
94add_vrf_and_check()
95{
96	local nsname=$1
97	local vrfname=$2
98	local vrftable=$3
99	local cnt
100	local rc
101
102	add_vrf ${nsname} ${vrfname} ${vrftable}; rc=$?
103
104	cnt=$(count_vrf_by_table_id ${nsname} ${vrftable})
105
106	log_test ${rc} 0 "${nsname}: add vrf ${vrfname}, ${cnt} vrfs for table ${vrftable}"
107}
108
109add_vrf_and_check_fail()
110{
111	local nsname=$1
112	local vrfname=$2
113	local vrftable=$3
114	local cnt
115	local rc
116
117	add_vrf ${nsname} ${vrfname} ${vrftable}; rc=$?
118
119	cnt=$(count_vrf_by_table_id ${nsname} ${vrftable})
120
121	log_test ${rc} 2 "${nsname}: CANNOT add vrf ${vrfname}, ${cnt} vrfs for table ${vrftable}"
122}
123
124del_vrf_and_check()
125{
126	local nsname=$1
127	local vrfname=$2
128	local nsarg="$(ip_expand_args ${nsname})"
129
130	ip ${nsarg} link del ${vrfname}
131	log_test $? 0 "${nsname}: remove vrf ${vrfname}"
132}
133
134config_vrf_and_check()
135{
136	local nsname=$1
137	local addr=$2
138	local vrfname=$3
139	local nsarg="$(ip_expand_args ${nsname})"
140
141	ip ${nsarg} link set dev ${vrfname} up && \
142		ip ${nsarg} addr add ${addr} dev ${vrfname}
143	log_test $? 0 "${nsname}: vrf ${vrfname} up, addr ${addr}"
144}
145
146read_strict_mode()
147{
148	local nsname=$1
149	local rval
150	local rc=0
151	local nsexec=""
152
153	if [ "${nsname}" != "${INIT_NETNS_NAME}" ]; then
154		# a custom network namespace is provided
155		nsexec="ip netns exec ${nsname}"
156	fi
157
158	rval="$(${nsexec} bash -c "cat /proc/sys/net/vrf/strict_mode" | \
159		grep -E "^[0-1]$")" &> /dev/null
160	if [ $? -ne 0 ]; then
161		# set errors
162		rval=255
163		rc=1
164	fi
165
166	# on success, rval can be only 0 or 1; on error, rval is equal to 255
167	echo ${rval}
168	return ${rc}
169}
170
171read_strict_mode_compare_and_check()
172{
173	local nsname=$1
174	local expected=$2
175	local res
176
177	res="$(read_strict_mode ${nsname})"
178	log_test ${res} ${expected} "${nsname}: check strict_mode=${res}"
179}
180
181set_strict_mode()
182{
183	local nsname=$1
184	local val=$2
185	local nsexec=""
186
187	if [ "${nsname}" != "${INIT_NETNS_NAME}" ]; then
188		# a custom network namespace is provided
189		nsexec="ip netns exec ${nsname}"
190	fi
191
192	${nsexec} bash -c "echo ${val} >/proc/sys/net/vrf/strict_mode" &>/dev/null
193}
194
195enable_strict_mode()
196{
197	local nsname=$1
198
199	set_strict_mode ${nsname} 1
200}
201
202disable_strict_mode()
203{
204	local nsname=$1
205
206	set_strict_mode ${nsname} 0
207}
208
209disable_strict_mode_and_check()
210{
211	local nsname=$1
212
213	disable_strict_mode ${nsname}
214	log_test $? 0 "${nsname}: disable strict_mode (=0)"
215}
216
217enable_strict_mode_and_check()
218{
219	local nsname=$1
220
221	enable_strict_mode ${nsname}
222	log_test $? 0 "${nsname}: enable strict_mode (=1)"
223}
224
225enable_strict_mode_and_check_fail()
226{
227	local nsname=$1
228
229	enable_strict_mode ${nsname}
230	log_test $? 1 "${nsname}: CANNOT enable strict_mode"
231}
232
233strict_mode_check_default()
234{
235	local nsname=$1
236	local strictmode
237	local vrfcnt
238
239	vrfcnt=$(vrf_count ${nsname})
240	strictmode=$(read_strict_mode ${nsname})
241	log_test ${strictmode} 0 "${nsname}: strict_mode=0 by default, ${vrfcnt} vrfs"
242}
243
244setup()
245{
246	modprobe vrf
247
248	setup_ns testns
249}
250
251cleanup()
252{
253	ip netns del $testns 2>/dev/null
254
255	ip link del vrf100 2>/dev/null
256	ip link del vrf101 2>/dev/null
257	ip link del vrf102 2>/dev/null
258
259	echo 0 >/proc/sys/net/vrf/strict_mode 2>/dev/null
260}
261
262vrf_strict_mode_tests_init()
263{
264	log_section "VRF strict_mode test on init network namespace"
265
266	vrf_strict_mode_check_support init
267
268	strict_mode_check_default init
269
270	add_vrf_and_check init vrf100 100
271	config_vrf_and_check init 172.16.100.1/24 vrf100
272
273	enable_strict_mode_and_check init
274
275	add_vrf_and_check_fail init vrf101 100
276
277	disable_strict_mode_and_check init
278
279	add_vrf_and_check init vrf101 100
280	config_vrf_and_check init 172.16.101.1/24 vrf101
281
282	enable_strict_mode_and_check_fail init
283
284	del_vrf_and_check init vrf101
285
286	enable_strict_mode_and_check init
287
288	add_vrf_and_check init vrf102 102
289	config_vrf_and_check init 172.16.102.1/24 vrf102
290
291	# the strict_modle is enabled in the init
292}
293
294vrf_strict_mode_tests_testns()
295{
296	log_section "VRF strict_mode test on testns network namespace"
297
298	vrf_strict_mode_check_support $testns
299
300	strict_mode_check_default $testns
301
302	enable_strict_mode_and_check $testns
303
304	add_vrf_and_check $testns vrf100 100
305	config_vrf_and_check $testns 10.0.100.1/24 vrf100
306
307	add_vrf_and_check_fail $testns vrf101 100
308
309	add_vrf_and_check_fail $testns vrf102 100
310
311	add_vrf_and_check $testns vrf200 200
312
313	disable_strict_mode_and_check $testns
314
315	add_vrf_and_check $testns vrf101 100
316
317	add_vrf_and_check $testns vrf102 100
318
319	#the strict_mode is disabled in the $testns
320}
321
322vrf_strict_mode_tests_mix()
323{
324	log_section "VRF strict_mode test mixing init and testns network namespaces"
325
326	read_strict_mode_compare_and_check init 1
327
328	read_strict_mode_compare_and_check $testns 0
329
330	del_vrf_and_check $testns vrf101
331
332	del_vrf_and_check $testns vrf102
333
334	disable_strict_mode_and_check init
335
336	enable_strict_mode_and_check $testns
337
338	enable_strict_mode_and_check init
339	enable_strict_mode_and_check init
340
341	disable_strict_mode_and_check $testns
342	disable_strict_mode_and_check $testns
343
344	read_strict_mode_compare_and_check init 1
345
346	read_strict_mode_compare_and_check $testns 0
347}
348
349################################################################################
350# usage
351
352usage()
353{
354	cat <<EOF
355usage: ${0##*/} OPTS
356
357	-t <test>	Test(s) to run (default: all)
358			(options: $TESTS)
359EOF
360}
361
362################################################################################
363# main
364
365while getopts ":t:h" opt; do
366	case $opt in
367		t) TESTS=$OPTARG;;
368		h) usage; exit 0;;
369		*) usage; exit 1;;
370	esac
371done
372
373vrf_strict_mode_check_support()
374{
375	local nsname=$1
376	local output
377	local rc
378
379	output="$(lsmod | grep '^vrf' | awk '{print $1}')"
380	if [ -z "${output}" ]; then
381		modinfo vrf || return $?
382	fi
383
384	# we do not care about the value of the strict_mode; we only check if
385	# the strict_mode parameter is available or not.
386	read_strict_mode ${nsname} &>/dev/null; rc=$?
387	log_test ${rc} 0 "${nsname}: net.vrf.strict_mode is available"
388
389	return ${rc}
390}
391
392if [ "$(id -u)" -ne 0 ];then
393	echo "SKIP: Need root privileges"
394	exit $ksft_skip
395fi
396
397if [ ! -x "$(command -v ip)" ]; then
398	echo "SKIP: Could not run test without ip tool"
399	exit $ksft_skip
400fi
401
402modprobe vrf &>/dev/null
403if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
404	echo "SKIP: vrf sysctl does not exist"
405	exit $ksft_skip
406fi
407
408cleanup &> /dev/null
409
410setup
411for t in $TESTS
412do
413	case $t in
414	vrf_strict_mode_tests_init|init) vrf_strict_mode_tests_init;;
415	vrf_strict_mode_tests_testns|testns) vrf_strict_mode_tests_testns;;
416	vrf_strict_mode_tests_mix|mix) vrf_strict_mode_tests_mix;;
417
418	help) echo "Test names: $TESTS"; exit 0;;
419
420	esac
421done
422cleanup
423
424print_log_test_results
425
426exit $ret
427