xref: /linux/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh (revision 06ed6aa56ffac9241e03a24649e8d048f8f1b10c)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test devlink-trap L3 exceptions functionality over mlxsw.
5# Check all exception traps to make sure they are triggered under the right
6# conditions.
7
8# +---------------------------------+
9# | H1 (vrf)                        |
10# |    + $h1                        |
11# |    | 192.0.2.1/24               |
12# |    | 2001:db8:1::1/64           |
13# |    |                            |
14# |    |  default via 192.0.2.2     |
15# |    |  default via 2001:db8:1::2 |
16# +----|----------------------------+
17#      |
18# +----|----------------------------------------------------------------------+
19# | SW |                                                                      |
20# |    + $rp1                                                                 |
21# |        192.0.2.2/24                                                       |
22# |        2001:db8:1::2/64                                                   |
23# |                                                                           |
24# |        2001:db8:2::2/64                                                   |
25# |        198.51.100.2/24                                                    |
26# |    + $rp2                                                                 |
27# |    |                                                                      |
28# +----|----------------------------------------------------------------------+
29#      |
30# +----|----------------------------+
31# |    |  default via 198.51.100.2  |
32# |    |  default via 2001:db8:2::2 |
33# |    |                            |
34# |    | 2001:db8:2::1/64           |
35# |    | 198.51.100.1/24            |
36# |    + $h2                        |
37# | H2 (vrf)                        |
38# +---------------------------------+
39
40lib_dir=$(dirname $0)/../../../net/forwarding
41
42ALL_TESTS="
43	mtu_value_is_too_small_test
44	ttl_value_is_too_small_test
45	mc_reverse_path_forwarding_test
46	reject_route_test
47	unresolved_neigh_test
48	ipv4_lpm_miss_test
49	ipv6_lpm_miss_test
50"
51
52NUM_NETIFS=4
53source $lib_dir/lib.sh
54source $lib_dir/tc_common.sh
55source $lib_dir/devlink_lib.sh
56
57require_command $MCD
58require_command $MC_CLI
59table_name=selftests
60
61h1_create()
62{
63	simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
64
65	ip -4 route add default vrf v$h1 nexthop via 192.0.2.2
66	ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2
67
68	tc qdisc add dev $h1 clsact
69}
70
71h1_destroy()
72{
73	tc qdisc del dev $h1 clsact
74
75	ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2
76	ip -4 route del default vrf v$h1 nexthop via 192.0.2.2
77
78	simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
79}
80
81h2_create()
82{
83	simple_if_init $h2 198.51.100.1/24 2001:db8:2::1/64
84
85	ip -4 route add default vrf v$h2 nexthop via 198.51.100.2
86	ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2
87}
88
89h2_destroy()
90{
91	ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2
92	ip -4 route del default vrf v$h2 nexthop via 198.51.100.2
93
94	simple_if_fini $h2 198.51.100.1/24 2001:db8:2::1/64
95}
96
97router_create()
98{
99	ip link set dev $rp1 up
100	ip link set dev $rp2 up
101
102	tc qdisc add dev $rp2 clsact
103
104	__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
105	__addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64
106}
107
108router_destroy()
109{
110	__addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64
111	__addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64
112
113	tc qdisc del dev $rp2 clsact
114}
115
116setup_prepare()
117{
118	h1=${NETIFS[p1]}
119	rp1=${NETIFS[p2]}
120
121	rp2=${NETIFS[p3]}
122	h2=${NETIFS[p4]}
123
124	rp1mac=$(mac_get $rp1)
125
126	start_mcd
127
128	vrf_prepare
129	forwarding_enable
130
131	h1_create
132	h2_create
133
134	router_create
135}
136
137cleanup()
138{
139	pre_cleanup
140
141	router_destroy
142
143	h2_destroy
144	h1_destroy
145
146	forwarding_restore
147	vrf_cleanup
148
149	kill_mcd
150}
151
152ping_check()
153{
154	ping_do $h1 198.51.100.1
155	check_err $? "Packets that should not be trapped were trapped"
156}
157
158trap_action_check()
159{
160	local trap_name=$1; shift
161	local expected_action=$1; shift
162
163	action=$(devlink_trap_action_get $trap_name)
164	if [ "$action" != $expected_action ]; then
165		check_err 1 "Trap $trap_name has wrong action: $action"
166	fi
167}
168
169mtu_value_is_too_small_test()
170{
171	local trap_name="mtu_value_is_too_small"
172	local group_name="l3_drops"
173	local expected_action="trap"
174	local mz_pid
175
176	RET=0
177
178	ping_check $trap_name
179	trap_action_check $trap_name $expected_action
180
181	# type - Destination Unreachable
182	# code - Fragmentation Needed and Don't Fragment was Set
183	tc filter add dev $h1 ingress protocol ip pref 1 handle 101 \
184		flower skip_hw ip_proto icmp type 3 code 4 action pass
185
186	mtu_set $rp2 1300
187
188	# Generate IP packets bigger than router's MTU with don't fragment
189	# flag on.
190	$MZ $h1 -t udp "sp=54321,dp=12345,df" -p 1400 -c 0 -d 1msec -b $rp1mac \
191		-B 198.51.100.1 -q &
192	mz_pid=$!
193
194	devlink_trap_exception_test $trap_name $group_name
195
196	tc_check_packets_hitting "dev $h1 ingress" 101
197	check_err $? "Packets were not received to h1"
198
199	log_test "MTU value is too small"
200
201	mtu_restore $rp2
202
203	kill $mz_pid && wait $mz_pid &> /dev/null
204	tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
205}
206
207__ttl_value_is_too_small_test()
208{
209	local ttl_val=$1; shift
210	local trap_name="ttl_value_is_too_small"
211	local group_name="l3_drops"
212	local expected_action="trap"
213	local mz_pid
214
215	RET=0
216
217	ping_check $trap_name
218	trap_action_check $trap_name $expected_action
219
220	# type - Time Exceeded
221	# code - Time to Live exceeded in Transit
222	tc filter add dev $h1 ingress protocol ip pref 1 handle 101 \
223		 flower skip_hw ip_proto icmp type 11 code 0 action pass
224
225	# Generate IP packets with small TTL
226	$MZ $h1 -t udp "ttl=$ttl_val,sp=54321,dp=12345" -c 0 -d 1msec \
227		-b $rp1mac -B 198.51.100.1 -q &
228	mz_pid=$!
229
230	devlink_trap_exception_test $trap_name $group_name
231
232	tc_check_packets_hitting "dev $h1 ingress" 101
233	check_err $? "Packets were not received to h1"
234
235	log_test "TTL value is too small: TTL=$ttl_val"
236
237	kill $mz_pid && wait $mz_pid &> /dev/null
238	tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
239}
240
241ttl_value_is_too_small_test()
242{
243	__ttl_value_is_too_small_test 0
244	__ttl_value_is_too_small_test 1
245}
246
247start_mcd()
248{
249	SMCROUTEDIR="$(mktemp -d)"
250	for ((i = 1; i <= $NUM_NETIFS; ++i)); do
251		 echo "phyint ${NETIFS[p$i]} enable" >> \
252			 $SMCROUTEDIR/$table_name.conf
253	done
254
255	$MCD -N -I $table_name -f $SMCROUTEDIR/$table_name.conf \
256		-P $SMCROUTEDIR/$table_name.pid
257}
258
259kill_mcd()
260{
261	pkill $MCD
262	rm -rf $SMCROUTEDIR
263}
264
265__mc_reverse_path_forwarding_test()
266{
267	local desc=$1; shift
268	local src_ip=$1; shift
269	local dst_ip=$1; shift
270	local dst_mac=$1; shift
271	local proto=$1; shift
272	local flags=${1:-""}; shift
273	local trap_name="mc_reverse_path_forwarding"
274	local group_name="l3_drops"
275	local expected_action="trap"
276	local mz_pid
277
278	RET=0
279
280	ping_check $trap_name
281	trap_action_check $trap_name $expected_action
282
283	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
284		flower dst_ip $dst_ip ip_proto udp action drop
285
286	$MC_CLI -I $table_name add $rp1 $src_ip $dst_ip $rp2
287
288	# Generate packets to multicast address.
289	$MZ $h2 $flags -t udp "sp=54321,dp=12345" -c 0 -p 128 \
290		-a 00:11:22:33:44:55 -b $dst_mac \
291		-A $src_ip -B $dst_ip -q &
292
293	mz_pid=$!
294
295	devlink_trap_exception_test $trap_name $group_name
296
297	tc_check_packets "dev $rp2 egress" 101 0
298	check_err $? "Packets were not dropped"
299
300	log_test "Multicast reverse path forwarding: $desc"
301
302	kill $mz_pid && wait $mz_pid &> /dev/null
303	tc filter del dev $rp2 egress protocol $proto pref 1 handle 101 flower
304}
305
306mc_reverse_path_forwarding_test()
307{
308	__mc_reverse_path_forwarding_test "IPv4" "192.0.2.1" "225.1.2.3" \
309		"01:00:5e:01:02:03" "ip"
310	__mc_reverse_path_forwarding_test "IPv6" "2001:db8:1::1" "ff0e::3" \
311		"33:33:00:00:00:03" "ipv6" "-6"
312}
313
314__reject_route_test()
315{
316	local desc=$1; shift
317	local dst_ip=$1; shift
318	local proto=$1; shift
319	local ip_proto=$1; shift
320	local type=$1; shift
321	local code=$1; shift
322	local unreachable=$1; shift
323	local flags=${1:-""}; shift
324	local trap_name="reject_route"
325	local group_name="l3_drops"
326	local expected_action="trap"
327	local mz_pid
328
329	RET=0
330
331	ping_check $trap_name
332	trap_action_check $trap_name $expected_action
333
334	tc filter add dev $h1 ingress protocol $proto pref 1 handle 101 flower \
335		skip_hw ip_proto $ip_proto type $type code $code action pass
336
337	ip route add unreachable $unreachable
338
339	# Generate pacekts to h2. The destination IP is unreachable.
340	$MZ $flags $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
341		-B $dst_ip -q &
342	mz_pid=$!
343
344	devlink_trap_exception_test $trap_name $group_name
345
346	tc_check_packets_hitting "dev $h1 ingress" 101
347	check_err $? "ICMP packet was not received to h1"
348
349	log_test "Reject route: $desc"
350
351	kill $mz_pid && wait $mz_pid &> /dev/null
352	ip route del unreachable $unreachable
353	tc filter del dev $h1 ingress protocol $proto pref 1 handle 101 flower
354}
355
356reject_route_test()
357{
358	# type - Destination Unreachable
359	# code - Host Unreachable
360	__reject_route_test "IPv4" 198.51.100.1 "ip" "icmp" 3 1 \
361		"198.51.100.0/26"
362	# type - Destination Unreachable
363	# code - No Route
364	__reject_route_test "IPv6" 2001:db8:2::1 "ipv6" "icmpv6" 1 0 \
365		"2001:db8:2::0/66" "-6"
366}
367
368__host_miss_test()
369{
370	local desc=$1; shift
371	local dip=$1; shift
372	local trap_name="unresolved_neigh"
373	local group_name="l3_drops"
374	local expected_action="trap"
375	local mz_pid
376
377	RET=0
378
379	ping_check $trap_name
380	trap_action_check $trap_name $expected_action
381
382	ip neigh flush dev $rp2
383
384	t0_packets=$(devlink_trap_rx_packets_get $trap_name)
385
386	# Generate packets to h2 (will incur a unresolved neighbor).
387	# The ping should pass and devlink counters should be increased.
388	ping_do $h1 $dip
389	check_err $? "ping failed: $desc"
390
391	t1_packets=$(devlink_trap_rx_packets_get $trap_name)
392
393	if [[ $t0_packets -eq $t1_packets ]]; then
394		check_err 1 "Trap counter did not increase"
395	fi
396
397	log_test "Unresolved neigh: host miss: $desc"
398}
399
400__invalid_nexthop_test()
401{
402	local desc=$1; shift
403	local dip=$1; shift
404	local extra_add=$1; shift
405	local subnet=$1; shift
406	local via_add=$1; shift
407	local trap_name="unresolved_neigh"
408	local group_name="l3_drops"
409	local expected_action="trap"
410	local mz_pid
411
412	RET=0
413
414	ping_check $trap_name
415	trap_action_check $trap_name $expected_action
416
417	ip address add $extra_add/$subnet dev $h2
418
419	# Check that correct route does not trigger unresolved_neigh
420	ip $flags route add $dip via $extra_add dev $rp2
421
422	# Generate packets in order to discover all neighbours.
423	# Without it, counters of unresolved_neigh will be increased
424	# during neighbours discovery and the check below will fail
425	# for a wrong reason
426	ping_do $h1 $dip
427
428	t0_packets=$(devlink_trap_rx_packets_get $trap_name)
429	ping_do $h1 $dip
430	t1_packets=$(devlink_trap_rx_packets_get $trap_name)
431
432	if [[ $t0_packets -ne $t1_packets ]]; then
433		check_err 1 "Trap counter increased when it should not"
434	fi
435
436	ip $flags route del $dip via $extra_add dev $rp2
437
438	# Check that route to nexthop that does not exist trigger
439	# unresolved_neigh
440	ip $flags route add $dip via $via_add dev $h2
441
442	t0_packets=$(devlink_trap_rx_packets_get $trap_name)
443	ping_do $h1 $dip
444	t1_packets=$(devlink_trap_rx_packets_get $trap_name)
445
446	if [[ $t0_packets -eq $t1_packets ]]; then
447		check_err 1 "Trap counter did not increase"
448	fi
449
450	ip $flags route del $dip via $via_add dev $h2
451	ip address del $extra_add/$subnet dev $h2
452	log_test "Unresolved neigh: nexthop does not exist: $desc"
453}
454
455unresolved_neigh_test()
456{
457	__host_miss_test "IPv4" 198.51.100.1
458	__host_miss_test "IPv6" 2001:db8:2::1
459	__invalid_nexthop_test "IPv4" 198.51.100.1 198.51.100.3 24 198.51.100.4
460	__invalid_nexthop_test "IPv6" 2001:db8:2::1 2001:db8:2::3 64 \
461		2001:db8:2::4
462}
463
464vrf_without_routes_create()
465{
466	# VRF creating makes the links to be down and then up again.
467	# By default, IPv6 address is not saved after link becomes down.
468	# Save IPv6 address using sysctl configuration.
469	sysctl_set net.ipv6.conf.$rp1.keep_addr_on_down 1
470	sysctl_set net.ipv6.conf.$rp2.keep_addr_on_down 1
471
472	ip link add dev vrf1 type vrf table 101
473	ip link set dev $rp1 master vrf1
474	ip link set dev $rp2 master vrf1
475	ip link set dev vrf1 up
476
477	# Wait for rp1 and rp2 to be up
478	setup_wait
479}
480
481vrf_without_routes_destroy()
482{
483	ip link set dev $rp1 nomaster
484	ip link set dev $rp2 nomaster
485	ip link del dev vrf1
486
487	sysctl_restore net.ipv6.conf.$rp2.keep_addr_on_down
488	sysctl_restore net.ipv6.conf.$rp1.keep_addr_on_down
489
490	# Wait for interfaces to be up
491	setup_wait
492}
493
494ipv4_lpm_miss_test()
495{
496	local trap_name="ipv4_lpm_miss"
497	local group_name="l3_drops"
498	local expected_action="trap"
499	local mz_pid
500
501	RET=0
502
503	ping_check $trap_name
504	trap_action_check $trap_name $expected_action
505
506	# Create a VRF without a default route
507	vrf_without_routes_create
508
509	# Generate packets through a VRF without a matching route.
510	$MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
511		-B 203.0.113.1 -q &
512	mz_pid=$!
513
514	devlink_trap_exception_test $trap_name $group_name
515
516	log_test "LPM miss: IPv4"
517
518	kill $mz_pid && wait $mz_pid &> /dev/null
519	vrf_without_routes_destroy
520}
521
522ipv6_lpm_miss_test()
523{
524	local trap_name="ipv6_lpm_miss"
525	local group_name="l3_drops"
526	local expected_action="trap"
527	local mz_pid
528
529	RET=0
530
531	ping_check $trap_name
532	trap_action_check $trap_name $expected_action
533
534	# Create a VRF without a default route
535	vrf_without_routes_create
536
537	# Generate packets through a VRF without a matching route.
538	$MZ -6 $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
539		-B 2001:db8::1 -q &
540	mz_pid=$!
541
542	devlink_trap_exception_test $trap_name $group_name
543
544	log_test "LPM miss: IPv6"
545
546	kill $mz_pid && wait $mz_pid &> /dev/null
547	vrf_without_routes_destroy
548}
549
550trap cleanup EXIT
551
552setup_prepare
553setup_wait
554
555tests_run
556
557exit $EXIT_STATUS
558