1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4lib_dir=$(dirname $0)/../../../net/forwarding
5
6ALL_TESTS="
7	ipv4_route_addition_test
8	ipv4_route_deletion_test
9	ipv4_route_replacement_test
10	ipv4_route_offload_failed_test
11	ipv6_route_addition_test
12	ipv6_route_deletion_test
13	ipv6_route_replacement_test
14	ipv6_route_offload_failed_test
15"
16
17NETDEVSIM_PATH=/sys/bus/netdevsim/
18DEV_ADDR=1337
19DEV=netdevsim${DEV_ADDR}
20DEVLINK_DEV=netdevsim/${DEV}
21SYSFS_NET_DIR=/sys/bus/netdevsim/devices/$DEV/net/
22DEBUGFS_DIR=/sys/kernel/debug/netdevsim/$DEV/
23NUM_NETIFS=0
24source $lib_dir/lib.sh
25
26check_rt_offload_failed()
27{
28	local outfile=$1; shift
29	local line
30
31	# Make sure that the first notification was emitted without
32	# RTM_F_OFFLOAD_FAILED flag and the second with RTM_F_OFFLOAD_FAILED
33	# flag
34	head -n 1 $outfile | grep -q "rt_offload_failed"
35	if [[ $? -eq 0 ]]; then
36		return 1
37	fi
38
39	head -n 2 $outfile | tail -n 1 | grep -q "rt_offload_failed"
40}
41
42check_rt_trap()
43{
44	local outfile=$1; shift
45	local line
46
47	# Make sure that the first notification was emitted without RTM_F_TRAP
48	# flag and the second with RTM_F_TRAP flag
49	head -n 1 $outfile | grep -q "rt_trap"
50	if [[ $? -eq 0 ]]; then
51		return 1
52	fi
53
54	head -n 2 $outfile | tail -n 1 | grep -q "rt_trap"
55}
56
57route_notify_check()
58{
59	local outfile=$1; shift
60	local expected_num_lines=$1; shift
61	local offload_failed=${1:-0}; shift
62
63	# check the monitor results
64	lines=`wc -l $outfile | cut "-d " -f1`
65	test $lines -eq $expected_num_lines
66	check_err $? "$expected_num_lines notifications were expected but $lines were received"
67
68	if [[ $expected_num_lines -eq 1 ]]; then
69		return
70	fi
71
72	if [[ $offload_failed -eq 0 ]]; then
73		check_rt_trap $outfile
74		check_err $? "Wrong RTM_F_TRAP flags in notifications"
75	else
76		check_rt_offload_failed $outfile
77		check_err $? "Wrong RTM_F_OFFLOAD_FAILED flags in notifications"
78	fi
79}
80
81route_addition_check()
82{
83	local ip=$1; shift
84	local notify=$1; shift
85	local route=$1; shift
86	local expected_num_notifications=$1; shift
87	local offload_failed=${1:-0}; shift
88
89	ip netns exec testns1 sysctl -qw net.$ip.fib_notify_on_flag_change=$notify
90
91	local outfile=$(mktemp)
92
93	$IP monitor route &> $outfile &
94	sleep 1
95	$IP route add $route dev dummy1
96	sleep 1
97	kill %% && wait %% &> /dev/null
98
99	route_notify_check $outfile $expected_num_notifications $offload_failed
100	rm -f $outfile
101
102	$IP route del $route dev dummy1
103}
104
105ipv4_route_addition_test()
106{
107	RET=0
108
109	local ip="ipv4"
110	local route=192.0.2.0/24
111
112	# Make sure a single notification will be emitted for the programmed
113	# route.
114	local notify=0
115	local expected_num_notifications=1
116	# route_addition_check will assign value to RET.
117	route_addition_check $ip $notify $route $expected_num_notifications
118
119	# Make sure two notifications will be emitted for the programmed route.
120	notify=1
121	expected_num_notifications=2
122	route_addition_check $ip $notify $route $expected_num_notifications
123
124	# notify=2 means emit notifications only for failed route installation,
125	# make sure a single notification will be emitted for the programmed
126	# route.
127	notify=2
128	expected_num_notifications=1
129	route_addition_check $ip $notify $route $expected_num_notifications
130
131	log_test "IPv4 route addition"
132}
133
134route_deletion_check()
135{
136	local ip=$1; shift
137	local notify=$1; shift
138	local route=$1; shift
139	local expected_num_notifications=$1; shift
140
141	ip netns exec testns1 sysctl -qw net.$ip.fib_notify_on_flag_change=$notify
142	$IP route add $route dev dummy1
143	sleep 1
144
145	local outfile=$(mktemp)
146
147	$IP monitor route &> $outfile &
148	sleep 1
149	$IP route del $route dev dummy1
150	sleep 1
151	kill %% && wait %% &> /dev/null
152
153	route_notify_check $outfile $expected_num_notifications
154	rm -f $outfile
155}
156
157ipv4_route_deletion_test()
158{
159	RET=0
160
161	local ip="ipv4"
162	local route=192.0.2.0/24
163	local expected_num_notifications=1
164
165	# Make sure a single notification will be emitted for the deleted route,
166	# regardless of fib_notify_on_flag_change value.
167	local notify=0
168	# route_deletion_check will assign value to RET.
169	route_deletion_check $ip $notify $route $expected_num_notifications
170
171	notify=1
172	route_deletion_check $ip $notify $route $expected_num_notifications
173
174	log_test "IPv4 route deletion"
175}
176
177route_replacement_check()
178{
179	local ip=$1; shift
180	local notify=$1; shift
181	local route=$1; shift
182	local expected_num_notifications=$1; shift
183
184	ip netns exec testns1 sysctl -qw net.$ip.fib_notify_on_flag_change=$notify
185	$IP route add $route dev dummy1
186	sleep 1
187
188	local outfile=$(mktemp)
189
190	$IP monitor route &> $outfile &
191	sleep 1
192	$IP route replace $route dev dummy2
193	sleep 1
194	kill %% && wait %% &> /dev/null
195
196	route_notify_check $outfile $expected_num_notifications
197	rm -f $outfile
198
199	$IP route del $route dev dummy2
200}
201
202ipv4_route_replacement_test()
203{
204	RET=0
205
206	local ip="ipv4"
207	local route=192.0.2.0/24
208
209	$IP link add name dummy2 type dummy
210	$IP link set dev dummy2 up
211
212	# Make sure a single notification will be emitted for the new route.
213	local notify=0
214	local expected_num_notifications=1
215	# route_replacement_check will assign value to RET.
216	route_replacement_check $ip $notify $route $expected_num_notifications
217
218	# Make sure two notifications will be emitted for the new route.
219	notify=1
220	expected_num_notifications=2
221	route_replacement_check $ip $notify $route $expected_num_notifications
222
223	# notify=2 means emit notifications only for failed route installation,
224	# make sure a single notification will be emitted for the new route.
225	notify=2
226	expected_num_notifications=1
227	route_replacement_check $ip $notify $route $expected_num_notifications
228
229	$IP link del name dummy2
230
231	log_test "IPv4 route replacement"
232}
233
234ipv4_route_offload_failed_test()
235{
236
237	RET=0
238
239	local ip="ipv4"
240	local route=192.0.2.0/24
241	local offload_failed=1
242
243	echo "y"> $DEBUGFS_DIR/fib/fail_route_offload
244	check_err $? "Failed to setup route offload to fail"
245
246	# Make sure a single notification will be emitted for the programmed
247	# route.
248	local notify=0
249	local expected_num_notifications=1
250	route_addition_check $ip $notify $route $expected_num_notifications \
251		$offload_failed
252
253	# Make sure two notifications will be emitted for the new route.
254	notify=1
255	expected_num_notifications=2
256	route_addition_check $ip $notify $route $expected_num_notifications \
257		$offload_failed
258
259	# notify=2 means emit notifications only for failed route installation,
260	# make sure two notifications will be emitted for the new route.
261	notify=2
262	expected_num_notifications=2
263	route_addition_check $ip $notify $route $expected_num_notifications \
264		$offload_failed
265
266	echo "n"> $DEBUGFS_DIR/fib/fail_route_offload
267	check_err $? "Failed to setup route offload not to fail"
268
269	log_test "IPv4 route offload failed"
270}
271
272ipv6_route_addition_test()
273{
274	RET=0
275
276	local ip="ipv6"
277	local route=2001:db8:1::/64
278
279	# Make sure a single notification will be emitted for the programmed
280	# route.
281	local notify=0
282	local expected_num_notifications=1
283	route_addition_check $ip $notify $route $expected_num_notifications
284
285	# Make sure two notifications will be emitted for the programmed route.
286	notify=1
287	expected_num_notifications=2
288	route_addition_check $ip $notify $route $expected_num_notifications
289
290	# notify=2 means emit notifications only for failed route installation,
291	# make sure a single notification will be emitted for the programmed
292	# route.
293	notify=2
294	expected_num_notifications=1
295	route_addition_check $ip $notify $route $expected_num_notifications
296
297	log_test "IPv6 route addition"
298}
299
300ipv6_route_deletion_test()
301{
302	RET=0
303
304	local ip="ipv6"
305	local route=2001:db8:1::/64
306	local expected_num_notifications=1
307
308	# Make sure a single notification will be emitted for the deleted route,
309	# regardless of fib_notify_on_flag_change value.
310	local notify=0
311	route_deletion_check $ip $notify $route $expected_num_notifications
312
313	notify=1
314	route_deletion_check $ip $notify $route $expected_num_notifications
315
316	log_test "IPv6 route deletion"
317}
318
319ipv6_route_replacement_test()
320{
321	RET=0
322
323	local ip="ipv6"
324	local route=2001:db8:1::/64
325
326	$IP link add name dummy2 type dummy
327	$IP link set dev dummy2 up
328
329	# Make sure a single notification will be emitted for the new route.
330	local notify=0
331	local expected_num_notifications=1
332	route_replacement_check $ip $notify $route $expected_num_notifications
333
334	# Make sure two notifications will be emitted for the new route.
335	notify=1
336	expected_num_notifications=2
337	route_replacement_check $ip $notify $route $expected_num_notifications
338
339	# notify=2 means emit notifications only for failed route installation,
340	# make sure a single notification will be emitted for the new route.
341	notify=2
342	expected_num_notifications=1
343	route_replacement_check $ip $notify $route $expected_num_notifications
344
345	$IP link del name dummy2
346
347	log_test "IPv6 route replacement"
348}
349
350ipv6_route_offload_failed_test()
351{
352
353	RET=0
354
355	local ip="ipv6"
356	local route=2001:db8:1::/64
357	local offload_failed=1
358
359	echo "y"> $DEBUGFS_DIR/fib/fail_route_offload
360	check_err $? "Failed to setup route offload to fail"
361
362	# Make sure a single notification will be emitted for the programmed
363	# route.
364	local notify=0
365	local expected_num_notifications=1
366	route_addition_check $ip $notify $route $expected_num_notifications \
367		$offload_failed
368
369	# Make sure two notifications will be emitted for the new route.
370	notify=1
371	expected_num_notifications=2
372	route_addition_check $ip $notify $route $expected_num_notifications \
373		$offload_failed
374
375	# notify=2 means emit notifications only for failed route installation,
376	# make sure two notifications will be emitted for the new route.
377	notify=2
378	expected_num_notifications=2
379	route_addition_check $ip $notify $route $expected_num_notifications \
380		$offload_failed
381
382	echo "n"> $DEBUGFS_DIR/fib/fail_route_offload
383	check_err $? "Failed to setup route offload not to fail"
384
385	log_test "IPv6 route offload failed"
386}
387
388setup_prepare()
389{
390	modprobe netdevsim &> /dev/null
391	echo "$DEV_ADDR 1" > ${NETDEVSIM_PATH}/new_device
392	while [ ! -d $SYSFS_NET_DIR ] ; do :; done
393
394	ip netns add testns1
395
396	if [ $? -ne 0 ]; then
397		echo "Failed to add netns \"testns1\""
398		exit 1
399	fi
400
401	devlink dev reload $DEVLINK_DEV netns testns1
402
403	if [ $? -ne 0 ]; then
404		echo "Failed to reload into netns \"testns1\""
405		exit 1
406	fi
407
408	IP="ip -n testns1"
409
410	$IP link add name dummy1 type dummy
411	$IP link set dev dummy1 up
412}
413
414cleanup()
415{
416	pre_cleanup
417
418	$IP link del name dummy1
419	ip netns del testns1
420	echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device
421	modprobe -r netdevsim &> /dev/null
422}
423
424trap cleanup EXIT
425
426setup_prepare
427
428tests_run
429
430exit $EXIT_STATUS
431