1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is for checking the A-TCAM and C-TCAM operation in Spectrum-2.
5# It tries to exercise as many code paths in the eRP state machine as
6# possible.
7
8lib_dir=$(dirname $0)/../../../../net/forwarding
9
10ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
11	multiple_masks_test ctcam_edge_cases_test delta_simple_test \
12	delta_two_masks_one_key_test delta_simple_rehash_test \
13	bloom_simple_test bloom_complex_test bloom_delta_test"
14NUM_NETIFS=2
15source $lib_dir/lib.sh
16source $lib_dir/tc_common.sh
17source $lib_dir/devlink_lib.sh
18
19tcflags="skip_hw"
20
21h1_create()
22{
23	simple_if_init $h1 192.0.2.1/24 198.51.100.1/24
24}
25
26h1_destroy()
27{
28	simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24
29}
30
31h2_create()
32{
33	simple_if_init $h2 192.0.2.2/24 198.51.100.2/24
34	tc qdisc add dev $h2 clsact
35}
36
37h2_destroy()
38{
39	tc qdisc del dev $h2 clsact
40	simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24
41}
42
43tp_record()
44{
45	local tracepoint=$1
46	local cmd=$2
47
48	perf record -q -e $tracepoint $cmd
49	return $?
50}
51
52tp_record_all()
53{
54	local tracepoint=$1
55	local seconds=$2
56
57	perf record -a -q -e $tracepoint sleep $seconds
58	return $?
59}
60
61__tp_hit_count()
62{
63	local tracepoint=$1
64
65	local perf_output=`perf script -F trace:event,trace`
66	return `echo $perf_output | grep "$tracepoint:" | wc -l`
67}
68
69tp_check_hits()
70{
71	local tracepoint=$1
72	local count=$2
73
74	__tp_hit_count $tracepoint
75	if [[ "$?" -ne "$count" ]]; then
76		return 1
77	fi
78	return 0
79}
80
81tp_check_hits_any()
82{
83	local tracepoint=$1
84
85	__tp_hit_count $tracepoint
86	if [[ "$?" -eq "0" ]]; then
87		return 1
88	fi
89	return 0
90}
91
92single_mask_test()
93{
94	# When only a single mask is required, the device uses the master
95	# mask and not the eRP table. Verify that under this mode the right
96	# filter is matched
97
98	RET=0
99
100	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
101		$tcflags dst_ip 192.0.2.2 action drop
102
103	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
104		-t ip -q
105
106	tc_check_packets "dev $h2 ingress" 101 1
107	check_err $? "Single filter - did not match"
108
109	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
110		$tcflags dst_ip 198.51.100.2 action drop
111
112	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
113		-t ip -q
114
115	tc_check_packets "dev $h2 ingress" 101 2
116	check_err $? "Two filters - did not match highest priority"
117
118	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
119		-t ip -q
120
121	tc_check_packets "dev $h2 ingress" 102 1
122	check_err $? "Two filters - did not match lowest priority"
123
124	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
125
126	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
127		-t ip -q
128
129	tc_check_packets "dev $h2 ingress" 102 2
130	check_err $? "Single filter - did not match after delete"
131
132	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
133
134	log_test "single mask test ($tcflags)"
135}
136
137identical_filters_test()
138{
139	# When two filters that only differ in their priority are used,
140	# one needs to be inserted into the C-TCAM. This test verifies
141	# that filters are correctly spilled to C-TCAM and that the right
142	# filter is matched
143
144	RET=0
145
146	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
147		$tcflags dst_ip 192.0.2.2 action drop
148	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
149		$tcflags dst_ip 192.0.2.2 action drop
150
151	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
152		-t ip -q
153
154	tc_check_packets "dev $h2 ingress" 101 1
155	check_err $? "Did not match A-TCAM filter"
156
157	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
158
159	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
160		-t ip -q
161
162	tc_check_packets "dev $h2 ingress" 102 1
163	check_err $? "Did not match C-TCAM filter after A-TCAM delete"
164
165	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
166		$tcflags dst_ip 192.0.2.2 action drop
167
168	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
169		-t ip -q
170
171	tc_check_packets "dev $h2 ingress" 102 2
172	check_err $? "Did not match C-TCAM filter after A-TCAM add"
173
174	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
175
176	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
177		-t ip -q
178
179	tc_check_packets "dev $h2 ingress" 103 1
180	check_err $? "Did not match A-TCAM filter after C-TCAM delete"
181
182	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
183
184	log_test "identical filters test ($tcflags)"
185}
186
187two_masks_test()
188{
189	# When more than one mask is required, the eRP table is used. This
190	# test verifies that the eRP table is correctly allocated and used
191
192	RET=0
193
194	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
195		$tcflags dst_ip 192.0.2.2 action drop
196	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
197		$tcflags dst_ip 192.0.0.0/8 action drop
198
199	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
200		-t ip -q
201
202	tc_check_packets "dev $h2 ingress" 101 1
203	check_err $? "Two filters - did not match highest priority"
204
205	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
206
207	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
208		-t ip -q
209
210	tc_check_packets "dev $h2 ingress" 103 1
211	check_err $? "Single filter - did not match"
212
213	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
214		$tcflags dst_ip 192.0.2.0/24 action drop
215
216	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
217		-t ip -q
218
219	tc_check_packets "dev $h2 ingress" 102 1
220	check_err $? "Two filters - did not match highest priority after add"
221
222	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
223	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
224
225	log_test "two masks test ($tcflags)"
226}
227
228multiple_masks_test()
229{
230	# The number of masks in a region is limited. Once the maximum
231	# number of masks has been reached filters that require new
232	# masks are spilled to the C-TCAM. This test verifies that
233	# spillage is performed correctly and that the right filter is
234	# matched
235
236	if [[ "$tcflags" != "skip_sw" ]]; then
237		return 0;
238	fi
239
240	local index
241
242	RET=0
243
244	NUM_MASKS=32
245	NUM_ERPS=16
246	BASE_INDEX=100
247
248	for i in $(eval echo {1..$NUM_MASKS}); do
249		index=$((BASE_INDEX - i))
250
251		if ((i > NUM_ERPS)); then
252			exp_hits=1
253			err_msg="$i filters - C-TCAM spill did not happen when it was expected"
254		else
255			exp_hits=0
256			err_msg="$i filters - C-TCAM spill happened when it should not"
257		fi
258
259		tp_record "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" \
260			"tc filter add dev $h2 ingress protocol ip pref $index \
261				handle $index \
262				flower $tcflags \
263				dst_ip 192.0.2.2/${i} src_ip 192.0.2.1/${i} \
264				action drop"
265		tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" \
266				$exp_hits
267		check_err $? "$err_msg"
268
269		$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
270			-B 192.0.2.2 -t ip -q
271
272		tc_check_packets "dev $h2 ingress" $index 1
273		check_err $? "$i filters - did not match highest priority (add)"
274	done
275
276	for i in $(eval echo {$NUM_MASKS..1}); do
277		index=$((BASE_INDEX - i))
278
279		$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
280			-B 192.0.2.2 -t ip -q
281
282		tc_check_packets "dev $h2 ingress" $index 2
283		check_err $? "$i filters - did not match highest priority (del)"
284
285		tc filter del dev $h2 ingress protocol ip pref $index \
286			handle $index flower
287	done
288
289	log_test "multiple masks test ($tcflags)"
290}
291
292ctcam_two_atcam_masks_test()
293{
294	RET=0
295
296	# First case: C-TCAM is disabled when there are two A-TCAM masks.
297	# We push a filter into the C-TCAM by using two identical filters
298	# as in identical_filters_test()
299
300	# Filter goes into A-TCAM
301	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
302		$tcflags dst_ip 192.0.2.2 action drop
303	# Filter goes into C-TCAM
304	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
305		$tcflags dst_ip 192.0.2.2 action drop
306	# Filter goes into A-TCAM
307	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
308		$tcflags dst_ip 192.0.0.0/16 action drop
309
310	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
311		-t ip -q
312
313	tc_check_packets "dev $h2 ingress" 101 1
314	check_err $? "Did not match A-TCAM filter"
315
316	# Delete both A-TCAM and C-TCAM filters and make sure the remaining
317	# A-TCAM filter still works
318	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
319	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
320
321	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
322		-t ip -q
323
324	tc_check_packets "dev $h2 ingress" 103 1
325	check_err $? "Did not match A-TCAM filter"
326
327	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
328
329	log_test "ctcam with two atcam masks test ($tcflags)"
330}
331
332ctcam_one_atcam_mask_test()
333{
334	RET=0
335
336	# Second case: C-TCAM is disabled when there is one A-TCAM mask.
337	# The test is similar to identical_filters_test()
338
339	# Filter goes into A-TCAM
340	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
341		$tcflags dst_ip 192.0.2.2 action drop
342	# Filter goes into C-TCAM
343	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
344		$tcflags dst_ip 192.0.2.2 action drop
345
346	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
347		-t ip -q
348
349	tc_check_packets "dev $h2 ingress" 101 1
350	check_err $? "Did not match C-TCAM filter"
351
352	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
353
354	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
355		-t ip -q
356
357	tc_check_packets "dev $h2 ingress" 102 1
358	check_err $? "Did not match A-TCAM filter"
359
360	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
361
362	log_test "ctcam with one atcam mask test ($tcflags)"
363}
364
365ctcam_no_atcam_masks_test()
366{
367	RET=0
368
369	# Third case: C-TCAM is disabled when there are no A-TCAM masks
370	# This test exercises the code path that transitions the eRP table
371	# to its initial state after deleting the last C-TCAM mask
372
373	# Filter goes into A-TCAM
374	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
375		$tcflags dst_ip 192.0.2.2 action drop
376	# Filter goes into C-TCAM
377	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
378		$tcflags dst_ip 192.0.2.2 action drop
379
380	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
381	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
382
383	log_test "ctcam with no atcam masks test ($tcflags)"
384}
385
386ctcam_edge_cases_test()
387{
388	# When the C-TCAM is disabled after deleting the last C-TCAM
389	# mask, we want to make sure the eRP state machine is put in
390	# the correct state
391
392	ctcam_two_atcam_masks_test
393	ctcam_one_atcam_mask_test
394	ctcam_no_atcam_masks_test
395}
396
397delta_simple_test()
398{
399	# The first filter will create eRP, the second filter will fit into
400	# the first eRP with delta. Remove the first rule then and check that
401        # the eRP stays (referenced by the second filter).
402
403	RET=0
404
405	if [[ "$tcflags" != "skip_sw" ]]; then
406		return 0;
407	fi
408
409	tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
410		   pref 1 handle 101 flower $tcflags dst_ip 192.0.0.0/24 \
411		   action drop"
412	tp_check_hits "objagg:objagg_obj_root_create" 1
413	check_err $? "eRP was not created"
414
415	tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
416		   pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
417		   action drop"
418	tp_check_hits "objagg:objagg_obj_root_create" 0
419	check_err $? "eRP was incorrectly created"
420	tp_check_hits "objagg:objagg_obj_parent_assign" 1
421	check_err $? "delta was not created"
422
423	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
424		-t ip -q
425
426	tc_check_packets "dev $h2 ingress" 101 1
427	check_fail $? "Matched a wrong filter"
428
429	tc_check_packets "dev $h2 ingress" 102 1
430	check_err $? "Did not match on correct filter"
431
432	tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
433		   pref 1 handle 101 flower"
434	tp_check_hits "objagg:objagg_obj_root_destroy" 0
435	check_err $? "eRP was incorrectly destroyed"
436	tp_check_hits "objagg:objagg_obj_parent_unassign" 0
437	check_err $? "delta was incorrectly destroyed"
438
439	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
440		-t ip -q
441
442	tc_check_packets "dev $h2 ingress" 102 2
443	check_err $? "Did not match on correct filter after the first was removed"
444
445	tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
446		   pref 2 handle 102 flower"
447	tp_check_hits "objagg:objagg_obj_parent_unassign" 1
448	check_err $? "delta was not destroyed"
449	tp_check_hits "objagg:objagg_obj_root_destroy" 1
450	check_err $? "eRP was not destroyed"
451
452	log_test "delta simple test ($tcflags)"
453}
454
455delta_two_masks_one_key_test()
456{
457	# If 2 keys are the same and only differ in mask in a way that
458	# they belong under the same ERP (second is delta of the first),
459	# there should be no C-TCAM spill.
460
461	RET=0
462
463	if [[ "$tcflags" != "skip_sw" ]]; then
464		return 0;
465	fi
466
467	tp_record "mlxsw:*" "tc filter add dev $h2 ingress protocol ip \
468		   pref 1 handle 101 flower $tcflags dst_ip 192.0.2.0/24 \
469		   action drop"
470	tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" 0
471	check_err $? "incorrect C-TCAM spill while inserting the first rule"
472
473	tp_record "mlxsw:*" "tc filter add dev $h2 ingress protocol ip \
474		   pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
475		   action drop"
476	tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" 0
477	check_err $? "incorrect C-TCAM spill while inserting the second rule"
478
479	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
480		-t ip -q
481
482	tc_check_packets "dev $h2 ingress" 101 1
483	check_err $? "Did not match on correct filter"
484
485	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
486
487	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
488		-t ip -q
489
490	tc_check_packets "dev $h2 ingress" 102 1
491	check_err $? "Did not match on correct filter"
492
493	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
494
495	log_test "delta two masks one key test ($tcflags)"
496}
497
498delta_simple_rehash_test()
499{
500	RET=0
501
502	if [[ "$tcflags" != "skip_sw" ]]; then
503		return 0;
504	fi
505
506	devlink dev param set $DEVLINK_DEV \
507		name acl_region_rehash_interval cmode runtime value 0
508	check_err $? "Failed to set ACL region rehash interval"
509
510	tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
511	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
512	check_fail $? "Rehash trace was hit even when rehash should be disabled"
513
514	devlink dev param set $DEVLINK_DEV \
515		name acl_region_rehash_interval cmode runtime value 3000
516	check_err $? "Failed to set ACL region rehash interval"
517
518	sleep 1
519
520	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
521		$tcflags dst_ip 192.0.1.0/25 action drop
522	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
523		$tcflags dst_ip 192.0.2.2 action drop
524	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
525		$tcflags dst_ip 192.0.3.0/24 action drop
526
527	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
528		-t ip -q
529
530	tc_check_packets "dev $h2 ingress" 101 1
531	check_fail $? "Matched a wrong filter"
532
533	tc_check_packets "dev $h2 ingress" 103 1
534	check_fail $? "Matched a wrong filter"
535
536	tc_check_packets "dev $h2 ingress" 102 1
537	check_err $? "Did not match on correct filter"
538
539	tp_record_all mlxsw:* 3
540	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
541	check_err $? "Rehash trace was not hit"
542	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
543	check_err $? "Migrate trace was not hit"
544	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
545	check_err $? "Migrate end trace was not hit"
546	tp_record_all mlxsw:* 3
547	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
548	check_err $? "Rehash trace was not hit"
549	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
550	check_fail $? "Migrate trace was hit when no migration should happen"
551	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
552	check_fail $? "Migrate end trace was hit when no migration should happen"
553
554	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
555		-t ip -q
556
557	tc_check_packets "dev $h2 ingress" 101 1
558	check_fail $? "Matched a wrong filter after rehash"
559
560	tc_check_packets "dev $h2 ingress" 103 1
561	check_fail $? "Matched a wrong filter after rehash"
562
563	tc_check_packets "dev $h2 ingress" 102 2
564	check_err $? "Did not match on correct filter after rehash"
565
566	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
567	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
568	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
569
570	log_test "delta simple rehash test ($tcflags)"
571}
572
573delta_simple_ipv6_rehash_test()
574{
575	RET=0
576
577	if [[ "$tcflags" != "skip_sw" ]]; then
578		return 0;
579	fi
580
581	devlink dev param set $DEVLINK_DEV \
582		name acl_region_rehash_interval cmode runtime value 0
583	check_err $? "Failed to set ACL region rehash interval"
584
585	tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
586	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
587	check_fail $? "Rehash trace was hit even when rehash should be disabled"
588
589	devlink dev param set $DEVLINK_DEV \
590		name acl_region_rehash_interval cmode runtime value 3000
591	check_err $? "Failed to set ACL region rehash interval"
592
593	sleep 1
594
595	tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 101 flower \
596		$tcflags dst_ip 2001:db8:1::0/121 action drop
597	tc filter add dev $h2 ingress protocol ipv6 pref 2 handle 102 flower \
598		$tcflags dst_ip 2001:db8:2::2 action drop
599	tc filter add dev $h2 ingress protocol ipv6 pref 3 handle 103 flower \
600		$tcflags dst_ip 2001:db8:3::0/120 action drop
601
602	$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
603		-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
604
605	tc_check_packets "dev $h2 ingress" 101 1
606	check_fail $? "Matched a wrong filter"
607
608	tc_check_packets "dev $h2 ingress" 103 1
609	check_fail $? "Matched a wrong filter"
610
611	tc_check_packets "dev $h2 ingress" 102 1
612	check_err $? "Did not match on correct filter"
613
614	tp_record_all mlxsw:* 3
615	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
616	check_err $? "Rehash trace was not hit"
617	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
618	check_err $? "Migrate trace was not hit"
619	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
620	check_err $? "Migrate end trace was not hit"
621	tp_record_all mlxsw:* 3
622	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
623	check_err $? "Rehash trace was not hit"
624	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
625	check_fail $? "Migrate trace was hit when no migration should happen"
626	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
627	check_fail $? "Migrate end trace was hit when no migration should happen"
628
629	$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
630		-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
631
632	tc_check_packets "dev $h2 ingress" 101 1
633	check_fail $? "Matched a wrong filter after rehash"
634
635	tc_check_packets "dev $h2 ingress" 103 1
636	check_fail $? "Matched a wrong filter after rehash"
637
638	tc_check_packets "dev $h2 ingress" 102 2
639	check_err $? "Did not match on correct filter after rehash"
640
641	tc filter del dev $h2 ingress protocol ipv6 pref 3 handle 103 flower
642	tc filter del dev $h2 ingress protocol ipv6 pref 2 handle 102 flower
643	tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 101 flower
644
645	log_test "delta simple IPv6 rehash test ($tcflags)"
646}
647
648TEST_RULE_BASE=256
649declare -a test_rules_inserted
650
651test_rule_add()
652{
653	local iface=$1
654	local tcflags=$2
655	local index=$3
656
657	if ! [ ${test_rules_inserted[$index]} ] ; then
658		test_rules_inserted[$index]=false
659	fi
660	if ${test_rules_inserted[$index]} ; then
661		return
662	fi
663
664	local number=$(( $index + $TEST_RULE_BASE ))
665	printf -v hexnumber '%x' $number
666
667	batch="${batch}filter add dev $iface ingress protocol ipv6 pref 1 \
668		handle $number flower $tcflags \
669		src_ip 2001:db8:1::$hexnumber action drop\n"
670	test_rules_inserted[$index]=true
671}
672
673test_rule_del()
674{
675	local iface=$1
676	local index=$2
677
678	if ! [ ${test_rules_inserted[$index]} ] ; then
679		test_rules_inserted[$index]=false
680	fi
681	if ! ${test_rules_inserted[$index]} ; then
682		return
683	fi
684
685	local number=$(( $index + $TEST_RULE_BASE ))
686	printf -v hexnumber '%x' $number
687
688	batch="${batch}filter del dev $iface ingress protocol ipv6 pref 1 \
689		handle $number flower\n"
690	test_rules_inserted[$index]=false
691}
692
693test_rule_add_or_remove()
694{
695	local iface=$1
696	local tcflags=$2
697	local index=$3
698
699	if ! [ ${test_rules_inserted[$index]} ] ; then
700		test_rules_inserted[$index]=false
701	fi
702	if ${test_rules_inserted[$index]} ; then
703		test_rule_del $iface $index
704	else
705		test_rule_add $iface $tcflags $index
706	fi
707}
708
709test_rule_add_or_remove_random_batch()
710{
711	local iface=$1
712	local tcflags=$2
713	local total_count=$3
714	local skip=0
715	local count=0
716	local MAXSKIP=20
717	local MAXCOUNT=20
718
719	for ((i=1;i<=total_count;i++)); do
720		if (( $skip == 0 )) && (($count == 0)); then
721			((skip=$RANDOM % $MAXSKIP + 1))
722			((count=$RANDOM % $MAXCOUNT + 1))
723		fi
724		if (( $skip != 0 )); then
725			((skip-=1))
726		else
727			((count-=1))
728			test_rule_add_or_remove $iface $tcflags $i
729		fi
730	done
731}
732
733delta_massive_ipv6_rehash_test()
734{
735	RET=0
736
737	if [[ "$tcflags" != "skip_sw" ]]; then
738		return 0;
739	fi
740
741	devlink dev param set $DEVLINK_DEV \
742		name acl_region_rehash_interval cmode runtime value 0
743	check_err $? "Failed to set ACL region rehash interval"
744
745	tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
746	tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
747	check_fail $? "Rehash trace was hit even when rehash should be disabled"
748
749	RANDOM=4432897
750	declare batch=""
751	test_rule_add_or_remove_random_batch $h2 $tcflags 5000
752
753	echo -n -e $batch | tc -b -
754
755	declare batch=""
756	test_rule_add_or_remove_random_batch $h2 $tcflags 5000
757
758	devlink dev param set $DEVLINK_DEV \
759		name acl_region_rehash_interval cmode runtime value 3000
760	check_err $? "Failed to set ACL region rehash interval"
761
762	sleep 1
763
764	tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 101 flower \
765		$tcflags dst_ip 2001:db8:1::0/121 action drop
766	tc filter add dev $h2 ingress protocol ipv6 pref 2 handle 102 flower \
767		$tcflags dst_ip 2001:db8:2::2 action drop
768	tc filter add dev $h2 ingress protocol ipv6 pref 3 handle 103 flower \
769		$tcflags dst_ip 2001:db8:3::0/120 action drop
770
771	$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
772		-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
773
774	tc_check_packets "dev $h2 ingress" 101 1
775	check_fail $? "Matched a wrong filter"
776
777	tc_check_packets "dev $h2 ingress" 103 1
778	check_fail $? "Matched a wrong filter"
779
780	tc_check_packets "dev $h2 ingress" 102 1
781	check_err $? "Did not match on correct filter"
782
783	echo -n -e $batch | tc -b -
784
785	devlink dev param set $DEVLINK_DEV \
786		name acl_region_rehash_interval cmode runtime value 0
787	check_err $? "Failed to set ACL region rehash interval"
788
789	$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
790		-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
791
792	tc_check_packets "dev $h2 ingress" 101 1
793	check_fail $? "Matched a wrong filter after rehash"
794
795	tc_check_packets "dev $h2 ingress" 103 1
796	check_fail $? "Matched a wrong filter after rehash"
797
798	tc_check_packets "dev $h2 ingress" 102 2
799	check_err $? "Did not match on correct filter after rehash"
800
801	tc filter del dev $h2 ingress protocol ipv6 pref 3 handle 103 flower
802	tc filter del dev $h2 ingress protocol ipv6 pref 2 handle 102 flower
803	tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 101 flower
804
805	declare batch=""
806	for i in {1..5000}; do
807		test_rule_del $h2 $tcflags $i
808	done
809	echo -e $batch | tc -b -
810
811	log_test "delta massive IPv6 rehash test ($tcflags)"
812}
813
814bloom_simple_test()
815{
816	# Bloom filter requires that the eRP table is used. This test
817	# verifies that Bloom filter is not harming correctness of ACLs.
818	# First, make sure that eRP table is used and then set rule patterns
819	# which are distant enough and will result skipping a lookup after
820	# consulting the Bloom filter. Although some eRP lookups are skipped,
821	# the correct filter should be hit.
822
823	RET=0
824
825	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
826		$tcflags dst_ip 192.0.2.2 action drop
827	tc filter add dev $h2 ingress protocol ip pref 5 handle 104 flower \
828		$tcflags dst_ip 198.51.100.2 action drop
829	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
830		$tcflags dst_ip 192.0.0.0/8 action drop
831
832	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
833		-t ip -q
834
835	tc_check_packets "dev $h2 ingress" 101 1
836	check_err $? "Two filters - did not match highest priority"
837
838	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
839		-t ip -q
840
841	tc_check_packets "dev $h2 ingress" 104 1
842	check_err $? "Single filter - did not match"
843
844	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
845
846	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
847		-t ip -q
848
849	tc_check_packets "dev $h2 ingress" 103 1
850	check_err $? "Low prio filter - did not match"
851
852	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
853		$tcflags dst_ip 198.0.0.0/8 action drop
854
855	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
856		-t ip -q
857
858	tc_check_packets "dev $h2 ingress" 102 1
859	check_err $? "Two filters - did not match highest priority after add"
860
861	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
862	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
863	tc filter del dev $h2 ingress protocol ip pref 5 handle 104 flower
864
865	log_test "bloom simple test ($tcflags)"
866}
867
868bloom_complex_test()
869{
870	# Bloom filter index computation is affected from region ID, eRP
871	# ID and from the region key size. In order to excercise those parts
872	# of the Bloom filter code, use a series of regions, each with a
873	# different key size and send packet that should hit all of them.
874	local index
875
876	RET=0
877	NUM_CHAINS=4
878	BASE_INDEX=100
879
880	# Create chain with up to 2 key blocks (ip_proto only)
881	tc chain add dev $h2 ingress chain 1 protocol ip flower \
882		ip_proto tcp &> /dev/null
883	# Create chain with 2-4 key blocks (ip_proto, src MAC)
884	tc chain add dev $h2 ingress chain 2 protocol ip flower \
885		ip_proto tcp \
886		src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
887	# Create chain with 4-8 key blocks (ip_proto, src & dst MAC, IPv4 dest)
888	tc chain add dev $h2 ingress chain 3 protocol ip flower \
889		ip_proto tcp \
890		dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF \
891		src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF \
892		dst_ip 0.0.0.0/32 &> /dev/null
893	# Default chain contains all fields and therefore is 8-12 key blocks
894	tc chain add dev $h2 ingress chain 4
895
896	# We need at least 2 rules in every region to have eRP table active
897	# so create a dummy rule per chain using a different pattern
898	for i in $(eval echo {0..$NUM_CHAINS}); do
899		index=$((BASE_INDEX - 1 - i))
900		tc filter add dev $h2 ingress chain $i protocol ip \
901			pref 2 handle $index flower \
902			$tcflags ip_proto tcp action drop
903	done
904
905	# Add rules to test Bloom filter, each in a different chain
906	index=$BASE_INDEX
907	tc filter add dev $h2 ingress protocol ip \
908		pref 1 handle $((++index)) flower \
909		$tcflags dst_ip 192.0.0.0/16 action goto chain 1
910	tc filter add dev $h2 ingress chain 1 protocol ip \
911		pref 1 handle $((++index)) flower \
912		$tcflags action goto chain 2
913	tc filter add dev $h2 ingress chain 2 protocol ip \
914		pref 1 handle $((++index)) flower \
915		$tcflags src_mac $h1mac action goto chain 3
916	tc filter add dev $h2 ingress chain 3 protocol ip \
917		pref 1 handle $((++index)) flower \
918		$tcflags dst_ip 192.0.0.0/8 action goto chain 4
919	tc filter add dev $h2 ingress chain 4 protocol ip \
920		pref 1 handle $((++index)) flower \
921		$tcflags src_ip 192.0.2.0/24 action drop
922
923	# Send a packet that is supposed to hit all chains
924	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
925		-t ip -q
926
927	for i in $(eval echo {0..$NUM_CHAINS}); do
928		index=$((BASE_INDEX + i + 1))
929		tc_check_packets "dev $h2 ingress" $index 1
930		check_err $? "Did not match chain $i"
931	done
932
933	# Rules cleanup
934	for i in $(eval echo {$NUM_CHAINS..0}); do
935		index=$((BASE_INDEX - i - 1))
936		tc filter del dev $h2 ingress chain $i \
937			pref 2 handle $index flower
938		index=$((BASE_INDEX + i + 1))
939		tc filter del dev $h2 ingress chain $i \
940			pref 1 handle $index flower
941	done
942
943	# Chains cleanup
944	for i in $(eval echo {$NUM_CHAINS..1}); do
945		tc chain del dev $h2 ingress chain $i
946	done
947
948	log_test "bloom complex test ($tcflags)"
949}
950
951
952bloom_delta_test()
953{
954	# When multiple masks are used, the eRP table is activated. When
955	# masks are close enough (delta) the masks reside on the same
956	# eRP table. This test verifies that the eRP table is correctly
957	# allocated and used in delta condition and that Bloom filter is
958	# still functional with delta.
959
960	RET=0
961
962	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
963		$tcflags dst_ip 192.1.0.0/16 action drop
964
965	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.1.2.1 -B 192.1.2.2 \
966		-t ip -q
967
968	tc_check_packets "dev $h2 ingress" 103 1
969	check_err $? "Single filter - did not match"
970
971	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
972		$tcflags dst_ip 192.2.1.0/24 action drop
973
974	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.2.1.1 -B 192.2.1.2 \
975		-t ip -q
976
977	tc_check_packets "dev $h2 ingress" 102 1
978	check_err $? "Delta filters - did not match second filter"
979
980	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
981	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
982
983	log_test "bloom delta test ($tcflags)"
984}
985
986setup_prepare()
987{
988	h1=${NETIFS[p1]}
989	h2=${NETIFS[p2]}
990	h1mac=$(mac_get $h1)
991	h2mac=$(mac_get $h2)
992
993	vrf_prepare
994
995	h1_create
996	h2_create
997}
998
999cleanup()
1000{
1001	pre_cleanup
1002
1003	h2_destroy
1004	h1_destroy
1005
1006	vrf_cleanup
1007}
1008
1009trap cleanup EXIT
1010
1011setup_prepare
1012setup_wait
1013
1014tests_run
1015
1016if ! tc_offload_check; then
1017	check_err 1 "Could not test offloaded functionality"
1018	log_test "mlxsw-specific tests for tc flower"
1019	exit
1020else
1021	tcflags="skip_sw"
1022	tests_run
1023fi
1024
1025exit $EXIT_STATUS
1026