xref: /dpdk/drivers/common/cnxk/roc_npc_parse.c (revision b19f366c)
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 int
140 npc_parse_lb(struct npc_parse_state *pst)
141 {
142 	const struct roc_npc_item_info *pattern = pst->pattern;
143 	const struct roc_npc_item_info *last_pattern;
144 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
145 	struct npc_parse_item_info info;
146 	int lid, lt, lflags;
147 	int nr_vlans = 0;
148 	int rc;
149 
150 	info.spec = NULL;
151 	info.mask = NULL;
152 	info.def_mask = NULL;
153 	info.hw_hdr_len = NPC_TPID_LENGTH;
154 
155 	lid = NPC_LID_LB;
156 	lflags = 0;
157 	last_pattern = pattern;
158 
159 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
160 		/* RTE vlan is either 802.1q or 802.1ad,
161 		 * this maps to either CTAG/STAG. We need to decide
162 		 * based on number of VLANS present. Matching is
163 		 * supported on first tag only.
164 		 */
165 		info.hw_mask = NULL;
166 		info.len = pst->pattern->size;
167 
168 		pattern = pst->pattern;
169 		while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
170 			nr_vlans++;
171 
172 			/* Basic validation of Second/Third vlan item */
173 			if (nr_vlans > 1) {
174 				rc = npc_parse_item_basic(pattern, &info);
175 				if (rc != 0)
176 					return rc;
177 			}
178 			last_pattern = pattern;
179 			pattern++;
180 			pattern = npc_parse_skip_void_and_any_items(pattern);
181 		}
182 
183 		switch (nr_vlans) {
184 		case 1:
185 			lt = NPC_LT_LB_CTAG;
186 			break;
187 		case 2:
188 			lt = NPC_LT_LB_STAG_QINQ;
189 			lflags = NPC_F_STAG_CTAG;
190 			break;
191 		case 3:
192 			lt = NPC_LT_LB_STAG_QINQ;
193 			lflags = NPC_F_STAG_STAG_CTAG;
194 			break;
195 		default:
196 			return NPC_ERR_PATTERN_NOTSUP;
197 		}
198 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
199 		/* we can support ETAG and match a subsequent CTAG
200 		 * without any matching support.
201 		 */
202 		lt = NPC_LT_LB_ETAG;
203 		lflags = 0;
204 
205 		last_pattern = pst->pattern;
206 		pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
207 		if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
208 			/* set supported mask to NULL for vlan tag */
209 			info.hw_mask = NULL;
210 			info.len = pattern->size;
211 			rc = npc_parse_item_basic(pattern, &info);
212 			if (rc != 0)
213 				return rc;
214 
215 			lflags = NPC_F_ETAG_CTAG;
216 			last_pattern = pattern;
217 		}
218 		info.len = pattern->size;
219 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
220 		info.hw_mask = NULL;
221 		info.len = pst->pattern->size;
222 		lt = NPC_LT_LB_STAG_QINQ;
223 		lflags = NPC_F_STAG_CTAG;
224 	} else {
225 		return 0;
226 	}
227 
228 	info.hw_mask = &hw_mask;
229 	info.spec = NULL;
230 	info.mask = NULL;
231 	npc_get_hw_supp_mask(pst, &info, lid, lt);
232 
233 	rc = npc_parse_item_basic(pst->pattern, &info);
234 	if (rc != 0)
235 		return rc;
236 
237 	/* Point pattern to last item consumed */
238 	pst->pattern = last_pattern;
239 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
240 }
241 
242 static int
243 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
244 {
245 	uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
246 			       NPC_F_MPLS_4_LABELS};
247 	const struct roc_npc_item_info *pattern = pst->pattern;
248 	struct npc_parse_item_info info;
249 	int nr_labels = 0;
250 	int rc;
251 
252 	/*
253 	 * pst->pattern points to first MPLS label. We only check
254 	 * that subsequent labels do not have anything to match.
255 	 */
256 	info.hw_mask = NULL;
257 	info.len = pattern->size;
258 	info.spec = NULL;
259 	info.mask = NULL;
260 	info.hw_hdr_len = 0;
261 	info.def_mask = NULL;
262 
263 	while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
264 		nr_labels++;
265 
266 		/* Basic validation of Second/Third/Fourth mpls item */
267 		if (nr_labels > 1) {
268 			rc = npc_parse_item_basic(pattern, &info);
269 			if (rc != 0)
270 				return rc;
271 		}
272 		pst->last_pattern = pattern;
273 		pattern++;
274 		pattern = npc_parse_skip_void_and_any_items(pattern);
275 	}
276 
277 	if (nr_labels < 1 || nr_labels > 4)
278 		return NPC_ERR_PATTERN_NOTSUP;
279 
280 	*flag = flag_list[nr_labels - 1];
281 	return 0;
282 }
283 
284 static int
285 npc_parse_mpls(struct npc_parse_state *pst, int lid)
286 {
287 	/* Find number of MPLS labels */
288 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
289 	struct npc_parse_item_info info;
290 	int lt, lflags;
291 	int rc;
292 
293 	lflags = 0;
294 
295 	if (lid == NPC_LID_LC)
296 		lt = NPC_LT_LC_MPLS;
297 	else if (lid == NPC_LID_LD)
298 		lt = NPC_LT_LD_TU_MPLS_IN_IP;
299 	else
300 		lt = NPC_LT_LE_TU_MPLS_IN_UDP;
301 
302 	/* Prepare for parsing the first item */
303 	info.hw_mask = &hw_mask;
304 	info.len = pst->pattern->size;
305 	info.spec = NULL;
306 	info.mask = NULL;
307 	info.hw_hdr_len = 0;
308 
309 	npc_get_hw_supp_mask(pst, &info, lid, lt);
310 	rc = npc_parse_item_basic(pst->pattern, &info);
311 	if (rc != 0)
312 		return rc;
313 
314 	/*
315 	 * Parse for more labels.
316 	 * This sets lflags and pst->last_pattern correctly.
317 	 */
318 	rc = npc_parse_mpls_label_stack(pst, &lflags);
319 	if (rc != 0)
320 		return rc;
321 
322 	pst->tunnel = 1;
323 	pst->pattern = pst->last_pattern;
324 
325 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
326 }
327 
328 static inline void
329 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
330 {
331 	const struct roc_npc_item_info *pattern = pst->pattern + 1;
332 
333 	pattern = npc_parse_skip_void_and_any_items(pattern);
334 	if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
335 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
336 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
337 		pst->tunnel = 1;
338 }
339 
340 int
341 npc_parse_lc(struct npc_parse_state *pst)
342 {
343 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
344 	struct npc_parse_item_info info;
345 	int lid, lt;
346 	int rc;
347 
348 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
349 		return npc_parse_mpls(pst, NPC_LID_LC);
350 
351 	info.hw_mask = &hw_mask;
352 	info.spec = NULL;
353 	info.mask = NULL;
354 	info.hw_hdr_len = 0;
355 	lid = NPC_LID_LC;
356 
357 	switch (pst->pattern->type) {
358 	case ROC_NPC_ITEM_TYPE_IPV4:
359 		lt = NPC_LT_LC_IP;
360 		info.len = pst->pattern->size;
361 		break;
362 	case ROC_NPC_ITEM_TYPE_IPV6:
363 		lid = NPC_LID_LC;
364 		lt = NPC_LT_LC_IP6;
365 		info.len = pst->pattern->size;
366 		break;
367 	case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
368 		lt = NPC_LT_LC_ARP;
369 		info.len = pst->pattern->size;
370 		break;
371 	case ROC_NPC_ITEM_TYPE_IPV6_EXT:
372 		lid = NPC_LID_LC;
373 		lt = NPC_LT_LC_IP6_EXT;
374 		info.len = pst->pattern->size;
375 		info.hw_hdr_len = 40;
376 		break;
377 	case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
378 		lt = NPC_LT_LC_CUSTOM0;
379 		info.len = pst->pattern->size;
380 		break;
381 	default:
382 		/* No match at this layer */
383 		return 0;
384 	}
385 
386 	/* Identify if IP tunnels MPLS or IPv4/v6 */
387 	npc_check_lc_ip_tunnel(pst);
388 
389 	npc_get_hw_supp_mask(pst, &info, lid, lt);
390 	rc = npc_parse_item_basic(pst->pattern, &info);
391 	if (rc != 0)
392 		return rc;
393 
394 	return npc_update_parse_state(pst, &info, lid, lt, 0);
395 }
396 
397 int
398 npc_parse_ld(struct npc_parse_state *pst)
399 {
400 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
401 	struct npc_parse_item_info info;
402 	int lid, lt, lflags;
403 	int rc;
404 
405 	if (pst->tunnel) {
406 		/* We have already parsed MPLS or IPv4/v6 followed
407 		 * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
408 		 * would be parsed as tunneled versions. Skip
409 		 * this layer, except for tunneled MPLS. If LC is
410 		 * MPLS, we have anyway skipped all stacked MPLS
411 		 * labels.
412 		 */
413 		if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
414 			return npc_parse_mpls(pst, NPC_LID_LD);
415 		return 0;
416 	}
417 	info.hw_mask = &hw_mask;
418 	info.spec = NULL;
419 	info.mask = NULL;
420 	info.def_mask = NULL;
421 	info.len = 0;
422 	info.hw_hdr_len = 0;
423 
424 	lid = NPC_LID_LD;
425 	lflags = 0;
426 
427 	switch (pst->pattern->type) {
428 	case ROC_NPC_ITEM_TYPE_ICMP:
429 		if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
430 			lt = NPC_LT_LD_ICMP6;
431 		else
432 			lt = NPC_LT_LD_ICMP;
433 		info.len = pst->pattern->size;
434 		break;
435 	case ROC_NPC_ITEM_TYPE_UDP:
436 		lt = NPC_LT_LD_UDP;
437 		info.len = pst->pattern->size;
438 		break;
439 	case ROC_NPC_ITEM_TYPE_IGMP:
440 		lt = NPC_LT_LD_IGMP;
441 		info.len = pst->pattern->size;
442 		break;
443 	case ROC_NPC_ITEM_TYPE_TCP:
444 		lt = NPC_LT_LD_TCP;
445 		info.len = pst->pattern->size;
446 		break;
447 	case ROC_NPC_ITEM_TYPE_SCTP:
448 		lt = NPC_LT_LD_SCTP;
449 		info.len = pst->pattern->size;
450 		break;
451 	case ROC_NPC_ITEM_TYPE_GRE:
452 		lt = NPC_LT_LD_GRE;
453 		info.len = pst->pattern->size;
454 		break;
455 	case ROC_NPC_ITEM_TYPE_GRE_KEY:
456 		lt = NPC_LT_LD_GRE;
457 		info.len = pst->pattern->size;
458 		info.hw_hdr_len = 4;
459 		break;
460 	case ROC_NPC_ITEM_TYPE_NVGRE:
461 		lt = NPC_LT_LD_NVGRE;
462 		lflags = NPC_F_GRE_NVGRE;
463 		info.len = pst->pattern->size;
464 		/* Further IP/Ethernet are parsed as tunneled */
465 		pst->tunnel = 1;
466 		break;
467 	default:
468 		return 0;
469 	}
470 
471 	npc_get_hw_supp_mask(pst, &info, lid, lt);
472 	rc = npc_parse_item_basic(pst->pattern, &info);
473 	if (rc != 0)
474 		return rc;
475 
476 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
477 }
478 
479 int
480 npc_parse_le(struct npc_parse_state *pst)
481 {
482 	const struct roc_npc_item_info *pattern = pst->pattern;
483 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
484 	struct npc_parse_item_info info;
485 	int lid, lt, lflags;
486 	int rc;
487 
488 	if (pst->tunnel)
489 		return 0;
490 
491 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
492 		return npc_parse_mpls(pst, NPC_LID_LE);
493 
494 	info.spec = NULL;
495 	info.mask = NULL;
496 	info.hw_mask = NULL;
497 	info.def_mask = NULL;
498 	info.len = 0;
499 	info.hw_hdr_len = 0;
500 	lid = NPC_LID_LE;
501 	lflags = 0;
502 
503 	/* Ensure we are not matching anything in UDP */
504 	rc = npc_parse_item_basic(pattern, &info);
505 	if (rc)
506 		return rc;
507 
508 	info.hw_mask = &hw_mask;
509 	pattern = npc_parse_skip_void_and_any_items(pattern);
510 	switch (pattern->type) {
511 	case ROC_NPC_ITEM_TYPE_VXLAN:
512 		lflags = NPC_F_UDP_VXLAN;
513 		info.len = pattern->size;
514 		lt = NPC_LT_LE_VXLAN;
515 		break;
516 	case ROC_NPC_ITEM_TYPE_GTPC:
517 		lflags = NPC_F_UDP_GTP_GTPC;
518 		info.len = pattern->size;
519 		lt = NPC_LT_LE_GTPC;
520 		break;
521 	case ROC_NPC_ITEM_TYPE_GTPU:
522 		lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
523 		info.len = pattern->size;
524 		lt = NPC_LT_LE_GTPU;
525 		break;
526 	case ROC_NPC_ITEM_TYPE_GENEVE:
527 		lflags = NPC_F_UDP_GENEVE;
528 		info.len = pattern->size;
529 		lt = NPC_LT_LE_GENEVE;
530 		break;
531 	case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
532 		lflags = NPC_F_UDP_VXLANGPE;
533 		info.len = pattern->size;
534 		lt = NPC_LT_LE_VXLANGPE;
535 		break;
536 	case ROC_NPC_ITEM_TYPE_ESP:
537 		lt = NPC_LT_LE_ESP;
538 		info.len = pst->pattern->size;
539 		break;
540 	default:
541 		return 0;
542 	}
543 
544 	pst->tunnel = 1;
545 
546 	npc_get_hw_supp_mask(pst, &info, lid, lt);
547 	rc = npc_parse_item_basic(pattern, &info);
548 	if (rc != 0)
549 		return rc;
550 
551 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
552 }
553 
554 int
555 npc_parse_lf(struct npc_parse_state *pst)
556 {
557 	const struct roc_npc_item_info *pattern, *last_pattern;
558 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
559 	struct npc_parse_item_info info;
560 	int lid, lt, lflags;
561 	int nr_vlans = 0;
562 	int rc;
563 
564 	/* We hit this layer if there is a tunneling protocol */
565 	if (!pst->tunnel)
566 		return 0;
567 
568 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
569 		return 0;
570 
571 	lid = NPC_LID_LF;
572 	lt = NPC_LT_LF_TU_ETHER;
573 	lflags = 0;
574 
575 	/* No match support for vlan tags */
576 	info.hw_mask = NULL;
577 	info.len = pst->pattern->size;
578 	info.spec = NULL;
579 	info.mask = NULL;
580 	info.hw_hdr_len = 0;
581 
582 	/* Look ahead and find out any VLAN tags. These can be
583 	 * detected but no data matching is available.
584 	 */
585 	last_pattern = pst->pattern;
586 	pattern = pst->pattern + 1;
587 	pattern = npc_parse_skip_void_and_any_items(pattern);
588 	while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
589 		nr_vlans++;
590 		last_pattern = pattern;
591 		pattern++;
592 		pattern = npc_parse_skip_void_and_any_items(pattern);
593 	}
594 	switch (nr_vlans) {
595 	case 0:
596 		break;
597 	case 1:
598 		lflags = NPC_F_TU_ETHER_CTAG;
599 		break;
600 	case 2:
601 		lflags = NPC_F_TU_ETHER_STAG_CTAG;
602 		break;
603 	default:
604 		return NPC_ERR_PATTERN_NOTSUP;
605 	}
606 
607 	info.hw_mask = &hw_mask;
608 	info.len = pst->pattern->size;
609 	info.hw_hdr_len = 0;
610 	npc_get_hw_supp_mask(pst, &info, lid, lt);
611 	info.spec = NULL;
612 	info.mask = NULL;
613 
614 	rc = npc_parse_item_basic(pst->pattern, &info);
615 	if (rc != 0)
616 		return rc;
617 
618 	pst->pattern = last_pattern;
619 
620 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
621 }
622 
623 int
624 npc_parse_lg(struct npc_parse_state *pst)
625 {
626 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
627 	struct npc_parse_item_info info;
628 	int lid, lt;
629 	int rc;
630 
631 	if (!pst->tunnel)
632 		return 0;
633 
634 	info.hw_mask = &hw_mask;
635 	info.spec = NULL;
636 	info.mask = NULL;
637 	info.hw_hdr_len = 0;
638 	lid = NPC_LID_LG;
639 
640 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
641 		lt = NPC_LT_LG_TU_IP;
642 		info.len = pst->pattern->size;
643 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
644 		lt = NPC_LT_LG_TU_IP6;
645 		info.len = pst->pattern->size;
646 	} else {
647 		/* There is no tunneled IP header */
648 		return 0;
649 	}
650 
651 	npc_get_hw_supp_mask(pst, &info, lid, lt);
652 	rc = npc_parse_item_basic(pst->pattern, &info);
653 	if (rc != 0)
654 		return rc;
655 
656 	return npc_update_parse_state(pst, &info, lid, lt, 0);
657 }
658 
659 int
660 npc_parse_lh(struct npc_parse_state *pst)
661 {
662 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
663 	struct npc_parse_item_info info;
664 	int lid, lt;
665 	int rc;
666 
667 	if (!pst->tunnel)
668 		return 0;
669 
670 	info.hw_mask = &hw_mask;
671 	info.spec = NULL;
672 	info.mask = NULL;
673 	info.hw_hdr_len = 0;
674 	lid = NPC_LID_LH;
675 
676 	switch (pst->pattern->type) {
677 	case ROC_NPC_ITEM_TYPE_UDP:
678 		lt = NPC_LT_LH_TU_UDP;
679 		info.len = pst->pattern->size;
680 		break;
681 	case ROC_NPC_ITEM_TYPE_TCP:
682 		lt = NPC_LT_LH_TU_TCP;
683 		info.len = pst->pattern->size;
684 		break;
685 	case ROC_NPC_ITEM_TYPE_SCTP:
686 		lt = NPC_LT_LH_TU_SCTP;
687 		info.len = pst->pattern->size;
688 		break;
689 	case ROC_NPC_ITEM_TYPE_ESP:
690 		lt = NPC_LT_LH_TU_ESP;
691 		info.len = pst->pattern->size;
692 		break;
693 	default:
694 		return 0;
695 	}
696 
697 	npc_get_hw_supp_mask(pst, &info, lid, lt);
698 	rc = npc_parse_item_basic(pst->pattern, &info);
699 	if (rc != 0)
700 		return rc;
701 
702 	return npc_update_parse_state(pst, &info, lid, lt, 0);
703 }
704