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