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