1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# This test is for checking devlink-trap functionality. It makes use of
5# netdevsim which implements the required callbacks.
6
7lib_dir=$(dirname $0)/../../../net/forwarding
8
9ALL_TESTS="
10	init_test
11	trap_action_test
12	trap_metadata_test
13	bad_trap_test
14	bad_trap_action_test
15	trap_stats_test
16	trap_group_action_test
17	bad_trap_group_test
18	trap_group_stats_test
19	port_del_test
20	dev_del_test
21"
22NETDEVSIM_PATH=/sys/bus/netdevsim/
23DEV_ADDR=1337
24DEV=netdevsim${DEV_ADDR}
25DEVLINK_DEV=netdevsim/${DEV}
26SLEEP_TIME=1
27NETDEV=""
28NUM_NETIFS=0
29source $lib_dir/lib.sh
30source $lib_dir/devlink_lib.sh
31
32require_command udevadm
33
34modprobe netdevsim &> /dev/null
35if [ ! -d "$NETDEVSIM_PATH" ]; then
36	echo "SKIP: No netdevsim support"
37	exit 1
38fi
39
40if [ -d "${NETDEVSIM_PATH}/devices/netdevsim${DEV_ADDR}" ]; then
41	echo "SKIP: Device netdevsim${DEV_ADDR} already exists"
42	exit 1
43fi
44
45init_test()
46{
47	RET=0
48
49	test $(devlink_traps_num_get) -ne 0
50	check_err $? "No traps were registered"
51
52	log_test "Initialization"
53}
54
55trap_action_test()
56{
57	local orig_action
58	local trap_name
59	local action
60
61	RET=0
62
63	for trap_name in $(devlink_traps_get); do
64		# The action of non-drop traps cannot be changed.
65		if [ $(devlink_trap_type_get $trap_name) = "drop" ]; then
66			devlink_trap_action_set $trap_name "trap"
67			action=$(devlink_trap_action_get $trap_name)
68			if [ $action != "trap" ]; then
69				check_err 1 "Trap $trap_name did not change action to trap"
70			fi
71
72			devlink_trap_action_set $trap_name "drop"
73			action=$(devlink_trap_action_get $trap_name)
74			if [ $action != "drop" ]; then
75				check_err 1 "Trap $trap_name did not change action to drop"
76			fi
77		else
78			orig_action=$(devlink_trap_action_get $trap_name)
79
80			devlink_trap_action_set $trap_name "trap"
81			action=$(devlink_trap_action_get $trap_name)
82			if [ $action != $orig_action ]; then
83				check_err 1 "Trap $trap_name changed action when should not"
84			fi
85
86			devlink_trap_action_set $trap_name "drop"
87			action=$(devlink_trap_action_get $trap_name)
88			if [ $action != $orig_action ]; then
89				check_err 1 "Trap $trap_name changed action when should not"
90			fi
91		fi
92	done
93
94	log_test "Trap action"
95}
96
97trap_metadata_test()
98{
99	local trap_name
100
101	RET=0
102
103	for trap_name in $(devlink_traps_get); do
104		devlink_trap_metadata_test $trap_name "input_port"
105		check_err $? "Input port not reported as metadata of trap $trap_name"
106		if [ $trap_name == "ingress_flow_action_drop" ] ||
107		   [ $trap_name == "egress_flow_action_drop" ]; then
108			devlink_trap_metadata_test $trap_name "flow_action_cookie"
109			check_err $? "Flow action cookie not reported as metadata of trap $trap_name"
110		fi
111	done
112
113	log_test "Trap metadata"
114}
115
116bad_trap_test()
117{
118	RET=0
119
120	devlink_trap_action_set "made_up_trap" "drop"
121	check_fail $? "Did not get an error for non-existing trap"
122
123	log_test "Non-existing trap"
124}
125
126bad_trap_action_test()
127{
128	local traps_arr
129	local trap_name
130
131	RET=0
132
133	# Pick first trap.
134	traps_arr=($(devlink_traps_get))
135	trap_name=${traps_arr[0]}
136
137	devlink_trap_action_set $trap_name "made_up_action"
138	check_fail $? "Did not get an error for non-existing trap action"
139
140	log_test "Non-existing trap action"
141}
142
143trap_stats_test()
144{
145	local trap_name
146
147	RET=0
148
149	for trap_name in $(devlink_traps_get); do
150		devlink_trap_stats_idle_test $trap_name
151		check_err $? "Stats of trap $trap_name not idle when netdev down"
152
153		ip link set dev $NETDEV up
154
155		if [ $(devlink_trap_type_get $trap_name) = "drop" ]; then
156			devlink_trap_action_set $trap_name "trap"
157			devlink_trap_stats_idle_test $trap_name
158			check_fail $? "Stats of trap $trap_name idle when action is trap"
159
160			devlink_trap_action_set $trap_name "drop"
161			devlink_trap_stats_idle_test $trap_name
162			check_err $? "Stats of trap $trap_name not idle when action is drop"
163		else
164			devlink_trap_stats_idle_test $trap_name
165			check_fail $? "Stats of non-drop trap $trap_name idle when should not"
166		fi
167
168		ip link set dev $NETDEV down
169	done
170
171	log_test "Trap statistics"
172}
173
174trap_group_action_test()
175{
176	local curr_group group_name
177	local trap_name
178	local trap_type
179	local action
180
181	RET=0
182
183	for group_name in $(devlink_trap_groups_get); do
184		devlink_trap_group_action_set $group_name "trap"
185
186		for trap_name in $(devlink_traps_get); do
187			curr_group=$(devlink_trap_group_get $trap_name)
188			if [ $curr_group != $group_name ]; then
189				continue
190			fi
191
192			trap_type=$(devlink_trap_type_get $trap_name)
193			if [ $trap_type != "drop" ]; then
194				continue
195			fi
196
197			action=$(devlink_trap_action_get $trap_name)
198			if [ $action != "trap" ]; then
199				check_err 1 "Trap $trap_name did not change action to trap"
200			fi
201		done
202
203		devlink_trap_group_action_set $group_name "drop"
204
205		for trap_name in $(devlink_traps_get); do
206			curr_group=$(devlink_trap_group_get $trap_name)
207			if [ $curr_group != $group_name ]; then
208				continue
209			fi
210
211			trap_type=$(devlink_trap_type_get $trap_name)
212			if [ $trap_type != "drop" ]; then
213				continue
214			fi
215
216			action=$(devlink_trap_action_get $trap_name)
217			if [ $action != "drop" ]; then
218				check_err 1 "Trap $trap_name did not change action to drop"
219			fi
220		done
221	done
222
223	log_test "Trap group action"
224}
225
226bad_trap_group_test()
227{
228	RET=0
229
230	devlink_trap_group_action_set "made_up_trap_group" "drop"
231	check_fail $? "Did not get an error for non-existing trap group"
232
233	log_test "Non-existing trap group"
234}
235
236trap_group_stats_test()
237{
238	local group_name
239
240	RET=0
241
242	for group_name in $(devlink_trap_groups_get); do
243		devlink_trap_group_stats_idle_test $group_name
244		check_err $? "Stats of trap group $group_name not idle when netdev down"
245
246		ip link set dev $NETDEV up
247
248		devlink_trap_group_action_set $group_name "trap"
249		devlink_trap_group_stats_idle_test $group_name
250		check_fail $? "Stats of trap group $group_name idle when action is trap"
251
252		devlink_trap_group_action_set $group_name "drop"
253		ip link set dev $NETDEV down
254	done
255
256	log_test "Trap group statistics"
257}
258
259port_del_test()
260{
261	local group_name
262	local i
263
264	# The test never fails. It is meant to exercise different code paths
265	# and make sure we properly dismantle a port while packets are
266	# in-flight.
267	RET=0
268
269	devlink_traps_enable_all
270
271	for i in $(seq 1 10); do
272		ip link set dev $NETDEV up
273
274		sleep $SLEEP_TIME
275
276		netdevsim_port_destroy
277		netdevsim_port_create
278		udevadm settle
279	done
280
281	devlink_traps_disable_all
282
283	log_test "Port delete"
284}
285
286dev_del_test()
287{
288	local group_name
289	local i
290
291	# The test never fails. It is meant to exercise different code paths
292	# and make sure we properly unregister traps while packets are
293	# in-flight.
294	RET=0
295
296	devlink_traps_enable_all
297
298	for i in $(seq 1 10); do
299		ip link set dev $NETDEV up
300
301		sleep $SLEEP_TIME
302
303		cleanup
304		setup_prepare
305	done
306
307	devlink_traps_disable_all
308
309	log_test "Device delete"
310}
311
312netdevsim_dev_create()
313{
314	echo "$DEV_ADDR 0" > ${NETDEVSIM_PATH}/new_device
315}
316
317netdevsim_dev_destroy()
318{
319	echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device
320}
321
322netdevsim_port_create()
323{
324	echo 1 > ${NETDEVSIM_PATH}/devices/${DEV}/new_port
325}
326
327netdevsim_port_destroy()
328{
329	echo 1 > ${NETDEVSIM_PATH}/devices/${DEV}/del_port
330}
331
332setup_prepare()
333{
334	local netdev
335
336	netdevsim_dev_create
337
338	if [ ! -d "${NETDEVSIM_PATH}/devices/${DEV}" ]; then
339		echo "Failed to create netdevsim device"
340		exit 1
341	fi
342
343	netdevsim_port_create
344
345	if [ ! -d "${NETDEVSIM_PATH}/devices/${DEV}/net/" ]; then
346		echo "Failed to create netdevsim port"
347		exit 1
348	fi
349
350	# Wait for udev to rename newly created netdev.
351	udevadm settle
352
353	NETDEV=$(ls ${NETDEVSIM_PATH}/devices/${DEV}/net/)
354}
355
356cleanup()
357{
358	pre_cleanup
359	netdevsim_port_destroy
360	netdevsim_dev_destroy
361}
362
363trap cleanup EXIT
364
365setup_prepare
366
367tests_run
368
369exit $EXIT_STATUS
370