common/cnxk: fix log level during MCAM allocation
[dpdk.git] / drivers / common / cnxk / roc_npc_parse.c
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                 if (ipv6_spec) {
566                         rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
567                         if (rc)
568                                 return rc;
569                 }
570                 info.len = sizeof(ipv6_spec->hdr);
571                 break;
572         case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
573                 lt = NPC_LT_LC_ARP;
574                 info.len = pst->pattern->size;
575                 break;
576         case ROC_NPC_ITEM_TYPE_IPV6_EXT:
577                 lid = NPC_LID_LC;
578                 lt = NPC_LT_LC_IP6_EXT;
579                 info.len = pst->pattern->size;
580                 info.hw_hdr_len = 40;
581                 break;
582         case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
583                 lt = NPC_LT_LC_CUSTOM0;
584                 info.len = pst->pattern->size;
585                 break;
586         case ROC_NPC_ITEM_TYPE_RAW:
587                 raw_spec = pst->pattern->spec;
588                 if (!raw_spec->relative)
589                         return 0;
590
591                 len = raw_spec->length + raw_spec->offset;
592                 if (len > NPC_MAX_RAW_ITEM_LEN)
593                         return -EINVAL;
594
595                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
596                                                   pst->pattern->spec,
597                                           (const struct roc_npc_flow_item_raw *)
598                                                   pst->pattern->mask,
599                                           &info, raw_spec_buf, raw_mask_buf);
600
601                 lid = NPC_LID_LC;
602                 lt = NPC_LT_LC_NGIO;
603                 info.hw_mask = &hw_mask;
604                 npc_get_hw_supp_mask(pst, &info, lid, lt);
605                 break;
606         default:
607                 /* No match at this layer */
608                 return 0;
609         }
610
611         /* Identify if IP tunnels MPLS or IPv4/v6 */
612         npc_check_lc_ip_tunnel(pst);
613
614         npc_get_hw_supp_mask(pst, &info, lid, lt);
615         rc = npc_parse_item_basic(pst->pattern, &info);
616
617         if (rc != 0)
618                 return rc;
619
620         return npc_update_parse_state(pst, &info, lid, lt, flags);
621 }
622
623 int
624 npc_parse_ld(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, lflags;
629         int rc;
630
631         if (pst->tunnel) {
632                 /* We have already parsed MPLS or IPv4/v6 followed
633                  * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
634                  * would be parsed as tunneled versions. Skip
635                  * this layer, except for tunneled MPLS. If LC is
636                  * MPLS, we have anyway skipped all stacked MPLS
637                  * labels.
638                  */
639                 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
640                         return npc_parse_mpls(pst, NPC_LID_LD);
641                 return 0;
642         }
643         info.hw_mask = &hw_mask;
644         info.spec = NULL;
645         info.mask = NULL;
646         info.def_mask = NULL;
647         info.len = 0;
648         info.hw_hdr_len = 0;
649
650         lid = NPC_LID_LD;
651         lflags = 0;
652
653         switch (pst->pattern->type) {
654         case ROC_NPC_ITEM_TYPE_ICMP:
655                 if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
656                         lt = NPC_LT_LD_ICMP6;
657                 else
658                         lt = NPC_LT_LD_ICMP;
659                 info.len = pst->pattern->size;
660                 break;
661         case ROC_NPC_ITEM_TYPE_UDP:
662                 lt = NPC_LT_LD_UDP;
663                 info.len = pst->pattern->size;
664                 break;
665         case ROC_NPC_ITEM_TYPE_IGMP:
666                 lt = NPC_LT_LD_IGMP;
667                 info.len = pst->pattern->size;
668                 break;
669         case ROC_NPC_ITEM_TYPE_TCP:
670                 lt = NPC_LT_LD_TCP;
671                 info.len = pst->pattern->size;
672                 break;
673         case ROC_NPC_ITEM_TYPE_SCTP:
674                 lt = NPC_LT_LD_SCTP;
675                 info.len = pst->pattern->size;
676                 break;
677         case ROC_NPC_ITEM_TYPE_GRE:
678                 lt = NPC_LT_LD_GRE;
679                 info.len = pst->pattern->size;
680                 break;
681         case ROC_NPC_ITEM_TYPE_GRE_KEY:
682                 lt = NPC_LT_LD_GRE;
683                 info.len = pst->pattern->size;
684                 info.hw_hdr_len = 4;
685                 break;
686         case ROC_NPC_ITEM_TYPE_NVGRE:
687                 lt = NPC_LT_LD_NVGRE;
688                 lflags = NPC_F_GRE_NVGRE;
689                 info.len = pst->pattern->size;
690                 /* Further IP/Ethernet are parsed as tunneled */
691                 pst->tunnel = 1;
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, lflags);
703 }
704
705 int
706 npc_parse_le(struct npc_parse_state *pst)
707 {
708         const struct roc_npc_item_info *pattern = pst->pattern;
709         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
710         struct npc_parse_item_info info;
711         int lid, lt, lflags;
712         int rc;
713
714         if (pst->tunnel)
715                 return 0;
716
717         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
718                 return npc_parse_mpls(pst, NPC_LID_LE);
719
720         info.spec = NULL;
721         info.mask = NULL;
722         info.hw_mask = NULL;
723         info.def_mask = NULL;
724         info.len = 0;
725         info.hw_hdr_len = 0;
726         lid = NPC_LID_LE;
727         lflags = 0;
728
729         /* Ensure we are not matching anything in UDP */
730         rc = npc_parse_item_basic(pattern, &info);
731         if (rc)
732                 return rc;
733
734         info.hw_mask = &hw_mask;
735         pattern = npc_parse_skip_void_and_any_items(pattern);
736         switch (pattern->type) {
737         case ROC_NPC_ITEM_TYPE_VXLAN:
738                 lflags = NPC_F_UDP_VXLAN;
739                 info.len = pattern->size;
740                 lt = NPC_LT_LE_VXLAN;
741                 break;
742         case ROC_NPC_ITEM_TYPE_GTPC:
743                 lflags = NPC_F_UDP_GTP_GTPC;
744                 info.len = pattern->size;
745                 lt = NPC_LT_LE_GTPC;
746                 break;
747         case ROC_NPC_ITEM_TYPE_GTPU:
748                 lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
749                 info.len = pattern->size;
750                 lt = NPC_LT_LE_GTPU;
751                 break;
752         case ROC_NPC_ITEM_TYPE_GENEVE:
753                 lflags = NPC_F_UDP_GENEVE;
754                 info.len = pattern->size;
755                 lt = NPC_LT_LE_GENEVE;
756                 break;
757         case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
758                 lflags = NPC_F_UDP_VXLANGPE;
759                 info.len = pattern->size;
760                 lt = NPC_LT_LE_VXLANGPE;
761                 break;
762         case ROC_NPC_ITEM_TYPE_ESP:
763                 lt = NPC_LT_LE_ESP;
764                 info.len = pst->pattern->size;
765                 break;
766         default:
767                 return 0;
768         }
769
770         pst->tunnel = 1;
771
772         npc_get_hw_supp_mask(pst, &info, lid, lt);
773         rc = npc_parse_item_basic(pattern, &info);
774         if (rc != 0)
775                 return rc;
776
777         return npc_update_parse_state(pst, &info, lid, lt, lflags);
778 }
779
780 int
781 npc_parse_lf(struct npc_parse_state *pst)
782 {
783         const struct roc_npc_item_info *pattern, *last_pattern;
784         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
785         struct npc_parse_item_info info;
786         int lid, lt, lflags;
787         int nr_vlans = 0;
788         int rc;
789
790         /* We hit this layer if there is a tunneling protocol */
791         if (!pst->tunnel)
792                 return 0;
793
794         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
795                 return 0;
796
797         lid = NPC_LID_LF;
798         lt = NPC_LT_LF_TU_ETHER;
799         lflags = 0;
800
801         /* No match support for vlan tags */
802         info.hw_mask = NULL;
803         info.len = pst->pattern->size;
804         info.spec = NULL;
805         info.mask = NULL;
806         info.hw_hdr_len = 0;
807
808         /* Look ahead and find out any VLAN tags. These can be
809          * detected but no data matching is available.
810          */
811         last_pattern = pst->pattern;
812         pattern = pst->pattern + 1;
813         pattern = npc_parse_skip_void_and_any_items(pattern);
814         while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
815                 nr_vlans++;
816                 last_pattern = pattern;
817                 pattern++;
818                 pattern = npc_parse_skip_void_and_any_items(pattern);
819         }
820         switch (nr_vlans) {
821         case 0:
822                 break;
823         case 1:
824                 lflags = NPC_F_TU_ETHER_CTAG;
825                 break;
826         case 2:
827                 lflags = NPC_F_TU_ETHER_STAG_CTAG;
828                 break;
829         default:
830                 return NPC_ERR_PATTERN_NOTSUP;
831         }
832
833         info.hw_mask = &hw_mask;
834         info.len = pst->pattern->size;
835         info.hw_hdr_len = 0;
836         npc_get_hw_supp_mask(pst, &info, lid, lt);
837         info.spec = NULL;
838         info.mask = NULL;
839
840         rc = npc_parse_item_basic(pst->pattern, &info);
841         if (rc != 0)
842                 return rc;
843
844         pst->pattern = last_pattern;
845
846         return npc_update_parse_state(pst, &info, lid, lt, lflags);
847 }
848
849 int
850 npc_parse_lg(struct npc_parse_state *pst)
851 {
852         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
853         struct npc_parse_item_info info;
854         int lid, lt;
855         int rc;
856
857         if (!pst->tunnel)
858                 return 0;
859
860         info.hw_mask = &hw_mask;
861         info.spec = NULL;
862         info.mask = NULL;
863         info.hw_hdr_len = 0;
864         lid = NPC_LID_LG;
865
866         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
867                 lt = NPC_LT_LG_TU_IP;
868                 info.len = pst->pattern->size;
869         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
870                 lt = NPC_LT_LG_TU_IP6;
871                 info.len = pst->pattern->size;
872         } else {
873                 /* There is no tunneled IP header */
874                 return 0;
875         }
876
877         npc_get_hw_supp_mask(pst, &info, lid, lt);
878         rc = npc_parse_item_basic(pst->pattern, &info);
879         if (rc != 0)
880                 return rc;
881
882         return npc_update_parse_state(pst, &info, lid, lt, 0);
883 }
884
885 int
886 npc_parse_lh(struct npc_parse_state *pst)
887 {
888         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
889         struct npc_parse_item_info info;
890         int lid, lt;
891         int rc;
892
893         if (!pst->tunnel)
894                 return 0;
895
896         info.hw_mask = &hw_mask;
897         info.spec = NULL;
898         info.mask = NULL;
899         info.hw_hdr_len = 0;
900         lid = NPC_LID_LH;
901
902         switch (pst->pattern->type) {
903         case ROC_NPC_ITEM_TYPE_UDP:
904                 lt = NPC_LT_LH_TU_UDP;
905                 info.len = pst->pattern->size;
906                 break;
907         case ROC_NPC_ITEM_TYPE_TCP:
908                 lt = NPC_LT_LH_TU_TCP;
909                 info.len = pst->pattern->size;
910                 break;
911         case ROC_NPC_ITEM_TYPE_SCTP:
912                 lt = NPC_LT_LH_TU_SCTP;
913                 info.len = pst->pattern->size;
914                 break;
915         case ROC_NPC_ITEM_TYPE_ESP:
916                 lt = NPC_LT_LH_TU_ESP;
917                 info.len = pst->pattern->size;
918                 break;
919         default:
920                 return 0;
921         }
922
923         npc_get_hw_supp_mask(pst, &info, lid, lt);
924         rc = npc_parse_item_basic(pst->pattern, &info);
925         if (rc != 0)
926                 return rc;
927
928         return npc_update_parse_state(pst, &info, lid, lt, 0);
929 }