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	done
107
108	log_test "Trap metadata"
109}
110
111bad_trap_test()
112{
113	RET=0
114
115	devlink_trap_action_set "made_up_trap" "drop"
116	check_fail $? "Did not get an error for non-existing trap"
117
118	log_test "Non-existing trap"
119}
120
121bad_trap_action_test()
122{
123	local traps_arr
124	local trap_name
125
126	RET=0
127
128	# Pick first trap.
129	traps_arr=($(devlink_traps_get))
130	trap_name=${traps_arr[0]}
131
132	devlink_trap_action_set $trap_name "made_up_action"
133	check_fail $? "Did not get an error for non-existing trap action"
134
135	log_test "Non-existing trap action"
136}
137
138trap_stats_test()
139{
140	local trap_name
141
142	RET=0
143
144	for trap_name in $(devlink_traps_get); do
145		devlink_trap_stats_idle_test $trap_name
146		check_err $? "Stats of trap $trap_name not idle when netdev down"
147
148		ip link set dev $NETDEV up
149
150		if [ $(devlink_trap_type_get $trap_name) = "drop" ]; then
151			devlink_trap_action_set $trap_name "trap"
152			devlink_trap_stats_idle_test $trap_name
153			check_fail $? "Stats of trap $trap_name idle when action is trap"
154
155			devlink_trap_action_set $trap_name "drop"
156			devlink_trap_stats_idle_test $trap_name
157			check_err $? "Stats of trap $trap_name not idle when action is drop"
158		else
159			devlink_trap_stats_idle_test $trap_name
160			check_fail $? "Stats of non-drop trap $trap_name idle when should not"
161		fi
162
163		ip link set dev $NETDEV down
164	done
165
166	log_test "Trap statistics"
167}
168
169trap_group_action_test()
170{
171	local curr_group group_name
172	local trap_name
173	local trap_type
174	local action
175
176	RET=0
177
178	for group_name in $(devlink_trap_groups_get); do
179		devlink_trap_group_action_set $group_name "trap"
180
181		for trap_name in $(devlink_traps_get); do
182			curr_group=$(devlink_trap_group_get $trap_name)
183			if [ $curr_group != $group_name ]; then
184				continue
185			fi
186
187			trap_type=$(devlink_trap_type_get $trap_name)
188			if [ $trap_type != "drop" ]; then
189				continue
190			fi
191
192			action=$(devlink_trap_action_get $trap_name)
193			if [ $action != "trap" ]; then
194				check_err 1 "Trap $trap_name did not change action to trap"
195			fi
196		done
197
198		devlink_trap_group_action_set $group_name "drop"
199
200		for trap_name in $(devlink_traps_get); do
201			curr_group=$(devlink_trap_group_get $trap_name)
202			if [ $curr_group != $group_name ]; then
203				continue
204			fi
205
206			trap_type=$(devlink_trap_type_get $trap_name)
207			if [ $trap_type != "drop" ]; then
208				continue
209			fi
210
211			action=$(devlink_trap_action_get $trap_name)
212			if [ $action != "drop" ]; then
213				check_err 1 "Trap $trap_name did not change action to drop"
214			fi
215		done
216	done
217
218	log_test "Trap group action"
219}
220
221bad_trap_group_test()
222{
223	RET=0
224
225	devlink_trap_group_action_set "made_up_trap_group" "drop"
226	check_fail $? "Did not get an error for non-existing trap group"
227
228	log_test "Non-existing trap group"
229}
230
231trap_group_stats_test()
232{
233	local group_name
234
235	RET=0
236
237	for group_name in $(devlink_trap_groups_get); do
238		devlink_trap_group_stats_idle_test $group_name
239		check_err $? "Stats of trap group $group_name not idle when netdev down"
240
241		ip link set dev $NETDEV up
242
243		devlink_trap_group_action_set $group_name "trap"
244		devlink_trap_group_stats_idle_test $group_name
245		check_fail $? "Stats of trap group $group_name idle when action is trap"
246
247		devlink_trap_group_action_set $group_name "drop"
248		ip link set dev $NETDEV down
249	done
250
251	log_test "Trap group statistics"
252}
253
254port_del_test()
255{
256	local group_name
257	local i
258
259	# The test never fails. It is meant to exercise different code paths
260	# and make sure we properly dismantle a port while packets are
261	# in-flight.
262	RET=0
263
264	devlink_traps_enable_all
265
266	for i in $(seq 1 10); do
267		ip link set dev $NETDEV up
268
269		sleep $SLEEP_TIME
270
271		netdevsim_port_destroy
272		netdevsim_port_create
273		udevadm settle
274	done
275
276	devlink_traps_disable_all
277
278	log_test "Port delete"
279}
280
281dev_del_test()
282{
283	local group_name
284	local i
285
286	# The test never fails. It is meant to exercise different code paths
287	# and make sure we properly unregister traps while packets are
288	# in-flight.
289	RET=0
290
291	devlink_traps_enable_all
292
293	for i in $(seq 1 10); do
294		ip link set dev $NETDEV up
295
296		sleep $SLEEP_TIME
297
298		cleanup
299		setup_prepare
300	done
301
302	devlink_traps_disable_all
303
304	log_test "Device delete"
305}
306
307netdevsim_dev_create()
308{
309	echo "$DEV_ADDR 0" > ${NETDEVSIM_PATH}/new_device
310}
311
312netdevsim_dev_destroy()
313{
314	echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device
315}
316
317netdevsim_port_create()
318{
319	echo 1 > ${NETDEVSIM_PATH}/devices/${DEV}/new_port
320}
321
322netdevsim_port_destroy()
323{
324	echo 1 > ${NETDEVSIM_PATH}/devices/${DEV}/del_port
325}
326
327setup_prepare()
328{
329	local netdev
330
331	netdevsim_dev_create
332
333	if [ ! -d "${NETDEVSIM_PATH}/devices/${DEV}" ]; then
334		echo "Failed to create netdevsim device"
335		exit 1
336	fi
337
338	netdevsim_port_create
339
340	if [ ! -d "${NETDEVSIM_PATH}/devices/${DEV}/net/" ]; then
341		echo "Failed to create netdevsim port"
342		exit 1
343	fi
344
345	# Wait for udev to rename newly created netdev.
346	udevadm settle
347
348	NETDEV=$(ls ${NETDEVSIM_PATH}/devices/${DEV}/net/)
349}
350
351cleanup()
352{
353	pre_cleanup
354	netdevsim_port_destroy
355	netdevsim_dev_destroy
356}
357
358trap cleanup EXIT
359
360setup_prepare
361
362tests_run
363
364exit $EXIT_STATUS
365