xref: /dpdk/drivers/common/cnxk/roc_npc_parse.c (revision 29fd052d)
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 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
18 npc_parse_meta_items(struct npc_parse_state *pst)
19 {
20 	PLT_SET_USED(pst);
21 	return 0;
22 }
23 
24 static int
25 npc_flow_raw_item_prepare(const struct roc_npc_flow_item_raw *raw_spec,
26 			  const struct roc_npc_flow_item_raw *raw_mask,
27 			  struct npc_parse_item_info *info, uint8_t *spec_buf,
28 			  uint8_t *mask_buf)
29 {
30 
31 	memset(spec_buf, 0, NPC_MAX_RAW_ITEM_LEN);
32 	memset(mask_buf, 0, NPC_MAX_RAW_ITEM_LEN);
33 
34 	memcpy(spec_buf + raw_spec->offset, raw_spec->pattern,
35 	       raw_spec->length);
36 
37 	if (raw_mask && raw_mask->pattern) {
38 		memcpy(mask_buf + raw_spec->offset, raw_mask->pattern,
39 		       raw_spec->length);
40 	} else {
41 		memset(mask_buf + raw_spec->offset, 0xFF, raw_spec->length);
42 	}
43 
44 	info->len = NPC_MAX_RAW_ITEM_LEN;
45 	info->spec = spec_buf;
46 	info->mask = mask_buf;
47 	return 0;
48 }
49 
50 int
51 npc_parse_pre_l2(struct npc_parse_state *pst)
52 {
53 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
54 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
55 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN] = {0};
56 	const struct roc_npc_flow_item_raw *raw_spec;
57 	struct npc_parse_item_info info;
58 	int lid, lt, len;
59 	int rc;
60 
61 	if (pst->npc->switch_header_type != ROC_PRIV_FLAGS_PRE_L2)
62 		return 0;
63 
64 	/* Identify the pattern type into lid, lt */
65 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_RAW)
66 		return 0;
67 
68 	lid = NPC_LID_LA;
69 	lt = NPC_LT_LA_CUSTOM_PRE_L2_ETHER;
70 	info.hw_hdr_len = 0;
71 
72 	raw_spec = pst->pattern->spec;
73 	len = raw_spec->length + raw_spec->offset;
74 	if (len > NPC_MAX_RAW_ITEM_LEN)
75 		return -EINVAL;
76 
77 	if (raw_spec->relative == 0 || raw_spec->search || raw_spec->limit ||
78 	    raw_spec->offset < 0)
79 		return -EINVAL;
80 
81 	npc_flow_raw_item_prepare(
82 		(const struct roc_npc_flow_item_raw *)pst->pattern->spec,
83 		(const struct roc_npc_flow_item_raw *)pst->pattern->mask, &info,
84 		raw_spec_buf, raw_mask_buf);
85 
86 	info.hw_mask = &hw_mask;
87 	npc_get_hw_supp_mask(pst, &info, lid, lt);
88 
89 	/* Basic validation of item parameters */
90 	rc = npc_parse_item_basic(pst->pattern, &info);
91 	if (rc)
92 		return rc;
93 
94 	/* Update pst if not validate only? clash check? */
95 	return npc_update_parse_state(pst, &info, lid, lt, 0);
96 }
97 
98 int
99 npc_parse_cpt_hdr(struct npc_parse_state *pst)
100 {
101 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
102 	struct npc_parse_item_info info;
103 	int lid, lt;
104 	int rc;
105 
106 	/* Identify the pattern type into lid, lt */
107 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR)
108 		return 0;
109 
110 	lid = NPC_LID_LA;
111 	lt = NPC_LT_LA_CPT_HDR;
112 	info.hw_hdr_len = 0;
113 
114 	/* Prepare for parsing the item */
115 	info.def_mask = NULL;
116 	info.hw_mask = &hw_mask;
117 	info.len = pst->pattern->size;
118 	npc_get_hw_supp_mask(pst, &info, lid, lt);
119 	info.spec = NULL;
120 	info.mask = NULL;
121 
122 	/* Basic validation of item parameters */
123 	rc = npc_parse_item_basic(pst->pattern, &info);
124 	if (rc)
125 		return rc;
126 
127 	/* Update pst if not validate only? clash check? */
128 	return npc_update_parse_state(pst, &info, lid, lt, 0);
129 }
130 
131 int
132 npc_parse_higig2_hdr(struct npc_parse_state *pst)
133 {
134 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
135 	struct npc_parse_item_info info;
136 	int lid, lt;
137 	int rc;
138 
139 	/* Identify the pattern type into lid, lt */
140 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
141 		return 0;
142 
143 	lid = NPC_LID_LA;
144 	lt = NPC_LT_LA_HIGIG2_ETHER;
145 	info.hw_hdr_len = 0;
146 
147 	if (pst->flow->nix_intf == NIX_INTF_TX) {
148 		lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
149 		info.hw_hdr_len = NPC_IH_LENGTH;
150 	}
151 
152 	/* Prepare for parsing the item */
153 	info.def_mask = NULL;
154 	info.hw_mask = &hw_mask;
155 	info.len = pst->pattern->size;
156 	npc_get_hw_supp_mask(pst, &info, lid, lt);
157 	info.spec = NULL;
158 	info.mask = NULL;
159 
160 	/* Basic validation of item parameters */
161 	rc = npc_parse_item_basic(pst->pattern, &info);
162 	if (rc)
163 		return rc;
164 
165 	/* Update pst if not validate only? clash check? */
166 	return npc_update_parse_state(pst, &info, lid, lt, 0);
167 }
168 
169 int
170 npc_parse_la(struct npc_parse_state *pst)
171 {
172 	const struct roc_npc_flow_item_eth *eth_item;
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_ETH)
180 		return 0;
181 
182 	eth_item = pst->pattern->spec;
183 
184 	lid = NPC_LID_LA;
185 	lt = NPC_LT_LA_ETHER;
186 	info.hw_hdr_len = 0;
187 
188 	if (pst->flow->nix_intf == NIX_INTF_TX) {
189 		lt = NPC_LT_LA_IH_NIX_ETHER;
190 		info.hw_hdr_len = NPC_IH_LENGTH;
191 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
192 			lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
193 			info.hw_hdr_len += NPC_HIGIG2_LENGTH;
194 		}
195 	} else {
196 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
197 			lt = NPC_LT_LA_HIGIG2_ETHER;
198 			info.hw_hdr_len = NPC_HIGIG2_LENGTH;
199 		}
200 	}
201 
202 	/* Prepare for parsing the item */
203 	info.def_mask = NULL;
204 	info.hw_mask = &hw_mask;
205 	info.len = sizeof(eth_item->hdr);
206 	npc_get_hw_supp_mask(pst, &info, lid, lt);
207 	info.spec = NULL;
208 	info.mask = NULL;
209 
210 	/* Basic validation of item parameters */
211 	rc = npc_parse_item_basic(pst->pattern, &info);
212 	if (rc)
213 		return rc;
214 
215 	rc = npc_update_parse_state(pst, &info, lid, lt, 0);
216 	if (rc)
217 		return rc;
218 
219 	if (eth_item && eth_item->has_vlan)
220 		pst->set_vlan_ltype_mask = true;
221 
222 	return 0;
223 }
224 
225 #define NPC_MAX_SUPPORTED_VLANS 3
226 
227 int
228 npc_parse_lb(struct npc_parse_state *pst)
229 {
230 	const struct roc_npc_flow_item_vlan *vlan_item[NPC_MAX_SUPPORTED_VLANS];
231 	const struct roc_npc_item_info *pattern = pst->pattern;
232 	const struct roc_npc_item_info *last_pattern;
233 	const struct roc_npc_flow_item_raw *raw_spec;
234 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
235 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
236 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
237 	struct npc_parse_item_info info;
238 	int lid, lt, lflags, len = 0;
239 	int nr_vlans = 0;
240 	int rc;
241 
242 	info.def_mask = NULL;
243 	info.spec = NULL;
244 	info.mask = NULL;
245 	info.def_mask = NULL;
246 	info.hw_hdr_len = NPC_TPID_LENGTH;
247 
248 	lid = NPC_LID_LB;
249 	lflags = 0;
250 	last_pattern = pattern;
251 
252 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
253 		/* RTE vlan is either 802.1q or 802.1ad,
254 		 * this maps to either CTAG/STAG. We need to decide
255 		 * based on number of VLANS present. Matching is
256 		 * supported on first tag only.
257 		 */
258 		info.hw_mask = NULL;
259 		info.len = sizeof(vlan_item[0]->hdr);
260 
261 		pattern = pst->pattern;
262 		while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
263 			if (nr_vlans > NPC_MAX_SUPPORTED_VLANS - 1)
264 				return NPC_ERR_PATTERN_NOTSUP;
265 
266 			vlan_item[nr_vlans] = pattern->spec;
267 			nr_vlans++;
268 
269 			/* Basic validation of Second/Third vlan item */
270 			if (nr_vlans > 1) {
271 				rc = npc_parse_item_basic(pattern, &info);
272 				if (rc != 0)
273 					return rc;
274 			}
275 			last_pattern = pattern;
276 			pattern++;
277 			pattern = npc_parse_skip_void_and_any_items(pattern);
278 		}
279 
280 		switch (nr_vlans) {
281 		case 1:
282 			lt = NPC_LT_LB_CTAG;
283 			if (vlan_item[0] && vlan_item[0]->has_more_vlan)
284 				lt = NPC_LT_LB_STAG_QINQ;
285 			break;
286 		case 2:
287 			if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
288 				if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
289 				      0x3ULL << NPC_LFLAG_LB_OFFSET))
290 					return NPC_ERR_PATTERN_NOTSUP;
291 
292 				/* This lflag value will match either one of
293 				 * NPC_F_LB_L_WITH_STAG_STAG,
294 				 * NPC_F_LB_L_WITH_QINQ_CTAG,
295 				 * NPC_F_LB_L_WITH_QINQ_QINQ and
296 				 * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
297 				 * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
298 				 * hence will not match.
299 				 */
300 
301 				lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
302 					 NPC_F_LB_L_WITH_QINQ_QINQ &
303 					 NPC_F_LB_L_WITH_STAG_STAG;
304 			} else {
305 				lflags = NPC_F_LB_L_WITH_CTAG;
306 			}
307 			lt = NPC_LT_LB_STAG_QINQ;
308 			break;
309 		case 3:
310 			if (vlan_item[2] && vlan_item[2]->has_more_vlan)
311 				return NPC_ERR_PATTERN_NOTSUP;
312 			lt = NPC_LT_LB_STAG_QINQ;
313 			lflags = NPC_F_STAG_STAG_CTAG;
314 			break;
315 		default:
316 			return NPC_ERR_PATTERN_NOTSUP;
317 		}
318 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
319 		/* we can support ETAG and match a subsequent CTAG
320 		 * without any matching support.
321 		 */
322 		lt = NPC_LT_LB_ETAG;
323 		lflags = 0;
324 
325 		last_pattern = pst->pattern;
326 		pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
327 		if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
328 			/* set supported mask to NULL for vlan tag */
329 			info.hw_mask = NULL;
330 			info.len = pattern->size;
331 			rc = npc_parse_item_basic(pattern, &info);
332 			if (rc != 0)
333 				return rc;
334 
335 			lflags = NPC_F_ETAG_CTAG;
336 			last_pattern = pattern;
337 		}
338 		info.len = pattern->size;
339 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
340 		vlan_item[0] = pst->pattern->spec;
341 		info.hw_mask = NULL;
342 		info.len = sizeof(vlan_item[0]->hdr);
343 		lt = NPC_LT_LB_STAG_QINQ;
344 		lflags = NPC_F_STAG_CTAG;
345 		if (vlan_item[0] && vlan_item[0]->has_more_vlan) {
346 			lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
347 				 NPC_F_LB_L_WITH_QINQ_QINQ;
348 		}
349 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
350 		raw_spec = pst->pattern->spec;
351 		if (raw_spec->relative)
352 			return 0;
353 		len = raw_spec->length + raw_spec->offset;
354 		if (len > NPC_MAX_RAW_ITEM_LEN)
355 			return -EINVAL;
356 
357 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
358 			lt = NPC_LT_LB_VLAN_EXDSA;
359 		} else if (pst->npc->switch_header_type ==
360 			   ROC_PRIV_FLAGS_EXDSA) {
361 			lt = NPC_LT_LB_EXDSA;
362 		} else {
363 			return -EINVAL;
364 		}
365 
366 		npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
367 						  pst->pattern->spec,
368 					  (const struct roc_npc_flow_item_raw *)
369 						  pst->pattern->mask,
370 					  &info, raw_spec_buf, raw_mask_buf);
371 
372 		info.hw_hdr_len = 0;
373 	} else {
374 		return 0;
375 	}
376 
377 	info.hw_mask = &hw_mask;
378 	npc_get_hw_supp_mask(pst, &info, lid, lt);
379 
380 	rc = npc_parse_item_basic(pst->pattern, &info);
381 	if (rc != 0)
382 		return rc;
383 
384 	/* Point pattern to last item consumed */
385 	pst->pattern = last_pattern;
386 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
387 }
388 
389 static int
390 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
391 {
392 	uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
393 			       NPC_F_MPLS_4_LABELS};
394 	const struct roc_npc_item_info *pattern = pst->pattern;
395 	struct npc_parse_item_info info;
396 	int nr_labels = 0;
397 	int rc;
398 
399 	/*
400 	 * pst->pattern points to first MPLS label. We only check
401 	 * that subsequent labels do not have anything to match.
402 	 */
403 	info.def_mask = NULL;
404 	info.hw_mask = NULL;
405 	info.len = pattern->size;
406 	info.spec = NULL;
407 	info.mask = NULL;
408 	info.hw_hdr_len = 0;
409 
410 	while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
411 		nr_labels++;
412 
413 		/* Basic validation of Second/Third/Fourth mpls item */
414 		if (nr_labels > 1) {
415 			rc = npc_parse_item_basic(pattern, &info);
416 			if (rc != 0)
417 				return rc;
418 		}
419 		pst->last_pattern = pattern;
420 		pattern++;
421 		pattern = npc_parse_skip_void_and_any_items(pattern);
422 	}
423 
424 	if (nr_labels < 1 || nr_labels > 4)
425 		return NPC_ERR_PATTERN_NOTSUP;
426 
427 	*flag = flag_list[nr_labels - 1];
428 	return 0;
429 }
430 
431 static int
432 npc_parse_mpls(struct npc_parse_state *pst, int lid)
433 {
434 	/* Find number of MPLS labels */
435 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
436 	struct npc_parse_item_info info;
437 	int lt, lflags;
438 	int rc;
439 
440 	lflags = 0;
441 
442 	if (lid == NPC_LID_LC)
443 		lt = NPC_LT_LC_MPLS;
444 	else if (lid == NPC_LID_LD)
445 		lt = NPC_LT_LD_TU_MPLS_IN_IP;
446 	else
447 		lt = NPC_LT_LE_TU_MPLS_IN_UDP;
448 
449 	/* Prepare for parsing the first item */
450 	info.hw_mask = &hw_mask;
451 	info.len = pst->pattern->size;
452 	info.spec = NULL;
453 	info.mask = NULL;
454 	info.def_mask = NULL;
455 	info.hw_hdr_len = 0;
456 
457 	npc_get_hw_supp_mask(pst, &info, lid, lt);
458 	rc = npc_parse_item_basic(pst->pattern, &info);
459 	if (rc != 0)
460 		return rc;
461 
462 	/*
463 	 * Parse for more labels.
464 	 * This sets lflags and pst->last_pattern correctly.
465 	 */
466 	rc = npc_parse_mpls_label_stack(pst, &lflags);
467 	if (rc != 0)
468 		return rc;
469 
470 	pst->tunnel = 1;
471 	pst->pattern = pst->last_pattern;
472 
473 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
474 }
475 
476 static inline void
477 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
478 {
479 	const struct roc_npc_item_info *pattern = pst->pattern + 1;
480 
481 	pattern = npc_parse_skip_void_and_any_items(pattern);
482 	if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
483 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
484 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
485 		pst->tunnel = 1;
486 }
487 
488 static int
489 npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
490 			struct npc_parse_state *pst, uint8_t *flags)
491 {
492 	int flags_count = 0;
493 
494 	if (ipv6_spec->has_hop_ext) {
495 		*flags = NPC_F_LC_L_EXT_HOP;
496 		flags_count++;
497 	}
498 	if (ipv6_spec->has_route_ext) {
499 		*flags = NPC_F_LC_L_EXT_ROUT;
500 		flags_count++;
501 	}
502 	if (ipv6_spec->has_frag_ext) {
503 		*flags = NPC_F_LC_U_IP6_FRAG;
504 		flags_count++;
505 	}
506 	if (ipv6_spec->has_dest_ext) {
507 		*flags = NPC_F_LC_L_EXT_DEST;
508 		flags_count++;
509 	}
510 	if (ipv6_spec->has_mobil_ext) {
511 		*flags = NPC_F_LC_L_EXT_MOBILITY;
512 		flags_count++;
513 	}
514 	if (ipv6_spec->has_hip_ext) {
515 		*flags = NPC_F_LC_L_EXT_HOSTID;
516 		flags_count++;
517 	}
518 	if (ipv6_spec->has_shim6_ext) {
519 		*flags = NPC_F_LC_L_EXT_SHIM6;
520 		flags_count++;
521 	}
522 	if (ipv6_spec->has_auth_ext) {
523 		pst->lt[NPC_LID_LD] = NPC_LT_LD_AH;
524 		flags_count++;
525 	}
526 	if (ipv6_spec->has_esp_ext) {
527 		pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP;
528 		flags_count++;
529 	}
530 
531 	if (flags_count > 1)
532 		return -EINVAL;
533 
534 	if (flags_count)
535 		pst->set_ipv6ext_ltype_mask = true;
536 
537 	return 0;
538 }
539 
540 int
541 npc_parse_lc(struct npc_parse_state *pst)
542 {
543 	const struct roc_npc_flow_item_ipv6 *ipv6_spec;
544 	const struct roc_npc_flow_item_raw *raw_spec;
545 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
546 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
547 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
548 	struct npc_parse_item_info info;
549 	int rc, lid, lt, len = 0;
550 	uint8_t flags = 0;
551 
552 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
553 		return npc_parse_mpls(pst, NPC_LID_LC);
554 
555 	info.def_mask = NULL;
556 	info.hw_mask = &hw_mask;
557 	info.spec = NULL;
558 	info.mask = NULL;
559 	info.hw_hdr_len = 0;
560 	lid = NPC_LID_LC;
561 
562 	switch (pst->pattern->type) {
563 	case ROC_NPC_ITEM_TYPE_IPV4:
564 		lt = NPC_LT_LC_IP;
565 		info.len = pst->pattern->size;
566 		break;
567 	case ROC_NPC_ITEM_TYPE_IPV6:
568 		ipv6_spec = pst->pattern->spec;
569 		lid = NPC_LID_LC;
570 		lt = NPC_LT_LC_IP6;
571 		if (ipv6_spec) {
572 			rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
573 			if (rc)
574 				return rc;
575 		}
576 		info.len = sizeof(ipv6_spec->hdr);
577 		break;
578 	case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
579 		lt = NPC_LT_LC_ARP;
580 		info.len = pst->pattern->size;
581 		break;
582 	case ROC_NPC_ITEM_TYPE_IPV6_EXT:
583 		lid = NPC_LID_LC;
584 		lt = NPC_LT_LC_IP6_EXT;
585 		info.len = pst->pattern->size;
586 		info.hw_hdr_len = 40;
587 		break;
588 	case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
589 		lt = NPC_LT_LC_CUSTOM0;
590 		info.len = pst->pattern->size;
591 		break;
592 	case ROC_NPC_ITEM_TYPE_RAW:
593 		raw_spec = pst->pattern->spec;
594 		if (!raw_spec->relative)
595 			return 0;
596 
597 		len = raw_spec->length + raw_spec->offset;
598 		if (len > NPC_MAX_RAW_ITEM_LEN)
599 			return -EINVAL;
600 
601 		npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
602 						  pst->pattern->spec,
603 					  (const struct roc_npc_flow_item_raw *)
604 						  pst->pattern->mask,
605 					  &info, raw_spec_buf, raw_mask_buf);
606 
607 		lid = NPC_LID_LC;
608 		lt = NPC_LT_LC_NGIO;
609 		info.hw_mask = &hw_mask;
610 		npc_get_hw_supp_mask(pst, &info, lid, lt);
611 		break;
612 	default:
613 		/* No match at this layer */
614 		return 0;
615 	}
616 
617 	/* Identify if IP tunnels MPLS or IPv4/v6 */
618 	npc_check_lc_ip_tunnel(pst);
619 
620 	npc_get_hw_supp_mask(pst, &info, lid, lt);
621 	rc = npc_parse_item_basic(pst->pattern, &info);
622 
623 	if (rc != 0)
624 		return rc;
625 
626 	return npc_update_parse_state(pst, &info, lid, lt, flags);
627 }
628 
629 int
630 npc_parse_ld(struct npc_parse_state *pst)
631 {
632 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
633 	struct npc_parse_item_info info;
634 	int lid, lt, lflags;
635 	int rc;
636 
637 	if (pst->tunnel) {
638 		/* We have already parsed MPLS or IPv4/v6 followed
639 		 * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
640 		 * would be parsed as tunneled versions. Skip
641 		 * this layer, except for tunneled MPLS. If LC is
642 		 * MPLS, we have anyway skipped all stacked MPLS
643 		 * labels.
644 		 */
645 		if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
646 			return npc_parse_mpls(pst, NPC_LID_LD);
647 		return 0;
648 	}
649 	info.def_mask = NULL;
650 	info.hw_mask = &hw_mask;
651 	info.spec = NULL;
652 	info.mask = NULL;
653 	info.len = 0;
654 	info.hw_hdr_len = 0;
655 
656 	lid = NPC_LID_LD;
657 	lflags = 0;
658 
659 	switch (pst->pattern->type) {
660 	case ROC_NPC_ITEM_TYPE_ICMP:
661 		if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
662 			lt = NPC_LT_LD_ICMP6;
663 		else
664 			lt = NPC_LT_LD_ICMP;
665 		info.len = pst->pattern->size;
666 		break;
667 	case ROC_NPC_ITEM_TYPE_UDP:
668 		lt = NPC_LT_LD_UDP;
669 		info.len = pst->pattern->size;
670 		break;
671 	case ROC_NPC_ITEM_TYPE_IGMP:
672 		lt = NPC_LT_LD_IGMP;
673 		info.len = pst->pattern->size;
674 		break;
675 	case ROC_NPC_ITEM_TYPE_TCP:
676 		lt = NPC_LT_LD_TCP;
677 		info.len = pst->pattern->size;
678 		break;
679 	case ROC_NPC_ITEM_TYPE_SCTP:
680 		lt = NPC_LT_LD_SCTP;
681 		info.len = pst->pattern->size;
682 		break;
683 	case ROC_NPC_ITEM_TYPE_GRE:
684 		lt = NPC_LT_LD_GRE;
685 		info.len = pst->pattern->size;
686 		break;
687 	case ROC_NPC_ITEM_TYPE_GRE_KEY:
688 		lt = NPC_LT_LD_GRE;
689 		info.len = pst->pattern->size;
690 		info.hw_hdr_len = 4;
691 		break;
692 	case ROC_NPC_ITEM_TYPE_NVGRE:
693 		lt = NPC_LT_LD_NVGRE;
694 		lflags = NPC_F_GRE_NVGRE;
695 		info.len = pst->pattern->size;
696 		/* Further IP/Ethernet are parsed as tunneled */
697 		pst->tunnel = 1;
698 		break;
699 	default:
700 		return 0;
701 	}
702 
703 	npc_get_hw_supp_mask(pst, &info, lid, lt);
704 	rc = npc_parse_item_basic(pst->pattern, &info);
705 	if (rc != 0)
706 		return rc;
707 
708 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
709 }
710 
711 int
712 npc_parse_le(struct npc_parse_state *pst)
713 {
714 	const struct roc_npc_item_info *pattern = pst->pattern;
715 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
716 	struct npc_parse_item_info info;
717 	int lid, lt, lflags;
718 	int rc;
719 
720 	if (pst->tunnel)
721 		return 0;
722 
723 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
724 		return npc_parse_mpls(pst, NPC_LID_LE);
725 
726 	info.spec = NULL;
727 	info.mask = NULL;
728 	info.hw_mask = NULL;
729 	info.def_mask = NULL;
730 	info.len = 0;
731 	info.hw_hdr_len = 0;
732 	lid = NPC_LID_LE;
733 	lflags = 0;
734 
735 	/* Ensure we are not matching anything in UDP */
736 	rc = npc_parse_item_basic(pattern, &info);
737 	if (rc)
738 		return rc;
739 
740 	info.hw_mask = &hw_mask;
741 	pattern = npc_parse_skip_void_and_any_items(pattern);
742 	switch (pattern->type) {
743 	case ROC_NPC_ITEM_TYPE_VXLAN:
744 		lflags = NPC_F_UDP_VXLAN;
745 		info.len = pattern->size;
746 		lt = NPC_LT_LE_VXLAN;
747 		break;
748 	case ROC_NPC_ITEM_TYPE_GTPC:
749 		lflags = NPC_F_UDP_GTP_GTPC;
750 		info.len = pattern->size;
751 		lt = NPC_LT_LE_GTPC;
752 		break;
753 	case ROC_NPC_ITEM_TYPE_GTPU:
754 		lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
755 		info.len = pattern->size;
756 		lt = NPC_LT_LE_GTPU;
757 		break;
758 	case ROC_NPC_ITEM_TYPE_GENEVE:
759 		lflags = NPC_F_UDP_GENEVE;
760 		info.len = pattern->size;
761 		lt = NPC_LT_LE_GENEVE;
762 		break;
763 	case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
764 		lflags = NPC_F_UDP_VXLANGPE;
765 		info.len = pattern->size;
766 		lt = NPC_LT_LE_VXLANGPE;
767 		break;
768 	case ROC_NPC_ITEM_TYPE_ESP:
769 		lt = NPC_LT_LE_ESP;
770 		info.len = pst->pattern->size;
771 		break;
772 	default:
773 		return 0;
774 	}
775 
776 	pst->tunnel = 1;
777 
778 	npc_get_hw_supp_mask(pst, &info, lid, lt);
779 	rc = npc_parse_item_basic(pattern, &info);
780 	if (rc != 0)
781 		return rc;
782 
783 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
784 }
785 
786 int
787 npc_parse_lf(struct npc_parse_state *pst)
788 {
789 	const struct roc_npc_item_info *pattern, *last_pattern;
790 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
791 	struct npc_parse_item_info info;
792 	int lid, lt, lflags;
793 	int nr_vlans = 0;
794 	int rc;
795 
796 	/* We hit this layer if there is a tunneling protocol */
797 	if (!pst->tunnel)
798 		return 0;
799 
800 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
801 		return 0;
802 
803 	lid = NPC_LID_LF;
804 	lt = NPC_LT_LF_TU_ETHER;
805 	lflags = 0;
806 
807 	/* No match support for vlan tags */
808 	info.def_mask = NULL;
809 	info.hw_mask = NULL;
810 	info.len = pst->pattern->size;
811 	info.spec = NULL;
812 	info.mask = NULL;
813 	info.hw_hdr_len = 0;
814 
815 	/* Look ahead and find out any VLAN tags. These can be
816 	 * detected but no data matching is available.
817 	 */
818 	last_pattern = pst->pattern;
819 	pattern = pst->pattern + 1;
820 	pattern = npc_parse_skip_void_and_any_items(pattern);
821 	while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
822 		nr_vlans++;
823 		last_pattern = pattern;
824 		pattern++;
825 		pattern = npc_parse_skip_void_and_any_items(pattern);
826 	}
827 	switch (nr_vlans) {
828 	case 0:
829 		break;
830 	case 1:
831 		lflags = NPC_F_TU_ETHER_CTAG;
832 		break;
833 	case 2:
834 		lflags = NPC_F_TU_ETHER_STAG_CTAG;
835 		break;
836 	default:
837 		return NPC_ERR_PATTERN_NOTSUP;
838 	}
839 
840 	info.hw_mask = &hw_mask;
841 	info.len = pst->pattern->size;
842 	info.hw_hdr_len = 0;
843 	npc_get_hw_supp_mask(pst, &info, lid, lt);
844 	info.spec = NULL;
845 	info.mask = NULL;
846 
847 	rc = npc_parse_item_basic(pst->pattern, &info);
848 	if (rc != 0)
849 		return rc;
850 
851 	pst->pattern = last_pattern;
852 
853 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
854 }
855 
856 int
857 npc_parse_lg(struct npc_parse_state *pst)
858 {
859 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
860 	struct npc_parse_item_info info;
861 	int lid, lt;
862 	int rc;
863 
864 	if (!pst->tunnel)
865 		return 0;
866 
867 	info.def_mask = NULL;
868 	info.hw_mask = &hw_mask;
869 	info.spec = NULL;
870 	info.mask = NULL;
871 	info.hw_hdr_len = 0;
872 	lid = NPC_LID_LG;
873 
874 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
875 		lt = NPC_LT_LG_TU_IP;
876 		info.len = pst->pattern->size;
877 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
878 		lt = NPC_LT_LG_TU_IP6;
879 		info.len = pst->pattern->size;
880 	} else {
881 		/* There is no tunneled IP header */
882 		return 0;
883 	}
884 
885 	npc_get_hw_supp_mask(pst, &info, lid, lt);
886 	rc = npc_parse_item_basic(pst->pattern, &info);
887 	if (rc != 0)
888 		return rc;
889 
890 	return npc_update_parse_state(pst, &info, lid, lt, 0);
891 }
892 
893 int
894 npc_parse_lh(struct npc_parse_state *pst)
895 {
896 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
897 	struct npc_parse_item_info info;
898 	int lid, lt;
899 	int rc;
900 
901 	if (!pst->tunnel)
902 		return 0;
903 
904 	info.def_mask = NULL;
905 	info.hw_mask = &hw_mask;
906 	info.spec = NULL;
907 	info.mask = NULL;
908 	info.hw_hdr_len = 0;
909 	lid = NPC_LID_LH;
910 
911 	switch (pst->pattern->type) {
912 	case ROC_NPC_ITEM_TYPE_UDP:
913 		lt = NPC_LT_LH_TU_UDP;
914 		info.len = pst->pattern->size;
915 		break;
916 	case ROC_NPC_ITEM_TYPE_TCP:
917 		lt = NPC_LT_LH_TU_TCP;
918 		info.len = pst->pattern->size;
919 		break;
920 	case ROC_NPC_ITEM_TYPE_SCTP:
921 		lt = NPC_LT_LH_TU_SCTP;
922 		info.len = pst->pattern->size;
923 		break;
924 	case ROC_NPC_ITEM_TYPE_ESP:
925 		lt = NPC_LT_LH_TU_ESP;
926 		info.len = pst->pattern->size;
927 		break;
928 	default:
929 		return 0;
930 	}
931 
932 	npc_get_hw_supp_mask(pst, &info, lid, lt);
933 	rc = npc_parse_item_basic(pst->pattern, &info);
934 	if (rc != 0)
935 		return rc;
936 
937 	return npc_update_parse_state(pst, &info, lid, lt, 0);
938 }
939