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