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"
54
55NUM_NETIFS=4
56source $lib_dir/lib.sh
57source $lib_dir/tc_common.sh
58source $lib_dir/devlink_lib.sh
59
60h1_create()
61{
62	simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
63
64	ip -4 route add default vrf v$h1 nexthop via 192.0.2.2
65	ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2
66}
67
68h1_destroy()
69{
70	ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2
71	ip -4 route del default vrf v$h1 nexthop via 192.0.2.2
72
73	simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
74}
75
76h2_create()
77{
78	simple_if_init $h2 $h2_ipv4/24 $h2_ipv6/64
79
80	ip -4 route add default vrf v$h2 nexthop via 198.51.100.2
81	ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2
82}
83
84h2_destroy()
85{
86	ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2
87	ip -4 route del default vrf v$h2 nexthop via 198.51.100.2
88
89	simple_if_fini $h2 $h2_ipv4/24 $h2_ipv6/64
90}
91
92router_create()
93{
94	ip link set dev $rp1 up
95	ip link set dev $rp2 up
96
97	tc qdisc add dev $rp2 clsact
98
99	__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
100	__addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64
101}
102
103router_destroy()
104{
105	__addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64
106	__addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64
107
108	tc qdisc del dev $rp2 clsact
109}
110
111setup_prepare()
112{
113	h1=${NETIFS[p1]}
114	rp1=${NETIFS[p2]}
115
116	rp2=${NETIFS[p3]}
117	h2=${NETIFS[p4]}
118
119	h1mac=$(mac_get $h1)
120	rp1mac=$(mac_get $rp1)
121
122	h1_ipv4=192.0.2.1
123	h2_ipv4=198.51.100.1
124	h1_ipv6=2001:db8:1::1
125	h2_ipv6=2001:db8:2::1
126
127	vrf_prepare
128	forwarding_enable
129
130	h1_create
131	h2_create
132
133	router_create
134}
135
136cleanup()
137{
138	pre_cleanup
139
140	router_destroy
141
142	h2_destroy
143	h1_destroy
144
145	forwarding_restore
146	vrf_cleanup
147}
148
149ping_check()
150{
151	trap_name=$1; shift
152
153	devlink_trap_action_set $trap_name "trap"
154	ping_do $h1 $h2_ipv4
155	check_err $? "Packets that should not be trapped were trapped"
156	devlink_trap_action_set $trap_name "drop"
157}
158
159non_ip_test()
160{
161	local trap_name="non_ip"
162	local group_name="l3_drops"
163	local mz_pid
164
165	RET=0
166
167	ping_check $trap_name
168
169	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
170		flower dst_ip $h2_ipv4 action drop
171
172	# Generate non-IP packets to the router
173	$MZ $h1 -c 0 -p 100 -d 1msec -B $h2_ipv4 -q "$rp1mac $h1mac \
174		00:00 de:ad:be:ef" &
175	mz_pid=$!
176
177	devlink_trap_drop_test $trap_name $group_name $rp2
178
179	log_test "Non IP"
180
181	devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
182}
183
184__uc_dip_over_mc_dmac_test()
185{
186	local desc=$1; shift
187	local proto=$1; shift
188	local dip=$1; shift
189	local flags=${1:-""}; shift
190	local trap_name="uc_dip_over_mc_dmac"
191	local group_name="l3_drops"
192	local dmac=01:02:03:04:05:06
193	local mz_pid
194
195	RET=0
196
197	ping_check $trap_name
198
199	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
200		flower ip_proto udp src_port 54321 dst_port 12345 action drop
201
202	# Generate IP packets with a unicast IP and a multicast destination MAC
203	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $dmac \
204		-B $dip -d 1msec -q &
205	mz_pid=$!
206
207	devlink_trap_drop_test $trap_name $group_name $rp2
208
209	log_test "Unicast destination IP over multicast destination MAC: $desc"
210
211	devlink_trap_drop_cleanup $mz_pid $rp2 $proto
212}
213
214uc_dip_over_mc_dmac_test()
215{
216	__uc_dip_over_mc_dmac_test "IPv4" "ip" $h2_ipv4
217	__uc_dip_over_mc_dmac_test "IPv6" "ipv6" $h2_ipv6 "-6"
218}
219
220__sip_is_loopback_test()
221{
222	local desc=$1; shift
223	local proto=$1; shift
224	local sip=$1; shift
225	local dip=$1; shift
226	local flags=${1:-""}; shift
227	local trap_name="sip_is_loopback_address"
228	local group_name="l3_drops"
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 $group_name $rp2
244
245	log_test "Source IP is loopback address: $desc"
246
247	devlink_trap_drop_cleanup $mz_pid $rp2 $proto
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 group_name="l3_drops"
264	local mz_pid
265
266	RET=0
267
268	ping_check $trap_name
269
270	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
271		flower dst_ip $dip action drop
272
273	# Generate packets with loopback destination IP
274	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
275		-B $dip -d 1msec -q &
276	mz_pid=$!
277
278	devlink_trap_drop_test $trap_name $group_name $rp2
279
280	log_test "Destination IP is loopback address: $desc"
281
282	devlink_trap_drop_cleanup $mz_pid $rp2 $proto
283}
284
285dip_is_loopback_test()
286{
287	__dip_is_loopback_test "IPv4" "ip" "127.0.0.0/8"
288	__dip_is_loopback_test "IPv6" "ipv6" "::1" "-6"
289}
290
291__sip_is_mc_test()
292{
293	local desc=$1; shift
294	local proto=$1; shift
295	local sip=$1; shift
296	local dip=$1; shift
297	local flags=${1:-""}; shift
298	local trap_name="sip_is_mc"
299	local group_name="l3_drops"
300	local mz_pid
301
302	RET=0
303
304	ping_check $trap_name
305
306	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
307		flower src_ip $sip action drop
308
309	# Generate packets with multicast source IP
310	$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \
311		-b $rp1mac -B $dip -d 1msec -q &
312	mz_pid=$!
313
314	devlink_trap_drop_test $trap_name $group_name $rp2
315
316	log_test "Source IP is multicast: $desc"
317
318	devlink_trap_drop_cleanup $mz_pid $rp2 $proto
319}
320
321sip_is_mc_test()
322{
323	__sip_is_mc_test "IPv4" "ip" "239.1.1.1" $h2_ipv4
324	__sip_is_mc_test "IPv6" "ipv6" "FF02::2" $h2_ipv6 "-6"
325}
326
327ipv4_sip_is_limited_bc_test()
328{
329	local trap_name="ipv4_sip_is_limited_bc"
330	local group_name="l3_drops"
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 $group_name $rp2
347
348	log_test "IPv4 source IP is limited broadcast"
349
350	devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
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 group_name="l3_drops"
384	local payload
385	local mz_pid
386
387	RET=0
388
389	ping_check $trap_name
390
391	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
392		flower dst_ip $h2_ipv4 action drop
393
394	payload=$(ipv4_payload_get $ipver $ihl $checksum)
395
396	# Generate packets with corrupted IP header
397	$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
398	mz_pid=$!
399
400	devlink_trap_drop_test $trap_name $group_name $rp2
401
402	log_test "IP header corrupted: $desc: IPv4"
403
404	devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
405}
406
407ipv6_payload_get()
408{
409	local ipver=$1; shift
410
411	p=$(:
412		)"86:DD:"$(                  : ETH type
413		)"$ipver"$(                  : IP version
414		)"0:0:"$(                    : Traffic class
415		)"0:00:00:"$(		     : Flow label
416		)"00:00:"$(                  : Payload length
417		)"01:"$(                     : Next header
418		)"04:"$(                     : Hop limit
419		)"$h1_ipv6:"$(      	     : IP saddr
420		)"$h2_ipv6:"$(               : IP daddr
421		)
422	echo $p
423}
424
425__ipv6_header_corrupted_test()
426{
427	local desc=$1; shift
428	local ipver=$1; shift
429	local trap_name="ip_header_corrupted"
430	local group_name="l3_drops"
431	local payload
432	local mz_pid
433
434	RET=0
435
436	ping_check $trap_name
437
438	tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
439		flower dst_ip $h2_ipv4 action drop
440
441	payload=$(ipv6_payload_get $ipver)
442
443	# Generate packets with corrupted IP header
444	$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
445	mz_pid=$!
446
447	devlink_trap_drop_test $trap_name $group_name $rp2
448
449	log_test "IP header corrupted: $desc: IPv6"
450
451	devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
452}
453
454ip_header_corrupted_test()
455{
456	# Each test uses one wrong value. The three values below are correct.
457	local ipv="4"
458	local ihl="5"
459	local checksum="00:F4"
460
461	__ipv4_header_corrupted_test "wrong IP version" 5 $ihl $checksum
462	__ipv4_header_corrupted_test "wrong IHL" $ipv 4 $checksum
463	__ipv4_header_corrupted_test "wrong checksum" $ipv $ihl "00:00"
464	__ipv6_header_corrupted_test "wrong IP version" 5
465}
466
467ipv6_mc_dip_reserved_scope_test()
468{
469	local trap_name="ipv6_mc_dip_reserved_scope"
470	local group_name="l3_drops"
471	local dip=FF00::
472	local mz_pid
473
474	RET=0
475
476	ping_check $trap_name
477
478	tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
479		flower dst_ip $dip action drop
480
481	# Generate packets with reserved scope destination IP
482	$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
483		"33:33:00:00:00:00" -B $dip -d 1msec -q &
484	mz_pid=$!
485
486	devlink_trap_drop_test $trap_name $group_name $rp2
487
488	log_test "IPv6 multicast destination IP reserved scope"
489
490	devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6"
491}
492
493ipv6_mc_dip_interface_local_scope_test()
494{
495	local trap_name="ipv6_mc_dip_interface_local_scope"
496	local group_name="l3_drops"
497	local dip=FF01::
498	local mz_pid
499
500	RET=0
501
502	ping_check $trap_name
503
504	tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
505		flower dst_ip $dip action drop
506
507	# Generate packets with interface local scope destination IP
508	$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
509		"33:33:00:00:00:00" -B $dip -d 1msec -q &
510	mz_pid=$!
511
512	devlink_trap_drop_test $trap_name $group_name $rp2
513
514	log_test "IPv6 multicast destination IP interface-local scope"
515
516	devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6"
517}
518
519__blackhole_route_test()
520{
521	local flags=$1; shift
522	local subnet=$1; shift
523	local proto=$1; shift
524	local dip=$1; shift
525	local ip_proto=${1:-"icmp"}; shift
526	local trap_name="blackhole_route"
527	local group_name="l3_drops"
528	local mz_pid
529
530	RET=0
531
532	ping_check $trap_name
533
534	ip -$flags route add blackhole $subnet
535	tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
536		flower skip_hw dst_ip $dip ip_proto $ip_proto action drop
537
538	# Generate packets to the blackhole route
539	$MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
540		-B $dip -d 1msec -q &
541	mz_pid=$!
542
543	devlink_trap_drop_test $trap_name $group_name $rp2
544	log_test "Blackhole route: IPv$flags"
545
546	devlink_trap_drop_cleanup $mz_pid $rp2 $proto
547	ip -$flags route del blackhole $subnet
548}
549
550blackhole_route_test()
551{
552	__blackhole_route_test "4" "198.51.100.0/30" "ip" $h2_ipv4
553	__blackhole_route_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6 "icmpv6"
554}
555
556trap cleanup EXIT
557
558setup_prepare
559setup_wait
560
561tests_run
562
563exit $EXIT_STATUS
564