1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4lib_dir=$(dirname $0)/../../../net/forwarding
5
6ALL_TESTS="
7	l3_reporting_test
8	l3_fail_next_test
9	l3_counter_test
10	l3_rollback_test
11	l3_monitor_test
12"
13
14NETDEVSIM_PATH=/sys/bus/netdevsim/
15DEV_ADDR_1=1337
16DEV_ADDR_2=1057
17DEV_ADDR_3=5417
18NUM_NETIFS=0
19source $lib_dir/lib.sh
20
21DUMMY_IFINDEX=
22
23DEV_ADDR()
24{
25	local n=$1; shift
26	local var=DEV_ADDR_$n
27
28	echo ${!var}
29}
30
31DEV()
32{
33	echo netdevsim$(DEV_ADDR $1)
34}
35
36DEVLINK_DEV()
37{
38	echo netdevsim/$(DEV $1)
39}
40
41SYSFS_NET_DIR()
42{
43	echo /sys/bus/netdevsim/devices/$(DEV $1)/net/
44}
45
46DEBUGFS_DIR()
47{
48	echo /sys/kernel/debug/netdevsim/$(DEV $1)/
49}
50
51nsim_add()
52{
53	local n=$1; shift
54
55	echo "$(DEV_ADDR $n) 1" > ${NETDEVSIM_PATH}/new_device
56	while [ ! -d $(SYSFS_NET_DIR $n) ] ; do :; done
57}
58
59nsim_reload()
60{
61	local n=$1; shift
62	local ns=$1; shift
63
64	devlink dev reload $(DEVLINK_DEV $n) netns $ns
65
66	if [ $? -ne 0 ]; then
67		echo "Failed to reload $(DEV $n) into netns \"testns1\""
68		exit 1
69	fi
70
71}
72
73nsim_del()
74{
75	local n=$1; shift
76
77	echo "$(DEV_ADDR $n)" > ${NETDEVSIM_PATH}/del_device
78}
79
80nsim_hwstats_toggle()
81{
82	local action=$1; shift
83	local instance=$1; shift
84	local netdev=$1; shift
85	local type=$1; shift
86
87	local ifindex=$($IP -j link show dev $netdev | jq '.[].ifindex')
88
89	echo $ifindex > $(DEBUGFS_DIR $instance)/hwstats/$type/$action
90}
91
92nsim_hwstats_enable()
93{
94	nsim_hwstats_toggle enable_ifindex "$@"
95}
96
97nsim_hwstats_disable()
98{
99	nsim_hwstats_toggle disable_ifindex "$@"
100}
101
102nsim_hwstats_fail_next_enable()
103{
104	nsim_hwstats_toggle fail_next_enable "$@"
105}
106
107setup_prepare()
108{
109	modprobe netdevsim &> /dev/null
110	nsim_add 1
111	nsim_add 2
112	nsim_add 3
113
114	ip netns add testns1
115
116	if [ $? -ne 0 ]; then
117		echo "Failed to add netns \"testns1\""
118		exit 1
119	fi
120
121	nsim_reload 1 testns1
122	nsim_reload 2 testns1
123	nsim_reload 3 testns1
124
125	IP="ip -n testns1"
126
127	$IP link add name dummy1 type dummy
128	$IP link set dev dummy1 up
129	DUMMY_IFINDEX=$($IP -j link show dev dummy1 | jq '.[].ifindex')
130}
131
132cleanup()
133{
134	pre_cleanup
135
136	$IP link del name dummy1
137	ip netns del testns1
138	nsim_del 3
139	nsim_del 2
140	nsim_del 1
141	modprobe -r netdevsim &> /dev/null
142}
143
144netdev_hwstats_used()
145{
146	local netdev=$1; shift
147	local type=$1; shift
148
149	$IP -j stats show dev "$netdev" group offload subgroup hw_stats_info |
150	    jq '.[].info.l3_stats.used'
151}
152
153netdev_check_used()
154{
155	local netdev=$1; shift
156	local type=$1; shift
157
158	[[ $(netdev_hwstats_used $netdev $type) == "true" ]]
159}
160
161netdev_check_unused()
162{
163	local netdev=$1; shift
164	local type=$1; shift
165
166	[[ $(netdev_hwstats_used $netdev $type) == "false" ]]
167}
168
169netdev_hwstats_request()
170{
171	local netdev=$1; shift
172	local type=$1; shift
173
174	$IP -j stats show dev "$netdev" group offload subgroup hw_stats_info |
175	    jq ".[].info.${type}_stats.request"
176}
177
178netdev_check_requested()
179{
180	local netdev=$1; shift
181	local type=$1; shift
182
183	[[ $(netdev_hwstats_request $netdev $type) == "true" ]]
184}
185
186netdev_check_unrequested()
187{
188	local netdev=$1; shift
189	local type=$1; shift
190
191	[[ $(netdev_hwstats_request $netdev $type) == "false" ]]
192}
193
194reporting_test()
195{
196	local type=$1; shift
197	local instance=1
198
199	RET=0
200
201	[[ -n $(netdev_hwstats_used dummy1 $type) ]]
202	check_err $? "$type stats not reported"
203
204	netdev_check_unused dummy1 $type
205	check_err $? "$type stats reported as used before either device or netdevsim request"
206
207	nsim_hwstats_enable $instance dummy1 $type
208	netdev_check_unused dummy1 $type
209	check_err $? "$type stats reported as used before device request"
210	netdev_check_unrequested dummy1 $type
211	check_err $? "$type stats reported as requested before device request"
212
213	$IP stats set dev dummy1 ${type}_stats on
214	netdev_check_used dummy1 $type
215	check_err $? "$type stats reported as not used after both device and netdevsim request"
216	netdev_check_requested dummy1 $type
217	check_err $? "$type stats reported as not requested after device request"
218
219	nsim_hwstats_disable $instance dummy1 $type
220	netdev_check_unused dummy1 $type
221	check_err $? "$type stats reported as used after netdevsim request withdrawn"
222
223	nsim_hwstats_enable $instance dummy1 $type
224	netdev_check_used dummy1 $type
225	check_err $? "$type stats reported as not used after netdevsim request reenabled"
226
227	$IP stats set dev dummy1 ${type}_stats off
228	netdev_check_unused dummy1 $type
229	check_err $? "$type stats reported as used after device request withdrawn"
230	netdev_check_unrequested dummy1 $type
231	check_err $? "$type stats reported as requested after device request withdrawn"
232
233	nsim_hwstats_disable $instance dummy1 $type
234	netdev_check_unused dummy1 $type
235	check_err $? "$type stats reported as used after both requests withdrawn"
236
237	log_test "Reporting of $type stats usage"
238}
239
240l3_reporting_test()
241{
242	reporting_test l3
243}
244
245__fail_next_test()
246{
247	local instance=$1; shift
248	local type=$1; shift
249
250	RET=0
251
252	netdev_check_unused dummy1 $type
253	check_err $? "$type stats reported as used before either device or netdevsim request"
254
255	nsim_hwstats_enable $instance dummy1 $type
256	nsim_hwstats_fail_next_enable $instance dummy1 $type
257	netdev_check_unused dummy1 $type
258	check_err $? "$type stats reported as used before device request"
259	netdev_check_unrequested dummy1 $type
260	check_err $? "$type stats reported as requested before device request"
261
262	$IP stats set dev dummy1 ${type}_stats on 2>/dev/null
263	check_fail $? "$type stats request not bounced as it should have been"
264	netdev_check_unused dummy1 $type
265	check_err $? "$type stats reported as used after bounce"
266	netdev_check_unrequested dummy1 $type
267	check_err $? "$type stats reported as requested after bounce"
268
269	$IP stats set dev dummy1 ${type}_stats on
270	check_err $? "$type stats request failed when it shouldn't have"
271	netdev_check_used dummy1 $type
272	check_err $? "$type stats reported as not used after both device and netdevsim request"
273	netdev_check_requested dummy1 $type
274	check_err $? "$type stats reported as not requested after device request"
275
276	$IP stats set dev dummy1 ${type}_stats off
277	nsim_hwstats_disable $instance dummy1 $type
278
279	log_test "Injected failure of $type stats enablement (netdevsim #$instance)"
280}
281
282fail_next_test()
283{
284	__fail_next_test 1 "$@"
285	__fail_next_test 2 "$@"
286	__fail_next_test 3 "$@"
287}
288
289l3_fail_next_test()
290{
291	fail_next_test l3
292}
293
294get_hwstat()
295{
296	local netdev=$1; shift
297	local type=$1; shift
298	local selector=$1; shift
299
300	$IP -j stats show dev $netdev group offload subgroup ${type}_stats |
301		  jq ".[0].stats64.${selector}"
302}
303
304counter_test()
305{
306	local type=$1; shift
307	local instance=1
308
309	RET=0
310
311	nsim_hwstats_enable $instance dummy1 $type
312	$IP stats set dev dummy1 ${type}_stats on
313	netdev_check_used dummy1 $type
314	check_err $? "$type stats reported as not used after both device and netdevsim request"
315
316	# Netdevsim counts 10pps on ingress. We should see maybe a couple
317	# packets, unless things take a reeealy long time.
318	local pkts=$(get_hwstat dummy1 l3 rx.packets)
319	((pkts < 10))
320	check_err $? "$type stats show >= 10 packets after first enablement"
321
322	sleep 2.5
323
324	local pkts=$(get_hwstat dummy1 l3 rx.packets)
325	((pkts >= 20))
326	check_err $? "$type stats show < 20 packets after 2.5s passed"
327
328	$IP stats set dev dummy1 ${type}_stats off
329
330	sleep 2
331
332	$IP stats set dev dummy1 ${type}_stats on
333	local pkts=$(get_hwstat dummy1 l3 rx.packets)
334	((pkts < 10))
335	check_err $? "$type stats show >= 10 packets after second enablement"
336
337	$IP stats set dev dummy1 ${type}_stats off
338	nsim_hwstats_fail_next_enable $instance dummy1 $type
339	$IP stats set dev dummy1 ${type}_stats on 2>/dev/null
340	check_fail $? "$type stats request not bounced as it should have been"
341
342	sleep 2
343
344	$IP stats set dev dummy1 ${type}_stats on
345	local pkts=$(get_hwstat dummy1 l3 rx.packets)
346	((pkts < 10))
347	check_err $? "$type stats show >= 10 packets after post-fail enablement"
348
349	$IP stats set dev dummy1 ${type}_stats off
350
351	log_test "Counter values in $type stats"
352}
353
354l3_counter_test()
355{
356	counter_test l3
357}
358
359rollback_test()
360{
361	local type=$1; shift
362
363	RET=0
364
365	nsim_hwstats_enable 1 dummy1 l3
366	nsim_hwstats_enable 2 dummy1 l3
367	nsim_hwstats_enable 3 dummy1 l3
368
369	# The three netdevsim instances are registered in order of their number
370	# one after another. It is reasonable to expect that whatever
371	# notifications take place hit no. 2 in between hitting nos. 1 and 3,
372	# whatever the actual order. This allows us to test that a fail caused
373	# by no. 2 does not leave the system in a partial state, and rolls
374	# everything back.
375
376	nsim_hwstats_fail_next_enable 2 dummy1 l3
377	$IP stats set dev dummy1 ${type}_stats on 2>/dev/null
378	check_fail $? "$type stats request not bounced as it should have been"
379
380	netdev_check_unused dummy1 $type
381	check_err $? "$type stats reported as used after bounce"
382	netdev_check_unrequested dummy1 $type
383	check_err $? "$type stats reported as requested after bounce"
384
385	sleep 2
386
387	$IP stats set dev dummy1 ${type}_stats on
388	check_err $? "$type stats request not upheld as it should have been"
389
390	local pkts=$(get_hwstat dummy1 l3 rx.packets)
391	((pkts < 10))
392	check_err $? "$type stats show $pkts packets after post-fail enablement"
393
394	$IP stats set dev dummy1 ${type}_stats off
395
396	nsim_hwstats_disable 3 dummy1 l3
397	nsim_hwstats_disable 2 dummy1 l3
398	nsim_hwstats_disable 1 dummy1 l3
399
400	log_test "Failure in $type stats enablement rolled back"
401}
402
403l3_rollback_test()
404{
405	rollback_test l3
406}
407
408l3_monitor_test()
409{
410	hw_stats_monitor_test dummy1 l3		   \
411		"nsim_hwstats_enable 1 dummy1 l3"  \
412		"nsim_hwstats_disable 1 dummy1 l3" \
413		"$IP"
414}
415
416trap cleanup EXIT
417
418setup_prepare
419tests_run
420
421exit $EXIT_STATUS
422