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