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