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