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_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_bitmap: 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, u8 *r_bitmap, |
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 | memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_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_bitmap: 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, u8 *r_bitmap, |
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 | memcpy(r_bitmap, cmd->recipe_assoc, sizeof(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_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 | u16 i; |
2112 | |
2113 | for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) { |
2114 | u16 j; |
2115 | |
2116 | bitmap_zero(dst: profile_to_recipe[i], ICE_MAX_NUM_RECIPES); |
2117 | bitmap_zero(dst: r_bitmap, ICE_MAX_NUM_RECIPES); |
2118 | if (ice_aq_get_recipe_to_profile(hw, profile_id: i, r_bitmap: (u8 *)r_bitmap, NULL)) |
2119 | continue; |
2120 | bitmap_copy(dst: profile_to_recipe[i], src: r_bitmap, |
2121 | ICE_MAX_NUM_RECIPES); |
2122 | for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES) |
2123 | set_bit(nr: i, addr: recipe_to_profile[j]); |
2124 | } |
2125 | } |
2126 | |
2127 | /** |
2128 | * ice_collect_result_idx - copy result index values |
2129 | * @buf: buffer that contains the result index |
2130 | * @recp: the recipe struct to copy data into |
2131 | */ |
2132 | static void |
2133 | ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf, |
2134 | struct ice_sw_recipe *recp) |
2135 | { |
2136 | if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN) |
2137 | set_bit(nr: buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, |
2138 | addr: recp->res_idxs); |
2139 | } |
2140 | |
2141 | /** |
2142 | * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries |
2143 | * @hw: pointer to hardware structure |
2144 | * @recps: struct that we need to populate |
2145 | * @rid: recipe ID that we are populating |
2146 | * @refresh_required: true if we should get recipe to profile mapping from FW |
2147 | * |
2148 | * This function is used to populate all the necessary entries into our |
2149 | * bookkeeping so that we have a current list of all the recipes that are |
2150 | * programmed in the firmware. |
2151 | */ |
2152 | static int |
2153 | ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, |
2154 | bool *refresh_required) |
2155 | { |
2156 | DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS); |
2157 | struct ice_aqc_recipe_data_elem *tmp; |
2158 | u16 num_recps = ICE_MAX_NUM_RECIPES; |
2159 | struct ice_prot_lkup_ext *lkup_exts; |
2160 | u8 fv_word_idx = 0; |
2161 | u16 sub_recps; |
2162 | int status; |
2163 | |
2164 | bitmap_zero(dst: result_bm, ICE_MAX_FV_WORDS); |
2165 | |
2166 | /* we need a buffer big enough to accommodate all the recipes */ |
2167 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, size: sizeof(*tmp), GFP_KERNEL); |
2168 | if (!tmp) |
2169 | return -ENOMEM; |
2170 | |
2171 | tmp[0].recipe_indx = rid; |
2172 | status = ice_aq_get_recipe(hw, s_recipe_list: tmp, num_recipes: &num_recps, recipe_root: rid, NULL); |
2173 | /* non-zero status meaning recipe doesn't exist */ |
2174 | if (status) |
2175 | goto err_unroll; |
2176 | |
2177 | /* Get recipe to profile map so that we can get the fv from lkups that |
2178 | * we read for a recipe from FW. Since we want to minimize the number of |
2179 | * times we make this FW call, just make one call and cache the copy |
2180 | * until a new recipe is added. This operation is only required the |
2181 | * first time to get the changes from FW. Then to search existing |
2182 | * entries we don't need to update the cache again until another recipe |
2183 | * gets added. |
2184 | */ |
2185 | if (*refresh_required) { |
2186 | ice_get_recp_to_prof_map(hw); |
2187 | *refresh_required = false; |
2188 | } |
2189 | |
2190 | /* Start populating all the entries for recps[rid] based on lkups from |
2191 | * firmware. Note that we are only creating the root recipe in our |
2192 | * database. |
2193 | */ |
2194 | lkup_exts = &recps[rid].lkup_exts; |
2195 | |
2196 | for (sub_recps = 0; sub_recps < num_recps; sub_recps++) { |
2197 | struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps]; |
2198 | struct ice_recp_grp_entry *rg_entry; |
2199 | u8 i, prof, idx, prot = 0; |
2200 | bool is_root; |
2201 | u16 off = 0; |
2202 | |
2203 | rg_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*rg_entry), |
2204 | GFP_KERNEL); |
2205 | if (!rg_entry) { |
2206 | status = -ENOMEM; |
2207 | goto err_unroll; |
2208 | } |
2209 | |
2210 | idx = root_bufs.recipe_indx; |
2211 | is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT; |
2212 | |
2213 | /* Mark all result indices in this chain */ |
2214 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) |
2215 | set_bit(nr: root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, |
2216 | addr: result_bm); |
2217 | |
2218 | /* get the first profile that is associated with rid */ |
2219 | prof = find_first_bit(addr: recipe_to_profile[idx], |
2220 | ICE_MAX_NUM_PROFILES); |
2221 | for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) { |
2222 | u8 lkup_indx = root_bufs.content.lkup_indx[i + 1]; |
2223 | |
2224 | rg_entry->fv_idx[i] = lkup_indx; |
2225 | rg_entry->fv_mask[i] = |
2226 | le16_to_cpu(root_bufs.content.mask[i + 1]); |
2227 | |
2228 | /* If the recipe is a chained recipe then all its |
2229 | * child recipe's result will have a result index. |
2230 | * To fill fv_words we should not use those result |
2231 | * index, we only need the protocol ids and offsets. |
2232 | * We will skip all the fv_idx which stores result |
2233 | * index in them. We also need to skip any fv_idx which |
2234 | * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a |
2235 | * valid offset value. |
2236 | */ |
2237 | if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) || |
2238 | rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE || |
2239 | rg_entry->fv_idx[i] == 0) |
2240 | continue; |
2241 | |
2242 | ice_find_prot_off(hw, blk: ICE_BLK_SW, prof, |
2243 | fv_idx: rg_entry->fv_idx[i], prot: &prot, off: &off); |
2244 | lkup_exts->fv_words[fv_word_idx].prot_id = prot; |
2245 | lkup_exts->fv_words[fv_word_idx].off = off; |
2246 | lkup_exts->field_mask[fv_word_idx] = |
2247 | rg_entry->fv_mask[i]; |
2248 | fv_word_idx++; |
2249 | } |
2250 | /* populate rg_list with the data from the child entry of this |
2251 | * recipe |
2252 | */ |
2253 | list_add(new: &rg_entry->l_entry, head: &recps[rid].rg_list); |
2254 | |
2255 | /* Propagate some data to the recipe database */ |
2256 | recps[idx].is_root = !!is_root; |
2257 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; |
2258 | recps[idx].need_pass_l2 = root_bufs.content.act_ctrl & |
2259 | ICE_AQ_RECIPE_ACT_NEED_PASS_L2; |
2260 | recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl & |
2261 | ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2; |
2262 | bitmap_zero(dst: recps[idx].res_idxs, ICE_MAX_FV_WORDS); |
2263 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) { |
2264 | recps[idx].chain_idx = root_bufs.content.result_indx & |
2265 | ~ICE_AQ_RECIPE_RESULT_EN; |
2266 | set_bit(nr: recps[idx].chain_idx, addr: recps[idx].res_idxs); |
2267 | } else { |
2268 | recps[idx].chain_idx = ICE_INVAL_CHAIN_IND; |
2269 | } |
2270 | |
2271 | if (!is_root) |
2272 | continue; |
2273 | |
2274 | /* Only do the following for root recipes entries */ |
2275 | memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap, |
2276 | sizeof(recps[idx].r_bitmap)); |
2277 | recps[idx].root_rid = root_bufs.content.rid & |
2278 | ~ICE_AQ_RECIPE_ID_IS_ROOT; |
2279 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; |
2280 | } |
2281 | |
2282 | /* Complete initialization of the root recipe entry */ |
2283 | lkup_exts->n_val_words = fv_word_idx; |
2284 | recps[rid].big_recp = (num_recps > 1); |
2285 | recps[rid].n_grp_count = (u8)num_recps; |
2286 | recps[rid].root_buf = devm_kmemdup(dev: ice_hw_to_dev(hw), src: tmp, |
2287 | len: recps[rid].n_grp_count * sizeof(*recps[rid].root_buf), |
2288 | GFP_KERNEL); |
2289 | if (!recps[rid].root_buf) { |
2290 | status = -ENOMEM; |
2291 | goto err_unroll; |
2292 | } |
2293 | |
2294 | /* Copy result indexes */ |
2295 | bitmap_copy(dst: recps[rid].res_idxs, src: result_bm, ICE_MAX_FV_WORDS); |
2296 | recps[rid].recp_created = true; |
2297 | |
2298 | err_unroll: |
2299 | kfree(objp: tmp); |
2300 | return status; |
2301 | } |
2302 | |
2303 | /* ice_init_port_info - Initialize port_info with switch configuration data |
2304 | * @pi: pointer to port_info |
2305 | * @vsi_port_num: VSI number or port number |
2306 | * @type: Type of switch element (port or VSI) |
2307 | * @swid: switch ID of the switch the element is attached to |
2308 | * @pf_vf_num: PF or VF number |
2309 | * @is_vf: true if the element is a VF, false otherwise |
2310 | */ |
2311 | static void |
2312 | ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type, |
2313 | u16 swid, u16 pf_vf_num, bool is_vf) |
2314 | { |
2315 | switch (type) { |
2316 | case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT: |
2317 | pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK); |
2318 | pi->sw_id = swid; |
2319 | pi->pf_vf_num = pf_vf_num; |
2320 | pi->is_vf = is_vf; |
2321 | break; |
2322 | default: |
2323 | ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n" ); |
2324 | break; |
2325 | } |
2326 | } |
2327 | |
2328 | /* ice_get_initial_sw_cfg - Get initial port and default VSI data |
2329 | * @hw: pointer to the hardware structure |
2330 | */ |
2331 | int ice_get_initial_sw_cfg(struct ice_hw *hw) |
2332 | { |
2333 | struct ice_aqc_get_sw_cfg_resp_elem *rbuf; |
2334 | u16 req_desc = 0; |
2335 | u16 num_elems; |
2336 | int status; |
2337 | u16 i; |
2338 | |
2339 | rbuf = kzalloc(ICE_SW_CFG_MAX_BUF_LEN, GFP_KERNEL); |
2340 | if (!rbuf) |
2341 | return -ENOMEM; |
2342 | |
2343 | /* Multiple calls to ice_aq_get_sw_cfg may be required |
2344 | * to get all the switch configuration information. The need |
2345 | * for additional calls is indicated by ice_aq_get_sw_cfg |
2346 | * writing a non-zero value in req_desc |
2347 | */ |
2348 | do { |
2349 | struct ice_aqc_get_sw_cfg_resp_elem *ele; |
2350 | |
2351 | status = ice_aq_get_sw_cfg(hw, buf: rbuf, ICE_SW_CFG_MAX_BUF_LEN, |
2352 | req_desc: &req_desc, num_elems: &num_elems, NULL); |
2353 | |
2354 | if (status) |
2355 | break; |
2356 | |
2357 | for (i = 0, ele = rbuf; i < num_elems; i++, ele++) { |
2358 | u16 pf_vf_num, swid, vsi_port_num; |
2359 | bool is_vf = false; |
2360 | u8 res_type; |
2361 | |
2362 | vsi_port_num = le16_to_cpu(ele->vsi_port_num) & |
2363 | ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M; |
2364 | |
2365 | pf_vf_num = le16_to_cpu(ele->pf_vf_num) & |
2366 | ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M; |
2367 | |
2368 | swid = le16_to_cpu(ele->swid); |
2369 | |
2370 | if (le16_to_cpu(ele->pf_vf_num) & |
2371 | ICE_AQC_GET_SW_CONF_RESP_IS_VF) |
2372 | is_vf = true; |
2373 | |
2374 | res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >> |
2375 | ICE_AQC_GET_SW_CONF_RESP_TYPE_S); |
2376 | |
2377 | if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) { |
2378 | /* FW VSI is not needed. Just continue. */ |
2379 | continue; |
2380 | } |
2381 | |
2382 | ice_init_port_info(pi: hw->port_info, vsi_port_num, |
2383 | type: res_type, swid, pf_vf_num, is_vf); |
2384 | } |
2385 | } while (req_desc && !status); |
2386 | |
2387 | kfree(objp: rbuf); |
2388 | return status; |
2389 | } |
2390 | |
2391 | /** |
2392 | * ice_fill_sw_info - Helper function to populate lb_en and lan_en |
2393 | * @hw: pointer to the hardware structure |
2394 | * @fi: filter info structure to fill/update |
2395 | * |
2396 | * This helper function populates the lb_en and lan_en elements of the provided |
2397 | * ice_fltr_info struct using the switch's type and characteristics of the |
2398 | * switch rule being configured. |
2399 | */ |
2400 | static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi) |
2401 | { |
2402 | fi->lb_en = false; |
2403 | fi->lan_en = false; |
2404 | if ((fi->flag & ICE_FLTR_TX) && |
2405 | (fi->fltr_act == ICE_FWD_TO_VSI || |
2406 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || |
2407 | fi->fltr_act == ICE_FWD_TO_Q || |
2408 | fi->fltr_act == ICE_FWD_TO_QGRP)) { |
2409 | /* Setting LB for prune actions will result in replicated |
2410 | * packets to the internal switch that will be dropped. |
2411 | */ |
2412 | if (fi->lkup_type != ICE_SW_LKUP_VLAN) |
2413 | fi->lb_en = true; |
2414 | |
2415 | /* Set lan_en to TRUE if |
2416 | * 1. The switch is a VEB AND |
2417 | * 2 |
2418 | * 2.1 The lookup is a directional lookup like ethertype, |
2419 | * promiscuous, ethertype-MAC, promiscuous-VLAN |
2420 | * and default-port OR |
2421 | * 2.2 The lookup is VLAN, OR |
2422 | * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR |
2423 | * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC. |
2424 | * |
2425 | * OR |
2426 | * |
2427 | * The switch is a VEPA. |
2428 | * |
2429 | * In all other cases, the LAN enable has to be set to false. |
2430 | */ |
2431 | if (hw->evb_veb) { |
2432 | if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE || |
2433 | fi->lkup_type == ICE_SW_LKUP_PROMISC || |
2434 | fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || |
2435 | fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
2436 | fi->lkup_type == ICE_SW_LKUP_DFLT || |
2437 | fi->lkup_type == ICE_SW_LKUP_VLAN || |
2438 | (fi->lkup_type == ICE_SW_LKUP_MAC && |
2439 | !is_unicast_ether_addr(addr: fi->l_data.mac.mac_addr)) || |
2440 | (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN && |
2441 | !is_unicast_ether_addr(addr: fi->l_data.mac.mac_addr))) |
2442 | fi->lan_en = true; |
2443 | } else { |
2444 | fi->lan_en = true; |
2445 | } |
2446 | } |
2447 | } |
2448 | |
2449 | /** |
2450 | * ice_fill_eth_hdr - helper to copy dummy_eth_hdr into supplied buffer |
2451 | * @eth_hdr: pointer to buffer to populate |
2452 | */ |
2453 | void ice_fill_eth_hdr(u8 *eth_hdr) |
2454 | { |
2455 | memcpy(eth_hdr, dummy_eth_header, DUMMY_ETH_HDR_LEN); |
2456 | } |
2457 | |
2458 | /** |
2459 | * ice_fill_sw_rule - Helper function to fill switch rule structure |
2460 | * @hw: pointer to the hardware structure |
2461 | * @f_info: entry containing packet forwarding information |
2462 | * @s_rule: switch rule structure to be filled in based on mac_entry |
2463 | * @opc: switch rules population command type - pass in the command opcode |
2464 | */ |
2465 | static void |
2466 | ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, |
2467 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
2468 | enum ice_adminq_opc opc) |
2469 | { |
2470 | u16 vlan_id = ICE_MAX_VLAN_ID + 1; |
2471 | u16 vlan_tpid = ETH_P_8021Q; |
2472 | void *daddr = NULL; |
2473 | u16 eth_hdr_sz; |
2474 | u8 *eth_hdr; |
2475 | u32 act = 0; |
2476 | __be16 *off; |
2477 | u8 q_rgn; |
2478 | |
2479 | if (opc == ice_aqc_opc_remove_sw_rules) { |
2480 | s_rule->act = 0; |
2481 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); |
2482 | s_rule->hdr_len = 0; |
2483 | return; |
2484 | } |
2485 | |
2486 | eth_hdr_sz = sizeof(dummy_eth_header); |
2487 | eth_hdr = s_rule->hdr_data; |
2488 | |
2489 | /* initialize the ether header with a dummy header */ |
2490 | memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); |
2491 | ice_fill_sw_info(hw, fi: f_info); |
2492 | |
2493 | switch (f_info->fltr_act) { |
2494 | case ICE_FWD_TO_VSI: |
2495 | act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & |
2496 | ICE_SINGLE_ACT_VSI_ID_M; |
2497 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) |
2498 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | |
2499 | ICE_SINGLE_ACT_VALID_BIT; |
2500 | break; |
2501 | case ICE_FWD_TO_VSI_LIST: |
2502 | act |= ICE_SINGLE_ACT_VSI_LIST; |
2503 | act |= (f_info->fwd_id.vsi_list_id << |
2504 | ICE_SINGLE_ACT_VSI_LIST_ID_S) & |
2505 | ICE_SINGLE_ACT_VSI_LIST_ID_M; |
2506 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) |
2507 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | |
2508 | ICE_SINGLE_ACT_VALID_BIT; |
2509 | break; |
2510 | case ICE_FWD_TO_Q: |
2511 | act |= ICE_SINGLE_ACT_TO_Q; |
2512 | act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & |
2513 | ICE_SINGLE_ACT_Q_INDEX_M; |
2514 | break; |
2515 | case ICE_DROP_PACKET: |
2516 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | |
2517 | ICE_SINGLE_ACT_VALID_BIT; |
2518 | break; |
2519 | case ICE_FWD_TO_QGRP: |
2520 | q_rgn = f_info->qgrp_size > 0 ? |
2521 | (u8)ilog2(f_info->qgrp_size) : 0; |
2522 | act |= ICE_SINGLE_ACT_TO_Q; |
2523 | act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & |
2524 | ICE_SINGLE_ACT_Q_INDEX_M; |
2525 | act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & |
2526 | ICE_SINGLE_ACT_Q_REGION_M; |
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 |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M; |
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 |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; |
2661 | lg_act->act[1] = cpu_to_le32(act); |
2662 | |
2663 | act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX << |
2664 | ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M; |
2665 | |
2666 | /* Third action Marker value */ |
2667 | act |= ICE_LG_ACT_GENERIC; |
2668 | act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) & |
2669 | ICE_LG_ACT_GENERIC_VALUE_M; |
2670 | |
2671 | lg_act->act[2] = cpu_to_le32(act); |
2672 | |
2673 | /* call the fill switch rule to fill the lookup Tx Rx structure */ |
2674 | ice_fill_sw_rule(hw, f_info: &m_ent->fltr_info, s_rule: rx_tx, |
2675 | opc: ice_aqc_opc_update_sw_rules); |
2676 | |
2677 | /* Update the action to point to the large action ID */ |
2678 | rx_tx->act = cpu_to_le32(ICE_SINGLE_ACT_PTR | |
2679 | ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) & |
2680 | ICE_SINGLE_ACT_PTR_VAL_M)); |
2681 | |
2682 | /* Use the filter rule ID of the previously created rule with single |
2683 | * act. Once the update happens, hardware will treat this as large |
2684 | * action |
2685 | */ |
2686 | rx_tx->index = cpu_to_le16(m_ent->fltr_info.fltr_rule_id); |
2687 | |
2688 | status = ice_aq_sw_rules(hw, rule_list: lg_act, rule_list_sz: rules_size, num_rules: 2, |
2689 | opc: ice_aqc_opc_update_sw_rules, NULL); |
2690 | if (!status) { |
2691 | m_ent->lg_act_idx = l_id; |
2692 | m_ent->sw_marker_id = sw_marker; |
2693 | } |
2694 | |
2695 | devm_kfree(dev: ice_hw_to_dev(hw), p: lg_act); |
2696 | return status; |
2697 | } |
2698 | |
2699 | /** |
2700 | * ice_create_vsi_list_map |
2701 | * @hw: pointer to the hardware structure |
2702 | * @vsi_handle_arr: array of VSI handles to set in the VSI mapping |
2703 | * @num_vsi: number of VSI handles in the array |
2704 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
2705 | * |
2706 | * Helper function to create a new entry of VSI list ID to VSI mapping |
2707 | * using the given VSI list ID |
2708 | */ |
2709 | static struct ice_vsi_list_map_info * |
2710 | ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2711 | u16 vsi_list_id) |
2712 | { |
2713 | struct ice_switch_info *sw = hw->switch_info; |
2714 | struct ice_vsi_list_map_info *v_map; |
2715 | int i; |
2716 | |
2717 | v_map = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*v_map), GFP_KERNEL); |
2718 | if (!v_map) |
2719 | return NULL; |
2720 | |
2721 | v_map->vsi_list_id = vsi_list_id; |
2722 | v_map->ref_cnt = 1; |
2723 | for (i = 0; i < num_vsi; i++) |
2724 | set_bit(nr: vsi_handle_arr[i], addr: v_map->vsi_map); |
2725 | |
2726 | list_add(new: &v_map->list_entry, head: &sw->vsi_list_map_head); |
2727 | return v_map; |
2728 | } |
2729 | |
2730 | /** |
2731 | * ice_update_vsi_list_rule |
2732 | * @hw: pointer to the hardware structure |
2733 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2734 | * @num_vsi: number of VSI handles in the array |
2735 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
2736 | * @remove: Boolean value to indicate if this is a remove action |
2737 | * @opc: switch rules population command type - pass in the command opcode |
2738 | * @lkup_type: lookup type of the filter |
2739 | * |
2740 | * Call AQ command to add a new switch rule or update existing switch rule |
2741 | * using the given VSI list ID |
2742 | */ |
2743 | static int |
2744 | ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2745 | u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, |
2746 | enum ice_sw_lkup_type lkup_type) |
2747 | { |
2748 | struct ice_sw_rule_vsi_list *s_rule; |
2749 | u16 s_rule_size; |
2750 | u16 rule_type; |
2751 | int status; |
2752 | int i; |
2753 | |
2754 | if (!num_vsi) |
2755 | return -EINVAL; |
2756 | |
2757 | if (lkup_type == ICE_SW_LKUP_MAC || |
2758 | lkup_type == ICE_SW_LKUP_MAC_VLAN || |
2759 | lkup_type == ICE_SW_LKUP_ETHERTYPE || |
2760 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || |
2761 | lkup_type == ICE_SW_LKUP_PROMISC || |
2762 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
2763 | lkup_type == ICE_SW_LKUP_DFLT) |
2764 | rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR : |
2765 | ICE_AQC_SW_RULES_T_VSI_LIST_SET; |
2766 | else if (lkup_type == ICE_SW_LKUP_VLAN) |
2767 | rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR : |
2768 | ICE_AQC_SW_RULES_T_PRUNE_LIST_SET; |
2769 | else |
2770 | return -EINVAL; |
2771 | |
2772 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi); |
2773 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), size: s_rule_size, GFP_KERNEL); |
2774 | if (!s_rule) |
2775 | return -ENOMEM; |
2776 | for (i = 0; i < num_vsi; i++) { |
2777 | if (!ice_is_vsi_valid(hw, vsi_handle: vsi_handle_arr[i])) { |
2778 | status = -EINVAL; |
2779 | goto exit; |
2780 | } |
2781 | /* AQ call requires hw_vsi_id(s) */ |
2782 | s_rule->vsi[i] = |
2783 | cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); |
2784 | } |
2785 | |
2786 | s_rule->hdr.type = cpu_to_le16(rule_type); |
2787 | s_rule->number_vsi = cpu_to_le16(num_vsi); |
2788 | s_rule->index = cpu_to_le16(vsi_list_id); |
2789 | |
2790 | status = ice_aq_sw_rules(hw, rule_list: s_rule, rule_list_sz: s_rule_size, num_rules: 1, opc, NULL); |
2791 | |
2792 | exit: |
2793 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2794 | return status; |
2795 | } |
2796 | |
2797 | /** |
2798 | * ice_create_vsi_list_rule - Creates and populates a VSI list rule |
2799 | * @hw: pointer to the HW struct |
2800 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2801 | * @num_vsi: number of VSI handles in the array |
2802 | * @vsi_list_id: stores the ID of the VSI list to be created |
2803 | * @lkup_type: switch rule filter's lookup type |
2804 | */ |
2805 | static int |
2806 | ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
2807 | u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) |
2808 | { |
2809 | int status; |
2810 | |
2811 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, |
2812 | opc: ice_aqc_opc_alloc_res); |
2813 | if (status) |
2814 | return status; |
2815 | |
2816 | /* Update the newly created VSI list to include the specified VSIs */ |
2817 | return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, |
2818 | vsi_list_id: *vsi_list_id, remove: false, |
2819 | opc: ice_aqc_opc_add_sw_rules, lkup_type); |
2820 | } |
2821 | |
2822 | /** |
2823 | * ice_create_pkt_fwd_rule |
2824 | * @hw: pointer to the hardware structure |
2825 | * @f_entry: entry containing packet forwarding information |
2826 | * |
2827 | * Create switch rule with given filter information and add an entry |
2828 | * to the corresponding filter management list to track this switch rule |
2829 | * and VSI mapping |
2830 | */ |
2831 | static int |
2832 | ice_create_pkt_fwd_rule(struct ice_hw *hw, |
2833 | struct ice_fltr_list_entry *f_entry) |
2834 | { |
2835 | struct ice_fltr_mgmt_list_entry *fm_entry; |
2836 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
2837 | enum ice_sw_lkup_type l_type; |
2838 | struct ice_sw_recipe *recp; |
2839 | int status; |
2840 | |
2841 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
2842 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2843 | GFP_KERNEL); |
2844 | if (!s_rule) |
2845 | return -ENOMEM; |
2846 | fm_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*fm_entry), |
2847 | GFP_KERNEL); |
2848 | if (!fm_entry) { |
2849 | status = -ENOMEM; |
2850 | goto ice_create_pkt_fwd_rule_exit; |
2851 | } |
2852 | |
2853 | fm_entry->fltr_info = f_entry->fltr_info; |
2854 | |
2855 | /* Initialize all the fields for the management entry */ |
2856 | fm_entry->vsi_count = 1; |
2857 | fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX; |
2858 | fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID; |
2859 | fm_entry->counter_index = ICE_INVAL_COUNTER_ID; |
2860 | |
2861 | ice_fill_sw_rule(hw, f_info: &fm_entry->fltr_info, s_rule, |
2862 | opc: ice_aqc_opc_add_sw_rules); |
2863 | |
2864 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
2865 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), num_rules: 1, |
2866 | opc: ice_aqc_opc_add_sw_rules, NULL); |
2867 | if (status) { |
2868 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
2869 | goto ice_create_pkt_fwd_rule_exit; |
2870 | } |
2871 | |
2872 | f_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
2873 | fm_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
2874 | |
2875 | /* The book keeping entries will get removed when base driver |
2876 | * calls remove filter AQ command |
2877 | */ |
2878 | l_type = fm_entry->fltr_info.lkup_type; |
2879 | recp = &hw->switch_info->recp_list[l_type]; |
2880 | list_add(new: &fm_entry->list_entry, head: &recp->filt_rules); |
2881 | |
2882 | ice_create_pkt_fwd_rule_exit: |
2883 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2884 | return status; |
2885 | } |
2886 | |
2887 | /** |
2888 | * ice_update_pkt_fwd_rule |
2889 | * @hw: pointer to the hardware structure |
2890 | * @f_info: filter information for switch rule |
2891 | * |
2892 | * Call AQ command to update a previously created switch rule with a |
2893 | * VSI list ID |
2894 | */ |
2895 | static int |
2896 | ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) |
2897 | { |
2898 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
2899 | int status; |
2900 | |
2901 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
2902 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2903 | GFP_KERNEL); |
2904 | if (!s_rule) |
2905 | return -ENOMEM; |
2906 | |
2907 | ice_fill_sw_rule(hw, f_info, s_rule, opc: ice_aqc_opc_update_sw_rules); |
2908 | |
2909 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); |
2910 | |
2911 | /* Update switch rule with new rule set to forward VSI list */ |
2912 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
2913 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), num_rules: 1, |
2914 | opc: ice_aqc_opc_update_sw_rules, NULL); |
2915 | |
2916 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
2917 | return status; |
2918 | } |
2919 | |
2920 | /** |
2921 | * ice_update_sw_rule_bridge_mode |
2922 | * @hw: pointer to the HW struct |
2923 | * |
2924 | * Updates unicast switch filter rules based on VEB/VEPA mode |
2925 | */ |
2926 | int ice_update_sw_rule_bridge_mode(struct ice_hw *hw) |
2927 | { |
2928 | struct ice_switch_info *sw = hw->switch_info; |
2929 | struct ice_fltr_mgmt_list_entry *fm_entry; |
2930 | struct list_head *rule_head; |
2931 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
2932 | int status = 0; |
2933 | |
2934 | rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; |
2935 | rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; |
2936 | |
2937 | mutex_lock(rule_lock); |
2938 | list_for_each_entry(fm_entry, rule_head, list_entry) { |
2939 | struct ice_fltr_info *fi = &fm_entry->fltr_info; |
2940 | u8 *addr = fi->l_data.mac.mac_addr; |
2941 | |
2942 | /* Update unicast Tx rules to reflect the selected |
2943 | * VEB/VEPA mode |
2944 | */ |
2945 | if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) && |
2946 | (fi->fltr_act == ICE_FWD_TO_VSI || |
2947 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || |
2948 | fi->fltr_act == ICE_FWD_TO_Q || |
2949 | fi->fltr_act == ICE_FWD_TO_QGRP)) { |
2950 | status = ice_update_pkt_fwd_rule(hw, f_info: fi); |
2951 | if (status) |
2952 | break; |
2953 | } |
2954 | } |
2955 | |
2956 | mutex_unlock(lock: rule_lock); |
2957 | |
2958 | return status; |
2959 | } |
2960 | |
2961 | /** |
2962 | * ice_add_update_vsi_list |
2963 | * @hw: pointer to the hardware structure |
2964 | * @m_entry: pointer to current filter management list entry |
2965 | * @cur_fltr: filter information from the book keeping entry |
2966 | * @new_fltr: filter information with the new VSI to be added |
2967 | * |
2968 | * Call AQ command to add or update previously created VSI list with new VSI. |
2969 | * |
2970 | * Helper function to do book keeping associated with adding filter information |
2971 | * The algorithm to do the book keeping is described below : |
2972 | * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.) |
2973 | * if only one VSI has been added till now |
2974 | * Allocate a new VSI list and add two VSIs |
2975 | * to this list using switch rule command |
2976 | * Update the previously created switch rule with the |
2977 | * newly created VSI list ID |
2978 | * if a VSI list was previously created |
2979 | * Add the new VSI to the previously created VSI list set |
2980 | * using the update switch rule command |
2981 | */ |
2982 | static int |
2983 | ice_add_update_vsi_list(struct ice_hw *hw, |
2984 | struct ice_fltr_mgmt_list_entry *m_entry, |
2985 | struct ice_fltr_info *cur_fltr, |
2986 | struct ice_fltr_info *new_fltr) |
2987 | { |
2988 | u16 vsi_list_id = 0; |
2989 | int status = 0; |
2990 | |
2991 | if ((cur_fltr->fltr_act == ICE_FWD_TO_Q || |
2992 | cur_fltr->fltr_act == ICE_FWD_TO_QGRP)) |
2993 | return -EOPNOTSUPP; |
2994 | |
2995 | if ((new_fltr->fltr_act == ICE_FWD_TO_Q || |
2996 | new_fltr->fltr_act == ICE_FWD_TO_QGRP) && |
2997 | (cur_fltr->fltr_act == ICE_FWD_TO_VSI || |
2998 | cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST)) |
2999 | return -EOPNOTSUPP; |
3000 | |
3001 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { |
3002 | /* Only one entry existed in the mapping and it was not already |
3003 | * a part of a VSI list. So, create a VSI list with the old and |
3004 | * new VSIs. |
3005 | */ |
3006 | struct ice_fltr_info tmp_fltr; |
3007 | u16 vsi_handle_arr[2]; |
3008 | |
3009 | /* A rule already exists with the new VSI being added */ |
3010 | if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) |
3011 | return -EEXIST; |
3012 | |
3013 | vsi_handle_arr[0] = cur_fltr->vsi_handle; |
3014 | vsi_handle_arr[1] = new_fltr->vsi_handle; |
3015 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3016 | vsi_list_id: &vsi_list_id, |
3017 | lkup_type: new_fltr->lkup_type); |
3018 | if (status) |
3019 | return status; |
3020 | |
3021 | tmp_fltr = *new_fltr; |
3022 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; |
3023 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
3024 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
3025 | /* Update the previous switch rule of "MAC forward to VSI" to |
3026 | * "MAC fwd to VSI list" |
3027 | */ |
3028 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
3029 | if (status) |
3030 | return status; |
3031 | |
3032 | cur_fltr->fwd_id.vsi_list_id = vsi_list_id; |
3033 | cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; |
3034 | m_entry->vsi_list_info = |
3035 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3036 | vsi_list_id); |
3037 | |
3038 | if (!m_entry->vsi_list_info) |
3039 | return -ENOMEM; |
3040 | |
3041 | /* If this entry was large action then the large action needs |
3042 | * to be updated to point to FWD to VSI list |
3043 | */ |
3044 | if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) |
3045 | status = |
3046 | ice_add_marker_act(hw, m_ent: m_entry, |
3047 | sw_marker: m_entry->sw_marker_id, |
3048 | l_id: m_entry->lg_act_idx); |
3049 | } else { |
3050 | u16 vsi_handle = new_fltr->vsi_handle; |
3051 | enum ice_adminq_opc opcode; |
3052 | |
3053 | if (!m_entry->vsi_list_info) |
3054 | return -EIO; |
3055 | |
3056 | /* A rule already exists with the new VSI being added */ |
3057 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) |
3058 | return 0; |
3059 | |
3060 | /* Update the previously created VSI list set with |
3061 | * the new VSI ID passed in |
3062 | */ |
3063 | vsi_list_id = cur_fltr->fwd_id.vsi_list_id; |
3064 | opcode = ice_aqc_opc_update_sw_rules; |
3065 | |
3066 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, |
3067 | vsi_list_id, remove: false, opc: opcode, |
3068 | lkup_type: new_fltr->lkup_type); |
3069 | /* update VSI list mapping info with new VSI ID */ |
3070 | if (!status) |
3071 | set_bit(nr: vsi_handle, addr: m_entry->vsi_list_info->vsi_map); |
3072 | } |
3073 | if (!status) |
3074 | m_entry->vsi_count++; |
3075 | return status; |
3076 | } |
3077 | |
3078 | /** |
3079 | * ice_find_rule_entry - Search a rule entry |
3080 | * @hw: pointer to the hardware structure |
3081 | * @recp_id: lookup type for which the specified rule needs to be searched |
3082 | * @f_info: rule information |
3083 | * |
3084 | * Helper function to search for a given rule entry |
3085 | * Returns pointer to entry storing the rule if found |
3086 | */ |
3087 | static struct ice_fltr_mgmt_list_entry * |
3088 | ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) |
3089 | { |
3090 | struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL; |
3091 | struct ice_switch_info *sw = hw->switch_info; |
3092 | struct list_head *list_head; |
3093 | |
3094 | list_head = &sw->recp_list[recp_id].filt_rules; |
3095 | list_for_each_entry(list_itr, list_head, list_entry) { |
3096 | if (!memcmp(p: &f_info->l_data, q: &list_itr->fltr_info.l_data, |
3097 | size: sizeof(f_info->l_data)) && |
3098 | f_info->flag == list_itr->fltr_info.flag) { |
3099 | ret = list_itr; |
3100 | break; |
3101 | } |
3102 | } |
3103 | return ret; |
3104 | } |
3105 | |
3106 | /** |
3107 | * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 |
3108 | * @hw: pointer to the hardware structure |
3109 | * @recp_id: lookup type for which VSI lists needs to be searched |
3110 | * @vsi_handle: VSI handle to be found in VSI list |
3111 | * @vsi_list_id: VSI list ID found containing vsi_handle |
3112 | * |
3113 | * Helper function to search a VSI list with single entry containing given VSI |
3114 | * handle element. This can be extended further to search VSI list with more |
3115 | * than 1 vsi_count. Returns pointer to VSI list entry if found. |
3116 | */ |
3117 | struct ice_vsi_list_map_info * |
3118 | ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, |
3119 | u16 *vsi_list_id) |
3120 | { |
3121 | struct ice_vsi_list_map_info *map_info = NULL; |
3122 | struct ice_switch_info *sw = hw->switch_info; |
3123 | struct ice_fltr_mgmt_list_entry *list_itr; |
3124 | struct list_head *list_head; |
3125 | |
3126 | list_head = &sw->recp_list[recp_id].filt_rules; |
3127 | list_for_each_entry(list_itr, list_head, list_entry) { |
3128 | if (list_itr->vsi_list_info) { |
3129 | map_info = list_itr->vsi_list_info; |
3130 | if (test_bit(vsi_handle, map_info->vsi_map)) { |
3131 | *vsi_list_id = map_info->vsi_list_id; |
3132 | return map_info; |
3133 | } |
3134 | } |
3135 | } |
3136 | return NULL; |
3137 | } |
3138 | |
3139 | /** |
3140 | * ice_add_rule_internal - add rule for a given lookup type |
3141 | * @hw: pointer to the hardware structure |
3142 | * @recp_id: lookup type (recipe ID) for which rule has to be added |
3143 | * @f_entry: structure containing MAC forwarding information |
3144 | * |
3145 | * Adds or updates the rule lists for a given recipe |
3146 | */ |
3147 | static int |
3148 | ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, |
3149 | struct ice_fltr_list_entry *f_entry) |
3150 | { |
3151 | struct ice_switch_info *sw = hw->switch_info; |
3152 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3153 | struct ice_fltr_mgmt_list_entry *m_entry; |
3154 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3155 | int status = 0; |
3156 | |
3157 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3158 | return -EINVAL; |
3159 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3160 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3161 | |
3162 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; |
3163 | |
3164 | mutex_lock(rule_lock); |
3165 | new_fltr = &f_entry->fltr_info; |
3166 | if (new_fltr->flag & ICE_FLTR_RX) |
3167 | new_fltr->src = hw->port_info->lport; |
3168 | else if (new_fltr->flag & ICE_FLTR_TX) |
3169 | new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; |
3170 | |
3171 | m_entry = ice_find_rule_entry(hw, recp_id, f_info: new_fltr); |
3172 | if (!m_entry) { |
3173 | mutex_unlock(lock: rule_lock); |
3174 | return ice_create_pkt_fwd_rule(hw, f_entry); |
3175 | } |
3176 | |
3177 | cur_fltr = &m_entry->fltr_info; |
3178 | status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr); |
3179 | mutex_unlock(lock: rule_lock); |
3180 | |
3181 | return status; |
3182 | } |
3183 | |
3184 | /** |
3185 | * ice_remove_vsi_list_rule |
3186 | * @hw: pointer to the hardware structure |
3187 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
3188 | * @lkup_type: switch rule filter lookup type |
3189 | * |
3190 | * The VSI list should be emptied before this function is called to remove the |
3191 | * VSI list. |
3192 | */ |
3193 | static int |
3194 | ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, |
3195 | enum ice_sw_lkup_type lkup_type) |
3196 | { |
3197 | struct ice_sw_rule_vsi_list *s_rule; |
3198 | u16 s_rule_size; |
3199 | int status; |
3200 | |
3201 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, 0); |
3202 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), size: s_rule_size, GFP_KERNEL); |
3203 | if (!s_rule) |
3204 | return -ENOMEM; |
3205 | |
3206 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); |
3207 | s_rule->index = cpu_to_le16(vsi_list_id); |
3208 | |
3209 | /* Free the vsi_list resource that we allocated. It is assumed that the |
3210 | * list is empty at this point. |
3211 | */ |
3212 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id: &vsi_list_id, lkup_type, |
3213 | opc: ice_aqc_opc_free_res); |
3214 | |
3215 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
3216 | return status; |
3217 | } |
3218 | |
3219 | /** |
3220 | * ice_rem_update_vsi_list |
3221 | * @hw: pointer to the hardware structure |
3222 | * @vsi_handle: VSI handle of the VSI to remove |
3223 | * @fm_list: filter management entry for which the VSI list management needs to |
3224 | * be done |
3225 | */ |
3226 | static int |
3227 | ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
3228 | struct ice_fltr_mgmt_list_entry *fm_list) |
3229 | { |
3230 | enum ice_sw_lkup_type lkup_type; |
3231 | u16 vsi_list_id; |
3232 | int status = 0; |
3233 | |
3234 | if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST || |
3235 | fm_list->vsi_count == 0) |
3236 | return -EINVAL; |
3237 | |
3238 | /* A rule with the VSI being removed does not exist */ |
3239 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) |
3240 | return -ENOENT; |
3241 | |
3242 | lkup_type = fm_list->fltr_info.lkup_type; |
3243 | vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; |
3244 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, vsi_list_id, remove: true, |
3245 | opc: ice_aqc_opc_update_sw_rules, |
3246 | lkup_type); |
3247 | if (status) |
3248 | return status; |
3249 | |
3250 | fm_list->vsi_count--; |
3251 | clear_bit(nr: vsi_handle, addr: fm_list->vsi_list_info->vsi_map); |
3252 | |
3253 | if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) { |
3254 | struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info; |
3255 | struct ice_vsi_list_map_info *vsi_list_info = |
3256 | fm_list->vsi_list_info; |
3257 | u16 rem_vsi_handle; |
3258 | |
3259 | rem_vsi_handle = find_first_bit(addr: vsi_list_info->vsi_map, |
3260 | ICE_MAX_VSI); |
3261 | if (!ice_is_vsi_valid(hw, vsi_handle: rem_vsi_handle)) |
3262 | return -EIO; |
3263 | |
3264 | /* Make sure VSI list is empty before removing it below */ |
3265 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &rem_vsi_handle, num_vsi: 1, |
3266 | vsi_list_id, remove: true, |
3267 | opc: ice_aqc_opc_update_sw_rules, |
3268 | lkup_type); |
3269 | if (status) |
3270 | return status; |
3271 | |
3272 | tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI; |
3273 | tmp_fltr_info.fwd_id.hw_vsi_id = |
3274 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
3275 | tmp_fltr_info.vsi_handle = rem_vsi_handle; |
3276 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr_info); |
3277 | if (status) { |
3278 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n" , |
3279 | tmp_fltr_info.fwd_id.hw_vsi_id, status); |
3280 | return status; |
3281 | } |
3282 | |
3283 | fm_list->fltr_info = tmp_fltr_info; |
3284 | } |
3285 | |
3286 | if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || |
3287 | (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { |
3288 | struct ice_vsi_list_map_info *vsi_list_info = |
3289 | fm_list->vsi_list_info; |
3290 | |
3291 | /* Remove the VSI list since it is no longer used */ |
3292 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); |
3293 | if (status) { |
3294 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n" , |
3295 | vsi_list_id, status); |
3296 | return status; |
3297 | } |
3298 | |
3299 | list_del(entry: &vsi_list_info->list_entry); |
3300 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi_list_info); |
3301 | fm_list->vsi_list_info = NULL; |
3302 | } |
3303 | |
3304 | return status; |
3305 | } |
3306 | |
3307 | /** |
3308 | * ice_remove_rule_internal - Remove a filter rule of a given type |
3309 | * @hw: pointer to the hardware structure |
3310 | * @recp_id: recipe ID for which the rule needs to removed |
3311 | * @f_entry: rule entry containing filter information |
3312 | */ |
3313 | static int |
3314 | ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, |
3315 | struct ice_fltr_list_entry *f_entry) |
3316 | { |
3317 | struct ice_switch_info *sw = hw->switch_info; |
3318 | struct ice_fltr_mgmt_list_entry *list_elem; |
3319 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3320 | bool remove_rule = false; |
3321 | u16 vsi_handle; |
3322 | int status = 0; |
3323 | |
3324 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3325 | return -EINVAL; |
3326 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3327 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3328 | |
3329 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; |
3330 | mutex_lock(rule_lock); |
3331 | list_elem = ice_find_rule_entry(hw, recp_id, f_info: &f_entry->fltr_info); |
3332 | if (!list_elem) { |
3333 | status = -ENOENT; |
3334 | goto exit; |
3335 | } |
3336 | |
3337 | if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { |
3338 | remove_rule = true; |
3339 | } else if (!list_elem->vsi_list_info) { |
3340 | status = -ENOENT; |
3341 | goto exit; |
3342 | } else if (list_elem->vsi_list_info->ref_cnt > 1) { |
3343 | /* a ref_cnt > 1 indicates that the vsi_list is being |
3344 | * shared by multiple rules. Decrement the ref_cnt and |
3345 | * remove this rule, but do not modify the list, as it |
3346 | * is in-use by other rules. |
3347 | */ |
3348 | list_elem->vsi_list_info->ref_cnt--; |
3349 | remove_rule = true; |
3350 | } else { |
3351 | /* a ref_cnt of 1 indicates the vsi_list is only used |
3352 | * by one rule. However, the original removal request is only |
3353 | * for a single VSI. Update the vsi_list first, and only |
3354 | * remove the rule if there are no further VSIs in this list. |
3355 | */ |
3356 | vsi_handle = f_entry->fltr_info.vsi_handle; |
3357 | status = ice_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
3358 | if (status) |
3359 | goto exit; |
3360 | /* if VSI count goes to zero after updating the VSI list */ |
3361 | if (list_elem->vsi_count == 0) |
3362 | remove_rule = true; |
3363 | } |
3364 | |
3365 | if (remove_rule) { |
3366 | /* Remove the lookup rule */ |
3367 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
3368 | |
3369 | s_rule = devm_kzalloc(dev: ice_hw_to_dev(hw), |
3370 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
3371 | GFP_KERNEL); |
3372 | if (!s_rule) { |
3373 | status = -ENOMEM; |
3374 | goto exit; |
3375 | } |
3376 | |
3377 | ice_fill_sw_rule(hw, f_info: &list_elem->fltr_info, s_rule, |
3378 | opc: ice_aqc_opc_remove_sw_rules); |
3379 | |
3380 | status = ice_aq_sw_rules(hw, rule_list: s_rule, |
3381 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
3382 | num_rules: 1, opc: ice_aqc_opc_remove_sw_rules, NULL); |
3383 | |
3384 | /* Remove a book keeping from the list */ |
3385 | devm_kfree(dev: ice_hw_to_dev(hw), p: s_rule); |
3386 | |
3387 | if (status) |
3388 | goto exit; |
3389 | |
3390 | list_del(entry: &list_elem->list_entry); |
3391 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem); |
3392 | } |
3393 | exit: |
3394 | mutex_unlock(lock: rule_lock); |
3395 | return status; |
3396 | } |
3397 | |
3398 | /** |
3399 | * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI |
3400 | * @hw: pointer to the hardware structure |
3401 | * @vlan_id: VLAN ID |
3402 | * @vsi_handle: check MAC filter for this VSI |
3403 | */ |
3404 | bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle) |
3405 | { |
3406 | struct ice_fltr_mgmt_list_entry *entry; |
3407 | struct list_head *rule_head; |
3408 | struct ice_switch_info *sw; |
3409 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3410 | u16 hw_vsi_id; |
3411 | |
3412 | if (vlan_id > ICE_MAX_VLAN_ID) |
3413 | return false; |
3414 | |
3415 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3416 | return false; |
3417 | |
3418 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3419 | sw = hw->switch_info; |
3420 | rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; |
3421 | if (!rule_head) |
3422 | return false; |
3423 | |
3424 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
3425 | mutex_lock(rule_lock); |
3426 | list_for_each_entry(entry, rule_head, list_entry) { |
3427 | struct ice_fltr_info *f_info = &entry->fltr_info; |
3428 | u16 entry_vlan_id = f_info->l_data.vlan.vlan_id; |
3429 | struct ice_vsi_list_map_info *map_info; |
3430 | |
3431 | if (entry_vlan_id > ICE_MAX_VLAN_ID) |
3432 | continue; |
3433 | |
3434 | if (f_info->flag != ICE_FLTR_TX || |
3435 | f_info->src_id != ICE_SRC_ID_VSI || |
3436 | f_info->lkup_type != ICE_SW_LKUP_VLAN) |
3437 | continue; |
3438 | |
3439 | /* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */ |
3440 | if (f_info->fltr_act != ICE_FWD_TO_VSI && |
3441 | f_info->fltr_act != ICE_FWD_TO_VSI_LIST) |
3442 | continue; |
3443 | |
3444 | if (f_info->fltr_act == ICE_FWD_TO_VSI) { |
3445 | if (hw_vsi_id != f_info->fwd_id.hw_vsi_id) |
3446 | continue; |
3447 | } else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { |
3448 | /* If filter_action is FWD_TO_VSI_LIST, make sure |
3449 | * that VSI being checked is part of VSI list |
3450 | */ |
3451 | if (entry->vsi_count == 1 && |
3452 | entry->vsi_list_info) { |
3453 | map_info = entry->vsi_list_info; |
3454 | if (!test_bit(vsi_handle, map_info->vsi_map)) |
3455 | continue; |
3456 | } |
3457 | } |
3458 | |
3459 | if (vlan_id == entry_vlan_id) { |
3460 | mutex_unlock(lock: rule_lock); |
3461 | return true; |
3462 | } |
3463 | } |
3464 | mutex_unlock(lock: rule_lock); |
3465 | |
3466 | return false; |
3467 | } |
3468 | |
3469 | /** |
3470 | * ice_add_mac - Add a MAC address based filter rule |
3471 | * @hw: pointer to the hardware structure |
3472 | * @m_list: list of MAC addresses and forwarding information |
3473 | */ |
3474 | int ice_add_mac(struct ice_hw *hw, struct list_head *m_list) |
3475 | { |
3476 | struct ice_fltr_list_entry *m_list_itr; |
3477 | int status = 0; |
3478 | |
3479 | if (!m_list || !hw) |
3480 | return -EINVAL; |
3481 | |
3482 | list_for_each_entry(m_list_itr, m_list, list_entry) { |
3483 | u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; |
3484 | u16 vsi_handle; |
3485 | u16 hw_vsi_id; |
3486 | |
3487 | m_list_itr->fltr_info.flag = ICE_FLTR_TX; |
3488 | vsi_handle = m_list_itr->fltr_info.vsi_handle; |
3489 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3490 | return -EINVAL; |
3491 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3492 | m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; |
3493 | /* update the src in case it is VSI num */ |
3494 | if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) |
3495 | return -EINVAL; |
3496 | m_list_itr->fltr_info.src = hw_vsi_id; |
3497 | if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || |
3498 | is_zero_ether_addr(addr: add)) |
3499 | return -EINVAL; |
3500 | |
3501 | m_list_itr->status = ice_add_rule_internal(hw, recp_id: ICE_SW_LKUP_MAC, |
3502 | f_entry: m_list_itr); |
3503 | if (m_list_itr->status) |
3504 | return m_list_itr->status; |
3505 | } |
3506 | |
3507 | return status; |
3508 | } |
3509 | |
3510 | /** |
3511 | * ice_add_vlan_internal - Add one VLAN based filter rule |
3512 | * @hw: pointer to the hardware structure |
3513 | * @f_entry: filter entry containing one VLAN information |
3514 | */ |
3515 | static int |
3516 | ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) |
3517 | { |
3518 | struct ice_switch_info *sw = hw->switch_info; |
3519 | struct ice_fltr_mgmt_list_entry *v_list_itr; |
3520 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3521 | enum ice_sw_lkup_type lkup_type; |
3522 | u16 vsi_list_id = 0, vsi_handle; |
3523 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3524 | int status = 0; |
3525 | |
3526 | if (!ice_is_vsi_valid(hw, vsi_handle: f_entry->fltr_info.vsi_handle)) |
3527 | return -EINVAL; |
3528 | |
3529 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3530 | ice_get_hw_vsi_num(hw, vsi_handle: f_entry->fltr_info.vsi_handle); |
3531 | new_fltr = &f_entry->fltr_info; |
3532 | |
3533 | /* VLAN ID should only be 12 bits */ |
3534 | if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) |
3535 | return -EINVAL; |
3536 | |
3537 | if (new_fltr->src_id != ICE_SRC_ID_VSI) |
3538 | return -EINVAL; |
3539 | |
3540 | new_fltr->src = new_fltr->fwd_id.hw_vsi_id; |
3541 | lkup_type = new_fltr->lkup_type; |
3542 | vsi_handle = new_fltr->vsi_handle; |
3543 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
3544 | mutex_lock(rule_lock); |
3545 | v_list_itr = ice_find_rule_entry(hw, recp_id: ICE_SW_LKUP_VLAN, f_info: new_fltr); |
3546 | if (!v_list_itr) { |
3547 | struct ice_vsi_list_map_info *map_info = NULL; |
3548 | |
3549 | if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { |
3550 | /* All VLAN pruning rules use a VSI list. Check if |
3551 | * there is already a VSI list containing VSI that we |
3552 | * want to add. If found, use the same vsi_list_id for |
3553 | * this new VLAN rule or else create a new list. |
3554 | */ |
3555 | map_info = ice_find_vsi_list_entry(hw, recp_id: ICE_SW_LKUP_VLAN, |
3556 | vsi_handle, |
3557 | vsi_list_id: &vsi_list_id); |
3558 | if (!map_info) { |
3559 | status = ice_create_vsi_list_rule(hw, |
3560 | vsi_handle_arr: &vsi_handle, |
3561 | num_vsi: 1, |
3562 | vsi_list_id: &vsi_list_id, |
3563 | lkup_type); |
3564 | if (status) |
3565 | goto exit; |
3566 | } |
3567 | /* Convert the action to forwarding to a VSI list. */ |
3568 | new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; |
3569 | new_fltr->fwd_id.vsi_list_id = vsi_list_id; |
3570 | } |
3571 | |
3572 | status = ice_create_pkt_fwd_rule(hw, f_entry); |
3573 | if (!status) { |
3574 | v_list_itr = ice_find_rule_entry(hw, recp_id: ICE_SW_LKUP_VLAN, |
3575 | f_info: new_fltr); |
3576 | if (!v_list_itr) { |
3577 | status = -ENOENT; |
3578 | goto exit; |
3579 | } |
3580 | /* reuse VSI list for new rule and increment ref_cnt */ |
3581 | if (map_info) { |
3582 | v_list_itr->vsi_list_info = map_info; |
3583 | map_info->ref_cnt++; |
3584 | } else { |
3585 | v_list_itr->vsi_list_info = |
3586 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle, |
3587 | num_vsi: 1, vsi_list_id); |
3588 | } |
3589 | } |
3590 | } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { |
3591 | /* Update existing VSI list to add new VSI ID only if it used |
3592 | * by one VLAN rule. |
3593 | */ |
3594 | cur_fltr = &v_list_itr->fltr_info; |
3595 | status = ice_add_update_vsi_list(hw, m_entry: v_list_itr, cur_fltr, |
3596 | new_fltr); |
3597 | } else { |
3598 | /* If VLAN rule exists and VSI list being used by this rule is |
3599 | * referenced by more than 1 VLAN rule. Then create a new VSI |
3600 | * list appending previous VSI with new VSI and update existing |
3601 | * VLAN rule to point to new VSI list ID |
3602 | */ |
3603 | struct ice_fltr_info tmp_fltr; |
3604 | u16 vsi_handle_arr[2]; |
3605 | u16 cur_handle; |
3606 | |
3607 | /* Current implementation only supports reusing VSI list with |
3608 | * one VSI count. We should never hit below condition |
3609 | */ |
3610 | if (v_list_itr->vsi_count > 1 && |
3611 | v_list_itr->vsi_list_info->ref_cnt > 1) { |
3612 | ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n" ); |
3613 | status = -EIO; |
3614 | goto exit; |
3615 | } |
3616 | |
3617 | cur_handle = |
3618 | find_first_bit(addr: v_list_itr->vsi_list_info->vsi_map, |
3619 | ICE_MAX_VSI); |
3620 | |
3621 | /* A rule already exists with the new VSI being added */ |
3622 | if (cur_handle == vsi_handle) { |
3623 | status = -EEXIST; |
3624 | goto exit; |
3625 | } |
3626 | |
3627 | vsi_handle_arr[0] = cur_handle; |
3628 | vsi_handle_arr[1] = vsi_handle; |
3629 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3630 | vsi_list_id: &vsi_list_id, lkup_type); |
3631 | if (status) |
3632 | goto exit; |
3633 | |
3634 | tmp_fltr = v_list_itr->fltr_info; |
3635 | tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; |
3636 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
3637 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
3638 | /* Update the previous switch rule to a new VSI list which |
3639 | * includes current VSI that is requested |
3640 | */ |
3641 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
3642 | if (status) |
3643 | goto exit; |
3644 | |
3645 | /* before overriding VSI list map info. decrement ref_cnt of |
3646 | * previous VSI list |
3647 | */ |
3648 | v_list_itr->vsi_list_info->ref_cnt--; |
3649 | |
3650 | /* now update to newly created list */ |
3651 | v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; |
3652 | v_list_itr->vsi_list_info = |
3653 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
3654 | vsi_list_id); |
3655 | v_list_itr->vsi_count++; |
3656 | } |
3657 | |
3658 | exit: |
3659 | mutex_unlock(lock: rule_lock); |
3660 | return status; |
3661 | } |
3662 | |
3663 | /** |
3664 | * ice_add_vlan - Add VLAN based filter rule |
3665 | * @hw: pointer to the hardware structure |
3666 | * @v_list: list of VLAN entries and forwarding information |
3667 | */ |
3668 | int ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) |
3669 | { |
3670 | struct ice_fltr_list_entry *v_list_itr; |
3671 | |
3672 | if (!v_list || !hw) |
3673 | return -EINVAL; |
3674 | |
3675 | list_for_each_entry(v_list_itr, v_list, list_entry) { |
3676 | if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) |
3677 | return -EINVAL; |
3678 | v_list_itr->fltr_info.flag = ICE_FLTR_TX; |
3679 | v_list_itr->status = ice_add_vlan_internal(hw, f_entry: v_list_itr); |
3680 | if (v_list_itr->status) |
3681 | return v_list_itr->status; |
3682 | } |
3683 | return 0; |
3684 | } |
3685 | |
3686 | /** |
3687 | * ice_add_eth_mac - Add ethertype and MAC based filter rule |
3688 | * @hw: pointer to the hardware structure |
3689 | * @em_list: list of ether type MAC filter, MAC is optional |
3690 | * |
3691 | * This function requires the caller to populate the entries in |
3692 | * the filter list with the necessary fields (including flags to |
3693 | * indicate Tx or Rx rules). |
3694 | */ |
3695 | int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
3696 | { |
3697 | struct ice_fltr_list_entry *em_list_itr; |
3698 | |
3699 | if (!em_list || !hw) |
3700 | return -EINVAL; |
3701 | |
3702 | list_for_each_entry(em_list_itr, em_list, list_entry) { |
3703 | enum ice_sw_lkup_type l_type = |
3704 | em_list_itr->fltr_info.lkup_type; |
3705 | |
3706 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && |
3707 | l_type != ICE_SW_LKUP_ETHERTYPE) |
3708 | return -EINVAL; |
3709 | |
3710 | em_list_itr->status = ice_add_rule_internal(hw, recp_id: l_type, |
3711 | f_entry: em_list_itr); |
3712 | if (em_list_itr->status) |
3713 | return em_list_itr->status; |
3714 | } |
3715 | return 0; |
3716 | } |
3717 | |
3718 | /** |
3719 | * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule |
3720 | * @hw: pointer to the hardware structure |
3721 | * @em_list: list of ethertype or ethertype MAC entries |
3722 | */ |
3723 | int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
3724 | { |
3725 | struct ice_fltr_list_entry *em_list_itr, *tmp; |
3726 | |
3727 | if (!em_list || !hw) |
3728 | return -EINVAL; |
3729 | |
3730 | list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { |
3731 | enum ice_sw_lkup_type l_type = |
3732 | em_list_itr->fltr_info.lkup_type; |
3733 | |
3734 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && |
3735 | l_type != ICE_SW_LKUP_ETHERTYPE) |
3736 | return -EINVAL; |
3737 | |
3738 | em_list_itr->status = ice_remove_rule_internal(hw, recp_id: l_type, |
3739 | f_entry: em_list_itr); |
3740 | if (em_list_itr->status) |
3741 | return em_list_itr->status; |
3742 | } |
3743 | return 0; |
3744 | } |
3745 | |
3746 | /** |
3747 | * ice_rem_sw_rule_info |
3748 | * @hw: pointer to the hardware structure |
3749 | * @rule_head: pointer to the switch list structure that we want to delete |
3750 | */ |
3751 | static void |
3752 | ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) |
3753 | { |
3754 | if (!list_empty(head: rule_head)) { |
3755 | struct ice_fltr_mgmt_list_entry *entry; |
3756 | struct ice_fltr_mgmt_list_entry *tmp; |
3757 | |
3758 | list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { |
3759 | list_del(entry: &entry->list_entry); |
3760 | devm_kfree(dev: ice_hw_to_dev(hw), p: entry); |
3761 | } |
3762 | } |
3763 | } |
3764 | |
3765 | /** |
3766 | * ice_rem_adv_rule_info |
3767 | * @hw: pointer to the hardware structure |
3768 | * @rule_head: pointer to the switch list structure that we want to delete |
3769 | */ |
3770 | static void |
3771 | ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head) |
3772 | { |
3773 | struct ice_adv_fltr_mgmt_list_entry *tmp_entry; |
3774 | struct ice_adv_fltr_mgmt_list_entry *lst_itr; |
3775 | |
3776 | if (list_empty(head: rule_head)) |
3777 | return; |
3778 | |
3779 | list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) { |
3780 | list_del(entry: &lst_itr->list_entry); |
3781 | devm_kfree(dev: ice_hw_to_dev(hw), p: lst_itr->lkups); |
3782 | devm_kfree(dev: ice_hw_to_dev(hw), p: lst_itr); |
3783 | } |
3784 | } |
3785 | |
3786 | /** |
3787 | * ice_cfg_dflt_vsi - change state of VSI to set/clear default |
3788 | * @pi: pointer to the port_info structure |
3789 | * @vsi_handle: VSI handle to set as default |
3790 | * @set: true to add the above mentioned switch rule, false to remove it |
3791 | * @direction: ICE_FLTR_RX or ICE_FLTR_TX |
3792 | * |
3793 | * add filter rule to set/unset given VSI as default VSI for the switch |
3794 | * (represented by swid) |
3795 | */ |
3796 | int |
3797 | ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set, |
3798 | u8 direction) |
3799 | { |
3800 | struct ice_fltr_list_entry f_list_entry; |
3801 | struct ice_fltr_info f_info; |
3802 | struct ice_hw *hw = pi->hw; |
3803 | u16 hw_vsi_id; |
3804 | int status; |
3805 | |
3806 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3807 | return -EINVAL; |
3808 | |
3809 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3810 | |
3811 | memset(&f_info, 0, sizeof(f_info)); |
3812 | |
3813 | f_info.lkup_type = ICE_SW_LKUP_DFLT; |
3814 | f_info.flag = direction; |
3815 | f_info.fltr_act = ICE_FWD_TO_VSI; |
3816 | f_info.fwd_id.hw_vsi_id = hw_vsi_id; |
3817 | f_info.vsi_handle = vsi_handle; |
3818 | |
3819 | if (f_info.flag & ICE_FLTR_RX) { |
3820 | f_info.src = hw->port_info->lport; |
3821 | f_info.src_id = ICE_SRC_ID_LPORT; |
3822 | } else if (f_info.flag & ICE_FLTR_TX) { |
3823 | f_info.src_id = ICE_SRC_ID_VSI; |
3824 | f_info.src = hw_vsi_id; |
3825 | } |
3826 | f_list_entry.fltr_info = f_info; |
3827 | |
3828 | if (set) |
3829 | status = ice_add_rule_internal(hw, recp_id: ICE_SW_LKUP_DFLT, |
3830 | f_entry: &f_list_entry); |
3831 | else |
3832 | status = ice_remove_rule_internal(hw, recp_id: ICE_SW_LKUP_DFLT, |
3833 | f_entry: &f_list_entry); |
3834 | |
3835 | return status; |
3836 | } |
3837 | |
3838 | /** |
3839 | * ice_vsi_uses_fltr - Determine if given VSI uses specified filter |
3840 | * @fm_entry: filter entry to inspect |
3841 | * @vsi_handle: VSI handle to compare with filter info |
3842 | */ |
3843 | static bool |
3844 | ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) |
3845 | { |
3846 | return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && |
3847 | fm_entry->fltr_info.vsi_handle == vsi_handle) || |
3848 | (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && |
3849 | fm_entry->vsi_list_info && |
3850 | (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); |
3851 | } |
3852 | |
3853 | /** |
3854 | * ice_check_if_dflt_vsi - check if VSI is default VSI |
3855 | * @pi: pointer to the port_info structure |
3856 | * @vsi_handle: vsi handle to check for in filter list |
3857 | * @rule_exists: indicates if there are any VSI's in the rule list |
3858 | * |
3859 | * checks if the VSI is in a default VSI list, and also indicates |
3860 | * if the default VSI list is empty |
3861 | */ |
3862 | bool |
3863 | ice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, |
3864 | bool *rule_exists) |
3865 | { |
3866 | struct ice_fltr_mgmt_list_entry *fm_entry; |
3867 | struct ice_sw_recipe *recp_list; |
3868 | struct list_head *rule_head; |
3869 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
3870 | bool ret = false; |
3871 | |
3872 | recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT]; |
3873 | rule_lock = &recp_list->filt_rule_lock; |
3874 | rule_head = &recp_list->filt_rules; |
3875 | |
3876 | mutex_lock(rule_lock); |
3877 | |
3878 | if (rule_exists && !list_empty(head: rule_head)) |
3879 | *rule_exists = true; |
3880 | |
3881 | list_for_each_entry(fm_entry, rule_head, list_entry) { |
3882 | if (ice_vsi_uses_fltr(fm_entry, vsi_handle)) { |
3883 | ret = true; |
3884 | break; |
3885 | } |
3886 | } |
3887 | |
3888 | mutex_unlock(lock: rule_lock); |
3889 | |
3890 | return ret; |
3891 | } |
3892 | |
3893 | /** |
3894 | * ice_remove_mac - remove a MAC address based filter rule |
3895 | * @hw: pointer to the hardware structure |
3896 | * @m_list: list of MAC addresses and forwarding information |
3897 | * |
3898 | * This function removes either a MAC filter rule or a specific VSI from a |
3899 | * VSI list for a multicast MAC address. |
3900 | * |
3901 | * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should |
3902 | * be aware that this call will only work if all the entries passed into m_list |
3903 | * were added previously. It will not attempt to do a partial remove of entries |
3904 | * that were found. |
3905 | */ |
3906 | int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) |
3907 | { |
3908 | struct ice_fltr_list_entry *list_itr, *tmp; |
3909 | |
3910 | if (!m_list) |
3911 | return -EINVAL; |
3912 | |
3913 | list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { |
3914 | enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; |
3915 | u16 vsi_handle; |
3916 | |
3917 | if (l_type != ICE_SW_LKUP_MAC) |
3918 | return -EINVAL; |
3919 | |
3920 | vsi_handle = list_itr->fltr_info.vsi_handle; |
3921 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
3922 | return -EINVAL; |
3923 | |
3924 | list_itr->fltr_info.fwd_id.hw_vsi_id = |
3925 | ice_get_hw_vsi_num(hw, vsi_handle); |
3926 | |
3927 | list_itr->status = ice_remove_rule_internal(hw, |
3928 | recp_id: ICE_SW_LKUP_MAC, |
3929 | f_entry: list_itr); |
3930 | if (list_itr->status) |
3931 | return list_itr->status; |
3932 | } |
3933 | return 0; |
3934 | } |
3935 | |
3936 | /** |
3937 | * ice_remove_vlan - Remove VLAN based filter rule |
3938 | * @hw: pointer to the hardware structure |
3939 | * @v_list: list of VLAN entries and forwarding information |
3940 | */ |
3941 | int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) |
3942 | { |
3943 | struct ice_fltr_list_entry *v_list_itr, *tmp; |
3944 | |
3945 | if (!v_list || !hw) |
3946 | return -EINVAL; |
3947 | |
3948 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { |
3949 | enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; |
3950 | |
3951 | if (l_type != ICE_SW_LKUP_VLAN) |
3952 | return -EINVAL; |
3953 | v_list_itr->status = ice_remove_rule_internal(hw, |
3954 | recp_id: ICE_SW_LKUP_VLAN, |
3955 | f_entry: v_list_itr); |
3956 | if (v_list_itr->status) |
3957 | return v_list_itr->status; |
3958 | } |
3959 | return 0; |
3960 | } |
3961 | |
3962 | /** |
3963 | * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list |
3964 | * @hw: pointer to the hardware structure |
3965 | * @vsi_handle: VSI handle to remove filters from |
3966 | * @vsi_list_head: pointer to the list to add entry to |
3967 | * @fi: pointer to fltr_info of filter entry to copy & add |
3968 | * |
3969 | * Helper function, used when creating a list of filters to remove from |
3970 | * a specific VSI. The entry added to vsi_list_head is a COPY of the |
3971 | * original filter entry, with the exception of fltr_info.fltr_act and |
3972 | * fltr_info.fwd_id fields. These are set such that later logic can |
3973 | * extract which VSI to remove the fltr from, and pass on that information. |
3974 | */ |
3975 | static int |
3976 | ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
3977 | struct list_head *vsi_list_head, |
3978 | struct ice_fltr_info *fi) |
3979 | { |
3980 | struct ice_fltr_list_entry *tmp; |
3981 | |
3982 | /* this memory is freed up in the caller function |
3983 | * once filters for this VSI are removed |
3984 | */ |
3985 | tmp = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*tmp), GFP_KERNEL); |
3986 | if (!tmp) |
3987 | return -ENOMEM; |
3988 | |
3989 | tmp->fltr_info = *fi; |
3990 | |
3991 | /* Overwrite these fields to indicate which VSI to remove filter from, |
3992 | * so find and remove logic can extract the information from the |
3993 | * list entries. Note that original entries will still have proper |
3994 | * values. |
3995 | */ |
3996 | tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; |
3997 | tmp->fltr_info.vsi_handle = vsi_handle; |
3998 | tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3999 | |
4000 | list_add(new: &tmp->list_entry, head: vsi_list_head); |
4001 | |
4002 | return 0; |
4003 | } |
4004 | |
4005 | /** |
4006 | * ice_add_to_vsi_fltr_list - Add VSI filters to the list |
4007 | * @hw: pointer to the hardware structure |
4008 | * @vsi_handle: VSI handle to remove filters from |
4009 | * @lkup_list_head: pointer to the list that has certain lookup type filters |
4010 | * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle |
4011 | * |
4012 | * Locates all filters in lkup_list_head that are used by the given VSI, |
4013 | * and adds COPIES of those entries to vsi_list_head (intended to be used |
4014 | * to remove the listed filters). |
4015 | * Note that this means all entries in vsi_list_head must be explicitly |
4016 | * deallocated by the caller when done with list. |
4017 | */ |
4018 | static int |
4019 | ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
4020 | struct list_head *lkup_list_head, |
4021 | struct list_head *vsi_list_head) |
4022 | { |
4023 | struct ice_fltr_mgmt_list_entry *fm_entry; |
4024 | int status = 0; |
4025 | |
4026 | /* check to make sure VSI ID is valid and within boundary */ |
4027 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4028 | return -EINVAL; |
4029 | |
4030 | list_for_each_entry(fm_entry, lkup_list_head, list_entry) { |
4031 | if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) |
4032 | continue; |
4033 | |
4034 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, |
4035 | vsi_list_head, |
4036 | fi: &fm_entry->fltr_info); |
4037 | if (status) |
4038 | return status; |
4039 | } |
4040 | return status; |
4041 | } |
4042 | |
4043 | /** |
4044 | * ice_determine_promisc_mask |
4045 | * @fi: filter info to parse |
4046 | * |
4047 | * Helper function to determine which ICE_PROMISC_ mask corresponds |
4048 | * to given filter into. |
4049 | */ |
4050 | static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) |
4051 | { |
4052 | u16 vid = fi->l_data.mac_vlan.vlan_id; |
4053 | u8 *macaddr = fi->l_data.mac.mac_addr; |
4054 | bool is_tx_fltr = false; |
4055 | u8 promisc_mask = 0; |
4056 | |
4057 | if (fi->flag == ICE_FLTR_TX) |
4058 | is_tx_fltr = true; |
4059 | |
4060 | if (is_broadcast_ether_addr(addr: macaddr)) |
4061 | promisc_mask |= is_tx_fltr ? |
4062 | ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; |
4063 | else if (is_multicast_ether_addr(addr: macaddr)) |
4064 | promisc_mask |= is_tx_fltr ? |
4065 | ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; |
4066 | else if (is_unicast_ether_addr(addr: macaddr)) |
4067 | promisc_mask |= is_tx_fltr ? |
4068 | ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; |
4069 | if (vid) |
4070 | promisc_mask |= is_tx_fltr ? |
4071 | ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; |
4072 | |
4073 | return promisc_mask; |
4074 | } |
4075 | |
4076 | /** |
4077 | * ice_remove_promisc - Remove promisc based filter rules |
4078 | * @hw: pointer to the hardware structure |
4079 | * @recp_id: recipe ID for which the rule needs to removed |
4080 | * @v_list: list of promisc entries |
4081 | */ |
4082 | static int |
4083 | ice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list) |
4084 | { |
4085 | struct ice_fltr_list_entry *v_list_itr, *tmp; |
4086 | |
4087 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { |
4088 | v_list_itr->status = |
4089 | ice_remove_rule_internal(hw, recp_id, f_entry: v_list_itr); |
4090 | if (v_list_itr->status) |
4091 | return v_list_itr->status; |
4092 | } |
4093 | return 0; |
4094 | } |
4095 | |
4096 | /** |
4097 | * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI |
4098 | * @hw: pointer to the hardware structure |
4099 | * @vsi_handle: VSI handle to clear mode |
4100 | * @promisc_mask: mask of promiscuous config bits to clear |
4101 | * @vid: VLAN ID to clear VLAN promiscuous |
4102 | */ |
4103 | int |
4104 | ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4105 | u16 vid) |
4106 | { |
4107 | struct ice_switch_info *sw = hw->switch_info; |
4108 | struct ice_fltr_list_entry *fm_entry, *tmp; |
4109 | struct list_head remove_list_head; |
4110 | struct ice_fltr_mgmt_list_entry *itr; |
4111 | struct list_head *rule_head; |
4112 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
4113 | int status = 0; |
4114 | u8 recipe_id; |
4115 | |
4116 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4117 | return -EINVAL; |
4118 | |
4119 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) |
4120 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; |
4121 | else |
4122 | recipe_id = ICE_SW_LKUP_PROMISC; |
4123 | |
4124 | rule_head = &sw->recp_list[recipe_id].filt_rules; |
4125 | rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; |
4126 | |
4127 | INIT_LIST_HEAD(list: &remove_list_head); |
4128 | |
4129 | mutex_lock(rule_lock); |
4130 | list_for_each_entry(itr, rule_head, list_entry) { |
4131 | struct ice_fltr_info *fltr_info; |
4132 | u8 fltr_promisc_mask = 0; |
4133 | |
4134 | if (!ice_vsi_uses_fltr(fm_entry: itr, vsi_handle)) |
4135 | continue; |
4136 | fltr_info = &itr->fltr_info; |
4137 | |
4138 | if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && |
4139 | vid != fltr_info->l_data.mac_vlan.vlan_id) |
4140 | continue; |
4141 | |
4142 | fltr_promisc_mask |= ice_determine_promisc_mask(fi: fltr_info); |
4143 | |
4144 | /* Skip if filter is not completely specified by given mask */ |
4145 | if (fltr_promisc_mask & ~promisc_mask) |
4146 | continue; |
4147 | |
4148 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, |
4149 | vsi_list_head: &remove_list_head, |
4150 | fi: fltr_info); |
4151 | if (status) { |
4152 | mutex_unlock(lock: rule_lock); |
4153 | goto free_fltr_list; |
4154 | } |
4155 | } |
4156 | mutex_unlock(lock: rule_lock); |
4157 | |
4158 | status = ice_remove_promisc(hw, recp_id: recipe_id, v_list: &remove_list_head); |
4159 | |
4160 | free_fltr_list: |
4161 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { |
4162 | list_del(entry: &fm_entry->list_entry); |
4163 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
4164 | } |
4165 | |
4166 | return status; |
4167 | } |
4168 | |
4169 | /** |
4170 | * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) |
4171 | * @hw: pointer to the hardware structure |
4172 | * @vsi_handle: VSI handle to configure |
4173 | * @promisc_mask: mask of promiscuous config bits |
4174 | * @vid: VLAN ID to set VLAN promiscuous |
4175 | */ |
4176 | int |
4177 | ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) |
4178 | { |
4179 | enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; |
4180 | struct ice_fltr_list_entry f_list_entry; |
4181 | struct ice_fltr_info new_fltr; |
4182 | bool is_tx_fltr; |
4183 | int status = 0; |
4184 | u16 hw_vsi_id; |
4185 | int pkt_type; |
4186 | u8 recipe_id; |
4187 | |
4188 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
4189 | return -EINVAL; |
4190 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
4191 | |
4192 | memset(&new_fltr, 0, sizeof(new_fltr)); |
4193 | |
4194 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { |
4195 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; |
4196 | new_fltr.l_data.mac_vlan.vlan_id = vid; |
4197 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; |
4198 | } else { |
4199 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; |
4200 | recipe_id = ICE_SW_LKUP_PROMISC; |
4201 | } |
4202 | |
4203 | /* Separate filters must be set for each direction/packet type |
4204 | * combination, so we will loop over the mask value, store the |
4205 | * individual type, and clear it out in the input mask as it |
4206 | * is found. |
4207 | */ |
4208 | while (promisc_mask) { |
4209 | u8 *mac_addr; |
4210 | |
4211 | pkt_type = 0; |
4212 | is_tx_fltr = false; |
4213 | |
4214 | if (promisc_mask & ICE_PROMISC_UCAST_RX) { |
4215 | promisc_mask &= ~ICE_PROMISC_UCAST_RX; |
4216 | pkt_type = UCAST_FLTR; |
4217 | } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { |
4218 | promisc_mask &= ~ICE_PROMISC_UCAST_TX; |
4219 | pkt_type = UCAST_FLTR; |
4220 | is_tx_fltr = true; |
4221 | } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { |
4222 | promisc_mask &= ~ICE_PROMISC_MCAST_RX; |
4223 | pkt_type = MCAST_FLTR; |
4224 | } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { |
4225 | promisc_mask &= ~ICE_PROMISC_MCAST_TX; |
4226 | pkt_type = MCAST_FLTR; |
4227 | is_tx_fltr = true; |
4228 | } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { |
4229 | promisc_mask &= ~ICE_PROMISC_BCAST_RX; |
4230 | pkt_type = BCAST_FLTR; |
4231 | } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { |
4232 | promisc_mask &= ~ICE_PROMISC_BCAST_TX; |
4233 | pkt_type = BCAST_FLTR; |
4234 | is_tx_fltr = true; |
4235 | } |
4236 | |
4237 | /* Check for VLAN promiscuous flag */ |
4238 | if (promisc_mask & ICE_PROMISC_VLAN_RX) { |
4239 | promisc_mask &= ~ICE_PROMISC_VLAN_RX; |
4240 | } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { |
4241 | promisc_mask &= ~ICE_PROMISC_VLAN_TX; |
4242 | is_tx_fltr = true; |
4243 | } |
4244 | |
4245 | /* Set filter DA based on packet type */ |
4246 | mac_addr = new_fltr.l_data.mac.mac_addr; |
4247 | if (pkt_type == BCAST_FLTR) { |
4248 | eth_broadcast_addr(addr: mac_addr); |
4249 | } else if (pkt_type == MCAST_FLTR || |
4250 | pkt_type == UCAST_FLTR) { |
4251 | /* Use the dummy ether header DA */ |
4252 | ether_addr_copy(dst: mac_addr, src: dummy_eth_header); |
4253 | if (pkt_type == MCAST_FLTR) |
4254 | mac_addr[0] |= 0x1; /* Set multicast bit */ |
4255 | } |
4256 | |
4257 | /* Need to reset this to zero for all iterations */ |
4258 | new_fltr.flag = 0; |
4259 | if (is_tx_fltr) { |
4260 | new_fltr.flag |= ICE_FLTR_TX; |
4261 | new_fltr.src = hw_vsi_id; |
4262 | } else { |
4263 | new_fltr.flag |= ICE_FLTR_RX; |
4264 | new_fltr.src = hw->port_info->lport; |
4265 | } |
4266 | |
4267 | new_fltr.fltr_act = ICE_FWD_TO_VSI; |
4268 | new_fltr.vsi_handle = vsi_handle; |
4269 | new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; |
4270 | f_list_entry.fltr_info = new_fltr; |
4271 | |
4272 | status = ice_add_rule_internal(hw, recp_id: recipe_id, f_entry: &f_list_entry); |
4273 | if (status) |
4274 | goto set_promisc_exit; |
4275 | } |
4276 | |
4277 | set_promisc_exit: |
4278 | return status; |
4279 | } |
4280 | |
4281 | /** |
4282 | * ice_set_vlan_vsi_promisc |
4283 | * @hw: pointer to the hardware structure |
4284 | * @vsi_handle: VSI handle to configure |
4285 | * @promisc_mask: mask of promiscuous config bits |
4286 | * @rm_vlan_promisc: Clear VLANs VSI promisc mode |
4287 | * |
4288 | * Configure VSI with all associated VLANs to given promiscuous mode(s) |
4289 | */ |
4290 | int |
4291 | ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4292 | bool rm_vlan_promisc) |
4293 | { |
4294 | struct ice_switch_info *sw = hw->switch_info; |
4295 | struct ice_fltr_list_entry *list_itr, *tmp; |
4296 | struct list_head vsi_list_head; |
4297 | struct list_head *vlan_head; |
4298 | struct mutex *vlan_lock; /* Lock to protect filter rule list */ |
4299 | u16 vlan_id; |
4300 | int status; |
4301 | |
4302 | INIT_LIST_HEAD(list: &vsi_list_head); |
4303 | vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
4304 | vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; |
4305 | mutex_lock(vlan_lock); |
4306 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, lkup_list_head: vlan_head, |
4307 | vsi_list_head: &vsi_list_head); |
4308 | mutex_unlock(lock: vlan_lock); |
4309 | if (status) |
4310 | goto free_fltr_list; |
4311 | |
4312 | list_for_each_entry(list_itr, &vsi_list_head, list_entry) { |
4313 | /* Avoid enabling or disabling VLAN zero twice when in double |
4314 | * VLAN mode |
4315 | */ |
4316 | if (ice_is_dvm_ena(hw) && |
4317 | list_itr->fltr_info.l_data.vlan.tpid == 0) |
4318 | continue; |
4319 | |
4320 | vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; |
4321 | if (rm_vlan_promisc) |
4322 | status = ice_clear_vsi_promisc(hw, vsi_handle, |
4323 | promisc_mask, vid: vlan_id); |
4324 | else |
4325 | status = ice_set_vsi_promisc(hw, vsi_handle, |
4326 | promisc_mask, vid: vlan_id); |
4327 | if (status && status != -EEXIST) |
4328 | break; |
4329 | } |
4330 | |
4331 | free_fltr_list: |
4332 | list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { |
4333 | list_del(entry: &list_itr->list_entry); |
4334 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_itr); |
4335 | } |
4336 | return status; |
4337 | } |
4338 | |
4339 | /** |
4340 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI |
4341 | * @hw: pointer to the hardware structure |
4342 | * @vsi_handle: VSI handle to remove filters from |
4343 | * @lkup: switch rule filter lookup type |
4344 | */ |
4345 | static void |
4346 | ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, |
4347 | enum ice_sw_lkup_type lkup) |
4348 | { |
4349 | struct ice_switch_info *sw = hw->switch_info; |
4350 | struct ice_fltr_list_entry *fm_entry; |
4351 | struct list_head remove_list_head; |
4352 | struct list_head *rule_head; |
4353 | struct ice_fltr_list_entry *tmp; |
4354 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
4355 | int status; |
4356 | |
4357 | INIT_LIST_HEAD(list: &remove_list_head); |
4358 | rule_lock = &sw->recp_list[lkup].filt_rule_lock; |
4359 | rule_head = &sw->recp_list[lkup].filt_rules; |
4360 | mutex_lock(rule_lock); |
4361 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, lkup_list_head: rule_head, |
4362 | vsi_list_head: &remove_list_head); |
4363 | mutex_unlock(lock: rule_lock); |
4364 | if (status) |
4365 | goto free_fltr_list; |
4366 | |
4367 | switch (lkup) { |
4368 | case ICE_SW_LKUP_MAC: |
4369 | ice_remove_mac(hw, m_list: &remove_list_head); |
4370 | break; |
4371 | case ICE_SW_LKUP_VLAN: |
4372 | ice_remove_vlan(hw, v_list: &remove_list_head); |
4373 | break; |
4374 | case ICE_SW_LKUP_PROMISC: |
4375 | case ICE_SW_LKUP_PROMISC_VLAN: |
4376 | ice_remove_promisc(hw, recp_id: lkup, v_list: &remove_list_head); |
4377 | break; |
4378 | case ICE_SW_LKUP_MAC_VLAN: |
4379 | case ICE_SW_LKUP_ETHERTYPE: |
4380 | case ICE_SW_LKUP_ETHERTYPE_MAC: |
4381 | case ICE_SW_LKUP_DFLT: |
4382 | case ICE_SW_LKUP_LAST: |
4383 | default: |
4384 | ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n" , lkup); |
4385 | break; |
4386 | } |
4387 | |
4388 | free_fltr_list: |
4389 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { |
4390 | list_del(entry: &fm_entry->list_entry); |
4391 | devm_kfree(dev: ice_hw_to_dev(hw), p: fm_entry); |
4392 | } |
4393 | } |
4394 | |
4395 | /** |
4396 | * ice_remove_vsi_fltr - Remove all filters for a VSI |
4397 | * @hw: pointer to the hardware structure |
4398 | * @vsi_handle: VSI handle to remove filters from |
4399 | */ |
4400 | void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) |
4401 | { |
4402 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_MAC); |
4403 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_MAC_VLAN); |
4404 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_PROMISC); |
4405 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_VLAN); |
4406 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_DFLT); |
4407 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_ETHERTYPE); |
4408 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_ETHERTYPE_MAC); |
4409 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, lkup: ICE_SW_LKUP_PROMISC_VLAN); |
4410 | } |
4411 | |
4412 | /** |
4413 | * ice_alloc_res_cntr - allocating resource counter |
4414 | * @hw: pointer to the hardware structure |
4415 | * @type: type of resource |
4416 | * @alloc_shared: if set it is shared else dedicated |
4417 | * @num_items: number of entries requested for FD resource type |
4418 | * @counter_id: counter index returned by AQ call |
4419 | */ |
4420 | int |
4421 | ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4422 | u16 *counter_id) |
4423 | { |
4424 | DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4425 | u16 buf_len = __struct_size(buf); |
4426 | int status; |
4427 | |
4428 | buf->num_elems = cpu_to_le16(num_items); |
4429 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & |
4430 | ICE_AQC_RES_TYPE_M) | alloc_shared); |
4431 | |
4432 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, opc: ice_aqc_opc_alloc_res); |
4433 | if (status) |
4434 | return status; |
4435 | |
4436 | *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp); |
4437 | return status; |
4438 | } |
4439 | |
4440 | /** |
4441 | * ice_free_res_cntr - free resource counter |
4442 | * @hw: pointer to the hardware structure |
4443 | * @type: type of resource |
4444 | * @alloc_shared: if set it is shared else dedicated |
4445 | * @num_items: number of entries to be freed for FD resource type |
4446 | * @counter_id: counter ID resource which needs to be freed |
4447 | */ |
4448 | int |
4449 | ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4450 | u16 counter_id) |
4451 | { |
4452 | DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4453 | u16 buf_len = __struct_size(buf); |
4454 | int status; |
4455 | |
4456 | buf->num_elems = cpu_to_le16(num_items); |
4457 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & |
4458 | ICE_AQC_RES_TYPE_M) | alloc_shared); |
4459 | buf->elem[0].e.sw_resp = cpu_to_le16(counter_id); |
4460 | |
4461 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, opc: ice_aqc_opc_free_res); |
4462 | if (status) |
4463 | ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n" ); |
4464 | |
4465 | return status; |
4466 | } |
4467 | |
4468 | #define ICE_PROTOCOL_ENTRY(id, ...) { \ |
4469 | .prot_type = id, \ |
4470 | .offs = {__VA_ARGS__}, \ |
4471 | } |
4472 | |
4473 | /** |
4474 | * ice_share_res - set a resource as shared or dedicated |
4475 | * @hw: hw struct of original owner of resource |
4476 | * @type: resource type |
4477 | * @shared: is the resource being set to shared |
4478 | * @res_id: resource id (descriptor) |
4479 | */ |
4480 | int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id) |
4481 | { |
4482 | DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1); |
4483 | u16 buf_len = __struct_size(buf); |
4484 | int status; |
4485 | |
4486 | buf->num_elems = cpu_to_le16(1); |
4487 | if (shared) |
4488 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & |
4489 | ICE_AQC_RES_TYPE_M) | |
4490 | ICE_AQC_RES_TYPE_FLAG_SHARED); |
4491 | else |
4492 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & |
4493 | ICE_AQC_RES_TYPE_M) & |
4494 | ~ICE_AQC_RES_TYPE_FLAG_SHARED); |
4495 | |
4496 | buf->elem[0].e.sw_resp = cpu_to_le16(res_id); |
4497 | status = ice_aq_alloc_free_res(hw, buf, buf_size: buf_len, |
4498 | opc: ice_aqc_opc_share_res); |
4499 | if (status) |
4500 | ice_debug(hw, ICE_DBG_SW, "Could not set resource type %u id %u to %s\n" , |
4501 | type, res_id, shared ? "SHARED" : "DEDICATED" ); |
4502 | |
4503 | return status; |
4504 | } |
4505 | |
4506 | /* This is mapping table entry that maps every word within a given protocol |
4507 | * structure to the real byte offset as per the specification of that |
4508 | * protocol header. |
4509 | * for example dst address is 3 words in ethertype header and corresponding |
4510 | * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8 |
4511 | * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a |
4512 | * matching entry describing its field. This needs to be updated if new |
4513 | * structure is added to that union. |
4514 | */ |
4515 | static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { |
4516 | ICE_PROTOCOL_ENTRY(ICE_MAC_OFOS, 0, 2, 4, 6, 8, 10, 12), |
4517 | ICE_PROTOCOL_ENTRY(ICE_MAC_IL, 0, 2, 4, 6, 8, 10, 12), |
4518 | ICE_PROTOCOL_ENTRY(ICE_ETYPE_OL, 0), |
4519 | ICE_PROTOCOL_ENTRY(ICE_ETYPE_IL, 0), |
4520 | ICE_PROTOCOL_ENTRY(ICE_VLAN_OFOS, 2, 0), |
4521 | ICE_PROTOCOL_ENTRY(ICE_IPV4_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), |
4522 | ICE_PROTOCOL_ENTRY(ICE_IPV4_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), |
4523 | ICE_PROTOCOL_ENTRY(ICE_IPV6_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, |
4524 | 20, 22, 24, 26, 28, 30, 32, 34, 36, 38), |
4525 | ICE_PROTOCOL_ENTRY(ICE_IPV6_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, |
4526 | 22, 24, 26, 28, 30, 32, 34, 36, 38), |
4527 | ICE_PROTOCOL_ENTRY(ICE_TCP_IL, 0, 2), |
4528 | ICE_PROTOCOL_ENTRY(ICE_UDP_OF, 0, 2), |
4529 | ICE_PROTOCOL_ENTRY(ICE_UDP_ILOS, 0, 2), |
4530 | ICE_PROTOCOL_ENTRY(ICE_VXLAN, 8, 10, 12, 14), |
4531 | ICE_PROTOCOL_ENTRY(ICE_GENEVE, 8, 10, 12, 14), |
4532 | ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6), |
4533 | ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22), |
4534 | ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14), |
4535 | ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6), |
4536 | ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10), |
4537 | ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0), |
4538 | ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0), |
4539 | ICE_PROTOCOL_ENTRY(ICE_HW_METADATA, |
4540 | ICE_SOURCE_PORT_MDID_OFFSET, |
4541 | ICE_PTYPE_MDID_OFFSET, |
4542 | ICE_PACKET_LENGTH_MDID_OFFSET, |
4543 | ICE_SOURCE_VSI_MDID_OFFSET, |
4544 | ICE_PKT_VLAN_MDID_OFFSET, |
4545 | ICE_PKT_TUNNEL_MDID_OFFSET, |
4546 | ICE_PKT_TCP_MDID_OFFSET, |
4547 | ICE_PKT_ERROR_MDID_OFFSET), |
4548 | }; |
4549 | |
4550 | static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { |
4551 | { ICE_MAC_OFOS, ICE_MAC_OFOS_HW }, |
4552 | { ICE_MAC_IL, ICE_MAC_IL_HW }, |
4553 | { ICE_ETYPE_OL, ICE_ETYPE_OL_HW }, |
4554 | { ICE_ETYPE_IL, ICE_ETYPE_IL_HW }, |
4555 | { ICE_VLAN_OFOS, ICE_VLAN_OL_HW }, |
4556 | { ICE_IPV4_OFOS, ICE_IPV4_OFOS_HW }, |
4557 | { ICE_IPV4_IL, ICE_IPV4_IL_HW }, |
4558 | { ICE_IPV6_OFOS, ICE_IPV6_OFOS_HW }, |
4559 | { ICE_IPV6_IL, ICE_IPV6_IL_HW }, |
4560 | { ICE_TCP_IL, ICE_TCP_IL_HW }, |
4561 | { ICE_UDP_OF, ICE_UDP_OF_HW }, |
4562 | { ICE_UDP_ILOS, ICE_UDP_ILOS_HW }, |
4563 | { ICE_VXLAN, ICE_UDP_OF_HW }, |
4564 | { ICE_GENEVE, ICE_UDP_OF_HW }, |
4565 | { ICE_NVGRE, ICE_GRE_OF_HW }, |
4566 | { ICE_GTP, ICE_UDP_OF_HW }, |
4567 | { ICE_GTP_NO_PAY, ICE_UDP_ILOS_HW }, |
4568 | { ICE_PPPOE, ICE_PPPOE_HW }, |
4569 | { ICE_L2TPV3, ICE_L2TPV3_HW }, |
4570 | { ICE_VLAN_EX, ICE_VLAN_OF_HW }, |
4571 | { ICE_VLAN_IN, ICE_VLAN_OL_HW }, |
4572 | { ICE_HW_METADATA, ICE_META_DATA_ID_HW }, |
4573 | }; |
4574 | |
4575 | /** |
4576 | * ice_find_recp - find a recipe |
4577 | * @hw: pointer to the hardware structure |
4578 | * @lkup_exts: extension sequence to match |
4579 | * @rinfo: information regarding the rule e.g. priority and action info |
4580 | * |
4581 | * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. |
4582 | */ |
4583 | static u16 |
4584 | ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, |
4585 | const struct ice_adv_rule_info *rinfo) |
4586 | { |
4587 | bool refresh_required = true; |
4588 | struct ice_sw_recipe *recp; |
4589 | u8 i; |
4590 | |
4591 | /* Walk through existing recipes to find a match */ |
4592 | recp = hw->switch_info->recp_list; |
4593 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
4594 | /* If recipe was not created for this ID, in SW bookkeeping, |
4595 | * check if FW has an entry for this recipe. If the FW has an |
4596 | * entry update it in our SW bookkeeping and continue with the |
4597 | * matching. |
4598 | */ |
4599 | if (!recp[i].recp_created) |
4600 | if (ice_get_recp_frm_fw(hw, |
4601 | recps: hw->switch_info->recp_list, rid: i, |
4602 | refresh_required: &refresh_required)) |
4603 | continue; |
4604 | |
4605 | /* Skip inverse action recipes */ |
4606 | if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & |
4607 | ICE_AQ_RECIPE_ACT_INV_ACT) |
4608 | continue; |
4609 | |
4610 | /* if number of words we are looking for match */ |
4611 | if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) { |
4612 | struct ice_fv_word *ar = recp[i].lkup_exts.fv_words; |
4613 | struct ice_fv_word *be = lkup_exts->fv_words; |
4614 | u16 *cr = recp[i].lkup_exts.field_mask; |
4615 | u16 *de = lkup_exts->field_mask; |
4616 | bool found = true; |
4617 | u8 pe, qr; |
4618 | |
4619 | /* ar, cr, and qr are related to the recipe words, while |
4620 | * be, de, and pe are related to the lookup words |
4621 | */ |
4622 | for (pe = 0; pe < lkup_exts->n_val_words; pe++) { |
4623 | for (qr = 0; qr < recp[i].lkup_exts.n_val_words; |
4624 | qr++) { |
4625 | if (ar[qr].off == be[pe].off && |
4626 | ar[qr].prot_id == be[pe].prot_id && |
4627 | cr[qr] == de[pe]) |
4628 | /* Found the "pe"th word in the |
4629 | * given recipe |
4630 | */ |
4631 | break; |
4632 | } |
4633 | /* After walking through all the words in the |
4634 | * "i"th recipe if "p"th word was not found then |
4635 | * this recipe is not what we are looking for. |
4636 | * So break out from this loop and try the next |
4637 | * recipe |
4638 | */ |
4639 | if (qr >= recp[i].lkup_exts.n_val_words) { |
4640 | found = false; |
4641 | break; |
4642 | } |
4643 | } |
4644 | /* If for "i"th recipe the found was never set to false |
4645 | * then it means we found our match |
4646 | * Also tun type and *_pass_l2 of recipe needs to be |
4647 | * checked |
4648 | */ |
4649 | if (found && recp[i].tun_type == rinfo->tun_type && |
4650 | recp[i].need_pass_l2 == rinfo->need_pass_l2 && |
4651 | recp[i].allow_pass_l2 == rinfo->allow_pass_l2) |
4652 | return i; /* Return the recipe ID */ |
4653 | } |
4654 | } |
4655 | return ICE_MAX_NUM_RECIPES; |
4656 | } |
4657 | |
4658 | /** |
4659 | * ice_change_proto_id_to_dvm - change proto id in prot_id_tbl |
4660 | * |
4661 | * As protocol id for outer vlan is different in dvm and svm, if dvm is |
4662 | * supported protocol array record for outer vlan has to be modified to |
4663 | * reflect the value proper for DVM. |
4664 | */ |
4665 | void ice_change_proto_id_to_dvm(void) |
4666 | { |
4667 | u8 i; |
4668 | |
4669 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) |
4670 | if (ice_prot_id_tbl[i].type == ICE_VLAN_OFOS && |
4671 | ice_prot_id_tbl[i].protocol_id != ICE_VLAN_OF_HW) |
4672 | ice_prot_id_tbl[i].protocol_id = ICE_VLAN_OF_HW; |
4673 | } |
4674 | |
4675 | /** |
4676 | * ice_prot_type_to_id - get protocol ID from protocol type |
4677 | * @type: protocol type |
4678 | * @id: pointer to variable that will receive the ID |
4679 | * |
4680 | * Returns true if found, false otherwise |
4681 | */ |
4682 | static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id) |
4683 | { |
4684 | u8 i; |
4685 | |
4686 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) |
4687 | if (ice_prot_id_tbl[i].type == type) { |
4688 | *id = ice_prot_id_tbl[i].protocol_id; |
4689 | return true; |
4690 | } |
4691 | return false; |
4692 | } |
4693 | |
4694 | /** |
4695 | * ice_fill_valid_words - count valid words |
4696 | * @rule: advanced rule with lookup information |
4697 | * @lkup_exts: byte offset extractions of the words that are valid |
4698 | * |
4699 | * calculate valid words in a lookup rule using mask value |
4700 | */ |
4701 | static u8 |
4702 | ice_fill_valid_words(struct ice_adv_lkup_elem *rule, |
4703 | struct ice_prot_lkup_ext *lkup_exts) |
4704 | { |
4705 | u8 j, word, prot_id, ret_val; |
4706 | |
4707 | if (!ice_prot_type_to_id(type: rule->type, id: &prot_id)) |
4708 | return 0; |
4709 | |
4710 | word = lkup_exts->n_val_words; |
4711 | |
4712 | for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++) |
4713 | if (((u16 *)&rule->m_u)[j] && |
4714 | rule->type < ARRAY_SIZE(ice_prot_ext)) { |
4715 | /* No more space to accommodate */ |
4716 | if (word >= ICE_MAX_CHAIN_WORDS) |
4717 | return 0; |
4718 | lkup_exts->fv_words[word].off = |
4719 | ice_prot_ext[rule->type].offs[j]; |
4720 | lkup_exts->fv_words[word].prot_id = |
4721 | ice_prot_id_tbl[rule->type].protocol_id; |
4722 | lkup_exts->field_mask[word] = |
4723 | be16_to_cpu(((__force __be16 *)&rule->m_u)[j]); |
4724 | word++; |
4725 | } |
4726 | |
4727 | ret_val = word - lkup_exts->n_val_words; |
4728 | lkup_exts->n_val_words = word; |
4729 | |
4730 | return ret_val; |
4731 | } |
4732 | |
4733 | /** |
4734 | * ice_create_first_fit_recp_def - Create a recipe grouping |
4735 | * @hw: pointer to the hardware structure |
4736 | * @lkup_exts: an array of protocol header extractions |
4737 | * @rg_list: pointer to a list that stores new recipe groups |
4738 | * @recp_cnt: pointer to a variable that stores returned number of recipe groups |
4739 | * |
4740 | * Using first fit algorithm, take all the words that are still not done |
4741 | * and start grouping them in 4-word groups. Each group makes up one |
4742 | * recipe. |
4743 | */ |
4744 | static int |
4745 | ice_create_first_fit_recp_def(struct ice_hw *hw, |
4746 | struct ice_prot_lkup_ext *lkup_exts, |
4747 | struct list_head *rg_list, |
4748 | u8 *recp_cnt) |
4749 | { |
4750 | struct ice_pref_recipe_group *grp = NULL; |
4751 | u8 j; |
4752 | |
4753 | *recp_cnt = 0; |
4754 | |
4755 | /* Walk through every word in the rule to check if it is not done. If so |
4756 | * then this word needs to be part of a new recipe. |
4757 | */ |
4758 | for (j = 0; j < lkup_exts->n_val_words; j++) |
4759 | if (!test_bit(j, lkup_exts->done)) { |
4760 | if (!grp || |
4761 | grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) { |
4762 | struct ice_recp_grp_entry *entry; |
4763 | |
4764 | entry = devm_kzalloc(dev: ice_hw_to_dev(hw), |
4765 | size: sizeof(*entry), |
4766 | GFP_KERNEL); |
4767 | if (!entry) |
4768 | return -ENOMEM; |
4769 | list_add(new: &entry->l_entry, head: rg_list); |
4770 | grp = &entry->r_group; |
4771 | (*recp_cnt)++; |
4772 | } |
4773 | |
4774 | grp->pairs[grp->n_val_pairs].prot_id = |
4775 | lkup_exts->fv_words[j].prot_id; |
4776 | grp->pairs[grp->n_val_pairs].off = |
4777 | lkup_exts->fv_words[j].off; |
4778 | grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j]; |
4779 | grp->n_val_pairs++; |
4780 | } |
4781 | |
4782 | return 0; |
4783 | } |
4784 | |
4785 | /** |
4786 | * ice_fill_fv_word_index - fill in the field vector indices for a recipe group |
4787 | * @hw: pointer to the hardware structure |
4788 | * @fv_list: field vector with the extraction sequence information |
4789 | * @rg_list: recipe groupings with protocol-offset pairs |
4790 | * |
4791 | * Helper function to fill in the field vector indices for protocol-offset |
4792 | * pairs. These indexes are then ultimately programmed into a recipe. |
4793 | */ |
4794 | static int |
4795 | ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list, |
4796 | struct list_head *rg_list) |
4797 | { |
4798 | struct ice_sw_fv_list_entry *fv; |
4799 | struct ice_recp_grp_entry *rg; |
4800 | struct ice_fv_word *fv_ext; |
4801 | |
4802 | if (list_empty(head: fv_list)) |
4803 | return 0; |
4804 | |
4805 | fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry, |
4806 | list_entry); |
4807 | fv_ext = fv->fv_ptr->ew; |
4808 | |
4809 | list_for_each_entry(rg, rg_list, l_entry) { |
4810 | u8 i; |
4811 | |
4812 | for (i = 0; i < rg->r_group.n_val_pairs; i++) { |
4813 | struct ice_fv_word *pr; |
4814 | bool found = false; |
4815 | u16 mask; |
4816 | u8 j; |
4817 | |
4818 | pr = &rg->r_group.pairs[i]; |
4819 | mask = rg->r_group.mask[i]; |
4820 | |
4821 | for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) |
4822 | if (fv_ext[j].prot_id == pr->prot_id && |
4823 | fv_ext[j].off == pr->off) { |
4824 | found = true; |
4825 | |
4826 | /* Store index of field vector */ |
4827 | rg->fv_idx[i] = j; |
4828 | rg->fv_mask[i] = mask; |
4829 | break; |
4830 | } |
4831 | |
4832 | /* Protocol/offset could not be found, caller gave an |
4833 | * invalid pair |
4834 | */ |
4835 | if (!found) |
4836 | return -EINVAL; |
4837 | } |
4838 | } |
4839 | |
4840 | return 0; |
4841 | } |
4842 | |
4843 | /** |
4844 | * ice_find_free_recp_res_idx - find free result indexes for recipe |
4845 | * @hw: pointer to hardware structure |
4846 | * @profiles: bitmap of profiles that will be associated with the new recipe |
4847 | * @free_idx: pointer to variable to receive the free index bitmap |
4848 | * |
4849 | * The algorithm used here is: |
4850 | * 1. When creating a new recipe, create a set P which contains all |
4851 | * Profiles that will be associated with our new recipe |
4852 | * |
4853 | * 2. For each Profile p in set P: |
4854 | * a. Add all recipes associated with Profile p into set R |
4855 | * b. Optional : PossibleIndexes &= profile[p].possibleIndexes |
4856 | * [initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF] |
4857 | * i. Or just assume they all have the same possible indexes: |
4858 | * 44, 45, 46, 47 |
4859 | * i.e., PossibleIndexes = 0x0000F00000000000 |
4860 | * |
4861 | * 3. For each Recipe r in set R: |
4862 | * a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes |
4863 | * b. FreeIndexes = UsedIndexes ^ PossibleIndexes |
4864 | * |
4865 | * FreeIndexes will contain the bits indicating the indexes free for use, |
4866 | * then the code needs to update the recipe[r].used_result_idx_bits to |
4867 | * indicate which indexes were selected for use by this recipe. |
4868 | */ |
4869 | static u16 |
4870 | ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, |
4871 | unsigned long *free_idx) |
4872 | { |
4873 | DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS); |
4874 | DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES); |
4875 | DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS); |
4876 | u16 bit; |
4877 | |
4878 | bitmap_zero(dst: recipes, ICE_MAX_NUM_RECIPES); |
4879 | bitmap_zero(dst: used_idx, ICE_MAX_FV_WORDS); |
4880 | |
4881 | bitmap_fill(dst: possible_idx, ICE_MAX_FV_WORDS); |
4882 | |
4883 | /* For each profile we are going to associate the recipe with, add the |
4884 | * recipes that are associated with that profile. This will give us |
4885 | * the set of recipes that our recipe may collide with. Also, determine |
4886 | * what possible result indexes are usable given this set of profiles. |
4887 | */ |
4888 | for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) { |
4889 | bitmap_or(dst: recipes, src1: recipes, src2: profile_to_recipe[bit], |
4890 | ICE_MAX_NUM_RECIPES); |
4891 | bitmap_and(dst: possible_idx, src1: possible_idx, |
4892 | src2: hw->switch_info->prof_res_bm[bit], |
4893 | ICE_MAX_FV_WORDS); |
4894 | } |
4895 | |
4896 | /* For each recipe that our new recipe may collide with, determine |
4897 | * which indexes have been used. |
4898 | */ |
4899 | for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES) |
4900 | bitmap_or(dst: used_idx, src1: used_idx, |
4901 | src2: hw->switch_info->recp_list[bit].res_idxs, |
4902 | ICE_MAX_FV_WORDS); |
4903 | |
4904 | bitmap_xor(dst: free_idx, src1: used_idx, src2: possible_idx, ICE_MAX_FV_WORDS); |
4905 | |
4906 | /* return number of free indexes */ |
4907 | return (u16)bitmap_weight(src: free_idx, ICE_MAX_FV_WORDS); |
4908 | } |
4909 | |
4910 | /** |
4911 | * ice_add_sw_recipe - function to call AQ calls to create switch recipe |
4912 | * @hw: pointer to hardware structure |
4913 | * @rm: recipe management list entry |
4914 | * @profiles: bitmap of profiles that will be associated. |
4915 | */ |
4916 | static int |
4917 | ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm, |
4918 | unsigned long *profiles) |
4919 | { |
4920 | DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS); |
4921 | struct ice_aqc_recipe_content *content; |
4922 | struct ice_aqc_recipe_data_elem *tmp; |
4923 | struct ice_aqc_recipe_data_elem *buf; |
4924 | struct ice_recp_grp_entry *entry; |
4925 | u16 free_res_idx; |
4926 | u16 recipe_count; |
4927 | u8 chain_idx; |
4928 | u8 recps = 0; |
4929 | int status; |
4930 | |
4931 | /* When more than one recipe are required, another recipe is needed to |
4932 | * chain them together. Matching a tunnel metadata ID takes up one of |
4933 | * the match fields in the chaining recipe reducing the number of |
4934 | * chained recipes by one. |
4935 | */ |
4936 | /* check number of free result indices */ |
4937 | bitmap_zero(dst: result_idx_bm, ICE_MAX_FV_WORDS); |
4938 | free_res_idx = ice_find_free_recp_res_idx(hw, profiles, free_idx: result_idx_bm); |
4939 | |
4940 | ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n" , |
4941 | free_res_idx, rm->n_grp_count); |
4942 | |
4943 | if (rm->n_grp_count > 1) { |
4944 | if (rm->n_grp_count > free_res_idx) |
4945 | return -ENOSPC; |
4946 | |
4947 | rm->n_grp_count++; |
4948 | } |
4949 | |
4950 | if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE) |
4951 | return -ENOSPC; |
4952 | |
4953 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, size: sizeof(*tmp), GFP_KERNEL); |
4954 | if (!tmp) |
4955 | return -ENOMEM; |
4956 | |
4957 | buf = devm_kcalloc(dev: ice_hw_to_dev(hw), n: rm->n_grp_count, size: sizeof(*buf), |
4958 | GFP_KERNEL); |
4959 | if (!buf) { |
4960 | status = -ENOMEM; |
4961 | goto err_mem; |
4962 | } |
4963 | |
4964 | bitmap_zero(dst: rm->r_bitmap, ICE_MAX_NUM_RECIPES); |
4965 | recipe_count = ICE_MAX_NUM_RECIPES; |
4966 | status = ice_aq_get_recipe(hw, s_recipe_list: tmp, num_recipes: &recipe_count, recipe_root: ICE_SW_LKUP_MAC, |
4967 | NULL); |
4968 | if (status || recipe_count == 0) |
4969 | goto err_unroll; |
4970 | |
4971 | /* Allocate the recipe resources, and configure them according to the |
4972 | * match fields from protocol headers and extracted field vectors. |
4973 | */ |
4974 | chain_idx = find_first_bit(addr: result_idx_bm, ICE_MAX_FV_WORDS); |
4975 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
4976 | u8 i; |
4977 | |
4978 | status = ice_alloc_recipe(hw, rid: &entry->rid); |
4979 | if (status) |
4980 | goto err_unroll; |
4981 | |
4982 | content = &buf[recps].content; |
4983 | |
4984 | /* Clear the result index of the located recipe, as this will be |
4985 | * updated, if needed, later in the recipe creation process. |
4986 | */ |
4987 | tmp[0].content.result_indx = 0; |
4988 | |
4989 | buf[recps] = tmp[0]; |
4990 | buf[recps].recipe_indx = (u8)entry->rid; |
4991 | /* if the recipe is a non-root recipe RID should be programmed |
4992 | * as 0 for the rules to be applied correctly. |
4993 | */ |
4994 | content->rid = 0; |
4995 | memset(&content->lkup_indx, 0, |
4996 | sizeof(content->lkup_indx)); |
4997 | |
4998 | /* All recipes use look-up index 0 to match switch ID. */ |
4999 | content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; |
5000 | content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); |
5001 | /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask |
5002 | * to be 0 |
5003 | */ |
5004 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { |
5005 | content->lkup_indx[i] = 0x80; |
5006 | content->mask[i] = 0; |
5007 | } |
5008 | |
5009 | for (i = 0; i < entry->r_group.n_val_pairs; i++) { |
5010 | content->lkup_indx[i + 1] = entry->fv_idx[i]; |
5011 | content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]); |
5012 | } |
5013 | |
5014 | if (rm->n_grp_count > 1) { |
5015 | /* Checks to see if there really is a valid result index |
5016 | * that can be used. |
5017 | */ |
5018 | if (chain_idx >= ICE_MAX_FV_WORDS) { |
5019 | ice_debug(hw, ICE_DBG_SW, "No chain index available\n" ); |
5020 | status = -ENOSPC; |
5021 | goto err_unroll; |
5022 | } |
5023 | |
5024 | entry->chain_idx = chain_idx; |
5025 | content->result_indx = |
5026 | ICE_AQ_RECIPE_RESULT_EN | |
5027 | ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) & |
5028 | ICE_AQ_RECIPE_RESULT_DATA_M); |
5029 | clear_bit(nr: chain_idx, addr: result_idx_bm); |
5030 | chain_idx = find_first_bit(addr: result_idx_bm, |
5031 | ICE_MAX_FV_WORDS); |
5032 | } |
5033 | |
5034 | /* fill recipe dependencies */ |
5035 | bitmap_zero(dst: (unsigned long *)buf[recps].recipe_bitmap, |
5036 | ICE_MAX_NUM_RECIPES); |
5037 | set_bit(nr: buf[recps].recipe_indx, |
5038 | addr: (unsigned long *)buf[recps].recipe_bitmap); |
5039 | content->act_ctrl_fwd_priority = rm->priority; |
5040 | |
5041 | if (rm->need_pass_l2) |
5042 | content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2; |
5043 | |
5044 | if (rm->allow_pass_l2) |
5045 | content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2; |
5046 | recps++; |
5047 | } |
5048 | |
5049 | if (rm->n_grp_count == 1) { |
5050 | rm->root_rid = buf[0].recipe_indx; |
5051 | set_bit(nr: buf[0].recipe_indx, addr: rm->r_bitmap); |
5052 | buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT; |
5053 | if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) { |
5054 | memcpy(buf[0].recipe_bitmap, rm->r_bitmap, |
5055 | sizeof(buf[0].recipe_bitmap)); |
5056 | } else { |
5057 | status = -EINVAL; |
5058 | goto err_unroll; |
5059 | } |
5060 | /* Applicable only for ROOT_RECIPE, set the fwd_priority for |
5061 | * the recipe which is getting created if specified |
5062 | * by user. Usually any advanced switch filter, which results |
5063 | * into new extraction sequence, ended up creating a new recipe |
5064 | * of type ROOT and usually recipes are associated with profiles |
5065 | * Switch rule referreing newly created recipe, needs to have |
5066 | * either/or 'fwd' or 'join' priority, otherwise switch rule |
5067 | * evaluation will not happen correctly. In other words, if |
5068 | * switch rule to be evaluated on priority basis, then recipe |
5069 | * needs to have priority, otherwise it will be evaluated last. |
5070 | */ |
5071 | buf[0].content.act_ctrl_fwd_priority = rm->priority; |
5072 | } else { |
5073 | struct ice_recp_grp_entry *last_chain_entry; |
5074 | u16 rid, i; |
5075 | |
5076 | /* Allocate the last recipe that will chain the outcomes of the |
5077 | * other recipes together |
5078 | */ |
5079 | status = ice_alloc_recipe(hw, rid: &rid); |
5080 | if (status) |
5081 | goto err_unroll; |
5082 | |
5083 | content = &buf[recps].content; |
5084 | |
5085 | buf[recps].recipe_indx = (u8)rid; |
5086 | content->rid = (u8)rid; |
5087 | content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT; |
5088 | /* the new entry created should also be part of rg_list to |
5089 | * make sure we have complete recipe |
5090 | */ |
5091 | last_chain_entry = devm_kzalloc(dev: ice_hw_to_dev(hw), |
5092 | size: sizeof(*last_chain_entry), |
5093 | GFP_KERNEL); |
5094 | if (!last_chain_entry) { |
5095 | status = -ENOMEM; |
5096 | goto err_unroll; |
5097 | } |
5098 | last_chain_entry->rid = rid; |
5099 | memset(&content->lkup_indx, 0, sizeof(content->lkup_indx)); |
5100 | /* All recipes use look-up index 0 to match switch ID. */ |
5101 | content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; |
5102 | content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); |
5103 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { |
5104 | content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE; |
5105 | content->mask[i] = 0; |
5106 | } |
5107 | |
5108 | i = 1; |
5109 | /* update r_bitmap with the recp that is used for chaining */ |
5110 | set_bit(nr: rid, addr: rm->r_bitmap); |
5111 | /* this is the recipe that chains all the other recipes so it |
5112 | * should not have a chaining ID to indicate the same |
5113 | */ |
5114 | last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND; |
5115 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
5116 | last_chain_entry->fv_idx[i] = entry->chain_idx; |
5117 | content->lkup_indx[i] = entry->chain_idx; |
5118 | content->mask[i++] = cpu_to_le16(0xFFFF); |
5119 | set_bit(nr: entry->rid, addr: rm->r_bitmap); |
5120 | } |
5121 | list_add(new: &last_chain_entry->l_entry, head: &rm->rg_list); |
5122 | if (sizeof(buf[recps].recipe_bitmap) >= |
5123 | sizeof(rm->r_bitmap)) { |
5124 | memcpy(buf[recps].recipe_bitmap, rm->r_bitmap, |
5125 | sizeof(buf[recps].recipe_bitmap)); |
5126 | } else { |
5127 | status = -EINVAL; |
5128 | goto err_unroll; |
5129 | } |
5130 | content->act_ctrl_fwd_priority = rm->priority; |
5131 | |
5132 | recps++; |
5133 | rm->root_rid = (u8)rid; |
5134 | } |
5135 | status = ice_acquire_change_lock(hw, access: ICE_RES_WRITE); |
5136 | if (status) |
5137 | goto err_unroll; |
5138 | |
5139 | status = ice_aq_add_recipe(hw, s_recipe_list: buf, num_recipes: rm->n_grp_count, NULL); |
5140 | ice_release_change_lock(hw); |
5141 | if (status) |
5142 | goto err_unroll; |
5143 | |
5144 | /* Every recipe that just got created add it to the recipe |
5145 | * book keeping list |
5146 | */ |
5147 | list_for_each_entry(entry, &rm->rg_list, l_entry) { |
5148 | struct ice_switch_info *sw = hw->switch_info; |
5149 | bool is_root, idx_found = false; |
5150 | struct ice_sw_recipe *recp; |
5151 | u16 idx, buf_idx = 0; |
5152 | |
5153 | /* find buffer index for copying some data */ |
5154 | for (idx = 0; idx < rm->n_grp_count; idx++) |
5155 | if (buf[idx].recipe_indx == entry->rid) { |
5156 | buf_idx = idx; |
5157 | idx_found = true; |
5158 | } |
5159 | |
5160 | if (!idx_found) { |
5161 | status = -EIO; |
5162 | goto err_unroll; |
5163 | } |
5164 | |
5165 | recp = &sw->recp_list[entry->rid]; |
5166 | is_root = (rm->root_rid == entry->rid); |
5167 | recp->is_root = is_root; |
5168 | |
5169 | recp->root_rid = entry->rid; |
5170 | recp->big_recp = (is_root && rm->n_grp_count > 1); |
5171 | |
5172 | memcpy(&recp->ext_words, entry->r_group.pairs, |
5173 | entry->r_group.n_val_pairs * sizeof(struct ice_fv_word)); |
5174 | |
5175 | memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap, |
5176 | sizeof(recp->r_bitmap)); |
5177 | |
5178 | /* Copy non-result fv index values and masks to recipe. This |
5179 | * call will also update the result recipe bitmask. |
5180 | */ |
5181 | ice_collect_result_idx(buf: &buf[buf_idx], recp); |
5182 | |
5183 | /* for non-root recipes, also copy to the root, this allows |
5184 | * easier matching of a complete chained recipe |
5185 | */ |
5186 | if (!is_root) |
5187 | ice_collect_result_idx(buf: &buf[buf_idx], |
5188 | recp: &sw->recp_list[rm->root_rid]); |
5189 | |
5190 | recp->n_ext_words = entry->r_group.n_val_pairs; |
5191 | recp->chain_idx = entry->chain_idx; |
5192 | recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority; |
5193 | recp->n_grp_count = rm->n_grp_count; |
5194 | recp->tun_type = rm->tun_type; |
5195 | recp->need_pass_l2 = rm->need_pass_l2; |
5196 | recp->allow_pass_l2 = rm->allow_pass_l2; |
5197 | recp->recp_created = true; |
5198 | } |
5199 | rm->root_buf = buf; |
5200 | kfree(objp: tmp); |
5201 | return status; |
5202 | |
5203 | err_unroll: |
5204 | err_mem: |
5205 | kfree(objp: tmp); |
5206 | devm_kfree(dev: ice_hw_to_dev(hw), p: buf); |
5207 | return status; |
5208 | } |
5209 | |
5210 | /** |
5211 | * ice_create_recipe_group - creates recipe group |
5212 | * @hw: pointer to hardware structure |
5213 | * @rm: recipe management list entry |
5214 | * @lkup_exts: lookup elements |
5215 | */ |
5216 | static int |
5217 | ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, |
5218 | struct ice_prot_lkup_ext *lkup_exts) |
5219 | { |
5220 | u8 recp_count = 0; |
5221 | int status; |
5222 | |
5223 | rm->n_grp_count = 0; |
5224 | |
5225 | /* Create recipes for words that are marked not done by packing them |
5226 | * as best fit. |
5227 | */ |
5228 | status = ice_create_first_fit_recp_def(hw, lkup_exts, |
5229 | rg_list: &rm->rg_list, recp_cnt: &recp_count); |
5230 | if (!status) { |
5231 | rm->n_grp_count += recp_count; |
5232 | rm->n_ext_words = lkup_exts->n_val_words; |
5233 | memcpy(&rm->ext_words, lkup_exts->fv_words, |
5234 | sizeof(rm->ext_words)); |
5235 | memcpy(rm->word_masks, lkup_exts->field_mask, |
5236 | sizeof(rm->word_masks)); |
5237 | } |
5238 | |
5239 | return status; |
5240 | } |
5241 | |
5242 | /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule |
5243 | * @hw: pointer to hardware structure |
5244 | * @rinfo: other information regarding the rule e.g. priority and action info |
5245 | * @bm: pointer to memory for returning the bitmap of field vectors |
5246 | */ |
5247 | static void |
5248 | ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo, |
5249 | unsigned long *bm) |
5250 | { |
5251 | enum ice_prof_type prof_type; |
5252 | |
5253 | bitmap_zero(dst: bm, ICE_MAX_NUM_PROFILES); |
5254 | |
5255 | switch (rinfo->tun_type) { |
5256 | case ICE_NON_TUN: |
5257 | prof_type = ICE_PROF_NON_TUN; |
5258 | break; |
5259 | case ICE_ALL_TUNNELS: |
5260 | prof_type = ICE_PROF_TUN_ALL; |
5261 | break; |
5262 | case ICE_SW_TUN_GENEVE: |
5263 | case ICE_SW_TUN_VXLAN: |
5264 | prof_type = ICE_PROF_TUN_UDP; |
5265 | break; |
5266 | case ICE_SW_TUN_NVGRE: |
5267 | prof_type = ICE_PROF_TUN_GRE; |
5268 | break; |
5269 | case ICE_SW_TUN_GTPU: |
5270 | prof_type = ICE_PROF_TUN_GTPU; |
5271 | break; |
5272 | case ICE_SW_TUN_GTPC: |
5273 | prof_type = ICE_PROF_TUN_GTPC; |
5274 | break; |
5275 | case ICE_SW_TUN_AND_NON_TUN: |
5276 | default: |
5277 | prof_type = ICE_PROF_ALL; |
5278 | break; |
5279 | } |
5280 | |
5281 | ice_get_sw_fv_bitmap(hw, type: prof_type, bm); |
5282 | } |
5283 | |
5284 | /** |
5285 | * ice_add_adv_recipe - Add an advanced recipe that is not part of the default |
5286 | * @hw: pointer to hardware structure |
5287 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5288 | * structure per protocol header |
5289 | * @lkups_cnt: number of protocols |
5290 | * @rinfo: other information regarding the rule e.g. priority and action info |
5291 | * @rid: return the recipe ID of the recipe created |
5292 | */ |
5293 | static int |
5294 | ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
5295 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid) |
5296 | { |
5297 | DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES); |
5298 | DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES); |
5299 | struct ice_prot_lkup_ext *lkup_exts; |
5300 | struct ice_recp_grp_entry *r_entry; |
5301 | struct ice_sw_fv_list_entry *fvit; |
5302 | struct ice_recp_grp_entry *r_tmp; |
5303 | struct ice_sw_fv_list_entry *tmp; |
5304 | struct ice_sw_recipe *rm; |
5305 | int status = 0; |
5306 | u8 i; |
5307 | |
5308 | if (!lkups_cnt) |
5309 | return -EINVAL; |
5310 | |
5311 | lkup_exts = kzalloc(size: sizeof(*lkup_exts), GFP_KERNEL); |
5312 | if (!lkup_exts) |
5313 | return -ENOMEM; |
5314 | |
5315 | /* Determine the number of words to be matched and if it exceeds a |
5316 | * recipe's restrictions |
5317 | */ |
5318 | for (i = 0; i < lkups_cnt; i++) { |
5319 | u16 count; |
5320 | |
5321 | if (lkups[i].type >= ICE_PROTOCOL_LAST) { |
5322 | status = -EIO; |
5323 | goto err_free_lkup_exts; |
5324 | } |
5325 | |
5326 | count = ice_fill_valid_words(rule: &lkups[i], lkup_exts); |
5327 | if (!count) { |
5328 | status = -EIO; |
5329 | goto err_free_lkup_exts; |
5330 | } |
5331 | } |
5332 | |
5333 | rm = kzalloc(size: sizeof(*rm), GFP_KERNEL); |
5334 | if (!rm) { |
5335 | status = -ENOMEM; |
5336 | goto err_free_lkup_exts; |
5337 | } |
5338 | |
5339 | /* Get field vectors that contain fields extracted from all the protocol |
5340 | * headers being programmed. |
5341 | */ |
5342 | INIT_LIST_HEAD(list: &rm->fv_list); |
5343 | INIT_LIST_HEAD(list: &rm->rg_list); |
5344 | |
5345 | /* Get bitmap of field vectors (profiles) that are compatible with the |
5346 | * rule request; only these will be searched in the subsequent call to |
5347 | * ice_get_sw_fv_list. |
5348 | */ |
5349 | ice_get_compat_fv_bitmap(hw, rinfo, bm: fv_bitmap); |
5350 | |
5351 | status = ice_get_sw_fv_list(hw, lkups: lkup_exts, bm: fv_bitmap, fv_list: &rm->fv_list); |
5352 | if (status) |
5353 | goto err_unroll; |
5354 | |
5355 | /* Group match words into recipes using preferred recipe grouping |
5356 | * criteria. |
5357 | */ |
5358 | status = ice_create_recipe_group(hw, rm, lkup_exts); |
5359 | if (status) |
5360 | goto err_unroll; |
5361 | |
5362 | /* set the recipe priority if specified */ |
5363 | rm->priority = (u8)rinfo->priority; |
5364 | |
5365 | rm->need_pass_l2 = rinfo->need_pass_l2; |
5366 | rm->allow_pass_l2 = rinfo->allow_pass_l2; |
5367 | |
5368 | /* Find offsets from the field vector. Pick the first one for all the |
5369 | * recipes. |
5370 | */ |
5371 | status = ice_fill_fv_word_index(hw, fv_list: &rm->fv_list, rg_list: &rm->rg_list); |
5372 | if (status) |
5373 | goto err_unroll; |
5374 | |
5375 | /* get bitmap of all profiles the recipe will be associated with */ |
5376 | bitmap_zero(dst: profiles, ICE_MAX_NUM_PROFILES); |
5377 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { |
5378 | ice_debug(hw, ICE_DBG_SW, "profile: %d\n" , fvit->profile_id); |
5379 | set_bit(nr: (u16)fvit->profile_id, addr: profiles); |
5380 | } |
5381 | |
5382 | /* Look for a recipe which matches our requested fv / mask list */ |
5383 | *rid = ice_find_recp(hw, lkup_exts, rinfo); |
5384 | if (*rid < ICE_MAX_NUM_RECIPES) |
5385 | /* Success if found a recipe that match the existing criteria */ |
5386 | goto err_unroll; |
5387 | |
5388 | rm->tun_type = rinfo->tun_type; |
5389 | /* Recipe we need does not exist, add a recipe */ |
5390 | status = ice_add_sw_recipe(hw, rm, profiles); |
5391 | if (status) |
5392 | goto err_unroll; |
5393 | |
5394 | /* Associate all the recipes created with all the profiles in the |
5395 | * common field vector. |
5396 | */ |
5397 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { |
5398 | DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); |
5399 | u16 j; |
5400 | |
5401 | status = ice_aq_get_recipe_to_profile(hw, profile_id: fvit->profile_id, |
5402 | r_bitmap: (u8 *)r_bitmap, NULL); |
5403 | if (status) |
5404 | goto err_unroll; |
5405 | |
5406 | bitmap_or(dst: r_bitmap, src1: r_bitmap, src2: rm->r_bitmap, |
5407 | ICE_MAX_NUM_RECIPES); |
5408 | status = ice_acquire_change_lock(hw, access: ICE_RES_WRITE); |
5409 | if (status) |
5410 | goto err_unroll; |
5411 | |
5412 | status = ice_aq_map_recipe_to_profile(hw, profile_id: fvit->profile_id, |
5413 | r_bitmap: (u8 *)r_bitmap, |
5414 | NULL); |
5415 | ice_release_change_lock(hw); |
5416 | |
5417 | if (status) |
5418 | goto err_unroll; |
5419 | |
5420 | /* Update profile to recipe bitmap array */ |
5421 | bitmap_copy(dst: profile_to_recipe[fvit->profile_id], src: r_bitmap, |
5422 | ICE_MAX_NUM_RECIPES); |
5423 | |
5424 | /* Update recipe to profile bitmap array */ |
5425 | for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES) |
5426 | set_bit(nr: (u16)fvit->profile_id, addr: recipe_to_profile[j]); |
5427 | } |
5428 | |
5429 | *rid = rm->root_rid; |
5430 | memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, |
5431 | sizeof(*lkup_exts)); |
5432 | err_unroll: |
5433 | list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) { |
5434 | list_del(entry: &r_entry->l_entry); |
5435 | devm_kfree(dev: ice_hw_to_dev(hw), p: r_entry); |
5436 | } |
5437 | |
5438 | list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) { |
5439 | list_del(entry: &fvit->list_entry); |
5440 | devm_kfree(dev: ice_hw_to_dev(hw), p: fvit); |
5441 | } |
5442 | |
5443 | devm_kfree(dev: ice_hw_to_dev(hw), p: rm->root_buf); |
5444 | kfree(objp: rm); |
5445 | |
5446 | err_free_lkup_exts: |
5447 | kfree(objp: lkup_exts); |
5448 | |
5449 | return status; |
5450 | } |
5451 | |
5452 | /** |
5453 | * ice_dummy_packet_add_vlan - insert VLAN header to dummy pkt |
5454 | * |
5455 | * @dummy_pkt: dummy packet profile pattern to which VLAN tag(s) will be added |
5456 | * @num_vlan: number of VLAN tags |
5457 | */ |
5458 | static struct ice_dummy_pkt_profile * |
5459 | ice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt, |
5460 | u32 num_vlan) |
5461 | { |
5462 | struct ice_dummy_pkt_profile *profile; |
5463 | struct ice_dummy_pkt_offsets *offsets; |
5464 | u32 buf_len, off, etype_off, i; |
5465 | u8 *pkt; |
5466 | |
5467 | if (num_vlan < 1 || num_vlan > 2) |
5468 | return ERR_PTR(error: -EINVAL); |
5469 | |
5470 | off = num_vlan * VLAN_HLEN; |
5471 | |
5472 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet_offsets)) + |
5473 | dummy_pkt->offsets_len; |
5474 | offsets = kzalloc(size: buf_len, GFP_KERNEL); |
5475 | if (!offsets) |
5476 | return ERR_PTR(error: -ENOMEM); |
5477 | |
5478 | offsets[0] = dummy_pkt->offsets[0]; |
5479 | if (num_vlan == 2) { |
5480 | offsets[1] = ice_dummy_qinq_packet_offsets[0]; |
5481 | offsets[2] = ice_dummy_qinq_packet_offsets[1]; |
5482 | } else if (num_vlan == 1) { |
5483 | offsets[1] = ice_dummy_vlan_packet_offsets[0]; |
5484 | } |
5485 | |
5486 | for (i = 1; dummy_pkt->offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5487 | offsets[i + num_vlan].type = dummy_pkt->offsets[i].type; |
5488 | offsets[i + num_vlan].offset = |
5489 | dummy_pkt->offsets[i].offset + off; |
5490 | } |
5491 | offsets[i + num_vlan] = dummy_pkt->offsets[i]; |
5492 | |
5493 | etype_off = dummy_pkt->offsets[1].offset; |
5494 | |
5495 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet)) + |
5496 | dummy_pkt->pkt_len; |
5497 | pkt = kzalloc(size: buf_len, GFP_KERNEL); |
5498 | if (!pkt) { |
5499 | kfree(objp: offsets); |
5500 | return ERR_PTR(error: -ENOMEM); |
5501 | } |
5502 | |
5503 | memcpy(pkt, dummy_pkt->pkt, etype_off); |
5504 | memcpy(pkt + etype_off, |
5505 | num_vlan == 2 ? ice_dummy_qinq_packet : ice_dummy_vlan_packet, |
5506 | off); |
5507 | memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off, |
5508 | dummy_pkt->pkt_len - etype_off); |
5509 | |
5510 | profile = kzalloc(size: sizeof(*profile), GFP_KERNEL); |
5511 | if (!profile) { |
5512 | kfree(objp: offsets); |
5513 | kfree(objp: pkt); |
5514 | return ERR_PTR(error: -ENOMEM); |
5515 | } |
5516 | |
5517 | profile->offsets = offsets; |
5518 | profile->pkt = pkt; |
5519 | profile->pkt_len = buf_len; |
5520 | profile->match |= ICE_PKT_KMALLOC; |
5521 | |
5522 | return profile; |
5523 | } |
5524 | |
5525 | /** |
5526 | * ice_find_dummy_packet - find dummy packet |
5527 | * |
5528 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5529 | * structure per protocol header |
5530 | * @lkups_cnt: number of protocols |
5531 | * @tun_type: tunnel type |
5532 | * |
5533 | * Returns the &ice_dummy_pkt_profile corresponding to these lookup params. |
5534 | */ |
5535 | static const struct ice_dummy_pkt_profile * |
5536 | ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
5537 | enum ice_sw_tunnel_type tun_type) |
5538 | { |
5539 | const struct ice_dummy_pkt_profile *ret = ice_dummy_pkt_profiles; |
5540 | u32 match = 0, vlan_count = 0; |
5541 | u16 i; |
5542 | |
5543 | switch (tun_type) { |
5544 | case ICE_SW_TUN_GTPC: |
5545 | match |= ICE_PKT_TUN_GTPC; |
5546 | break; |
5547 | case ICE_SW_TUN_GTPU: |
5548 | match |= ICE_PKT_TUN_GTPU; |
5549 | break; |
5550 | case ICE_SW_TUN_NVGRE: |
5551 | match |= ICE_PKT_TUN_NVGRE; |
5552 | break; |
5553 | case ICE_SW_TUN_GENEVE: |
5554 | case ICE_SW_TUN_VXLAN: |
5555 | match |= ICE_PKT_TUN_UDP; |
5556 | break; |
5557 | default: |
5558 | break; |
5559 | } |
5560 | |
5561 | for (i = 0; i < lkups_cnt; i++) { |
5562 | if (lkups[i].type == ICE_UDP_ILOS) |
5563 | match |= ICE_PKT_INNER_UDP; |
5564 | else if (lkups[i].type == ICE_TCP_IL) |
5565 | match |= ICE_PKT_INNER_TCP; |
5566 | else if (lkups[i].type == ICE_IPV6_OFOS) |
5567 | match |= ICE_PKT_OUTER_IPV6; |
5568 | else if (lkups[i].type == ICE_VLAN_OFOS || |
5569 | lkups[i].type == ICE_VLAN_EX) |
5570 | vlan_count++; |
5571 | else if (lkups[i].type == ICE_VLAN_IN) |
5572 | vlan_count++; |
5573 | else if (lkups[i].type == ICE_ETYPE_OL && |
5574 | lkups[i].h_u.ethertype.ethtype_id == |
5575 | cpu_to_be16(ICE_IPV6_ETHER_ID) && |
5576 | lkups[i].m_u.ethertype.ethtype_id == |
5577 | cpu_to_be16(0xFFFF)) |
5578 | match |= ICE_PKT_OUTER_IPV6; |
5579 | else if (lkups[i].type == ICE_ETYPE_IL && |
5580 | lkups[i].h_u.ethertype.ethtype_id == |
5581 | cpu_to_be16(ICE_IPV6_ETHER_ID) && |
5582 | lkups[i].m_u.ethertype.ethtype_id == |
5583 | cpu_to_be16(0xFFFF)) |
5584 | match |= ICE_PKT_INNER_IPV6; |
5585 | else if (lkups[i].type == ICE_IPV6_IL) |
5586 | match |= ICE_PKT_INNER_IPV6; |
5587 | else if (lkups[i].type == ICE_GTP_NO_PAY) |
5588 | match |= ICE_PKT_GTP_NOPAY; |
5589 | else if (lkups[i].type == ICE_PPPOE) { |
5590 | match |= ICE_PKT_PPPOE; |
5591 | if (lkups[i].h_u.pppoe_hdr.ppp_prot_id == |
5592 | htons(PPP_IPV6)) |
5593 | match |= ICE_PKT_OUTER_IPV6; |
5594 | } else if (lkups[i].type == ICE_L2TPV3) |
5595 | match |= ICE_PKT_L2TPV3; |
5596 | } |
5597 | |
5598 | while (ret->match && (match & ret->match) != ret->match) |
5599 | ret++; |
5600 | |
5601 | if (vlan_count != 0) |
5602 | ret = ice_dummy_packet_add_vlan(dummy_pkt: ret, num_vlan: vlan_count); |
5603 | |
5604 | return ret; |
5605 | } |
5606 | |
5607 | /** |
5608 | * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria |
5609 | * |
5610 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5611 | * structure per protocol header |
5612 | * @lkups_cnt: number of protocols |
5613 | * @s_rule: stores rule information from the match criteria |
5614 | * @profile: dummy packet profile (the template, its size and header offsets) |
5615 | */ |
5616 | static int |
5617 | ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
5618 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
5619 | const struct ice_dummy_pkt_profile *profile) |
5620 | { |
5621 | u8 *pkt; |
5622 | u16 i; |
5623 | |
5624 | /* Start with a packet with a pre-defined/dummy content. Then, fill |
5625 | * in the header values to be looked up or matched. |
5626 | */ |
5627 | pkt = s_rule->hdr_data; |
5628 | |
5629 | memcpy(pkt, profile->pkt, profile->pkt_len); |
5630 | |
5631 | for (i = 0; i < lkups_cnt; i++) { |
5632 | const struct ice_dummy_pkt_offsets *offsets = profile->offsets; |
5633 | enum ice_protocol_type type; |
5634 | u16 offset = 0, len = 0, j; |
5635 | bool found = false; |
5636 | |
5637 | /* find the start of this layer; it should be found since this |
5638 | * was already checked when search for the dummy packet |
5639 | */ |
5640 | type = lkups[i].type; |
5641 | /* metadata isn't present in the packet */ |
5642 | if (type == ICE_HW_METADATA) |
5643 | continue; |
5644 | |
5645 | for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { |
5646 | if (type == offsets[j].type) { |
5647 | offset = offsets[j].offset; |
5648 | found = true; |
5649 | break; |
5650 | } |
5651 | } |
5652 | /* this should never happen in a correct calling sequence */ |
5653 | if (!found) |
5654 | return -EINVAL; |
5655 | |
5656 | switch (lkups[i].type) { |
5657 | case ICE_MAC_OFOS: |
5658 | case ICE_MAC_IL: |
5659 | len = sizeof(struct ice_ether_hdr); |
5660 | break; |
5661 | case ICE_ETYPE_OL: |
5662 | case ICE_ETYPE_IL: |
5663 | len = sizeof(struct ice_ethtype_hdr); |
5664 | break; |
5665 | case ICE_VLAN_OFOS: |
5666 | case ICE_VLAN_EX: |
5667 | case ICE_VLAN_IN: |
5668 | len = sizeof(struct ice_vlan_hdr); |
5669 | break; |
5670 | case ICE_IPV4_OFOS: |
5671 | case ICE_IPV4_IL: |
5672 | len = sizeof(struct ice_ipv4_hdr); |
5673 | break; |
5674 | case ICE_IPV6_OFOS: |
5675 | case ICE_IPV6_IL: |
5676 | len = sizeof(struct ice_ipv6_hdr); |
5677 | break; |
5678 | case ICE_TCP_IL: |
5679 | case ICE_UDP_OF: |
5680 | case ICE_UDP_ILOS: |
5681 | len = sizeof(struct ice_l4_hdr); |
5682 | break; |
5683 | case ICE_SCTP_IL: |
5684 | len = sizeof(struct ice_sctp_hdr); |
5685 | break; |
5686 | case ICE_NVGRE: |
5687 | len = sizeof(struct ice_nvgre_hdr); |
5688 | break; |
5689 | case ICE_VXLAN: |
5690 | case ICE_GENEVE: |
5691 | len = sizeof(struct ice_udp_tnl_hdr); |
5692 | break; |
5693 | case ICE_GTP_NO_PAY: |
5694 | case ICE_GTP: |
5695 | len = sizeof(struct ice_udp_gtp_hdr); |
5696 | break; |
5697 | case ICE_PPPOE: |
5698 | len = sizeof(struct ice_pppoe_hdr); |
5699 | break; |
5700 | case ICE_L2TPV3: |
5701 | len = sizeof(struct ice_l2tpv3_sess_hdr); |
5702 | break; |
5703 | default: |
5704 | return -EINVAL; |
5705 | } |
5706 | |
5707 | /* the length should be a word multiple */ |
5708 | if (len % ICE_BYTES_PER_WORD) |
5709 | return -EIO; |
5710 | |
5711 | /* We have the offset to the header start, the length, the |
5712 | * caller's header values and mask. Use this information to |
5713 | * copy the data into the dummy packet appropriately based on |
5714 | * the mask. Note that we need to only write the bits as |
5715 | * indicated by the mask to make sure we don't improperly write |
5716 | * over any significant packet data. |
5717 | */ |
5718 | for (j = 0; j < len / sizeof(u16); j++) { |
5719 | u16 *ptr = (u16 *)(pkt + offset); |
5720 | u16 mask = lkups[i].m_raw[j]; |
5721 | |
5722 | if (!mask) |
5723 | continue; |
5724 | |
5725 | ptr[j] = (ptr[j] & ~mask) | (lkups[i].h_raw[j] & mask); |
5726 | } |
5727 | } |
5728 | |
5729 | s_rule->hdr_len = cpu_to_le16(profile->pkt_len); |
5730 | |
5731 | return 0; |
5732 | } |
5733 | |
5734 | /** |
5735 | * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port |
5736 | * @hw: pointer to the hardware structure |
5737 | * @tun_type: tunnel type |
5738 | * @pkt: dummy packet to fill in |
5739 | * @offsets: offset info for the dummy packet |
5740 | */ |
5741 | static int |
5742 | ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type, |
5743 | u8 *pkt, const struct ice_dummy_pkt_offsets *offsets) |
5744 | { |
5745 | u16 open_port, i; |
5746 | |
5747 | switch (tun_type) { |
5748 | case ICE_SW_TUN_VXLAN: |
5749 | if (!ice_get_open_tunnel_port(hw, port: &open_port, type: TNL_VXLAN)) |
5750 | return -EIO; |
5751 | break; |
5752 | case ICE_SW_TUN_GENEVE: |
5753 | if (!ice_get_open_tunnel_port(hw, port: &open_port, type: TNL_GENEVE)) |
5754 | return -EIO; |
5755 | break; |
5756 | default: |
5757 | /* Nothing needs to be done for this tunnel type */ |
5758 | return 0; |
5759 | } |
5760 | |
5761 | /* Find the outer UDP protocol header and insert the port number */ |
5762 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5763 | if (offsets[i].type == ICE_UDP_OF) { |
5764 | struct ice_l4_hdr *hdr; |
5765 | u16 offset; |
5766 | |
5767 | offset = offsets[i].offset; |
5768 | hdr = (struct ice_l4_hdr *)&pkt[offset]; |
5769 | hdr->dst_port = cpu_to_be16(open_port); |
5770 | |
5771 | return 0; |
5772 | } |
5773 | } |
5774 | |
5775 | return -EIO; |
5776 | } |
5777 | |
5778 | /** |
5779 | * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type |
5780 | * @hw: pointer to hw structure |
5781 | * @vlan_type: VLAN tag type |
5782 | * @pkt: dummy packet to fill in |
5783 | * @offsets: offset info for the dummy packet |
5784 | */ |
5785 | static int |
5786 | ice_fill_adv_packet_vlan(struct ice_hw *hw, u16 vlan_type, u8 *pkt, |
5787 | const struct ice_dummy_pkt_offsets *offsets) |
5788 | { |
5789 | u16 i; |
5790 | |
5791 | /* Check if there is something to do */ |
5792 | if (!vlan_type || !ice_is_dvm_ena(hw)) |
5793 | return 0; |
5794 | |
5795 | /* Find VLAN header and insert VLAN TPID */ |
5796 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { |
5797 | if (offsets[i].type == ICE_VLAN_OFOS || |
5798 | offsets[i].type == ICE_VLAN_EX) { |
5799 | struct ice_vlan_hdr *hdr; |
5800 | u16 offset; |
5801 | |
5802 | offset = offsets[i].offset; |
5803 | hdr = (struct ice_vlan_hdr *)&pkt[offset]; |
5804 | hdr->type = cpu_to_be16(vlan_type); |
5805 | |
5806 | return 0; |
5807 | } |
5808 | } |
5809 | |
5810 | return -EIO; |
5811 | } |
5812 | |
5813 | static bool ice_rules_equal(const struct ice_adv_rule_info *first, |
5814 | const struct ice_adv_rule_info *second) |
5815 | { |
5816 | return first->sw_act.flag == second->sw_act.flag && |
5817 | first->tun_type == second->tun_type && |
5818 | first->vlan_type == second->vlan_type && |
5819 | first->src_vsi == second->src_vsi && |
5820 | first->need_pass_l2 == second->need_pass_l2 && |
5821 | first->allow_pass_l2 == second->allow_pass_l2; |
5822 | } |
5823 | |
5824 | /** |
5825 | * ice_find_adv_rule_entry - Search a rule entry |
5826 | * @hw: pointer to the hardware structure |
5827 | * @lkups: lookup elements or match criteria for the advanced recipe, one |
5828 | * structure per protocol header |
5829 | * @lkups_cnt: number of protocols |
5830 | * @recp_id: recipe ID for which we are finding the rule |
5831 | * @rinfo: other information regarding the rule e.g. priority and action info |
5832 | * |
5833 | * Helper function to search for a given advance rule entry |
5834 | * Returns pointer to entry storing the rule if found |
5835 | */ |
5836 | static struct ice_adv_fltr_mgmt_list_entry * |
5837 | ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
5838 | u16 lkups_cnt, u16 recp_id, |
5839 | struct ice_adv_rule_info *rinfo) |
5840 | { |
5841 | struct ice_adv_fltr_mgmt_list_entry *list_itr; |
5842 | struct ice_switch_info *sw = hw->switch_info; |
5843 | int i; |
5844 | |
5845 | list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules, |
5846 | list_entry) { |
5847 | bool lkups_matched = true; |
5848 | |
5849 | if (lkups_cnt != list_itr->lkups_cnt) |
5850 | continue; |
5851 | for (i = 0; i < list_itr->lkups_cnt; i++) |
5852 | if (memcmp(p: &list_itr->lkups[i], q: &lkups[i], |
5853 | size: sizeof(*lkups))) { |
5854 | lkups_matched = false; |
5855 | break; |
5856 | } |
5857 | if (ice_rules_equal(first: rinfo, second: &list_itr->rule_info) && |
5858 | lkups_matched) |
5859 | return list_itr; |
5860 | } |
5861 | return NULL; |
5862 | } |
5863 | |
5864 | /** |
5865 | * ice_adv_add_update_vsi_list |
5866 | * @hw: pointer to the hardware structure |
5867 | * @m_entry: pointer to current adv filter management list entry |
5868 | * @cur_fltr: filter information from the book keeping entry |
5869 | * @new_fltr: filter information with the new VSI to be added |
5870 | * |
5871 | * Call AQ command to add or update previously created VSI list with new VSI. |
5872 | * |
5873 | * Helper function to do book keeping associated with adding filter information |
5874 | * The algorithm to do the booking keeping is described below : |
5875 | * When a VSI needs to subscribe to a given advanced filter |
5876 | * if only one VSI has been added till now |
5877 | * Allocate a new VSI list and add two VSIs |
5878 | * to this list using switch rule command |
5879 | * Update the previously created switch rule with the |
5880 | * newly created VSI list ID |
5881 | * if a VSI list was previously created |
5882 | * Add the new VSI to the previously created VSI list set |
5883 | * using the update switch rule command |
5884 | */ |
5885 | static int |
5886 | ice_adv_add_update_vsi_list(struct ice_hw *hw, |
5887 | struct ice_adv_fltr_mgmt_list_entry *m_entry, |
5888 | struct ice_adv_rule_info *cur_fltr, |
5889 | struct ice_adv_rule_info *new_fltr) |
5890 | { |
5891 | u16 vsi_list_id = 0; |
5892 | int status; |
5893 | |
5894 | if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || |
5895 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP || |
5896 | cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET) |
5897 | return -EOPNOTSUPP; |
5898 | |
5899 | if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || |
5900 | new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) && |
5901 | (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI || |
5902 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST)) |
5903 | return -EOPNOTSUPP; |
5904 | |
5905 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { |
5906 | /* Only one entry existed in the mapping and it was not already |
5907 | * a part of a VSI list. So, create a VSI list with the old and |
5908 | * new VSIs. |
5909 | */ |
5910 | struct ice_fltr_info tmp_fltr; |
5911 | u16 vsi_handle_arr[2]; |
5912 | |
5913 | /* A rule already exists with the new VSI being added */ |
5914 | if (cur_fltr->sw_act.fwd_id.hw_vsi_id == |
5915 | new_fltr->sw_act.fwd_id.hw_vsi_id) |
5916 | return -EEXIST; |
5917 | |
5918 | vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle; |
5919 | vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle; |
5920 | status = ice_create_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
5921 | vsi_list_id: &vsi_list_id, |
5922 | lkup_type: ICE_SW_LKUP_LAST); |
5923 | if (status) |
5924 | return status; |
5925 | |
5926 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); |
5927 | tmp_fltr.flag = m_entry->rule_info.sw_act.flag; |
5928 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; |
5929 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; |
5930 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; |
5931 | tmp_fltr.lkup_type = ICE_SW_LKUP_LAST; |
5932 | |
5933 | /* Update the previous switch rule of "forward to VSI" to |
5934 | * "fwd to VSI list" |
5935 | */ |
5936 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
5937 | if (status) |
5938 | return status; |
5939 | |
5940 | cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id; |
5941 | cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST; |
5942 | m_entry->vsi_list_info = |
5943 | ice_create_vsi_list_map(hw, vsi_handle_arr: &vsi_handle_arr[0], num_vsi: 2, |
5944 | vsi_list_id); |
5945 | } else { |
5946 | u16 vsi_handle = new_fltr->sw_act.vsi_handle; |
5947 | |
5948 | if (!m_entry->vsi_list_info) |
5949 | return -EIO; |
5950 | |
5951 | /* A rule already exists with the new VSI being added */ |
5952 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) |
5953 | return 0; |
5954 | |
5955 | /* Update the previously created VSI list set with |
5956 | * the new VSI ID passed in |
5957 | */ |
5958 | vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id; |
5959 | |
5960 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, |
5961 | vsi_list_id, remove: false, |
5962 | opc: ice_aqc_opc_update_sw_rules, |
5963 | lkup_type: ICE_SW_LKUP_LAST); |
5964 | /* update VSI list mapping info with new VSI ID */ |
5965 | if (!status) |
5966 | set_bit(nr: vsi_handle, addr: m_entry->vsi_list_info->vsi_map); |
5967 | } |
5968 | if (!status) |
5969 | m_entry->vsi_count++; |
5970 | return status; |
5971 | } |
5972 | |
5973 | void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup) |
5974 | { |
5975 | lkup->type = ICE_HW_METADATA; |
5976 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID21] |= |
5977 | cpu_to_be16(ICE_PKT_TUNNEL_MASK); |
5978 | } |
5979 | |
5980 | void ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup) |
5981 | { |
5982 | lkup->type = ICE_HW_METADATA; |
5983 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |= |
5984 | cpu_to_be16(ICE_PKT_FROM_NETWORK); |
5985 | } |
5986 | |
5987 | void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup) |
5988 | { |
5989 | lkup->type = ICE_HW_METADATA; |
5990 | lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |= |
5991 | cpu_to_be16(ICE_PKT_VLAN_MASK); |
5992 | } |
5993 | |
5994 | void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup) |
5995 | { |
5996 | lkup->type = ICE_HW_METADATA; |
5997 | lkup->m_u.metadata.source_vsi = cpu_to_be16(ICE_MDID_SOURCE_VSI_MASK); |
5998 | } |
5999 | |
6000 | /** |
6001 | * ice_add_adv_rule - helper function to create an advanced switch rule |
6002 | * @hw: pointer to the hardware structure |
6003 | * @lkups: information on the words that needs to be looked up. All words |
6004 | * together makes one recipe |
6005 | * @lkups_cnt: num of entries in the lkups array |
6006 | * @rinfo: other information related to the rule that needs to be programmed |
6007 | * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be |
6008 | * ignored is case of error. |
6009 | * |
6010 | * This function can program only 1 rule at a time. The lkups is used to |
6011 | * describe the all the words that forms the "lookup" portion of the recipe. |
6012 | * These words can span multiple protocols. Callers to this function need to |
6013 | * pass in a list of protocol headers with lookup information along and mask |
6014 | * that determines which words are valid from the given protocol header. |
6015 | * rinfo describes other information related to this rule such as forwarding |
6016 | * IDs, priority of this rule, etc. |
6017 | */ |
6018 | int |
6019 | ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6020 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, |
6021 | struct ice_rule_query_data *added_entry) |
6022 | { |
6023 | struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; |
6024 | struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; |
6025 | const struct ice_dummy_pkt_profile *profile; |
6026 | u16 rid = 0, i, rule_buf_sz, vsi_handle; |
6027 | struct list_head *rule_head; |
6028 | struct ice_switch_info *sw; |
6029 | u16 word_cnt; |
6030 | u32 act = 0; |
6031 | int status; |
6032 | u8 q_rgn; |
6033 | |
6034 | /* Initialize profile to result index bitmap */ |
6035 | if (!hw->switch_info->prof_res_bm_init) { |
6036 | hw->switch_info->prof_res_bm_init = 1; |
6037 | ice_init_prof_result_bm(hw); |
6038 | } |
6039 | |
6040 | if (!lkups_cnt) |
6041 | return -EINVAL; |
6042 | |
6043 | /* get # of words we need to match */ |
6044 | word_cnt = 0; |
6045 | for (i = 0; i < lkups_cnt; i++) { |
6046 | u16 j; |
6047 | |
6048 | for (j = 0; j < ARRAY_SIZE(lkups->m_raw); j++) |
6049 | if (lkups[i].m_raw[j]) |
6050 | word_cnt++; |
6051 | } |
6052 | |
6053 | if (!word_cnt) |
6054 | return -EINVAL; |
6055 | |
6056 | if (word_cnt > ICE_MAX_CHAIN_WORDS) |
6057 | return -ENOSPC; |
6058 | |
6059 | /* locate a dummy packet */ |
6060 | profile = ice_find_dummy_packet(lkups, lkups_cnt, tun_type: rinfo->tun_type); |
6061 | if (IS_ERR(ptr: profile)) |
6062 | return PTR_ERR(ptr: profile); |
6063 | |
6064 | if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || |
6065 | rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || |
6066 | rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || |
6067 | rinfo->sw_act.fltr_act == ICE_DROP_PACKET || |
6068 | rinfo->sw_act.fltr_act == ICE_NOP)) { |
6069 | status = -EIO; |
6070 | goto free_pkt_profile; |
6071 | } |
6072 | |
6073 | vsi_handle = rinfo->sw_act.vsi_handle; |
6074 | if (!ice_is_vsi_valid(hw, vsi_handle)) { |
6075 | status = -EINVAL; |
6076 | goto free_pkt_profile; |
6077 | } |
6078 | |
6079 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || |
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 | if (rinfo->src_vsi) |
6085 | rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle: rinfo->src_vsi); |
6086 | else |
6087 | rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); |
6088 | |
6089 | status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, rid: &rid); |
6090 | if (status) |
6091 | goto free_pkt_profile; |
6092 | m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, recp_id: rid, rinfo); |
6093 | if (m_entry) { |
6094 | /* we have to add VSI to VSI_LIST and increment vsi_count. |
6095 | * Also Update VSI list so that we can change forwarding rule |
6096 | * if the rule already exists, we will check if it exists with |
6097 | * same vsi_id, if not then add it to the VSI list if it already |
6098 | * exists if not then create a VSI list and add the existing VSI |
6099 | * ID and the new VSI ID to the list |
6100 | * We will add that VSI to the list |
6101 | */ |
6102 | status = ice_adv_add_update_vsi_list(hw, m_entry, |
6103 | cur_fltr: &m_entry->rule_info, |
6104 | new_fltr: rinfo); |
6105 | if (added_entry) { |
6106 | added_entry->rid = rid; |
6107 | added_entry->rule_id = m_entry->rule_info.fltr_rule_id; |
6108 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; |
6109 | } |
6110 | goto free_pkt_profile; |
6111 | } |
6112 | rule_buf_sz = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, profile->pkt_len); |
6113 | s_rule = kzalloc(size: rule_buf_sz, GFP_KERNEL); |
6114 | if (!s_rule) { |
6115 | status = -ENOMEM; |
6116 | goto free_pkt_profile; |
6117 | } |
6118 | if (!rinfo->flags_info.act_valid) { |
6119 | act |= ICE_SINGLE_ACT_LAN_ENABLE; |
6120 | act |= ICE_SINGLE_ACT_LB_ENABLE; |
6121 | } else { |
6122 | act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE | |
6123 | ICE_SINGLE_ACT_LB_ENABLE); |
6124 | } |
6125 | |
6126 | switch (rinfo->sw_act.fltr_act) { |
6127 | case ICE_FWD_TO_VSI: |
6128 | act |= (rinfo->sw_act.fwd_id.hw_vsi_id << |
6129 | ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; |
6130 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT; |
6131 | break; |
6132 | case ICE_FWD_TO_Q: |
6133 | act |= ICE_SINGLE_ACT_TO_Q; |
6134 | act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & |
6135 | ICE_SINGLE_ACT_Q_INDEX_M; |
6136 | break; |
6137 | case ICE_FWD_TO_QGRP: |
6138 | q_rgn = rinfo->sw_act.qgrp_size > 0 ? |
6139 | (u8)ilog2(rinfo->sw_act.qgrp_size) : 0; |
6140 | act |= ICE_SINGLE_ACT_TO_Q; |
6141 | act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & |
6142 | ICE_SINGLE_ACT_Q_INDEX_M; |
6143 | act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & |
6144 | ICE_SINGLE_ACT_Q_REGION_M; |
6145 | break; |
6146 | case ICE_DROP_PACKET: |
6147 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | |
6148 | ICE_SINGLE_ACT_VALID_BIT; |
6149 | break; |
6150 | case ICE_NOP: |
6151 | act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, |
6152 | rinfo->sw_act.fwd_id.hw_vsi_id); |
6153 | act &= ~ICE_SINGLE_ACT_VALID_BIT; |
6154 | break; |
6155 | default: |
6156 | status = -EIO; |
6157 | goto err_ice_add_adv_rule; |
6158 | } |
6159 | |
6160 | /* If there is no matching criteria for direction there |
6161 | * is only one difference between Rx and Tx: |
6162 | * - get switch id base on VSI number from source field (Tx) |
6163 | * - get switch id base on port number (Rx) |
6164 | * |
6165 | * If matching on direction metadata is chose rule direction is |
6166 | * extracted from type value set here. |
6167 | */ |
6168 | if (rinfo->sw_act.flag & ICE_FLTR_TX) { |
6169 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); |
6170 | s_rule->src = cpu_to_le16(rinfo->sw_act.src); |
6171 | } else { |
6172 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); |
6173 | s_rule->src = cpu_to_le16(hw->port_info->lport); |
6174 | } |
6175 | |
6176 | s_rule->recipe_id = cpu_to_le16(rid); |
6177 | s_rule->act = cpu_to_le32(act); |
6178 | |
6179 | status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, profile); |
6180 | if (status) |
6181 | goto err_ice_add_adv_rule; |
6182 | |
6183 | status = ice_fill_adv_packet_tun(hw, tun_type: rinfo->tun_type, pkt: s_rule->hdr_data, |
6184 | offsets: profile->offsets); |
6185 | if (status) |
6186 | goto err_ice_add_adv_rule; |
6187 | |
6188 | status = ice_fill_adv_packet_vlan(hw, vlan_type: rinfo->vlan_type, |
6189 | pkt: s_rule->hdr_data, |
6190 | offsets: profile->offsets); |
6191 | if (status) |
6192 | goto err_ice_add_adv_rule; |
6193 | |
6194 | status = ice_aq_sw_rules(hw, rule_list: (struct ice_aqc_sw_rules *)s_rule, |
6195 | rule_list_sz: rule_buf_sz, num_rules: 1, opc: ice_aqc_opc_add_sw_rules, |
6196 | NULL); |
6197 | if (status) |
6198 | goto err_ice_add_adv_rule; |
6199 | adv_fltr = devm_kzalloc(dev: ice_hw_to_dev(hw), |
6200 | size: sizeof(struct ice_adv_fltr_mgmt_list_entry), |
6201 | GFP_KERNEL); |
6202 | if (!adv_fltr) { |
6203 | status = -ENOMEM; |
6204 | goto err_ice_add_adv_rule; |
6205 | } |
6206 | |
6207 | adv_fltr->lkups = devm_kmemdup(dev: ice_hw_to_dev(hw), src: lkups, |
6208 | len: lkups_cnt * sizeof(*lkups), GFP_KERNEL); |
6209 | if (!adv_fltr->lkups) { |
6210 | status = -ENOMEM; |
6211 | goto err_ice_add_adv_rule; |
6212 | } |
6213 | |
6214 | adv_fltr->lkups_cnt = lkups_cnt; |
6215 | adv_fltr->rule_info = *rinfo; |
6216 | adv_fltr->rule_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
6217 | sw = hw->switch_info; |
6218 | sw->recp_list[rid].adv_rule = true; |
6219 | rule_head = &sw->recp_list[rid].filt_rules; |
6220 | |
6221 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) |
6222 | adv_fltr->vsi_count = 1; |
6223 | |
6224 | /* Add rule entry to book keeping list */ |
6225 | list_add(new: &adv_fltr->list_entry, head: rule_head); |
6226 | if (added_entry) { |
6227 | added_entry->rid = rid; |
6228 | added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id; |
6229 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; |
6230 | } |
6231 | err_ice_add_adv_rule: |
6232 | if (status && adv_fltr) { |
6233 | devm_kfree(dev: ice_hw_to_dev(hw), p: adv_fltr->lkups); |
6234 | devm_kfree(dev: ice_hw_to_dev(hw), p: adv_fltr); |
6235 | } |
6236 | |
6237 | kfree(objp: s_rule); |
6238 | |
6239 | free_pkt_profile: |
6240 | if (profile->match & ICE_PKT_KMALLOC) { |
6241 | kfree(objp: profile->offsets); |
6242 | kfree(objp: profile->pkt); |
6243 | kfree(objp: profile); |
6244 | } |
6245 | |
6246 | return status; |
6247 | } |
6248 | |
6249 | /** |
6250 | * ice_replay_vsi_fltr - Replay filters for requested VSI |
6251 | * @hw: pointer to the hardware structure |
6252 | * @vsi_handle: driver VSI handle |
6253 | * @recp_id: Recipe ID for which rules need to be replayed |
6254 | * @list_head: list for which filters need to be replayed |
6255 | * |
6256 | * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. |
6257 | * It is required to pass valid VSI handle. |
6258 | */ |
6259 | static int |
6260 | ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, |
6261 | struct list_head *list_head) |
6262 | { |
6263 | struct ice_fltr_mgmt_list_entry *itr; |
6264 | int status = 0; |
6265 | u16 hw_vsi_id; |
6266 | |
6267 | if (list_empty(head: list_head)) |
6268 | return status; |
6269 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
6270 | |
6271 | list_for_each_entry(itr, list_head, list_entry) { |
6272 | struct ice_fltr_list_entry f_entry; |
6273 | |
6274 | f_entry.fltr_info = itr->fltr_info; |
6275 | if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && |
6276 | itr->fltr_info.vsi_handle == vsi_handle) { |
6277 | /* update the src in case it is VSI num */ |
6278 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6279 | f_entry.fltr_info.src = hw_vsi_id; |
6280 | status = ice_add_rule_internal(hw, recp_id, f_entry: &f_entry); |
6281 | if (status) |
6282 | goto end; |
6283 | continue; |
6284 | } |
6285 | if (!itr->vsi_list_info || |
6286 | !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) |
6287 | continue; |
6288 | /* Clearing it so that the logic can add it back */ |
6289 | clear_bit(nr: vsi_handle, addr: itr->vsi_list_info->vsi_map); |
6290 | f_entry.fltr_info.vsi_handle = vsi_handle; |
6291 | f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; |
6292 | /* update the src in case it is VSI num */ |
6293 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6294 | f_entry.fltr_info.src = hw_vsi_id; |
6295 | if (recp_id == ICE_SW_LKUP_VLAN) |
6296 | status = ice_add_vlan_internal(hw, f_entry: &f_entry); |
6297 | else |
6298 | status = ice_add_rule_internal(hw, recp_id, f_entry: &f_entry); |
6299 | if (status) |
6300 | goto end; |
6301 | } |
6302 | end: |
6303 | return status; |
6304 | } |
6305 | |
6306 | /** |
6307 | * ice_adv_rem_update_vsi_list |
6308 | * @hw: pointer to the hardware structure |
6309 | * @vsi_handle: VSI handle of the VSI to remove |
6310 | * @fm_list: filter management entry for which the VSI list management needs to |
6311 | * be done |
6312 | */ |
6313 | static int |
6314 | ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
6315 | struct ice_adv_fltr_mgmt_list_entry *fm_list) |
6316 | { |
6317 | struct ice_vsi_list_map_info *vsi_list_info; |
6318 | enum ice_sw_lkup_type lkup_type; |
6319 | u16 vsi_list_id; |
6320 | int status; |
6321 | |
6322 | if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST || |
6323 | fm_list->vsi_count == 0) |
6324 | return -EINVAL; |
6325 | |
6326 | /* A rule with the VSI being removed does not exist */ |
6327 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) |
6328 | return -ENOENT; |
6329 | |
6330 | lkup_type = ICE_SW_LKUP_LAST; |
6331 | vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id; |
6332 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &vsi_handle, num_vsi: 1, vsi_list_id, remove: true, |
6333 | opc: ice_aqc_opc_update_sw_rules, |
6334 | lkup_type); |
6335 | if (status) |
6336 | return status; |
6337 | |
6338 | fm_list->vsi_count--; |
6339 | clear_bit(nr: vsi_handle, addr: fm_list->vsi_list_info->vsi_map); |
6340 | vsi_list_info = fm_list->vsi_list_info; |
6341 | if (fm_list->vsi_count == 1) { |
6342 | struct ice_fltr_info tmp_fltr; |
6343 | u16 rem_vsi_handle; |
6344 | |
6345 | rem_vsi_handle = find_first_bit(addr: vsi_list_info->vsi_map, |
6346 | ICE_MAX_VSI); |
6347 | if (!ice_is_vsi_valid(hw, vsi_handle: rem_vsi_handle)) |
6348 | return -EIO; |
6349 | |
6350 | /* Make sure VSI list is empty before removing it below */ |
6351 | status = ice_update_vsi_list_rule(hw, vsi_handle_arr: &rem_vsi_handle, num_vsi: 1, |
6352 | vsi_list_id, remove: true, |
6353 | opc: ice_aqc_opc_update_sw_rules, |
6354 | lkup_type); |
6355 | if (status) |
6356 | return status; |
6357 | |
6358 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); |
6359 | tmp_fltr.flag = fm_list->rule_info.sw_act.flag; |
6360 | tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id; |
6361 | fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; |
6362 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI; |
6363 | tmp_fltr.fwd_id.hw_vsi_id = |
6364 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
6365 | fm_list->rule_info.sw_act.fwd_id.hw_vsi_id = |
6366 | ice_get_hw_vsi_num(hw, vsi_handle: rem_vsi_handle); |
6367 | fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle; |
6368 | |
6369 | /* Update the previous switch rule of "MAC forward to VSI" to |
6370 | * "MAC fwd to VSI list" |
6371 | */ |
6372 | status = ice_update_pkt_fwd_rule(hw, f_info: &tmp_fltr); |
6373 | if (status) { |
6374 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n" , |
6375 | tmp_fltr.fwd_id.hw_vsi_id, status); |
6376 | return status; |
6377 | } |
6378 | fm_list->vsi_list_info->ref_cnt--; |
6379 | |
6380 | /* Remove the VSI list since it is no longer used */ |
6381 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); |
6382 | if (status) { |
6383 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n" , |
6384 | vsi_list_id, status); |
6385 | return status; |
6386 | } |
6387 | |
6388 | list_del(entry: &vsi_list_info->list_entry); |
6389 | devm_kfree(dev: ice_hw_to_dev(hw), p: vsi_list_info); |
6390 | fm_list->vsi_list_info = NULL; |
6391 | } |
6392 | |
6393 | return status; |
6394 | } |
6395 | |
6396 | /** |
6397 | * ice_rem_adv_rule - removes existing advanced switch rule |
6398 | * @hw: pointer to the hardware structure |
6399 | * @lkups: information on the words that needs to be looked up. All words |
6400 | * together makes one recipe |
6401 | * @lkups_cnt: num of entries in the lkups array |
6402 | * @rinfo: Its the pointer to the rule information for the rule |
6403 | * |
6404 | * This function can be used to remove 1 rule at a time. The lkups is |
6405 | * used to describe all the words that forms the "lookup" portion of the |
6406 | * rule. These words can span multiple protocols. Callers to this function |
6407 | * need to pass in a list of protocol headers with lookup information along |
6408 | * and mask that determines which words are valid from the given protocol |
6409 | * header. rinfo describes other information related to this rule such as |
6410 | * forwarding IDs, priority of this rule, etc. |
6411 | */ |
6412 | static int |
6413 | ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6414 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo) |
6415 | { |
6416 | struct ice_adv_fltr_mgmt_list_entry *list_elem; |
6417 | struct ice_prot_lkup_ext lkup_exts; |
6418 | bool remove_rule = false; |
6419 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
6420 | u16 i, rid, vsi_handle; |
6421 | int status = 0; |
6422 | |
6423 | memset(&lkup_exts, 0, sizeof(lkup_exts)); |
6424 | for (i = 0; i < lkups_cnt; i++) { |
6425 | u16 count; |
6426 | |
6427 | if (lkups[i].type >= ICE_PROTOCOL_LAST) |
6428 | return -EIO; |
6429 | |
6430 | count = ice_fill_valid_words(rule: &lkups[i], lkup_exts: &lkup_exts); |
6431 | if (!count) |
6432 | return -EIO; |
6433 | } |
6434 | |
6435 | rid = ice_find_recp(hw, lkup_exts: &lkup_exts, rinfo); |
6436 | /* If did not find a recipe that match the existing criteria */ |
6437 | if (rid == ICE_MAX_NUM_RECIPES) |
6438 | return -EINVAL; |
6439 | |
6440 | rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock; |
6441 | list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, recp_id: rid, rinfo); |
6442 | /* the rule is already removed */ |
6443 | if (!list_elem) |
6444 | return 0; |
6445 | mutex_lock(rule_lock); |
6446 | if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) { |
6447 | remove_rule = true; |
6448 | } else if (list_elem->vsi_count > 1) { |
6449 | remove_rule = false; |
6450 | vsi_handle = rinfo->sw_act.vsi_handle; |
6451 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
6452 | } else { |
6453 | vsi_handle = rinfo->sw_act.vsi_handle; |
6454 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, fm_list: list_elem); |
6455 | if (status) { |
6456 | mutex_unlock(lock: rule_lock); |
6457 | return status; |
6458 | } |
6459 | if (list_elem->vsi_count == 0) |
6460 | remove_rule = true; |
6461 | } |
6462 | mutex_unlock(lock: rule_lock); |
6463 | if (remove_rule) { |
6464 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
6465 | u16 rule_buf_sz; |
6466 | |
6467 | rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule); |
6468 | s_rule = kzalloc(size: rule_buf_sz, GFP_KERNEL); |
6469 | if (!s_rule) |
6470 | return -ENOMEM; |
6471 | s_rule->act = 0; |
6472 | s_rule->index = cpu_to_le16(list_elem->rule_info.fltr_rule_id); |
6473 | s_rule->hdr_len = 0; |
6474 | status = ice_aq_sw_rules(hw, rule_list: (struct ice_aqc_sw_rules *)s_rule, |
6475 | rule_list_sz: rule_buf_sz, num_rules: 1, |
6476 | opc: ice_aqc_opc_remove_sw_rules, NULL); |
6477 | if (!status || status == -ENOENT) { |
6478 | struct ice_switch_info *sw = hw->switch_info; |
6479 | |
6480 | mutex_lock(rule_lock); |
6481 | list_del(entry: &list_elem->list_entry); |
6482 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem->lkups); |
6483 | devm_kfree(dev: ice_hw_to_dev(hw), p: list_elem); |
6484 | mutex_unlock(lock: rule_lock); |
6485 | if (list_empty(head: &sw->recp_list[rid].filt_rules)) |
6486 | sw->recp_list[rid].adv_rule = false; |
6487 | } |
6488 | kfree(objp: s_rule); |
6489 | } |
6490 | return status; |
6491 | } |
6492 | |
6493 | /** |
6494 | * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID |
6495 | * @hw: pointer to the hardware structure |
6496 | * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID |
6497 | * |
6498 | * This function is used to remove 1 rule at a time. The removal is based on |
6499 | * the remove_entry parameter. This function will remove rule for a given |
6500 | * vsi_handle with a given rule_id which is passed as parameter in remove_entry |
6501 | */ |
6502 | int |
6503 | ice_rem_adv_rule_by_id(struct ice_hw *hw, |
6504 | struct ice_rule_query_data *remove_entry) |
6505 | { |
6506 | struct ice_adv_fltr_mgmt_list_entry *list_itr; |
6507 | struct list_head *list_head; |
6508 | struct ice_adv_rule_info rinfo; |
6509 | struct ice_switch_info *sw; |
6510 | |
6511 | sw = hw->switch_info; |
6512 | if (!sw->recp_list[remove_entry->rid].recp_created) |
6513 | return -EINVAL; |
6514 | list_head = &sw->recp_list[remove_entry->rid].filt_rules; |
6515 | list_for_each_entry(list_itr, list_head, list_entry) { |
6516 | if (list_itr->rule_info.fltr_rule_id == |
6517 | remove_entry->rule_id) { |
6518 | rinfo = list_itr->rule_info; |
6519 | rinfo.sw_act.vsi_handle = remove_entry->vsi_handle; |
6520 | return ice_rem_adv_rule(hw, lkups: list_itr->lkups, |
6521 | lkups_cnt: list_itr->lkups_cnt, rinfo: &rinfo); |
6522 | } |
6523 | } |
6524 | /* either list is empty or unable to find rule */ |
6525 | return -ENOENT; |
6526 | } |
6527 | |
6528 | /** |
6529 | * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI |
6530 | * @hw: pointer to the hardware structure |
6531 | * @vsi_handle: driver VSI handle |
6532 | * @list_head: list for which filters need to be replayed |
6533 | * |
6534 | * Replay the advanced rule for the given VSI. |
6535 | */ |
6536 | static int |
6537 | ice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle, |
6538 | struct list_head *list_head) |
6539 | { |
6540 | struct ice_rule_query_data added_entry = { 0 }; |
6541 | struct ice_adv_fltr_mgmt_list_entry *adv_fltr; |
6542 | int status = 0; |
6543 | |
6544 | if (list_empty(head: list_head)) |
6545 | return status; |
6546 | list_for_each_entry(adv_fltr, list_head, list_entry) { |
6547 | struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info; |
6548 | u16 lk_cnt = adv_fltr->lkups_cnt; |
6549 | |
6550 | if (vsi_handle != rinfo->sw_act.vsi_handle) |
6551 | continue; |
6552 | status = ice_add_adv_rule(hw, lkups: adv_fltr->lkups, lkups_cnt: lk_cnt, rinfo, |
6553 | added_entry: &added_entry); |
6554 | if (status) |
6555 | break; |
6556 | } |
6557 | return status; |
6558 | } |
6559 | |
6560 | /** |
6561 | * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists |
6562 | * @hw: pointer to the hardware structure |
6563 | * @vsi_handle: driver VSI handle |
6564 | * |
6565 | * Replays filters for requested VSI via vsi_handle. |
6566 | */ |
6567 | int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) |
6568 | { |
6569 | struct ice_switch_info *sw = hw->switch_info; |
6570 | int status; |
6571 | u8 i; |
6572 | |
6573 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
6574 | struct list_head *head; |
6575 | |
6576 | head = &sw->recp_list[i].filt_replay_rules; |
6577 | if (!sw->recp_list[i].adv_rule) |
6578 | status = ice_replay_vsi_fltr(hw, vsi_handle, recp_id: i, list_head: head); |
6579 | else |
6580 | status = ice_replay_vsi_adv_rule(hw, vsi_handle, list_head: head); |
6581 | if (status) |
6582 | return status; |
6583 | } |
6584 | return status; |
6585 | } |
6586 | |
6587 | /** |
6588 | * ice_rm_all_sw_replay_rule_info - deletes filter replay rules |
6589 | * @hw: pointer to the HW struct |
6590 | * |
6591 | * Deletes the filter replay rules. |
6592 | */ |
6593 | void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) |
6594 | { |
6595 | struct ice_switch_info *sw = hw->switch_info; |
6596 | u8 i; |
6597 | |
6598 | if (!sw) |
6599 | return; |
6600 | |
6601 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
6602 | if (!list_empty(head: &sw->recp_list[i].filt_replay_rules)) { |
6603 | struct list_head *l_head; |
6604 | |
6605 | l_head = &sw->recp_list[i].filt_replay_rules; |
6606 | if (!sw->recp_list[i].adv_rule) |
6607 | ice_rem_sw_rule_info(hw, rule_head: l_head); |
6608 | else |
6609 | ice_rem_adv_rule_info(hw, rule_head: l_head); |
6610 | } |
6611 | } |
6612 | } |
6613 | |