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