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