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"
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/16 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.2.0/24 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
327setup_prepare()
328{
329	h1=${NETIFS[p1]}
330	h2=${NETIFS[p2]}
331	h1mac=$(mac_get $h1)
332	h2mac=$(mac_get $h2)
333
334	vrf_prepare
335
336	h1_create
337	h2_create
338}
339
340cleanup()
341{
342	pre_cleanup
343
344	h2_destroy
345	h1_destroy
346
347	vrf_cleanup
348}
349
350trap cleanup EXIT
351
352setup_prepare
353setup_wait
354
355tests_run
356
357if ! tc_offload_check; then
358	check_err 1 "Could not test offloaded functionality"
359	log_test "mlxsw-specific tests for tc flower"
360	exit
361else
362	tcflags="skip_sw"
363	tests_run
364fi
365
366exit $EXIT_STATUS
367