1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright 2020 NXP
4
5WAIT_TIME=1
6NUM_NETIFS=4
7lib_dir=$(dirname $0)/../../../net/forwarding
8source $lib_dir/tc_common.sh
9source $lib_dir/lib.sh
10
11require_command tcpdump
12
13#
14#   +---------------------------------------------+
15#   |       DUT ports         Generator ports     |
16#   | +--------+ +--------+ +--------+ +--------+ |
17#   | |        | |        | |        | |        | |
18#   | |  eth0  | |  eth1  | |  eth2  | |  eth3  | |
19#   | |        | |        | |        | |        | |
20#   +-+--------+-+--------+-+--------+-+--------+-+
21#          |         |           |          |
22#          |         |           |          |
23#          |         +-----------+          |
24#          |                                |
25#          +--------------------------------+
26
27eth0=${NETIFS[p1]}
28eth1=${NETIFS[p2]}
29eth2=${NETIFS[p3]}
30eth3=${NETIFS[p4]}
31
32eth0_mac="de:ad:be:ef:00:00"
33eth1_mac="de:ad:be:ef:00:01"
34eth2_mac="de:ad:be:ef:00:02"
35eth3_mac="de:ad:be:ef:00:03"
36
37# Helpers to map a VCAP IS1 and VCAP IS2 lookup and policy to a chain number
38# used by the kernel driver. The numbers are:
39# VCAP IS1 lookup 0:            10000
40# VCAP IS1 lookup 1:            11000
41# VCAP IS1 lookup 2:            12000
42# VCAP IS2 lookup 0 policy 0:   20000
43# VCAP IS2 lookup 0 policy 1:   20001
44# VCAP IS2 lookup 0 policy 255: 20255
45# VCAP IS2 lookup 1 policy 0:   21000
46# VCAP IS2 lookup 1 policy 1:   21001
47# VCAP IS2 lookup 1 policy 255: 21255
48IS1()
49{
50	local lookup=$1
51
52	echo $((10000 + 1000 * lookup))
53}
54
55IS2()
56{
57	local lookup=$1
58	local pag=$2
59
60	echo $((20000 + 1000 * lookup + pag))
61}
62
63ES0()
64{
65	echo 0
66}
67
68# The Ocelot switches have a fixed ingress pipeline composed of:
69#
70# +----------------------------------------------+      +-----------------------------------------+
71# |                   VCAP IS1                   |      |                  VCAP IS2               |
72# |                                              |      |                                         |
73# | +----------+    +----------+    +----------+ |      |            +----------+    +----------+ |
74# | | Lookup 0 |    | Lookup 1 |    | Lookup 2 | | --+------> PAG 0: | Lookup 0 | -> | Lookup 1 | |
75# | +----------+ -> +----------+ -> +----------+ |   |  |            +----------+    +----------+ |
76# | |key&action|    |key&action|    |key&action| |   |  |            |key&action|    |key&action| |
77# | |key&action|    |key&action|    |key&action| |   |  |            |    ..    |    |    ..    | |
78# | |    ..    |    |    ..    |    |    ..    | |   |  |            +----------+    +----------+ |
79# | +----------+    +----------+    +----------+ |   |  |                                         |
80# |                                 selects PAG  |   |  |            +----------+    +----------+ |
81# +----------------------------------------------+   +------> PAG 1: | Lookup 0 | -> | Lookup 1 | |
82#                                                    |  |            +----------+    +----------+ |
83#                                                    |  |            |key&action|    |key&action| |
84#                                                    |  |            |    ..    |    |    ..    | |
85#                                                    |  |            +----------+    +----------+ |
86#                                                    |  |      ...                                |
87#                                                    |  |                                         |
88#                                                    |  |            +----------+    +----------+ |
89#                                                    +----> PAG 254: | Lookup 0 | -> | Lookup 1 | |
90#                                                    |  |            +----------+    +----------+ |
91#                                                    |  |            |key&action|    |key&action| |
92#                                                    |  |            |    ..    |    |    ..    | |
93#                                                    |  |            +----------+    +----------+ |
94#                                                    |  |                                         |
95#                                                    |  |            +----------+    +----------+ |
96#                                                    +----> PAG 255: | Lookup 0 | -> | Lookup 1 | |
97#                                                       |            +----------+    +----------+ |
98#                                                       |            |key&action|    |key&action| |
99#                                                       |            |    ..    |    |    ..    | |
100#                                                       |            +----------+    +----------+ |
101#                                                       +-----------------------------------------+
102#
103# Both the VCAP IS1 (Ingress Stage 1) and IS2 (Ingress Stage 2) are indexed
104# (looked up) multiple times: IS1 3 times, and IS2 2 times. Each filter
105# (key and action pair) can be configured to only match during the first, or
106# second, etc, lookup.
107#
108# During one TCAM lookup, the filter processing stops at the first entry that
109# matches, then the pipeline jumps to the next lookup.
110# The driver maps each individual lookup of each individual ingress TCAM to a
111# separate chain number. For correct rule offloading, it is mandatory that each
112# filter installed in one TCAM is terminated by a non-optional GOTO action to
113# the next lookup from the fixed pipeline.
114#
115# A chain can only be used if there is a GOTO action correctly set up from the
116# prior lookup in the processing pipeline. Setting up all chains is not
117# mandatory.
118
119# NOTE: VCAP IS1 currently uses only S1_NORMAL half keys and VCAP IS2
120# dynamically chooses between MAC_ETYPE, ARP, IP4_TCP_UDP, IP4_OTHER, which are
121# all half keys as well.
122
123create_tcam_skeleton()
124{
125	local eth=$1
126
127	tc qdisc add dev $eth clsact
128
129	# VCAP IS1 is the Ingress Classification TCAM and can offload the
130	# following actions:
131	# - skbedit priority
132	# - vlan pop
133	# - vlan modify
134	# - goto (only in lookup 2, the last IS1 lookup)
135	tc filter add dev $eth ingress chain 0 pref 49152 flower \
136		skip_sw action goto chain $(IS1 0)
137	tc filter add dev $eth ingress chain $(IS1 0) pref 49152 \
138		flower skip_sw action goto chain $(IS1 1)
139	tc filter add dev $eth ingress chain $(IS1 1) pref 49152 \
140		flower skip_sw action goto chain $(IS1 2)
141	tc filter add dev $eth ingress chain $(IS1 2) pref 49152 \
142		flower skip_sw action goto chain $(IS2 0 0)
143
144	# VCAP IS2 is the Security Enforcement ingress TCAM and can offload the
145	# following actions:
146	# - trap
147	# - drop
148	# - police
149	# The two VCAP IS2 lookups can be segmented into up to 256 groups of
150	# rules, called Policies. A Policy is selected through the Policy
151	# Association Group (PAG) action of VCAP IS1 (which is the
152	# GOTO offload).
153	tc filter add dev $eth ingress chain $(IS2 0 0) pref 49152 \
154		flower skip_sw action goto chain $(IS2 1 0)
155}
156
157setup_prepare()
158{
159	ip link set $eth0 up
160	ip link set $eth1 up
161	ip link set $eth2 up
162	ip link set $eth3 up
163
164	create_tcam_skeleton $eth0
165
166	ip link add br0 type bridge
167	ip link set $eth0 master br0
168	ip link set $eth1 master br0
169	ip link set br0 up
170
171	ip link add link $eth3 name $eth3.100 type vlan id 100
172	ip link set $eth3.100 up
173
174	ip link add link $eth3 name $eth3.200 type vlan id 200
175	ip link set $eth3.200 up
176
177	tc filter add dev $eth0 ingress chain $(IS1 1) pref 1 \
178		protocol 802.1Q flower skip_sw vlan_id 100 \
179		action vlan pop \
180		action goto chain $(IS1 2)
181
182	tc filter add dev $eth0 egress chain $(ES0) pref 1 \
183		flower skip_sw indev $eth1 \
184		action vlan push protocol 802.1Q id 100
185
186	tc filter add dev $eth0 ingress chain $(IS1 0) pref 2 \
187		protocol ipv4 flower skip_sw src_ip 10.1.1.2 \
188		action skbedit priority 7 \
189		action goto chain $(IS1 1)
190
191	tc filter add dev $eth0 ingress chain $(IS2 0 0) pref 1 \
192		protocol ipv4 flower skip_sw ip_proto udp dst_port 5201 \
193		action police rate 50mbit burst 64k \
194		action goto chain $(IS2 1 0)
195}
196
197cleanup()
198{
199	ip link del $eth3.200
200	ip link del $eth3.100
201	tc qdisc del dev $eth0 clsact
202	ip link del br0
203}
204
205test_vlan_pop()
206{
207	printf "Testing VLAN pop..			"
208
209	tcpdump_start $eth2
210
211	# Work around Mausezahn VLAN builder bug
212	# (https://github.com/netsniff-ng/netsniff-ng/issues/225) by using
213	# an 8021q upper
214	$MZ $eth3.100 -q -c 1 -p 64 -a $eth3_mac -b $eth2_mac -t ip
215
216	sleep 1
217
218	tcpdump_stop
219
220	if tcpdump_show | grep -q "$eth3_mac > $eth2_mac, ethertype IPv4"; then
221		echo "OK"
222	else
223		echo "FAIL"
224	fi
225
226	tcpdump_cleanup
227}
228
229test_vlan_push()
230{
231	printf "Testing VLAN push..			"
232
233	tcpdump_start $eth3.100
234
235	$MZ $eth2 -q -c 1 -p 64 -a $eth2_mac -b $eth3_mac -t ip
236
237	sleep 1
238
239	tcpdump_stop
240
241	if tcpdump_show | grep -q "$eth2_mac > $eth3_mac"; then
242		echo "OK"
243	else
244		echo "FAIL"
245	fi
246
247	tcpdump_cleanup
248}
249
250test_vlan_ingress_modify()
251{
252	printf "Testing ingress VLAN modification..		"
253
254	ip link set br0 type bridge vlan_filtering 1
255	bridge vlan add dev $eth0 vid 200
256	bridge vlan add dev $eth0 vid 300
257	bridge vlan add dev $eth1 vid 300
258
259	tc filter add dev $eth0 ingress chain $(IS1 2) pref 3 \
260		protocol 802.1Q flower skip_sw vlan_id 200 \
261		action vlan modify id 300 \
262		action goto chain $(IS2 0 0)
263
264	tcpdump_start $eth2
265
266	$MZ $eth3.200 -q -c 1 -p 64 -a $eth3_mac -b $eth2_mac -t ip
267
268	sleep 1
269
270	tcpdump_stop
271
272	if tcpdump_show | grep -q "$eth3_mac > $eth2_mac, .* vlan 300"; then
273		echo "OK"
274	else
275		echo "FAIL"
276	fi
277
278	tcpdump_cleanup
279
280	tc filter del dev $eth0 ingress chain $(IS1 2) pref 3
281
282	bridge vlan del dev $eth0 vid 200
283	bridge vlan del dev $eth0 vid 300
284	bridge vlan del dev $eth1 vid 300
285	ip link set br0 type bridge vlan_filtering 0
286}
287
288test_vlan_egress_modify()
289{
290	printf "Testing egress VLAN modification..		"
291
292	tc qdisc add dev $eth1 clsact
293
294	ip link set br0 type bridge vlan_filtering 1
295	bridge vlan add dev $eth0 vid 200
296	bridge vlan add dev $eth1 vid 200
297
298	tc filter add dev $eth1 egress chain $(ES0) pref 3 \
299		protocol 802.1Q flower skip_sw vlan_id 200 vlan_prio 0 \
300		action vlan modify id 300 priority 7
301
302	tcpdump_start $eth2
303
304	$MZ $eth3.200 -q -c 1 -p 64 -a $eth3_mac -b $eth2_mac -t ip
305
306	sleep 1
307
308	tcpdump_stop
309
310	if tcpdump_show | grep -q "$eth3_mac > $eth2_mac, .* vlan 300"; then
311		echo "OK"
312	else
313		echo "FAIL"
314	fi
315
316	tcpdump_cleanup
317
318	tc filter del dev $eth1 egress chain $(ES0) pref 3
319	tc qdisc del dev $eth1 clsact
320
321	bridge vlan del dev $eth0 vid 200
322	bridge vlan del dev $eth1 vid 200
323	ip link set br0 type bridge vlan_filtering 0
324}
325
326test_skbedit_priority()
327{
328	local num_pkts=100
329
330	printf "Testing frame prioritization..		"
331
332	before=$(ethtool_stats_get $eth0 'rx_green_prio_7')
333
334	$MZ $eth3 -q -c $num_pkts -p 64 -a $eth3_mac -b $eth2_mac -t ip -A 10.1.1.2
335
336	after=$(ethtool_stats_get $eth0 'rx_green_prio_7')
337
338	if [ $((after - before)) = $num_pkts ]; then
339		echo "OK"
340	else
341		echo "FAIL"
342	fi
343}
344
345trap cleanup EXIT
346
347ALL_TESTS="
348	test_vlan_pop
349	test_vlan_push
350	test_vlan_ingress_modify
351	test_vlan_egress_modify
352	test_skbedit_priority
353"
354
355setup_prepare
356setup_wait
357
358tests_run
359
360exit $EXIT_STATUS
361