1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2018, Intel Corporation. */ |
3 | |
4 | #include "ice_lib.h" |
5 | #include "ice_switch.h" |
6 | |
7 | #define ICE_ETH_DA_OFFSET 0 |
8 | #define ICE_ETH_ETHTYPE_OFFSET 12 |
9 | #define ICE_ETH_VLAN_TCI_OFFSET 14 |
10 | #define ICE_MAX_VLAN_ID 0xFFF |
11 | #define ICE_IPV6_ETHER_ID 0x86DD |
12 | |
13 | /* Dummy ethernet header needed in the ice_aqc_sw_rules_elem |
14 | * struct to configure any switch filter rules. |
15 | * {DA (6 bytes), SA(6 bytes), |
16 | * Ether type (2 bytes for header without VLAN tag) OR |
17 | * VLAN tag (4 bytes for header with VLAN tag) } |
18 | * |
19 | * Word on Hardcoded values |
20 | * byte 0 = 0x2: to identify it as locally administered DA MAC |
21 | * byte 6 = 0x2: to identify it as locally administered SA MAC |
22 | * byte 12 = 0x81 & byte 13 = 0x00: |
23 | * In case of VLAN filter first two bytes defines ether type (0x8100) |
24 | * and remaining two bytes are placeholder for programming a given VLAN ID |
25 | * In case of Ether type filter it is treated as header without VLAN tag |
26 | * and byte 12 and 13 is used to program a given Ether type instead |
27 | */ |
28 | static const u8 [DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0, |
29 | 0x2, 0, 0, 0, 0, 0, |
30 | 0x81, 0, 0, 0}; |
31 | |
32 | enum { |
33 | ICE_PKT_OUTER_IPV6 = BIT(0), |
34 | ICE_PKT_TUN_GTPC = BIT(1), |
35 | ICE_PKT_TUN_GTPU = BIT(2), |
36 | ICE_PKT_TUN_NVGRE = BIT(3), |
37 | ICE_PKT_TUN_UDP = BIT(4), |
38 | ICE_PKT_INNER_IPV6 = BIT(5), |
39 | ICE_PKT_INNER_TCP = BIT(6), |
40 | ICE_PKT_INNER_UDP = BIT(7), |
41 | ICE_PKT_GTP_NOPAY = BIT(8), |
42 | ICE_PKT_KMALLOC = BIT(9), |
43 | ICE_PKT_PPPOE = BIT(10), |
44 | ICE_PKT_L2TPV3 = BIT(11), |
45 | }; |
46 | |
47 | struct ice_dummy_pkt_offsets { |
48 | enum ice_protocol_type type; |
49 | u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */ |
50 | }; |
51 | |
52 | struct ice_dummy_pkt_profile { |
53 | const struct ice_dummy_pkt_offsets *offsets; |
54 | const u8 *pkt; |
55 | u32 match; |
56 | u16 pkt_len; |
57 | u16 offsets_len; |
58 | }; |
59 | |
60 | #define ICE_DECLARE_PKT_OFFSETS(type) \ |
61 | static const struct ice_dummy_pkt_offsets \ |
62 | ice_dummy_##type##_packet_offsets[] |
63 | |
64 | #define ICE_DECLARE_PKT_TEMPLATE(type) \ |
65 | static const u8 ice_dummy_##type##_packet[] |
66 | |
67 | #define ICE_PKT_PROFILE(type, m) { \ |
68 | .match = (m), \ |
69 | .pkt = ice_dummy_##type##_packet, \ |
70 | .pkt_len = sizeof(ice_dummy_##type##_packet), \ |
71 | .offsets = ice_dummy_##type##_packet_offsets, \ |
72 | .offsets_len = sizeof(ice_dummy_##type##_packet_offsets), \ |
73 | } |
74 | |
75 | ICE_DECLARE_PKT_OFFSETS(vlan) = { |
76 | { ICE_VLAN_OFOS, 12 }, |
77 | }; |
78 | |
79 | ICE_DECLARE_PKT_TEMPLATE(vlan) = { |
80 | 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */ |
81 | }; |
82 | |
83 | ICE_DECLARE_PKT_OFFSETS(qinq) = { |
84 | { ICE_VLAN_EX, 12 }, |
85 | { ICE_VLAN_IN, 16 }, |
86 | }; |
87 | |
88 | ICE_DECLARE_PKT_TEMPLATE(qinq) = { |
89 | 0x91, 0x00, 0x00, 0x00, /* ICE_VLAN_EX 12 */ |
90 | 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_IN 16 */ |
91 | }; |
92 | |
93 | ICE_DECLARE_PKT_OFFSETS(gre_tcp) = { |
94 | { ICE_MAC_OFOS, 0 }, |
95 | { ICE_ETYPE_OL, 12 }, |
96 | { ICE_IPV4_OFOS, 14 }, |
97 | { ICE_NVGRE, 34 }, |
98 | { ICE_MAC_IL, 42 }, |
99 | { ICE_ETYPE_IL, 54 }, |
100 | { ICE_IPV4_IL, 56 }, |
101 | { ICE_TCP_IL, 76 }, |
102 | { ICE_PROTOCOL_LAST, 0 }, |
103 | }; |
104 | |
105 | ICE_DECLARE_PKT_TEMPLATE(gre_tcp) = { |
106 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
107 | 0x00, 0x00, 0x00, 0x00, |
108 | 0x00, 0x00, 0x00, 0x00, |
109 | |
110 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
111 | |
112 | 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ |
113 | 0x00, 0x00, 0x00, 0x00, |
114 | 0x00, 0x2F, 0x00, 0x00, |
115 | 0x00, 0x00, 0x00, 0x00, |
116 | 0x00, 0x00, 0x00, 0x00, |
117 | |
118 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ |
119 | 0x00, 0x00, 0x00, 0x00, |
120 | |
121 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ |
122 | 0x00, 0x00, 0x00, 0x00, |
123 | 0x00, 0x00, 0x00, 0x00, |
124 | |
125 | 0x08, 0x00, /* ICE_ETYPE_IL 54 */ |
126 | |
127 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ |
128 | 0x00, 0x00, 0x00, 0x00, |
129 | 0x00, 0x06, 0x00, 0x00, |
130 | 0x00, 0x00, 0x00, 0x00, |
131 | 0x00, 0x00, 0x00, 0x00, |
132 | |
133 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 76 */ |
134 | 0x00, 0x00, 0x00, 0x00, |
135 | 0x00, 0x00, 0x00, 0x00, |
136 | 0x50, 0x02, 0x20, 0x00, |
137 | 0x00, 0x00, 0x00, 0x00 |
138 | }; |
139 | |
140 | ICE_DECLARE_PKT_OFFSETS(gre_udp) = { |
141 | { ICE_MAC_OFOS, 0 }, |
142 | { ICE_ETYPE_OL, 12 }, |
143 | { ICE_IPV4_OFOS, 14 }, |
144 | { ICE_NVGRE, 34 }, |
145 | { ICE_MAC_IL, 42 }, |
146 | { ICE_ETYPE_IL, 54 }, |
147 | { ICE_IPV4_IL, 56 }, |
148 | { ICE_UDP_ILOS, 76 }, |
149 | { ICE_PROTOCOL_LAST, 0 }, |
150 | }; |
151 | |
152 | ICE_DECLARE_PKT_TEMPLATE(gre_udp) = { |
153 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
154 | 0x00, 0x00, 0x00, 0x00, |
155 | 0x00, 0x00, 0x00, 0x00, |
156 | |
157 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
158 | |
159 | 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ |
160 | 0x00, 0x00, 0x00, 0x00, |
161 | 0x00, 0x2F, 0x00, 0x00, |
162 | 0x00, 0x00, 0x00, 0x00, |
163 | 0x00, 0x00, 0x00, 0x00, |
164 | |
165 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ |
166 | 0x00, 0x00, 0x00, 0x00, |
167 | |
168 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ |
169 | 0x00, 0x00, 0x00, 0x00, |
170 | 0x00, 0x00, 0x00, 0x00, |
171 | |
172 | 0x08, 0x00, /* ICE_ETYPE_IL 54 */ |
173 | |
174 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ |
175 | 0x00, 0x00, 0x00, 0x00, |
176 | 0x00, 0x11, 0x00, 0x00, |
177 | 0x00, 0x00, 0x00, 0x00, |
178 | 0x00, 0x00, 0x00, 0x00, |
179 | |
180 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 76 */ |
181 | 0x00, 0x08, 0x00, 0x00, |
182 | }; |
183 | |
184 | ICE_DECLARE_PKT_OFFSETS(udp_tun_tcp) = { |
185 | { ICE_MAC_OFOS, 0 }, |
186 | { ICE_ETYPE_OL, 12 }, |
187 | { ICE_IPV4_OFOS, 14 }, |
188 | { ICE_UDP_OF, 34 }, |
189 | { ICE_VXLAN, 42 }, |
190 | { ICE_GENEVE, 42 }, |
191 | { ICE_VXLAN_GPE, 42 }, |
192 | { ICE_MAC_IL, 50 }, |
193 | { ICE_ETYPE_IL, 62 }, |
194 | { ICE_IPV4_IL, 64 }, |
195 | { ICE_TCP_IL, 84 }, |
196 | { ICE_PROTOCOL_LAST, 0 }, |
197 | }; |
198 | |
199 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_tcp) = { |
200 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
201 | 0x00, 0x00, 0x00, 0x00, |
202 | 0x00, 0x00, 0x00, 0x00, |
203 | |
204 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
205 | |
206 | 0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */ |
207 | 0x00, 0x01, 0x00, 0x00, |
208 | 0x40, 0x11, 0x00, 0x00, |
209 | 0x00, 0x00, 0x00, 0x00, |
210 | 0x00, 0x00, 0x00, 0x00, |
211 | |
212 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ |
213 | 0x00, 0x46, 0x00, 0x00, |
214 | |
215 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ |
216 | 0x00, 0x00, 0x00, 0x00, |
217 | |
218 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ |
219 | 0x00, 0x00, 0x00, 0x00, |
220 | 0x00, 0x00, 0x00, 0x00, |
221 | |
222 | 0x08, 0x00, /* ICE_ETYPE_IL 62 */ |
223 | |
224 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */ |
225 | 0x00, 0x01, 0x00, 0x00, |
226 | 0x40, 0x06, 0x00, 0x00, |
227 | 0x00, 0x00, 0x00, 0x00, |
228 | 0x00, 0x00, 0x00, 0x00, |
229 | |
230 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */ |
231 | 0x00, 0x00, 0x00, 0x00, |
232 | 0x00, 0x00, 0x00, 0x00, |
233 | 0x50, 0x02, 0x20, 0x00, |
234 | 0x00, 0x00, 0x00, 0x00 |
235 | }; |
236 | |
237 | ICE_DECLARE_PKT_OFFSETS(udp_tun_udp) = { |
238 | { ICE_MAC_OFOS, 0 }, |
239 | { ICE_ETYPE_OL, 12 }, |
240 | { ICE_IPV4_OFOS, 14 }, |
241 | { ICE_UDP_OF, 34 }, |
242 | { ICE_VXLAN, 42 }, |
243 | { ICE_GENEVE, 42 }, |
244 | { ICE_VXLAN_GPE, 42 }, |
245 | { ICE_MAC_IL, 50 }, |
246 | { ICE_ETYPE_IL, 62 }, |
247 | { ICE_IPV4_IL, 64 }, |
248 | { ICE_UDP_ILOS, 84 }, |
249 | { ICE_PROTOCOL_LAST, 0 }, |
250 | }; |
251 | |
252 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_udp) = { |
253 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
254 | 0x00, 0x00, 0x00, 0x00, |
255 | 0x00, 0x00, 0x00, 0x00, |
256 | |
257 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
258 | |
259 | 0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */ |
260 | 0x00, 0x01, 0x00, 0x00, |
261 | 0x00, 0x11, 0x00, 0x00, |
262 | 0x00, 0x00, 0x00, 0x00, |
263 | 0x00, 0x00, 0x00, 0x00, |
264 | |
265 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ |
266 | 0x00, 0x3a, 0x00, 0x00, |
267 | |
268 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ |
269 | 0x00, 0x00, 0x00, 0x00, |
270 | |
271 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ |
272 | 0x00, 0x00, 0x00, 0x00, |
273 | 0x00, 0x00, 0x00, 0x00, |
274 | |
275 | 0x08, 0x00, /* ICE_ETYPE_IL 62 */ |
276 | |
277 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */ |
278 | 0x00, 0x01, 0x00, 0x00, |
279 | 0x00, 0x11, 0x00, 0x00, |
280 | 0x00, 0x00, 0x00, 0x00, |
281 | 0x00, 0x00, 0x00, 0x00, |
282 | |
283 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */ |
284 | 0x00, 0x08, 0x00, 0x00, |
285 | }; |
286 | |
287 | ICE_DECLARE_PKT_OFFSETS(gre_ipv6_tcp) = { |
288 | { ICE_MAC_OFOS, 0 }, |
289 | { ICE_ETYPE_OL, 12 }, |
290 | { ICE_IPV4_OFOS, 14 }, |
291 | { ICE_NVGRE, 34 }, |
292 | { ICE_MAC_IL, 42 }, |
293 | { ICE_ETYPE_IL, 54 }, |
294 | { ICE_IPV6_IL, 56 }, |
295 | { ICE_TCP_IL, 96 }, |
296 | { ICE_PROTOCOL_LAST, 0 }, |
297 | }; |
298 | |
299 | ICE_DECLARE_PKT_TEMPLATE(gre_ipv6_tcp) = { |
300 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
301 | 0x00, 0x00, 0x00, 0x00, |
302 | 0x00, 0x00, 0x00, 0x00, |
303 | |
304 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
305 | |
306 | 0x45, 0x00, 0x00, 0x66, /* ICE_IPV4_OFOS 14 */ |
307 | 0x00, 0x00, 0x00, 0x00, |
308 | 0x00, 0x2F, 0x00, 0x00, |
309 | 0x00, 0x00, 0x00, 0x00, |
310 | 0x00, 0x00, 0x00, 0x00, |
311 | |
312 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ |
313 | 0x00, 0x00, 0x00, 0x00, |
314 | |
315 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ |
316 | 0x00, 0x00, 0x00, 0x00, |
317 | 0x00, 0x00, 0x00, 0x00, |
318 | |
319 | 0x86, 0xdd, /* ICE_ETYPE_IL 54 */ |
320 | |
321 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */ |
322 | 0x00, 0x08, 0x06, 0x40, |
323 | 0x00, 0x00, 0x00, 0x00, |
324 | 0x00, 0x00, 0x00, 0x00, |
325 | 0x00, 0x00, 0x00, 0x00, |
326 | 0x00, 0x00, 0x00, 0x00, |
327 | 0x00, 0x00, 0x00, 0x00, |
328 | 0x00, 0x00, 0x00, 0x00, |
329 | 0x00, 0x00, 0x00, 0x00, |
330 | 0x00, 0x00, 0x00, 0x00, |
331 | |
332 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 96 */ |
333 | 0x00, 0x00, 0x00, 0x00, |
334 | 0x00, 0x00, 0x00, 0x00, |
335 | 0x50, 0x02, 0x20, 0x00, |
336 | 0x00, 0x00, 0x00, 0x00 |
337 | }; |
338 | |
339 | ICE_DECLARE_PKT_OFFSETS(gre_ipv6_udp) = { |
340 | { ICE_MAC_OFOS, 0 }, |
341 | { ICE_ETYPE_OL, 12 }, |
342 | { ICE_IPV4_OFOS, 14 }, |
343 | { ICE_NVGRE, 34 }, |
344 | { ICE_MAC_IL, 42 }, |
345 | { ICE_ETYPE_IL, 54 }, |
346 | { ICE_IPV6_IL, 56 }, |
347 | { ICE_UDP_ILOS, 96 }, |
348 | { ICE_PROTOCOL_LAST, 0 }, |
349 | }; |
350 | |
351 | ICE_DECLARE_PKT_TEMPLATE(gre_ipv6_udp) = { |
352 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
353 | 0x00, 0x00, 0x00, 0x00, |
354 | 0x00, 0x00, 0x00, 0x00, |
355 | |
356 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
357 | |
358 | 0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */ |
359 | 0x00, 0x00, 0x00, 0x00, |
360 | 0x00, 0x2F, 0x00, 0x00, |
361 | 0x00, 0x00, 0x00, 0x00, |
362 | 0x00, 0x00, 0x00, 0x00, |
363 | |
364 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ |
365 | 0x00, 0x00, 0x00, 0x00, |
366 | |
367 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ |
368 | 0x00, 0x00, 0x00, 0x00, |
369 | 0x00, 0x00, 0x00, 0x00, |
370 | |
371 | 0x86, 0xdd, /* ICE_ETYPE_IL 54 */ |
372 | |
373 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */ |
374 | 0x00, 0x08, 0x11, 0x40, |
375 | 0x00, 0x00, 0x00, 0x00, |
376 | 0x00, 0x00, 0x00, 0x00, |
377 | 0x00, 0x00, 0x00, 0x00, |
378 | 0x00, 0x00, 0x00, 0x00, |
379 | 0x00, 0x00, 0x00, 0x00, |
380 | 0x00, 0x00, 0x00, 0x00, |
381 | 0x00, 0x00, 0x00, 0x00, |
382 | 0x00, 0x00, 0x00, 0x00, |
383 | |
384 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 96 */ |
385 | 0x00, 0x08, 0x00, 0x00, |
386 | }; |
387 | |
388 | ICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_tcp) = { |
389 | { ICE_MAC_OFOS, 0 }, |
390 | { ICE_ETYPE_OL, 12 }, |
391 | { ICE_IPV4_OFOS, 14 }, |
392 | { ICE_UDP_OF, 34 }, |
393 | { ICE_VXLAN, 42 }, |
394 | { ICE_GENEVE, 42 }, |
395 | { ICE_VXLAN_GPE, 42 }, |
396 | { ICE_MAC_IL, 50 }, |
397 | { ICE_ETYPE_IL, 62 }, |
398 | { ICE_IPV6_IL, 64 }, |
399 | { ICE_TCP_IL, 104 }, |
400 | { ICE_PROTOCOL_LAST, 0 }, |
401 | }; |
402 | |
403 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_tcp) = { |
404 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
405 | 0x00, 0x00, 0x00, 0x00, |
406 | 0x00, 0x00, 0x00, 0x00, |
407 | |
408 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
409 | |
410 | 0x45, 0x00, 0x00, 0x6e, /* ICE_IPV4_OFOS 14 */ |
411 | 0x00, 0x01, 0x00, 0x00, |
412 | 0x40, 0x11, 0x00, 0x00, |
413 | 0x00, 0x00, 0x00, 0x00, |
414 | 0x00, 0x00, 0x00, 0x00, |
415 | |
416 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ |
417 | 0x00, 0x5a, 0x00, 0x00, |
418 | |
419 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ |
420 | 0x00, 0x00, 0x00, 0x00, |
421 | |
422 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ |
423 | 0x00, 0x00, 0x00, 0x00, |
424 | 0x00, 0x00, 0x00, 0x00, |
425 | |
426 | 0x86, 0xdd, /* ICE_ETYPE_IL 62 */ |
427 | |
428 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */ |
429 | 0x00, 0x08, 0x06, 0x40, |
430 | 0x00, 0x00, 0x00, 0x00, |
431 | 0x00, 0x00, 0x00, 0x00, |
432 | 0x00, 0x00, 0x00, 0x00, |
433 | 0x00, 0x00, 0x00, 0x00, |
434 | 0x00, 0x00, 0x00, 0x00, |
435 | 0x00, 0x00, 0x00, 0x00, |
436 | 0x00, 0x00, 0x00, 0x00, |
437 | 0x00, 0x00, 0x00, 0x00, |
438 | |
439 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 104 */ |
440 | 0x00, 0x00, 0x00, 0x00, |
441 | 0x00, 0x00, 0x00, 0x00, |
442 | 0x50, 0x02, 0x20, 0x00, |
443 | 0x00, 0x00, 0x00, 0x00 |
444 | }; |
445 | |
446 | ICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_udp) = { |
447 | { ICE_MAC_OFOS, 0 }, |
448 | { ICE_ETYPE_OL, 12 }, |
449 | { ICE_IPV4_OFOS, 14 }, |
450 | { ICE_UDP_OF, 34 }, |
451 | { ICE_VXLAN, 42 }, |
452 | { ICE_GENEVE, 42 }, |
453 | { ICE_VXLAN_GPE, 42 }, |
454 | { ICE_MAC_IL, 50 }, |
455 | { ICE_ETYPE_IL, 62 }, |
456 | { ICE_IPV6_IL, 64 }, |
457 | { ICE_UDP_ILOS, 104 }, |
458 | { ICE_PROTOCOL_LAST, 0 }, |
459 | }; |
460 | |
461 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_udp) = { |
462 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
463 | 0x00, 0x00, 0x00, 0x00, |
464 | 0x00, 0x00, 0x00, 0x00, |
465 | |
466 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
467 | |
468 | 0x45, 0x00, 0x00, 0x62, /* ICE_IPV4_OFOS 14 */ |
469 | 0x00, 0x01, 0x00, 0x00, |
470 | 0x00, 0x11, 0x00, 0x00, |
471 | 0x00, 0x00, 0x00, 0x00, |
472 | 0x00, 0x00, 0x00, 0x00, |
473 | |
474 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ |
475 | 0x00, 0x4e, 0x00, 0x00, |
476 | |
477 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ |
478 | 0x00, 0x00, 0x00, 0x00, |
479 | |
480 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ |
481 | 0x00, 0x00, 0x00, 0x00, |
482 | 0x00, 0x00, 0x00, 0x00, |
483 | |
484 | 0x86, 0xdd, /* ICE_ETYPE_IL 62 */ |
485 | |
486 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */ |
487 | 0x00, 0x08, 0x11, 0x40, |
488 | 0x00, 0x00, 0x00, 0x00, |
489 | 0x00, 0x00, 0x00, 0x00, |
490 | 0x00, 0x00, 0x00, 0x00, |
491 | 0x00, 0x00, 0x00, 0x00, |
492 | 0x00, 0x00, 0x00, 0x00, |
493 | 0x00, 0x00, 0x00, 0x00, |
494 | 0x00, 0x00, 0x00, 0x00, |
495 | 0x00, 0x00, 0x00, 0x00, |
496 | |
497 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 104 */ |
498 | 0x00, 0x08, 0x00, 0x00, |
499 | }; |
500 | |
501 | /* offset info for MAC + IPv4 + UDP dummy packet */ |
502 | ICE_DECLARE_PKT_OFFSETS(udp) = { |
503 | { ICE_MAC_OFOS, 0 }, |
504 | { ICE_ETYPE_OL, 12 }, |
505 | { ICE_IPV4_OFOS, 14 }, |
506 | { ICE_UDP_ILOS, 34 }, |
507 | { ICE_PROTOCOL_LAST, 0 }, |
508 | }; |
509 | |
510 | /* Dummy packet for MAC + IPv4 + UDP */ |
511 | ICE_DECLARE_PKT_TEMPLATE(udp) = { |
512 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
513 | 0x00, 0x00, 0x00, 0x00, |
514 | 0x00, 0x00, 0x00, 0x00, |
515 | |
516 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
517 | |
518 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */ |
519 | 0x00, 0x01, 0x00, 0x00, |
520 | 0x00, 0x11, 0x00, 0x00, |
521 | 0x00, 0x00, 0x00, 0x00, |
522 | 0x00, 0x00, 0x00, 0x00, |
523 | |
524 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */ |
525 | 0x00, 0x08, 0x00, 0x00, |
526 | |
527 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
528 | }; |
529 | |
530 | /* offset info for MAC + IPv4 + TCP dummy packet */ |
531 | ICE_DECLARE_PKT_OFFSETS(tcp) = { |
532 | { ICE_MAC_OFOS, 0 }, |
533 | { ICE_ETYPE_OL, 12 }, |
534 | { ICE_IPV4_OFOS, 14 }, |
535 | { ICE_TCP_IL, 34 }, |
536 | { ICE_PROTOCOL_LAST, 0 }, |
537 | }; |
538 | |
539 | /* Dummy packet for MAC + IPv4 + TCP */ |
540 | ICE_DECLARE_PKT_TEMPLATE(tcp) = { |
541 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
542 | 0x00, 0x00, 0x00, 0x00, |
543 | 0x00, 0x00, 0x00, 0x00, |
544 | |
545 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
546 | |
547 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */ |
548 | 0x00, 0x01, 0x00, 0x00, |
549 | 0x00, 0x06, 0x00, 0x00, |
550 | 0x00, 0x00, 0x00, 0x00, |
551 | 0x00, 0x00, 0x00, 0x00, |
552 | |
553 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */ |
554 | 0x00, 0x00, 0x00, 0x00, |
555 | 0x00, 0x00, 0x00, 0x00, |
556 | 0x50, 0x00, 0x00, 0x00, |
557 | 0x00, 0x00, 0x00, 0x00, |
558 | |
559 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
560 | }; |
561 | |
562 | ICE_DECLARE_PKT_OFFSETS(tcp_ipv6) = { |
563 | { ICE_MAC_OFOS, 0 }, |
564 | { ICE_ETYPE_OL, 12 }, |
565 | { ICE_IPV6_OFOS, 14 }, |
566 | { ICE_TCP_IL, 54 }, |
567 | { ICE_PROTOCOL_LAST, 0 }, |
568 | }; |
569 | |
570 | ICE_DECLARE_PKT_TEMPLATE(tcp_ipv6) = { |
571 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
572 | 0x00, 0x00, 0x00, 0x00, |
573 | 0x00, 0x00, 0x00, 0x00, |
574 | |
575 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ |
576 | |
577 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ |
578 | 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ |
579 | 0x00, 0x00, 0x00, 0x00, |
580 | 0x00, 0x00, 0x00, 0x00, |
581 | 0x00, 0x00, 0x00, 0x00, |
582 | 0x00, 0x00, 0x00, 0x00, |
583 | 0x00, 0x00, 0x00, 0x00, |
584 | 0x00, 0x00, 0x00, 0x00, |
585 | 0x00, 0x00, 0x00, 0x00, |
586 | 0x00, 0x00, 0x00, 0x00, |
587 | |
588 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */ |
589 | 0x00, 0x00, 0x00, 0x00, |
590 | 0x00, 0x00, 0x00, 0x00, |
591 | 0x50, 0x00, 0x00, 0x00, |
592 | 0x00, 0x00, 0x00, 0x00, |
593 | |
594 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
595 | }; |
596 | |
597 | /* IPv6 + UDP */ |
598 | ICE_DECLARE_PKT_OFFSETS(udp_ipv6) = { |
599 | { ICE_MAC_OFOS, 0 }, |
600 | { ICE_ETYPE_OL, 12 }, |
601 | { ICE_IPV6_OFOS, 14 }, |
602 | { ICE_UDP_ILOS, 54 }, |
603 | { ICE_PROTOCOL_LAST, 0 }, |
604 | }; |
605 | |
606 | /* IPv6 + UDP dummy packet */ |
607 | ICE_DECLARE_PKT_TEMPLATE(udp_ipv6) = { |
608 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
609 | 0x00, 0x00, 0x00, 0x00, |
610 | 0x00, 0x00, 0x00, 0x00, |
611 | |
612 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ |
613 | |
614 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ |
615 | 0x00, 0x10, 0x11, 0x00, /* Next header UDP */ |
616 | 0x00, 0x00, 0x00, 0x00, |
617 | 0x00, 0x00, 0x00, 0x00, |
618 | 0x00, 0x00, 0x00, 0x00, |
619 | 0x00, 0x00, 0x00, 0x00, |
620 | 0x00, 0x00, 0x00, 0x00, |
621 | 0x00, 0x00, 0x00, 0x00, |
622 | 0x00, 0x00, 0x00, 0x00, |
623 | 0x00, 0x00, 0x00, 0x00, |
624 | |
625 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */ |
626 | 0x00, 0x10, 0x00, 0x00, |
627 | |
628 | 0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */ |
629 | 0x00, 0x00, 0x00, 0x00, |
630 | |
631 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
632 | }; |
633 | |
634 | /* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner TCP */ |
635 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_tcp) = { |
636 | { ICE_MAC_OFOS, 0 }, |
637 | { ICE_IPV4_OFOS, 14 }, |
638 | { ICE_UDP_OF, 34 }, |
639 | { ICE_GTP, 42 }, |
640 | { ICE_IPV4_IL, 62 }, |
641 | { ICE_TCP_IL, 82 }, |
642 | { ICE_PROTOCOL_LAST, 0 }, |
643 | }; |
644 | |
645 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_tcp) = { |
646 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
647 | 0x00, 0x00, 0x00, 0x00, |
648 | 0x00, 0x00, 0x00, 0x00, |
649 | 0x08, 0x00, |
650 | |
651 | 0x45, 0x00, 0x00, 0x58, /* IP 14 */ |
652 | 0x00, 0x00, 0x00, 0x00, |
653 | 0x00, 0x11, 0x00, 0x00, |
654 | 0x00, 0x00, 0x00, 0x00, |
655 | 0x00, 0x00, 0x00, 0x00, |
656 | |
657 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ |
658 | 0x00, 0x44, 0x00, 0x00, |
659 | |
660 | 0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 42 */ |
661 | 0x00, 0x00, 0x00, 0x00, |
662 | 0x00, 0x00, 0x00, 0x85, |
663 | |
664 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ |
665 | 0x00, 0x00, 0x00, 0x00, |
666 | |
667 | 0x45, 0x00, 0x00, 0x28, /* IP 62 */ |
668 | 0x00, 0x00, 0x00, 0x00, |
669 | 0x00, 0x06, 0x00, 0x00, |
670 | 0x00, 0x00, 0x00, 0x00, |
671 | 0x00, 0x00, 0x00, 0x00, |
672 | |
673 | 0x00, 0x00, 0x00, 0x00, /* TCP 82 */ |
674 | 0x00, 0x00, 0x00, 0x00, |
675 | 0x00, 0x00, 0x00, 0x00, |
676 | 0x50, 0x00, 0x00, 0x00, |
677 | 0x00, 0x00, 0x00, 0x00, |
678 | |
679 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
680 | }; |
681 | |
682 | /* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner UDP */ |
683 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_udp) = { |
684 | { ICE_MAC_OFOS, 0 }, |
685 | { ICE_IPV4_OFOS, 14 }, |
686 | { ICE_UDP_OF, 34 }, |
687 | { ICE_GTP, 42 }, |
688 | { ICE_IPV4_IL, 62 }, |
689 | { ICE_UDP_ILOS, 82 }, |
690 | { ICE_PROTOCOL_LAST, 0 }, |
691 | }; |
692 | |
693 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_udp) = { |
694 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
695 | 0x00, 0x00, 0x00, 0x00, |
696 | 0x00, 0x00, 0x00, 0x00, |
697 | 0x08, 0x00, |
698 | |
699 | 0x45, 0x00, 0x00, 0x4c, /* IP 14 */ |
700 | 0x00, 0x00, 0x00, 0x00, |
701 | 0x00, 0x11, 0x00, 0x00, |
702 | 0x00, 0x00, 0x00, 0x00, |
703 | 0x00, 0x00, 0x00, 0x00, |
704 | |
705 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ |
706 | 0x00, 0x38, 0x00, 0x00, |
707 | |
708 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 42 */ |
709 | 0x00, 0x00, 0x00, 0x00, |
710 | 0x00, 0x00, 0x00, 0x85, |
711 | |
712 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ |
713 | 0x00, 0x00, 0x00, 0x00, |
714 | |
715 | 0x45, 0x00, 0x00, 0x1c, /* IP 62 */ |
716 | 0x00, 0x00, 0x00, 0x00, |
717 | 0x00, 0x11, 0x00, 0x00, |
718 | 0x00, 0x00, 0x00, 0x00, |
719 | 0x00, 0x00, 0x00, 0x00, |
720 | |
721 | 0x00, 0x00, 0x00, 0x00, /* UDP 82 */ |
722 | 0x00, 0x08, 0x00, 0x00, |
723 | |
724 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
725 | }; |
726 | |
727 | /* Outer IPv6 + Outer UDP + GTP + Inner IPv4 + Inner TCP */ |
728 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_tcp) = { |
729 | { ICE_MAC_OFOS, 0 }, |
730 | { ICE_IPV4_OFOS, 14 }, |
731 | { ICE_UDP_OF, 34 }, |
732 | { ICE_GTP, 42 }, |
733 | { ICE_IPV6_IL, 62 }, |
734 | { ICE_TCP_IL, 102 }, |
735 | { ICE_PROTOCOL_LAST, 0 }, |
736 | }; |
737 | |
738 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_tcp) = { |
739 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
740 | 0x00, 0x00, 0x00, 0x00, |
741 | 0x00, 0x00, 0x00, 0x00, |
742 | 0x08, 0x00, |
743 | |
744 | 0x45, 0x00, 0x00, 0x6c, /* IP 14 */ |
745 | 0x00, 0x00, 0x00, 0x00, |
746 | 0x00, 0x11, 0x00, 0x00, |
747 | 0x00, 0x00, 0x00, 0x00, |
748 | 0x00, 0x00, 0x00, 0x00, |
749 | |
750 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ |
751 | 0x00, 0x58, 0x00, 0x00, |
752 | |
753 | 0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 42 */ |
754 | 0x00, 0x00, 0x00, 0x00, |
755 | 0x00, 0x00, 0x00, 0x85, |
756 | |
757 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ |
758 | 0x00, 0x00, 0x00, 0x00, |
759 | |
760 | 0x60, 0x00, 0x00, 0x00, /* IPv6 62 */ |
761 | 0x00, 0x14, 0x06, 0x00, |
762 | 0x00, 0x00, 0x00, 0x00, |
763 | 0x00, 0x00, 0x00, 0x00, |
764 | 0x00, 0x00, 0x00, 0x00, |
765 | 0x00, 0x00, 0x00, 0x00, |
766 | 0x00, 0x00, 0x00, 0x00, |
767 | 0x00, 0x00, 0x00, 0x00, |
768 | 0x00, 0x00, 0x00, 0x00, |
769 | 0x00, 0x00, 0x00, 0x00, |
770 | |
771 | 0x00, 0x00, 0x00, 0x00, /* TCP 102 */ |
772 | 0x00, 0x00, 0x00, 0x00, |
773 | 0x00, 0x00, 0x00, 0x00, |
774 | 0x50, 0x00, 0x00, 0x00, |
775 | 0x00, 0x00, 0x00, 0x00, |
776 | |
777 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
778 | }; |
779 | |
780 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_udp) = { |
781 | { ICE_MAC_OFOS, 0 }, |
782 | { ICE_IPV4_OFOS, 14 }, |
783 | { ICE_UDP_OF, 34 }, |
784 | { ICE_GTP, 42 }, |
785 | { ICE_IPV6_IL, 62 }, |
786 | { ICE_UDP_ILOS, 102 }, |
787 | { ICE_PROTOCOL_LAST, 0 }, |
788 | }; |
789 | |
790 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_udp) = { |
791 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
792 | 0x00, 0x00, 0x00, 0x00, |
793 | 0x00, 0x00, 0x00, 0x00, |
794 | 0x08, 0x00, |
795 | |
796 | 0x45, 0x00, 0x00, 0x60, /* IP 14 */ |
797 | 0x00, 0x00, 0x00, 0x00, |
798 | 0x00, 0x11, 0x00, 0x00, |
799 | 0x00, 0x00, 0x00, 0x00, |
800 | 0x00, 0x00, 0x00, 0x00, |
801 | |
802 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ |
803 | 0x00, 0x4c, 0x00, 0x00, |
804 | |
805 | 0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 42 */ |
806 | 0x00, 0x00, 0x00, 0x00, |
807 | 0x00, 0x00, 0x00, 0x85, |
808 | |
809 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ |
810 | 0x00, 0x00, 0x00, 0x00, |
811 | |
812 | 0x60, 0x00, 0x00, 0x00, /* IPv6 62 */ |
813 | 0x00, 0x08, 0x11, 0x00, |
814 | 0x00, 0x00, 0x00, 0x00, |
815 | 0x00, 0x00, 0x00, 0x00, |
816 | 0x00, 0x00, 0x00, 0x00, |
817 | 0x00, 0x00, 0x00, 0x00, |
818 | 0x00, 0x00, 0x00, 0x00, |
819 | 0x00, 0x00, 0x00, 0x00, |
820 | 0x00, 0x00, 0x00, 0x00, |
821 | 0x00, 0x00, 0x00, 0x00, |
822 | |
823 | 0x00, 0x00, 0x00, 0x00, /* UDP 102 */ |
824 | 0x00, 0x08, 0x00, 0x00, |
825 | |
826 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
827 | }; |
828 | |
829 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_tcp) = { |
830 | { ICE_MAC_OFOS, 0 }, |
831 | { ICE_IPV6_OFOS, 14 }, |
832 | { ICE_UDP_OF, 54 }, |
833 | { ICE_GTP, 62 }, |
834 | { ICE_IPV4_IL, 82 }, |
835 | { ICE_TCP_IL, 102 }, |
836 | { ICE_PROTOCOL_LAST, 0 }, |
837 | }; |
838 | |
839 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_tcp) = { |
840 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
841 | 0x00, 0x00, 0x00, 0x00, |
842 | 0x00, 0x00, 0x00, 0x00, |
843 | 0x86, 0xdd, |
844 | |
845 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ |
846 | 0x00, 0x44, 0x11, 0x00, |
847 | 0x00, 0x00, 0x00, 0x00, |
848 | 0x00, 0x00, 0x00, 0x00, |
849 | 0x00, 0x00, 0x00, 0x00, |
850 | 0x00, 0x00, 0x00, 0x00, |
851 | 0x00, 0x00, 0x00, 0x00, |
852 | 0x00, 0x00, 0x00, 0x00, |
853 | 0x00, 0x00, 0x00, 0x00, |
854 | 0x00, 0x00, 0x00, 0x00, |
855 | |
856 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ |
857 | 0x00, 0x44, 0x00, 0x00, |
858 | |
859 | 0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 62 */ |
860 | 0x00, 0x00, 0x00, 0x00, |
861 | 0x00, 0x00, 0x00, 0x85, |
862 | |
863 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ |
864 | 0x00, 0x00, 0x00, 0x00, |
865 | |
866 | 0x45, 0x00, 0x00, 0x28, /* IP 82 */ |
867 | 0x00, 0x00, 0x00, 0x00, |
868 | 0x00, 0x06, 0x00, 0x00, |
869 | 0x00, 0x00, 0x00, 0x00, |
870 | 0x00, 0x00, 0x00, 0x00, |
871 | |
872 | 0x00, 0x00, 0x00, 0x00, /* TCP 102 */ |
873 | 0x00, 0x00, 0x00, 0x00, |
874 | 0x00, 0x00, 0x00, 0x00, |
875 | 0x50, 0x00, 0x00, 0x00, |
876 | 0x00, 0x00, 0x00, 0x00, |
877 | |
878 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
879 | }; |
880 | |
881 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_udp) = { |
882 | { ICE_MAC_OFOS, 0 }, |
883 | { ICE_IPV6_OFOS, 14 }, |
884 | { ICE_UDP_OF, 54 }, |
885 | { ICE_GTP, 62 }, |
886 | { ICE_IPV4_IL, 82 }, |
887 | { ICE_UDP_ILOS, 102 }, |
888 | { ICE_PROTOCOL_LAST, 0 }, |
889 | }; |
890 | |
891 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_udp) = { |
892 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
893 | 0x00, 0x00, 0x00, 0x00, |
894 | 0x00, 0x00, 0x00, 0x00, |
895 | 0x86, 0xdd, |
896 | |
897 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ |
898 | 0x00, 0x38, 0x11, 0x00, |
899 | 0x00, 0x00, 0x00, 0x00, |
900 | 0x00, 0x00, 0x00, 0x00, |
901 | 0x00, 0x00, 0x00, 0x00, |
902 | 0x00, 0x00, 0x00, 0x00, |
903 | 0x00, 0x00, 0x00, 0x00, |
904 | 0x00, 0x00, 0x00, 0x00, |
905 | 0x00, 0x00, 0x00, 0x00, |
906 | 0x00, 0x00, 0x00, 0x00, |
907 | |
908 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ |
909 | 0x00, 0x38, 0x00, 0x00, |
910 | |
911 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 62 */ |
912 | 0x00, 0x00, 0x00, 0x00, |
913 | 0x00, 0x00, 0x00, 0x85, |
914 | |
915 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ |
916 | 0x00, 0x00, 0x00, 0x00, |
917 | |
918 | 0x45, 0x00, 0x00, 0x1c, /* IP 82 */ |
919 | 0x00, 0x00, 0x00, 0x00, |
920 | 0x00, 0x11, 0x00, 0x00, |
921 | 0x00, 0x00, 0x00, 0x00, |
922 | 0x00, 0x00, 0x00, 0x00, |
923 | |
924 | 0x00, 0x00, 0x00, 0x00, /* UDP 102 */ |
925 | 0x00, 0x08, 0x00, 0x00, |
926 | |
927 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
928 | }; |
929 | |
930 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_tcp) = { |
931 | { ICE_MAC_OFOS, 0 }, |
932 | { ICE_IPV6_OFOS, 14 }, |
933 | { ICE_UDP_OF, 54 }, |
934 | { ICE_GTP, 62 }, |
935 | { ICE_IPV6_IL, 82 }, |
936 | { ICE_TCP_IL, 122 }, |
937 | { ICE_PROTOCOL_LAST, 0 }, |
938 | }; |
939 | |
940 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_tcp) = { |
941 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
942 | 0x00, 0x00, 0x00, 0x00, |
943 | 0x00, 0x00, 0x00, 0x00, |
944 | 0x86, 0xdd, |
945 | |
946 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ |
947 | 0x00, 0x58, 0x11, 0x00, |
948 | 0x00, 0x00, 0x00, 0x00, |
949 | 0x00, 0x00, 0x00, 0x00, |
950 | 0x00, 0x00, 0x00, 0x00, |
951 | 0x00, 0x00, 0x00, 0x00, |
952 | 0x00, 0x00, 0x00, 0x00, |
953 | 0x00, 0x00, 0x00, 0x00, |
954 | 0x00, 0x00, 0x00, 0x00, |
955 | 0x00, 0x00, 0x00, 0x00, |
956 | |
957 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ |
958 | 0x00, 0x58, 0x00, 0x00, |
959 | |
960 | 0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 62 */ |
961 | 0x00, 0x00, 0x00, 0x00, |
962 | 0x00, 0x00, 0x00, 0x85, |
963 | |
964 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ |
965 | 0x00, 0x00, 0x00, 0x00, |
966 | |
967 | 0x60, 0x00, 0x00, 0x00, /* IPv6 82 */ |
968 | 0x00, 0x14, 0x06, 0x00, |
969 | 0x00, 0x00, 0x00, 0x00, |
970 | 0x00, 0x00, 0x00, 0x00, |
971 | 0x00, 0x00, 0x00, 0x00, |
972 | 0x00, 0x00, 0x00, 0x00, |
973 | 0x00, 0x00, 0x00, 0x00, |
974 | 0x00, 0x00, 0x00, 0x00, |
975 | 0x00, 0x00, 0x00, 0x00, |
976 | 0x00, 0x00, 0x00, 0x00, |
977 | |
978 | 0x00, 0x00, 0x00, 0x00, /* TCP 122 */ |
979 | 0x00, 0x00, 0x00, 0x00, |
980 | 0x00, 0x00, 0x00, 0x00, |
981 | 0x50, 0x00, 0x00, 0x00, |
982 | 0x00, 0x00, 0x00, 0x00, |
983 | |
984 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
985 | }; |
986 | |
987 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_udp) = { |
988 | { ICE_MAC_OFOS, 0 }, |
989 | { ICE_IPV6_OFOS, 14 }, |
990 | { ICE_UDP_OF, 54 }, |
991 | { ICE_GTP, 62 }, |
992 | { ICE_IPV6_IL, 82 }, |
993 | { ICE_UDP_ILOS, 122 }, |
994 | { ICE_PROTOCOL_LAST, 0 }, |
995 | }; |
996 | |
997 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_udp) = { |
998 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
999 | 0x00, 0x00, 0x00, 0x00, |
1000 | 0x00, 0x00, 0x00, 0x00, |
1001 | 0x86, 0xdd, |
1002 | |
1003 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ |
1004 | 0x00, 0x4c, 0x11, 0x00, |
1005 | 0x00, 0x00, 0x00, 0x00, |
1006 | 0x00, 0x00, 0x00, 0x00, |
1007 | 0x00, 0x00, 0x00, 0x00, |
1008 | 0x00, 0x00, 0x00, 0x00, |
1009 | 0x00, 0x00, 0x00, 0x00, |
1010 | 0x00, 0x00, 0x00, 0x00, |
1011 | 0x00, 0x00, 0x00, 0x00, |
1012 | 0x00, 0x00, 0x00, 0x00, |
1013 | |
1014 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ |
1015 | 0x00, 0x4c, 0x00, 0x00, |
1016 | |
1017 | 0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 62 */ |
1018 | 0x00, 0x00, 0x00, 0x00, |
1019 | 0x00, 0x00, 0x00, 0x85, |
1020 | |
1021 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ |
1022 | 0x00, 0x00, 0x00, 0x00, |
1023 | |
1024 | 0x60, 0x00, 0x00, 0x00, /* IPv6 82 */ |
1025 | 0x00, 0x08, 0x11, 0x00, |
1026 | 0x00, 0x00, 0x00, 0x00, |
1027 | 0x00, 0x00, 0x00, 0x00, |
1028 | 0x00, 0x00, 0x00, 0x00, |
1029 | 0x00, 0x00, 0x00, 0x00, |
1030 | 0x00, 0x00, 0x00, 0x00, |
1031 | 0x00, 0x00, 0x00, 0x00, |
1032 | 0x00, 0x00, 0x00, 0x00, |
1033 | 0x00, 0x00, 0x00, 0x00, |
1034 | |
1035 | 0x00, 0x00, 0x00, 0x00, /* UDP 122 */ |
1036 | 0x00, 0x08, 0x00, 0x00, |
1037 | |
1038 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ |
1039 | }; |
1040 | |
1041 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4) = { |
1042 | { ICE_MAC_OFOS, 0 }, |
1043 | { ICE_IPV4_OFOS, 14 }, |
1044 | { ICE_UDP_OF, 34 }, |
1045 | { ICE_GTP_NO_PAY, 42 }, |
1046 | { ICE_PROTOCOL_LAST, 0 }, |
1047 | }; |
1048 | |
1049 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4) = { |
1050 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1051 | 0x00, 0x00, 0x00, 0x00, |
1052 | 0x00, 0x00, 0x00, 0x00, |
1053 | 0x08, 0x00, |
1054 | |
1055 | 0x45, 0x00, 0x00, 0x44, /* ICE_IPV4_OFOS 14 */ |
1056 | 0x00, 0x00, 0x40, 0x00, |
1057 | 0x40, 0x11, 0x00, 0x00, |
1058 | 0x00, 0x00, 0x00, 0x00, |
1059 | 0x00, 0x00, 0x00, 0x00, |
1060 | |
1061 | 0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 34 */ |
1062 | 0x00, 0x00, 0x00, 0x00, |
1063 | |
1064 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP 42 */ |
1065 | 0x00, 0x00, 0x00, 0x00, |
1066 | 0x00, 0x00, 0x00, 0x85, |
1067 | |
1068 | 0x02, 0x00, 0x00, 0x00, /* PDU Session extension header */ |
1069 | 0x00, 0x00, 0x00, 0x00, |
1070 | |
1071 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 62 */ |
1072 | 0x00, 0x00, 0x40, 0x00, |
1073 | 0x40, 0x00, 0x00, 0x00, |
1074 | 0x00, 0x00, 0x00, 0x00, |
1075 | 0x00, 0x00, 0x00, 0x00, |
1076 | 0x00, 0x00, |
1077 | }; |
1078 | |
1079 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtp) = { |
1080 | { ICE_MAC_OFOS, 0 }, |
1081 | { ICE_IPV6_OFOS, 14 }, |
1082 | { ICE_UDP_OF, 54 }, |
1083 | { ICE_GTP_NO_PAY, 62 }, |
1084 | { ICE_PROTOCOL_LAST, 0 }, |
1085 | }; |
1086 | |
1087 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtp) = { |
1088 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1089 | 0x00, 0x00, 0x00, 0x00, |
1090 | 0x00, 0x00, 0x00, 0x00, |
1091 | 0x86, 0xdd, |
1092 | |
1093 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */ |
1094 | 0x00, 0x6c, 0x11, 0x00, /* Next header UDP*/ |
1095 | 0x00, 0x00, 0x00, 0x00, |
1096 | 0x00, 0x00, 0x00, 0x00, |
1097 | 0x00, 0x00, 0x00, 0x00, |
1098 | 0x00, 0x00, 0x00, 0x00, |
1099 | 0x00, 0x00, 0x00, 0x00, |
1100 | 0x00, 0x00, 0x00, 0x00, |
1101 | 0x00, 0x00, 0x00, 0x00, |
1102 | 0x00, 0x00, 0x00, 0x00, |
1103 | |
1104 | 0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 54 */ |
1105 | 0x00, 0x00, 0x00, 0x00, |
1106 | |
1107 | 0x30, 0x00, 0x00, 0x28, /* ICE_GTP 62 */ |
1108 | 0x00, 0x00, 0x00, 0x00, |
1109 | |
1110 | 0x00, 0x00, |
1111 | }; |
1112 | |
1113 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = { |
1114 | { ICE_MAC_OFOS, 0 }, |
1115 | { ICE_ETYPE_OL, 12 }, |
1116 | { ICE_PPPOE, 14 }, |
1117 | { ICE_IPV4_OFOS, 22 }, |
1118 | { ICE_TCP_IL, 42 }, |
1119 | { ICE_PROTOCOL_LAST, 0 }, |
1120 | }; |
1121 | |
1122 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_tcp) = { |
1123 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1124 | 0x00, 0x00, 0x00, 0x00, |
1125 | 0x00, 0x00, 0x00, 0x00, |
1126 | |
1127 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ |
1128 | |
1129 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ |
1130 | 0x00, 0x16, |
1131 | |
1132 | 0x00, 0x21, /* PPP Link Layer 20 */ |
1133 | |
1134 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 22 */ |
1135 | 0x00, 0x01, 0x00, 0x00, |
1136 | 0x00, 0x06, 0x00, 0x00, |
1137 | 0x00, 0x00, 0x00, 0x00, |
1138 | 0x00, 0x00, 0x00, 0x00, |
1139 | |
1140 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 42 */ |
1141 | 0x00, 0x00, 0x00, 0x00, |
1142 | 0x00, 0x00, 0x00, 0x00, |
1143 | 0x50, 0x00, 0x00, 0x00, |
1144 | 0x00, 0x00, 0x00, 0x00, |
1145 | |
1146 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1147 | }; |
1148 | |
1149 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_udp) = { |
1150 | { ICE_MAC_OFOS, 0 }, |
1151 | { ICE_ETYPE_OL, 12 }, |
1152 | { ICE_PPPOE, 14 }, |
1153 | { ICE_IPV4_OFOS, 22 }, |
1154 | { ICE_UDP_ILOS, 42 }, |
1155 | { ICE_PROTOCOL_LAST, 0 }, |
1156 | }; |
1157 | |
1158 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_udp) = { |
1159 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1160 | 0x00, 0x00, 0x00, 0x00, |
1161 | 0x00, 0x00, 0x00, 0x00, |
1162 | |
1163 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ |
1164 | |
1165 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ |
1166 | 0x00, 0x16, |
1167 | |
1168 | 0x00, 0x21, /* PPP Link Layer 20 */ |
1169 | |
1170 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 22 */ |
1171 | 0x00, 0x01, 0x00, 0x00, |
1172 | 0x00, 0x11, 0x00, 0x00, |
1173 | 0x00, 0x00, 0x00, 0x00, |
1174 | 0x00, 0x00, 0x00, 0x00, |
1175 | |
1176 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 42 */ |
1177 | 0x00, 0x08, 0x00, 0x00, |
1178 | |
1179 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1180 | }; |
1181 | |
1182 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_tcp) = { |
1183 | { ICE_MAC_OFOS, 0 }, |
1184 | { ICE_ETYPE_OL, 12 }, |
1185 | { ICE_PPPOE, 14 }, |
1186 | { ICE_IPV6_OFOS, 22 }, |
1187 | { ICE_TCP_IL, 62 }, |
1188 | { ICE_PROTOCOL_LAST, 0 }, |
1189 | }; |
1190 | |
1191 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_tcp) = { |
1192 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1193 | 0x00, 0x00, 0x00, 0x00, |
1194 | 0x00, 0x00, 0x00, 0x00, |
1195 | |
1196 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ |
1197 | |
1198 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ |
1199 | 0x00, 0x2a, |
1200 | |
1201 | 0x00, 0x57, /* PPP Link Layer 20 */ |
1202 | |
1203 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */ |
1204 | 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ |
1205 | 0x00, 0x00, 0x00, 0x00, |
1206 | 0x00, 0x00, 0x00, 0x00, |
1207 | 0x00, 0x00, 0x00, 0x00, |
1208 | 0x00, 0x00, 0x00, 0x00, |
1209 | 0x00, 0x00, 0x00, 0x00, |
1210 | 0x00, 0x00, 0x00, 0x00, |
1211 | 0x00, 0x00, 0x00, 0x00, |
1212 | 0x00, 0x00, 0x00, 0x00, |
1213 | |
1214 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 62 */ |
1215 | 0x00, 0x00, 0x00, 0x00, |
1216 | 0x00, 0x00, 0x00, 0x00, |
1217 | 0x50, 0x00, 0x00, 0x00, |
1218 | 0x00, 0x00, 0x00, 0x00, |
1219 | |
1220 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1221 | }; |
1222 | |
1223 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_udp) = { |
1224 | { ICE_MAC_OFOS, 0 }, |
1225 | { ICE_ETYPE_OL, 12 }, |
1226 | { ICE_PPPOE, 14 }, |
1227 | { ICE_IPV6_OFOS, 22 }, |
1228 | { ICE_UDP_ILOS, 62 }, |
1229 | { ICE_PROTOCOL_LAST, 0 }, |
1230 | }; |
1231 | |
1232 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_udp) = { |
1233 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1234 | 0x00, 0x00, 0x00, 0x00, |
1235 | 0x00, 0x00, 0x00, 0x00, |
1236 | |
1237 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ |
1238 | |
1239 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ |
1240 | 0x00, 0x2a, |
1241 | |
1242 | 0x00, 0x57, /* PPP Link Layer 20 */ |
1243 | |
1244 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */ |
1245 | 0x00, 0x08, 0x11, 0x00, /* Next header UDP*/ |
1246 | 0x00, 0x00, 0x00, 0x00, |
1247 | 0x00, 0x00, 0x00, 0x00, |
1248 | 0x00, 0x00, 0x00, 0x00, |
1249 | 0x00, 0x00, 0x00, 0x00, |
1250 | 0x00, 0x00, 0x00, 0x00, |
1251 | 0x00, 0x00, 0x00, 0x00, |
1252 | 0x00, 0x00, 0x00, 0x00, |
1253 | 0x00, 0x00, 0x00, 0x00, |
1254 | |
1255 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 62 */ |
1256 | 0x00, 0x08, 0x00, 0x00, |
1257 | |
1258 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1259 | }; |
1260 | |
1261 | ICE_DECLARE_PKT_OFFSETS(ipv4_l2tpv3) = { |
1262 | { ICE_MAC_OFOS, 0 }, |
1263 | { ICE_ETYPE_OL, 12 }, |
1264 | { ICE_IPV4_OFOS, 14 }, |
1265 | { ICE_L2TPV3, 34 }, |
1266 | { ICE_PROTOCOL_LAST, 0 }, |
1267 | }; |
1268 | |
1269 | ICE_DECLARE_PKT_TEMPLATE(ipv4_l2tpv3) = { |
1270 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1271 | 0x00, 0x00, 0x00, 0x00, |
1272 | 0x00, 0x00, 0x00, 0x00, |
1273 | |
1274 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ |
1275 | |
1276 | 0x45, 0x00, 0x00, 0x20, /* ICE_IPV4_IL 14 */ |
1277 | 0x00, 0x00, 0x40, 0x00, |
1278 | 0x40, 0x73, 0x00, 0x00, |
1279 | 0x00, 0x00, 0x00, 0x00, |
1280 | 0x00, 0x00, 0x00, 0x00, |
1281 | |
1282 | 0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 34 */ |
1283 | 0x00, 0x00, 0x00, 0x00, |
1284 | 0x00, 0x00, 0x00, 0x00, |
1285 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1286 | }; |
1287 | |
1288 | ICE_DECLARE_PKT_OFFSETS(ipv6_l2tpv3) = { |
1289 | { ICE_MAC_OFOS, 0 }, |
1290 | { ICE_ETYPE_OL, 12 }, |
1291 | { ICE_IPV6_OFOS, 14 }, |
1292 | { ICE_L2TPV3, 54 }, |
1293 | { ICE_PROTOCOL_LAST, 0 }, |
1294 | }; |
1295 | |
1296 | ICE_DECLARE_PKT_TEMPLATE(ipv6_l2tpv3) = { |
1297 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1298 | 0x00, 0x00, 0x00, 0x00, |
1299 | 0x00, 0x00, 0x00, 0x00, |
1300 | |
1301 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ |
1302 | |
1303 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 14 */ |
1304 | 0x00, 0x0c, 0x73, 0x40, |
1305 | 0x00, 0x00, 0x00, 0x00, |
1306 | 0x00, 0x00, 0x00, 0x00, |
1307 | 0x00, 0x00, 0x00, 0x00, |
1308 | 0x00, 0x00, 0x00, 0x00, |
1309 | 0x00, 0x00, 0x00, 0x00, |
1310 | 0x00, 0x00, 0x00, 0x00, |
1311 | 0x00, 0x00, 0x00, 0x00, |
1312 | 0x00, 0x00, 0x00, 0x00, |
1313 | |
1314 | 0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 54 */ |
1315 | 0x00, 0x00, 0x00, 0x00, |
1316 | 0x00, 0x00, 0x00, 0x00, |
1317 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ |
1318 | }; |
1319 | |
1320 | static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = { |
1321 | ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPU | ICE_PKT_OUTER_IPV6 | |
1322 | ICE_PKT_GTP_NOPAY), |
1323 | ICE_PKT_PROFILE(ipv6_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU | |
1324 | ICE_PKT_OUTER_IPV6 | |
1325 | ICE_PKT_INNER_IPV6 | |
1326 | ICE_PKT_INNER_UDP), |
1327 | ICE_PKT_PROFILE(ipv6_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU | |
1328 | ICE_PKT_OUTER_IPV6 | |
1329 | ICE_PKT_INNER_IPV6), |
1330 | ICE_PKT_PROFILE(ipv6_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU | |
1331 | ICE_PKT_OUTER_IPV6 | |
1332 | ICE_PKT_INNER_UDP), |
1333 | ICE_PKT_PROFILE(ipv6_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU | |
1334 | ICE_PKT_OUTER_IPV6), |
1335 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPU | ICE_PKT_GTP_NOPAY), |
1336 | ICE_PKT_PROFILE(ipv4_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU | |
1337 | ICE_PKT_INNER_IPV6 | |
1338 | ICE_PKT_INNER_UDP), |
1339 | ICE_PKT_PROFILE(ipv4_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU | |
1340 | ICE_PKT_INNER_IPV6), |
1341 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU | |
1342 | ICE_PKT_INNER_UDP), |
1343 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU), |
1344 | ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6), |
1345 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC), |
1346 | ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 | |
1347 | ICE_PKT_INNER_UDP), |
1348 | ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6), |
1349 | ICE_PKT_PROFILE(pppoe_ipv4_udp, ICE_PKT_PPPOE | ICE_PKT_INNER_UDP), |
1350 | ICE_PKT_PROFILE(pppoe_ipv4_tcp, ICE_PKT_PPPOE), |
1351 | ICE_PKT_PROFILE(gre_ipv6_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6 | |
1352 | ICE_PKT_INNER_TCP), |
1353 | ICE_PKT_PROFILE(gre_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_TCP), |
1354 | ICE_PKT_PROFILE(gre_ipv6_udp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6), |
1355 | ICE_PKT_PROFILE(gre_udp, ICE_PKT_TUN_NVGRE), |
1356 | ICE_PKT_PROFILE(udp_tun_ipv6_tcp, ICE_PKT_TUN_UDP | |
1357 | ICE_PKT_INNER_IPV6 | |
1358 | ICE_PKT_INNER_TCP), |
1359 | ICE_PKT_PROFILE(ipv6_l2tpv3, ICE_PKT_L2TPV3 | ICE_PKT_OUTER_IPV6), |
1360 | ICE_PKT_PROFILE(ipv4_l2tpv3, ICE_PKT_L2TPV3), |
1361 | ICE_PKT_PROFILE(udp_tun_tcp, ICE_PKT_TUN_UDP | ICE_PKT_INNER_TCP), |
1362 | ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP | |
1363 | ICE_PKT_INNER_IPV6), |
1364 | ICE_PKT_PROFILE(udp_tun_udp, ICE_PKT_TUN_UDP), |
1365 | ICE_PKT_PROFILE(udp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_INNER_UDP), |
1366 | ICE_PKT_PROFILE(udp, ICE_PKT_INNER_UDP), |
1367 | ICE_PKT_PROFILE(tcp_ipv6, ICE_PKT_OUTER_IPV6), |
1368 | ICE_PKT_PROFILE(tcp, 0), |
1369 | }; |
1370 | |
1371 | /* this is a recipe to profile association bitmap */ |
1372 | static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES], |
1373 | ICE_MAX_NUM_PROFILES); |
1374 | |
1375 | /* this is a profile to recipe association bitmap */ |
1376 | static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES], |
1377 | ICE_MAX_NUM_RECIPES); |
1378 | |
1379 | /** |
1380 | * ice_init_def_sw_recp - initialize the recipe book keeping tables |
1381 | * @hw: pointer to the HW struct |
1382 | * |
1383 | * Allocate memory for the entire recipe table and initialize the structures/ |
1384 | * entries corresponding to basic recipes. |
1385 | */ |
1386 | int ice_init_def_sw_recp(struct ice_hw *hw) |
1387 | { |
1388 | struct ice_sw_recipe *recps; |
1389 | u8 i; |
1390 | |
1391 | recps = devm_kcalloc(dev: ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES, |
1392 | size: sizeof(*recps), GFP_KERNEL); |
1393 | if (!recps) |
1394 | return -ENOMEM; |
1395 | |
1396 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
1397 | recps[i].root_rid = i; |
1398 | INIT_LIST_HEAD(list: &recps[i].filt_rules); |
1399 | INIT_LIST_HEAD(list: &recps[i].filt_replay_rules); |
1400 | INIT_LIST_HEAD(list: &recps[i].rg_list); |
1401 | mutex_init(&recps[i].filt_rule_lock); |
1402 | } |
1403 | |
1404 | hw->switch_info->recp_list = recps; |
1405 | |
1406 | return 0; |
1407 | } |
1408 | |
1409 | /** |
1410 | * ice_aq_get_sw_cfg - get switch configuration |
1411 | * @hw: pointer to the hardware structure |
1412 | * @buf: pointer to the result buffer |
1413 | * @buf_size: length of the buffer available for response |
1414 | * @req_desc: pointer to requested descriptor |
1415 | * @num_elems: pointer to number of elements |
1416 | * @cd: pointer to command details structure or NULL |
1417 | * |
1418 | * Get switch configuration (0x0200) to be placed in buf. |
1419 | * This admin command returns information such as initial VSI/port number |
1420 | * and switch ID it belongs to. |
1421 | * |
1422 | * NOTE: *req_desc is both an input/output parameter. |
1423 | * The caller of this function first calls this function with *request_desc set |
1424 | * to 0. If the response from f/w has *req_desc set to 0, all the switch |
1425 | * configuration information has been returned; if non-zero (meaning not all |
1426 | * the information was returned), the caller should call this function again |
1427 | * with *req_desc set to the previous value returned by f/w to get the |
1428 | * next block of switch configuration information. |
1429 | * |
1430 | * *num_elems is output only parameter. This reflects the number of elements |
1431 | * in response buffer. The caller of this function to use *num_elems while |
1432 | * parsing the response buffer. |
1433 | */ |
1434 | static int |
1435 | ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf, |
1436 | u16 buf_size, u16 *req_desc, u16 *num_elems, |
1437 | struct ice_sq_cd *cd) |
1438 | { |
1439 | struct ice_aqc_get_sw_cfg *cmd; |
1440 | struct ice_aq_desc desc; |
1441 | int status; |
1442 | |
1443 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_get_sw_cfg); |
1444 | cmd = &desc.params.get_sw_conf; |
1445 | cmd->element = cpu_to_le16(*req_desc); |
1446 | |
1447 | status = ice_aq_send_cmd(hw, desc: &desc, buf, buf_size, cd); |
1448 | if (!status) { |
1449 | *req_desc = le16_to_cpu(cmd->element); |
1450 | *num_elems = le16_to_cpu(cmd->num_elems); |
1451 | } |
1452 | |
1453 | return status; |
1454 | } |
1455 | |
1456 | /** |
1457 | * ice_aq_add_vsi |
1458 | * @hw: pointer to the HW struct |
1459 | * @vsi_ctx: pointer to a VSI context struct |
1460 | * @cd: pointer to command details structure or NULL |
1461 | * |
1462 | * Add a VSI context to the hardware (0x0210) |
1463 | */ |
1464 | static int |
1465 | ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1466 | struct ice_sq_cd *cd) |
1467 | { |
1468 | struct ice_aqc_add_update_free_vsi_resp *res; |
1469 | struct ice_aqc_add_get_update_free_vsi *cmd; |
1470 | struct ice_aq_desc desc; |
1471 | int status; |
1472 | |
1473 | cmd = &desc.params.vsi_cmd; |
1474 | res = &desc.params.add_update_free_vsi_res; |
1475 | |
1476 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_add_vsi); |
1477 | |
1478 | if (!vsi_ctx->alloc_from_pool) |
1479 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | |
1480 | ICE_AQ_VSI_IS_VALID); |
1481 | cmd->vf_id = vsi_ctx->vf_num; |
1482 | |
1483 | cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags); |
1484 | |
1485 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1486 | |
1487 | status = ice_aq_send_cmd(hw, desc: &desc, buf: &vsi_ctx->info, |
1488 | buf_size: sizeof(vsi_ctx->info), cd); |
1489 | |
1490 | if (!status) { |
1491 | vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M; |
1492 | vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used); |
1493 | vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free); |
1494 | } |
1495 | |
1496 | return status; |
1497 | } |
1498 | |
1499 | /** |
1500 | * ice_aq_free_vsi |
1501 | * @hw: pointer to the HW struct |
1502 | * @vsi_ctx: pointer to a VSI context struct |
1503 | * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources |
1504 | * @cd: pointer to command details structure or NULL |
1505 | * |
1506 | * Free VSI context info from hardware (0x0213) |
1507 | */ |
1508 | static int |
1509 | ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1510 | bool keep_vsi_alloc, struct ice_sq_cd *cd) |
1511 | { |
1512 | struct ice_aqc_add_update_free_vsi_resp *resp; |
1513 | struct ice_aqc_add_get_update_free_vsi *cmd; |
1514 | struct ice_aq_desc desc; |
1515 | int status; |
1516 | |
1517 | cmd = &desc.params.vsi_cmd; |
1518 | resp = &desc.params.add_update_free_vsi_res; |
1519 | |
1520 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_free_vsi); |
1521 | |
1522 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); |
1523 | if (keep_vsi_alloc) |
1524 | cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC); |
1525 | |
1526 | status = ice_aq_send_cmd(hw, desc: &desc, NULL, buf_size: 0, cd); |
1527 | if (!status) { |
1528 | vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); |
1529 | vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); |
1530 | } |
1531 | |
1532 | return status; |
1533 | } |
1534 | |
1535 | /** |
1536 | * ice_aq_update_vsi |
1537 | * @hw: pointer to the HW struct |
1538 | * @vsi_ctx: pointer to a VSI context struct |
1539 | * @cd: pointer to command details structure or NULL |
1540 | * |
1541 | * Update VSI context in the hardware (0x0211) |
1542 | */ |
1543 | static int |
1544 | ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1545 | struct ice_sq_cd *cd) |
1546 | { |
1547 | struct ice_aqc_add_update_free_vsi_resp *resp; |
1548 | struct ice_aqc_add_get_update_free_vsi *cmd; |
1549 | struct ice_aq_desc desc; |
1550 | int status; |
1551 | |
1552 | cmd = &desc.params.vsi_cmd; |
1553 | resp = &desc.params.add_update_free_vsi_res; |
1554 | |
1555 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_update_vsi); |
1556 | |
1557 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); |
1558 | |
1559 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1560 | |
1561 | status = ice_aq_send_cmd(hw, desc: &desc, buf: &vsi_ctx->info, |
1562 | buf_size: sizeof(vsi_ctx->info), cd); |
1563 | |
1564 | if (!status) { |
1565 | vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); |
1566 | vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); |
1567 | } |
1568 | |
1569 | return status; |
1570 | } |
1571 | |
1572 | /** |
1573 | * ice_is_vsi_valid - check whether the VSI is valid or not |
1574 | * @hw: pointer to the HW struct |
1575 | * @vsi_handle: VSI handle |
1576 | * |
1577 | * check whether the VSI is valid or not |
1578 | */ |
1579 | bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) |
1580 | { |
1581 | return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; |
1582 | } |
1583 | |
1584 | /** |
1585 | * ice_get_hw_vsi_num - return the HW VSI number |
1586 | * @hw: pointer to the HW struct |
1587 | * @vsi_handle: VSI handle |
1588 | * |
1589 | * return the HW VSI number |
1590 | * Caution: call this function only if VSI is valid (ice_is_vsi_valid) |
1591 | */ |
1592 | u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) |
1593 | { |
1594 | return hw->vsi_ctx[vsi_handle]->vsi_num; |
1595 | } |
1596 | |
1597 | /** |
1598 | * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle |
1599 | * @hw: pointer to the HW struct |
1600 | * @vsi_handle: VSI handle |
1601 | * |
1602 | * return the VSI context entry for a given VSI handle |
1603 | */ |
1604 | struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) |
1605 | { |
1606 | return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; |
1607 | } |
1608 | |
1609 | /** |
1610 | * ice_save_vsi_ctx - save the VSI context for a given VSI handle |
1611 | * @hw: pointer to the HW struct |
1612 | * @vsi_handle: VSI handle |
1613 | * @vsi: VSI context pointer |
1614 | * |
1615 | * save the VSI context entry for a given VSI handle |
1616 | */ |
1617 | static void |
1618 | ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi) |
1619 | { |
1620 | hw->vsi_ctx[vsi_handle] = vsi; |
1621 | } |
1622 | |
1623 | /** |
1624 | * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs |
1625 | * @hw: pointer to the HW struct |
1626 | * @vsi_handle: VSI handle |
1627 | */ |
1628 | static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle) |
1629 | { |
1630 | struct ice_vsi_ctx *vsi = ice_get_vsi_ctx(hw, vsi_handle); |
1631 | u8 i; |
1632 | |
1633 | if (!vsi) |
1634 | return; |
1635 | ice_for_each_traffic_class(i) { |
1636 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi->lan_q_ctx[i]); |
1637 | vsi->lan_q_ctx[i] = NULL; |
1638 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi->rdma_q_ctx[i]); |
1639 | vsi->rdma_q_ctx[i] = NULL; |
1640 | } |
1641 | } |
1642 | |
1643 | /** |
1644 | * ice_clear_vsi_ctx - clear the VSI context entry |
1645 | * @hw: pointer to the HW struct |
1646 | * @vsi_handle: VSI handle |
1647 | * |
1648 | * clear the VSI context entry |
1649 | */ |
1650 | static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) |
1651 | { |
1652 | struct ice_vsi_ctx *vsi; |
1653 | |
1654 | vsi = ice_get_vsi_ctx(hw, vsi_handle); |
1655 | if (vsi) { |
1656 | ice_clear_vsi_q_ctx(hw, vsi_handle); |
1657 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi); |
1658 | hw->vsi_ctx[vsi_handle] = NULL; |
1659 | } |
1660 | } |
1661 | |
1662 | /** |
1663 | * ice_clear_all_vsi_ctx - clear all the VSI context entries |
1664 | * @hw: pointer to the HW struct |
1665 | */ |
1666 | void ice_clear_all_vsi_ctx(struct ice_hw *hw) |
1667 | { |
1668 | u16 i; |
1669 | |
1670 | for (i = 0; i < ICE_MAX_VSI; i++) |
1671 | ice_clear_vsi_ctx(hw, vsi_handle: i); |
1672 | } |
1673 | |
1674 | /** |
1675 | * ice_add_vsi - add VSI context to the hardware and VSI handle list |
1676 | * @hw: pointer to the HW struct |
1677 | * @vsi_handle: unique VSI handle provided by drivers |
1678 | * @vsi_ctx: pointer to a VSI context struct |
1679 | * @cd: pointer to command details structure or NULL |
1680 | * |
1681 | * Add a VSI context to the hardware also add it into the VSI handle list. |
1682 | * If this function gets called after reset for existing VSIs then update |
1683 | * with the new HW VSI number in the corresponding VSI handle list entry. |
1684 | */ |
1685 | int |
1686 | ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1687 | struct ice_sq_cd *cd) |
1688 | { |
1689 | struct ice_vsi_ctx *tmp_vsi_ctx; |
1690 | int status; |
1691 | |
1692 | if (vsi_handle >= ICE_MAX_VSI) |
1693 | return -EINVAL; |
1694 | status = ice_aq_add_vsi(hw, vsi_ctx, cd); |
1695 | if (status) |
1696 | return status; |
1697 | tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); |
1698 | if (!tmp_vsi_ctx) { |
1699 | /* Create a new VSI context */ |
1700 | tmp_vsi_ctx = devm_kzalloc(dev: ice_hw_to_dev(hw), |
1701 | size: sizeof(*tmp_vsi_ctx), GFP_KERNEL); |
1702 | if (!tmp_vsi_ctx) { |
1703 | ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc: false, cd); |
1704 | return -ENOMEM; |
1705 | } |
1706 | *tmp_vsi_ctx = *vsi_ctx; |
1707 | ice_save_vsi_ctx(hw, vsi_handle, vsi: tmp_vsi_ctx); |
1708 | } else { |
1709 | /* update with new HW VSI num */ |
1710 | tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; |
1711 | } |
1712 | |
1713 | return 0; |
1714 | } |
1715 | |
1716 | /** |
1717 | * ice_free_vsi- free VSI context from hardware and VSI handle list |
1718 | * @hw: pointer to the HW struct |
1719 | * @vsi_handle: unique VSI handle |
1720 | * @vsi_ctx: pointer to a VSI context struct |
1721 | * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources |
1722 | * @cd: pointer to command details structure or NULL |
1723 | * |
1724 | * Free VSI context info from hardware as well as from VSI handle list |
1725 | */ |
1726 | int |
1727 | ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1728 | bool keep_vsi_alloc, struct ice_sq_cd *cd) |
1729 | { |
1730 | int status; |
1731 | |
1732 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
1733 | return -EINVAL; |
1734 | vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); |
1735 | status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd); |
1736 | if (!status) |
1737 | ice_clear_vsi_ctx(hw, vsi_handle); |
1738 | return status; |
1739 | } |
1740 | |
1741 | /** |
1742 | * ice_update_vsi |
1743 | * @hw: pointer to the HW struct |
1744 | * @vsi_handle: unique VSI handle |
1745 | * @vsi_ctx: pointer to a VSI context struct |
1746 | * @cd: pointer to command details structure or NULL |
1747 | * |
1748 | * Update VSI context in the hardware |
1749 | */ |
1750 | int |
1751 | ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1752 | struct ice_sq_cd *cd) |
1753 | { |
1754 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
1755 | return -EINVAL; |
1756 | vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); |
1757 | return ice_aq_update_vsi(hw, vsi_ctx, cd); |
1758 | } |
1759 | |
1760 | /** |
1761 | * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI |
1762 | * @hw: pointer to HW struct |
1763 | * @vsi_handle: VSI SW index |
1764 | * @enable: boolean for enable/disable |
1765 | */ |
1766 | int |
1767 | ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable) |
1768 | { |
1769 | struct ice_vsi_ctx *ctx, *cached_ctx; |
1770 | int status; |
1771 | |
1772 | cached_ctx = ice_get_vsi_ctx(hw, vsi_handle); |
1773 | if (!cached_ctx) |
1774 | return -ENOENT; |
1775 | |
1776 | ctx = kzalloc(size: sizeof(*ctx), GFP_KERNEL); |
1777 | if (!ctx) |
1778 | return -ENOMEM; |
1779 | |
1780 | ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss; |
1781 | ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc; |
1782 | ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags; |
1783 | |
1784 | ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); |
1785 | |
1786 | if (enable) |
1787 | ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; |
1788 | else |
1789 | ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; |
1790 | |
1791 | status = ice_update_vsi(hw, vsi_handle, vsi_ctx: ctx, NULL); |
1792 | if (!status) { |
1793 | cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags; |
1794 | cached_ctx->info.valid_sections |= ctx->info.valid_sections; |
1795 | } |
1796 | |
1797 | kfree(objp: ctx); |
1798 | return status; |
1799 | } |
1800 | |
1801 | /** |
1802 | * ice_aq_alloc_free_vsi_list |
1803 | * @hw: pointer to the HW struct |
1804 | * @vsi_list_id: VSI list ID returned or used for lookup |
1805 | * @lkup_type: switch rule filter lookup type |
1806 | * @opc: switch rules population command type - pass in the command opcode |
1807 | * |
1808 | * allocates or free a VSI list resource |
1809 | */ |
1810 | static int |
1811 | ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id, |
1812 | enum ice_sw_lkup_type lkup_type, |
1813 | enum ice_adminq_opc opc) |
1814 | { |
1815 | DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); |
1816 | u16 buf_len = __struct_size(sw_buf); |
1817 | struct ice_aqc_res_elem *vsi_ele; |
1818 | int status; |
1819 | |
1820 | sw_buf->num_elems = cpu_to_le16(1); |
1821 | |
1822 | if (lkup_type == ICE_SW_LKUP_MAC || |
1823 | lkup_type == ICE_SW_LKUP_MAC_VLAN || |
1824 | lkup_type == ICE_SW_LKUP_ETHERTYPE || |
1825 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || |
1826 | lkup_type == ICE_SW_LKUP_PROMISC || |
1827 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
1828 | lkup_type == ICE_SW_LKUP_DFLT) { |
1829 | sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP); |
1830 | } else if (lkup_type == ICE_SW_LKUP_VLAN) { |
1831 | if (opc == ice_aqc_opc_alloc_res) |
1832 | sw_buf->res_type = |
1833 | cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE | |
1834 | ICE_AQC_RES_TYPE_FLAG_SHARED); |
1835 | else |
1836 | sw_buf->res_type = |
1837 | cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE); |
1838 | } else { |
1839 | return -EINVAL; |
1840 | } |
1841 | |
1842 | if (opc == ice_aqc_opc_free_res) |
1843 | sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id); |
1844 | |
1845 | status = ice_aq_alloc_free_res(hw, buf: sw_buf, buf_size: buf_len, opc); |
1846 | if (status) |
1847 | return status; |
1848 | |
1849 | if (opc == ice_aqc_opc_alloc_res) { |
1850 | vsi_ele = &sw_buf->elem[0]; |
1851 | *vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp); |
1852 | } |
1853 | |
1854 | return 0; |
1855 | } |
1856 | |
1857 | /** |
1858 | * ice_aq_sw_rules - add/update/remove switch rules |
1859 | * @hw: pointer to the HW struct |
1860 | * @rule_list: pointer to switch rule population list |
1861 | * @rule_list_sz: total size of the rule list in bytes |
1862 | * @num_rules: number of switch rules in the rule_list |
1863 | * @opc: switch rules population command type - pass in the command opcode |
1864 | * @cd: pointer to command details structure or NULL |
1865 | * |
1866 | * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware |
1867 | */ |
1868 | int |
1869 | ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, |
1870 | u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd) |
1871 | { |
1872 | struct ice_aq_desc desc; |
1873 | int status; |
1874 | |
1875 | if (opc != ice_aqc_opc_add_sw_rules && |
1876 | opc != ice_aqc_opc_update_sw_rules && |
1877 | opc != ice_aqc_opc_remove_sw_rules) |
1878 | return -EINVAL; |
1879 | |
1880 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: opc); |
1881 | |
1882 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1883 | desc.params.sw_rules.num_rules_fltr_entry_index = |
1884 | cpu_to_le16(num_rules); |
1885 | status = ice_aq_send_cmd(hw, desc: &desc, buf: rule_list, buf_size: rule_list_sz, cd); |
1886 | if (opc != ice_aqc_opc_add_sw_rules && |
1887 | hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) |
1888 | status = -ENOENT; |
1889 | |
1890 | return status; |
1891 | } |
1892 | |
1893 | /** |
1894 | * ice_aq_add_recipe - add switch recipe |
1895 | * @hw: pointer to the HW struct |
1896 | * @s_recipe_list: pointer to switch rule population list |
1897 | * @num_recipes: number of switch recipes in the list |
1898 | * @cd: pointer to command details structure or NULL |
1899 | * |
1900 | * Add(0x0290) |
1901 | */ |
1902 | int |
1903 | ice_aq_add_recipe(struct ice_hw *hw, |
1904 | struct ice_aqc_recipe_data_elem *s_recipe_list, |
1905 | u16 num_recipes, struct ice_sq_cd *cd) |
1906 | { |
1907 | struct ice_aqc_add_get_recipe *cmd; |
1908 | struct ice_aq_desc desc; |
1909 | u16 buf_size; |
1910 | |
1911 | cmd = &desc.params.add_get_recipe; |
1912 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_add_recipe); |
1913 | |
1914 | cmd->num_sub_recipes = cpu_to_le16(num_recipes); |
1915 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1916 | |
1917 | buf_size = num_recipes * sizeof(*s_recipe_list); |
1918 | |
1919 | return ice_aq_send_cmd(hw, desc: &desc, buf: s_recipe_list, buf_size, cd); |
1920 | } |
1921 | |
1922 | /** |
1923 | * ice_aq_get_recipe - get switch recipe |
1924 | * @hw: pointer to the HW struct |
1925 | * @s_recipe_list: pointer to switch rule population list |
1926 | * @num_recipes: pointer to the number of recipes (input and output) |
1927 | * @recipe_root: root recipe number of recipe(s) to retrieve |
1928 | * @cd: pointer to command details structure or NULL |
1929 | * |
1930 | * Get(0x0292) |
1931 | * |
1932 | * On input, *num_recipes should equal the number of entries in s_recipe_list. |
1933 | * On output, *num_recipes will equal the number of entries returned in |
1934 | * s_recipe_list. |
1935 | * |
1936 | * The caller must supply enough space in s_recipe_list to hold all possible |
1937 | * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES. |
1938 | */ |
1939 | int |
1940 | ice_aq_get_recipe(struct ice_hw *hw, |
1941 | struct ice_aqc_recipe_data_elem *s_recipe_list, |
1942 | u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd) |
1943 | { |
1944 | struct ice_aqc_add_get_recipe *cmd; |
1945 | struct ice_aq_desc desc; |
1946 | u16 buf_size; |
1947 | int status; |
1948 | |
1949 | if (*num_recipes != ICE_MAX_NUM_RECIPES) |
1950 | return -EINVAL; |
1951 | |
1952 | cmd = &desc.params.add_get_recipe; |
1953 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_get_recipe); |
1954 | |
1955 | cmd->return_index = cpu_to_le16(recipe_root); |
1956 | cmd->num_sub_recipes = 0; |
1957 | |
1958 | buf_size = *num_recipes * sizeof(*s_recipe_list); |
1959 | |
1960 | status = ice_aq_send_cmd(hw, desc: &desc, buf: s_recipe_list, buf_size, cd); |
1961 | *num_recipes = le16_to_cpu(cmd->num_sub_recipes); |
1962 | |
1963 | return status; |
1964 | } |
1965 | |
1966 | /** |
1967 | * ice_update_recipe_lkup_idx - update a default recipe based on the lkup_idx |
1968 | * @hw: pointer to the HW struct |
1969 | * @params: parameters used to update the default recipe |
1970 | * |
1971 | * This function only supports updating default recipes and it only supports |
1972 | * updating a single recipe based on the lkup_idx at a time. |
1973 | * |
1974 | * This is done as a read-modify-write operation. First, get the current recipe |
1975 | * contents based on the recipe's ID. Then modify the field vector index and |
1976 | * mask if it's valid at the lkup_idx. Finally, use the add recipe AQ to update |
1977 | * the pre-existing recipe with the modifications. |
1978 | */ |
1979 | int |
1980 | ice_update_recipe_lkup_idx(struct ice_hw *hw, |
1981 | struct ice_update_recipe_lkup_idx_params *params) |
1982 | { |
1983 | struct ice_aqc_recipe_data_elem *rcp_list; |
1984 | u16 num_recps = ICE_MAX_NUM_RECIPES; |
1985 | int status; |
1986 | |
1987 | rcp_list = kcalloc(n: num_recps, size: sizeof(*rcp_list), GFP_KERNEL); |
1988 | if (!rcp_list) |
1989 | return -ENOMEM; |
1990 | |
1991 | /* read current recipe list from firmware */ |
1992 | rcp_list->recipe_indx = params->rid; |
1993 | status = ice_aq_get_recipe(hw, s_recipe_list: rcp_list, num_recipes: &num_recps, recipe_root: params->rid, NULL); |
1994 | if (status) { |
1995 | ice_debug(hw, ICE_DBG_SW, "Failed to get recipe %d, status %d\n" , |
1996 | params->rid, status); |
1997 | goto error_out; |
1998 | } |
1999 | |
2000 | /* only modify existing recipe's lkup_idx and mask if valid, while |
2001 | * leaving all other fields the same, then update the recipe firmware |
2002 | */ |
2003 | rcp_list->content.lkup_indx[params->lkup_idx] = params->fv_idx; |
2004 | if (params->mask_valid) |
2005 | rcp_list->content.mask[params->lkup_idx] = |
2006 | cpu_to_le16(params->mask); |
2007 | |
2008 | if (params->ignore_valid) |
2009 | rcp_list->content.lkup_indx[params->lkup_idx] |= |
2010 | ICE_AQ_RECIPE_LKUP_IGNORE; |
2011 | |
2012 | status = ice_aq_add_recipe(hw, s_recipe_list: &rcp_list[0], num_recipes: 1, NULL); |
2013 | if (status) |
2014 | ice_debug(hw, ICE_DBG_SW, "Failed to update recipe %d lkup_idx %d fv_idx %d mask %d mask_valid %s, status %d\n" , |
2015 | params->rid, params->lkup_idx, params->fv_idx, |
2016 | params->mask, params->mask_valid ? "true" : "false" , |
2017 | status); |
2018 | |
2019 | error_out: |
2020 | kfree(objp: rcp_list); |
2021 | return status; |
2022 | } |
2023 | |
2024 | /** |
2025 | * ice_aq_map_recipe_to_profile - Map recipe to packet profile |
2026 | * @hw: pointer to the HW struct |
2027 | * @profile_id: package profile ID to associate the recipe with |
2028 | * @r_assoc: Recipe bitmap filled in and need to be returned as response |
2029 | * @cd: pointer to command details structure or NULL |
2030 | * Recipe to profile association (0x0291) |
2031 | */ |
2032 | int |
2033 | ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 r_assoc, |
2034 | struct ice_sq_cd *cd) |
2035 | { |
2036 | struct ice_aqc_recipe_to_profile *cmd; |
2037 | struct ice_aq_desc desc; |
2038 | |
2039 | cmd = &desc.params.recipe_to_profile; |
2040 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_recipe_to_profile); |
2041 | cmd->profile_id = cpu_to_le16(profile_id); |
2042 | /* Set the recipe ID bit in the bitmask to let the device know which |
2043 | * profile we are associating the recipe to |
2044 | */ |
2045 | cmd->recipe_assoc = cpu_to_le64(r_assoc); |
2046 | |
2047 | return ice_aq_send_cmd(hw, desc: &desc, NULL, buf_size: 0, cd); |
2048 | } |
2049 | |
2050 | /** |
2051 | * ice_aq_get_recipe_to_profile - Map recipe to packet profile |
2052 | * @hw: pointer to the HW struct |
2053 | * @profile_id: package profile ID to associate the recipe with |
2054 | * @r_assoc: Recipe bitmap filled in and need to be returned as response |
2055 | * @cd: pointer to command details structure or NULL |
2056 | * Associate profile ID with given recipe (0x0293) |
2057 | */ |
2058 | int |
2059 | ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc, |
2060 | struct ice_sq_cd *cd) |
2061 | { |
2062 | struct ice_aqc_recipe_to_profile *cmd; |
2063 | struct ice_aq_desc desc; |
2064 | int status; |
2065 | |
2066 | cmd = &desc.params.recipe_to_profile; |
2067 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_get_recipe_to_profile); |
2068 | cmd->profile_id = cpu_to_le16(profile_id); |
2069 | |
2070 | status = ice_aq_send_cmd(hw, desc: &desc, NULL, buf_size: 0, cd); |
2071 | if (!status) |
2072 | *r_assoc = le64_to_cpu(cmd->recipe_assoc); |
2073 | |
2074 | return status; |
2075 | } |
2076 | |
2077 | /** |
2078 | * ice_alloc_recipe - add recipe resource |
2079 | * @hw: pointer to the hardware structure |
2080 | * @rid: recipe ID returned as response to AQ call |
2081 | */ |
2082 | int ice_alloc_recipe(struct ice_hw *hw, u16 *rid) |
2083 | { |
2084 | DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1); |
2085 | u16 buf_len = __struct_size(sw_buf); |
2086 | int status; |
2087 | |
2088 | sw_buf->num_elems = cpu_to_le16(1); |
2089 | sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE << |
2090 | ICE_AQC_RES_TYPE_S) | |
2091 | ICE_AQC_RES_TYPE_FLAG_SHARED); |
2092 | status = ice_aq_alloc_free_res(hw, buf: sw_buf, buf_size: buf_len, |
2093 | opc: ice_aqc_opc_alloc_res); |
2094 | if (!status) |
2095 | *rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp); |
2096 | |
2097 | return status; |
2098 | } |
2099 | |
2100 | /** |
2101 | * ice_get_recp_to_prof_map - updates recipe to profile mapping |
2102 | * @hw: pointer to hardware structure |
2103 | * |
2104 | * This function is used to populate recipe_to_profile matrix where index to |
2105 | * this array is the recipe ID and the element is the mapping of which profiles |
2106 | * is this recipe mapped to. |
2107 | */ |
2108 | static void ice_get_recp_to_prof_map(struct ice_hw *hw) |
2109 | { |
2110 | DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); |
2111 | u64 recp_assoc; |
2112 | u16 i; |
2113 | |
2114 | for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) { |
2115 | u16 j; |
2116 | |
2117 | bitmap_zero(dst: profile_to_recipe[i], ICE_MAX_NUM_RECIPES); |
2118 | bitmap_zero(dst: r_bitmap, ICE_MAX_NUM_RECIPES); |
2119 | if (ice_aq_get_recipe_to_profile(hw, profile_id: i, r_assoc: &recp_assoc, NULL)) |
2120 | continue; |
2121 | bitmap_from_arr64(r_bitmap, &recp_assoc, ICE_MAX_NUM_RECIPES); |
2122 | bitmap_copy(dst: profile_to_recipe[i], src: r_bitmap, |
2123 | ICE_MAX_NUM_RECIPES); |
2124 | for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES) |
2125 | set_bit(nr: i, addr: recipe_to_profile[j]); |
2126 | } |
2127 | } |
2128 | |
2129 | /** |
2130 | * ice_collect_result_idx - copy result index values |
2131 | * @buf: buffer that contains the result index |
2132 | * @recp: the recipe struct to copy data into |
2133 | */ |
2134 | static void |
2135 | ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf, |
2136 | struct ice_sw_recipe *recp) |
2137 | { |
2138 | if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN) |
2139 | set_bit(nr: buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, |
2140 | addr: recp->res_idxs); |
2141 | } |
2142 | |
2143 | /** |
2144 | * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries |
2145 | * @hw: pointer to hardware structure |
2146 | * @recps: struct that we need to populate |
2147 | * @rid: recipe ID that we are populating |
2148 | * @refresh_required: true if we should get recipe to profile mapping from FW |
2149 | * |
2150 | * This function is used to populate all the necessary entries into our |
2151 | * bookkeeping so that we have a current list of all the recipes that are |
2152 | * programmed in the firmware. |
2153 | */ |
2154 | static int |
2155 | ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, |
2156 | bool *refresh_required) |
2157 | { |
2158 | DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS); |
2159 | struct ice_aqc_recipe_data_elem *tmp; |
2160 | u16 num_recps = ICE_MAX_NUM_RECIPES; |
2161 | struct ice_prot_lkup_ext *lkup_exts; |
2162 | u8 fv_word_idx = 0; |
2163 | u16 sub_recps; |
2164 | int status; |
2165 | |
2166 | bitmap_zero(dst: result_bm, ICE_MAX_FV_WORDS); |
2167 | |
2168 | /* we need a buffer big enough to accommodate all the recipes */ |
2169 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, size: sizeof(*tmp), GFP_KERNEL); |
2170 | if (!tmp) |
2171 | return -ENOMEM; |
2172 | |
2173 | tmp[0].recipe_indx = rid; |
2174 | status = ice_aq_get_recipe(hw, s_recipe_list: tmp, num_recipes: &num_recps, recipe_root: rid, NULL); |
2175 | /* non-zero status meaning recipe doesn't exist */ |
2176 | if (status) |
2177 | goto err_unroll; |
2178 | |
2179 | /* Get recipe to profile map so that we can get the fv from lkups that |
2180 | * we read for a recipe from FW. Since we want to minimize the number of |
2181 | * times we make this FW call, just make one call and cache the copy |
2182 | * until a new recipe is added. This operation is only required the |
2183 | * first time to get the changes from FW. Then to search existing |
2184 | * entries we don't need to update the cache again until another recipe |
2185 | * gets added. |
2186 | */ |
2187 | if (*refresh_required) { |
2188 | ice_get_recp_to_prof_map(hw); |
2189 | *refresh_required = false; |
2190 | } |
2191 | |
2192 | /* Start populating all the entries for recps[rid] based on lkups from |
2193 | * firmware. Note that we are only creating the root recipe in our |
2194 | * database. |
2195 | */ |
2196 | lkup_exts = &recps[rid].lkup_exts; |
2197 | |
2198 | for (sub_recps = 0; sub_recps < num_recps; sub_recps++) { |
2199 | struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps]; |
2200 | struct ice_recp_grp_entry *rg_entry; |
2201 | u8 i, prof, idx, prot = 0; |
2202 | bool is_root; |
2203 | u16 off = 0; |
2204 | |
2205 | rg_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*rg_entry), |
2206 | GFP_KERNEL); |
2207 | if (!rg_entry) { |
2208 | status = -ENOMEM; |
2209 | goto err_unroll; |
2210 | } |
2211 | |
2212 | idx = root_bufs.recipe_indx; |
2213 | is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT; |
2214 | |
2215 | /* Mark all result indices in this chain */ |
2216 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) |
2217 | set_bit(nr: root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, |
2218 | addr: result_bm); |
2219 | |
2220 | /* get the first profile that is associated with rid */ |
2221 | prof = find_first_bit(addr: recipe_to_profile[idx], |
2222 | ICE_MAX_NUM_PROFILES); |
2223 | for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) { |
2224 | u8 lkup_indx = root_bufs.content.lkup_indx[i + 1]; |
2225 | |
2226 | rg_entry->fv_idx[i] = lkup_indx; |
2227 | rg_entry->fv_mask[i] = |
2228 | le16_to_cpu(root_bufs.content.mask[i + 1]); |
2229 | |
2230 | /* If the recipe is a chained recipe then all its |
2231 | * child recipe's result will have a result index. |
2232 | * To fill fv_words we should not use those result |
2233 | * index, we only need the protocol ids and offsets. |
2234 | * We will skip all the fv_idx which stores result |
2235 | * index in them. We also need to skip any fv_idx which |
2236 | * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a |
2237 | * valid offset value. |
2238 | */ |
2239 | if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) || |
2240 | rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE || |
2241 | rg_entry->fv_idx[i] == 0) |
2242 | continue; |
2243 | |
2244 | ice_find_prot_off(hw, blk: ICE_BLK_SW, prof, |
2245 | fv_idx: rg_entry->fv_idx[i], prot: &prot, off: &off); |
2246 | lkup_exts->fv_words[fv_word_idx].prot_id = prot; |
2247 | lkup_exts->fv_words[fv_word_idx].off = off; |
2248 | lkup_exts->field_mask[fv_word_idx] = |
2249 | rg_entry->fv_mask[i]; |
2250 | fv_word_idx++; |
2251 | } |
2252 | /* populate rg_list with the data from the child entry of this |
2253 | * recipe |
2254 | */ |
2255 | list_add(new: &rg_entry->l_entry, head: &recps[rid].rg_list); |
2256 | |
2257 | /* Propagate some data to the recipe database */ |
2258 | recps[idx].is_root = !!is_root; |
2259 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; |
2260 | recps[idx].need_pass_l2 = root_bufs.content.act_ctrl & |
2261 | ICE_AQ_RECIPE_ACT_NEED_PASS_L2; |
2262 | recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl & |
2263 | ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2; |
2264 | bitmap_zero(dst: recps[idx].res_idxs, ICE_MAX_FV_WORDS); |
2265 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) { |
2266 | recps[idx].chain_idx = root_bufs.content.result_indx & |
2267 | ~ICE_AQ_RECIPE_RESULT_EN; |
2268 | set_bit(nr: recps[idx].chain_idx, addr: recps[idx].res_idxs); |
2269 | } else { |
2270 | recps[idx].chain_idx = ICE_INVAL_CHAIN_IND; |
2271 | } |
2272 | |
2273 | if (!is_root) |
2274 | continue; |
2275 | |
2276 | /* Only do the following for root recipes entries */ |
2277 | memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap, |
2278 | sizeof(recps[idx].r_bitmap)); |
2279 | recps[idx].root_rid = root_bufs.content.rid & |
2280 | ~ICE_AQ_RECIPE_ID_IS_ROOT; |
2281 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; |
2282 | } |
2283 | |
2284 | /* Complete initialization of the root recipe entry */ |
2285 | lkup_exts->n_val_words = fv_word_idx; |
2286 | recps[rid].big_recp = (num_recps > 1); |
2287 | recps[rid].n_grp_count = (u8)num_recps; |
2288 | recps[rid].root_buf = devm_kmemdup(dev: ice_hw_to_dev(hw), src: tmp, |
2289 | len: recps[rid].n_grp_count * sizeof(*recps[rid].root_buf), |
2290 | GFP_KERNEL); |
2291 | if (!recps[rid].root_buf) { |
2292 | status = -ENOMEM; |
2293 | goto err_unroll; |
2294 | } |
2295 | |
2296 | /* Copy result indexes */ |
2297 | bitmap_copy(dst: recps[rid].res_idxs, src: result_bm, ICE_MAX_FV_WORDS); |
2298 | recps[rid].recp_created = true; |
2299 | |
2300 | err_unroll: |
2301 | kfree(objp: tmp); |
2302 | return status; |
2303 | } |
2304 | |
2305 | /* ice_init_port_info - Initialize port_info with switch configuration data |
2306 | * @pi: pointer to port_info |
2307 | * @vsi_port_num: VSI number or port number |
2308 | * @type: Type of switch element (port or VSI) |
2309 | * @swid: switch ID of the switch the element is attached to |
2310 | * @pf_vf_num: PF or VF number |
2311 | * @is_vf: true if the element is a VF, false otherwise |
2312 | */ |
2313 | static void |
2314 | ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type, |
2315 | u16 swid, u16 pf_vf_num, bool is_vf) |
2316 | { |
2317 | switch (type) { |
2318 | case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT: |
2319 | pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK); |
2320 | pi->sw_id = swid; |
2321 | pi->pf_vf_num = pf_vf_num; |
2322 | pi->is_vf = is_vf; |
2323 | break; |
2324 | default: |
2325 | ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n" ); |
2326 | break; |
2327 | } |
2328 | } |
2329 | |
2330 | /* ice_get_initial_sw_cfg - Get initial port and default VSI data |
2331 | * @hw: pointer to the hardware structure |
2332 | */ |
2333 | int ice_get_initial_sw_cfg(struct ice_hw *hw) |
2334 | { |
2335 | struct ice_aqc_get_sw_cfg_resp_elem *rbuf; |
2336 | u16 req_desc = 0; |
2337 | u16 num_elems; |
2338 | int status; |
2339 | u16 i; |
2340 | |
2341 | rbuf = kzalloc(ICE_SW_CFG_MAX_BUF_LEN, GFP_KERNEL); |
2342 | if (!rbuf) |
2343 | return -ENOMEM; |
2344 | |
2345 | /* Multiple calls to ice_aq_get_sw_cfg may be required |
2346 | * to get all the switch configuration information. The need |
2347 | * for additional calls is indicated by ice_aq_get_sw_cfg |
2348 | * writing a non-zero value in req_desc |
2349 | */ |
2350 | do { |
2351 | struct ice_aqc_get_sw_cfg_resp_elem *ele; |
2352 | |
2353 | status = ice_aq_get_sw_cfg(hw, buf: rbuf, ICE_SW_CFG_MAX_BUF_LEN, |
2354 | req_desc: &req_desc, num_elems: &num_elems, NULL); |
2355 | |
2356 | if (status) |
2357 | break; |
2358 | |
2359 | for (i = 0, ele = rbuf; i < num_elems; i++, ele++) { |
2360 | u16 pf_vf_num, swid, vsi_port_num; |
2361 | bool is_vf = false; |
2362 | u8 res_type; |
2363 | |
2364 | vsi_port_num = le16_to_cpu(ele->vsi_port_num) & |
2365 | ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M; |
2366 | |
2367 | pf_vf_num = le16_to_cpu(ele->pf_vf_num) & |
2368 | ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M; |
2369 | |
2370 | swid = le16_to_cpu(ele->swid); |
2371 | |
2372 | if (le16_to_cpu(ele->pf_vf_num) & |
2373 | ICE_AQC_GET_SW_CONF_RESP_IS_VF) |
2374 | is_vf = true; |
2375 | |
2376 | res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >> |
2377 | ICE_AQC_GET_SW_CONF_RESP_TYPE_S); |
2378 | |
2379 | if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) { |
2380 | /* FW VSI is not needed. Just continue. */ |
2381 | continue; |
2382 | } |
2383 | |
2384 | ice_init_port_info(pi: hw->port_info, vsi_port_num, |
2385 | type: res_type, swid, pf_vf_num, is_vf); |
2386 | } |
2387 | } while (req_desc && !status); |
2388 | |
2389 | kfree(objp: rbuf); |
2390 | return status; |
2391 | } |
2392 | |
2393 | /** |
2394 | * ice_fill_sw_info - Helper function to populate lb_en and lan_en |
2395 | * @hw: pointer to the hardware structure |
2396 | * @fi: filter info structure to fill/update |
2397 | * |
2398 | * This helper function populates the lb_en and lan_en elements of the provided |
2399 | * ice_fltr_info struct using the switch's type and characteristics of the |
2400 | * switch rule being configured. |
2401 | */ |
2402 | static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi) |
2403 | { |
2404 | fi->lb_en = false; |
2405 | fi->lan_en = false; |
2406 | if ((fi->flag & ICE_FLTR_TX) && |
2407 | (fi->fltr_act == ICE_FWD_TO_VSI || |
2408 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || |
2409 | fi->fltr_act == ICE_FWD_TO_Q || |
2410 | fi->fltr_act == ICE_FWD_TO_QGRP)) { |
2411 | /* Setting LB for prune actions will result in replicated |
2412 | * packets to the internal switch that will be dropped. |
2413 | */ |
2414 | if (fi->lkup_type != ICE_SW_LKUP_VLAN) |
2415 | fi->lb_en = true; |
2416 | |
2417 | /* Set lan_en to TRUE if |
2418 | * 1. The switch is a VEB AND |
2419 | * 2 |
2420 | * 2.1 The lookup is a directional lookup like ethertype, |
2421 | * promiscuous, ethertype-MAC, promiscuous-VLAN |
2422 | * and default-port OR |
2423 | * 2.2 The lookup is VLAN, OR |
2424 | * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR |
2425 | * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC. |
2426 | * |
2427 | * OR |
2428 | * |
2429 | * The switch is a VEPA. |
2430 | * |
2431 | * In all other cases, the LAN enable has to be set to false. |
2432 | */ |
2433 | if (hw->evb_veb) { |
2434 | if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE || |
2435 | fi->lkup_type == ICE_SW_LKUP_PROMISC || |
2436 | fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || |
2437 | fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
2438 | fi->lkup_type == ICE_SW_LKUP_DFLT || |
2439 | fi->lkup_type == ICE_SW_LKUP_VLAN || |
2440 | (fi->lkup_type == ICE_SW_LKUP_MAC && |
2441 | !is_unicast_ether_addr(addr: fi->l_data.mac.mac_addr)) || |
2442 | (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN && |
2443 | !is_unicast_ether_addr(addr: fi->l_data.mac.mac_addr))) |
2444 | fi->lan_en = true; |
2445 | } else { |
2446 | fi->lan_en = true; |
2447 | } |
2448 | } |
2449 | } |
2450 | |
2451 | /** |
2452 | * ice_fill_eth_hdr - helper to copy dummy_eth_hdr into supplied buffer |
2453 | * @eth_hdr: pointer to buffer to populate |
2454 | */ |
2455 | void ice_fill_eth_hdr(u8 *eth_hdr) |
2456 | { |
2457 | memcpy(eth_hdr, dummy_eth_header, DUMMY_ETH_HDR_LEN); |
2458 | } |
2459 | |
2460 | /** |
2461 | * ice_fill_sw_rule - Helper function to fill switch rule structure |
2462 | * @hw: pointer to the hardware structure |
2463 | * @f_info: entry containing packet forwarding information |
2464 | * @s_rule: switch rule structure to be filled in based on mac_entry |
2465 | * @opc: switch rules population command type - pass in the command opcode |
2466 | */ |
2467 | static void |
2468 | ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, |
2469 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
2470 | enum ice_adminq_opc opc) |
2471 | { |
2472 | u16 vlan_id = ICE_MAX_VLAN_ID + 1; |
2473 | u16 vlan_tpid = ETH_P_8021Q; |
2474 | void *daddr = NULL; |
2475 | u16 eth_hdr_sz; |
2476 | u8 *eth_hdr; |
2477 | u32 act = 0; |
2478 | __be16 *off; |
2479 | u8 q_rgn; |
2480 | |
2481 | if (opc == ice_aqc_opc_remove_sw_rules) { |
2482 | s_rule->act = 0; |
2483 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); |
2484 | s_rule->hdr_len = 0; |
2485 | return; |
2486 | } |
2487 | |
2488 | eth_hdr_sz = sizeof(dummy_eth_header); |
2489 | eth_hdr = s_rule->hdr_data; |
2490 | |
2491 | /* initialize the ether header with a dummy header */ |
2492 | memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); |
2493 | ice_fill_sw_info(hw, fi: f_info); |
2494 | |
2495 | switch (f_info->fltr_act) { |
2496 | case ICE_FWD_TO_VSI: |
2497 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, |
2498 | f_info->fwd_id.hw_vsi_id); |
2499 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) |
2500 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | |
2501 | ICE_SINGLE_ACT_VALID_BIT; |
2502 | break; |
2503 | case ICE_FWD_TO_VSI_LIST: |
2504 | act |= ICE_SINGLE_ACT_VSI_LIST; |
2505 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_LIST_ID_M, |
2506 | f_info->fwd_id.vsi_list_id); |
2507 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) |
2508 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | |
2509 | ICE_SINGLE_ACT_VALID_BIT; |
2510 | break; |
2511 | case ICE_FWD_TO_Q: |
2512 | act |= ICE_SINGLE_ACT_TO_Q; |
2513 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M, |
2514 | f_info->fwd_id.q_id); |
2515 | break; |
2516 | case ICE_DROP_PACKET: |
2517 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | |
2518 | ICE_SINGLE_ACT_VALID_BIT; |
2519 | break; |
2520 | case ICE_FWD_TO_QGRP: |
2521 | q_rgn = f_info->qgrp_size > 0 ? |
2522 | (u8)ilog2(f_info->qgrp_size) : 0; |
2523 | act |= ICE_SINGLE_ACT_TO_Q; |
2524 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M, |
2525 | f_info->fwd_id.q_id); |
2526 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn); |
2527 | break; |
2528 | default: |
2529 | return; |
2530 | } |
2531 | |
2532 | if (f_info->lb_en) |
2533 | act |= ICE_SINGLE_ACT_LB_ENABLE; |
2534 | if (f_info->lan_en) |
2535 | act |= ICE_SINGLE_ACT_LAN_ENABLE; |
2536 | |
2537 | switch (f_info->lkup_type) { |
2538 | case ICE_SW_LKUP_MAC: |
2539 | daddr = f_info->l_data.mac.mac_addr; |
2540 | break; |
2541 | case ICE_SW_LKUP_VLAN: |
2542 | vlan_id = f_info->l_data.vlan.vlan_id; |
2543 | if (f_info->l_data.vlan.tpid_valid) |
2544 | vlan_tpid = f_info->l_data.vlan.tpid; |
2545 | if (f_info->fltr_act == ICE_FWD_TO_VSI || |
2546 | f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { |
2547 | act |= ICE_SINGLE_ACT_PRUNE; |
2548 | act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS; |
2549 | } |
2550 | break; |
2551 | case ICE_SW_LKUP_ETHERTYPE_MAC: |
2552 | daddr = f_info->l_data.ethertype_mac.mac_addr; |
2553 | fallthrough; |
2554 | case ICE_SW_LKUP_ETHERTYPE: |
2555 | off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); |
2556 | *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); |
2557 | break; |
2558 | case ICE_SW_LKUP_MAC_VLAN: |
2559 | daddr = f_info->l_data.mac_vlan.mac_addr; |
2560 | vlan_id = f_info->l_data.mac_vlan.vlan_id; |
2561 | break; |
2562 | case ICE_SW_LKUP_PROMISC_VLAN: |
2563 | vlan_id = f_info->l_data.mac_vlan.vlan_id; |
2564 | fallthrough; |
2565 | case ICE_SW_LKUP_PROMISC: |
2566 | daddr = f_info->l_data.mac_vlan.mac_addr; |
2567 | break; |
2568 | default: |
2569 | break; |
2570 | } |
2571 | |
2572 | s_rule->hdr.type = (f_info->flag & ICE_FLTR_RX) ? |
2573 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) : |
2574 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); |
2575 | |
2576 | /* Recipe set depending on lookup type */ |
2577 | s_rule->recipe_id = cpu_to_le16(f_info->lkup_type); |
2578 | s_rule->src = cpu_to_le16(f_info->src); |
2579 | s_rule->act = cpu_to_le32(act); |
2580 | |
2581 | if (daddr) |
2582 | ether_addr_copy(dst: eth_hdr + ICE_ETH_DA_OFFSET, src: daddr); |
2583 | |
2584 | if (!(vlan_id > ICE_MAX_VLAN_ID)) { |
2585 | off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET); |
2586 | *off = cpu_to_be16(vlan_id); |
2587 | off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); |
2588 | *off = cpu_to_be16(vlan_tpid); |
2589 | } |
2590 | |
2591 | /* Create the switch rule with the final dummy Ethernet header */ |
2592 | if (opc != ice_aqc_opc_update_sw_rules) |
2593 | s_rule->hdr_len = cpu_to_le16(eth_hdr_sz); |
2594 | } |
2595 | |
2596 | /** |
2597 | * ice_add_marker_act |
2598 | * @hw: pointer to the hardware structure |
2599 | * @m_ent: the management entry for which sw marker needs to be added |
2600 | * @sw_marker: sw marker to tag the Rx descriptor with |
2601 | * @l_id: large action resource ID |
2602 | * |
2603 | * Create a large action to hold software marker and update the switch rule |
2604 | * entry pointed by m_ent with newly created large action |
2605 | */ |
2606 | static int |
2607 | ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, |
2608 | u16 sw_marker, u16 l_id) |
2609 | { |
2610 | struct ice_sw_rule_lkup_rx_tx *rx_tx; |
2611 | struct ice_sw_rule_lg_act *lg_act; |
2612 | /* For software marker we need 3 large actions |
2613 | * 1. FWD action: FWD TO VSI or VSI LIST |
2614 | * 2. GENERIC VALUE action to hold the profile ID |
2615 | * 3. GENERIC VALUE action to hold the software marker ID |
2616 | */ |
2617 | const u16 num_lg_acts = 3; |
2618 | u16 lg_act_size; |
2619 | u16 rules_size; |
2620 | int status; |
2621 | u32 act; |
2622 | u16 id; |
2623 | |
2624 | if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) |
2625 | return -EINVAL; |
2626 | |
2627 | /* Create two back-to-back switch rules and submit them to the HW using |
2628 | * one memory buffer: |
2629 | * 1. Large Action |
2630 | * 2. Look up Tx Rx |
2631 | */ |
2632 | lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(lg_act, num_lg_acts); |
2633 | rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(rx_tx); |
2634 | lg_act = devm_kzalloc(dev: ice_hw_to_dev(hw), size: rules_size, GFP_KERNEL); |
2635 | if (!lg_act) |
2636 | return -ENOMEM; |
2637 | |
2638 | rx_tx = (typeof(rx_tx))((u8 *)lg_act + lg_act_size); |
2639 | |
2640 | /* Fill in the first switch rule i.e. large action */ |
2641 | lg_act->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT); |
2642 | lg_act->index = cpu_to_le16(l_id); |
2643 | lg_act->size = cpu_to_le16(num_lg_acts); |
2644 | |
2645 | /* First action VSI forwarding or VSI list forwarding depending on how |
2646 | * many VSIs |
2647 | */ |
2648 | id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id : |
2649 | m_ent->fltr_info.fwd_id.hw_vsi_id; |
2650 | |
2651 | act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; |
2652 | act |= FIELD_PREP(ICE_LG_ACT_VSI_LIST_ID_M, id); |
2653 | if (m_ent->vsi_count > 1) |
2654 | act |= ICE_LG_ACT_VSI_LIST; |
2655 | lg_act->act[0] = cpu_to_le32(act); |
2656 | |
2657 | /* Second action descriptor type */ |
2658 | act = ICE_LG_ACT_GENERIC; |
2659 | |
2660 | act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, 1); |
2661 | lg_act->act[1] = cpu_to_le32(act); |
2662 | |
2663 | act = FIELD_PREP(ICE_LG_ACT_GENERIC_OFFSET_M, |
2664 | ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX); |
2665 | |
2666 | /* Third action Marker value */ |
2667 | act |= ICE_LG_ACT_GENERIC; |
2668 | act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, sw_marker); |
2669 | |
2670 | lg_act->act[2] = cpu_to_le32(act); |
2671 | |
2672 | /* call the fill switch rule to fill the lookup Tx Rx structure */ |
2673 | ice_fill_sw_rule(hw, f_info: &m_ent->fltr_info, s_rule: rx_tx, |
2674 | opc: ice_aqc_opc_update_sw_rules); |
2675 | |
2676 | /* Update the action to point to the large action ID */ |
2677 | act = ICE_SINGLE_ACT_PTR; |
2678 | act |= FIELD_PREP(ICE_SINGLE_ACT_PTR_VAL_M, l_id); |
2679 | rx_tx->act = cpu_to_le32(act); |
2680 | |
2681 | /* Use the filter rule ID of the previously created rule with single |
2682 | * act. Once the update happens, hardware will treat this as large |
2683 | * action |
2684 | */ |
2685 | rx_tx->index = cpu_to_le16(m_ent->fltr_info.fltr_rule_id); |
2686 | |
2687 | status = ice_aq_sw_rules(hw, rule_list: lg_act, rule_list_sz: rules_size, num_rules: 2, |
2688 | opc: ice_aqc_opc_update_sw_rules, NULL); |
2689 | if (!status) { |
2690 | m_ent->lg_act_idx = l_id; |
2691 | m_ent->sw_marker_id = sw_marker; |
2692 | } |
2693 | |
2694 | devm_kfree(dev: ice_hw_to_dev(hw), p: lg_act); |
2695 | return status; |
2696 | } |
2697 | |
2698 | /** |
2699 | * ice_create_vsi_list_map |
2700 | * @hw: pointer to the hardware structure |
2701 | * @vsi_handle_arr: array of VSI handles to set in the VSI mapping |
2702 | * @num_vsi: number of VSI handles in the array |
2703 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
2704 | * |
2705 | * Helper function to create a new entry of VSI list ID to VSI mapping |
2706 | * using the given VSI list ID |
2707 | */ |
2708 | static struct ice_vsi_list_map_info * |
2709 | ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2710 | u16 vsi_list_id) |
2711 | { |
2712 | struct ice_switch_info *sw = hw->switch_info; |
2713 | struct ice_vsi_list_map_info *v_map; |
2714 | int i; |
2715 | |
2716 | v_map = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*v_map), GFP_KERNEL); |
2717 | if (!v_map) |
2718 | return NULL; |
2719 | |
2720 | v_map->vsi_list_id = vsi_list_id; |
2721 | v_map->ref_cnt = 1; |
2722 | for (i = 0; i < num_vsi; i++) |
2723 | set_bit(nr: vsi_handle_arr[i], addr: v_map->vsi_map); |
2724 | |
2725 | list_add(new: &v_map->list_entry, head: &sw->vsi_list_map_head); |
2726 | return v_map; |
2727 | } |
2728 | |
2729 | /** |
2730 | * ice_update_vsi_list_rule |
2731 | * @hw: pointer to the hardware structure |
2732 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2733 | * @num_vsi: number of VSI handles in the array |
2734 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
2735 | * @remove: Boolean value to indicate if this is a remove action |
2736 | * @opc: switch rules population command type - pass in the command opcode |
2737 | * @lkup_type: lookup type of the filter |
2738 | * |
2739 | * Call AQ command to add a new switch rule or update existing switch rule |
2740 | * using the given VSI list ID |
2741 | */ |
2742 | static int |
2743 | ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2744 | u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, |
2745 | enum ice_sw_lkup_type lkup_type) |
2746 | { |
2747 | struct ice_sw_rule_vsi_list *s_rule; |
2748 | u16 s_rule_size; |
2749 | u16 rule_type; |
2750 | int status; |
2751 | int i; |
2752 | |
2753 | if (!num_vsi) |
2754 | return -EINVAL; |
2755 | |
2756 | if (lkup_type == ICE_SW_LKUP_MAC || |
2757 | lkup_type == ICE_SW_LKUP_MAC_VLAN || |
2758 | lkup_type == ICE_SW_LKUP_ETHERTYPE || |
2759 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || |
2760 | lkup_type == ICE_SW_LKUP_PROMISC || |
2761 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
2762 | lkup_type == ICE_SW_LKUP_DFLT) |
2763 | rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR : |
2764 | ICE_AQC_SW_RULES_T_VSI_LIST_SET; |
2765 | else if (lkup_type == ICE_SW_LKUP_VLAN) |
2766 | rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR : |
2767 | ICE_AQC_SW_RULES_T_PRUNE_LIST_SET; |
2768 | else |
2769 | return -EINVAL; |
2770 | |
2771 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi); |
2772 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), size: s_rule_size, GFP_KERNEL); |
2773 | if (!s_rule) |
2774 | return -ENOMEM; |
2775 | for (i = 0; i < num_vsi; i++) { |
2776 | if (!ice_is_vsi_valid(hw, vsi_handle: vsi_handle_arr[i])) { |
2777 | status = -EINVAL; |
2778 | goto exit; |
2779 | } |
2780 | /* AQ call requires hw_vsi_id(s) */ |
2781 | s_rule->vsi[i] = |
2782 | cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); |
2783 | } |
2784 | |
2785 | s_rule->hdr.type = cpu_to_le16(rule_type); |
2786 | s_rule->number_vsi = cpu_to_le16(num_vsi); |
2787 | s_rule->index = cpu_to_le16(vsi_list_id); |
2788 | |
2789 | status = ice_aq_sw_rules(hw, rule_list: s_rule, rule_list_sz: s_rule_size, num_rules: 1, opc, NULL); |
2790 | |
2791 | exit: |
2792 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2793 | return status; |
2794 | } |
2795 | |
2796 | /** |
2797 | * ice_create_vsi_list_rule - Creates and populates a VSI list rule |
2798 | * @hw: pointer to the HW struct |
2799 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2800 | * @num_vsi: number of VSI handles in the array |
2801 | * @vsi_list_id: stores the ID of the VSI list to be created |
2802 | * @lkup_type: switch rule filter's lookup type |
2803 | */ |
2804 | static int |
2805 | ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2806 | u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) |
2807 | { |
2808 | int status; |
2809 | |
2810 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, |
2811 | opc: ice_aqc_opc_alloc_res); |
2812 | if (status) |
2813 | return status; |
2814 | |
2815 | /* Update the newly created VSI list to include the specified VSIs */ |
2816 | return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, |
2817 | vsi_list_id: *vsi_list_id, remove: false, |
2818 | opc: ice_aqc_opc_add_sw_rules, lkup_type); |
2819 | } |
2820 | |
2821 | /** |
2822 | * ice_create_pkt_fwd_rule |
2823 | * @hw: pointer to the hardware structure |
2824 | * @f_entry: entry containing packet forwarding information |
2825 | * |
2826 | * Create switch rule with given filter information and add an entry |
2827 | * to the corresponding filter management list to track this switch rule |
2828 | * and VSI mapping |
2829 | */ |
2830 | static int |
2831 | ice_create_pkt_fwd_rule(struct ice_hw *hw, |
2832 | struct ice_fltr_list_entry *f_entry) |
2833 | { |
2834 | struct ice_fltr_mgmt_list_entry *fm_entry; |
2835 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
2836 | enum ice_sw_lkup_type l_type; |
2837 | struct ice_sw_recipe *recp; |
2838 | int status; |
2839 | |
2840 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
2841 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2842 | GFP_KERNEL); |
2843 | if (!s_rule) |
2844 | return -ENOMEM; |
2845 | fm_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*fm_entry), |
2846 | GFP_KERNEL); |
2847 | if (!fm_entry) { |
2848 | status = -ENOMEM; |
2849 | goto ice_create_pkt_fwd_rule_exit; |
2850 | } |
2851 | |
2852 | fm_entry->fltr_info = f_entry->fltr_info; |
2853 | |
2854 | /* Initialize all the fields for the management entry */ |
2855 | fm_entry->vsi_count = 1; |
2856 | fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX; |
2857 | fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID; |
2858 | fm_entry->counter_index = ICE_INVAL_COUNTER_ID; |
2859 | |
2860 | ice_fill_sw_rule(hw, f_info: &fm_entry->fltr_info, s_rule, |
2861 | opc: ice_aqc_opc_add_sw_rules); |
2862 | |
2863 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
2864 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), num_rules: 1, |
2865 | opc: ice_aqc_opc_add_sw_rules, NULL); |
2866 | if (status) { |
2867 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
2868 | goto ice_create_pkt_fwd_rule_exit; |
2869 | } |
2870 | |
2871 | f_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
2872 | fm_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
2873 | |
2874 | /* The book keeping entries will get removed when base driver |
2875 | * calls remove filter AQ command |
2876 | */ |
2877 | l_type = fm_entry->fltr_info.lkup_type; |
2878 | recp = &hw->switch_info->recp_list[l_type]; |
2879 | list_add(new: &fm_entry->list_entry, head: &recp->filt_rules); |
2880 | |
2881 | ice_create_pkt_fwd_rule_exit: |
2882 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2883 | return status; |
2884 | } |
2885 | |
2886 | /** |
2887 | * ice_update_pkt_fwd_rule |
2888 | * @hw: pointer to the hardware structure |
2889 | * @f_info: filter information for switch rule |
2890 | * |
2891 | * Call AQ command to update a previously created switch rule with a |
2892 | * VSI list ID |
2893 | */ |
2894 | static int |
2895 | ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) |
2896 | { |
2897 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
2898 | int status; |
2899 | |
2900 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
2901 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2902 | GFP_KERNEL); |
2903 | if (!s_rule) |
2904 | return -ENOMEM; |
2905 | |
2906 | ice_fill_sw_rule(hw, f_info, s_rule, opc: ice_aqc_opc_update_sw_rules); |
2907 | |
2908 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); |
2909 | |
2910 | /* Update switch rule with new rule set to forward VSI list */ |
2911 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
2912 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), num_rules: 1, |
2913 | opc: ice_aqc_opc_update_sw_rules, NULL); |
2914 | |
2915 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2916 | return status; |
2917 | } |
2918 | |
2919 | /** |
2920 | * ice_update_sw_rule_bridge_mode |
2921 | * @hw: pointer to the HW struct |
2922 | * |
2923 | * Updates unicast switch filter rules based on VEB/VEPA mode |
2924 | */ |
2925 | int ice_update_sw_rule_bridge_mode(struct ice_hw *hw) |
2926 | { |
2927 | struct ice_switch_info *sw = hw->switch_info; |
2928 | struct ice_fltr_mgmt_list_entry *fm_entry; |
2929 | struct list_head *rule_head; |
2930 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
2931 | int status = 0; |
2932 | |
2933 | rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; |
2934 | rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; |
2935 | |
2936 | mutex_lock(rule_lock); |
2937 | list_for_each_entry(fm_entry, rule_head, list_entry) { |
2938 | struct ice_fltr_info *fi = &fm_entry->fltr_info; |
2939 | u8 *addr = fi->l_data.mac.mac_addr; |
2940 | |
2941 | /* Update unicast Tx rules to reflect the selected |
2942 | * VEB/VEPA mode |
2943 | */ |
2944 | if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) && |
2945 | (fi->fltr_act == ICE_FWD_TO_VSI || |
2946 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || |
2947 | fi->fltr_act == ICE_FWD_TO_Q || |
2948 | fi->fltr_act == ICE_FWD_TO_QGRP)) { |
2949 | status = ice_update_pkt_fwd_rule(hw, f_info: fi); |
2950 | if (status) |
2951 | break; |
2952 | } |
2953 | } |
2954 | |
2955 | mutex_unlock(lock: rule_lock); |
2956 | |
2957 | return status; |
2958 | } |
2959 | |
2960 | /** |
2961 | * ice_add_update_vsi_list |
2962 | * @hw: pointer to the hardware structure |
2963 | * @m_entry: pointer to current filter management list entry |
2964 | * @cur_fltr: filter information from the book keeping entry |
2965 | * @new_fltr: filter information with the new VSI to be added |
2966 | * |
2967 | * Call AQ command to add or update previously created VSI list with new VSI. |
2968 | * |
2969 | * Helper function to do book keeping associated with adding filter information |
2970 | * The algorithm to do the book keeping is described below : |
2971 | * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.) |
2972 | * if only one VSI has been added till now |
2973 | * Allocate a new VSI list and add two VSIs |
2974 | * to this list using switch rule command |
2975 | * Update the previously created switch rule with the |
2976 | * newly created VSI list ID |
2977 | * if a VSI list was previously created |
2978 | * Add the new VSI to the previously created VSI list set |
2979 | * using the update switch rule command |
2980 | */ |
2981 | static int |
2982 | ice_add_update_vsi_list(struct ice_hw *hw, |
2983 | struct ice_fltr_mgmt_list_entry *m_entry, |
2984 | struct ice_fltr_info *cur_fltr, |
2985 | struct ice_fltr_info *new_fltr) |
2986 | { |
2987 | u16 vsi_list_id = 0; |
2988 | int status = 0; |
2989 | |
2990 | if ((cur_fltr->fltr_act == ICE_FWD_TO_Q || |
2991 | cur_fltr->fltr_act == ICE_FWD_TO_QGRP)) |
2992 | return -EOPNOTSUPP; |
2993 | |
2994 | if ((new_fltr->fltr_act == ICE_FWD_TO_Q || |
2995 | new_fltr->fltr_act == ICE_FWD_TO_QGRP) && |
2996 | (cur_fltr->fltr_act == ICE_FWD_TO_VSI || |
2997 | cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST)) |
2998 | return -EOPNOTSUPP; |
2999 | |
3000 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { |
3001 | /* Only one entry existed in the mapping and it was not already |
3002 | * a part of a VSI list. So, create a VSI list with the old and |
3003 | * new VSIs. |
3004 | */ |
3005 | struct ice_fltr_info tmp_fltr; |
3006 | u16 vsi_handle_arr[2]; |
3007 | |
3008 | /* A rule already exists with the new VSI being added */ |
3009 | if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) |
3010 | return -EEXIST; |
3011 | |
3012 | vsi_handle_arr[0] = cur_fltr->vsi_handle; |
3013 | vsi_handle_arr[1] = new_fltr->vsi_handle; |
3014 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3015 | vsi_list_id: &vsi_list_id, |
3016 | lkup_type: new_fltr->lkup_type); |
3017 | if (status) |
3018 | return status; |
3019 | |
3020 | tmp_fltr = *new_fltr; |
3021 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; |
3022 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
3023 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
3024 | /* Update the previous switch rule of "MAC forward to VSI" to |
3025 | * "MAC fwd to VSI list" |
3026 | */ |
3027 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
3028 | if (status) |
3029 | return status; |
3030 | |
3031 | cur_fltr->fwd_id.vsi_list_id = vsi_list_id; |
3032 | cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; |
3033 | m_entry->vsi_list_info = |
3034 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3035 | vsi_list_id); |
3036 | |
3037 | if (!m_entry->vsi_list_info) |
3038 | return -ENOMEM; |
3039 | |
3040 | /* If this entry was large action then the large action needs |
3041 | * to be updated to point to FWD to VSI list |
3042 | */ |
3043 | if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) |
3044 | status = |
3045 | ice_add_marker_act(hw, m_ent: m_entry, |
3046 | sw_marker: m_entry->sw_marker_id, |
3047 | l_id: m_entry->lg_act_idx); |
3048 | } else { |
3049 | u16 vsi_handle = new_fltr->vsi_handle; |
3050 | enum ice_adminq_opc opcode; |
3051 | |
3052 | if (!m_entry->vsi_list_info) |
3053 | return -EIO; |
3054 | |
3055 | /* A rule already exists with the new VSI being added */ |
3056 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) |
3057 | return 0; |
3058 | |
3059 | /* Update the previously created VSI list set with |
3060 | * the new VSI ID passed in |
3061 | */ |
3062 | vsi_list_id = cur_fltr->fwd_id.vsi_list_id; |
3063 | opcode = ice_aqc_opc_update_sw_rules; |
3064 | |
3065 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, |
3066 | vsi_list_id, remove: false, opc: opcode, |
3067 | lkup_type: new_fltr->lkup_type); |
3068 | /* update VSI list mapping info with new VSI ID */ |
3069 | if (!status) |
3070 | set_bit(nr: vsi_handle, addr: m_entry->vsi_list_info->vsi_map); |
3071 | } |
3072 | if (!status) |
3073 | m_entry->vsi_count++; |
3074 | return status; |
3075 | } |
3076 | |
3077 | /** |
3078 | * ice_find_rule_entry - Search a rule entry |
3079 | * @hw: pointer to the hardware structure |
3080 | * @recp_id: lookup type for which the specified rule needs to be searched |
3081 | * @f_info: rule information |
3082 | * |
3083 | * Helper function to search for a given rule entry |
3084 | * Returns pointer to entry storing the rule if found |
3085 | */ |
3086 | static struct ice_fltr_mgmt_list_entry * |
3087 | ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) |
3088 | { |
3089 | struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL; |
3090 | struct ice_switch_info *sw = hw->switch_info; |
3091 | struct list_head *list_head; |
3092 | |
3093 | list_head = &sw->recp_list[recp_id].filt_rules; |
3094 | list_for_each_entry(list_itr, list_head, list_entry) { |
3095 | if (!memcmp(p: &f_info->l_data, q: &list_itr->fltr_info.l_data, |
3096 | size: sizeof(f_info->l_data)) && |
3097 | f_info->flag == list_itr->fltr_info.flag) { |
3098 | ret = list_itr; |
3099 | break; |
3100 | } |
3101 | } |
3102 | return ret; |
3103 | } |
3104 | |
3105 | /** |
3106 | * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 |
3107 | * @hw: pointer to the hardware structure |
3108 | * @recp_id: lookup type for which VSI lists needs to be searched |
3109 | * @vsi_handle: VSI handle to be found in VSI list |
3110 | * @vsi_list_id: VSI list ID found containing vsi_handle |
3111 | * |
3112 | * Helper function to search a VSI list with single entry containing given VSI |
3113 | * handle element. This can be extended further to search VSI list with more |
3114 | * than 1 vsi_count. Returns pointer to VSI list entry if found. |
3115 | */ |
3116 | struct ice_vsi_list_map_info * |
3117 | ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, |
3118 | u16 *vsi_list_id) |
3119 | { |
3120 | struct ice_vsi_list_map_info *map_info = NULL; |
3121 | struct ice_switch_info *sw = hw->switch_info; |
3122 | struct ice_fltr_mgmt_list_entry *list_itr; |
3123 | struct list_head *list_head; |
3124 | |
3125 | list_head = &sw->recp_list[recp_id].filt_rules; |
3126 | list_for_each_entry(list_itr, list_head, list_entry) { |
3127 | if (list_itr->vsi_list_info) { |
3128 | map_info = list_itr->vsi_list_info; |
3129 | if (test_bit(vsi_handle, map_info->vsi_map)) { |
3130 | *vsi_list_id = map_info->vsi_list_id; |
3131 | return map_info; |
3132 | } |
3133 | } |
3134 | } |
3135 | return NULL; |
3136 | } |
3137 | |
3138 | /** |
3139 | * ice_add_rule_internal - add rule for a given lookup type |
3140 | * @hw: pointer to the hardware structure |
3141 | * @recp_id: lookup type (recipe ID) for which rule has to be added |
3142 | * @f_entry: structure containing MAC forwarding information |
3143 | * |
3144 | * Adds or updates the rule lists for a given recipe |
3145 | */ |
3146 | static int |
3147 | ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, |
3148 | struct ice_fltr_list_entry *f_entry) |
3149 | { |
3150 | struct ice_switch_info *sw = hw->switch_info; |
3151 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3152 | struct ice_fltr_mgmt_list_entry *m_entry; |
3153 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3154 | int status = 0; |
3155 | |
3156 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3157 | return -EINVAL; |
3158 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3159 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3160 | |
3161 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; |
3162 | |
3163 | mutex_lock(rule_lock); |
3164 | new_fltr = &f_entry->fltr_info; |
3165 | if (new_fltr->flag & ICE_FLTR_RX) |
3166 | new_fltr->src = hw->port_info->lport; |
3167 | else if (new_fltr->flag & ICE_FLTR_TX) |
3168 | new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; |
3169 | |
3170 | m_entry = ice_find_rule_entry(hw, recp_id, f_info: new_fltr); |
3171 | if (!m_entry) { |
3172 | mutex_unlock(lock: rule_lock); |
3173 | return ice_create_pkt_fwd_rule(hw, f_entry); |
3174 | } |
3175 | |
3176 | cur_fltr = &m_entry->fltr_info; |
3177 | status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr); |
3178 | mutex_unlock(lock: rule_lock); |
3179 | |
3180 | return status; |
3181 | } |
3182 | |
3183 | /** |
3184 | * ice_remove_vsi_list_rule |
3185 | * @hw: pointer to the hardware structure |
3186 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
3187 | * @lkup_type: switch rule filter lookup type |
3188 | * |
3189 | * The VSI list should be emptied before this function is called to remove the |
3190 | * VSI list. |
3191 | */ |
3192 | static int |
3193 | ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, |
3194 | enum ice_sw_lkup_type lkup_type) |
3195 | { |
3196 | struct ice_sw_rule_vsi_list *s_rule; |
3197 | u16 s_rule_size; |
3198 | int status; |
3199 | |
3200 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, 0); |
3201 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), size: s_rule_size, GFP_KERNEL); |
3202 | if (!s_rule) |
3203 | return -ENOMEM; |
3204 | |
3205 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); |
3206 | s_rule->index = cpu_to_le16(vsi_list_id); |
3207 | |
3208 | /* Free the vsi_list resource that we allocated. It is assumed that the |
3209 | * list is empty at this point. |
3210 | */ |
3211 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id: &vsi_list_id, lkup_type, |
3212 | opc: ice_aqc_opc_free_res); |
3213 | |
3214 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
3215 | return status; |
3216 | } |
3217 | |
3218 | /** |
3219 | * ice_rem_update_vsi_list |
3220 | * @hw: pointer to the hardware structure |
3221 | * @vsi_handle: VSI handle of the VSI to remove |
3222 | * @fm_list: filter management entry for which the VSI list management needs to |
3223 | * be done |
3224 | */ |
3225 | static int |
3226 | ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
3227 | struct ice_fltr_mgmt_list_entry *fm_list) |
3228 | { |
3229 | enum ice_sw_lkup_type lkup_type; |
3230 | u16 vsi_list_id; |
3231 | int status = 0; |
3232 | |
3233 | if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST || |
3234 | fm_list->vsi_count == 0) |
3235 | return -EINVAL; |
3236 | |
3237 | /* A rule with the VSI being removed does not exist */ |
3238 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) |
3239 | return -ENOENT; |
3240 | |
3241 | lkup_type = fm_list->fltr_info.lkup_type; |
3242 | vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; |
3243 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, vsi_list_id, remove: true, |
3244 | opc: ice_aqc_opc_update_sw_rules, |
3245 | lkup_type); |
3246 | if (status) |
3247 | return status; |
3248 | |
3249 | fm_list->vsi_count--; |
3250 | clear_bit(nr: vsi_handle, addr: fm_list->vsi_list_info->vsi_map); |
3251 | |
3252 | if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) { |
3253 | struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info; |
3254 | struct ice_vsi_list_map_info *vsi_list_info = |
3255 | fm_list->vsi_list_info; |
3256 | u16 rem_vsi_handle; |
3257 | |
3258 | rem_vsi_handle = find_first_bit(addr: vsi_list_info->vsi_map, |
3259 | ICE_MAX_VSI); |
3260 | if (!ice_is_vsi_valid(hw, vsi_handle: rem_vsi_handle)) |
3261 | return -EIO; |
3262 | |
3263 | /* Make sure VSI list is empty before removing it below */ |
3264 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &rem_vsi_handle, num_vsi: 1, |
3265 | vsi_list_id, remove: true, |
3266 | opc: ice_aqc_opc_update_sw_rules, |
3267 | lkup_type); |
3268 | if (status) |
3269 | return status; |
3270 | |
3271 | tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI; |
3272 | tmp_fltr_info.fwd_id.hw_vsi_id = |
3273 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
3274 | tmp_fltr_info.vsi_handle = rem_vsi_handle; |
3275 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr_info); |
3276 | if (status) { |
3277 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n" , |
3278 | tmp_fltr_info.fwd_id.hw_vsi_id, status); |
3279 | return status; |
3280 | } |
3281 | |
3282 | fm_list->fltr_info = tmp_fltr_info; |
3283 | } |
3284 | |
3285 | if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || |
3286 | (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { |
3287 | struct ice_vsi_list_map_info *vsi_list_info = |
3288 | fm_list->vsi_list_info; |
3289 | |
3290 | /* Remove the VSI list since it is no longer used */ |
3291 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); |
3292 | if (status) { |
3293 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n" , |
3294 | vsi_list_id, status); |
3295 | return status; |
3296 | } |
3297 | |
3298 | list_del(entry: &vsi_list_info->list_entry); |
3299 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi_list_info); |
3300 | fm_list->vsi_list_info = NULL; |
3301 | } |
3302 | |
3303 | return status; |
3304 | } |
3305 | |
3306 | /** |
3307 | * ice_remove_rule_internal - Remove a filter rule of a given type |
3308 | * @hw: pointer to the hardware structure |
3309 | * @recp_id: recipe ID for which the rule needs to removed |
3310 | * @f_entry: rule entry containing filter information |
3311 | */ |
3312 | static int |
3313 | ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, |
3314 | struct ice_fltr_list_entry *f_entry) |
3315 | { |
3316 | struct ice_switch_info *sw = hw->switch_info; |
3317 | struct ice_fltr_mgmt_list_entry *list_elem; |
3318 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3319 | bool remove_rule = false; |
3320 | u16 vsi_handle; |
3321 | int status = 0; |
3322 | |
3323 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3324 | return -EINVAL; |
3325 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3326 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3327 | |
3328 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; |
3329 | mutex_lock(rule_lock); |
3330 | list_elem = ice_find_rule_entry(hw, recp_id, f_info: &f_entry->fltr_info); |
3331 | if (!list_elem) { |
3332 | status = -ENOENT; |
3333 | goto exit; |
3334 | } |
3335 | |
3336 | if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { |
3337 | remove_rule = true; |
3338 | } else if (!list_elem->vsi_list_info) { |
3339 | status = -ENOENT; |
3340 | goto exit; |
3341 | } else if (list_elem->vsi_list_info->ref_cnt > 1) { |
3342 | /* a ref_cnt > 1 indicates that the vsi_list is being |
3343 | * shared by multiple rules. Decrement the ref_cnt and |
3344 | * remove this rule, but do not modify the list, as it |
3345 | * is in-use by other rules. |
3346 | */ |
3347 | list_elem->vsi_list_info->ref_cnt--; |
3348 | remove_rule = true; |
3349 | } else { |
3350 | /* a ref_cnt of 1 indicates the vsi_list is only used |
3351 | * by one rule. However, the original removal request is only |
3352 | * for a single VSI. Update the vsi_list first, and only |
3353 | * remove the rule if there are no further VSIs in this list. |
3354 | */ |
3355 | vsi_handle = f_entry->fltr_info.vsi_handle; |
3356 | status = ice_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
3357 | if (status) |
3358 | goto exit; |
3359 | /* if VSI count goes to zero after updating the VSI list */ |
3360 | if (list_elem->vsi_count == 0) |
3361 | remove_rule = true; |
3362 | } |
3363 | |
3364 | if (remove_rule) { |
3365 | /* Remove the lookup rule */ |
3366 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
3367 | |
3368 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
3369 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
3370 | GFP_KERNEL); |
3371 | if (!s_rule) { |
3372 | status = -ENOMEM; |
3373 | goto exit; |
3374 | } |
3375 | |
3376 | ice_fill_sw_rule(hw, f_info: &list_elem->fltr_info, s_rule, |
3377 | opc: ice_aqc_opc_remove_sw_rules); |
3378 | |
3379 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
3380 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
3381 | num_rules: 1, opc: ice_aqc_opc_remove_sw_rules, NULL); |
3382 | |
3383 | /* Remove a book keeping from the list */ |
3384 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
3385 | |
3386 | if (status) |
3387 | goto exit; |
3388 | |
3389 | list_del(entry: &list_elem->list_entry); |
3390 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem); |
3391 | } |
3392 | exit: |
3393 | mutex_unlock(lock: rule_lock); |
3394 | return status; |
3395 | } |
3396 | |
3397 | /** |
3398 | * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI |
3399 | * @hw: pointer to the hardware structure |
3400 | * @vlan_id: VLAN ID |
3401 | * @vsi_handle: check MAC filter for this VSI |
3402 | */ |
3403 | bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle) |
3404 | { |
3405 | struct ice_fltr_mgmt_list_entry *entry; |
3406 | struct list_head *rule_head; |
3407 | struct ice_switch_info *sw; |
3408 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3409 | u16 hw_vsi_id; |
3410 | |
3411 | if (vlan_id > ICE_MAX_VLAN_ID) |
3412 | return false; |
3413 | |
3414 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3415 | return false; |
3416 | |
3417 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3418 | sw = hw->switch_info; |
3419 | rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; |
3420 | if (!rule_head) |
3421 | return false; |
3422 | |
3423 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
3424 | mutex_lock(rule_lock); |
3425 | list_for_each_entry(entry, rule_head, list_entry) { |
3426 | struct ice_fltr_info *f_info = &entry->fltr_info; |
3427 | u16 entry_vlan_id = f_info->l_data.vlan.vlan_id; |
3428 | struct ice_vsi_list_map_info *map_info; |
3429 | |
3430 | if (entry_vlan_id > ICE_MAX_VLAN_ID) |
3431 | continue; |
3432 | |
3433 | if (f_info->flag != ICE_FLTR_TX || |
3434 | f_info->src_id != ICE_SRC_ID_VSI || |
3435 | f_info->lkup_type != ICE_SW_LKUP_VLAN) |
3436 | continue; |
3437 | |
3438 | /* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */ |
3439 | if (f_info->fltr_act != ICE_FWD_TO_VSI && |
3440 | f_info->fltr_act != ICE_FWD_TO_VSI_LIST) |
3441 | continue; |
3442 | |
3443 | if (f_info->fltr_act == ICE_FWD_TO_VSI) { |
3444 | if (hw_vsi_id != f_info->fwd_id.hw_vsi_id) |
3445 | continue; |
3446 | } else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { |
3447 | /* If filter_action is FWD_TO_VSI_LIST, make sure |
3448 | * that VSI being checked is part of VSI list |
3449 | */ |
3450 | if (entry->vsi_count == 1 && |
3451 | entry->vsi_list_info) { |
3452 | map_info = entry->vsi_list_info; |
3453 | if (!test_bit(vsi_handle, map_info->vsi_map)) |
3454 | continue; |
3455 | } |
3456 | } |
3457 | |
3458 | if (vlan_id == entry_vlan_id) { |
3459 | mutex_unlock(lock: rule_lock); |
3460 | return true; |
3461 | } |
3462 | } |
3463 | mutex_unlock(lock: rule_lock); |
3464 | |
3465 | return false; |
3466 | } |
3467 | |
3468 | /** |
3469 | * ice_add_mac - Add a MAC address based filter rule |
3470 | * @hw: pointer to the hardware structure |
3471 | * @m_list: list of MAC addresses and forwarding information |
3472 | */ |
3473 | int ice_add_mac(struct ice_hw *hw, struct list_head *m_list) |
3474 | { |
3475 | struct ice_fltr_list_entry *m_list_itr; |
3476 | int status = 0; |
3477 | |
3478 | if (!m_list || !hw) |
3479 | return -EINVAL; |
3480 | |
3481 | list_for_each_entry(m_list_itr, m_list, list_entry) { |
3482 | u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; |
3483 | u16 vsi_handle; |
3484 | u16 hw_vsi_id; |
3485 | |
3486 | m_list_itr->fltr_info.flag = ICE_FLTR_TX; |
3487 | vsi_handle = m_list_itr->fltr_info.vsi_handle; |
3488 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3489 | return -EINVAL; |
3490 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3491 | m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; |
3492 | /* update the src in case it is VSI num */ |
3493 | if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) |
3494 | return -EINVAL; |
3495 | m_list_itr->fltr_info.src = hw_vsi_id; |
3496 | if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || |
3497 | is_zero_ether_addr(addr: add)) |
3498 | return -EINVAL; |
3499 | |
3500 | m_list_itr->status = ice_add_rule_internal(hw, recp_id: ICE_SW_LKUP_MAC, |
3501 | f_entry: m_list_itr); |
3502 | if (m_list_itr->status) |
3503 | return m_list_itr->status; |
3504 | } |
3505 | |
3506 | return status; |
3507 | } |
3508 | |
3509 | /** |
3510 | * ice_add_vlan_internal - Add one VLAN based filter rule |
3511 | * @hw: pointer to the hardware structure |
3512 | * @f_entry: filter entry containing one VLAN information |
3513 | */ |
3514 | static int |
3515 | ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) |
3516 | { |
3517 | struct ice_switch_info *sw = hw->switch_info; |
3518 | struct ice_fltr_mgmt_list_entry *v_list_itr; |
3519 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3520 | enum ice_sw_lkup_type lkup_type; |
3521 | u16 vsi_list_id = 0, vsi_handle; |
3522 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3523 | int status = 0; |
3524 | |
3525 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3526 | return -EINVAL; |
3527 | |
3528 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3529 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3530 | new_fltr = &f_entry->fltr_info; |
3531 | |
3532 | /* VLAN ID should only be 12 bits */ |
3533 | if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) |
3534 | return -EINVAL; |
3535 | |
3536 | if (new_fltr->src_id != ICE_SRC_ID_VSI) |
3537 | return -EINVAL; |
3538 | |
3539 | new_fltr->src = new_fltr->fwd_id.hw_vsi_id; |
3540 | lkup_type = new_fltr->lkup_type; |
3541 | vsi_handle = new_fltr->vsi_handle; |
3542 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
3543 | mutex_lock(rule_lock); |
3544 | v_list_itr = ice_find_rule_entry(hw, recp_id: ICE_SW_LKUP_VLAN, f_info: new_fltr); |
3545 | if (!v_list_itr) { |
3546 | struct ice_vsi_list_map_info *map_info = NULL; |
3547 | |
3548 | if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { |
3549 | /* All VLAN pruning rules use a VSI list. Check if |
3550 | * there is already a VSI list containing VSI that we |
3551 | * want to add. If found, use the same vsi_list_id for |
3552 | * this new VLAN rule or else create a new list. |
3553 | */ |
3554 | map_info = ice_find_vsi_list_entry(hw, recp_id: ICE_SW_LKUP_VLAN, |
3555 | vsi_handle, |
3556 | vsi_list_id: &vsi_list_id); |
3557 | if (!map_info) { |
3558 | status = ice_create_vsi_list_rule(hw, |
3559 | vsi_handle_arr: &vsi_handle, |
3560 | num_vsi: 1, |
3561 | vsi_list_id: &vsi_list_id, |
3562 | lkup_type); |
3563 | if (status) |
3564 | goto exit; |
3565 | } |
3566 | /* Convert the action to forwarding to a VSI list. */ |
3567 | new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; |
3568 | new_fltr->fwd_id.vsi_list_id = vsi_list_id; |
3569 | } |
3570 | |
3571 | status = ice_create_pkt_fwd_rule(hw, f_entry); |
3572 | if (!status) { |
3573 | v_list_itr = ice_find_rule_entry(hw, recp_id: ICE_SW_LKUP_VLAN, |
3574 | f_info: new_fltr); |
3575 | if (!v_list_itr) { |
3576 | status = -ENOENT; |
3577 | goto exit; |
3578 | } |
3579 | /* reuse VSI list for new rule and increment ref_cnt */ |
3580 | if (map_info) { |
3581 | v_list_itr->vsi_list_info = map_info; |
3582 | map_info->ref_cnt++; |
3583 | } else { |
3584 | v_list_itr->vsi_list_info = |
3585 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle, |
3586 | num_vsi: 1, vsi_list_id); |
3587 | } |
3588 | } |
3589 | } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { |
3590 | /* Update existing VSI list to add new VSI ID only if it used |
3591 | * by one VLAN rule. |
3592 | */ |
3593 | cur_fltr = &v_list_itr->fltr_info; |
3594 | status = ice_add_update_vsi_list(hw, m_entry: v_list_itr, cur_fltr, |
3595 | new_fltr); |
3596 | } else { |
3597 | /* If VLAN rule exists and VSI list being used by this rule is |
3598 | * referenced by more than 1 VLAN rule. Then create a new VSI |
3599 | * list appending previous VSI with new VSI and update existing |
3600 | * VLAN rule to point to new VSI list ID |
3601 | */ |
3602 | struct ice_fltr_info tmp_fltr; |
3603 | u16 vsi_handle_arr[2]; |
3604 | u16 cur_handle; |
3605 | |
3606 | /* Current implementation only supports reusing VSI list with |
3607 | * one VSI count. We should never hit below condition |
3608 | */ |
3609 | if (v_list_itr->vsi_count > 1 && |
3610 | v_list_itr->vsi_list_info->ref_cnt > 1) { |
3611 | ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n" ); |
3612 | status = -EIO; |
3613 | goto exit; |
3614 | } |
3615 | |
3616 | cur_handle = |
3617 | find_first_bit(addr: v_list_itr->vsi_list_info->vsi_map, |
3618 | ICE_MAX_VSI); |
3619 | |
3620 | /* A rule already exists with the new VSI being added */ |
3621 | if (cur_handle == vsi_handle) { |
3622 | status = -EEXIST; |
3623 | goto exit; |
3624 | } |
3625 | |
3626 | vsi_handle_arr[0] = cur_handle; |
3627 | vsi_handle_arr[1] = vsi_handle; |
3628 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3629 | vsi_list_id: &vsi_list_id, lkup_type); |
3630 | if (status) |
3631 | goto exit; |
3632 | |
3633 | tmp_fltr = v_list_itr->fltr_info; |
3634 | tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; |
3635 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
3636 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
3637 | /* Update the previous switch rule to a new VSI list which |
3638 | * includes current VSI that is requested |
3639 | */ |
3640 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
3641 | if (status) |
3642 | goto exit; |
3643 | |
3644 | /* before overriding VSI list map info. decrement ref_cnt of |
3645 | * previous VSI list |
3646 | */ |
3647 | v_list_itr->vsi_list_info->ref_cnt--; |
3648 | |
3649 | /* now update to newly created list */ |
3650 | v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; |
3651 | v_list_itr->vsi_list_info = |
3652 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3653 | vsi_list_id); |
3654 | v_list_itr->vsi_count++; |
3655 | } |
3656 | |
3657 | exit: |
3658 | mutex_unlock(lock: rule_lock); |
3659 | return status; |
3660 | } |
3661 | |
3662 | /** |
3663 | * ice_add_vlan - Add VLAN based filter rule |
3664 | * @hw: pointer to the hardware structure |
3665 | * @v_list: list of VLAN entries and forwarding information |
3666 | */ |
3667 | int ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) |
3668 | { |
3669 | struct ice_fltr_list_entry *v_list_itr; |
3670 | |
3671 | if (!v_list || !hw) |
3672 | return -EINVAL; |
3673 | |
3674 | list_for_each_entry(v_list_itr, v_list, list_entry) { |
3675 | if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) |
3676 | return -EINVAL; |
3677 | v_list_itr->fltr_info.flag = ICE_FLTR_TX; |
3678 | v_list_itr->status = ice_add_vlan_internal(hw, f_entry: v_list_itr); |
3679 | if (v_list_itr->status) |
3680 | return v_list_itr->status; |
3681 | } |
3682 | return 0; |
3683 | } |
3684 | |
3685 | /** |
3686 | * ice_add_eth_mac - Add ethertype and MAC based filter rule |
3687 | * @hw: pointer to the hardware structure |
3688 | * @em_list: list of ether type MAC filter, MAC is optional |
3689 | * |
3690 | * This function requires the caller to populate the entries in |
3691 | * the filter list with the necessary fields (including flags to |
3692 | * indicate Tx or Rx rules). |
3693 | */ |
3694 | int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
3695 | { |
3696 | struct ice_fltr_list_entry *em_list_itr; |
3697 | |
3698 | if (!em_list || !hw) |
3699 | return -EINVAL; |
3700 | |
3701 | list_for_each_entry(em_list_itr, em_list, list_entry) { |
3702 | enum ice_sw_lkup_type l_type = |
3703 | em_list_itr->fltr_info.lkup_type; |
3704 | |
3705 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && |
3706 | l_type != ICE_SW_LKUP_ETHERTYPE) |
3707 | return -EINVAL; |
3708 | |
3709 | em_list_itr->status = ice_add_rule_internal(hw, recp_id: l_type, |
3710 | f_entry: em_list_itr); |
3711 | if (em_list_itr->status) |
3712 | return em_list_itr->status; |
3713 | } |
3714 | return 0; |
3715 | } |
3716 | |
3717 | /** |
3718 | * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule |
3719 | * @hw: pointer to the hardware structure |
3720 | * @em_list: list of ethertype or ethertype MAC entries |
3721 | */ |
3722 | int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
3723 | { |
3724 | struct ice_fltr_list_entry *em_list_itr, *tmp; |
3725 | |
3726 | if (!em_list || !hw) |
3727 | return -EINVAL; |
3728 | |
3729 | list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { |
3730 | enum ice_sw_lkup_type l_type = |
3731 | em_list_itr->fltr_info.lkup_type; |
3732 | |
3733 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && |
3734 | l_type != ICE_SW_LKUP_ETHERTYPE) |
3735 | return -EINVAL; |
3736 | |
3737 | em_list_itr->status = ice_remove_rule_internal(hw, recp_id: l_type, |
3738 | f_entry: em_list_itr); |
3739 | if (em_list_itr->status) |
3740 | return em_list_itr->status; |
3741 | } |
3742 | return 0; |
3743 | } |
3744 | |
3745 | /** |
3746 | * ice_rem_sw_rule_info |
3747 | * @hw: pointer to the hardware structure |
3748 | * @rule_head: pointer to the switch list structure that we want to delete |
3749 | */ |
3750 | static void |
3751 | ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) |
3752 | { |
3753 | if (!list_empty(head: rule_head)) { |
3754 | struct ice_fltr_mgmt_list_entry *entry; |
3755 | struct ice_fltr_mgmt_list_entry *tmp; |
3756 | |
3757 | list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { |
3758 | list_del(entry: &entry->list_entry); |
3759 | devm_kfree(dev: ice_hw_to_dev(hw), p: entry); |
3760 | } |
3761 | } |
3762 | } |
3763 | |
3764 | /** |
3765 | * ice_rem_adv_rule_info |
3766 | * @hw: pointer to the hardware structure |
3767 | * @rule_head: pointer to the switch list structure that we want to delete |
3768 | */ |
3769 | static void |
3770 | ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head) |
3771 | { |
3772 | struct ice_adv_fltr_mgmt_list_entry *tmp_entry; |
3773 | struct ice_adv_fltr_mgmt_list_entry *lst_itr; |
3774 | |
3775 | if (list_empty(head: rule_head)) |
3776 | return; |
3777 | |
3778 | list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) { |
3779 | list_del(entry: &lst_itr->list_entry); |
3780 | devm_kfree(dev: ice_hw_to_dev(hw), p: lst_itr->lkups); |
3781 | devm_kfree(dev: ice_hw_to_dev(hw), p: lst_itr); |
3782 | } |
3783 | } |
3784 | |
3785 | /** |
3786 | * ice_cfg_dflt_vsi - change state of VSI to set/clear default |
3787 | * @pi: pointer to the port_info structure |
3788 | * @vsi_handle: VSI handle to set as default |
3789 | * @set: true to add the above mentioned switch rule, false to remove it |
3790 | * @direction: ICE_FLTR_RX or ICE_FLTR_TX |
3791 | * |
3792 | * add filter rule to set/unset given VSI as default VSI for the switch |
3793 | * (represented by swid) |
3794 | */ |
3795 | int |
3796 | ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set, |
3797 | u8 direction) |
3798 | { |
3799 | struct ice_fltr_list_entry f_list_entry; |
3800 | struct ice_fltr_info f_info; |
3801 | struct ice_hw *hw = pi->hw; |
3802 | u16 hw_vsi_id; |
3803 | int status; |
3804 | |
3805 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3806 | return -EINVAL; |
3807 | |
3808 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3809 | |
3810 | memset(&f_info, 0, sizeof(f_info)); |
3811 | |
3812 | f_info.lkup_type = ICE_SW_LKUP_DFLT; |
3813 | f_info.flag = direction; |
3814 | f_info.fltr_act = ICE_FWD_TO_VSI; |
3815 | f_info.fwd_id.hw_vsi_id = hw_vsi_id; |
3816 | f_info.vsi_handle = vsi_handle; |
3817 | |
3818 | if (f_info.flag & ICE_FLTR_RX) { |
3819 | f_info.src = hw->port_info->lport; |
3820 | f_info.src_id = ICE_SRC_ID_LPORT; |
3821 | } else if (f_info.flag & ICE_FLTR_TX) { |
3822 | f_info.src_id = ICE_SRC_ID_VSI; |
3823 | f_info.src = hw_vsi_id; |
3824 | } |
3825 | f_list_entry.fltr_info = f_info; |
3826 | |
3827 | if (set) |
3828 | status = ice_add_rule_internal(hw, recp_id: ICE_SW_LKUP_DFLT, |
3829 | f_entry: &f_list_entry); |
3830 | else |
3831 | status = ice_remove_rule_internal(hw, recp_id: ICE_SW_LKUP_DFLT, |
3832 | f_entry: &f_list_entry); |
3833 | |
3834 | return status; |
3835 | } |
3836 | |
3837 | /** |
3838 | * ice_vsi_uses_fltr - Determine if given VSI uses specified filter |
3839 | * @fm_entry: filter entry to inspect |
3840 | * @vsi_handle: VSI handle to compare with filter info |
3841 | */ |
3842 | static bool |
3843 | ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) |
3844 | { |
3845 | return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && |
3846 | fm_entry->fltr_info.vsi_handle == vsi_handle) || |
3847 | (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && |
3848 | fm_entry->vsi_list_info && |
3849 | (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); |
3850 | } |
3851 | |
3852 | /** |
3853 | * ice_check_if_dflt_vsi - check if VSI is default VSI |
3854 | * @pi: pointer to the port_info structure |
3855 | * @vsi_handle: vsi handle to check for in filter list |
3856 | * @rule_exists: indicates if there are any VSI's in the rule list |
3857 | * |
3858 | * checks if the VSI is in a default VSI list, and also indicates |
3859 | * if the default VSI list is empty |
3860 | */ |
3861 | bool |
3862 | ice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, |
3863 | bool *rule_exists) |
3864 | { |
3865 | struct ice_fltr_mgmt_list_entry *fm_entry; |
3866 | struct ice_sw_recipe *recp_list; |
3867 | struct list_head *rule_head; |
3868 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3869 | bool ret = false; |
3870 | |
3871 | recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT]; |
3872 | rule_lock = &recp_list->filt_rule_lock; |
3873 | rule_head = &recp_list->filt_rules; |
3874 | |
3875 | mutex_lock(rule_lock); |
3876 | |
3877 | if (rule_exists && !list_empty(head: rule_head)) |
3878 | *rule_exists = true; |
3879 | |
3880 | list_for_each_entry(fm_entry, rule_head, list_entry) { |
3881 | if (ice_vsi_uses_fltr(fm_entry, vsi_handle)) { |
3882 | ret = true; |
3883 | break; |
3884 | } |
3885 | } |
3886 | |
3887 | mutex_unlock(lock: rule_lock); |
3888 | |
3889 | return ret; |
3890 | } |
3891 | |
3892 | /** |
3893 | * ice_remove_mac - remove a MAC address based filter rule |
3894 | * @hw: pointer to the hardware structure |
3895 | * @m_list: list of MAC addresses and forwarding information |
3896 | * |
3897 | * This function removes either a MAC filter rule or a specific VSI from a |
3898 | * VSI list for a multicast MAC address. |
3899 | * |
3900 | * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should |
3901 | * be aware that this call will only work if all the entries passed into m_list |
3902 | * were added previously. It will not attempt to do a partial remove of entries |
3903 | * that were found. |
3904 | */ |
3905 | int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) |
3906 | { |
3907 | struct ice_fltr_list_entry *list_itr, *tmp; |
3908 | |
3909 | if (!m_list) |
3910 | return -EINVAL; |
3911 | |
3912 | list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { |
3913 | enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; |
3914 | u16 vsi_handle; |
3915 | |
3916 | if (l_type != ICE_SW_LKUP_MAC) |
3917 | return -EINVAL; |
3918 | |
3919 | vsi_handle = list_itr->fltr_info.vsi_handle; |
3920 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3921 | return -EINVAL; |
3922 | |
3923 | list_itr->fltr_info.fwd_id.hw_vsi_id = |
3924 | ice_get_hw_vsi_num(hw, vsi_handle); |
3925 | |
3926 | list_itr->status = ice_remove_rule_internal(hw, |
3927 | recp_id: ICE_SW_LKUP_MAC, |
3928 | f_entry: list_itr); |
3929 | if (list_itr->status) |
3930 | return list_itr->status; |
3931 | } |
3932 | return 0; |
3933 | } |
3934 | |
3935 | /** |
3936 | * ice_remove_vlan - Remove VLAN based filter rule |
3937 | * @hw: pointer to the hardware structure |
3938 | * @v_list: list of VLAN entries and forwarding information |
3939 | */ |
3940 | int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) |
3941 | { |
3942 | struct ice_fltr_list_entry *v_list_itr, *tmp; |
3943 | |
3944 | if (!v_list || !hw) |
3945 | return -EINVAL; |
3946 | |
3947 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { |
3948 | enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; |
3949 | |
3950 | if (l_type != ICE_SW_LKUP_VLAN) |
3951 | return -EINVAL; |
3952 | v_list_itr->status = ice_remove_rule_internal(hw, |
3953 | recp_id: ICE_SW_LKUP_VLAN, |
3954 | f_entry: v_list_itr); |
3955 | if (v_list_itr->status) |
3956 | return v_list_itr->status; |
3957 | } |
3958 | return 0; |
3959 | } |
3960 | |
3961 | /** |
3962 | * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list |
3963 | * @hw: pointer to the hardware structure |
3964 | * @vsi_handle: VSI handle to remove filters from |
3965 | * @vsi_list_head: pointer to the list to add entry to |
3966 | * @fi: pointer to fltr_info of filter entry to copy & add |
3967 | * |
3968 | * Helper function, used when creating a list of filters to remove from |
3969 | * a specific VSI. The entry added to vsi_list_head is a COPY of the |
3970 | * original filter entry, with the exception of fltr_info.fltr_act and |
3971 | * fltr_info.fwd_id fields. These are set such that later logic can |
3972 | * extract which VSI to remove the fltr from, and pass on that information. |
3973 | */ |
3974 | static int |
3975 | ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
3976 | struct list_head *vsi_list_head, |
3977 | struct ice_fltr_info *fi) |
3978 | { |
3979 | struct ice_fltr_list_entry *tmp; |
3980 | |
3981 | /* this memory is freed up in the caller function |
3982 | * once filters for this VSI are removed |
3983 | */ |
3984 | tmp = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*tmp), GFP_KERNEL); |
3985 | if (!tmp) |
3986 | return -ENOMEM; |
3987 | |
3988 | tmp->fltr_info = *fi; |
3989 | |
3990 | /* Overwrite these fields to indicate which VSI to remove filter from, |
3991 | * so find and remove logic can extract the information from the |
3992 | * list entries. Note that original entries will still have proper |
3993 | * values. |
3994 | */ |
3995 | tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; |
3996 | tmp->fltr_info.vsi_handle = vsi_handle; |
3997 | tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3998 | |
3999 | list_add(new: &tmp->list_entry, head: vsi_list_head); |
4000 | |
4001 | return 0; |
4002 | } |
4003 | |
4004 | /** |
4005 | * ice_add_to_vsi_fltr_list - Add VSI filters to the list |
4006 | * @hw: pointer to the hardware structure |
4007 | * @vsi_handle: VSI handle to remove filters from |
4008 | * @lkup_list_head: pointer to the list that has certain lookup type filters |
4009 | * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle |
4010 | * |
4011 | * Locates all filters in lkup_list_head that are used by the given VSI, |
4012 | * and adds COPIES of those entries to vsi_list_head (intended to be used |
4013 | * to remove the listed filters). |
4014 | * Note that this means all entries in vsi_list_head must be explicitly |
4015 | * deallocated by the caller when done with list. |
4016 | */ |
4017 | static int |
4018 | ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
4019 | struct list_head *lkup_list_head, |
4020 | struct list_head *vsi_list_head) |
4021 | { |
4022 | struct ice_fltr_mgmt_list_entry *fm_entry; |
4023 | int status = 0; |
4024 | |
4025 | /* check to make sure VSI ID is valid and within boundary */ |
4026 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4027 | return -EINVAL; |
4028 | |
4029 | list_for_each_entry(fm_entry, lkup_list_head, list_entry) { |
4030 | if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) |
4031 | continue; |
4032 | |
4033 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, |
4034 | vsi_list_head, |
4035 | fi: &fm_entry->fltr_info); |
4036 | if (status) |
4037 | return status; |
4038 | } |
4039 | return status; |
4040 | } |
4041 | |
4042 | /** |
4043 | * ice_determine_promisc_mask |
4044 | * @fi: filter info to parse |
4045 | * |
4046 | * Helper function to determine which ICE_PROMISC_ mask corresponds |
4047 | * to given filter into. |
4048 | */ |
4049 | static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) |
4050 | { |
4051 | u16 vid = fi->l_data.mac_vlan.vlan_id; |
4052 | u8 *macaddr = fi->l_data.mac.mac_addr; |
4053 | bool is_tx_fltr = false; |
4054 | u8 promisc_mask = 0; |
4055 | |
4056 | if (fi->flag == ICE_FLTR_TX) |
4057 | is_tx_fltr = true; |
4058 | |
4059 | if (is_broadcast_ether_addr(addr: macaddr)) |
4060 | promisc_mask |= is_tx_fltr ? |
4061 | ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; |
4062 | else if (is_multicast_ether_addr(addr: macaddr)) |
4063 | promisc_mask |= is_tx_fltr ? |
4064 | ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; |
4065 | else if (is_unicast_ether_addr(addr: macaddr)) |
4066 | promisc_mask |= is_tx_fltr ? |
4067 | ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; |
4068 | if (vid) |
4069 | promisc_mask |= is_tx_fltr ? |
4070 | ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; |
4071 | |
4072 | return promisc_mask; |
4073 | } |
4074 | |
4075 | /** |
4076 | * ice_remove_promisc - Remove promisc based filter rules |
4077 | * @hw: pointer to the hardware structure |
4078 | * @recp_id: recipe ID for which the rule needs to removed |
4079 | * @v_list: list of promisc entries |
4080 | */ |
4081 | static int |
4082 | ice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list) |
4083 | { |
4084 | struct ice_fltr_list_entry *v_list_itr, *tmp; |
4085 | |
4086 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { |
4087 | v_list_itr->status = |
4088 | ice_remove_rule_internal(hw, recp_id, f_entry: v_list_itr); |
4089 | if (v_list_itr->status) |
4090 | return v_list_itr->status; |
4091 | } |
4092 | return 0; |
4093 | } |
4094 | |
4095 | /** |
4096 | * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI |
4097 | * @hw: pointer to the hardware structure |
4098 | * @vsi_handle: VSI handle to clear mode |
4099 | * @promisc_mask: mask of promiscuous config bits to clear |
4100 | * @vid: VLAN ID to clear VLAN promiscuous |
4101 | */ |
4102 | int |
4103 | ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4104 | u16 vid) |
4105 | { |
4106 | struct ice_switch_info *sw = hw->switch_info; |
4107 | struct ice_fltr_list_entry *fm_entry, *tmp; |
4108 | struct list_head remove_list_head; |
4109 | struct ice_fltr_mgmt_list_entry *itr; |
4110 | struct list_head *rule_head; |
4111 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
4112 | int status = 0; |
4113 | u8 recipe_id; |
4114 | |
4115 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4116 | return -EINVAL; |
4117 | |
4118 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) |
4119 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; |
4120 | else |
4121 | recipe_id = ICE_SW_LKUP_PROMISC; |
4122 | |
4123 | rule_head = &sw->recp_list[recipe_id].filt_rules; |
4124 | rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; |
4125 | |
4126 | INIT_LIST_HEAD(list: &remove_list_head); |
4127 | |
4128 | mutex_lock(rule_lock); |
4129 | list_for_each_entry(itr, rule_head, list_entry) { |
4130 | struct ice_fltr_info *fltr_info; |
4131 | u8 fltr_promisc_mask = 0; |
4132 | |
4133 | if (!ice_vsi_uses_fltr(fm_entry: itr, vsi_handle)) |
4134 | continue; |
4135 | fltr_info = &itr->fltr_info; |
4136 | |
4137 | if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && |
4138 | vid != fltr_info->l_data.mac_vlan.vlan_id) |
4139 | continue; |
4140 | |
4141 | fltr_promisc_mask |= ice_determine_promisc_mask(fi: fltr_info); |
4142 | |
4143 | /* Skip if filter is not completely specified by given mask */ |
4144 | if (fltr_promisc_mask & ~promisc_mask) |
4145 | continue; |
4146 | |
4147 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, |
4148 | vsi_list_head: &remove_list_head, |
4149 | fi: fltr_info); |
4150 | if (status) { |
4151 | mutex_unlock(lock: rule_lock); |
4152 | goto free_fltr_list; |
4153 | } |
4154 | } |
4155 | mutex_unlock(lock: rule_lock); |
4156 | |
4157 | status = ice_remove_promisc(hw, recp_id: recipe_id, v_list: &remove_list_head); |
4158 | |
4159 | free_fltr_list: |
4160 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { |
4161 | list_del(entry: &fm_entry->list_entry); |
4162 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
4163 | } |
4164 | |
4165 | return status; |
4166 | } |
4167 | |
4168 | /** |
4169 | * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) |
4170 | * @hw: pointer to the hardware structure |
4171 | * @vsi_handle: VSI handle to configure |
4172 | * @promisc_mask: mask of promiscuous config bits |
4173 | * @vid: VLAN ID to set VLAN promiscuous |
4174 | */ |
4175 | int |
4176 | ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) |
4177 | { |
4178 | enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; |
4179 | struct ice_fltr_list_entry f_list_entry; |
4180 | struct ice_fltr_info new_fltr; |
4181 | bool is_tx_fltr; |
4182 | int status = 0; |
4183 | u16 hw_vsi_id; |
4184 | int pkt_type; |
4185 | u8 recipe_id; |
4186 | |
4187 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4188 | return -EINVAL; |
4189 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
4190 | |
4191 | memset(&new_fltr, 0, sizeof(new_fltr)); |
4192 | |
4193 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { |
4194 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; |
4195 | new_fltr.l_data.mac_vlan.vlan_id = vid; |
4196 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; |
4197 | } else { |
4198 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; |
4199 | recipe_id = ICE_SW_LKUP_PROMISC; |
4200 | } |
4201 | |
4202 | /* Separate filters must be set for each direction/packet type |
4203 | * combination, so we will loop over the mask value, store the |
4204 | * individual type, and clear it out in the input mask as it |
4205 | * is found. |
4206 | */ |
4207 | while (promisc_mask) { |
4208 | u8 *mac_addr; |
4209 | |
4210 | pkt_type = 0; |
4211 | is_tx_fltr = false; |
4212 | |
4213 | if (promisc_mask & ICE_PROMISC_UCAST_RX) { |
4214 | promisc_mask &= ~ICE_PROMISC_UCAST_RX; |
4215 | pkt_type = UCAST_FLTR; |
4216 | } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { |
4217 | promisc_mask &= ~ICE_PROMISC_UCAST_TX; |
4218 | pkt_type = UCAST_FLTR; |
4219 | is_tx_fltr = true; |
4220 | } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { |
4221 | promisc_mask &= ~ICE_PROMISC_MCAST_RX; |
4222 | pkt_type = MCAST_FLTR; |
4223 | } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { |
4224 | promisc_mask &= ~ICE_PROMISC_MCAST_TX; |
4225 | pkt_type = MCAST_FLTR; |
4226 | is_tx_fltr = true; |
4227 | } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { |
4228 | promisc_mask &= ~ICE_PROMISC_BCAST_RX; |
4229 | pkt_type = BCAST_FLTR; |
4230 | } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { |
4231 | promisc_mask &= ~ICE_PROMISC_BCAST_TX; |
4232 | pkt_type = BCAST_FLTR; |
4233 | is_tx_fltr = true; |
4234 | } |
4235 | |
4236 | /* Check for VLAN promiscuous flag */ |
4237 | if (promisc_mask & ICE_PROMISC_VLAN_RX) { |
4238 | promisc_mask &= ~ICE_PROMISC_VLAN_RX; |
4239 | } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { |
4240 | promisc_mask &= ~ICE_PROMISC_VLAN_TX; |
4241 | is_tx_fltr = true; |
4242 | } |
4243 | |
4244 | /* Set filter DA based on packet type */ |
4245 | mac_addr = new_fltr.l_data.mac.mac_addr; |
4246 | if (pkt_type == BCAST_FLTR) { |
4247 | eth_broadcast_addr(addr: mac_addr); |
4248 | } else if (pkt_type == MCAST_FLTR || |
4249 | pkt_type == UCAST_FLTR) { |
4250 | /* Use the dummy ether header DA */ |
4251 | ether_addr_copy(dst: mac_addr, src: dummy_eth_header); |
4252 | if (pkt_type == MCAST_FLTR) |
4253 | mac_addr[0] |= 0x1; /* Set multicast bit */ |
4254 | } |
4255 | |
4256 | /* Need to reset this to zero for all iterations */ |
4257 | new_fltr.flag = 0; |
4258 | if (is_tx_fltr) { |
4259 | new_fltr.flag |= ICE_FLTR_TX; |
4260 | new_fltr.src = hw_vsi_id; |
4261 | } else { |
4262 | new_fltr.flag |= ICE_FLTR_RX; |
4263 | new_fltr.src = hw->port_info->lport; |
4264 | } |
4265 | |
4266 | new_fltr.fltr_act = ICE_FWD_TO_VSI; |
4267 | new_fltr.vsi_handle = vsi_handle; |
4268 | new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; |
4269 | f_list_entry.fltr_info = new_fltr; |
4270 | |
4271 | status = ice_add_rule_internal(hw, recp_id: recipe_id, f_entry: &f_list_entry); |
4272 | if (status) |
4273 | goto set_promisc_exit; |
4274 | } |
4275 | |
4276 | set_promisc_exit: |
4277 | return status; |
4278 | } |
4279 | |
4280 | /** |
4281 | * ice_set_vlan_vsi_promisc |
4282 | * @hw: pointer to the hardware structure |
4283 | * @vsi_handle: VSI handle to configure |
4284 | * @promisc_mask: mask of promiscuous config bits |
4285 | * @rm_vlan_promisc: Clear VLANs VSI promisc mode |
4286 | * |
4287 | * Configure VSI with all associated VLANs to given promiscuous mode(s) |
4288 | */ |
4289 | int |
4290 | ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4291 | bool rm_vlan_promisc) |
4292 | { |
4293 | struct ice_switch_info *sw = hw->switch_info; |
4294 | struct ice_fltr_list_entry *list_itr, *tmp; |
4295 | struct list_head vsi_list_head; |
4296 | struct list_head *vlan_head; |
4297 | struct mutex *vlan_lock; /* Lock to protect filter rule list */ |
4298 | u16 vlan_id; |
4299 | int status; |
4300 | |
4301 | INIT_LIST_HEAD(list: &vsi_list_head); |
4302 | vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
4303 | vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; |
4304 | mutex_lock(vlan_lock); |
4305 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, lkup_list_head: vlan_head, |
4306 | vsi_list_head: &vsi_list_head); |
4307 | mutex_unlock(lock: vlan_lock); |
4308 | if (status) |
4309 | goto free_fltr_list; |
4310 | |
4311 | list_for_each_entry(list_itr, &vsi_list_head, list_entry) { |
4312 | /* Avoid enabling or disabling VLAN zero twice when in double |
4313 | * VLAN mode |
4314 | */ |
4315 | if (ice_is_dvm_ena(hw) && |
4316 | list_itr->fltr_info.l_data.vlan.tpid == 0) |
4317 | continue; |
4318 | |
4319 | vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; |
4320 | if (rm_vlan_promisc) |
4321 | status = ice_clear_vsi_promisc(hw, vsi_handle, |
4322 | promisc_mask, vid: vlan_id); |
4323 | else |
4324 | status = ice_set_vsi_promisc(hw, vsi_handle, |
4325 | promisc_mask, vid: vlan_id); |
4326 | if (status && status != -EEXIST) |
4327 | break; |
4328 | } |
4329 | |
4330 | free_fltr_list: |
4331 | list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { |
4332 | list_del(entry: &list_itr->list_entry); |
4333 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_itr); |
4334 | } |
4335 | return status; |
4336 | } |
4337 | |
4338 | /** |
4339 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI |
4340 | * @hw: pointer to the hardware structure |
4341 | * @vsi_handle: VSI handle to remove filters from |
4342 | * @lkup: switch rule filter lookup type |
4343 | */ |
4344 | static void |
4345 | ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, |
4346 | enum ice_sw_lkup_type lkup) |
4347 | { |
4348 | struct ice_switch_info *sw = hw->switch_info; |
4349 | struct ice_fltr_list_entry *fm_entry; |
4350 | struct list_head remove_list_head; |
4351 | struct list_head *rule_head; |
4352 | struct ice_fltr_list_entry *tmp; |
4353 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
4354 | int status; |
4355 | |
4356 | INIT_LIST_HEAD(list: &remove_list_head); |
4357 | rule_lock = &sw->recp_list[lkup].filt_rule_lock; |
4358 | rule_head = &sw->recp_list[lkup].filt_rules; |
4359 | mutex_lock(rule_lock); |
4360 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, lkup_list_head: rule_head, |
4361 | vsi_list_head: &remove_list_head); |
4362 | mutex_unlock(lock: rule_lock); |
4363 | if (status) |
4364 | goto free_fltr_list; |
4365 | |
4366 | switch (lkup) { |
4367 | case ICE_SW_LKUP_MAC: |
4368 | ice_remove_mac(hw, m_list: &remove_list_head); |
4369 | break; |
4370 | case ICE_SW_LKUP_VLAN: |
4371 | ice_remove_vlan(hw, v_list: &remove_list_head); |
4372 | break; |
4373 | case ICE_SW_LKUP_PROMISC: |
4374 | case ICE_SW_LKUP_PROMISC_VLAN: |
4375 | ice_remove_promisc(hw, recp_id: lkup, v_list: &remove_list_head); |
4376 | break; |
4377 | case ICE_SW_LKUP_MAC_VLAN: |
4378 | case ICE_SW_LKUP_ETHERTYPE: |
4379 | case ICE_SW_LKUP_ETHERTYPE_MAC: |
4380 | case ICE_SW_LKUP_DFLT: |
4381 | case ICE_SW_LKUP_LAST: |
4382 | default: |
4383 | ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n" , lkup); |
4384 | break; |
4385 | } |
4386 | |
4387 | free_fltr_list: |
4388 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { |
4389 | list_del(entry: &fm_entry->list_entry); |
4390 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
4391 | } |
4392 | } |
4393 | |
4394 | /** |
4395 | * ice_remove_vsi_fltr - Remove all filters for a VSI |
4396 | * @hw: pointer to the hardware structure |
4397 | * @vsi_handle: VSI handle to remove filters from |
4398 | */ |
4399 | void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) |
4400 | { |
4401 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_MAC); |
4402 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_MAC_VLAN); |
4403 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_PROMISC); |
4404 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_VLAN); |
4405 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_DFLT); |
4406 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_ETHERTYPE); |
4407 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_ETHERTYPE_MAC); |
4408 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_PROMISC_VLAN); |
4409 | } |
4410 | |
4411 | /** |
4412 | * ice_alloc_res_cntr - allocating resource counter |
4413 | * @hw: pointer to the hardware structure |
4414 | * @type: type of resource |
4415 | * @alloc_shared: if set it is shared else dedicated |
4416 | * @num_items: number of entries requested for FD resource type |
4417 | * @counter_id: counter index returned by AQ call |
4418 | */ |
4419 | int |
4420 | ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4421 | u16 *counter_id) |
4422 | { |
4423 | DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4424 | u16 buf_len = __struct_size(buf); |
4425 | int status; |
4426 | |
4427 | buf->num_elems = cpu_to_le16(num_items); |
4428 | buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) | |
4429 | alloc_shared); |
4430 | |
4431 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, opc: ice_aqc_opc_alloc_res); |
4432 | if (status) |
4433 | return status; |
4434 | |
4435 | *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp); |
4436 | return status; |
4437 | } |
4438 | |
4439 | /** |
4440 | * ice_free_res_cntr - free resource counter |
4441 | * @hw: pointer to the hardware structure |
4442 | * @type: type of resource |
4443 | * @alloc_shared: if set it is shared else dedicated |
4444 | * @num_items: number of entries to be freed for FD resource type |
4445 | * @counter_id: counter ID resource which needs to be freed |
4446 | */ |
4447 | int |
4448 | ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4449 | u16 counter_id) |
4450 | { |
4451 | DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4452 | u16 buf_len = __struct_size(buf); |
4453 | int status; |
4454 | |
4455 | buf->num_elems = cpu_to_le16(num_items); |
4456 | buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) | |
4457 | alloc_shared); |
4458 | buf->elem[0].e.sw_resp = cpu_to_le16(counter_id); |
4459 | |
4460 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, opc: ice_aqc_opc_free_res); |
4461 | if (status) |
4462 | ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n" ); |
4463 | |
4464 | return status; |
4465 | } |
4466 | |
4467 | #define ICE_PROTOCOL_ENTRY(id, ...) { \ |
4468 | .prot_type = id, \ |
4469 | .offs = {__VA_ARGS__}, \ |
4470 | } |
4471 | |
4472 | /** |
4473 | * ice_share_res - set a resource as shared or dedicated |
4474 | * @hw: hw struct of original owner of resource |
4475 | * @type: resource type |
4476 | * @shared: is the resource being set to shared |
4477 | * @res_id: resource id (descriptor) |
4478 | */ |
4479 | int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id) |
4480 | { |
4481 | DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4482 | u16 buf_len = __struct_size(buf); |
4483 | u16 res_type; |
4484 | int status; |
4485 | |
4486 | buf->num_elems = cpu_to_le16(1); |
4487 | res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, type); |
4488 | if (shared) |
4489 | res_type |= ICE_AQC_RES_TYPE_FLAG_SHARED; |
4490 | |
4491 | buf->res_type = cpu_to_le16(res_type); |
4492 | buf->elem[0].e.sw_resp = cpu_to_le16(res_id); |
4493 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, |
4494 | opc: ice_aqc_opc_share_res); |
4495 | if (status) |
4496 | ice_debug(hw, ICE_DBG_SW, "Could not set resource type %u id %u to %s\n" , |
4497 | type, res_id, shared ? "SHARED" : "DEDICATED" ); |
4498 | |
4499 | return status; |
4500 | } |
4501 | |
4502 | /* This is mapping table entry that maps every word within a given protocol |
4503 | * structure to the real byte offset as per the specification of that |
4504 | * protocol header. |
4505 | * for example dst address is 3 words in ethertype header and corresponding |
4506 | * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8 |
4507 | * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a |
4508 | * matching entry describing its field. This needs to be updated if new |
4509 | * structure is added to that union. |
4510 | */ |
4511 | static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { |
4512 | ICE_PROTOCOL_ENTRY(ICE_MAC_OFOS, 0, 2, 4, 6, 8, 10, 12), |
4513 | ICE_PROTOCOL_ENTRY(ICE_MAC_IL, 0, 2, 4, 6, 8, 10, 12), |
4514 | ICE_PROTOCOL_ENTRY(ICE_ETYPE_OL, 0), |
4515 | ICE_PROTOCOL_ENTRY(ICE_ETYPE_IL, 0), |
4516 | ICE_PROTOCOL_ENTRY(ICE_VLAN_OFOS, 2, 0), |
4517 | ICE_PROTOCOL_ENTRY(ICE_IPV4_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), |
4518 | ICE_PROTOCOL_ENTRY(ICE_IPV4_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), |
4519 | ICE_PROTOCOL_ENTRY(ICE_IPV6_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, |
4520 | 20, 22, 24, 26, 28, 30, 32, 34, 36, 38), |
4521 | ICE_PROTOCOL_ENTRY(ICE_IPV6_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, |
4522 | 22, 24, 26, 28, 30, 32, 34, 36, 38), |
4523 | ICE_PROTOCOL_ENTRY(ICE_TCP_IL, 0, 2), |
4524 | ICE_PROTOCOL_ENTRY(ICE_UDP_OF, 0, 2), |
4525 | ICE_PROTOCOL_ENTRY(ICE_UDP_ILOS, 0, 2), |
4526 | ICE_PROTOCOL_ENTRY(ICE_VXLAN, 8, 10, 12, 14), |
4527 | ICE_PROTOCOL_ENTRY(ICE_GENEVE, 8, 10, 12, 14), |
4528 | ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6), |
4529 | ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22), |
4530 | ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14), |
4531 | ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6), |
4532 | ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10), |
4533 | ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0), |
4534 | ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0), |
4535 | ICE_PROTOCOL_ENTRY(ICE_HW_METADATA, |
4536 | ICE_SOURCE_PORT_MDID_OFFSET, |
4537 | ICE_PTYPE_MDID_OFFSET, |
4538 | ICE_PACKET_LENGTH_MDID_OFFSET, |
4539 | ICE_SOURCE_VSI_MDID_OFFSET, |
4540 | ICE_PKT_VLAN_MDID_OFFSET, |
4541 | ICE_PKT_TUNNEL_MDID_OFFSET, |
4542 | ICE_PKT_TCP_MDID_OFFSET, |
4543 | ICE_PKT_ERROR_MDID_OFFSET), |
4544 | }; |
4545 | |
4546 | static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { |
4547 | { ICE_MAC_OFOS, ICE_MAC_OFOS_HW }, |
4548 | { ICE_MAC_IL, ICE_MAC_IL_HW }, |
4549 | { ICE_ETYPE_OL, ICE_ETYPE_OL_HW }, |
4550 | { ICE_ETYPE_IL, ICE_ETYPE_IL_HW }, |
4551 | { ICE_VLAN_OFOS, ICE_VLAN_OL_HW }, |
4552 | { ICE_IPV4_OFOS, ICE_IPV4_OFOS_HW }, |
4553 | { ICE_IPV4_IL, ICE_IPV4_IL_HW }, |
4554 | { ICE_IPV6_OFOS, ICE_IPV6_OFOS_HW }, |
4555 | { ICE_IPV6_IL, ICE_IPV6_IL_HW }, |
4556 | { ICE_TCP_IL, ICE_TCP_IL_HW }, |
4557 | { ICE_UDP_OF, ICE_UDP_OF_HW }, |
4558 | { ICE_UDP_ILOS, ICE_UDP_ILOS_HW }, |
4559 | { ICE_VXLAN, ICE_UDP_OF_HW }, |
4560 | { ICE_GENEVE, ICE_UDP_OF_HW }, |
4561 | { ICE_NVGRE, ICE_GRE_OF_HW }, |
4562 | { ICE_GTP, ICE_UDP_OF_HW }, |
4563 | { ICE_GTP_NO_PAY, ICE_UDP_ILOS_HW }, |
4564 | { ICE_PPPOE, ICE_PPPOE_HW }, |
4565 | { ICE_L2TPV3, ICE_L2TPV3_HW }, |
4566 | { ICE_VLAN_EX, ICE_VLAN_OF_HW }, |
4567 | { ICE_VLAN_IN, ICE_VLAN_OL_HW }, |
4568 | { ICE_HW_METADATA, ICE_META_DATA_ID_HW }, |
4569 | }; |
4570 | |
4571 | /** |
4572 | * ice_find_recp - find a recipe |
4573 | * @hw: pointer to the hardware structure |
4574 | * @lkup_exts: extension sequence to match |
4575 | * @rinfo: information regarding the rule e.g. priority and action info |
4576 | * |
4577 | * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. |
4578 | */ |
4579 | static u16 |
4580 | ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, |
4581 | const struct ice_adv_rule_info *rinfo) |
4582 | { |
4583 | bool refresh_required = true; |
4584 | struct ice_sw_recipe *recp; |
4585 | u8 i; |
4586 | |
4587 | /* Walk through existing recipes to find a match */ |
4588 | recp = hw->switch_info->recp_list; |
4589 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
4590 | /* If recipe was not created for this ID, in SW bookkeeping, |
4591 | * check if FW has an entry for this recipe. If the FW has an |
4592 | * entry update it in our SW bookkeeping and continue with the |
4593 | * matching. |
4594 | */ |
4595 | if (!recp[i].recp_created) |
4596 | if (ice_get_recp_frm_fw(hw, |
4597 | recps: hw->switch_info->recp_list, rid: i, |
4598 | refresh_required: &refresh_required)) |
4599 | continue; |
4600 | |
4601 | /* Skip inverse action recipes */ |
4602 | if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & |
4603 | ICE_AQ_RECIPE_ACT_INV_ACT) |
4604 | continue; |
4605 | |
4606 | /* if number of words we are looking for match */ |
4607 | if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) { |
4608 | struct ice_fv_word *ar = recp[i].lkup_exts.fv_words; |
4609 | struct ice_fv_word *be = lkup_exts->fv_words; |
4610 | u16 *cr = recp[i].lkup_exts.field_mask; |
4611 | u16 *de = lkup_exts->field_mask; |
4612 | bool found = true; |
4613 | u8 pe, qr; |
4614 | |
4615 | /* ar, cr, and qr are related to the recipe words, while |
4616 | * be, de, and pe are related to the lookup words |
4617 | */ |
4618 | for (pe = 0; pe < lkup_exts->n_val_words; pe++) { |
4619 | for (qr = 0; qr < recp[i].lkup_exts.n_val_words; |
4620 | qr++) { |
4621 | if (ar[qr].off == be[pe].off && |
4622 | ar[qr].prot_id == be[pe].prot_id && |
4623 | cr[qr] == de[pe]) |
4624 | /* Found the "pe"th word in the |
4625 | * given recipe |
4626 | */ |
4627 | break; |
4628 | } |
4629 | /* After walking through all the words in the |
4630 | * "i"th recipe if "p"th word was not found then |
4631 | * this recipe is not what we are looking for. |
4632 | * So break out from this loop and try the next |
4633 | * recipe |
4634 | */ |
4635 | if (qr >= recp[i].lkup_exts.n_val_words) { |
4636 | found = false; |
4637 | break; |
4638 | } |
4639 | } |
4640 | /* If for "i"th recipe the found was never set to false |
4641 | * then it means we found our match |
4642 | * Also tun type and *_pass_l2 of recipe needs to be |
4643 | * checked |
4644 | */ |
4645 | if (found && recp[i].tun_type == rinfo->tun_type && |
4646 | recp[i].need_pass_l2 == rinfo->need_pass_l2 && |
4647 | recp[i].allow_pass_l2 == rinfo->allow_pass_l2) |
4648 | return i; /* Return the recipe ID */ |
4649 | } |
4650 | } |
4651 | return ICE_MAX_NUM_RECIPES; |
4652 | } |
4653 | |
4654 | /** |
4655 | * ice_change_proto_id_to_dvm - change proto id in prot_id_tbl |
4656 | * |
4657 | * As protocol id for outer vlan is different in dvm and svm, if dvm is |
4658 | * supported protocol array record for outer vlan has to be modified to |
4659 | * reflect the value proper for DVM. |
4660 | */ |
4661 | void ice_change_proto_id_to_dvm(void) |
4662 | { |
4663 | u8 i; |
4664 | |
4665 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) |
4666 | if (ice_prot_id_tbl[i].type == ICE_VLAN_OFOS && |
4667 | ice_prot_id_tbl[i].protocol_id != ICE_VLAN_OF_HW) |
4668 | ice_prot_id_tbl[i].protocol_id = ICE_VLAN_OF_HW; |
4669 | } |
4670 | |
4671 | /** |
4672 | * ice_prot_type_to_id - get protocol ID from protocol type |
4673 | * @type: protocol type |
4674 | * @id: pointer to variable that will receive the ID |
4675 | * |
4676 | * Returns true if found, false otherwise |
4677 | */ |
4678 | static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id) |
4679 | { |
4680 | u8 i; |
4681 | |
4682 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) |
4683 | if (ice_prot_id_tbl[i].type == type) { |
4684 | *id = ice_prot_id_tbl[i].protocol_id; |
4685 | return true; |
4686 | } |
4687 | return false; |
4688 | } |
4689 | |
4690 | /** |
4691 | * ice_fill_valid_words - count valid words |
4692 | * @rule: advanced rule with lookup information |
4693 | * @lkup_exts: byte offset extractions of the words that are valid |
4694 | * |
4695 | * calculate valid words in a lookup rule using mask value |
4696 | */ |
4697 | static u8 |
4698 | ice_fill_valid_words(struct ice_adv_lkup_elem *rule, |
4699 | struct ice_prot_lkup_ext *lkup_exts) |
4700 | { |
4701 | u8 j, word, prot_id, ret_val; |
4702 | |
4703 | if (!ice_prot_type_to_id(type: rule->type, id: &prot_id)) |
4704 | return 0; |
4705 | |
4706 | word = lkup_exts->n_val_words; |
4707 | |
4708 | for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++) |
4709 | if (((u16 *)&rule->m_u)[j] && |
4710 | rule->type < ARRAY_SIZE(ice_prot_ext)) { |
4711 | /* No more space to accommodate */ |
4712 | if (word >= ICE_MAX_CHAIN_WORDS) |
4713 | return 0; |
4714 | lkup_exts->fv_words[word].off = |
4715 | ice_prot_ext[rule->type].offs[j]; |
4716 | lkup_exts->fv_words[word].prot_id = |
4717 | ice_prot_id_tbl[rule->type].protocol_id; |
4718 | lkup_exts->field_mask[word] = |
4719 | be16_to_cpu(((__force __be16 *)&rule->m_u)[j]); |
4720 | word++; |
4721 | } |
4722 | |
4723 | ret_val = word - lkup_exts->n_val_words; |
4724 | lkup_exts->n_val_words = word; |
4725 | |
4726 | return ret_val; |
4727 | } |
4728 | |
4729 | /** |
4730 | * ice_create_first_fit_recp_def - Create a recipe grouping |
4731 | * @hw: pointer to the hardware structure |
4732 | * @lkup_exts: an array of protocol header extractions |
4733 | * @rg_list: pointer to a list that stores new recipe groups |
4734 | * @recp_cnt: pointer to a variable that stores returned number of recipe groups |
4735 | * |
4736 | * Using first fit algorithm, take all the words that are still not done |
4737 | * and start grouping them in 4-word groups. Each group makes up one |
4738 | * recipe. |
4739 | */ |
4740 | static int |
4741 | ice_create_first_fit_recp_def(struct ice_hw *hw, |
4742 | struct ice_prot_lkup_ext *lkup_exts, |
4743 | struct list_head *rg_list, |
4744 | u8 *recp_cnt) |
4745 | { |
4746 | struct ice_pref_recipe_group *grp = NULL; |
4747 | u8 j; |
4748 | |
4749 | *recp_cnt = 0; |
4750 | |
4751 | /* Walk through every word in the rule to check if it is not done. If so |
4752 | * then this word needs to be part of a new recipe. |
4753 | */ |
4754 | for (j = 0; j < lkup_exts->n_val_words; j++) |
4755 | if (!test_bit(j, lkup_exts->done)) { |
4756 | if (!grp || |
4757 | grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) { |
4758 | struct ice_recp_grp_entry *entry; |
4759 | |
4760 | entry = devm_kzalloc(dev: ice_hw_to_dev(hw), |
4761 | size: sizeof(*entry), |
4762 | GFP_KERNEL); |
4763 | if (!entry) |
4764 | return -ENOMEM; |
4765 | list_add(new: &entry->l_entry, head: rg_list); |
4766 | grp = &entry->r_group; |
4767 | (*recp_cnt)++; |
4768 | } |
4769 | |
4770 | grp->pairs[grp->n_val_pairs].prot_id = |
4771 | lkup_exts->fv_words[j].prot_id; |
4772 | grp->pairs[grp->n_val_pairs].off = |
4773 | lkup_exts->fv_words[j].off; |
4774 | grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j]; |
4775 | grp->n_val_pairs++; |
4776 | } |
4777 | |
4778 | return 0; |
4779 | } |
4780 | |
4781 | /** |
4782 | * ice_fill_fv_word_index - fill in the field vector indices for a recipe group |
4783 | * @hw: pointer to the hardware structure |
4784 | * @fv_list: field vector with the extraction sequence information |
4785 | * @rg_list: recipe groupings with protocol-offset pairs |
4786 | * |
4787 | * Helper function to fill in the field vector indices for protocol-offset |
4788 | * pairs. These indexes are then ultimately programmed into a recipe. |
4789 | */ |
4790 | static int |
4791 | ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list, |
4792 | struct list_head *rg_list) |
4793 | { |
4794 | struct ice_sw_fv_list_entry *fv; |
4795 | struct ice_recp_grp_entry *rg; |
4796 | struct ice_fv_word *fv_ext; |
4797 | |
4798 | if (list_empty(head: fv_list)) |
4799 | return 0; |
4800 | |
4801 | fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry, |
4802 | list_entry); |
4803 | fv_ext = fv->fv_ptr->ew; |
4804 | |
4805 | list_for_each_entry(rg, rg_list, l_entry) { |
4806 | u8 i; |
4807 | |
4808 | for (i = 0; i < rg->r_group.n_val_pairs; i++) { |
4809 | struct ice_fv_word *pr; |
4810 | bool found = false; |
4811 | u16 mask; |
4812 | u8 j; |
4813 | |
4814 | pr = &rg->r_group.pairs[i]; |
4815 | mask = rg->r_group.mask[i]; |
4816 | |
4817 | for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) |
4818 | if (fv_ext[j].prot_id == pr->prot_id && |
4819 | fv_ext[j].off == pr->off) { |
4820 | found = true; |
4821 | |
4822 | /* Store index of field vector */ |
4823 | rg->fv_idx[i] = j; |
4824 | rg->fv_mask[i] = mask; |
4825 | break; |
4826 | } |
4827 | |
4828 | /* Protocol/offset could not be found, caller gave an |
4829 | * invalid pair |
4830 | */ |
4831 | if (!found) |
4832 | return -EINVAL; |
4833 | } |
4834 | } |
4835 | |
4836 | return 0; |
4837 | } |
4838 | |
4839 | /** |
4840 | * ice_find_free_recp_res_idx - find free result indexes for recipe |
4841 | * @hw: pointer to hardware structure |
4842 | * @profiles: bitmap of profiles that will be associated with the new recipe |
4843 | * @free_idx: pointer to variable to receive the free index bitmap |
4844 | * |
4845 | * The algorithm used here is: |
4846 | * 1. When creating a new recipe, create a set P which contains all |
4847 | * Profiles that will be associated with our new recipe |
4848 | * |
4849 | * 2. For each Profile p in set P: |
4850 | * a. Add all recipes associated with Profile p into set R |
4851 | * b. Optional : PossibleIndexes &= profile[p].possibleIndexes |
4852 | * [initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF] |
4853 | * i. Or just assume they all have the same possible indexes: |
4854 | * 44, 45, 46, 47 |
4855 | * i.e., PossibleIndexes = 0x0000F00000000000 |
4856 | * |
4857 | * 3. For each Recipe r in set R: |
4858 | * a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes |
4859 | * b. FreeIndexes = UsedIndexes ^ PossibleIndexes |
4860 | * |
4861 | * FreeIndexes will contain the bits indicating the indexes free for use, |
4862 | * then the code needs to update the recipe[r].used_result_idx_bits to |
4863 | * indicate which indexes were selected for use by this recipe. |
4864 | */ |
4865 | static u16 |
4866 | ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, |
4867 | unsigned long *free_idx) |
4868 | { |
4869 | DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS); |
4870 | DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES); |
4871 | DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS); |
4872 | u16 bit; |
4873 | |
4874 | bitmap_zero(dst: recipes, ICE_MAX_NUM_RECIPES); |
4875 | bitmap_zero(dst: used_idx, ICE_MAX_FV_WORDS); |
4876 | |
4877 | bitmap_fill(dst: possible_idx, ICE_MAX_FV_WORDS); |
4878 | |
4879 | /* For each profile we are going to associate the recipe with, add the |
4880 | * recipes that are associated with that profile. This will give us |
4881 | * the set of recipes that our recipe may collide with. Also, determine |
4882 | * what possible result indexes are usable given this set of profiles. |
4883 | */ |
4884 | for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) { |
4885 | bitmap_or(dst: recipes, src1: recipes, src2: profile_to_recipe[bit], |
4886 | ICE_MAX_NUM_RECIPES); |
4887 | bitmap_and(dst: possible_idx, src1: possible_idx, |
4888 | src2: hw->switch_info->prof_res_bm[bit], |
4889 | ICE_MAX_FV_WORDS); |
4890 | } |
4891 | |
4892 | /* For each recipe that our new recipe may collide with, determine |
4893 | * which indexes have been used. |
4894 | */ |
4895 | for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES) |
4896 | bitmap_or(dst: used_idx, src1: used_idx, |
4897 | src2: hw->switch_info->recp_list[bit].res_idxs, |
4898 | ICE_MAX_FV_WORDS); |
4899 | |
4900 | bitmap_xor(dst: free_idx, src1: used_idx, src2: possible_idx, ICE_MAX_FV_WORDS); |
4901 | |
4902 | /* return number of free indexes */ |
4903 | return (u16)bitmap_weight(src: free_idx, ICE_MAX_FV_WORDS); |
4904 | } |
4905 | |
4906 | /** |
4907 | * ice_add_sw_recipe - function to call AQ calls to create switch recipe |
4908 | * @hw: pointer to hardware structure |
4909 | * @rm: recipe management list entry |
4910 | * @profiles: bitmap of profiles that will be associated. |
4911 | */ |
4912 | static int |
4913 | ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm, |
4914 | unsigned long *profiles) |
4915 | { |
4916 | DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS); |
4917 | struct ice_aqc_recipe_content *content; |
4918 | struct ice_aqc_recipe_data_elem *tmp; |
4919 | struct ice_aqc_recipe_data_elem *buf; |
4920 | struct ice_recp_grp_entry *entry; |
4921 | u16 free_res_idx; |
4922 | u16 recipe_count; |
4923 | u8 chain_idx; |
4924 | u8 recps = 0; |
4925 | int status; |
4926 | |
4927 | /* When more than one recipe are required, another recipe is needed to |
4928 | * chain them together. Matching a tunnel metadata ID takes up one of |
4929 | * the match fields in the chaining recipe reducing the number of |
4930 | * chained recipes by one. |
4931 | */ |
4932 | /* check number of free result indices */ |
4933 | bitmap_zero(dst: result_idx_bm, ICE_MAX_FV_WORDS); |
4934 | free_res_idx = ice_find_free_recp_res_idx(hw, profiles, free_idx: result_idx_bm); |
4935 | |
4936 | ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n" , |
4937 | free_res_idx, rm->n_grp_count); |
4938 | |
4939 | if (rm->n_grp_count > 1) { |
4940 | if (rm->n_grp_count > free_res_idx) |
4941 | return -ENOSPC; |
4942 | |
4943 | rm->n_grp_count++; |
4944 | } |
4945 | |
4946 | if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE) |
4947 | return -ENOSPC; |
4948 | |
4949 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, size: sizeof(*tmp), GFP_KERNEL); |
4950 | if (!tmp) |
4951 | return -ENOMEM; |
4952 | |
4953 | buf = devm_kcalloc(dev: ice_hw_to_dev(hw), n: rm->n_grp_count, size: sizeof(*buf), |
4954 | GFP_KERNEL); |
4955 | if (!buf) { |
4956 | status = -ENOMEM; |
4957 | goto err_mem; |
4958 | } |
4959 | |
4960 | bitmap_zero(dst: rm->r_bitmap, ICE_MAX_NUM_RECIPES); |
4961 | recipe_count = ICE_MAX_NUM_RECIPES; |
4962 | status = ice_aq_get_recipe(hw, s_recipe_list: tmp, num_recipes: &recipe_count, recipe_root: ICE_SW_LKUP_MAC, |
4963 | NULL); |
4964 | if (status || recipe_count == 0) |
4965 | goto err_unroll; |
4966 | |
4967 | /* Allocate the recipe resources, and configure them according to the |
4968 | * match fields from protocol headers and extracted field vectors. |
4969 | */ |
4970 | chain_idx = find_first_bit(addr: result_idx_bm, ICE_MAX_FV_WORDS); |
4971 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
4972 | u8 i; |
4973 | |
4974 | status = ice_alloc_recipe(hw, rid: &entry->rid); |
4975 | if (status) |
4976 | goto err_unroll; |
4977 | |
4978 | content = &buf[recps].content; |
4979 | |
4980 | /* Clear the result index of the located recipe, as this will be |
4981 | * updated, if needed, later in the recipe creation process. |
4982 | */ |
4983 | tmp[0].content.result_indx = 0; |
4984 | |
4985 | buf[recps] = tmp[0]; |
4986 | buf[recps].recipe_indx = (u8)entry->rid; |
4987 | /* if the recipe is a non-root recipe RID should be programmed |
4988 | * as 0 for the rules to be applied correctly. |
4989 | */ |
4990 | content->rid = 0; |
4991 | memset(&content->lkup_indx, 0, |
4992 | sizeof(content->lkup_indx)); |
4993 | |
4994 | /* All recipes use look-up index 0 to match switch ID. */ |
4995 | content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; |
4996 | content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); |
4997 | /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask |
4998 | * to be 0 |
4999 | */ |
5000 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { |
5001 | content->lkup_indx[i] = 0x80; |
5002 | content->mask[i] = 0; |
5003 | } |
5004 | |
5005 | for (i = 0; i < entry->r_group.n_val_pairs; i++) { |
5006 | content->lkup_indx[i + 1] = entry->fv_idx[i]; |
5007 | content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]); |
5008 | } |
5009 | |
5010 | if (rm->n_grp_count > 1) { |
5011 | /* Checks to see if there really is a valid result index |
5012 | * that can be used. |
5013 | */ |
5014 | if (chain_idx >= ICE_MAX_FV_WORDS) { |
5015 | ice_debug(hw, ICE_DBG_SW, "No chain index available\n" ); |
5016 | status = -ENOSPC; |
5017 | goto err_unroll; |
5018 | } |
5019 | |
5020 | entry->chain_idx = chain_idx; |
5021 | content->result_indx = |
5022 | ICE_AQ_RECIPE_RESULT_EN | |
5023 | FIELD_PREP(ICE_AQ_RECIPE_RESULT_DATA_M, |
5024 | chain_idx); |
5025 | clear_bit(nr: chain_idx, addr: result_idx_bm); |
5026 | chain_idx = find_first_bit(addr: result_idx_bm, |
5027 | ICE_MAX_FV_WORDS); |
5028 | } |
5029 | |
5030 | /* fill recipe dependencies */ |
5031 | bitmap_zero(dst: (unsigned long *)buf[recps].recipe_bitmap, |
5032 | ICE_MAX_NUM_RECIPES); |
5033 | set_bit(nr: buf[recps].recipe_indx, |
5034 | addr: (unsigned long *)buf[recps].recipe_bitmap); |
5035 | content->act_ctrl_fwd_priority = rm->priority; |
5036 | |
5037 | if (rm->need_pass_l2) |
5038 | content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2; |
5039 | |
5040 | if (rm->allow_pass_l2) |
5041 | content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2; |
5042 | recps++; |
5043 | } |
5044 | |
5045 | if (rm->n_grp_count == 1) { |
5046 | rm->root_rid = buf[0].recipe_indx; |
5047 | set_bit(nr: buf[0].recipe_indx, addr: rm->r_bitmap); |
5048 | buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT; |
5049 | if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) { |
5050 | memcpy(buf[0].recipe_bitmap, rm->r_bitmap, |
5051 | sizeof(buf[0].recipe_bitmap)); |
5052 | } else { |
5053 | status = -EINVAL; |
5054 | goto err_unroll; |
5055 | } |
5056 | /* Applicable only for ROOT_RECIPE, set the fwd_priority for |
5057 | * the recipe which is getting created if specified |
5058 | * by user. Usually any advanced switch filter, which results |
5059 | * into new extraction sequence, ended up creating a new recipe |
5060 | * of type ROOT and usually recipes are associated with profiles |
5061 | * Switch rule referreing newly created recipe, needs to have |
5062 | * either/or 'fwd' or 'join' priority, otherwise switch rule |
5063 | * evaluation will not happen correctly. In other words, if |
5064 | * switch rule to be evaluated on priority basis, then recipe |
5065 | * needs to have priority, otherwise it will be evaluated last. |
5066 | */ |
5067 | buf[0].content.act_ctrl_fwd_priority = rm->priority; |
5068 | } else { |
5069 | struct ice_recp_grp_entry *last_chain_entry; |
5070 | u16 rid, i; |
5071 | |
5072 | /* Allocate the last recipe that will chain the outcomes of the |
5073 | * other recipes together |
5074 | */ |
5075 | status = ice_alloc_recipe(hw, rid: &rid); |
5076 | if (status) |
5077 | goto err_unroll; |
5078 | |
5079 | content = &buf[recps].content; |
5080 | |
5081 | buf[recps].recipe_indx = (u8)rid; |
5082 | content->rid = (u8)rid; |
5083 | content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT; |
5084 | /* the new entry created should also be part of rg_list to |
5085 | * make sure we have complete recipe |
5086 | */ |
5087 | last_chain_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), |
5088 | size: sizeof(*last_chain_entry), |
5089 | GFP_KERNEL); |
5090 | if (!last_chain_entry) { |
5091 | status = -ENOMEM; |
5092 | goto err_unroll; |
5093 | } |
5094 | last_chain_entry->rid = rid; |
5095 | memset(&content->lkup_indx, 0, sizeof(content->lkup_indx)); |
5096 | /* All recipes use look-up index 0 to match switch ID. */ |
5097 | content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; |
5098 | content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); |
5099 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { |
5100 | content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE; |
5101 | content->mask[i] = 0; |
5102 | } |
5103 | |
5104 | i = 1; |
5105 | /* update r_bitmap with the recp that is used for chaining */ |
5106 | set_bit(nr: rid, addr: rm->r_bitmap); |
5107 | /* this is the recipe that chains all the other recipes so it |
5108 | * should not have a chaining ID to indicate the same |
5109 | */ |
5110 | last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND; |
5111 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
5112 | last_chain_entry->fv_idx[i] = entry->chain_idx; |
5113 | content->lkup_indx[i] = entry->chain_idx; |
5114 | content->mask[i++] = cpu_to_le16(0xFFFF); |
5115 | set_bit(nr: entry->rid, addr: rm->r_bitmap); |
5116 | } |
5117 | list_add(new: &last_chain_entry->l_entry, head: &rm->rg_list); |
5118 | if (sizeof(buf[recps].recipe_bitmap) >= |
5119 | sizeof(rm->r_bitmap)) { |
5120 | memcpy(buf[recps].recipe_bitmap, rm->r_bitmap, |
5121 | sizeof(buf[recps].recipe_bitmap)); |
5122 | } else { |
5123 | status = -EINVAL; |
5124 | goto err_unroll; |
5125 | } |
5126 | content->act_ctrl_fwd_priority = rm->priority; |
5127 | |
5128 | recps++; |
5129 | rm->root_rid = (u8)rid; |
5130 | } |
5131 | status = ice_acquire_change_lock(hw, access: ICE_RES_WRITE); |
5132 | if (status) |
5133 | goto err_unroll; |
5134 | |
5135 | status = ice_aq_add_recipe(hw, s_recipe_list: buf, num_recipes: rm->n_grp_count, NULL); |
5136 | ice_release_change_lock(hw); |
5137 | if (status) |
5138 | goto err_unroll; |
5139 | |
5140 | /* Every recipe that just got created add it to the recipe |
5141 | * book keeping list |
5142 | */ |
5143 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
5144 | struct ice_switch_info *sw = hw->switch_info; |
5145 | bool is_root, idx_found = false; |
5146 | struct ice_sw_recipe *recp; |
5147 | u16 idx, buf_idx = 0; |
5148 | |
5149 | /* find buffer index for copying some data */ |
5150 | for (idx = 0; idx < rm->n_grp_count; idx++) |
5151 | if (buf[idx].recipe_indx == entry->rid) { |
5152 | buf_idx = idx; |
5153 | idx_found = true; |
5154 | } |
5155 | |
5156 | if (!idx_found) { |
5157 | status = -EIO; |
5158 | goto err_unroll; |
5159 | } |
5160 | |
5161 | recp = &sw->recp_list[entry->rid]; |
5162 | is_root = (rm->root_rid == entry->rid); |
5163 | recp->is_root = is_root; |
5164 | |
5165 | recp->root_rid = entry->rid; |
5166 | recp->big_recp = (is_root && rm->n_grp_count > 1); |
5167 | |
5168 | memcpy(&recp->ext_words, entry->r_group.pairs, |
5169 | entry->r_group.n_val_pairs * sizeof(struct ice_fv_word)); |
5170 | |
5171 | memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap, |
5172 | sizeof(recp->r_bitmap)); |
5173 | |
5174 | /* Copy non-result fv index values and masks to recipe. This |
5175 | * call will also update the result recipe bitmask. |
5176 | */ |
5177 | ice_collect_result_idx(buf: &buf[buf_idx], recp); |
5178 | |
5179 | /* for non-root recipes, also copy to the root, this allows |
5180 | * easier matching of a complete chained recipe |
5181 | */ |
5182 | if (!is_root) |
5183 | ice_collect_result_idx(buf: &buf[buf_idx], |
5184 | recp: &sw->recp_list[rm->root_rid]); |
5185 | |
5186 | recp->n_ext_words = entry->r_group.n_val_pairs; |
5187 | recp->chain_idx = entry->chain_idx; |
5188 | recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority; |
5189 | recp->n_grp_count = rm->n_grp_count; |
5190 | recp->tun_type = rm->tun_type; |
5191 | recp->need_pass_l2 = rm->need_pass_l2; |
5192 | recp->allow_pass_l2 = rm->allow_pass_l2; |
5193 | recp->recp_created = true; |
5194 | } |
5195 | rm->root_buf = buf; |
5196 | kfree(objp: tmp); |
5197 | return status; |
5198 | |
5199 | err_unroll: |
5200 | err_mem: |
5201 | kfree(objp: tmp); |
5202 | devm_kfree(dev: ice_hw_to_dev(hw), p: buf); |
5203 | return status; |
5204 | } |
5205 | |
5206 | /** |
5207 | * ice_create_recipe_group - creates recipe group |
5208 | * @hw: pointer to hardware structure |
5209 | * @rm: recipe management list entry |
5210 | * @lkup_exts: lookup elements |
5211 | */ |
5212 | static int |
5213 | ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, |
5214 | struct ice_prot_lkup_ext *lkup_exts) |
5215 | { |
5216 | u8 recp_count = 0; |
5217 | int status; |
5218 | |
5219 | rm->n_grp_count = 0; |
5220 | |
5221 | /* Create recipes for words that are marked not done by packing them |
5222 | * as best fit. |
5223 | */ |
5224 | status = ice_create_first_fit_recp_def(hw, lkup_exts, |
5225 | rg_list: &rm->rg_list, recp_cnt: &recp_count); |
5226 | if (!status) { |
5227 | rm->n_grp_count += recp_count; |
5228 | rm->n_ext_words = lkup_exts->n_val_words; |
5229 | memcpy(&rm->ext_words, lkup_exts->fv_words, |
5230 | sizeof(rm->ext_words)); |
5231 | memcpy(rm->word_masks, lkup_exts->field_mask, |
5232 | sizeof(rm->word_masks)); |
5233 | } |
5234 | |
5235 | return status; |
5236 | } |
5237 | |
5238 | /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule |
5239 | * @hw: pointer to hardware structure |
5240 | * @rinfo: other information regarding the rule e.g. priority and action info |
5241 | * @bm: pointer to memory for returning the bitmap of field vectors |
5242 | */ |
5243 | static void |
5244 | ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo, |
5245 | unsigned long *bm) |
5246 | { |
5247 | enum ice_prof_type prof_type; |
5248 | |
5249 | bitmap_zero(dst: bm, ICE_MAX_NUM_PROFILES); |
5250 | |
5251 | switch (rinfo->tun_type) { |
5252 | case ICE_NON_TUN: |
5253 | prof_type = ICE_PROF_NON_TUN; |
5254 | break; |
5255 | case ICE_ALL_TUNNELS: |
5256 | prof_type = ICE_PROF_TUN_ALL; |
5257 | break; |
5258 | case ICE_SW_TUN_GENEVE: |
5259 | case ICE_SW_TUN_VXLAN: |
5260 | prof_type = ICE_PROF_TUN_UDP; |
5261 | break; |
5262 | case ICE_SW_TUN_NVGRE: |
5263 | prof_type = ICE_PROF_TUN_GRE; |
5264 | break; |
5265 | case ICE_SW_TUN_GTPU: |
5266 | prof_type = ICE_PROF_TUN_GTPU; |
5267 | break; |
5268 | case ICE_SW_TUN_GTPC: |
5269 | prof_type = ICE_PROF_TUN_GTPC; |
5270 | break; |
5271 | case ICE_SW_TUN_AND_NON_TUN: |
5272 | default: |
5273 | prof_type = ICE_PROF_ALL; |
5274 | break; |
5275 | } |
5276 | |
5277 | ice_get_sw_fv_bitmap(hw, type: prof_type, bm); |
5278 | } |
5279 | |
5280 | /** |
5281 | * ice_add_adv_recipe - Add an advanced recipe that is not part of the default |
5282 | * @hw: pointer to hardware structure |
5283 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5284 | * structure per protocol header |
5285 | * @lkups_cnt: number of protocols |
5286 | * @rinfo: other information regarding the rule e.g. priority and action info |
5287 | * @rid: return the recipe ID of the recipe created |
5288 | */ |
5289 | static int |
5290 | ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
5291 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid) |
5292 | { |
5293 | DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES); |
5294 | DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES); |
5295 | struct ice_prot_lkup_ext *lkup_exts; |
5296 | struct ice_recp_grp_entry *r_entry; |
5297 | struct ice_sw_fv_list_entry *fvit; |
5298 | struct ice_recp_grp_entry *r_tmp; |
5299 | struct ice_sw_fv_list_entry *tmp; |
5300 | struct ice_sw_recipe *rm; |
5301 | int status = 0; |
5302 | u8 i; |
5303 | |
5304 | if (!lkups_cnt) |
5305 | return -EINVAL; |
5306 | |
5307 | lkup_exts = kzalloc(size: sizeof(*lkup_exts), GFP_KERNEL); |
5308 | if (!lkup_exts) |
5309 | return -ENOMEM; |
5310 | |
5311 | /* Determine the number of words to be matched and if it exceeds a |
5312 | * recipe's restrictions |
5313 | */ |
5314 | for (i = 0; i < lkups_cnt; i++) { |
5315 | u16 count; |
5316 | |
5317 | if (lkups[i].type >= ICE_PROTOCOL_LAST) { |
5318 | status = -EIO; |
5319 | goto err_free_lkup_exts; |
5320 | } |
5321 | |
5322 | count = ice_fill_valid_words(rule: &lkups[i], lkup_exts); |
5323 | if (!count) { |
5324 | status = -EIO; |
5325 | goto err_free_lkup_exts; |
5326 | } |
5327 | } |
5328 | |
5329 | rm = kzalloc(size: sizeof(*rm), GFP_KERNEL); |
5330 | if (!rm) { |
5331 | status = -ENOMEM; |
5332 | goto err_free_lkup_exts; |
5333 | } |
5334 | |
5335 | /* Get field vectors that contain fields extracted from all the protocol |
5336 | * headers being programmed. |
5337 | */ |
5338 | INIT_LIST_HEAD(list: &rm->fv_list); |
5339 | INIT_LIST_HEAD(list: &rm->rg_list); |
5340 | |
5341 | /* Get bitmap of field vectors (profiles) that are compatible with the |
5342 | * rule request; only these will be searched in the subsequent call to |
5343 | * ice_get_sw_fv_list. |
5344 | */ |
5345 | ice_get_compat_fv_bitmap(hw, rinfo, bm: fv_bitmap); |
5346 | |
5347 | status = ice_get_sw_fv_list(hw, lkups: lkup_exts, bm: fv_bitmap, fv_list: &rm->fv_list); |
5348 | if (status) |
5349 | goto err_unroll; |
5350 | |
5351 | /* Group match words into recipes using preferred recipe grouping |
5352 | * criteria. |
5353 | */ |
5354 | status = ice_create_recipe_group(hw, rm, lkup_exts); |
5355 | if (status) |
5356 | goto err_unroll; |
5357 | |
5358 | /* set the recipe priority if specified */ |
5359 | rm->priority = (u8)rinfo->priority; |
5360 | |
5361 | rm->need_pass_l2 = rinfo->need_pass_l2; |
5362 | rm->allow_pass_l2 = rinfo->allow_pass_l2; |
5363 | |
5364 | /* Find offsets from the field vector. Pick the first one for all the |
5365 | * recipes. |
5366 | */ |
5367 | status = ice_fill_fv_word_index(hw, fv_list: &rm->fv_list, rg_list: &rm->rg_list); |
5368 | if (status) |
5369 | goto err_unroll; |
5370 | |
5371 | /* get bitmap of all profiles the recipe will be associated with */ |
5372 | bitmap_zero(dst: profiles, ICE_MAX_NUM_PROFILES); |
5373 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { |
5374 | ice_debug(hw, ICE_DBG_SW, "profile: %d\n" , fvit->profile_id); |
5375 | set_bit(nr: (u16)fvit->profile_id, addr: profiles); |
5376 | } |
5377 | |
5378 | /* Look for a recipe which matches our requested fv / mask list */ |
5379 | *rid = ice_find_recp(hw, lkup_exts, rinfo); |
5380 | if (*rid < ICE_MAX_NUM_RECIPES) |
5381 | /* Success if found a recipe that match the existing criteria */ |
5382 | goto err_unroll; |
5383 | |
5384 | rm->tun_type = rinfo->tun_type; |
5385 | /* Recipe we need does not exist, add a recipe */ |
5386 | status = ice_add_sw_recipe(hw, rm, profiles); |
5387 | if (status) |
5388 | goto err_unroll; |
5389 | |
5390 | /* Associate all the recipes created with all the profiles in the |
5391 | * common field vector. |
5392 | */ |
5393 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { |
5394 | DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); |
5395 | u64 recp_assoc; |
5396 | u16 j; |
5397 | |
5398 | status = ice_aq_get_recipe_to_profile(hw, profile_id: fvit->profile_id, |
5399 | r_assoc: &recp_assoc, NULL); |
5400 | if (status) |
5401 | goto err_unroll; |
5402 | |
5403 | bitmap_from_arr64(r_bitmap, &recp_assoc, ICE_MAX_NUM_RECIPES); |
5404 | bitmap_or(dst: r_bitmap, src1: r_bitmap, src2: rm->r_bitmap, |
5405 | ICE_MAX_NUM_RECIPES); |
5406 | status = ice_acquire_change_lock(hw, access: ICE_RES_WRITE); |
5407 | if (status) |
5408 | goto err_unroll; |
5409 | |
5410 | bitmap_to_arr64(&recp_assoc, r_bitmap, ICE_MAX_NUM_RECIPES); |
5411 | status = ice_aq_map_recipe_to_profile(hw, profile_id: fvit->profile_id, |
5412 | r_assoc: recp_assoc, NULL); |
5413 | ice_release_change_lock(hw); |
5414 | |
5415 | if (status) |
5416 | goto err_unroll; |
5417 | |
5418 | /* Update profile to recipe bitmap array */ |
5419 | bitmap_copy(dst: profile_to_recipe[fvit->profile_id], src: r_bitmap, |
5420 | ICE_MAX_NUM_RECIPES); |
5421 | |
5422 | /* Update recipe to profile bitmap array */ |
5423 | for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES) |
5424 | set_bit(nr: (u16)fvit->profile_id, addr: recipe_to_profile[j]); |
5425 | } |
5426 | |
5427 | *rid = rm->root_rid; |
5428 | memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, |
5429 | sizeof(*lkup_exts)); |
5430 | err_unroll: |
5431 | list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) { |
5432 | list_del(entry: &r_entry->l_entry); |
5433 | devm_kfree(dev: ice_hw_to_dev(hw), p: r_entry); |
5434 | } |
5435 | |
5436 | list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) { |
5437 | list_del(entry: &fvit->list_entry); |
5438 | devm_kfree(dev: ice_hw_to_dev(hw), p: fvit); |
5439 | } |
5440 | |
5441 | devm_kfree(dev: ice_hw_to_dev(hw), p: rm->root_buf); |
5442 | kfree(objp: rm); |
5443 | |
5444 | err_free_lkup_exts: |
5445 | kfree(objp: lkup_exts); |
5446 | |
5447 | return status; |
5448 | } |
5449 | |
5450 | /** |
5451 | * ice_dummy_packet_add_vlan - insert VLAN header to dummy pkt |
5452 | * |
5453 | * @dummy_pkt: dummy packet profile pattern to which VLAN tag(s) will be added |
5454 | * @num_vlan: number of VLAN tags |
5455 | */ |
5456 | static struct ice_dummy_pkt_profile * |
5457 | ice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt, |
5458 | u32 num_vlan) |
5459 | { |
5460 | struct ice_dummy_pkt_profile *profile; |
5461 | struct ice_dummy_pkt_offsets *offsets; |
5462 | u32 buf_len, off, etype_off, i; |
5463 | u8 *pkt; |
5464 | |
5465 | if (num_vlan < 1 || num_vlan > 2) |
5466 | return ERR_PTR(error: -EINVAL); |
5467 | |
5468 | off = num_vlan * VLAN_HLEN; |
5469 | |
5470 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet_offsets)) + |
5471 | dummy_pkt->offsets_len; |
5472 | offsets = kzalloc(size: buf_len, GFP_KERNEL); |
5473 | if (!offsets) |
5474 | return ERR_PTR(error: -ENOMEM); |
5475 | |
5476 | offsets[0] = dummy_pkt->offsets[0]; |
5477 | if (num_vlan == 2) { |
5478 | offsets[1] = ice_dummy_qinq_packet_offsets[0]; |
5479 | offsets[2] = ice_dummy_qinq_packet_offsets[1]; |
5480 | } else if (num_vlan == 1) { |
5481 | offsets[1] = ice_dummy_vlan_packet_offsets[0]; |
5482 | } |
5483 | |
5484 | for (i = 1; dummy_pkt->offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5485 | offsets[i + num_vlan].type = dummy_pkt->offsets[i].type; |
5486 | offsets[i + num_vlan].offset = |
5487 | dummy_pkt->offsets[i].offset + off; |
5488 | } |
5489 | offsets[i + num_vlan] = dummy_pkt->offsets[i]; |
5490 | |
5491 | etype_off = dummy_pkt->offsets[1].offset; |
5492 | |
5493 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet)) + |
5494 | dummy_pkt->pkt_len; |
5495 | pkt = kzalloc(size: buf_len, GFP_KERNEL); |
5496 | if (!pkt) { |
5497 | kfree(objp: offsets); |
5498 | return ERR_PTR(error: -ENOMEM); |
5499 | } |
5500 | |
5501 | memcpy(pkt, dummy_pkt->pkt, etype_off); |
5502 | memcpy(pkt + etype_off, |
5503 | num_vlan == 2 ? ice_dummy_qinq_packet : ice_dummy_vlan_packet, |
5504 | off); |
5505 | memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off, |
5506 | dummy_pkt->pkt_len - etype_off); |
5507 | |
5508 | profile = kzalloc(size: sizeof(*profile), GFP_KERNEL); |
5509 | if (!profile) { |
5510 | kfree(objp: offsets); |
5511 | kfree(objp: pkt); |
5512 | return ERR_PTR(error: -ENOMEM); |
5513 | } |
5514 | |
5515 | profile->offsets = offsets; |
5516 | profile->pkt = pkt; |
5517 | profile->pkt_len = buf_len; |
5518 | profile->match |= ICE_PKT_KMALLOC; |
5519 | |
5520 | return profile; |
5521 | } |
5522 | |
5523 | /** |
5524 | * ice_find_dummy_packet - find dummy packet |
5525 | * |
5526 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5527 | * structure per protocol header |
5528 | * @lkups_cnt: number of protocols |
5529 | * @tun_type: tunnel type |
5530 | * |
5531 | * Returns the &ice_dummy_pkt_profile corresponding to these lookup params. |
5532 | */ |
5533 | static const struct ice_dummy_pkt_profile * |
5534 | ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
5535 | enum ice_sw_tunnel_type tun_type) |
5536 | { |
5537 | const struct ice_dummy_pkt_profile *ret = ice_dummy_pkt_profiles; |
5538 | u32 match = 0, vlan_count = 0; |
5539 | u16 i; |
5540 | |
5541 | switch (tun_type) { |
5542 | case ICE_SW_TUN_GTPC: |
5543 | match |= ICE_PKT_TUN_GTPC; |
5544 | break; |
5545 | case ICE_SW_TUN_GTPU: |
5546 | match |= ICE_PKT_TUN_GTPU; |
5547 | break; |
5548 | case ICE_SW_TUN_NVGRE: |
5549 | match |= ICE_PKT_TUN_NVGRE; |
5550 | break; |
5551 | case ICE_SW_TUN_GENEVE: |
5552 | case ICE_SW_TUN_VXLAN: |
5553 | match |= ICE_PKT_TUN_UDP; |
5554 | break; |
5555 | default: |
5556 | break; |
5557 | } |
5558 | |
5559 | for (i = 0; i < lkups_cnt; i++) { |
5560 | if (lkups[i].type == ICE_UDP_ILOS) |
5561 | match |= ICE_PKT_INNER_UDP; |
5562 | else if (lkups[i].type == ICE_TCP_IL) |
5563 | match |= ICE_PKT_INNER_TCP; |
5564 | else if (lkups[i].type == ICE_IPV6_OFOS) |
5565 | match |= ICE_PKT_OUTER_IPV6; |
5566 | else if (lkups[i].type == ICE_VLAN_OFOS || |
5567 | lkups[i].type == ICE_VLAN_EX) |
5568 | vlan_count++; |
5569 | else if (lkups[i].type == ICE_VLAN_IN) |
5570 | vlan_count++; |
5571 | else if (lkups[i].type == ICE_ETYPE_OL && |
5572 | lkups[i].h_u.ethertype.ethtype_id == |
5573 | cpu_to_be16(ICE_IPV6_ETHER_ID) && |
5574 | lkups[i].m_u.ethertype.ethtype_id == |
5575 | cpu_to_be16(0xFFFF)) |
5576 | match |= ICE_PKT_OUTER_IPV6; |
5577 | else if (lkups[i].type == ICE_ETYPE_IL && |
5578 | lkups[i].h_u.ethertype.ethtype_id == |
5579 | cpu_to_be16(ICE_IPV6_ETHER_ID) && |
5580 | lkups[i].m_u.ethertype.ethtype_id == |
5581 | cpu_to_be16(0xFFFF)) |
5582 | match |= ICE_PKT_INNER_IPV6; |
5583 | else if (lkups[i].type == ICE_IPV6_IL) |
5584 | match |= ICE_PKT_INNER_IPV6; |
5585 | else if (lkups[i].type == ICE_GTP_NO_PAY) |
5586 | match |= ICE_PKT_GTP_NOPAY; |
5587 | else if (lkups[i].type == ICE_PPPOE) { |
5588 | match |= ICE_PKT_PPPOE; |
5589 | if (lkups[i].h_u.pppoe_hdr.ppp_prot_id == |
5590 | htons(PPP_IPV6)) |
5591 | match |= ICE_PKT_OUTER_IPV6; |
5592 | } else if (lkups[i].type == ICE_L2TPV3) |
5593 | match |= ICE_PKT_L2TPV3; |
5594 | } |
5595 | |
5596 | while (ret->match && (match & ret->match) != ret->match) |
5597 | ret++; |
5598 | |
5599 | if (vlan_count != 0) |
5600 | ret = ice_dummy_packet_add_vlan(dummy_pkt: ret, num_vlan: vlan_count); |
5601 | |
5602 | return ret; |
5603 | } |
5604 | |
5605 | /** |
5606 | * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria |
5607 | * |
5608 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5609 | * structure per protocol header |
5610 | * @lkups_cnt: number of protocols |
5611 | * @s_rule: stores rule information from the match criteria |
5612 | * @profile: dummy packet profile (the template, its size and header offsets) |
5613 | */ |
5614 | static int |
5615 | ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
5616 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
5617 | const struct ice_dummy_pkt_profile *profile) |
5618 | { |
5619 | u8 *pkt; |
5620 | u16 i; |
5621 | |
5622 | /* Start with a packet with a pre-defined/dummy content. Then, fill |
5623 | * in the header values to be looked up or matched. |
5624 | */ |
5625 | pkt = s_rule->hdr_data; |
5626 | |
5627 | memcpy(pkt, profile->pkt, profile->pkt_len); |
5628 | |
5629 | for (i = 0; i < lkups_cnt; i++) { |
5630 | const struct ice_dummy_pkt_offsets *offsets = profile->offsets; |
5631 | enum ice_protocol_type type; |
5632 | u16 offset = 0, len = 0, j; |
5633 | bool found = false; |
5634 | |
5635 | /* find the start of this layer; it should be found since this |
5636 | * was already checked when search for the dummy packet |
5637 | */ |
5638 | type = lkups[i].type; |
5639 | /* metadata isn't present in the packet */ |
5640 | if (type == ICE_HW_METADATA) |
5641 | continue; |
5642 | |
5643 | for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { |
5644 | if (type == offsets[j].type) { |
5645 | offset = offsets[j].offset; |
5646 | found = true; |
5647 | break; |
5648 | } |
5649 | } |
5650 | /* this should never happen in a correct calling sequence */ |
5651 | if (!found) |
5652 | return -EINVAL; |
5653 | |
5654 | switch (lkups[i].type) { |
5655 | case ICE_MAC_OFOS: |
5656 | case ICE_MAC_IL: |
5657 | len = sizeof(struct ice_ether_hdr); |
5658 | break; |
5659 | case ICE_ETYPE_OL: |
5660 | case ICE_ETYPE_IL: |
5661 | len = sizeof(struct ice_ethtype_hdr); |
5662 | break; |
5663 | case ICE_VLAN_OFOS: |
5664 | case ICE_VLAN_EX: |
5665 | case ICE_VLAN_IN: |
5666 | len = sizeof(struct ice_vlan_hdr); |
5667 | break; |
5668 | case ICE_IPV4_OFOS: |
5669 | case ICE_IPV4_IL: |
5670 | len = sizeof(struct ice_ipv4_hdr); |
5671 | break; |
5672 | case ICE_IPV6_OFOS: |
5673 | case ICE_IPV6_IL: |
5674 | len = sizeof(struct ice_ipv6_hdr); |
5675 | break; |
5676 | case ICE_TCP_IL: |
5677 | case ICE_UDP_OF: |
5678 | case ICE_UDP_ILOS: |
5679 | len = sizeof(struct ice_l4_hdr); |
5680 | break; |
5681 | case ICE_SCTP_IL: |
5682 | len = sizeof(struct ice_sctp_hdr); |
5683 | break; |
5684 | case ICE_NVGRE: |
5685 | len = sizeof(struct ice_nvgre_hdr); |
5686 | break; |
5687 | case ICE_VXLAN: |
5688 | case ICE_GENEVE: |
5689 | len = sizeof(struct ice_udp_tnl_hdr); |
5690 | break; |
5691 | case ICE_GTP_NO_PAY: |
5692 | case ICE_GTP: |
5693 | len = sizeof(struct ice_udp_gtp_hdr); |
5694 | break; |
5695 | case ICE_PPPOE: |
5696 | len = sizeof(struct ice_pppoe_hdr); |
5697 | break; |
5698 | case ICE_L2TPV3: |
5699 | len = sizeof(struct ice_l2tpv3_sess_hdr); |
5700 | break; |
5701 | default: |
5702 | return -EINVAL; |
5703 | } |
5704 | |
5705 | /* the length should be a word multiple */ |
5706 | if (len % ICE_BYTES_PER_WORD) |
5707 | return -EIO; |
5708 | |
5709 | /* We have the offset to the header start, the length, the |
5710 | * caller's header values and mask. Use this information to |
5711 | * copy the data into the dummy packet appropriately based on |
5712 | * the mask. Note that we need to only write the bits as |
5713 | * indicated by the mask to make sure we don't improperly write |
5714 | * over any significant packet data. |
5715 | */ |
5716 | for (j = 0; j < len / sizeof(u16); j++) { |
5717 | u16 *ptr = (u16 *)(pkt + offset); |
5718 | u16 mask = lkups[i].m_raw[j]; |
5719 | |
5720 | if (!mask) |
5721 | continue; |
5722 | |
5723 | ptr[j] = (ptr[j] & ~mask) | (lkups[i].h_raw[j] & mask); |
5724 | } |
5725 | } |
5726 | |
5727 | s_rule->hdr_len = cpu_to_le16(profile->pkt_len); |
5728 | |
5729 | return 0; |
5730 | } |
5731 | |
5732 | /** |
5733 | * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port |
5734 | * @hw: pointer to the hardware structure |
5735 | * @tun_type: tunnel type |
5736 | * @pkt: dummy packet to fill in |
5737 | * @offsets: offset info for the dummy packet |
5738 | */ |
5739 | static int |
5740 | ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type, |
5741 | u8 *pkt, const struct ice_dummy_pkt_offsets *offsets) |
5742 | { |
5743 | u16 open_port, i; |
5744 | |
5745 | switch (tun_type) { |
5746 | case ICE_SW_TUN_VXLAN: |
5747 | if (!ice_get_open_tunnel_port(hw, port: &open_port, type: TNL_VXLAN)) |
5748 | return -EIO; |
5749 | break; |
5750 | case ICE_SW_TUN_GENEVE: |
5751 | if (!ice_get_open_tunnel_port(hw, port: &open_port, type: TNL_GENEVE)) |
5752 | return -EIO; |
5753 | break; |
5754 | default: |
5755 | /* Nothing needs to be done for this tunnel type */ |
5756 | return 0; |
5757 | } |
5758 | |
5759 | /* Find the outer UDP protocol header and insert the port number */ |
5760 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5761 | if (offsets[i].type == ICE_UDP_OF) { |
5762 | struct ice_l4_hdr *hdr; |
5763 | u16 offset; |
5764 | |
5765 | offset = offsets[i].offset; |
5766 | hdr = (struct ice_l4_hdr *)&pkt[offset]; |
5767 | hdr->dst_port = cpu_to_be16(open_port); |
5768 | |
5769 | return 0; |
5770 | } |
5771 | } |
5772 | |
5773 | return -EIO; |
5774 | } |
5775 | |
5776 | /** |
5777 | * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type |
5778 | * @hw: pointer to hw structure |
5779 | * @vlan_type: VLAN tag type |
5780 | * @pkt: dummy packet to fill in |
5781 | * @offsets: offset info for the dummy packet |
5782 | */ |
5783 | static int |
5784 | ice_fill_adv_packet_vlan(struct ice_hw *hw, u16 vlan_type, u8 *pkt, |
5785 | const struct ice_dummy_pkt_offsets *offsets) |
5786 | { |
5787 | u16 i; |
5788 | |
5789 | /* Check if there is something to do */ |
5790 | if (!vlan_type || !ice_is_dvm_ena(hw)) |
5791 | return 0; |
5792 | |
5793 | /* Find VLAN header and insert VLAN TPID */ |
5794 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5795 | if (offsets[i].type == ICE_VLAN_OFOS || |
5796 | offsets[i].type == ICE_VLAN_EX) { |
5797 | struct ice_vlan_hdr *hdr; |
5798 | u16 offset; |
5799 | |
5800 | offset = offsets[i].offset; |
5801 | hdr = (struct ice_vlan_hdr *)&pkt[offset]; |
5802 | hdr->type = cpu_to_be16(vlan_type); |
5803 | |
5804 | return 0; |
5805 | } |
5806 | } |
5807 | |
5808 | return -EIO; |
5809 | } |
5810 | |
5811 | static bool ice_rules_equal(const struct ice_adv_rule_info *first, |
5812 | const struct ice_adv_rule_info *second) |
5813 | { |
5814 | return first->sw_act.flag == second->sw_act.flag && |
5815 | first->tun_type == second->tun_type && |
5816 | first->vlan_type == second->vlan_type && |
5817 | first->src_vsi == second->src_vsi && |
5818 | first->need_pass_l2 == second->need_pass_l2 && |
5819 | first->allow_pass_l2 == second->allow_pass_l2; |
5820 | } |
5821 | |
5822 | /** |
5823 | * ice_find_adv_rule_entry - Search a rule entry |
5824 | * @hw: pointer to the hardware structure |
5825 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5826 | * structure per protocol header |
5827 | * @lkups_cnt: number of protocols |
5828 | * @recp_id: recipe ID for which we are finding the rule |
5829 | * @rinfo: other information regarding the rule e.g. priority and action info |
5830 | * |
5831 | * Helper function to search for a given advance rule entry |
5832 | * Returns pointer to entry storing the rule if found |
5833 | */ |
5834 | static struct ice_adv_fltr_mgmt_list_entry * |
5835 | ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
5836 | u16 lkups_cnt, u16 recp_id, |
5837 | struct ice_adv_rule_info *rinfo) |
5838 | { |
5839 | struct ice_adv_fltr_mgmt_list_entry *list_itr; |
5840 | struct ice_switch_info *sw = hw->switch_info; |
5841 | int i; |
5842 | |
5843 | list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules, |
5844 | list_entry) { |
5845 | bool lkups_matched = true; |
5846 | |
5847 | if (lkups_cnt != list_itr->lkups_cnt) |
5848 | continue; |
5849 | for (i = 0; i < list_itr->lkups_cnt; i++) |
5850 | if (memcmp(p: &list_itr->lkups[i], q: &lkups[i], |
5851 | size: sizeof(*lkups))) { |
5852 | lkups_matched = false; |
5853 | break; |
5854 | } |
5855 | if (ice_rules_equal(first: rinfo, second: &list_itr->rule_info) && |
5856 | lkups_matched) |
5857 | return list_itr; |
5858 | } |
5859 | return NULL; |
5860 | } |
5861 | |
5862 | /** |
5863 | * ice_adv_add_update_vsi_list |
5864 | * @hw: pointer to the hardware structure |
5865 | * @m_entry: pointer to current adv filter management list entry |
5866 | * @cur_fltr: filter information from the book keeping entry |
5867 | * @new_fltr: filter information with the new VSI to be added |
5868 | * |
5869 | * Call AQ command to add or update previously created VSI list with new VSI. |
5870 | * |
5871 | * Helper function to do book keeping associated with adding filter information |
5872 | * The algorithm to do the booking keeping is described below : |
5873 | * When a VSI needs to subscribe to a given advanced filter |
5874 | * if only one VSI has been added till now |
5875 | * Allocate a new VSI list and add two VSIs |
5876 | * to this list using switch rule command |
5877 | * Update the previously created switch rule with the |
5878 | * newly created VSI list ID |
5879 | * if a VSI list was previously created |
5880 | * Add the new VSI to the previously created VSI list set |
5881 | * using the update switch rule command |
5882 | */ |
5883 | static int |
5884 | ice_adv_add_update_vsi_list(struct ice_hw *hw, |
5885 | struct ice_adv_fltr_mgmt_list_entry *m_entry, |
5886 | struct ice_adv_rule_info *cur_fltr, |
5887 | struct ice_adv_rule_info *new_fltr) |
5888 | { |
5889 | u16 vsi_list_id = 0; |
5890 | int status; |
5891 | |
5892 | if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || |
5893 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP || |
5894 | cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET) |
5895 | return -EOPNOTSUPP; |
5896 | |
5897 | if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || |
5898 | new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) && |
5899 | (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI || |
5900 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST)) |
5901 | return -EOPNOTSUPP; |
5902 | |
5903 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { |
5904 | /* Only one entry existed in the mapping and it was not already |
5905 | * a part of a VSI list. So, create a VSI list with the old and |
5906 | * new VSIs. |
5907 | */ |
5908 | struct ice_fltr_info tmp_fltr; |
5909 | u16 vsi_handle_arr[2]; |
5910 | |
5911 | /* A rule already exists with the new VSI being added */ |
5912 | if (cur_fltr->sw_act.fwd_id.hw_vsi_id == |
5913 | new_fltr->sw_act.fwd_id.hw_vsi_id) |
5914 | return -EEXIST; |
5915 | |
5916 | vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle; |
5917 | vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle; |
5918 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
5919 | vsi_list_id: &vsi_list_id, |
5920 | lkup_type: ICE_SW_LKUP_LAST); |
5921 | if (status) |
5922 | return status; |
5923 | |
5924 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); |
5925 | tmp_fltr.flag = m_entry->rule_info.sw_act.flag; |
5926 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; |
5927 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
5928 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
5929 | tmp_fltr.lkup_type = ICE_SW_LKUP_LAST; |
5930 | |
5931 | /* Update the previous switch rule of "forward to VSI" to |
5932 | * "fwd to VSI list" |
5933 | */ |
5934 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
5935 | if (status) |
5936 | return status; |
5937 | |
5938 | cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id; |
5939 | cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST; |
5940 | m_entry->vsi_list_info = |
5941 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
5942 | vsi_list_id); |
5943 | } else { |
5944 | u16 vsi_handle = new_fltr->sw_act.vsi_handle; |
5945 | |
5946 | if (!m_entry->vsi_list_info) |
5947 | return -EIO; |
5948 | |
5949 | /* A rule already exists with the new VSI being added */ |
5950 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) |
5951 | return 0; |
5952 | |
5953 | /* Update the previously created VSI list set with |
5954 | * the new VSI ID passed in |
5955 | */ |
5956 | vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id; |
5957 | |
5958 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, |
5959 | vsi_list_id, remove: false, |
5960 | opc: ice_aqc_opc_update_sw_rules, |
5961 | lkup_type: ICE_SW_LKUP_LAST); |
5962 | /* update VSI list mapping info with new VSI ID */ |
5963 | if (!status) |
5964 | set_bit(nr: vsi_handle, addr: m_entry->vsi_list_info->vsi_map); |
5965 | } |
5966 | if (!status) |
5967 | m_entry->vsi_count++; |
5968 | return status; |
5969 | } |
5970 | |
5971 | void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup) |
5972 | { |
5973 | lkup->type = ICE_HW_METADATA; |
5974 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID21] |= |
5975 | cpu_to_be16(ICE_PKT_TUNNEL_MASK); |
5976 | } |
5977 | |
5978 | void ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup) |
5979 | { |
5980 | lkup->type = ICE_HW_METADATA; |
5981 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |= |
5982 | cpu_to_be16(ICE_PKT_FROM_NETWORK); |
5983 | } |
5984 | |
5985 | void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup) |
5986 | { |
5987 | lkup->type = ICE_HW_METADATA; |
5988 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |= |
5989 | cpu_to_be16(ICE_PKT_VLAN_MASK); |
5990 | } |
5991 | |
5992 | void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup) |
5993 | { |
5994 | lkup->type = ICE_HW_METADATA; |
5995 | lkup->m_u.metadata.source_vsi = cpu_to_be16(ICE_MDID_SOURCE_VSI_MASK); |
5996 | } |
5997 | |
5998 | /** |
5999 | * ice_add_adv_rule - helper function to create an advanced switch rule |
6000 | * @hw: pointer to the hardware structure |
6001 | * @lkups: information on the words that needs to be looked up. All words |
6002 | * together makes one recipe |
6003 | * @lkups_cnt: num of entries in the lkups array |
6004 | * @rinfo: other information related to the rule that needs to be programmed |
6005 | * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be |
6006 | * ignored is case of error. |
6007 | * |
6008 | * This function can program only 1 rule at a time. The lkups is used to |
6009 | * describe the all the words that forms the "lookup" portion of the recipe. |
6010 | * These words can span multiple protocols. Callers to this function need to |
6011 | * pass in a list of protocol headers with lookup information along and mask |
6012 | * that determines which words are valid from the given protocol header. |
6013 | * rinfo describes other information related to this rule such as forwarding |
6014 | * IDs, priority of this rule, etc. |
6015 | */ |
6016 | int |
6017 | ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6018 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, |
6019 | struct ice_rule_query_data *added_entry) |
6020 | { |
6021 | struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; |
6022 | struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; |
6023 | const struct ice_dummy_pkt_profile *profile; |
6024 | u16 rid = 0, i, rule_buf_sz, vsi_handle; |
6025 | struct list_head *rule_head; |
6026 | struct ice_switch_info *sw; |
6027 | u16 word_cnt; |
6028 | u32 act = 0; |
6029 | int status; |
6030 | u8 q_rgn; |
6031 | |
6032 | /* Initialize profile to result index bitmap */ |
6033 | if (!hw->switch_info->prof_res_bm_init) { |
6034 | hw->switch_info->prof_res_bm_init = 1; |
6035 | ice_init_prof_result_bm(hw); |
6036 | } |
6037 | |
6038 | if (!lkups_cnt) |
6039 | return -EINVAL; |
6040 | |
6041 | /* get # of words we need to match */ |
6042 | word_cnt = 0; |
6043 | for (i = 0; i < lkups_cnt; i++) { |
6044 | u16 j; |
6045 | |
6046 | for (j = 0; j < ARRAY_SIZE(lkups->m_raw); j++) |
6047 | if (lkups[i].m_raw[j]) |
6048 | word_cnt++; |
6049 | } |
6050 | |
6051 | if (!word_cnt) |
6052 | return -EINVAL; |
6053 | |
6054 | if (word_cnt > ICE_MAX_CHAIN_WORDS) |
6055 | return -ENOSPC; |
6056 | |
6057 | /* locate a dummy packet */ |
6058 | profile = ice_find_dummy_packet(lkups, lkups_cnt, tun_type: rinfo->tun_type); |
6059 | if (IS_ERR(ptr: profile)) |
6060 | return PTR_ERR(ptr: profile); |
6061 | |
6062 | if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || |
6063 | rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || |
6064 | rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || |
6065 | rinfo->sw_act.fltr_act == ICE_DROP_PACKET || |
6066 | rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET || |
6067 | rinfo->sw_act.fltr_act == ICE_NOP)) { |
6068 | status = -EIO; |
6069 | goto free_pkt_profile; |
6070 | } |
6071 | |
6072 | vsi_handle = rinfo->sw_act.vsi_handle; |
6073 | if (!ice_is_vsi_valid(hw, vsi_handle)) { |
6074 | status = -EINVAL; |
6075 | goto free_pkt_profile; |
6076 | } |
6077 | |
6078 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || |
6079 | rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET || |
6080 | rinfo->sw_act.fltr_act == ICE_NOP) { |
6081 | rinfo->sw_act.fwd_id.hw_vsi_id = |
6082 | ice_get_hw_vsi_num(hw, vsi_handle); |
6083 | } |
6084 | |
6085 | if (rinfo->src_vsi) |
6086 | rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle: rinfo->src_vsi); |
6087 | else |
6088 | rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); |
6089 | |
6090 | status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, rid: &rid); |
6091 | if (status) |
6092 | goto free_pkt_profile; |
6093 | m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, recp_id: rid, rinfo); |
6094 | if (m_entry) { |
6095 | /* we have to add VSI to VSI_LIST and increment vsi_count. |
6096 | * Also Update VSI list so that we can change forwarding rule |
6097 | * if the rule already exists, we will check if it exists with |
6098 | * same vsi_id, if not then add it to the VSI list if it already |
6099 | * exists if not then create a VSI list and add the existing VSI |
6100 | * ID and the new VSI ID to the list |
6101 | * We will add that VSI to the list |
6102 | */ |
6103 | status = ice_adv_add_update_vsi_list(hw, m_entry, |
6104 | cur_fltr: &m_entry->rule_info, |
6105 | new_fltr: rinfo); |
6106 | if (added_entry) { |
6107 | added_entry->rid = rid; |
6108 | added_entry->rule_id = m_entry->rule_info.fltr_rule_id; |
6109 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; |
6110 | } |
6111 | goto free_pkt_profile; |
6112 | } |
6113 | rule_buf_sz = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, profile->pkt_len); |
6114 | s_rule = kzalloc(size: rule_buf_sz, GFP_KERNEL); |
6115 | if (!s_rule) { |
6116 | status = -ENOMEM; |
6117 | goto free_pkt_profile; |
6118 | } |
6119 | |
6120 | if (rinfo->sw_act.fltr_act != ICE_MIRROR_PACKET) { |
6121 | if (!rinfo->flags_info.act_valid) { |
6122 | act |= ICE_SINGLE_ACT_LAN_ENABLE; |
6123 | act |= ICE_SINGLE_ACT_LB_ENABLE; |
6124 | } else { |
6125 | act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE | |
6126 | ICE_SINGLE_ACT_LB_ENABLE); |
6127 | } |
6128 | } |
6129 | |
6130 | switch (rinfo->sw_act.fltr_act) { |
6131 | case ICE_FWD_TO_VSI: |
6132 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, |
6133 | rinfo->sw_act.fwd_id.hw_vsi_id); |
6134 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT; |
6135 | break; |
6136 | case ICE_FWD_TO_Q: |
6137 | act |= ICE_SINGLE_ACT_TO_Q; |
6138 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M, |
6139 | rinfo->sw_act.fwd_id.q_id); |
6140 | break; |
6141 | case ICE_FWD_TO_QGRP: |
6142 | q_rgn = rinfo->sw_act.qgrp_size > 0 ? |
6143 | (u8)ilog2(rinfo->sw_act.qgrp_size) : 0; |
6144 | act |= ICE_SINGLE_ACT_TO_Q; |
6145 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M, |
6146 | rinfo->sw_act.fwd_id.q_id); |
6147 | act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn); |
6148 | break; |
6149 | case ICE_DROP_PACKET: |
6150 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | |
6151 | ICE_SINGLE_ACT_VALID_BIT; |
6152 | break; |
6153 | case ICE_MIRROR_PACKET: |
6154 | act |= ICE_SINGLE_ACT_OTHER_ACTS; |
6155 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, |
6156 | rinfo->sw_act.fwd_id.hw_vsi_id); |
6157 | break; |
6158 | case ICE_NOP: |
6159 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, |
6160 | rinfo->sw_act.fwd_id.hw_vsi_id); |
6161 | act &= ~ICE_SINGLE_ACT_VALID_BIT; |
6162 | break; |
6163 | default: |
6164 | status = -EIO; |
6165 | goto err_ice_add_adv_rule; |
6166 | } |
6167 | |
6168 | /* If there is no matching criteria for direction there |
6169 | * is only one difference between Rx and Tx: |
6170 | * - get switch id base on VSI number from source field (Tx) |
6171 | * - get switch id base on port number (Rx) |
6172 | * |
6173 | * If matching on direction metadata is chose rule direction is |
6174 | * extracted from type value set here. |
6175 | */ |
6176 | if (rinfo->sw_act.flag & ICE_FLTR_TX) { |
6177 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); |
6178 | s_rule->src = cpu_to_le16(rinfo->sw_act.src); |
6179 | } else { |
6180 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); |
6181 | s_rule->src = cpu_to_le16(hw->port_info->lport); |
6182 | } |
6183 | |
6184 | s_rule->recipe_id = cpu_to_le16(rid); |
6185 | s_rule->act = cpu_to_le32(act); |
6186 | |
6187 | status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, profile); |
6188 | if (status) |
6189 | goto err_ice_add_adv_rule; |
6190 | |
6191 | status = ice_fill_adv_packet_tun(hw, tun_type: rinfo->tun_type, pkt: s_rule->hdr_data, |
6192 | offsets: profile->offsets); |
6193 | if (status) |
6194 | goto err_ice_add_adv_rule; |
6195 | |
6196 | status = ice_fill_adv_packet_vlan(hw, vlan_type: rinfo->vlan_type, |
6197 | pkt: s_rule->hdr_data, |
6198 | offsets: profile->offsets); |
6199 | if (status) |
6200 | goto err_ice_add_adv_rule; |
6201 | |
6202 | status = ice_aq_sw_rules(hw, rule_list: (struct ice_aqc_sw_rules *)s_rule, |
6203 | rule_list_sz: rule_buf_sz, num_rules: 1, opc: ice_aqc_opc_add_sw_rules, |
6204 | NULL); |
6205 | if (status) |
6206 | goto err_ice_add_adv_rule; |
6207 | adv_fltr = devm_kzalloc(dev: ice_hw_to_dev(hw), |
6208 | size: sizeof(struct ice_adv_fltr_mgmt_list_entry), |
6209 | GFP_KERNEL); |
6210 | if (!adv_fltr) { |
6211 | status = -ENOMEM; |
6212 | goto err_ice_add_adv_rule; |
6213 | } |
6214 | |
6215 | adv_fltr->lkups = devm_kmemdup(dev: ice_hw_to_dev(hw), src: lkups, |
6216 | len: lkups_cnt * sizeof(*lkups), GFP_KERNEL); |
6217 | if (!adv_fltr->lkups) { |
6218 | status = -ENOMEM; |
6219 | goto err_ice_add_adv_rule; |
6220 | } |
6221 | |
6222 | adv_fltr->lkups_cnt = lkups_cnt; |
6223 | adv_fltr->rule_info = *rinfo; |
6224 | adv_fltr->rule_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
6225 | sw = hw->switch_info; |
6226 | sw->recp_list[rid].adv_rule = true; |
6227 | rule_head = &sw->recp_list[rid].filt_rules; |
6228 | |
6229 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) |
6230 | adv_fltr->vsi_count = 1; |
6231 | |
6232 | /* Add rule entry to book keeping list */ |
6233 | list_add(new: &adv_fltr->list_entry, head: rule_head); |
6234 | if (added_entry) { |
6235 | added_entry->rid = rid; |
6236 | added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id; |
6237 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; |
6238 | } |
6239 | err_ice_add_adv_rule: |
6240 | if (status && adv_fltr) { |
6241 | devm_kfree(dev: ice_hw_to_dev(hw), p: adv_fltr->lkups); |
6242 | devm_kfree(dev: ice_hw_to_dev(hw), p: adv_fltr); |
6243 | } |
6244 | |
6245 | kfree(objp: s_rule); |
6246 | |
6247 | free_pkt_profile: |
6248 | if (profile->match & ICE_PKT_KMALLOC) { |
6249 | kfree(objp: profile->offsets); |
6250 | kfree(objp: profile->pkt); |
6251 | kfree(objp: profile); |
6252 | } |
6253 | |
6254 | return status; |
6255 | } |
6256 | |
6257 | /** |
6258 | * ice_replay_vsi_fltr - Replay filters for requested VSI |
6259 | * @hw: pointer to the hardware structure |
6260 | * @vsi_handle: driver VSI handle |
6261 | * @recp_id: Recipe ID for which rules need to be replayed |
6262 | * @list_head: list for which filters need to be replayed |
6263 | * |
6264 | * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. |
6265 | * It is required to pass valid VSI handle. |
6266 | */ |
6267 | static int |
6268 | ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, |
6269 | struct list_head *list_head) |
6270 | { |
6271 | struct ice_fltr_mgmt_list_entry *itr; |
6272 | int status = 0; |
6273 | u16 hw_vsi_id; |
6274 | |
6275 | if (list_empty(head: list_head)) |
6276 | return status; |
6277 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
6278 | |
6279 | list_for_each_entry(itr, list_head, list_entry) { |
6280 | struct ice_fltr_list_entry f_entry; |
6281 | |
6282 | f_entry.fltr_info = itr->fltr_info; |
6283 | if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && |
6284 | itr->fltr_info.vsi_handle == vsi_handle) { |
6285 | /* update the src in case it is VSI num */ |
6286 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6287 | f_entry.fltr_info.src = hw_vsi_id; |
6288 | status = ice_add_rule_internal(hw, recp_id, f_entry: &f_entry); |
6289 | if (status) |
6290 | goto end; |
6291 | continue; |
6292 | } |
6293 | if (!itr->vsi_list_info || |
6294 | !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) |
6295 | continue; |
6296 | /* Clearing it so that the logic can add it back */ |
6297 | clear_bit(nr: vsi_handle, addr: itr->vsi_list_info->vsi_map); |
6298 | f_entry.fltr_info.vsi_handle = vsi_handle; |
6299 | f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; |
6300 | /* update the src in case it is VSI num */ |
6301 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6302 | f_entry.fltr_info.src = hw_vsi_id; |
6303 | if (recp_id == ICE_SW_LKUP_VLAN) |
6304 | status = ice_add_vlan_internal(hw, f_entry: &f_entry); |
6305 | else |
6306 | status = ice_add_rule_internal(hw, recp_id, f_entry: &f_entry); |
6307 | if (status) |
6308 | goto end; |
6309 | } |
6310 | end: |
6311 | return status; |
6312 | } |
6313 | |
6314 | /** |
6315 | * ice_adv_rem_update_vsi_list |
6316 | * @hw: pointer to the hardware structure |
6317 | * @vsi_handle: VSI handle of the VSI to remove |
6318 | * @fm_list: filter management entry for which the VSI list management needs to |
6319 | * be done |
6320 | */ |
6321 | static int |
6322 | ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
6323 | struct ice_adv_fltr_mgmt_list_entry *fm_list) |
6324 | { |
6325 | struct ice_vsi_list_map_info *vsi_list_info; |
6326 | enum ice_sw_lkup_type lkup_type; |
6327 | u16 vsi_list_id; |
6328 | int status; |
6329 | |
6330 | if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST || |
6331 | fm_list->vsi_count == 0) |
6332 | return -EINVAL; |
6333 | |
6334 | /* A rule with the VSI being removed does not exist */ |
6335 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) |
6336 | return -ENOENT; |
6337 | |
6338 | lkup_type = ICE_SW_LKUP_LAST; |
6339 | vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id; |
6340 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, vsi_list_id, remove: true, |
6341 | opc: ice_aqc_opc_update_sw_rules, |
6342 | lkup_type); |
6343 | if (status) |
6344 | return status; |
6345 | |
6346 | fm_list->vsi_count--; |
6347 | clear_bit(nr: vsi_handle, addr: fm_list->vsi_list_info->vsi_map); |
6348 | vsi_list_info = fm_list->vsi_list_info; |
6349 | if (fm_list->vsi_count == 1) { |
6350 | struct ice_fltr_info tmp_fltr; |
6351 | u16 rem_vsi_handle; |
6352 | |
6353 | rem_vsi_handle = find_first_bit(addr: vsi_list_info->vsi_map, |
6354 | ICE_MAX_VSI); |
6355 | if (!ice_is_vsi_valid(hw, vsi_handle: rem_vsi_handle)) |
6356 | return -EIO; |
6357 | |
6358 | /* Make sure VSI list is empty before removing it below */ |
6359 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &rem_vsi_handle, num_vsi: 1, |
6360 | vsi_list_id, remove: true, |
6361 | opc: ice_aqc_opc_update_sw_rules, |
6362 | lkup_type); |
6363 | if (status) |
6364 | return status; |
6365 | |
6366 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); |
6367 | tmp_fltr.flag = fm_list->rule_info.sw_act.flag; |
6368 | tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id; |
6369 | fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; |
6370 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI; |
6371 | tmp_fltr.fwd_id.hw_vsi_id = |
6372 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
6373 | fm_list->rule_info.sw_act.fwd_id.hw_vsi_id = |
6374 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
6375 | fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle; |
6376 | |
6377 | /* Update the previous switch rule of "MAC forward to VSI" to |
6378 | * "MAC fwd to VSI list" |
6379 | */ |
6380 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
6381 | if (status) { |
6382 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n" , |
6383 | tmp_fltr.fwd_id.hw_vsi_id, status); |
6384 | return status; |
6385 | } |
6386 | fm_list->vsi_list_info->ref_cnt--; |
6387 | |
6388 | /* Remove the VSI list since it is no longer used */ |
6389 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); |
6390 | if (status) { |
6391 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n" , |
6392 | vsi_list_id, status); |
6393 | return status; |
6394 | } |
6395 | |
6396 | list_del(entry: &vsi_list_info->list_entry); |
6397 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi_list_info); |
6398 | fm_list->vsi_list_info = NULL; |
6399 | } |
6400 | |
6401 | return status; |
6402 | } |
6403 | |
6404 | /** |
6405 | * ice_rem_adv_rule - removes existing advanced switch rule |
6406 | * @hw: pointer to the hardware structure |
6407 | * @lkups: information on the words that needs to be looked up. All words |
6408 | * together makes one recipe |
6409 | * @lkups_cnt: num of entries in the lkups array |
6410 | * @rinfo: Its the pointer to the rule information for the rule |
6411 | * |
6412 | * This function can be used to remove 1 rule at a time. The lkups is |
6413 | * used to describe all the words that forms the "lookup" portion of the |
6414 | * rule. These words can span multiple protocols. Callers to this function |
6415 | * need to pass in a list of protocol headers with lookup information along |
6416 | * and mask that determines which words are valid from the given protocol |
6417 | * header. rinfo describes other information related to this rule such as |
6418 | * forwarding IDs, priority of this rule, etc. |
6419 | */ |
6420 | static int |
6421 | ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6422 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo) |
6423 | { |
6424 | struct ice_adv_fltr_mgmt_list_entry *list_elem; |
6425 | struct ice_prot_lkup_ext lkup_exts; |
6426 | bool remove_rule = false; |
6427 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
6428 | u16 i, rid, vsi_handle; |
6429 | int status = 0; |
6430 | |
6431 | memset(&lkup_exts, 0, sizeof(lkup_exts)); |
6432 | for (i = 0; i < lkups_cnt; i++) { |
6433 | u16 count; |
6434 | |
6435 | if (lkups[i].type >= ICE_PROTOCOL_LAST) |
6436 | return -EIO; |
6437 | |
6438 | count = ice_fill_valid_words(rule: &lkups[i], lkup_exts: &lkup_exts); |
6439 | if (!count) |
6440 | return -EIO; |
6441 | } |
6442 | |
6443 | rid = ice_find_recp(hw, lkup_exts: &lkup_exts, rinfo); |
6444 | /* If did not find a recipe that match the existing criteria */ |
6445 | if (rid == ICE_MAX_NUM_RECIPES) |
6446 | return -EINVAL; |
6447 | |
6448 | rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock; |
6449 | list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, recp_id: rid, rinfo); |
6450 | /* the rule is already removed */ |
6451 | if (!list_elem) |
6452 | return 0; |
6453 | mutex_lock(rule_lock); |
6454 | if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) { |
6455 | remove_rule = true; |
6456 | } else if (list_elem->vsi_count > 1) { |
6457 | remove_rule = false; |
6458 | vsi_handle = rinfo->sw_act.vsi_handle; |
6459 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
6460 | } else { |
6461 | vsi_handle = rinfo->sw_act.vsi_handle; |
6462 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
6463 | if (status) { |
6464 | mutex_unlock(lock: rule_lock); |
6465 | return status; |
6466 | } |
6467 | if (list_elem->vsi_count == 0) |
6468 | remove_rule = true; |
6469 | } |
6470 | mutex_unlock(lock: rule_lock); |
6471 | if (remove_rule) { |
6472 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
6473 | u16 rule_buf_sz; |
6474 | |
6475 | rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule); |
6476 | s_rule = kzalloc(size: rule_buf_sz, GFP_KERNEL); |
6477 | if (!s_rule) |
6478 | return -ENOMEM; |
6479 | s_rule->act = 0; |
6480 | s_rule->index = cpu_to_le16(list_elem->rule_info.fltr_rule_id); |
6481 | s_rule->hdr_len = 0; |
6482 | status = ice_aq_sw_rules(hw, rule_list: (struct ice_aqc_sw_rules *)s_rule, |
6483 | rule_list_sz: rule_buf_sz, num_rules: 1, |
6484 | opc: ice_aqc_opc_remove_sw_rules, NULL); |
6485 | if (!status || status == -ENOENT) { |
6486 | struct ice_switch_info *sw = hw->switch_info; |
6487 | |
6488 | mutex_lock(rule_lock); |
6489 | list_del(entry: &list_elem->list_entry); |
6490 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem->lkups); |
6491 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem); |
6492 | mutex_unlock(lock: rule_lock); |
6493 | if (list_empty(head: &sw->recp_list[rid].filt_rules)) |
6494 | sw->recp_list[rid].adv_rule = false; |
6495 | } |
6496 | kfree(objp: s_rule); |
6497 | } |
6498 | return status; |
6499 | } |
6500 | |
6501 | /** |
6502 | * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID |
6503 | * @hw: pointer to the hardware structure |
6504 | * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID |
6505 | * |
6506 | * This function is used to remove 1 rule at a time. The removal is based on |
6507 | * the remove_entry parameter. This function will remove rule for a given |
6508 | * vsi_handle with a given rule_id which is passed as parameter in remove_entry |
6509 | */ |
6510 | int |
6511 | ice_rem_adv_rule_by_id(struct ice_hw *hw, |
6512 | struct ice_rule_query_data *remove_entry) |
6513 | { |
6514 | struct ice_adv_fltr_mgmt_list_entry *list_itr; |
6515 | struct list_head *list_head; |
6516 | struct ice_adv_rule_info rinfo; |
6517 | struct ice_switch_info *sw; |
6518 | |
6519 | sw = hw->switch_info; |
6520 | if (!sw->recp_list[remove_entry->rid].recp_created) |
6521 | return -EINVAL; |
6522 | list_head = &sw->recp_list[remove_entry->rid].filt_rules; |
6523 | list_for_each_entry(list_itr, list_head, list_entry) { |
6524 | if (list_itr->rule_info.fltr_rule_id == |
6525 | remove_entry->rule_id) { |
6526 | rinfo = list_itr->rule_info; |
6527 | rinfo.sw_act.vsi_handle = remove_entry->vsi_handle; |
6528 | return ice_rem_adv_rule(hw, lkups: list_itr->lkups, |
6529 | lkups_cnt: list_itr->lkups_cnt, rinfo: &rinfo); |
6530 | } |
6531 | } |
6532 | /* either list is empty or unable to find rule */ |
6533 | return -ENOENT; |
6534 | } |
6535 | |
6536 | /** |
6537 | * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI |
6538 | * @hw: pointer to the hardware structure |
6539 | * @vsi_handle: driver VSI handle |
6540 | * @list_head: list for which filters need to be replayed |
6541 | * |
6542 | * Replay the advanced rule for the given VSI. |
6543 | */ |
6544 | static int |
6545 | ice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle, |
6546 | struct list_head *list_head) |
6547 | { |
6548 | struct ice_rule_query_data added_entry = { 0 }; |
6549 | struct ice_adv_fltr_mgmt_list_entry *adv_fltr; |
6550 | int status = 0; |
6551 | |
6552 | if (list_empty(head: list_head)) |
6553 | return status; |
6554 | list_for_each_entry(adv_fltr, list_head, list_entry) { |
6555 | struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info; |
6556 | u16 lk_cnt = adv_fltr->lkups_cnt; |
6557 | |
6558 | if (vsi_handle != rinfo->sw_act.vsi_handle) |
6559 | continue; |
6560 | status = ice_add_adv_rule(hw, lkups: adv_fltr->lkups, lkups_cnt: lk_cnt, rinfo, |
6561 | added_entry: &added_entry); |
6562 | if (status) |
6563 | break; |
6564 | } |
6565 | return status; |
6566 | } |
6567 | |
6568 | /** |
6569 | * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists |
6570 | * @hw: pointer to the hardware structure |
6571 | * @vsi_handle: driver VSI handle |
6572 | * |
6573 | * Replays filters for requested VSI via vsi_handle. |
6574 | */ |
6575 | int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) |
6576 | { |
6577 | struct ice_switch_info *sw = hw->switch_info; |
6578 | int status; |
6579 | u8 i; |
6580 | |
6581 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
6582 | struct list_head *head; |
6583 | |
6584 | head = &sw->recp_list[i].filt_replay_rules; |
6585 | if (!sw->recp_list[i].adv_rule) |
6586 | status = ice_replay_vsi_fltr(hw, vsi_handle, recp_id: i, list_head: head); |
6587 | else |
6588 | status = ice_replay_vsi_adv_rule(hw, vsi_handle, list_head: head); |
6589 | if (status) |
6590 | return status; |
6591 | } |
6592 | return status; |
6593 | } |
6594 | |
6595 | /** |
6596 | * ice_rm_all_sw_replay_rule_info - deletes filter replay rules |
6597 | * @hw: pointer to the HW struct |
6598 | * |
6599 | * Deletes the filter replay rules. |
6600 | */ |
6601 | void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) |
6602 | { |
6603 | struct ice_switch_info *sw = hw->switch_info; |
6604 | u8 i; |
6605 | |
6606 | if (!sw) |
6607 | return; |
6608 | |
6609 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
6610 | if (!list_empty(head: &sw->recp_list[i].filt_replay_rules)) { |
6611 | struct list_head *l_head; |
6612 | |
6613 | l_head = &sw->recp_list[i].filt_replay_rules; |
6614 | if (!sw->recp_list[i].adv_rule) |
6615 | ice_rem_sw_rule_info(hw, rule_head: l_head); |
6616 | else |
6617 | ice_rem_adv_rule_info(hw, rule_head: l_head); |
6618 | } |
6619 | } |
6620 | } |
6621 | |