1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test devlink-trap L3 drops functionality over mlxsw. Each registered L3 drop
5# packet trap is tested to make sure it is 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	non_ip_test
44	uc_dip_over_mc_dmac_test
45	dip_is_loopback_test
46	sip_is_mc_test
47	sip_is_loopback_test
48	ip_header_corrupted_test
49	ipv4_sip_is_limited_bc_test
50	ipv6_mc_dip_reserved_scope_test
51	ipv6_mc_dip_interface_local_scope_test
52	blackhole_route_test
53	irif_disabled_test
54	erif_disabled_test
55	blackhole_nexthop_test
56"
57
58NUM_NETIFS=4
59source $lib_dir/lib.sh
60source $lib_dir/tc_common.sh
61source $lib_dir/devlink_lib.sh
62
63h1_create()
64{
65	simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
66
67	ip -4 route add default vrf v$h1 nexthop via 192.0.2.2
68	ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2
69}
70
71h1_destroy()
72{
73	ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2
74	ip -4 route del default vrf v$h1 nexthop via 192.0.2.2
75
76	simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
77}
78
79h2_create()
80{
81	simple_if_init $h2 $h2_ipv4/24 $h2_ipv6/64
82
83	ip -4 route add default vrf v$h2 nexthop via 198.51.100.2
84	ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2
85}
86
87h2_destroy()
88{
89	ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2
90	ip -4 route del default vrf v$h2 nexthop via 198.51.100.2
91
92	simple_if_fini $h2 $h2_ipv4/24 $h2_ipv6/64
93}
94
95router_create()
96{
97	ip link set dev $rp1 up
98	ip link set dev $rp2 up
99
100	tc qdisc add dev $rp2 clsact
101
102	__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
103	__addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64
104}
105
106router_destroy()
107{
108	__addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64
109	__addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64
110
111	tc qdisc del dev $rp2 clsact
112}
113
114setup_prepare()
115{
116	h1=${NETIFS[p1]}
117	rp1=${NETIFS[p2]}
118
119	rp2=${NETIFS[p3]}
120	h2=${NETIFS[p4]}
121
122	h1mac=$(mac_get $h1)
123	rp1mac=$(mac_get $rp1)
124
125	h1_ipv4=192.0.2.1
126	h2_ipv4=198.51.100.1
127	h1_ipv6=2001:db8:1::1
128	h2_ipv6=2001:db8:2::1
129
130	vrf_prepare
131	forwarding_enable
132
133	h1_create
134	h2_create
135
136	router_create
137}
138
139cleanup()
140{
141	pre_cleanup
142
143	router_destroy
144
145	h2_destroy
146	h1_destroy
147
148	forwarding_restore
149	vrf_cleanup
150}
151
152ping_check()
153{
154	trap_name=$1; shift
155
156	devlink_trap_action_set $trap_name "trap"
157	ping_do $h1 $h2_ipv4
158	check_err $? "Packets that should not be trapped were trapped"
159	devlink_trap_action_set $trap_name "drop"
160}
161
162non_ip_test()
163{
164	local trap_name="non_ip"
165	local mz_pid
166
167	RET=0
168
169	ping_check $trap_name
170
171	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
172		flower dst_ip $h2_ipv4 action drop
173
174	# Generate non-IP packets to the router
175	$MZ $h1 -c 0 -p 100 -d 1msec -B $h2_ipv4 -q "$rp1mac $h1mac \
176		00:00 de:ad:be:ef" &
177	mz_pid=$!
178
179	devlink_trap_drop_test $trap_name $rp2 101
180
181	log_test "Non IP"
182
183	devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101
184}
185
186__uc_dip_over_mc_dmac_test()
187{
188	local desc=$1; shift
189	local proto=$1; shift
190	local dip=$1; shift
191	local flags=${1:-""}; shift
192	local trap_name="uc_dip_over_mc_dmac"
193	local dmac=01:02:03:04:05:06
194	local mz_pid
195
196	RET=0
197
198	ping_check $trap_name
199
200	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
201		flower ip_proto udp src_port 54321 dst_port 12345 action drop
202
203	# Generate IP packets with a unicast IP and a multicast destination MAC
204	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $dmac \
205		-B $dip -d 1msec -q &
206	mz_pid=$!
207
208	devlink_trap_drop_test $trap_name $rp2 101
209
210	log_test "Unicast destination IP over multicast destination MAC: $desc"
211
212	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
213}
214
215uc_dip_over_mc_dmac_test()
216{
217	__uc_dip_over_mc_dmac_test "IPv4" "ip" $h2_ipv4
218	__uc_dip_over_mc_dmac_test "IPv6" "ipv6" $h2_ipv6 "-6"
219}
220
221__sip_is_loopback_test()
222{
223	local desc=$1; shift
224	local proto=$1; shift
225	local sip=$1; shift
226	local dip=$1; shift
227	local flags=${1:-""}; shift
228	local trap_name="sip_is_loopback_address"
229	local mz_pid
230
231	RET=0
232
233	ping_check $trap_name
234
235	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
236		flower src_ip $sip action drop
237
238	# Generate packets with loopback source IP
239	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \
240		-b $rp1mac -B $dip -d 1msec -q &
241	mz_pid=$!
242
243	devlink_trap_drop_test $trap_name $rp2 101
244
245	log_test "Source IP is loopback address: $desc"
246
247	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
248}
249
250sip_is_loopback_test()
251{
252	__sip_is_loopback_test "IPv4" "ip" "127.0.0.0/8" $h2_ipv4
253	__sip_is_loopback_test "IPv6" "ipv6" "::1" $h2_ipv6 "-6"
254}
255
256__dip_is_loopback_test()
257{
258	local desc=$1; shift
259	local proto=$1; shift
260	local dip=$1; shift
261	local flags=${1:-""}; shift
262	local trap_name="dip_is_loopback_address"
263	local mz_pid
264
265	RET=0
266
267	ping_check $trap_name
268
269	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
270		flower dst_ip $dip action drop
271
272	# Generate packets with loopback destination IP
273	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
274		-B $dip -d 1msec -q &
275	mz_pid=$!
276
277	devlink_trap_drop_test $trap_name $rp2 101
278
279	log_test "Destination IP is loopback address: $desc"
280
281	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
282}
283
284dip_is_loopback_test()
285{
286	__dip_is_loopback_test "IPv4" "ip" "127.0.0.0/8"
287	__dip_is_loopback_test "IPv6" "ipv6" "::1" "-6"
288}
289
290__sip_is_mc_test()
291{
292	local desc=$1; shift
293	local proto=$1; shift
294	local sip=$1; shift
295	local dip=$1; shift
296	local flags=${1:-""}; shift
297	local trap_name="sip_is_mc"
298	local mz_pid
299
300	RET=0
301
302	ping_check $trap_name
303
304	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
305		flower src_ip $sip action drop
306
307	# Generate packets with multicast source IP
308	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \
309		-b $rp1mac -B $dip -d 1msec -q &
310	mz_pid=$!
311
312	devlink_trap_drop_test $trap_name $rp2 101
313
314	log_test "Source IP is multicast: $desc"
315
316	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
317}
318
319sip_is_mc_test()
320{
321	__sip_is_mc_test "IPv4" "ip" "239.1.1.1" $h2_ipv4
322	__sip_is_mc_test "IPv6" "ipv6" "FF02::2" $h2_ipv6 "-6"
323}
324
325ipv4_sip_is_limited_bc_test()
326{
327	local trap_name="ipv4_sip_is_limited_bc"
328	local sip=255.255.255.255
329	local mz_pid
330
331	RET=0
332
333	ping_check $trap_name
334
335	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
336		flower src_ip $sip action drop
337
338	# Generate packets with limited broadcast source IP
339	$MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip -b $rp1mac \
340		-B $h2_ipv4 -d 1msec -q &
341	mz_pid=$!
342
343	devlink_trap_drop_test $trap_name $rp2 101
344
345	log_test "IPv4 source IP is limited broadcast"
346
347	devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101
348}
349
350ipv4_payload_get()
351{
352	local ipver=$1; shift
353	local ihl=$1; shift
354	local checksum=$1; shift
355
356	p=$(:
357		)"08:00:"$(                   : ETH type
358		)"$ipver"$(                   : IP version
359		)"$ihl:"$(                    : IHL
360		)"00:"$(		      : IP TOS
361		)"00:F4:"$(                   : IP total length
362		)"00:00:"$(                   : IP identification
363		)"20:00:"$(                   : IP flags + frag off
364		)"30:"$(                      : IP TTL
365		)"01:"$(                      : IP proto
366		)"$checksum:"$(               : IP header csum
367		)"$h1_ipv4:"$(                : IP saddr
368	        )"$h2_ipv4:"$(                : IP daddr
369		)
370	echo $p
371}
372
373__ipv4_header_corrupted_test()
374{
375	local desc=$1; shift
376	local ipver=$1; shift
377	local ihl=$1; shift
378	local checksum=$1; shift
379	local trap_name="ip_header_corrupted"
380	local payload
381	local mz_pid
382
383	RET=0
384
385	ping_check $trap_name
386
387	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
388		flower dst_ip $h2_ipv4 action drop
389
390	payload=$(ipv4_payload_get $ipver $ihl $checksum)
391
392	# Generate packets with corrupted IP header
393	$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
394	mz_pid=$!
395
396	devlink_trap_drop_test $trap_name $rp2 101
397
398	log_test "IP header corrupted: $desc: IPv4"
399
400	devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101
401}
402
403ipv6_payload_get()
404{
405	local ipver=$1; shift
406
407	p=$(:
408		)"86:DD:"$(                  : ETH type
409		)"$ipver"$(                  : IP version
410		)"0:0:"$(                    : Traffic class
411		)"0:00:00:"$(		     : Flow label
412		)"00:00:"$(                  : Payload length
413		)"01:"$(                     : Next header
414		)"04:"$(                     : Hop limit
415		)"$h1_ipv6:"$(      	     : IP saddr
416		)"$h2_ipv6:"$(               : IP daddr
417		)
418	echo $p
419}
420
421__ipv6_header_corrupted_test()
422{
423	local desc=$1; shift
424	local ipver=$1; shift
425	local trap_name="ip_header_corrupted"
426	local payload
427	local mz_pid
428
429	RET=0
430
431	ping_check $trap_name
432
433	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
434		flower dst_ip $h2_ipv4 action drop
435
436	payload=$(ipv6_payload_get $ipver)
437
438	# Generate packets with corrupted IP header
439	$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
440	mz_pid=$!
441
442	devlink_trap_drop_test $trap_name $rp2 101
443
444	log_test "IP header corrupted: $desc: IPv6"
445
446	devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101
447}
448
449ip_header_corrupted_test()
450{
451	# Each test uses one wrong value. The three values below are correct.
452	local ipv="4"
453	local ihl="5"
454	local checksum="00:F4"
455
456	__ipv4_header_corrupted_test "wrong IP version" 5 $ihl $checksum
457	__ipv4_header_corrupted_test "wrong IHL" $ipv 4 $checksum
458	__ipv4_header_corrupted_test "wrong checksum" $ipv $ihl "00:00"
459	__ipv6_header_corrupted_test "wrong IP version" 5
460}
461
462ipv6_mc_dip_reserved_scope_test()
463{
464	local trap_name="ipv6_mc_dip_reserved_scope"
465	local dip=FF00::
466	local mz_pid
467
468	RET=0
469
470	ping_check $trap_name
471
472	tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
473		flower dst_ip $dip action drop
474
475	# Generate packets with reserved scope destination IP
476	$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
477		"33:33:00:00:00:00" -B $dip -d 1msec -q &
478	mz_pid=$!
479
480	devlink_trap_drop_test $trap_name $rp2 101
481
482	log_test "IPv6 multicast destination IP reserved scope"
483
484	devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6" 1 101
485}
486
487ipv6_mc_dip_interface_local_scope_test()
488{
489	local trap_name="ipv6_mc_dip_interface_local_scope"
490	local dip=FF01::
491	local mz_pid
492
493	RET=0
494
495	ping_check $trap_name
496
497	tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
498		flower dst_ip $dip action drop
499
500	# Generate packets with interface local scope destination IP
501	$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
502		"33:33:00:00:00:00" -B $dip -d 1msec -q &
503	mz_pid=$!
504
505	devlink_trap_drop_test $trap_name $rp2 101
506
507	log_test "IPv6 multicast destination IP interface-local scope"
508
509	devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6" 1 101
510}
511
512__blackhole_route_test()
513{
514	local flags=$1; shift
515	local subnet=$1; shift
516	local proto=$1; shift
517	local dip=$1; shift
518	local ip_proto=${1:-"icmp"}; shift
519	local trap_name="blackhole_route"
520	local mz_pid
521
522	RET=0
523
524	ping_check $trap_name
525
526	ip -$flags route add blackhole $subnet
527	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
528		flower skip_hw dst_ip $dip ip_proto $ip_proto action drop
529
530	# Generate packets to the blackhole route
531	$MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
532		-B $dip -d 1msec -q &
533	mz_pid=$!
534
535	devlink_trap_drop_test $trap_name $rp2 101
536	log_test "Blackhole route: IPv$flags"
537
538	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
539	ip -$flags route del blackhole $subnet
540}
541
542blackhole_route_test()
543{
544	__blackhole_route_test "4" "198.51.100.0/30" "ip" $h2_ipv4
545	__blackhole_route_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6 "icmpv6"
546}
547
548irif_disabled_test()
549{
550	local trap_name="irif_disabled"
551	local t0_packets t0_bytes
552	local t1_packets t1_bytes
553	local mz_pid
554
555	RET=0
556
557	ping_check $trap_name
558
559	devlink_trap_action_set $trap_name "trap"
560
561	# When RIF of a physical port ("Sub-port RIF") is destroyed, we first
562	# block the STP of the {Port, VLAN} so packets cannot get into the RIF.
563	# Using bridge enables us to see this trap because when bridge is
564	# destroyed, there is a small time window that packets can go into the
565	# RIF, while it is disabled.
566	ip link add dev br0 type bridge
567	ip link set dev $rp1 master br0
568	ip address flush dev $rp1
569	__addr_add_del br0 add 192.0.2.2/24
570	ip li set dev br0 up
571
572	t0_packets=$(devlink_trap_rx_packets_get $trap_name)
573	t0_bytes=$(devlink_trap_rx_bytes_get $trap_name)
574
575	# Generate packets to h2 through br0 RIF that will be removed later
576	$MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -p 100 -a own -b $rp1mac \
577		-B $h2_ipv4 -q &
578	mz_pid=$!
579
580	# Wait before removing br0 RIF to allow packets to go into the bridge.
581	sleep 1
582
583	# Flushing address will dismantle the RIF
584	ip address flush dev br0
585
586	t1_packets=$(devlink_trap_rx_packets_get $trap_name)
587	t1_bytes=$(devlink_trap_rx_bytes_get $trap_name)
588
589	if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then
590		check_err 1 "Trap stats idle when packets should be trapped"
591	fi
592
593	log_test "Ingress RIF disabled"
594
595	kill $mz_pid && wait $mz_pid &> /dev/null
596	ip link set dev $rp1 nomaster
597	__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
598	ip link del dev br0 type bridge
599	devlink_trap_action_set $trap_name "drop"
600}
601
602erif_disabled_test()
603{
604	local trap_name="erif_disabled"
605	local t0_packets t0_bytes
606	local t1_packets t1_bytes
607	local mz_pid
608
609	RET=0
610
611	ping_check $trap_name
612
613	devlink_trap_action_set $trap_name "trap"
614	ip link add dev br0 type bridge
615	ip add flush dev $rp1
616	ip link set dev $rp1 master br0
617	__addr_add_del br0 add 192.0.2.2/24
618	ip link set dev br0 up
619
620	t0_packets=$(devlink_trap_rx_packets_get $trap_name)
621	t0_bytes=$(devlink_trap_rx_bytes_get $trap_name)
622
623	rp2mac=$(mac_get $rp2)
624
625	# Generate packets that should go out through br0 RIF that will be
626	# removed later
627	$MZ $h2 -t udp "sp=54321,dp=12345" -c 0 -p 100 -a own -b $rp2mac \
628		-B 192.0.2.1 -q &
629	mz_pid=$!
630
631	sleep 5
632	# Unlinking the port from the bridge will disable the RIF associated
633	# with br0 as it is no longer an upper of any mlxsw port.
634	ip link set dev $rp1 nomaster
635
636	t1_packets=$(devlink_trap_rx_packets_get $trap_name)
637	t1_bytes=$(devlink_trap_rx_bytes_get $trap_name)
638
639	if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then
640		check_err 1 "Trap stats idle when packets should be trapped"
641	fi
642
643	log_test "Egress RIF disabled"
644
645	kill $mz_pid && wait $mz_pid &> /dev/null
646	__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
647	ip link del dev br0 type bridge
648	devlink_trap_action_set $trap_name "drop"
649}
650
651__blackhole_nexthop_test()
652{
653	local flags=$1; shift
654	local subnet=$1; shift
655	local proto=$1; shift
656	local dip=$1; shift
657	local trap_name="blackhole_nexthop"
658	local mz_pid
659
660	RET=0
661
662	ip -$flags nexthop add id 1 blackhole
663	ip -$flags route add $subnet nhid 1
664	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
665		flower skip_hw dst_ip $dip ip_proto udp action drop
666
667	# Generate packets to the blackhole nexthop
668	$MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
669		-B $dip -d 1msec -q &
670	mz_pid=$!
671
672	devlink_trap_drop_test $trap_name $rp2 101
673	log_test "Blackhole nexthop: IPv$flags"
674
675	devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101
676	ip -$flags route del $subnet
677	ip -$flags nexthop del id 1
678}
679
680blackhole_nexthop_test()
681{
682	__blackhole_nexthop_test "4" "198.51.100.0/30" "ip" $h2_ipv4
683	__blackhole_nexthop_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6
684}
685
686trap cleanup EXIT
687
688setup_prepare
689setup_wait
690
691tests_run
692
693exit $EXIT_STATUS
694