xref: /linux/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh (revision cad4977344b35ea116ec5fefe91a76b1dfa113f5)
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"
12NUM_NETIFS=2
13source $lib_dir/tc_common.sh
14source $lib_dir/lib.sh
15
16tcflags="skip_hw"
17
18h1_create()
19{
20	simple_if_init $h1 192.0.2.1/24 198.51.100.1/24
21}
22
23h1_destroy()
24{
25	simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24
26}
27
28h2_create()
29{
30	simple_if_init $h2 192.0.2.2/24 198.51.100.2/24
31	tc qdisc add dev $h2 clsact
32}
33
34h2_destroy()
35{
36	tc qdisc del dev $h2 clsact
37	simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24
38}
39
40single_mask_test()
41{
42	# When only a single mask is required, the device uses the master
43	# mask and not the eRP table. Verify that under this mode the right
44	# filter is matched
45
46	RET=0
47
48	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
49		$tcflags dst_ip 192.0.2.2 action drop
50
51	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
52		-t ip -q
53
54	tc_check_packets "dev $h2 ingress" 101 1
55	check_err $? "Single filter - did not match"
56
57	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
58		$tcflags dst_ip 198.51.100.2 action drop
59
60	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
61		-t ip -q
62
63	tc_check_packets "dev $h2 ingress" 101 2
64	check_err $? "Two filters - did not match highest priority"
65
66	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
67		-t ip -q
68
69	tc_check_packets "dev $h2 ingress" 102 1
70	check_err $? "Two filters - did not match lowest priority"
71
72	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
73
74	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
75		-t ip -q
76
77	tc_check_packets "dev $h2 ingress" 102 2
78	check_err $? "Single filter - did not match after delete"
79
80	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
81
82	log_test "single mask test ($tcflags)"
83}
84
85identical_filters_test()
86{
87	# When two filters that only differ in their priority are used,
88	# one needs to be inserted into the C-TCAM. This test verifies
89	# that filters are correctly spilled to C-TCAM and that the right
90	# filter is matched
91
92	RET=0
93
94	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
95		$tcflags dst_ip 192.0.2.2 action drop
96	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
97		$tcflags dst_ip 192.0.2.2 action drop
98
99	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
100		-t ip -q
101
102	tc_check_packets "dev $h2 ingress" 101 1
103	check_err $? "Did not match A-TCAM filter"
104
105	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
106
107	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
108		-t ip -q
109
110	tc_check_packets "dev $h2 ingress" 102 1
111	check_err $? "Did not match C-TCAM filter after A-TCAM delete"
112
113	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
114		$tcflags dst_ip 192.0.2.2 action drop
115
116	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
117		-t ip -q
118
119	tc_check_packets "dev $h2 ingress" 102 2
120	check_err $? "Did not match C-TCAM filter after A-TCAM add"
121
122	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
123
124	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
125		-t ip -q
126
127	tc_check_packets "dev $h2 ingress" 103 1
128	check_err $? "Did not match A-TCAM filter after C-TCAM delete"
129
130	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
131
132	log_test "identical filters test ($tcflags)"
133}
134
135two_masks_test()
136{
137	# When more than one mask is required, the eRP table is used. This
138	# test verifies that the eRP table is correctly allocated and used
139
140	RET=0
141
142	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
143		$tcflags dst_ip 192.0.2.2 action drop
144	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
145		$tcflags dst_ip 192.0.0.0/8 action drop
146
147	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
148		-t ip -q
149
150	tc_check_packets "dev $h2 ingress" 101 1
151	check_err $? "Two filters - did not match highest priority"
152
153	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
154
155	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
156		-t ip -q
157
158	tc_check_packets "dev $h2 ingress" 103 1
159	check_err $? "Single filter - did not match"
160
161	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
162		$tcflags dst_ip 192.0.2.0/24 action drop
163
164	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
165		-t ip -q
166
167	tc_check_packets "dev $h2 ingress" 102 1
168	check_err $? "Two filters - did not match highest priority after add"
169
170	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
171	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
172
173	log_test "two masks test ($tcflags)"
174}
175
176multiple_masks_test()
177{
178	# The number of masks in a region is limited. Once the maximum
179	# number of masks has been reached filters that require new
180	# masks are spilled to the C-TCAM. This test verifies that
181	# spillage is performed correctly and that the right filter is
182	# matched
183
184	local index
185
186	RET=0
187
188	NUM_MASKS=32
189	BASE_INDEX=100
190
191	for i in $(eval echo {1..$NUM_MASKS}); do
192		index=$((BASE_INDEX - i))
193
194		tc filter add dev $h2 ingress protocol ip pref $index \
195			handle $index \
196			flower $tcflags dst_ip 192.0.2.2/${i} src_ip 192.0.2.1 \
197			action drop
198
199		$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
200			-B 192.0.2.2 -t ip -q
201
202		tc_check_packets "dev $h2 ingress" $index 1
203		check_err $? "$i filters - did not match highest priority (add)"
204	done
205
206	for i in $(eval echo {$NUM_MASKS..1}); do
207		index=$((BASE_INDEX - i))
208
209		$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
210			-B 192.0.2.2 -t ip -q
211
212		tc_check_packets "dev $h2 ingress" $index 2
213		check_err $? "$i filters - did not match highest priority (del)"
214
215		tc filter del dev $h2 ingress protocol ip pref $index \
216			handle $index flower
217	done
218
219	log_test "multiple masks test ($tcflags)"
220}
221
222ctcam_two_atcam_masks_test()
223{
224	RET=0
225
226	# First case: C-TCAM is disabled when there are two A-TCAM masks.
227	# We push a filter into the C-TCAM by using two identical filters
228	# as in identical_filters_test()
229
230	# Filter goes into A-TCAM
231	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
232		$tcflags dst_ip 192.0.2.2 action drop
233	# Filter goes into C-TCAM
234	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
235		$tcflags dst_ip 192.0.2.2 action drop
236	# Filter goes into A-TCAM
237	tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
238		$tcflags dst_ip 192.0.0.0/16 action drop
239
240	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
241		-t ip -q
242
243	tc_check_packets "dev $h2 ingress" 101 1
244	check_err $? "Did not match A-TCAM filter"
245
246	# Delete both A-TCAM and C-TCAM filters and make sure the remaining
247	# A-TCAM filter still works
248	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
249	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
250
251	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
252		-t ip -q
253
254	tc_check_packets "dev $h2 ingress" 103 1
255	check_err $? "Did not match A-TCAM filter"
256
257	tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
258
259	log_test "ctcam with two atcam masks test ($tcflags)"
260}
261
262ctcam_one_atcam_mask_test()
263{
264	RET=0
265
266	# Second case: C-TCAM is disabled when there is one A-TCAM mask.
267	# The test is similar to identical_filters_test()
268
269	# Filter goes into A-TCAM
270	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
271		$tcflags dst_ip 192.0.2.2 action drop
272	# Filter goes into C-TCAM
273	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
274		$tcflags dst_ip 192.0.2.2 action drop
275
276	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
277		-t ip -q
278
279	tc_check_packets "dev $h2 ingress" 101 1
280	check_err $? "Did not match C-TCAM filter"
281
282	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
283
284	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
285		-t ip -q
286
287	tc_check_packets "dev $h2 ingress" 102 1
288	check_err $? "Did not match A-TCAM filter"
289
290	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
291
292	log_test "ctcam with one atcam mask test ($tcflags)"
293}
294
295ctcam_no_atcam_masks_test()
296{
297	RET=0
298
299	# Third case: C-TCAM is disabled when there are no A-TCAM masks
300	# This test exercises the code path that transitions the eRP table
301	# to its initial state after deleting the last C-TCAM mask
302
303	# Filter goes into A-TCAM
304	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
305		$tcflags dst_ip 192.0.2.2 action drop
306	# Filter goes into C-TCAM
307	tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
308		$tcflags dst_ip 192.0.2.2 action drop
309
310	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
311	tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
312
313	log_test "ctcam with no atcam masks test ($tcflags)"
314}
315
316ctcam_edge_cases_test()
317{
318	# When the C-TCAM is disabled after deleting the last C-TCAM
319	# mask, we want to make sure the eRP state machine is put in
320	# the correct state
321
322	ctcam_two_atcam_masks_test
323	ctcam_one_atcam_mask_test
324	ctcam_no_atcam_masks_test
325}
326
327tp_record()
328{
329	local tracepoint=$1
330	local cmd=$2
331
332	perf record -q -e $tracepoint $cmd
333	return $?
334}
335
336tp_check_hits()
337{
338	local tracepoint=$1
339	local count=$2
340
341	perf_output=`perf script -F trace:event,trace`
342	hits=`echo $perf_output | grep "$tracepoint:" | wc -l`
343	if [[ "$count" -ne "$hits" ]]; then
344		return 1
345	fi
346	return 0
347}
348
349delta_simple_test()
350{
351	# The first filter will create eRP, the second filter will fit into
352	# the first eRP with delta. Remove the first rule then and check that
353        # the eRP stays (referenced by the second filter).
354
355	RET=0
356
357	if [[ "$tcflags" != "skip_sw" ]]; then
358		return 0;
359	fi
360
361	tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
362		   pref 1 handle 101 flower $tcflags dst_ip 192.0.0.0/24 \
363		   action drop"
364	tp_check_hits "objagg:objagg_obj_root_create" 1
365	check_err $? "eRP was not created"
366
367	tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
368		   pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
369		   action drop"
370	tp_check_hits "objagg:objagg_obj_root_create" 0
371	check_err $? "eRP was incorrectly created"
372	tp_check_hits "objagg:objagg_obj_parent_assign" 1
373	check_err $? "delta was not created"
374
375	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
376		-t ip -q
377
378	tc_check_packets "dev $h2 ingress" 101 1
379	check_fail $? "Matched a wrong filter"
380
381	tc_check_packets "dev $h2 ingress" 102 1
382	check_err $? "Did not match on correct filter"
383
384	tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
385		   pref 1 handle 101 flower"
386	tp_check_hits "objagg:objagg_obj_root_destroy" 0
387	check_err $? "eRP was incorrectly destroyed"
388	tp_check_hits "objagg:objagg_obj_parent_unassign" 0
389	check_err $? "delta was incorrectly destroyed"
390
391	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
392		-t ip -q
393
394	tc_check_packets "dev $h2 ingress" 102 2
395	check_err $? "Did not match on correct filter after the first was removed"
396
397	tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
398		   pref 2 handle 102 flower"
399	tp_check_hits "objagg:objagg_obj_parent_unassign" 1
400	check_err $? "delta was not destroyed"
401	tp_check_hits "objagg:objagg_obj_root_destroy" 1
402	check_err $? "eRP was not destroyed"
403
404	log_test "delta simple test ($tcflags)"
405}
406
407setup_prepare()
408{
409	h1=${NETIFS[p1]}
410	h2=${NETIFS[p2]}
411	h1mac=$(mac_get $h1)
412	h2mac=$(mac_get $h2)
413
414	vrf_prepare
415
416	h1_create
417	h2_create
418}
419
420cleanup()
421{
422	pre_cleanup
423
424	h2_destroy
425	h1_destroy
426
427	vrf_cleanup
428}
429
430trap cleanup EXIT
431
432setup_prepare
433setup_wait
434
435tests_run
436
437if ! tc_offload_check; then
438	check_err 1 "Could not test offloaded functionality"
439	log_test "mlxsw-specific tests for tc flower"
440	exit
441else
442	tcflags="skip_sw"
443	tests_run
444fi
445
446exit $EXIT_STATUS
447