Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : : #include "roc_api.h"
5 : : #include "roc_priv.h"
6 : :
7 : : const struct roc_npc_item_info *
8 : 0 : npc_parse_skip_void_and_any_items(const struct roc_npc_item_info *pattern)
9 : : {
10 [ # # ]: 0 : while ((pattern->type == ROC_NPC_ITEM_TYPE_VOID) ||
11 : : (pattern->type == ROC_NPC_ITEM_TYPE_ANY))
12 : 0 : pattern++;
13 : :
14 : 0 : return pattern;
15 : : }
16 : :
17 : : int
18 : 0 : npc_parse_meta_items(struct npc_parse_state *pst)
19 : : {
20 : : PLT_SET_USED(pst);
21 : 0 : return 0;
22 : : }
23 : :
24 : : int
25 : 0 : npc_parse_mark_item(struct npc_parse_state *pst)
26 : : {
27 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MARK) {
28 [ # # ]: 0 : if (pst->flow->nix_intf != NIX_INTF_RX)
29 : : return -EINVAL;
30 : :
31 : 0 : pst->is_second_pass_rule = true;
32 : 0 : pst->pattern++;
33 : : }
34 : :
35 : : return 0;
36 : : }
37 : :
38 : : static int
39 [ # # ]: 0 : npc_flow_raw_item_prepare(const struct roc_npc_flow_item_raw *raw_spec,
40 : : const struct roc_npc_flow_item_raw *raw_mask,
41 : : struct npc_parse_item_info *info, uint8_t *spec_buf,
42 : : uint8_t *mask_buf)
43 : : {
44 : :
45 : : memset(spec_buf, 0, NPC_MAX_RAW_ITEM_LEN);
46 : : memset(mask_buf, 0, NPC_MAX_RAW_ITEM_LEN);
47 : :
48 : 0 : memcpy(spec_buf + raw_spec->offset, raw_spec->pattern,
49 [ # # ]: 0 : raw_spec->length);
50 : :
51 [ # # # # ]: 0 : if (raw_mask && raw_mask->pattern) {
52 : 0 : memcpy(mask_buf + raw_spec->offset, raw_mask->pattern,
53 : 0 : raw_spec->length);
54 : : } else {
55 : 0 : memset(mask_buf + raw_spec->offset, 0xFF, raw_spec->length);
56 : : }
57 : :
58 : 0 : info->len = NPC_MAX_RAW_ITEM_LEN;
59 : 0 : info->spec = spec_buf;
60 : 0 : info->mask = mask_buf;
61 : 0 : return 0;
62 : : }
63 : :
64 : : int
65 : 0 : npc_parse_pre_l2(struct npc_parse_state *pst)
66 : : {
67 : 0 : uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
68 : 0 : uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
69 : 0 : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN] = {0};
70 : : const struct roc_npc_flow_item_raw *raw_spec;
71 : : struct npc_parse_item_info info;
72 : : int lid, lt, len;
73 : : int rc;
74 : :
75 [ # # ]: 0 : if (pst->npc->switch_header_type != ROC_PRIV_FLAGS_PRE_L2)
76 : : return 0;
77 : :
78 : : /* Identify the pattern type into lid, lt */
79 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_RAW)
80 : : return 0;
81 : :
82 : : lid = NPC_LID_LA;
83 : : lt = NPC_LT_LA_CUSTOM_PRE_L2_ETHER;
84 : 0 : info.hw_hdr_len = 0;
85 : :
86 : 0 : raw_spec = pst->pattern->spec;
87 : 0 : len = raw_spec->length + raw_spec->offset;
88 [ # # ]: 0 : if (len > NPC_MAX_RAW_ITEM_LEN)
89 : : return -EINVAL;
90 : :
91 [ # # # # : 0 : if (raw_spec->relative == 0 || raw_spec->search || raw_spec->limit ||
# # ]
92 : : raw_spec->offset < 0)
93 : : return -EINVAL;
94 : :
95 : 0 : npc_flow_raw_item_prepare(
96 : : (const struct roc_npc_flow_item_raw *)pst->pattern->spec,
97 : 0 : (const struct roc_npc_flow_item_raw *)pst->pattern->mask, &info,
98 : : raw_spec_buf, raw_mask_buf);
99 : :
100 : 0 : info.def_mask = NULL;
101 : 0 : info.hw_mask = &hw_mask;
102 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
103 : :
104 : : /* Basic validation of item parameters */
105 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
106 [ # # ]: 0 : if (rc)
107 : : return rc;
108 : :
109 : : /* Update pst if not validate only? clash check? */
110 : 0 : return npc_update_parse_state(pst, &info, lid, lt, 0);
111 : : }
112 : :
113 : : int
114 : 0 : npc_parse_cpt_hdr(struct npc_parse_state *pst)
115 : : {
116 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
117 : : struct npc_parse_item_info info;
118 : : int lid, lt;
119 : : int rc;
120 : :
121 : : /* Identify the pattern type into lid, lt */
122 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR)
123 : : return 0;
124 : :
125 : : lid = NPC_LID_LA;
126 : : lt = NPC_LT_LA_CPT_HDR;
127 : 0 : info.hw_hdr_len = 0;
128 : :
129 : : /* Prepare for parsing the item */
130 : 0 : info.def_mask = NULL;
131 : 0 : info.hw_mask = &hw_mask;
132 : 0 : info.len = pst->pattern->size;
133 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
134 : 0 : info.spec = NULL;
135 : 0 : info.mask = NULL;
136 : :
137 : : /* Basic validation of item parameters */
138 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
139 [ # # ]: 0 : if (rc)
140 : : return rc;
141 : :
142 : : /* Update pst if not validate only? clash check? */
143 : 0 : return npc_update_parse_state(pst, &info, lid, lt, 0);
144 : : }
145 : :
146 : : int
147 : 0 : npc_parse_higig2_hdr(struct npc_parse_state *pst)
148 : : {
149 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
150 : : struct npc_parse_item_info info;
151 : : int lid, lt;
152 : : int rc;
153 : :
154 : : /* Identify the pattern type into lid, lt */
155 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
156 : : return 0;
157 : :
158 : : lid = NPC_LID_LA;
159 : : lt = NPC_LT_LA_HIGIG2_ETHER;
160 : 0 : info.hw_hdr_len = 0;
161 : :
162 [ # # ]: 0 : if (pst->flow->nix_intf == NIX_INTF_TX) {
163 : : lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
164 : 0 : info.hw_hdr_len = NPC_IH_LENGTH;
165 : : }
166 : :
167 : : /* Prepare for parsing the item */
168 : 0 : info.def_mask = NULL;
169 : 0 : info.hw_mask = &hw_mask;
170 : 0 : info.len = pst->pattern->size;
171 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
172 : 0 : info.spec = NULL;
173 : 0 : info.mask = NULL;
174 : :
175 : : /* Basic validation of item parameters */
176 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
177 [ # # ]: 0 : if (rc)
178 : : return rc;
179 : :
180 : : /* Update pst if not validate only? clash check? */
181 : 0 : return npc_update_parse_state(pst, &info, lid, lt, 0);
182 : : }
183 : :
184 : : int
185 [ # # ]: 0 : npc_parse_tx_queue(struct npc_parse_state *pst)
186 : : {
187 : : struct nix_inst_hdr_s nix_inst_hdr, nix_inst_hdr_mask;
188 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
189 : : struct npc_parse_item_info parse_info;
190 : : const uint16_t *send_queue;
191 : : int lid, lt, rc = 0;
192 : :
193 : : memset(&nix_inst_hdr, 0, sizeof(nix_inst_hdr));
194 : : memset(&nix_inst_hdr_mask, 0, sizeof(nix_inst_hdr_mask));
195 : : memset(&parse_info, 0, sizeof(parse_info));
196 : :
197 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_TX_QUEUE)
198 : : return 0;
199 : :
200 [ # # ]: 0 : if (pst->flow->nix_intf != NIX_INTF_TX)
201 : : return NPC_ERR_INVALID_SPEC;
202 : :
203 : : lid = NPC_LID_LA;
204 : : lt = NPC_LT_LA_IH_NIX_ETHER;
205 : 0 : send_queue = (const uint16_t *)pst->pattern->spec;
206 : :
207 [ # # ]: 0 : if (*send_queue >= pst->nb_tx_queues)
208 : : return NPC_ERR_INVALID_SPEC;
209 : :
210 : 0 : nix_inst_hdr.sq = *send_queue;
211 : 0 : nix_inst_hdr_mask.sq = 0xFFFF;
212 : :
213 : : parse_info.def_mask = NULL;
214 : 0 : parse_info.spec = &nix_inst_hdr;
215 : 0 : parse_info.mask = &nix_inst_hdr_mask;
216 : 0 : parse_info.len = sizeof(nix_inst_hdr);
217 : : parse_info.def_mask = NULL;
218 : : parse_info.hw_hdr_len = 0;
219 : :
220 : : memset(hw_mask, 0, sizeof(hw_mask));
221 : :
222 : 0 : parse_info.hw_mask = &hw_mask;
223 : 0 : npc_get_hw_supp_mask(pst, &parse_info, lid, lt);
224 : :
225 : 0 : rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
226 [ # # ]: 0 : if (!rc)
227 : : return NPC_ERR_INVALID_MASK;
228 : :
229 : 0 : rc = npc_update_parse_state(pst, &parse_info, lid, lt, 0);
230 [ # # ]: 0 : if (rc)
231 : 0 : return rc;
232 : :
233 : : return 0;
234 : : }
235 : :
236 : : int
237 : 0 : npc_parse_la(struct npc_parse_state *pst)
238 : : {
239 : : const struct roc_npc_flow_item_eth *eth_item;
240 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
241 : : struct npc_parse_item_info info;
242 : : int lid, lt;
243 : : int rc;
244 : :
245 : : /* Identify the pattern type into lid, lt */
246 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
247 : : return 0;
248 : :
249 : 0 : pst->has_eth_type = true;
250 : 0 : eth_item = pst->pattern->spec;
251 : :
252 : : lid = NPC_LID_LA;
253 : : lt = NPC_LT_LA_ETHER;
254 : 0 : info.hw_hdr_len = 0;
255 : :
256 [ # # ]: 0 : if (pst->flow->nix_intf == NIX_INTF_TX) {
257 : : lt = NPC_LT_LA_IH_NIX_ETHER;
258 : 0 : info.hw_hdr_len = NPC_IH_LENGTH;
259 [ # # ]: 0 : if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
260 : : lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
261 : 0 : info.hw_hdr_len += NPC_HIGIG2_LENGTH;
262 : : }
263 : : } else {
264 [ # # ]: 0 : if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
265 : : lt = NPC_LT_LA_HIGIG2_ETHER;
266 : 0 : info.hw_hdr_len = NPC_HIGIG2_LENGTH;
267 : : }
268 : : }
269 : :
270 : : /* Prepare for parsing the item */
271 : 0 : info.def_mask = NULL;
272 : 0 : info.hw_mask = &hw_mask;
273 : 0 : info.len = sizeof(eth_item->hdr);
274 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
275 : 0 : info.spec = NULL;
276 : 0 : info.mask = NULL;
277 : :
278 : : /* Basic validation of item parameters */
279 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
280 [ # # ]: 0 : if (rc)
281 : : return rc;
282 : :
283 : 0 : rc = npc_update_parse_state(pst, &info, lid, lt, 0);
284 [ # # ]: 0 : if (rc)
285 : : return rc;
286 : :
287 [ # # # # ]: 0 : if (eth_item && eth_item->has_vlan)
288 : 0 : pst->set_vlan_ltype_mask = true;
289 : :
290 : : return 0;
291 : : }
292 : :
293 : : #define NPC_MAX_SUPPORTED_VLANS 3
294 : :
295 : : static int
296 : 0 : npc_parse_vlan_count(const struct roc_npc_item_info *pattern,
297 : : const struct roc_npc_item_info **pattern_list,
298 : : const struct roc_npc_flow_item_vlan **vlan_items, int *vlan_count)
299 : : {
300 : 0 : *vlan_count = 0;
301 [ # # ]: 0 : while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
302 [ # # ]: 0 : if (*vlan_count > NPC_MAX_SUPPORTED_VLANS - 1)
303 : : return NPC_ERR_PATTERN_NOTSUP;
304 : :
305 : : /* Don't support ranges */
306 [ # # ]: 0 : if (pattern->last != NULL)
307 : : return NPC_ERR_INVALID_RANGE;
308 : :
309 : : /* If spec is NULL, both mask and last must be NULL, this
310 : : * makes it to match ANY value (eq to mask = 0).
311 : : * Setting either mask or last without spec is an error
312 : : */
313 : : if (pattern->spec == NULL) {
314 : : if (pattern->last != NULL && pattern->mask != NULL)
315 : : return NPC_ERR_INVALID_SPEC;
316 : : }
317 : :
318 : 0 : pattern_list[*vlan_count] = pattern;
319 : 0 : vlan_items[*vlan_count] = pattern->spec;
320 : 0 : (*vlan_count)++;
321 : :
322 : 0 : pattern++;
323 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
324 : : }
325 : :
326 : : return 0;
327 : : }
328 : :
329 : : static int
330 : 0 : npc_parse_vlan_ltype_get(struct npc_parse_state *pst,
331 : : const struct roc_npc_flow_item_vlan **vlan_item, int vlan_count,
332 : : int *ltype, int *lflags)
333 : : {
334 [ # # # # ]: 0 : switch (vlan_count) {
335 : 0 : case 1:
336 : 0 : *ltype = NPC_LT_LB_CTAG;
337 [ # # # # ]: 0 : if (vlan_item[0] && vlan_item[0]->has_more_vlan)
338 : 0 : *ltype = NPC_LT_LB_STAG_QINQ;
339 : : break;
340 : 0 : case 2:
341 [ # # # # ]: 0 : if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
342 [ # # ]: 0 : if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
343 : : 0x3ULL << NPC_LFLAG_LB_OFFSET))
344 : : return NPC_ERR_PATTERN_NOTSUP;
345 : :
346 : : /* This lflag value will match either one of
347 : : * NPC_F_LB_L_WITH_STAG_STAG,
348 : : * NPC_F_LB_L_WITH_QINQ_CTAG,
349 : : * NPC_F_LB_L_WITH_QINQ_QINQ and
350 : : * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
351 : : * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
352 : : * hence will not match.
353 : : */
354 : :
355 : 0 : *lflags = NPC_F_LB_L_WITH_QINQ_CTAG & NPC_F_LB_L_WITH_QINQ_QINQ &
356 : : NPC_F_LB_L_WITH_STAG_STAG;
357 : : }
358 : 0 : *ltype = NPC_LT_LB_STAG_QINQ;
359 : 0 : break;
360 : 0 : case 3:
361 [ # # # # ]: 0 : if (vlan_item[2] && vlan_item[2]->has_more_vlan)
362 : : return NPC_ERR_PATTERN_NOTSUP;
363 [ # # ]: 0 : if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] & 0x3ULL << NPC_LFLAG_LB_OFFSET))
364 : : return NPC_ERR_PATTERN_NOTSUP;
365 : 0 : *ltype = NPC_LT_LB_STAG_QINQ;
366 : 0 : *lflags = NPC_F_STAG_STAG_CTAG;
367 : 0 : break;
368 : : default:
369 : : return NPC_ERR_PATTERN_NOTSUP;
370 : : }
371 : :
372 : : return 0;
373 : : }
374 : :
375 : : static int
376 : 0 : npc_update_vlan_parse_state(struct npc_parse_state *pst, const struct roc_npc_item_info *pattern,
377 : : int lid, int lt, uint8_t lflags, int vlan_count)
378 : : {
379 : : uint8_t vlan_spec[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
380 : : uint8_t vlan_mask[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
381 : : int rc = 0, i, offset = NPC_TPID_LENGTH;
382 : : struct npc_parse_item_info parse_info;
383 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
384 : :
385 : : memset(vlan_spec, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
386 : : memset(vlan_mask, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
387 : : memset(&parse_info, 0, sizeof(parse_info));
388 : :
389 : : if (vlan_count > 2)
390 : : vlan_count = 2;
391 : :
392 [ # # ]: 0 : for (i = 0; i < vlan_count; i++) {
393 [ # # ]: 0 : if (pattern[i].spec)
394 : 0 : memcpy(vlan_spec + offset, pattern[i].spec, sizeof(struct roc_vlan_hdr));
395 [ # # ]: 0 : if (pattern[i].mask)
396 : 0 : memcpy(vlan_mask + offset, pattern[i].mask, sizeof(struct roc_vlan_hdr));
397 : :
398 : 0 : offset += 4;
399 : : }
400 : :
401 : : parse_info.def_mask = NULL;
402 : 0 : parse_info.spec = vlan_spec;
403 : 0 : parse_info.mask = vlan_mask;
404 : : parse_info.def_mask = NULL;
405 : : parse_info.hw_hdr_len = 0;
406 : :
407 : : lid = NPC_LID_LB;
408 : 0 : parse_info.hw_mask = hw_mask;
409 : :
410 [ # # ]: 0 : if (lt == NPC_LT_LB_CTAG)
411 : 0 : parse_info.len = sizeof(struct roc_vlan_hdr) + NPC_TPID_LENGTH;
412 : :
413 [ # # ]: 0 : if (lt == NPC_LT_LB_STAG_QINQ)
414 : 0 : parse_info.len = sizeof(struct roc_vlan_hdr) * 2 + NPC_TPID_LENGTH;
415 : :
416 : : memset(hw_mask, 0, sizeof(hw_mask));
417 : :
418 : : parse_info.hw_mask = &hw_mask;
419 : 0 : npc_get_hw_supp_mask(pst, &parse_info, lid, lt);
420 : :
421 : 0 : rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
422 [ # # ]: 0 : if (!rc)
423 : : return NPC_ERR_INVALID_MASK;
424 : :
425 : : /* Point pattern to last item consumed */
426 : 0 : pst->pattern = pattern;
427 : 0 : return npc_update_parse_state(pst, &parse_info, lid, lt, lflags);
428 : : }
429 : :
430 : : static int
431 : 0 : npc_parse_lb_vlan(struct npc_parse_state *pst)
432 : : {
433 : : const struct roc_npc_flow_item_vlan *vlan_items[NPC_MAX_SUPPORTED_VLANS];
434 : : const struct roc_npc_item_info *pattern_list[NPC_MAX_SUPPORTED_VLANS];
435 : : const struct roc_npc_item_info *last_pattern;
436 : 0 : int vlan_count = 0, rc = 0;
437 : : int lid, lt, lflags;
438 : :
439 : : lid = NPC_LID_LB;
440 : 0 : lflags = 0;
441 : 0 : last_pattern = pst->pattern;
442 : :
443 : 0 : rc = npc_parse_vlan_count(pst->pattern, pattern_list, vlan_items, &vlan_count);
444 [ # # ]: 0 : if (rc)
445 : : return rc;
446 : :
447 : 0 : rc = npc_parse_vlan_ltype_get(pst, vlan_items, vlan_count, <, &lflags);
448 [ # # ]: 0 : if (rc)
449 : : return rc;
450 : :
451 [ # # ]: 0 : if (vlan_count == 3) {
452 [ # # # # ]: 0 : if (pattern_list[2]->spec != NULL && pattern_list[2]->mask != NULL &&
453 [ # # ]: 0 : pattern_list[2]->last != NULL)
454 : : return NPC_ERR_PATTERN_NOTSUP;
455 : :
456 : : /* Matching can be done only for two tags. */
457 : 0 : vlan_count = 2;
458 : 0 : last_pattern++;
459 : : }
460 : :
461 : 0 : rc = npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags, vlan_count);
462 [ # # ]: 0 : if (rc)
463 : : return rc;
464 : :
465 [ # # ]: 0 : if (vlan_count > 1)
466 : 0 : pst->pattern = last_pattern + vlan_count;
467 : :
468 : : return 0;
469 : : }
470 : :
471 : : int
472 : 0 : npc_parse_lb(struct npc_parse_state *pst)
473 : : {
474 : 0 : const struct roc_npc_item_info *pattern = pst->pattern;
475 : : const struct roc_npc_item_info *last_pattern;
476 : : const struct roc_npc_flow_item_raw *raw_spec;
477 : : uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
478 : : uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
479 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
480 : : struct npc_parse_item_info info;
481 : : int lid, lt, lflags, len = 0;
482 : : int rc;
483 : :
484 : 0 : info.def_mask = NULL;
485 : 0 : info.spec = NULL;
486 : 0 : info.mask = NULL;
487 : : info.def_mask = NULL;
488 : 0 : info.hw_hdr_len = NPC_TPID_LENGTH;
489 : :
490 : : lid = NPC_LID_LB;
491 : : lflags = 0;
492 : : last_pattern = pattern;
493 : :
494 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
495 : : /* RTE vlan is either 802.1q or 802.1ad,
496 : : * this maps to either CTAG/STAG. We need to decide
497 : : * based on number of VLANS present. Matching is
498 : : * supported on first two tags.
499 : : */
500 : :
501 : 0 : return npc_parse_lb_vlan(pst);
502 [ # # ]: 0 : } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
503 : : /* we can support ETAG and match a subsequent CTAG
504 : : * without any matching support.
505 : : */
506 : : lt = NPC_LT_LB_ETAG;
507 : : lflags = 0;
508 : :
509 : : last_pattern = pst->pattern;
510 : 0 : pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
511 [ # # ]: 0 : if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
512 : : /* set supported mask to NULL for vlan tag */
513 : 0 : info.hw_mask = NULL;
514 : 0 : info.len = pattern->size;
515 : 0 : rc = npc_parse_item_basic(pattern, &info);
516 [ # # ]: 0 : if (rc != 0)
517 : : return rc;
518 : :
519 : : lflags = NPC_F_ETAG_CTAG;
520 : : last_pattern = pattern;
521 : : }
522 : 0 : info.len = pattern->size;
523 [ # # ]: 0 : } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
524 : : info.hw_mask = NULL;
525 : 0 : info.len = pattern->size;
526 : : lt = NPC_LT_LB_STAG_QINQ;
527 : : lflags = NPC_F_STAG_CTAG;
528 [ # # ]: 0 : } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
529 : 0 : raw_spec = pst->pattern->spec;
530 [ # # ]: 0 : if (raw_spec->relative)
531 : : return 0;
532 : 0 : len = raw_spec->length + raw_spec->offset;
533 [ # # ]: 0 : if (len > NPC_MAX_RAW_ITEM_LEN)
534 : : return -EINVAL;
535 : :
536 [ # # ]: 0 : if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
537 : : lt = NPC_LT_LB_VLAN_EXDSA;
538 [ # # ]: 0 : } else if (pst->npc->switch_header_type ==
539 : : ROC_PRIV_FLAGS_EXDSA) {
540 : : lt = NPC_LT_LB_EXDSA;
541 : : } else {
542 : : return -EINVAL;
543 : : }
544 : :
545 : 0 : npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
546 : : pst->pattern->spec,
547 : : (const struct roc_npc_flow_item_raw *)
548 : 0 : pst->pattern->mask,
549 : : &info, raw_spec_buf, raw_mask_buf);
550 : :
551 : 0 : info.hw_hdr_len = 0;
552 : : } else {
553 : : return 0;
554 : : }
555 : :
556 : 0 : info.hw_mask = &hw_mask;
557 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
558 : :
559 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
560 [ # # ]: 0 : if (rc != 0)
561 : : return rc;
562 : :
563 : : /* Point pattern to last item consumed */
564 : 0 : pst->pattern = last_pattern;
565 : 0 : return npc_update_parse_state(pst, &info, lid, lt, lflags);
566 : : }
567 : :
568 : : static int
569 : 0 : npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
570 : : {
571 : 0 : uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
572 : : NPC_F_MPLS_4_LABELS};
573 : 0 : const struct roc_npc_item_info *pattern = pst->pattern;
574 : : struct npc_parse_item_info info;
575 : : int nr_labels = 0;
576 : : int rc;
577 : :
578 : : /*
579 : : * pst->pattern points to first MPLS label. We only check
580 : : * that subsequent labels do not have anything to match.
581 : : */
582 : 0 : info.def_mask = NULL;
583 : 0 : info.hw_mask = NULL;
584 : 0 : info.len = pattern->size;
585 : 0 : info.spec = NULL;
586 : 0 : info.mask = NULL;
587 : 0 : info.hw_hdr_len = 0;
588 : :
589 [ # # ]: 0 : while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
590 : 0 : nr_labels++;
591 : :
592 : : /* Basic validation of Second/Third/Fourth mpls item */
593 [ # # ]: 0 : if (nr_labels > 1) {
594 : 0 : rc = npc_parse_item_basic(pattern, &info);
595 [ # # ]: 0 : if (rc != 0)
596 : 0 : return rc;
597 : : }
598 : 0 : pst->last_pattern = pattern;
599 : 0 : pattern++;
600 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
601 : : }
602 : :
603 [ # # ]: 0 : if (nr_labels < 1 || nr_labels > 4)
604 : : return NPC_ERR_PATTERN_NOTSUP;
605 : :
606 : 0 : *flag = flag_list[nr_labels - 1];
607 : 0 : return 0;
608 : : }
609 : :
610 : : static int
611 : 0 : npc_parse_mpls(struct npc_parse_state *pst, int lid)
612 : : {
613 : : /* Find number of MPLS labels */
614 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
615 : : struct npc_parse_item_info info;
616 : : int lt, lflags;
617 : : int rc;
618 : :
619 : 0 : lflags = 0;
620 : :
621 [ # # ]: 0 : if (lid == NPC_LID_LC)
622 : : lt = NPC_LT_LC_MPLS;
623 [ # # ]: 0 : else if (lid == NPC_LID_LD)
624 : : lt = NPC_LT_LD_TU_MPLS_IN_IP;
625 : : else
626 : : lt = NPC_LT_LE_TU_MPLS_IN_UDP;
627 : :
628 : : /* Prepare for parsing the first item */
629 : 0 : info.hw_mask = &hw_mask;
630 : 0 : info.len = pst->pattern->size;
631 : 0 : info.spec = NULL;
632 : 0 : info.mask = NULL;
633 : 0 : info.def_mask = NULL;
634 : 0 : info.hw_hdr_len = 0;
635 : :
636 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
637 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
638 [ # # ]: 0 : if (rc != 0)
639 : : return rc;
640 : :
641 : : /*
642 : : * Parse for more labels.
643 : : * This sets lflags and pst->last_pattern correctly.
644 : : */
645 : 0 : rc = npc_parse_mpls_label_stack(pst, &lflags);
646 [ # # ]: 0 : if (rc != 0)
647 : : return rc;
648 : :
649 : 0 : pst->tunnel = 1;
650 : 0 : pst->pattern = pst->last_pattern;
651 : :
652 : 0 : return npc_update_parse_state(pst, &info, lid, lt, lflags);
653 : : }
654 : :
655 : : static inline void
656 : 0 : npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
657 : : {
658 : 0 : const struct roc_npc_item_info *pattern = pst->pattern + 1;
659 : :
660 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
661 [ # # ]: 0 : if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
662 [ # # ]: 0 : pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
663 : : pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
664 : 0 : pst->tunnel = 1;
665 : 0 : }
666 : :
667 : : static int
668 : 0 : npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
669 : : struct npc_parse_state *pst, uint8_t *flags)
670 : : {
671 : : int flags_count = 0;
672 : :
673 [ # # ]: 0 : if (ipv6_spec->has_hop_ext) {
674 : 0 : *flags = NPC_F_LC_L_EXT_HOP;
675 : : flags_count++;
676 : : }
677 [ # # ]: 0 : if (ipv6_spec->has_route_ext) {
678 : 0 : *flags = NPC_F_LC_L_EXT_ROUT;
679 : 0 : flags_count++;
680 : : }
681 [ # # ]: 0 : if (ipv6_spec->has_frag_ext) {
682 : 0 : *flags = NPC_F_LC_U_IP6_FRAG;
683 : 0 : flags_count++;
684 : : }
685 [ # # ]: 0 : if (ipv6_spec->has_dest_ext) {
686 : 0 : *flags = NPC_F_LC_L_EXT_DEST;
687 : 0 : flags_count++;
688 : : }
689 [ # # ]: 0 : if (ipv6_spec->has_mobil_ext) {
690 : 0 : *flags = NPC_F_LC_L_EXT_MOBILITY;
691 : 0 : flags_count++;
692 : : }
693 [ # # ]: 0 : if (ipv6_spec->has_hip_ext) {
694 : 0 : *flags = NPC_F_LC_L_EXT_HOSTID;
695 : 0 : flags_count++;
696 : : }
697 [ # # ]: 0 : if (ipv6_spec->has_shim6_ext) {
698 : 0 : *flags = NPC_F_LC_L_EXT_SHIM6;
699 : 0 : flags_count++;
700 : : }
701 [ # # ]: 0 : if (ipv6_spec->has_auth_ext) {
702 : 0 : pst->lt[NPC_LID_LD] = NPC_LT_LD_AH;
703 : 0 : flags_count++;
704 : : }
705 [ # # ]: 0 : if (ipv6_spec->has_esp_ext) {
706 : 0 : pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP;
707 : 0 : flags_count++;
708 : : }
709 : :
710 [ # # ]: 0 : if (flags_count > 1)
711 : : return -EINVAL;
712 : :
713 [ # # ]: 0 : if (flags_count)
714 : 0 : pst->set_ipv6ext_ltype_mask = true;
715 : :
716 : : return 0;
717 : : }
718 : :
719 : : static int
720 : 0 : npc_process_ipv6_item(struct npc_parse_state *pst)
721 : : {
722 : : uint8_t ipv6_hdr_mask[2 * sizeof(struct roc_ipv6_hdr)];
723 : : uint8_t ipv6_hdr_buf[2 * sizeof(struct roc_ipv6_hdr)];
724 : : const struct roc_npc_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
725 : 0 : const struct roc_npc_item_info *pattern = pst->pattern;
726 : : int offset = 0, rc = 0, lid, item_count = 0;
727 : : struct npc_parse_item_info parse_info;
728 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
729 [ # # ]: 0 : uint8_t flags = 0, ltype;
730 : :
731 : : memset(ipv6_hdr_buf, 0, sizeof(ipv6_hdr_buf));
732 : : memset(ipv6_hdr_mask, 0, sizeof(ipv6_hdr_mask));
733 : :
734 : 0 : ipv6_spec = pst->pattern->spec;
735 : 0 : ipv6_mask = pst->pattern->mask;
736 : :
737 : 0 : parse_info.def_mask = NULL;
738 : 0 : parse_info.spec = ipv6_hdr_buf;
739 : 0 : parse_info.mask = ipv6_hdr_mask;
740 : : parse_info.def_mask = NULL;
741 : 0 : parse_info.hw_hdr_len = 0;
742 : 0 : parse_info.len = sizeof(ipv6_spec->hdr);
743 : :
744 : 0 : pst->set_ipv6ext_ltype_mask = true;
745 : :
746 : : lid = NPC_LID_LC;
747 : : ltype = NPC_LT_LC_IP6;
748 : :
749 [ # # ]: 0 : if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
750 : : item_count++;
751 [ # # ]: 0 : if (ipv6_spec) {
752 : 0 : memcpy(ipv6_hdr_buf, &ipv6_spec->hdr, sizeof(struct roc_ipv6_hdr));
753 : 0 : rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
754 [ # # ]: 0 : if (rc)
755 : : return rc;
756 : : }
757 [ # # ]: 0 : if (ipv6_mask)
758 : 0 : memcpy(ipv6_hdr_mask, &ipv6_mask->hdr, sizeof(struct roc_ipv6_hdr));
759 : : }
760 : :
761 : : offset = sizeof(struct roc_ipv6_hdr);
762 : :
763 [ # # ]: 0 : while (pattern->type != ROC_NPC_ITEM_TYPE_END) {
764 : : /* Don't support ranges */
765 [ # # ]: 0 : if (pattern->last != NULL)
766 : : return NPC_ERR_INVALID_RANGE;
767 : :
768 : : /* If spec is NULL, both mask and last must be NULL, this
769 : : * makes it to match ANY value (eq to mask = 0).
770 : : * Setting either mask or last without spec is
771 : : * an error
772 : : */
773 : 0 : if (pattern->spec == NULL) {
774 : : if (pattern->last != NULL && pattern->mask != NULL)
775 : : return NPC_ERR_INVALID_SPEC;
776 : : }
777 : : /* Either one ROC_NPC_ITEM_TYPE_IPV6_EXT or
778 : : * one ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT is supported
779 : : * following an ROC_NPC_ITEM_TYPE_IPV6 item.
780 : : */
781 [ # # ]: 0 : if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_EXT) {
782 : 0 : item_count++;
783 : : ltype = NPC_LT_LC_IP6_EXT;
784 : 0 : parse_info.len =
785 : : sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_flow_item_ipv6_ext);
786 [ # # ]: 0 : if (pattern->spec)
787 : : memcpy(ipv6_hdr_buf + offset, pattern->spec,
788 : : sizeof(struct roc_flow_item_ipv6_ext));
789 [ # # ]: 0 : if (pattern->mask)
790 : : memcpy(ipv6_hdr_mask + offset, pattern->mask,
791 : : sizeof(struct roc_flow_item_ipv6_ext));
792 : : break;
793 [ # # ]: 0 : } else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT) {
794 : 0 : item_count++;
795 : : ltype = NPC_LT_LC_IP6_EXT;
796 : 0 : flags = NPC_F_LC_U_IP6_FRAG;
797 : 0 : parse_info.len =
798 : : sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_ipv6_fragment_ext);
799 [ # # ]: 0 : if (pattern->spec)
800 : : memcpy(ipv6_hdr_buf + offset, pattern->spec,
801 : : sizeof(struct roc_ipv6_fragment_ext));
802 [ # # ]: 0 : if (pattern->mask)
803 : : memcpy(ipv6_hdr_mask + offset, pattern->mask,
804 : : sizeof(struct roc_ipv6_fragment_ext));
805 : :
806 : : break;
807 [ # # ]: 0 : } else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT) {
808 : 0 : item_count++;
809 : : ltype = NPC_LT_LC_IP6_EXT;
810 : 0 : parse_info.len = sizeof(struct roc_ipv6_hdr) + pattern->size;
811 : :
812 [ # # ]: 0 : if (pattern->spec)
813 : 0 : memcpy(ipv6_hdr_buf + offset, pattern->spec, pattern->size);
814 [ # # ]: 0 : if (pattern->mask)
815 : 0 : memcpy(ipv6_hdr_mask + offset, pattern->mask, pattern->size);
816 : : break;
817 : : }
818 : :
819 : 0 : pattern++;
820 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
821 : : }
822 : :
823 : : memset(hw_mask, 0, sizeof(hw_mask));
824 : :
825 : 0 : parse_info.hw_mask = &hw_mask;
826 : 0 : npc_get_hw_supp_mask(pst, &parse_info, lid, ltype);
827 : :
828 : 0 : rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
829 [ # # ]: 0 : if (!rc)
830 : : return NPC_ERR_INVALID_MASK;
831 : :
832 : 0 : rc = npc_update_parse_state(pst, &parse_info, lid, ltype, flags);
833 [ # # ]: 0 : if (rc)
834 : : return rc;
835 : :
836 [ # # ]: 0 : if (pst->npc->hash_extract_cap) {
837 : 0 : rc = npc_process_ipv6_field_hash(parse_info.spec, parse_info.mask, pst, ltype);
838 [ # # ]: 0 : if (rc)
839 : : return rc;
840 : : }
841 : :
842 : : /* npc_update_parse_state() increments pattern once.
843 : : * Check if additional increment is required.
844 : : */
845 [ # # ]: 0 : if (item_count == 2)
846 : 0 : pst->pattern++;
847 : :
848 : : return 0;
849 : : }
850 : :
851 : : int
852 : 0 : npc_parse_lc(struct npc_parse_state *pst)
853 : : {
854 : : const struct roc_npc_flow_item_raw *raw_spec;
855 : : uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
856 : : uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
857 : : uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
858 : : struct npc_parse_item_info info;
859 : : int rc, lid, lt, len = 0;
860 : : uint8_t flags = 0;
861 : :
862 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
863 : 0 : return npc_parse_mpls(pst, NPC_LID_LC);
864 : :
865 : 0 : info.def_mask = NULL;
866 : 0 : info.hw_mask = &hw_mask;
867 : 0 : info.spec = NULL;
868 : 0 : info.mask = NULL;
869 : 0 : info.hw_hdr_len = 0;
870 : : lid = NPC_LID_LC;
871 : :
872 [ # # # # : 0 : switch (pst->pattern->type) {
# # ]
873 : 0 : case ROC_NPC_ITEM_TYPE_IPV4:
874 : : lt = NPC_LT_LC_IP;
875 : 0 : info.len = pst->pattern->size;
876 : 0 : break;
877 : 0 : case ROC_NPC_ITEM_TYPE_IPV6:
878 : : case ROC_NPC_ITEM_TYPE_IPV6_EXT:
879 : : case ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT:
880 : : case ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT:
881 : 0 : return npc_process_ipv6_item(pst);
882 : 0 : case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
883 : : lt = NPC_LT_LC_ARP;
884 : 0 : info.len = pst->pattern->size;
885 : 0 : break;
886 : 0 : case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
887 : : lt = NPC_LT_LC_CUSTOM0;
888 : 0 : info.len = pst->pattern->size;
889 : 0 : break;
890 : 0 : case ROC_NPC_ITEM_TYPE_RAW:
891 : 0 : raw_spec = pst->pattern->spec;
892 [ # # ]: 0 : if (!raw_spec->relative)
893 : : return 0;
894 : :
895 : 0 : len = raw_spec->length + raw_spec->offset;
896 [ # # ]: 0 : if (len > NPC_MAX_RAW_ITEM_LEN)
897 : : return -EINVAL;
898 : :
899 : 0 : npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
900 : : pst->pattern->spec,
901 : : (const struct roc_npc_flow_item_raw *)
902 : 0 : pst->pattern->mask,
903 : : &info, raw_spec_buf, raw_mask_buf);
904 : :
905 : : lid = NPC_LID_LC;
906 : : lt = NPC_LT_LC_NGIO;
907 : : info.hw_mask = &hw_mask;
908 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
909 : 0 : break;
910 : : default:
911 : : /* No match at this layer */
912 : : return 0;
913 : : }
914 : :
915 : : /* Identify if IP tunnels MPLS or IPv4/v6 */
916 : 0 : npc_check_lc_ip_tunnel(pst);
917 : :
918 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
919 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
920 : :
921 [ # # ]: 0 : if (rc != 0)
922 : : return rc;
923 : :
924 : 0 : return npc_update_parse_state(pst, &info, lid, lt, flags);
925 : : }
926 : :
927 : : int
928 : 0 : npc_parse_ld(struct npc_parse_state *pst)
929 : : {
930 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
931 : : struct npc_parse_item_info info;
932 : : int lid, lt, lflags;
933 : : int rc;
934 : :
935 [ # # ]: 0 : if (pst->tunnel) {
936 : : /* We have already parsed MPLS or IPv4/v6 followed
937 : : * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
938 : : * would be parsed as tunneled versions. Skip
939 : : * this layer, except for tunneled MPLS. If LC is
940 : : * MPLS, we have anyway skipped all stacked MPLS
941 : : * labels.
942 : : */
943 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
944 : 0 : return npc_parse_mpls(pst, NPC_LID_LD);
945 : : return 0;
946 : : }
947 : 0 : info.def_mask = NULL;
948 : 0 : info.hw_mask = &hw_mask;
949 : 0 : info.spec = NULL;
950 : 0 : info.mask = NULL;
951 : : info.len = 0;
952 : 0 : info.hw_hdr_len = 0;
953 : :
954 : : lid = NPC_LID_LD;
955 : : lflags = 0;
956 : :
957 [ # # # # : 0 : switch (pst->pattern->type) {
# # # #
# ]
958 : 0 : case ROC_NPC_ITEM_TYPE_ICMP:
959 [ # # ]: 0 : if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
960 : : lt = NPC_LT_LD_ICMP6;
961 : : else
962 : : lt = NPC_LT_LD_ICMP;
963 : 0 : info.len = pst->pattern->size;
964 : 0 : break;
965 : 0 : case ROC_NPC_ITEM_TYPE_UDP:
966 : : lt = NPC_LT_LD_UDP;
967 : 0 : info.len = pst->pattern->size;
968 : 0 : break;
969 : 0 : case ROC_NPC_ITEM_TYPE_IGMP:
970 : : lt = NPC_LT_LD_IGMP;
971 : 0 : info.len = pst->pattern->size;
972 : 0 : break;
973 : 0 : case ROC_NPC_ITEM_TYPE_TCP:
974 : : lt = NPC_LT_LD_TCP;
975 : 0 : info.len = pst->pattern->size;
976 : 0 : break;
977 : 0 : case ROC_NPC_ITEM_TYPE_SCTP:
978 : : lt = NPC_LT_LD_SCTP;
979 : 0 : info.len = pst->pattern->size;
980 : 0 : break;
981 : 0 : case ROC_NPC_ITEM_TYPE_GRE:
982 : : lt = NPC_LT_LD_GRE;
983 : 0 : info.len = pst->pattern->size;
984 : 0 : pst->tunnel = 1;
985 : 0 : break;
986 : 0 : case ROC_NPC_ITEM_TYPE_GRE_KEY:
987 : : lt = NPC_LT_LD_GRE;
988 : 0 : info.len = pst->pattern->size;
989 : 0 : info.hw_hdr_len = 4;
990 : 0 : pst->tunnel = 1;
991 : 0 : break;
992 : 0 : case ROC_NPC_ITEM_TYPE_NVGRE:
993 : : lt = NPC_LT_LD_NVGRE;
994 : : lflags = NPC_F_GRE_NVGRE;
995 : 0 : info.len = pst->pattern->size;
996 : : /* Further IP/Ethernet are parsed as tunneled */
997 : 0 : pst->tunnel = 1;
998 : 0 : break;
999 : : default:
1000 : : return 0;
1001 : : }
1002 : :
1003 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
1004 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
1005 [ # # ]: 0 : if (rc != 0)
1006 : : return rc;
1007 : :
1008 : 0 : return npc_update_parse_state(pst, &info, lid, lt, lflags);
1009 : : }
1010 : :
1011 : : int
1012 : 0 : npc_parse_le(struct npc_parse_state *pst)
1013 : : {
1014 : 0 : const struct roc_npc_item_info *pattern = pst->pattern;
1015 : : const struct roc_npc_item_esp_hdr *esp = NULL;
1016 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1017 : : struct npc_parse_item_info info;
1018 : : int lid, lt, lflags;
1019 : : int rc;
1020 : :
1021 [ # # ]: 0 : if (pst->tunnel)
1022 : : return 0;
1023 : :
1024 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
1025 : 0 : return npc_parse_mpls(pst, NPC_LID_LE);
1026 : :
1027 : 0 : info.spec = NULL;
1028 : 0 : info.mask = NULL;
1029 : 0 : info.hw_mask = NULL;
1030 : 0 : info.def_mask = NULL;
1031 : 0 : info.len = 0;
1032 : 0 : info.hw_hdr_len = 0;
1033 : : lid = NPC_LID_LE;
1034 : : lflags = 0;
1035 : :
1036 : : /* Ensure we are not matching anything in UDP */
1037 : 0 : rc = npc_parse_item_basic(pattern, &info);
1038 [ # # ]: 0 : if (rc)
1039 : : return rc;
1040 : :
1041 : 0 : info.hw_mask = &hw_mask;
1042 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
1043 [ # # # # : 0 : switch (pattern->type) {
# # # ]
1044 : 0 : case ROC_NPC_ITEM_TYPE_VXLAN:
1045 : : lflags = NPC_F_UDP_VXLAN;
1046 : 0 : info.len = pattern->size;
1047 : : lt = NPC_LT_LE_VXLAN;
1048 : 0 : break;
1049 : 0 : case ROC_NPC_ITEM_TYPE_GTPC:
1050 : : lflags = NPC_F_UDP_GTP_GTPC;
1051 : 0 : info.len = pattern->size;
1052 : : lt = NPC_LT_LE_GTPC;
1053 : 0 : break;
1054 : 0 : case ROC_NPC_ITEM_TYPE_GTPU:
1055 : : lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
1056 : 0 : info.len = pattern->size;
1057 : : lt = NPC_LT_LE_GTPU;
1058 : 0 : break;
1059 : 0 : case ROC_NPC_ITEM_TYPE_GENEVE:
1060 : : lflags = NPC_F_UDP_GENEVE;
1061 : 0 : info.len = pattern->size;
1062 : : lt = NPC_LT_LE_GENEVE;
1063 : 0 : break;
1064 : 0 : case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
1065 : : lflags = NPC_F_UDP_VXLANGPE;
1066 : 0 : info.len = pattern->size;
1067 : : lt = NPC_LT_LE_VXLANGPE;
1068 : 0 : break;
1069 : 0 : case ROC_NPC_ITEM_TYPE_ESP:
1070 : : lt = NPC_LT_LE_ESP;
1071 : 0 : info.len = pst->pattern->size;
1072 : 0 : esp = (const struct roc_npc_item_esp_hdr *)pattern->spec;
1073 [ # # ]: 0 : if (esp)
1074 : 0 : pst->flow->spi_to_sa_info.spi = esp->spi;
1075 : : break;
1076 : : default:
1077 : : return 0;
1078 : : }
1079 : :
1080 : 0 : pst->tunnel = 1;
1081 : :
1082 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
1083 : 0 : rc = npc_parse_item_basic(pattern, &info);
1084 [ # # ]: 0 : if (rc != 0)
1085 : : return rc;
1086 : :
1087 : 0 : return npc_update_parse_state(pst, &info, lid, lt, lflags);
1088 : : }
1089 : :
1090 : : int
1091 : 0 : npc_parse_lf(struct npc_parse_state *pst)
1092 : : {
1093 : : const struct roc_npc_item_info *pattern, *last_pattern;
1094 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1095 : : struct npc_parse_item_info info;
1096 : : int lid, lt, lflags;
1097 : : int nr_vlans = 0;
1098 : : int rc;
1099 : :
1100 : : /* We hit this layer if there is a tunneling protocol */
1101 [ # # ]: 0 : if (!pst->tunnel)
1102 : : return 0;
1103 : :
1104 [ # # ]: 0 : if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
1105 : : return 0;
1106 : :
1107 : : lid = NPC_LID_LF;
1108 : : lt = NPC_LT_LF_TU_ETHER;
1109 : : lflags = 0;
1110 : :
1111 : : /* No match support for vlan tags */
1112 : 0 : info.def_mask = NULL;
1113 : 0 : info.hw_mask = NULL;
1114 : 0 : info.len = pst->pattern->size;
1115 : 0 : info.spec = NULL;
1116 : 0 : info.mask = NULL;
1117 : 0 : info.hw_hdr_len = 0;
1118 : :
1119 : : /* Look ahead and find out any VLAN tags. These can be
1120 : : * detected but no data matching is available.
1121 : : */
1122 : : last_pattern = pst->pattern;
1123 : 0 : pattern = pst->pattern + 1;
1124 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
1125 [ # # ]: 0 : while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
1126 : 0 : nr_vlans++;
1127 : : last_pattern = pattern;
1128 : 0 : pattern++;
1129 : 0 : pattern = npc_parse_skip_void_and_any_items(pattern);
1130 : : }
1131 : : switch (nr_vlans) {
1132 : : case 0:
1133 : : break;
1134 : : case 1:
1135 : : lflags = NPC_F_TU_ETHER_CTAG;
1136 : : break;
1137 : : case 2:
1138 : : lflags = NPC_F_TU_ETHER_STAG_CTAG;
1139 : : break;
1140 : : default:
1141 : : return NPC_ERR_PATTERN_NOTSUP;
1142 : : }
1143 : :
1144 : 0 : info.hw_mask = &hw_mask;
1145 : 0 : info.len = pst->pattern->size;
1146 : 0 : info.hw_hdr_len = 0;
1147 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
1148 : 0 : info.spec = NULL;
1149 : 0 : info.mask = NULL;
1150 : :
1151 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
1152 [ # # ]: 0 : if (rc != 0)
1153 : : return rc;
1154 : :
1155 : 0 : pst->pattern = last_pattern;
1156 : :
1157 : 0 : return npc_update_parse_state(pst, &info, lid, lt, lflags);
1158 : : }
1159 : :
1160 : : int
1161 : 0 : npc_parse_lg(struct npc_parse_state *pst)
1162 : : {
1163 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1164 : : struct npc_parse_item_info info;
1165 : : int lid, lt;
1166 : : int rc;
1167 : :
1168 [ # # ]: 0 : if (!pst->tunnel)
1169 : : return 0;
1170 : :
1171 : 0 : info.def_mask = NULL;
1172 : 0 : info.hw_mask = &hw_mask;
1173 : 0 : info.spec = NULL;
1174 : 0 : info.mask = NULL;
1175 : 0 : info.hw_hdr_len = 0;
1176 : : lid = NPC_LID_LG;
1177 : :
1178 [ # # ]: 0 : if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
1179 : : lt = NPC_LT_LG_TU_IP;
1180 : 0 : info.len = pst->pattern->size;
1181 [ # # ]: 0 : } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
1182 : : lt = NPC_LT_LG_TU_IP6;
1183 : 0 : info.len = pst->pattern->size;
1184 : : } else {
1185 : : /* There is no tunneled IP header */
1186 : : return 0;
1187 : : }
1188 : :
1189 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
1190 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
1191 [ # # ]: 0 : if (rc != 0)
1192 : : return rc;
1193 : :
1194 : 0 : return npc_update_parse_state(pst, &info, lid, lt, 0);
1195 : : }
1196 : :
1197 : : int
1198 : 0 : npc_parse_lh(struct npc_parse_state *pst)
1199 : : {
1200 : : char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1201 : : struct npc_parse_item_info info;
1202 : : int lid, lt;
1203 : : int rc;
1204 : :
1205 [ # # ]: 0 : if (!pst->tunnel)
1206 : : return 0;
1207 : :
1208 : 0 : info.def_mask = NULL;
1209 : 0 : info.hw_mask = &hw_mask;
1210 : 0 : info.spec = NULL;
1211 : 0 : info.mask = NULL;
1212 : 0 : info.hw_hdr_len = 0;
1213 : : lid = NPC_LID_LH;
1214 : :
1215 [ # # # # : 0 : switch (pst->pattern->type) {
# ]
1216 : 0 : case ROC_NPC_ITEM_TYPE_UDP:
1217 : : lt = NPC_LT_LH_TU_UDP;
1218 : 0 : info.len = pst->pattern->size;
1219 : 0 : break;
1220 : 0 : case ROC_NPC_ITEM_TYPE_TCP:
1221 : : lt = NPC_LT_LH_TU_TCP;
1222 : 0 : info.len = pst->pattern->size;
1223 : 0 : break;
1224 : 0 : case ROC_NPC_ITEM_TYPE_SCTP:
1225 : : lt = NPC_LT_LH_TU_SCTP;
1226 : 0 : info.len = pst->pattern->size;
1227 : 0 : break;
1228 : 0 : case ROC_NPC_ITEM_TYPE_ESP:
1229 : : lt = NPC_LT_LH_TU_ESP;
1230 : 0 : info.len = pst->pattern->size;
1231 : 0 : break;
1232 : : default:
1233 : : return 0;
1234 : : }
1235 : :
1236 : 0 : npc_get_hw_supp_mask(pst, &info, lid, lt);
1237 : 0 : rc = npc_parse_item_basic(pst->pattern, &info);
1238 [ # # ]: 0 : if (rc != 0)
1239 : : return rc;
1240 : :
1241 : 0 : return npc_update_parse_state(pst, &info, lid, lt, 0);
1242 : : }
|