xref: /dpdk/drivers/common/cnxk/roc_npc_parse.c (revision 296e9040e2c15b424cf716bfdde0f5257c17a9fd)
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 int
npc_parse_port_representor_id(struct npc_parse_state * pst)39 npc_parse_port_representor_id(struct npc_parse_state *pst)
40 {
41 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_REPRESENTED_PORT)
42 		return 0;
43 
44 	pst->pattern++;
45 
46 	return 0;
47 }
48 
49 int
npc_parse_represented_port_id(struct npc_parse_state * pst)50 npc_parse_represented_port_id(struct npc_parse_state *pst)
51 {
52 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_REPRESENTED_PORT)
53 		return 0;
54 
55 	if (pst->flow->nix_intf != NIX_INTF_RX)
56 		return -EINVAL;
57 
58 	pst->pattern++;
59 
60 	return 0;
61 }
62 
63 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)64 npc_flow_raw_item_prepare(const struct roc_npc_flow_item_raw *raw_spec,
65 			  const struct roc_npc_flow_item_raw *raw_mask,
66 			  struct npc_parse_item_info *info, uint8_t *spec_buf, uint8_t *mask_buf)
67 {
68 
69 	memset(spec_buf, 0, NPC_MAX_RAW_ITEM_LEN);
70 	memset(mask_buf, 0, NPC_MAX_RAW_ITEM_LEN);
71 
72 	memcpy(spec_buf + raw_spec->offset, raw_spec->pattern,
73 	       raw_spec->length);
74 
75 	if (raw_mask && raw_mask->pattern) {
76 		memcpy(mask_buf + raw_spec->offset, raw_mask->pattern,
77 		       raw_spec->length);
78 	} else {
79 		memset(mask_buf + raw_spec->offset, 0xFF, raw_spec->length);
80 	}
81 
82 	info->len = NPC_MAX_RAW_ITEM_LEN;
83 	info->spec = spec_buf;
84 	info->mask = mask_buf;
85 	return 0;
86 }
87 
88 int
npc_parse_pre_l2(struct npc_parse_state * pst)89 npc_parse_pre_l2(struct npc_parse_state *pst)
90 {
91 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
92 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN] = {0};
93 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN] = {0};
94 	const struct roc_npc_flow_item_raw *raw_spec;
95 	struct npc_parse_item_info info;
96 	int lid, lt, len;
97 	int rc;
98 
99 	if (pst->npc->switch_header_type != ROC_PRIV_FLAGS_PRE_L2)
100 		return 0;
101 
102 	/* Identify the pattern type into lid, lt */
103 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_RAW)
104 		return 0;
105 
106 	lid = NPC_LID_LA;
107 	lt = NPC_LT_LA_CUSTOM_PRE_L2_ETHER;
108 	info.hw_hdr_len = 0;
109 
110 	raw_spec = pst->pattern->spec;
111 	len = raw_spec->length + raw_spec->offset;
112 	if (len > NPC_MAX_RAW_ITEM_LEN)
113 		return -EINVAL;
114 
115 	if (raw_spec->relative == 0 || raw_spec->search || raw_spec->limit ||
116 	    raw_spec->offset < 0)
117 		return -EINVAL;
118 
119 	npc_flow_raw_item_prepare(
120 		(const struct roc_npc_flow_item_raw *)pst->pattern->spec,
121 		(const struct roc_npc_flow_item_raw *)pst->pattern->mask, &info,
122 		raw_spec_buf, raw_mask_buf);
123 
124 	info.def_mask = NULL;
125 	info.hw_mask = &hw_mask;
126 	npc_get_hw_supp_mask(pst, &info, lid, lt);
127 
128 	/* Basic validation of item parameters */
129 	rc = npc_parse_item_basic(pst->pattern, &info);
130 	if (rc)
131 		return rc;
132 
133 	/* Update pst if not validate only? clash check? */
134 	return npc_update_parse_state(pst, &info, lid, lt, 0);
135 }
136 
137 int
npc_parse_cpt_hdr(struct npc_parse_state * pst)138 npc_parse_cpt_hdr(struct npc_parse_state *pst)
139 {
140 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
141 	struct npc_parse_item_info info;
142 	int lid, lt;
143 	int rc;
144 
145 	/* Identify the pattern type into lid, lt */
146 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR)
147 		return 0;
148 
149 	lid = NPC_LID_LA;
150 	lt = NPC_LT_LA_CPT_HDR;
151 	info.hw_hdr_len = 0;
152 
153 	/* Prepare for parsing the item */
154 	info.def_mask = NULL;
155 	info.hw_mask = &hw_mask;
156 	info.len = pst->pattern->size;
157 	npc_get_hw_supp_mask(pst, &info, lid, lt);
158 	info.spec = NULL;
159 	info.mask = NULL;
160 
161 	/* Basic validation of item parameters */
162 	rc = npc_parse_item_basic(pst->pattern, &info);
163 	if (rc)
164 		return rc;
165 
166 	/* Update pst if not validate only? clash check? */
167 	return npc_update_parse_state(pst, &info, lid, lt, 0);
168 }
169 
170 int
npc_parse_higig2_hdr(struct npc_parse_state * pst)171 npc_parse_higig2_hdr(struct npc_parse_state *pst)
172 {
173 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
174 	struct npc_parse_item_info info;
175 	int lid, lt;
176 	int rc;
177 
178 	/* Identify the pattern type into lid, lt */
179 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
180 		return 0;
181 
182 	lid = NPC_LID_LA;
183 	lt = NPC_LT_LA_HIGIG2_ETHER;
184 	info.hw_hdr_len = 0;
185 
186 	if (pst->flow->nix_intf == NIX_INTF_TX) {
187 		lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
188 		info.hw_hdr_len = NPC_IH_LENGTH;
189 	}
190 
191 	/* Prepare for parsing the item */
192 	info.def_mask = NULL;
193 	info.hw_mask = &hw_mask;
194 	info.len = pst->pattern->size;
195 	npc_get_hw_supp_mask(pst, &info, lid, lt);
196 	info.spec = NULL;
197 	info.mask = NULL;
198 
199 	/* Basic validation of item parameters */
200 	rc = npc_parse_item_basic(pst->pattern, &info);
201 	if (rc)
202 		return rc;
203 
204 	/* Update pst if not validate only? clash check? */
205 	return npc_update_parse_state(pst, &info, lid, lt, 0);
206 }
207 
208 int
npc_parse_tx_queue(struct npc_parse_state * pst)209 npc_parse_tx_queue(struct npc_parse_state *pst)
210 {
211 	struct nix_inst_hdr_s nix_inst_hdr, nix_inst_hdr_mask;
212 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
213 	struct npc_parse_item_info parse_info;
214 	const uint16_t *send_queue;
215 	int lid, lt, rc = 0;
216 
217 	memset(&nix_inst_hdr, 0, sizeof(nix_inst_hdr));
218 	memset(&nix_inst_hdr_mask, 0, sizeof(nix_inst_hdr_mask));
219 	memset(&parse_info, 0, sizeof(parse_info));
220 
221 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_TX_QUEUE)
222 		return 0;
223 
224 	if (pst->flow->nix_intf != NIX_INTF_TX)
225 		return NPC_ERR_INVALID_SPEC;
226 
227 	lid = NPC_LID_LA;
228 	lt = NPC_LT_LA_IH_NIX_ETHER;
229 	send_queue = (const uint16_t *)pst->pattern->spec;
230 
231 	if (*send_queue >= pst->nb_tx_queues)
232 		return NPC_ERR_INVALID_SPEC;
233 
234 	nix_inst_hdr.sq = *send_queue;
235 	nix_inst_hdr_mask.sq = 0xFFFF;
236 
237 	parse_info.def_mask = NULL;
238 	parse_info.spec = &nix_inst_hdr;
239 	parse_info.mask = &nix_inst_hdr_mask;
240 	parse_info.len = sizeof(nix_inst_hdr);
241 	parse_info.def_mask = NULL;
242 	parse_info.hw_hdr_len = 0;
243 
244 	memset(hw_mask, 0, sizeof(hw_mask));
245 
246 	parse_info.hw_mask = &hw_mask;
247 	npc_get_hw_supp_mask(pst, &parse_info, lid, lt);
248 
249 	rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
250 	if (!rc)
251 		return NPC_ERR_INVALID_MASK;
252 
253 	rc = npc_update_parse_state(pst, &parse_info, lid, lt, 0);
254 	if (rc)
255 		return rc;
256 
257 	return 0;
258 }
259 
260 int
npc_parse_la(struct npc_parse_state * pst)261 npc_parse_la(struct npc_parse_state *pst)
262 {
263 	const struct roc_npc_flow_item_eth *eth_item;
264 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
265 	struct npc_parse_item_info info;
266 	int lid, lt;
267 	int rc;
268 
269 	/* Identify the pattern type into lid, lt */
270 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
271 		return 0;
272 
273 	pst->has_eth_type = true;
274 	eth_item = pst->pattern->spec;
275 
276 	lid = NPC_LID_LA;
277 	lt = NPC_LT_LA_ETHER;
278 	info.hw_hdr_len = 0;
279 
280 	if (pst->flow->nix_intf == NIX_INTF_TX) {
281 		lt = NPC_LT_LA_IH_NIX_ETHER;
282 		info.hw_hdr_len = NPC_IH_LENGTH;
283 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
284 			lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
285 			info.hw_hdr_len += NPC_HIGIG2_LENGTH;
286 		}
287 	} else {
288 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
289 			lt = NPC_LT_LA_HIGIG2_ETHER;
290 			info.hw_hdr_len = NPC_HIGIG2_LENGTH;
291 		}
292 	}
293 
294 	/* Prepare for parsing the item */
295 	info.def_mask = NULL;
296 	info.hw_mask = &hw_mask;
297 	info.len = sizeof(eth_item->hdr);
298 	npc_get_hw_supp_mask(pst, &info, lid, lt);
299 	info.spec = NULL;
300 	info.mask = NULL;
301 
302 	/* Basic validation of item parameters */
303 	rc = npc_parse_item_basic(pst->pattern, &info);
304 	if (rc)
305 		return rc;
306 
307 	rc = npc_update_parse_state(pst, &info, lid, lt, 0);
308 	if (rc)
309 		return rc;
310 
311 	if (eth_item && eth_item->has_vlan)
312 		pst->set_vlan_ltype_mask = true;
313 
314 	return 0;
315 }
316 
317 #define NPC_MAX_SUPPORTED_VLANS 3
318 
319 static int
npc_parse_vlan_count(const struct roc_npc_item_info * pattern,const struct roc_npc_item_info ** pattern_list,const struct roc_npc_flow_item_vlan ** vlan_items,int * vlan_count)320 npc_parse_vlan_count(const struct roc_npc_item_info *pattern,
321 		     const struct roc_npc_item_info **pattern_list,
322 		     const struct roc_npc_flow_item_vlan **vlan_items, int *vlan_count)
323 {
324 	*vlan_count = 0;
325 	while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
326 		if (*vlan_count > NPC_MAX_SUPPORTED_VLANS - 1)
327 			return NPC_ERR_PATTERN_NOTSUP;
328 
329 		/* Don't support ranges */
330 		if (pattern->last != NULL)
331 			return NPC_ERR_INVALID_RANGE;
332 
333 		/* If spec is NULL, both mask and last must be NULL, this
334 		 * makes it to match ANY value (eq to mask = 0).
335 		 * Setting either mask or last without spec is an error
336 		 */
337 		if (pattern->spec == NULL) {
338 			if (pattern->last != NULL && pattern->mask != NULL)
339 				return NPC_ERR_INVALID_SPEC;
340 		}
341 
342 		pattern_list[*vlan_count] = pattern;
343 		vlan_items[*vlan_count] = pattern->spec;
344 		(*vlan_count)++;
345 
346 		pattern++;
347 		pattern = npc_parse_skip_void_and_any_items(pattern);
348 	}
349 
350 	return 0;
351 }
352 
353 static int
npc_parse_vlan_ltype_get(struct npc_parse_state * pst,const struct roc_npc_flow_item_vlan ** vlan_item,int vlan_count,int * ltype,int * lflags)354 npc_parse_vlan_ltype_get(struct npc_parse_state *pst,
355 			 const struct roc_npc_flow_item_vlan **vlan_item, int vlan_count,
356 			 int *ltype, int *lflags)
357 {
358 	switch (vlan_count) {
359 	case 1:
360 		*ltype = NPC_LT_LB_CTAG;
361 		if (vlan_item[0] && vlan_item[0]->has_more_vlan)
362 			*ltype = NPC_LT_LB_STAG_QINQ;
363 		break;
364 	case 2:
365 		if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
366 			if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
367 			      0x3ULL << NPC_LFLAG_LB_OFFSET))
368 				return NPC_ERR_PATTERN_NOTSUP;
369 
370 			/* This lflag value will match either one of
371 			 * NPC_F_LB_L_WITH_STAG_STAG,
372 			 * NPC_F_LB_L_WITH_QINQ_CTAG,
373 			 * NPC_F_LB_L_WITH_QINQ_QINQ and
374 			 * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
375 			 * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
376 			 * hence will not match.
377 			 */
378 
379 			*lflags = NPC_F_LB_L_WITH_QINQ_CTAG & NPC_F_LB_L_WITH_QINQ_QINQ &
380 				  NPC_F_LB_L_WITH_STAG_STAG;
381 		}
382 		*ltype = NPC_LT_LB_STAG_QINQ;
383 		break;
384 	case 3:
385 		if (vlan_item[2] && vlan_item[2]->has_more_vlan)
386 			return NPC_ERR_PATTERN_NOTSUP;
387 		if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] & 0x3ULL << NPC_LFLAG_LB_OFFSET))
388 			return NPC_ERR_PATTERN_NOTSUP;
389 		*ltype = NPC_LT_LB_STAG_QINQ;
390 		*lflags = NPC_F_STAG_STAG_CTAG;
391 		break;
392 	default:
393 		return NPC_ERR_PATTERN_NOTSUP;
394 	}
395 
396 	return 0;
397 }
398 
399 static int
npc_update_vlan_parse_state(struct npc_parse_state * pst,const struct roc_npc_item_info * pattern,int lid,int lt,uint8_t lflags,int vlan_count)400 npc_update_vlan_parse_state(struct npc_parse_state *pst, const struct roc_npc_item_info *pattern,
401 			    int lid, int lt, uint8_t lflags, int vlan_count)
402 {
403 	uint8_t vlan_spec[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
404 	uint8_t vlan_mask[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
405 	int rc = 0, i, offset = NPC_TPID_LENGTH;
406 	struct npc_parse_item_info parse_info;
407 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
408 
409 	memset(vlan_spec, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
410 	memset(vlan_mask, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
411 	memset(&parse_info, 0, sizeof(parse_info));
412 
413 	if (vlan_count > 2)
414 		vlan_count = 2;
415 
416 	for (i = 0; i < vlan_count; i++) {
417 		if (pattern[i].spec)
418 			memcpy(vlan_spec + offset, pattern[i].spec, sizeof(struct roc_vlan_hdr));
419 		if (pattern[i].mask)
420 			memcpy(vlan_mask + offset, pattern[i].mask, sizeof(struct roc_vlan_hdr));
421 
422 		offset += 4;
423 	}
424 
425 	parse_info.def_mask = NULL;
426 	parse_info.spec = vlan_spec;
427 	parse_info.mask = vlan_mask;
428 	parse_info.def_mask = NULL;
429 	parse_info.hw_hdr_len = 0;
430 
431 	lid = NPC_LID_LB;
432 	parse_info.hw_mask = hw_mask;
433 
434 	if (lt == NPC_LT_LB_CTAG)
435 		parse_info.len = sizeof(struct roc_vlan_hdr) + NPC_TPID_LENGTH;
436 
437 	if (lt == NPC_LT_LB_STAG_QINQ)
438 		parse_info.len = sizeof(struct roc_vlan_hdr) * 2 + NPC_TPID_LENGTH;
439 
440 	memset(hw_mask, 0, sizeof(hw_mask));
441 
442 	parse_info.hw_mask = &hw_mask;
443 	npc_get_hw_supp_mask(pst, &parse_info, lid, lt);
444 
445 	rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
446 	if (!rc)
447 		return NPC_ERR_INVALID_MASK;
448 
449 	/* Point pattern to last item consumed */
450 	pst->pattern = pattern;
451 	return npc_update_parse_state(pst, &parse_info, lid, lt, lflags);
452 }
453 
454 static int
npc_parse_lb_vlan(struct npc_parse_state * pst)455 npc_parse_lb_vlan(struct npc_parse_state *pst)
456 {
457 	const struct roc_npc_flow_item_vlan *vlan_items[NPC_MAX_SUPPORTED_VLANS];
458 	const struct roc_npc_item_info *pattern_list[NPC_MAX_SUPPORTED_VLANS];
459 	const struct roc_npc_item_info *last_pattern;
460 	int vlan_count = 0, rc = 0;
461 	int lid, lt, lflags;
462 
463 	lid = NPC_LID_LB;
464 	lflags = 0;
465 	last_pattern = pst->pattern;
466 
467 	rc = npc_parse_vlan_count(pst->pattern, pattern_list, vlan_items, &vlan_count);
468 	if (rc)
469 		return rc;
470 
471 	rc = npc_parse_vlan_ltype_get(pst, vlan_items, vlan_count, &lt, &lflags);
472 	if (rc)
473 		return rc;
474 
475 	if (vlan_count == 3) {
476 		if (pattern_list[2]->spec != NULL && pattern_list[2]->mask != NULL &&
477 		    pattern_list[2]->last != NULL)
478 			return NPC_ERR_PATTERN_NOTSUP;
479 
480 		/* Matching can be done only for two tags. */
481 		vlan_count = 2;
482 		last_pattern++;
483 	}
484 
485 	rc = npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags, vlan_count);
486 	if (rc)
487 		return rc;
488 
489 	if (vlan_count > 1)
490 		pst->pattern = last_pattern + vlan_count;
491 
492 	return 0;
493 }
494 
495 int
npc_parse_lb(struct npc_parse_state * pst)496 npc_parse_lb(struct npc_parse_state *pst)
497 {
498 	const struct roc_npc_item_info *pattern = pst->pattern;
499 	const struct roc_npc_item_info *last_pattern;
500 	const struct roc_npc_flow_item_raw *raw_spec;
501 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
502 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
503 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
504 	struct npc_parse_item_info info;
505 	int lid, lt, lflags, len = 0;
506 	int rc;
507 
508 	info.def_mask = NULL;
509 	info.spec = NULL;
510 	info.mask = NULL;
511 	info.def_mask = NULL;
512 	info.hw_hdr_len = NPC_TPID_LENGTH;
513 
514 	lid = NPC_LID_LB;
515 	lflags = 0;
516 	last_pattern = pattern;
517 
518 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
519 		/* RTE vlan is either 802.1q or 802.1ad,
520 		 * this maps to either CTAG/STAG. We need to decide
521 		 * based on number of VLANS present. Matching is
522 		 * supported on first two tags.
523 		 */
524 
525 		return npc_parse_lb_vlan(pst);
526 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
527 		/* we can support ETAG and match a subsequent CTAG
528 		 * without any matching support.
529 		 */
530 		lt = NPC_LT_LB_ETAG;
531 		lflags = 0;
532 
533 		last_pattern = pst->pattern;
534 		pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
535 		if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
536 			/* set supported mask to NULL for vlan tag */
537 			info.hw_mask = NULL;
538 			info.len = pattern->size;
539 			rc = npc_parse_item_basic(pattern, &info);
540 			if (rc != 0)
541 				return rc;
542 
543 			lflags = NPC_F_ETAG_CTAG;
544 			last_pattern = pattern;
545 		}
546 		info.len = pattern->size;
547 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
548 		info.hw_mask = NULL;
549 		info.len = pattern->size;
550 		lt = NPC_LT_LB_STAG_QINQ;
551 		lflags = NPC_F_STAG_CTAG;
552 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_PPPOES) {
553 		info.hw_mask = NULL;
554 		info.len = pattern->size;
555 		info.hw_hdr_len = 2;
556 		lt = NPC_LT_LB_PPPOE;
557 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
558 		raw_spec = pst->pattern->spec;
559 		if (raw_spec->relative)
560 			return 0;
561 		len = raw_spec->length + raw_spec->offset;
562 		if (len > NPC_MAX_RAW_ITEM_LEN)
563 			return -EINVAL;
564 
565 		if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
566 			lt = NPC_LT_LB_VLAN_EXDSA;
567 		} else if (pst->npc->switch_header_type ==
568 			   ROC_PRIV_FLAGS_EXDSA) {
569 			lt = NPC_LT_LB_EXDSA;
570 		} else {
571 			return -EINVAL;
572 		}
573 
574 		npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
575 						  pst->pattern->spec,
576 					  (const struct roc_npc_flow_item_raw *)
577 						  pst->pattern->mask,
578 					  &info, raw_spec_buf, raw_mask_buf);
579 
580 		info.hw_hdr_len = 0;
581 	} else {
582 		return 0;
583 	}
584 
585 	info.hw_mask = &hw_mask;
586 	npc_get_hw_supp_mask(pst, &info, lid, lt);
587 
588 	rc = npc_parse_item_basic(pst->pattern, &info);
589 	if (rc != 0)
590 		return rc;
591 
592 	/* Point pattern to last item consumed */
593 	pst->pattern = last_pattern;
594 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
595 }
596 
597 static int
npc_parse_mpls_label_stack(struct npc_parse_state * pst,int * flag)598 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
599 {
600 	uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
601 			       NPC_F_MPLS_4_LABELS};
602 	const struct roc_npc_item_info *pattern = pst->pattern;
603 	struct npc_parse_item_info info;
604 	int nr_labels = 0;
605 	int rc;
606 
607 	/*
608 	 * pst->pattern points to first MPLS label. We only check
609 	 * that subsequent labels do not have anything to match.
610 	 */
611 	info.def_mask = NULL;
612 	info.hw_mask = NULL;
613 	info.len = pattern->size;
614 	info.spec = NULL;
615 	info.mask = NULL;
616 	info.hw_hdr_len = 0;
617 
618 	while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
619 		nr_labels++;
620 
621 		/* Basic validation of Second/Third/Fourth mpls item */
622 		if (nr_labels > 1) {
623 			rc = npc_parse_item_basic(pattern, &info);
624 			if (rc != 0)
625 				return rc;
626 		}
627 		pst->last_pattern = pattern;
628 		pattern++;
629 		pattern = npc_parse_skip_void_and_any_items(pattern);
630 	}
631 
632 	if (nr_labels < 1 || nr_labels > 4)
633 		return NPC_ERR_PATTERN_NOTSUP;
634 
635 	*flag = flag_list[nr_labels - 1];
636 	return 0;
637 }
638 
639 static int
npc_parse_mpls(struct npc_parse_state * pst,int lid)640 npc_parse_mpls(struct npc_parse_state *pst, int lid)
641 {
642 	/* Find number of MPLS labels */
643 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
644 	struct npc_parse_item_info info;
645 	int lt, lflags;
646 	int rc;
647 
648 	lflags = 0;
649 
650 	if (lid == NPC_LID_LC)
651 		lt = NPC_LT_LC_MPLS;
652 	else if (lid == NPC_LID_LD)
653 		lt = NPC_LT_LD_TU_MPLS_IN_IP;
654 	else
655 		lt = NPC_LT_LE_TU_MPLS_IN_UDP;
656 
657 	/* Prepare for parsing the first item */
658 	info.hw_mask = &hw_mask;
659 	info.len = pst->pattern->size;
660 	info.spec = NULL;
661 	info.mask = NULL;
662 	info.def_mask = NULL;
663 	info.hw_hdr_len = 0;
664 
665 	npc_get_hw_supp_mask(pst, &info, lid, lt);
666 	rc = npc_parse_item_basic(pst->pattern, &info);
667 	if (rc != 0)
668 		return rc;
669 
670 	/*
671 	 * Parse for more labels.
672 	 * This sets lflags and pst->last_pattern correctly.
673 	 */
674 	rc = npc_parse_mpls_label_stack(pst, &lflags);
675 	if (rc != 0)
676 		return rc;
677 
678 	pst->tunnel = 1;
679 	pst->pattern = pst->last_pattern;
680 
681 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
682 }
683 
684 static inline void
npc_check_lc_ip_tunnel(struct npc_parse_state * pst)685 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
686 {
687 	const struct roc_npc_item_info *pattern = pst->pattern + 1;
688 
689 	pattern = npc_parse_skip_void_and_any_items(pattern);
690 	if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
691 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
692 	    pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
693 		pst->tunnel = 1;
694 }
695 
696 static int
npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 * ipv6_spec,struct npc_parse_state * pst,uint8_t * flags)697 npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
698 			struct npc_parse_state *pst, uint8_t *flags)
699 {
700 	int flags_count = 0;
701 
702 	if (ipv6_spec->has_hop_ext) {
703 		*flags = NPC_F_LC_L_EXT_HOP;
704 		flags_count++;
705 	}
706 	if (ipv6_spec->has_route_ext) {
707 		*flags = NPC_F_LC_L_EXT_ROUT;
708 		flags_count++;
709 	}
710 	if (ipv6_spec->has_frag_ext) {
711 		*flags = NPC_F_LC_U_IP6_FRAG;
712 		flags_count++;
713 	}
714 	if (ipv6_spec->has_dest_ext) {
715 		*flags = NPC_F_LC_L_EXT_DEST;
716 		flags_count++;
717 	}
718 	if (ipv6_spec->has_mobil_ext) {
719 		*flags = NPC_F_LC_L_EXT_MOBILITY;
720 		flags_count++;
721 	}
722 	if (ipv6_spec->has_hip_ext) {
723 		*flags = NPC_F_LC_L_EXT_HOSTID;
724 		flags_count++;
725 	}
726 	if (ipv6_spec->has_shim6_ext) {
727 		*flags = NPC_F_LC_L_EXT_SHIM6;
728 		flags_count++;
729 	}
730 	if (ipv6_spec->has_auth_ext) {
731 		pst->lt[NPC_LID_LD] = NPC_LT_LD_AH;
732 		flags_count++;
733 	}
734 	if (ipv6_spec->has_esp_ext) {
735 		pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP;
736 		flags_count++;
737 	}
738 
739 	if (flags_count > 1)
740 		return -EINVAL;
741 
742 	if (flags_count)
743 		pst->set_ipv6ext_ltype_mask = true;
744 
745 	return 0;
746 }
747 
748 static int
npc_process_ipv6_item(struct npc_parse_state * pst)749 npc_process_ipv6_item(struct npc_parse_state *pst)
750 {
751 	uint8_t ipv6_hdr_mask[2 * sizeof(struct roc_ipv6_hdr)];
752 	uint8_t ipv6_hdr_buf[2 * sizeof(struct roc_ipv6_hdr)];
753 	const struct roc_npc_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
754 	const struct roc_npc_item_info *pattern = pst->pattern;
755 	int offset = 0, rc = 0, lid, item_count = 0;
756 	struct npc_parse_item_info parse_info;
757 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
758 	uint8_t flags = 0, ltype;
759 
760 	memset(ipv6_hdr_buf, 0, sizeof(ipv6_hdr_buf));
761 	memset(ipv6_hdr_mask, 0, sizeof(ipv6_hdr_mask));
762 
763 	ipv6_spec = pst->pattern->spec;
764 	ipv6_mask = pst->pattern->mask;
765 
766 	parse_info.def_mask = NULL;
767 	parse_info.spec = ipv6_hdr_buf;
768 	parse_info.mask = ipv6_hdr_mask;
769 	parse_info.def_mask = NULL;
770 	parse_info.hw_hdr_len = 0;
771 	parse_info.len = sizeof(ipv6_spec->hdr);
772 
773 	pst->set_ipv6ext_ltype_mask = true;
774 
775 	lid = NPC_LID_LC;
776 	ltype = NPC_LT_LC_IP6;
777 
778 	if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
779 		item_count++;
780 		if (ipv6_spec) {
781 			memcpy(ipv6_hdr_buf, &ipv6_spec->hdr, sizeof(struct roc_ipv6_hdr));
782 			rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
783 			if (rc)
784 				return rc;
785 		}
786 		if (ipv6_mask)
787 			memcpy(ipv6_hdr_mask, &ipv6_mask->hdr, sizeof(struct roc_ipv6_hdr));
788 	}
789 
790 	offset = sizeof(struct roc_ipv6_hdr);
791 
792 	while (pattern->type != ROC_NPC_ITEM_TYPE_END) {
793 		/* Don't support ranges */
794 		if (pattern->last != NULL)
795 			return NPC_ERR_INVALID_RANGE;
796 
797 		/* If spec is NULL, both mask and last must be NULL, this
798 		 * makes it to match ANY value (eq to mask = 0).
799 		 * Setting either mask or last without spec is
800 		 * an error
801 		 */
802 		if (pattern->spec == NULL) {
803 			if (pattern->last != NULL && pattern->mask != NULL)
804 				return NPC_ERR_INVALID_SPEC;
805 		}
806 		/* Either one ROC_NPC_ITEM_TYPE_IPV6_EXT or
807 		 * one ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT is supported
808 		 * following an ROC_NPC_ITEM_TYPE_IPV6 item.
809 		 */
810 		if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_EXT) {
811 			item_count++;
812 			ltype = NPC_LT_LC_IP6_EXT;
813 			parse_info.len =
814 				sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_flow_item_ipv6_ext);
815 			if (pattern->spec)
816 				memcpy(ipv6_hdr_buf + offset, pattern->spec,
817 				       sizeof(struct roc_flow_item_ipv6_ext));
818 			if (pattern->mask)
819 				memcpy(ipv6_hdr_mask + offset, pattern->mask,
820 				       sizeof(struct roc_flow_item_ipv6_ext));
821 			break;
822 		} else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT) {
823 			item_count++;
824 			ltype = NPC_LT_LC_IP6_EXT;
825 			flags = NPC_F_LC_U_IP6_FRAG;
826 			parse_info.len =
827 				sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_ipv6_fragment_ext);
828 			if (pattern->spec)
829 				memcpy(ipv6_hdr_buf + offset, pattern->spec,
830 				       sizeof(struct roc_ipv6_fragment_ext));
831 			if (pattern->mask)
832 				memcpy(ipv6_hdr_mask + offset, pattern->mask,
833 				       sizeof(struct roc_ipv6_fragment_ext));
834 
835 			break;
836 		} else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT) {
837 			item_count++;
838 			ltype = NPC_LT_LC_IP6_EXT;
839 			parse_info.len = sizeof(struct roc_ipv6_hdr) + pattern->size;
840 
841 			if (pattern->spec)
842 				memcpy(ipv6_hdr_buf + offset, pattern->spec, pattern->size);
843 			if (pattern->mask)
844 				memcpy(ipv6_hdr_mask + offset, pattern->mask, pattern->size);
845 			break;
846 		}
847 
848 		pattern++;
849 		pattern = npc_parse_skip_void_and_any_items(pattern);
850 	}
851 
852 	memset(hw_mask, 0, sizeof(hw_mask));
853 
854 	parse_info.hw_mask = &hw_mask;
855 	npc_get_hw_supp_mask(pst, &parse_info, lid, ltype);
856 
857 	rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
858 	if (!rc)
859 		return NPC_ERR_INVALID_MASK;
860 
861 	rc = npc_update_parse_state(pst, &parse_info, lid, ltype, flags);
862 	if (rc)
863 		return rc;
864 
865 	if (pst->npc->hash_extract_cap) {
866 		rc = npc_process_ipv6_field_hash(parse_info.spec, parse_info.mask, pst, ltype);
867 		if (rc)
868 			return rc;
869 	}
870 
871 	/* npc_update_parse_state() increments pattern once.
872 	 * Check if additional increment is required.
873 	 */
874 	if (item_count == 2)
875 		pst->pattern++;
876 
877 	return 0;
878 }
879 
880 int
npc_parse_lc(struct npc_parse_state * pst)881 npc_parse_lc(struct npc_parse_state *pst)
882 {
883 	const struct roc_npc_flow_item_raw *raw_spec;
884 	uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
885 	uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
886 	uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
887 	struct npc_parse_item_info info;
888 	int rc, lid, lt, len = 0;
889 	uint8_t flags = 0;
890 
891 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
892 		return npc_parse_mpls(pst, NPC_LID_LC);
893 
894 	info.def_mask = NULL;
895 	info.hw_mask = &hw_mask;
896 	info.spec = NULL;
897 	info.mask = NULL;
898 	info.hw_hdr_len = 0;
899 	lid = NPC_LID_LC;
900 
901 	switch (pst->pattern->type) {
902 	case ROC_NPC_ITEM_TYPE_IPV4:
903 		lt = NPC_LT_LC_IP;
904 		info.len = pst->pattern->size;
905 		break;
906 	case ROC_NPC_ITEM_TYPE_IPV6:
907 	case ROC_NPC_ITEM_TYPE_IPV6_EXT:
908 	case ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT:
909 	case ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT:
910 		return npc_process_ipv6_item(pst);
911 	case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
912 		lt = NPC_LT_LC_ARP;
913 		info.len = pst->pattern->size;
914 		break;
915 	case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
916 		lt = NPC_LT_LC_CUSTOM0;
917 		info.len = pst->pattern->size;
918 		break;
919 	case ROC_NPC_ITEM_TYPE_RAW:
920 		raw_spec = pst->pattern->spec;
921 		if (!raw_spec->relative)
922 			return 0;
923 
924 		len = raw_spec->length + raw_spec->offset;
925 		if (len > NPC_MAX_RAW_ITEM_LEN)
926 			return -EINVAL;
927 
928 		npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
929 						  pst->pattern->spec,
930 					  (const struct roc_npc_flow_item_raw *)
931 						  pst->pattern->mask,
932 					  &info, raw_spec_buf, raw_mask_buf);
933 
934 		lid = NPC_LID_LC;
935 		lt = NPC_LT_LC_NGIO;
936 		info.hw_mask = &hw_mask;
937 		npc_get_hw_supp_mask(pst, &info, lid, lt);
938 		break;
939 	default:
940 		/* No match at this layer */
941 		return 0;
942 	}
943 
944 	/* Identify if IP tunnels MPLS or IPv4/v6 */
945 	npc_check_lc_ip_tunnel(pst);
946 
947 	npc_get_hw_supp_mask(pst, &info, lid, lt);
948 	rc = npc_parse_item_basic(pst->pattern, &info);
949 
950 	if (rc != 0)
951 		return rc;
952 
953 	return npc_update_parse_state(pst, &info, lid, lt, flags);
954 }
955 
956 int
npc_parse_ld(struct npc_parse_state * pst)957 npc_parse_ld(struct npc_parse_state *pst)
958 {
959 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
960 	struct npc_parse_item_info info;
961 	int lid, lt, lflags;
962 	int rc;
963 
964 	if (pst->tunnel) {
965 		/* We have already parsed MPLS or IPv4/v6 followed
966 		 * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
967 		 * would be parsed as tunneled versions. Skip
968 		 * this layer, except for tunneled MPLS. If LC is
969 		 * MPLS, we have anyway skipped all stacked MPLS
970 		 * labels.
971 		 */
972 		if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
973 			return npc_parse_mpls(pst, NPC_LID_LD);
974 		return 0;
975 	}
976 	info.def_mask = NULL;
977 	info.hw_mask = &hw_mask;
978 	info.spec = NULL;
979 	info.mask = NULL;
980 	info.len = 0;
981 	info.hw_hdr_len = 0;
982 
983 	lid = NPC_LID_LD;
984 	lflags = 0;
985 
986 	switch (pst->pattern->type) {
987 	case ROC_NPC_ITEM_TYPE_ICMP:
988 		if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
989 			lt = NPC_LT_LD_ICMP6;
990 		else
991 			lt = NPC_LT_LD_ICMP;
992 		info.len = pst->pattern->size;
993 		break;
994 	case ROC_NPC_ITEM_TYPE_UDP:
995 		lt = NPC_LT_LD_UDP;
996 		info.len = pst->pattern->size;
997 		break;
998 	case ROC_NPC_ITEM_TYPE_IGMP:
999 		lt = NPC_LT_LD_IGMP;
1000 		info.len = pst->pattern->size;
1001 		break;
1002 	case ROC_NPC_ITEM_TYPE_TCP:
1003 		lt = NPC_LT_LD_TCP;
1004 		info.len = pst->pattern->size;
1005 		break;
1006 	case ROC_NPC_ITEM_TYPE_SCTP:
1007 		lt = NPC_LT_LD_SCTP;
1008 		info.len = pst->pattern->size;
1009 		break;
1010 	case ROC_NPC_ITEM_TYPE_GRE:
1011 		lt = NPC_LT_LD_GRE;
1012 		info.len = pst->pattern->size;
1013 		pst->tunnel = 1;
1014 		break;
1015 	case ROC_NPC_ITEM_TYPE_GRE_KEY:
1016 		lt = NPC_LT_LD_GRE;
1017 		info.len = pst->pattern->size;
1018 		info.hw_hdr_len = 4;
1019 		pst->tunnel = 1;
1020 		break;
1021 	case ROC_NPC_ITEM_TYPE_NVGRE:
1022 		lt = NPC_LT_LD_NVGRE;
1023 		lflags = NPC_F_GRE_NVGRE;
1024 		info.len = pst->pattern->size;
1025 		/* Further IP/Ethernet are parsed as tunneled */
1026 		pst->tunnel = 1;
1027 		break;
1028 	default:
1029 		return 0;
1030 	}
1031 
1032 	npc_get_hw_supp_mask(pst, &info, lid, lt);
1033 	rc = npc_parse_item_basic(pst->pattern, &info);
1034 	if (rc != 0)
1035 		return rc;
1036 
1037 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
1038 }
1039 
1040 int
npc_parse_le(struct npc_parse_state * pst)1041 npc_parse_le(struct npc_parse_state *pst)
1042 {
1043 	const struct roc_npc_item_info *pattern = pst->pattern;
1044 	const struct roc_npc_item_esp_hdr *esp = NULL;
1045 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1046 	struct npc_parse_item_info info;
1047 	int lid, lt, lflags;
1048 	int rc;
1049 
1050 	if (pst->tunnel)
1051 		return 0;
1052 
1053 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
1054 		return npc_parse_mpls(pst, NPC_LID_LE);
1055 
1056 	info.spec = NULL;
1057 	info.mask = NULL;
1058 	info.hw_mask = NULL;
1059 	info.def_mask = NULL;
1060 	info.len = 0;
1061 	info.hw_hdr_len = 0;
1062 	lid = NPC_LID_LE;
1063 	lflags = 0;
1064 
1065 	/* Ensure we are not matching anything in UDP */
1066 	rc = npc_parse_item_basic(pattern, &info);
1067 	if (rc)
1068 		return rc;
1069 
1070 	info.hw_mask = &hw_mask;
1071 	pattern = npc_parse_skip_void_and_any_items(pattern);
1072 	switch (pattern->type) {
1073 	case ROC_NPC_ITEM_TYPE_VXLAN:
1074 		lflags = NPC_F_UDP_VXLAN;
1075 		info.len = pattern->size;
1076 		lt = NPC_LT_LE_VXLAN;
1077 		break;
1078 	case ROC_NPC_ITEM_TYPE_GTPC:
1079 		lflags = NPC_F_UDP_GTP_GTPC;
1080 		info.len = pattern->size;
1081 		lt = NPC_LT_LE_GTPC;
1082 		break;
1083 	case ROC_NPC_ITEM_TYPE_GTPU:
1084 		lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
1085 		info.len = pattern->size;
1086 		lt = NPC_LT_LE_GTPU;
1087 		break;
1088 	case ROC_NPC_ITEM_TYPE_GENEVE:
1089 		lflags = NPC_F_UDP_GENEVE;
1090 		info.len = pattern->size;
1091 		lt = NPC_LT_LE_GENEVE;
1092 		break;
1093 	case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
1094 		lflags = NPC_F_UDP_VXLANGPE;
1095 		info.len = pattern->size;
1096 		lt = NPC_LT_LE_VXLANGPE;
1097 		break;
1098 	case ROC_NPC_ITEM_TYPE_ESP:
1099 		lt = NPC_LT_LE_ESP;
1100 		info.len = pst->pattern->size;
1101 		esp = (const struct roc_npc_item_esp_hdr *)pattern->spec;
1102 		if (esp)
1103 			pst->flow->spi_to_sa_info.spi = esp->spi;
1104 		break;
1105 	default:
1106 		return 0;
1107 	}
1108 
1109 	pst->tunnel = 1;
1110 
1111 	npc_get_hw_supp_mask(pst, &info, lid, lt);
1112 	rc = npc_parse_item_basic(pattern, &info);
1113 	if (rc != 0)
1114 		return rc;
1115 
1116 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
1117 }
1118 
1119 int
npc_parse_lf(struct npc_parse_state * pst)1120 npc_parse_lf(struct npc_parse_state *pst)
1121 {
1122 	const struct roc_npc_item_info *pattern, *last_pattern;
1123 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1124 	const struct roc_npc_flow_item_eth *eth_item;
1125 	struct npc_parse_item_info info;
1126 	int lid, lt, lflags;
1127 	int nr_vlans = 0;
1128 	int rc;
1129 
1130 	/* We hit this layer if there is a tunneling protocol */
1131 	if (!pst->tunnel)
1132 		return 0;
1133 
1134 	if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
1135 		return 0;
1136 
1137 	lid = NPC_LID_LF;
1138 	lt = NPC_LT_LF_TU_ETHER;
1139 	lflags = 0;
1140 
1141 	eth_item = pst->pattern->spec;
1142 
1143 	/* No match support for vlan tags */
1144 	info.def_mask = NULL;
1145 	info.hw_mask = NULL;
1146 	info.len = sizeof(eth_item->hdr);
1147 	info.spec = NULL;
1148 	info.mask = NULL;
1149 	info.hw_hdr_len = 0;
1150 
1151 	/* Look ahead and find out any VLAN tags. These can be
1152 	 * detected but no data matching is available.
1153 	 */
1154 	last_pattern = pst->pattern;
1155 	pattern = pst->pattern + 1;
1156 	pattern = npc_parse_skip_void_and_any_items(pattern);
1157 	while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
1158 		nr_vlans++;
1159 		last_pattern = pattern;
1160 		pattern++;
1161 		pattern = npc_parse_skip_void_and_any_items(pattern);
1162 	}
1163 	switch (nr_vlans) {
1164 	case 0:
1165 		break;
1166 	case 1:
1167 		lflags = NPC_F_TU_ETHER_CTAG;
1168 		break;
1169 	case 2:
1170 		lflags = NPC_F_TU_ETHER_STAG_CTAG;
1171 		break;
1172 	default:
1173 		return NPC_ERR_PATTERN_NOTSUP;
1174 	}
1175 
1176 	info.hw_mask = &hw_mask;
1177 	info.len = sizeof(eth_item->hdr);
1178 	info.hw_hdr_len = 0;
1179 	npc_get_hw_supp_mask(pst, &info, lid, lt);
1180 	info.spec = NULL;
1181 	info.mask = NULL;
1182 
1183 	if (eth_item && eth_item->has_vlan)
1184 		pst->set_vlan_ltype_mask = true;
1185 
1186 	rc = npc_parse_item_basic(pst->pattern, &info);
1187 	if (rc != 0)
1188 		return rc;
1189 
1190 	pst->pattern = last_pattern;
1191 
1192 	return npc_update_parse_state(pst, &info, lid, lt, lflags);
1193 }
1194 
1195 int
npc_parse_lg(struct npc_parse_state * pst)1196 npc_parse_lg(struct npc_parse_state *pst)
1197 {
1198 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1199 	struct npc_parse_item_info info;
1200 	int lid, lt;
1201 	int rc;
1202 
1203 	if (!pst->tunnel)
1204 		return 0;
1205 
1206 	info.def_mask = NULL;
1207 	info.hw_mask = &hw_mask;
1208 	info.spec = NULL;
1209 	info.mask = NULL;
1210 	info.hw_hdr_len = 0;
1211 	lid = NPC_LID_LG;
1212 
1213 	if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
1214 		lt = NPC_LT_LG_TU_IP;
1215 		info.len = pst->pattern->size;
1216 	} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
1217 		lt = NPC_LT_LG_TU_IP6;
1218 		info.len = pst->pattern->size;
1219 	} else {
1220 		/* There is no tunneled IP header */
1221 		return 0;
1222 	}
1223 
1224 	npc_get_hw_supp_mask(pst, &info, lid, lt);
1225 	rc = npc_parse_item_basic(pst->pattern, &info);
1226 	if (rc != 0)
1227 		return rc;
1228 
1229 	return npc_update_parse_state(pst, &info, lid, lt, 0);
1230 }
1231 
1232 int
npc_parse_lh(struct npc_parse_state * pst)1233 npc_parse_lh(struct npc_parse_state *pst)
1234 {
1235 	char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
1236 	struct npc_parse_item_info info;
1237 	int lid, lt;
1238 	int rc;
1239 
1240 	if (!pst->tunnel)
1241 		return 0;
1242 
1243 	info.def_mask = NULL;
1244 	info.hw_mask = &hw_mask;
1245 	info.spec = NULL;
1246 	info.mask = NULL;
1247 	info.hw_hdr_len = 0;
1248 	lid = NPC_LID_LH;
1249 
1250 	switch (pst->pattern->type) {
1251 	case ROC_NPC_ITEM_TYPE_UDP:
1252 		lt = NPC_LT_LH_TU_UDP;
1253 		info.len = pst->pattern->size;
1254 		break;
1255 	case ROC_NPC_ITEM_TYPE_TCP:
1256 		lt = NPC_LT_LH_TU_TCP;
1257 		info.len = pst->pattern->size;
1258 		break;
1259 	case ROC_NPC_ITEM_TYPE_SCTP:
1260 		lt = NPC_LT_LH_TU_SCTP;
1261 		info.len = pst->pattern->size;
1262 		break;
1263 	case ROC_NPC_ITEM_TYPE_ESP:
1264 		lt = NPC_LT_LH_TU_ESP;
1265 		info.len = pst->pattern->size;
1266 		break;
1267 	default:
1268 		return 0;
1269 	}
1270 
1271 	npc_get_hw_supp_mask(pst, &info, lid, lt);
1272 	rc = npc_parse_item_basic(pst->pattern, &info);
1273 	if (rc != 0)
1274 		return rc;
1275 
1276 	return npc_update_parse_state(pst, &info, lid, lt, 0);
1277 }
1278