common/cnxk: support CPT second pass flow rules
[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 int
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
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
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
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
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
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
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                 vlan_item[0] = pst->pattern->spec;
355                 info.hw_mask = NULL;
356                 info.len = sizeof(vlan_item[0]->hdr);
357                 lt = NPC_LT_LB_STAG_QINQ;
358                 lflags = NPC_F_STAG_CTAG;
359                 if (vlan_item[0] && vlan_item[0]->has_more_vlan) {
360                         lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
361                                  NPC_F_LB_L_WITH_QINQ_QINQ;
362                 }
363         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
364                 raw_spec = pst->pattern->spec;
365                 if (raw_spec->relative)
366                         return 0;
367                 len = raw_spec->length + raw_spec->offset;
368                 if (len > NPC_MAX_RAW_ITEM_LEN)
369                         return -EINVAL;
370
371                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
372                         lt = NPC_LT_LB_VLAN_EXDSA;
373                 } else if (pst->npc->switch_header_type ==
374                            ROC_PRIV_FLAGS_EXDSA) {
375                         lt = NPC_LT_LB_EXDSA;
376                 } else {
377                         return -EINVAL;
378                 }
379
380                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
381                                                   pst->pattern->spec,
382                                           (const struct roc_npc_flow_item_raw *)
383                                                   pst->pattern->mask,
384                                           &info, raw_spec_buf, raw_mask_buf);
385
386                 info.hw_hdr_len = 0;
387         } else {
388                 return 0;
389         }
390
391         info.hw_mask = &hw_mask;
392         npc_get_hw_supp_mask(pst, &info, lid, lt);
393
394         rc = npc_parse_item_basic(pst->pattern, &info);
395         if (rc != 0)
396                 return rc;
397
398         /* Point pattern to last item consumed */
399         pst->pattern = last_pattern;
400         return npc_update_parse_state(pst, &info, lid, lt, lflags);
401 }
402
403 static int
404 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
405 {
406         uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
407                                NPC_F_MPLS_4_LABELS};
408         const struct roc_npc_item_info *pattern = pst->pattern;
409         struct npc_parse_item_info info;
410         int nr_labels = 0;
411         int rc;
412
413         /*
414          * pst->pattern points to first MPLS label. We only check
415          * that subsequent labels do not have anything to match.
416          */
417         info.def_mask = NULL;
418         info.hw_mask = NULL;
419         info.len = pattern->size;
420         info.spec = NULL;
421         info.mask = NULL;
422         info.hw_hdr_len = 0;
423
424         while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
425                 nr_labels++;
426
427                 /* Basic validation of Second/Third/Fourth mpls item */
428                 if (nr_labels > 1) {
429                         rc = npc_parse_item_basic(pattern, &info);
430                         if (rc != 0)
431                                 return rc;
432                 }
433                 pst->last_pattern = pattern;
434                 pattern++;
435                 pattern = npc_parse_skip_void_and_any_items(pattern);
436         }
437
438         if (nr_labels < 1 || nr_labels > 4)
439                 return NPC_ERR_PATTERN_NOTSUP;
440
441         *flag = flag_list[nr_labels - 1];
442         return 0;
443 }
444
445 static int
446 npc_parse_mpls(struct npc_parse_state *pst, int lid)
447 {
448         /* Find number of MPLS labels */
449         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
450         struct npc_parse_item_info info;
451         int lt, lflags;
452         int rc;
453
454         lflags = 0;
455
456         if (lid == NPC_LID_LC)
457                 lt = NPC_LT_LC_MPLS;
458         else if (lid == NPC_LID_LD)
459                 lt = NPC_LT_LD_TU_MPLS_IN_IP;
460         else
461                 lt = NPC_LT_LE_TU_MPLS_IN_UDP;
462
463         /* Prepare for parsing the first item */
464         info.hw_mask = &hw_mask;
465         info.len = pst->pattern->size;
466         info.spec = NULL;
467         info.mask = NULL;
468         info.def_mask = NULL;
469         info.hw_hdr_len = 0;
470
471         npc_get_hw_supp_mask(pst, &info, lid, lt);
472         rc = npc_parse_item_basic(pst->pattern, &info);
473         if (rc != 0)
474                 return rc;
475
476         /*
477          * Parse for more labels.
478          * This sets lflags and pst->last_pattern correctly.
479          */
480         rc = npc_parse_mpls_label_stack(pst, &lflags);
481         if (rc != 0)
482                 return rc;
483
484         pst->tunnel = 1;
485         pst->pattern = pst->last_pattern;
486
487         return npc_update_parse_state(pst, &info, lid, lt, lflags);
488 }
489
490 static inline void
491 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
492 {
493         const struct roc_npc_item_info *pattern = pst->pattern + 1;
494
495         pattern = npc_parse_skip_void_and_any_items(pattern);
496         if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
497             pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
498             pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
499                 pst->tunnel = 1;
500 }
501
502 static int
503 npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
504                         struct npc_parse_state *pst, uint8_t *flags)
505 {
506         int flags_count = 0;
507
508         if (ipv6_spec->has_hop_ext) {
509                 *flags = NPC_F_LC_L_EXT_HOP;
510                 flags_count++;
511         }
512         if (ipv6_spec->has_route_ext) {
513                 *flags = NPC_F_LC_L_EXT_ROUT;
514                 flags_count++;
515         }
516         if (ipv6_spec->has_frag_ext) {
517                 *flags = NPC_F_LC_U_IP6_FRAG;
518                 flags_count++;
519         }
520         if (ipv6_spec->has_dest_ext) {
521                 *flags = NPC_F_LC_L_EXT_DEST;
522                 flags_count++;
523         }
524         if (ipv6_spec->has_mobil_ext) {
525                 *flags = NPC_F_LC_L_EXT_MOBILITY;
526                 flags_count++;
527         }
528         if (ipv6_spec->has_hip_ext) {
529                 *flags = NPC_F_LC_L_EXT_HOSTID;
530                 flags_count++;
531         }
532         if (ipv6_spec->has_shim6_ext) {
533                 *flags = NPC_F_LC_L_EXT_SHIM6;
534                 flags_count++;
535         }
536         if (ipv6_spec->has_auth_ext) {
537                 pst->lt[NPC_LID_LD] = NPC_LT_LD_AH;
538                 flags_count++;
539         }
540         if (ipv6_spec->has_esp_ext) {
541                 pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP;
542                 flags_count++;
543         }
544
545         if (flags_count > 1)
546                 return -EINVAL;
547
548         if (flags_count)
549                 pst->set_ipv6ext_ltype_mask = true;
550
551         return 0;
552 }
553
554 int
555 npc_parse_lc(struct npc_parse_state *pst)
556 {
557         const struct roc_npc_flow_item_ipv6 *ipv6_spec;
558         const struct roc_npc_flow_item_raw *raw_spec;
559         uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
560         uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
561         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
562         struct npc_parse_item_info info;
563         int rc, lid, lt, len = 0;
564         uint8_t flags = 0;
565
566         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
567                 return npc_parse_mpls(pst, NPC_LID_LC);
568
569         info.def_mask = NULL;
570         info.hw_mask = &hw_mask;
571         info.spec = NULL;
572         info.mask = NULL;
573         info.hw_hdr_len = 0;
574         lid = NPC_LID_LC;
575
576         switch (pst->pattern->type) {
577         case ROC_NPC_ITEM_TYPE_IPV4:
578                 lt = NPC_LT_LC_IP;
579                 info.len = pst->pattern->size;
580                 break;
581         case ROC_NPC_ITEM_TYPE_IPV6:
582                 ipv6_spec = pst->pattern->spec;
583                 lid = NPC_LID_LC;
584                 lt = NPC_LT_LC_IP6;
585                 if (ipv6_spec) {
586                         rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
587                         if (rc)
588                                 return rc;
589                 }
590                 info.len = sizeof(ipv6_spec->hdr);
591                 break;
592         case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
593                 lt = NPC_LT_LC_ARP;
594                 info.len = pst->pattern->size;
595                 break;
596         case ROC_NPC_ITEM_TYPE_IPV6_EXT:
597                 lid = NPC_LID_LC;
598                 lt = NPC_LT_LC_IP6_EXT;
599                 info.len = pst->pattern->size;
600                 info.hw_hdr_len = 40;
601                 break;
602         case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
603                 lt = NPC_LT_LC_CUSTOM0;
604                 info.len = pst->pattern->size;
605                 break;
606         case ROC_NPC_ITEM_TYPE_RAW:
607                 raw_spec = pst->pattern->spec;
608                 if (!raw_spec->relative)
609                         return 0;
610
611                 len = raw_spec->length + raw_spec->offset;
612                 if (len > NPC_MAX_RAW_ITEM_LEN)
613                         return -EINVAL;
614
615                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
616                                                   pst->pattern->spec,
617                                           (const struct roc_npc_flow_item_raw *)
618                                                   pst->pattern->mask,
619                                           &info, raw_spec_buf, raw_mask_buf);
620
621                 lid = NPC_LID_LC;
622                 lt = NPC_LT_LC_NGIO;
623                 info.hw_mask = &hw_mask;
624                 npc_get_hw_supp_mask(pst, &info, lid, lt);
625                 break;
626         default:
627                 /* No match at this layer */
628                 return 0;
629         }
630
631         /* Identify if IP tunnels MPLS or IPv4/v6 */
632         npc_check_lc_ip_tunnel(pst);
633
634         npc_get_hw_supp_mask(pst, &info, lid, lt);
635         rc = npc_parse_item_basic(pst->pattern, &info);
636
637         if (rc != 0)
638                 return rc;
639
640         return npc_update_parse_state(pst, &info, lid, lt, flags);
641 }
642
643 int
644 npc_parse_ld(struct npc_parse_state *pst)
645 {
646         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
647         struct npc_parse_item_info info;
648         int lid, lt, lflags;
649         int rc;
650
651         if (pst->tunnel) {
652                 /* We have already parsed MPLS or IPv4/v6 followed
653                  * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
654                  * would be parsed as tunneled versions. Skip
655                  * this layer, except for tunneled MPLS. If LC is
656                  * MPLS, we have anyway skipped all stacked MPLS
657                  * labels.
658                  */
659                 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
660                         return npc_parse_mpls(pst, NPC_LID_LD);
661                 return 0;
662         }
663         info.def_mask = NULL;
664         info.hw_mask = &hw_mask;
665         info.spec = NULL;
666         info.mask = NULL;
667         info.len = 0;
668         info.hw_hdr_len = 0;
669
670         lid = NPC_LID_LD;
671         lflags = 0;
672
673         switch (pst->pattern->type) {
674         case ROC_NPC_ITEM_TYPE_ICMP:
675                 if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
676                         lt = NPC_LT_LD_ICMP6;
677                 else
678                         lt = NPC_LT_LD_ICMP;
679                 info.len = pst->pattern->size;
680                 break;
681         case ROC_NPC_ITEM_TYPE_UDP:
682                 lt = NPC_LT_LD_UDP;
683                 info.len = pst->pattern->size;
684                 break;
685         case ROC_NPC_ITEM_TYPE_IGMP:
686                 lt = NPC_LT_LD_IGMP;
687                 info.len = pst->pattern->size;
688                 break;
689         case ROC_NPC_ITEM_TYPE_TCP:
690                 lt = NPC_LT_LD_TCP;
691                 info.len = pst->pattern->size;
692                 break;
693         case ROC_NPC_ITEM_TYPE_SCTP:
694                 lt = NPC_LT_LD_SCTP;
695                 info.len = pst->pattern->size;
696                 break;
697         case ROC_NPC_ITEM_TYPE_GRE:
698                 lt = NPC_LT_LD_GRE;
699                 info.len = pst->pattern->size;
700                 break;
701         case ROC_NPC_ITEM_TYPE_GRE_KEY:
702                 lt = NPC_LT_LD_GRE;
703                 info.len = pst->pattern->size;
704                 info.hw_hdr_len = 4;
705                 break;
706         case ROC_NPC_ITEM_TYPE_NVGRE:
707                 lt = NPC_LT_LD_NVGRE;
708                 lflags = NPC_F_GRE_NVGRE;
709                 info.len = pst->pattern->size;
710                 /* Further IP/Ethernet are parsed as tunneled */
711                 pst->tunnel = 1;
712                 break;
713         default:
714                 return 0;
715         }
716
717         npc_get_hw_supp_mask(pst, &info, lid, lt);
718         rc = npc_parse_item_basic(pst->pattern, &info);
719         if (rc != 0)
720                 return rc;
721
722         return npc_update_parse_state(pst, &info, lid, lt, lflags);
723 }
724
725 int
726 npc_parse_le(struct npc_parse_state *pst)
727 {
728         const struct roc_npc_item_info *pattern = pst->pattern;
729         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
730         struct npc_parse_item_info info;
731         int lid, lt, lflags;
732         int rc;
733
734         if (pst->tunnel)
735                 return 0;
736
737         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
738                 return npc_parse_mpls(pst, NPC_LID_LE);
739
740         info.spec = NULL;
741         info.mask = NULL;
742         info.hw_mask = NULL;
743         info.def_mask = NULL;
744         info.len = 0;
745         info.hw_hdr_len = 0;
746         lid = NPC_LID_LE;
747         lflags = 0;
748
749         /* Ensure we are not matching anything in UDP */
750         rc = npc_parse_item_basic(pattern, &info);
751         if (rc)
752                 return rc;
753
754         info.hw_mask = &hw_mask;
755         pattern = npc_parse_skip_void_and_any_items(pattern);
756         switch (pattern->type) {
757         case ROC_NPC_ITEM_TYPE_VXLAN:
758                 lflags = NPC_F_UDP_VXLAN;
759                 info.len = pattern->size;
760                 lt = NPC_LT_LE_VXLAN;
761                 break;
762         case ROC_NPC_ITEM_TYPE_GTPC:
763                 lflags = NPC_F_UDP_GTP_GTPC;
764                 info.len = pattern->size;
765                 lt = NPC_LT_LE_GTPC;
766                 break;
767         case ROC_NPC_ITEM_TYPE_GTPU:
768                 lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
769                 info.len = pattern->size;
770                 lt = NPC_LT_LE_GTPU;
771                 break;
772         case ROC_NPC_ITEM_TYPE_GENEVE:
773                 lflags = NPC_F_UDP_GENEVE;
774                 info.len = pattern->size;
775                 lt = NPC_LT_LE_GENEVE;
776                 break;
777         case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
778                 lflags = NPC_F_UDP_VXLANGPE;
779                 info.len = pattern->size;
780                 lt = NPC_LT_LE_VXLANGPE;
781                 break;
782         case ROC_NPC_ITEM_TYPE_ESP:
783                 lt = NPC_LT_LE_ESP;
784                 info.len = pst->pattern->size;
785                 break;
786         default:
787                 return 0;
788         }
789
790         pst->tunnel = 1;
791
792         npc_get_hw_supp_mask(pst, &info, lid, lt);
793         rc = npc_parse_item_basic(pattern, &info);
794         if (rc != 0)
795                 return rc;
796
797         return npc_update_parse_state(pst, &info, lid, lt, lflags);
798 }
799
800 int
801 npc_parse_lf(struct npc_parse_state *pst)
802 {
803         const struct roc_npc_item_info *pattern, *last_pattern;
804         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
805         struct npc_parse_item_info info;
806         int lid, lt, lflags;
807         int nr_vlans = 0;
808         int rc;
809
810         /* We hit this layer if there is a tunneling protocol */
811         if (!pst->tunnel)
812                 return 0;
813
814         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
815                 return 0;
816
817         lid = NPC_LID_LF;
818         lt = NPC_LT_LF_TU_ETHER;
819         lflags = 0;
820
821         /* No match support for vlan tags */
822         info.def_mask = NULL;
823         info.hw_mask = NULL;
824         info.len = pst->pattern->size;
825         info.spec = NULL;
826         info.mask = NULL;
827         info.hw_hdr_len = 0;
828
829         /* Look ahead and find out any VLAN tags. These can be
830          * detected but no data matching is available.
831          */
832         last_pattern = pst->pattern;
833         pattern = pst->pattern + 1;
834         pattern = npc_parse_skip_void_and_any_items(pattern);
835         while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
836                 nr_vlans++;
837                 last_pattern = pattern;
838                 pattern++;
839                 pattern = npc_parse_skip_void_and_any_items(pattern);
840         }
841         switch (nr_vlans) {
842         case 0:
843                 break;
844         case 1:
845                 lflags = NPC_F_TU_ETHER_CTAG;
846                 break;
847         case 2:
848                 lflags = NPC_F_TU_ETHER_STAG_CTAG;
849                 break;
850         default:
851                 return NPC_ERR_PATTERN_NOTSUP;
852         }
853
854         info.hw_mask = &hw_mask;
855         info.len = pst->pattern->size;
856         info.hw_hdr_len = 0;
857         npc_get_hw_supp_mask(pst, &info, lid, lt);
858         info.spec = NULL;
859         info.mask = NULL;
860
861         rc = npc_parse_item_basic(pst->pattern, &info);
862         if (rc != 0)
863                 return rc;
864
865         pst->pattern = last_pattern;
866
867         return npc_update_parse_state(pst, &info, lid, lt, lflags);
868 }
869
870 int
871 npc_parse_lg(struct npc_parse_state *pst)
872 {
873         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
874         struct npc_parse_item_info info;
875         int lid, lt;
876         int rc;
877
878         if (!pst->tunnel)
879                 return 0;
880
881         info.def_mask = NULL;
882         info.hw_mask = &hw_mask;
883         info.spec = NULL;
884         info.mask = NULL;
885         info.hw_hdr_len = 0;
886         lid = NPC_LID_LG;
887
888         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
889                 lt = NPC_LT_LG_TU_IP;
890                 info.len = pst->pattern->size;
891         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
892                 lt = NPC_LT_LG_TU_IP6;
893                 info.len = pst->pattern->size;
894         } else {
895                 /* There is no tunneled IP header */
896                 return 0;
897         }
898
899         npc_get_hw_supp_mask(pst, &info, lid, lt);
900         rc = npc_parse_item_basic(pst->pattern, &info);
901         if (rc != 0)
902                 return rc;
903
904         return npc_update_parse_state(pst, &info, lid, lt, 0);
905 }
906
907 int
908 npc_parse_lh(struct npc_parse_state *pst)
909 {
910         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
911         struct npc_parse_item_info info;
912         int lid, lt;
913         int rc;
914
915         if (!pst->tunnel)
916                 return 0;
917
918         info.def_mask = NULL;
919         info.hw_mask = &hw_mask;
920         info.spec = NULL;
921         info.mask = NULL;
922         info.hw_hdr_len = 0;
923         lid = NPC_LID_LH;
924
925         switch (pst->pattern->type) {
926         case ROC_NPC_ITEM_TYPE_UDP:
927                 lt = NPC_LT_LH_TU_UDP;
928                 info.len = pst->pattern->size;
929                 break;
930         case ROC_NPC_ITEM_TYPE_TCP:
931                 lt = NPC_LT_LH_TU_TCP;
932                 info.len = pst->pattern->size;
933                 break;
934         case ROC_NPC_ITEM_TYPE_SCTP:
935                 lt = NPC_LT_LH_TU_SCTP;
936                 info.len = pst->pattern->size;
937                 break;
938         case ROC_NPC_ITEM_TYPE_ESP:
939                 lt = NPC_LT_LH_TU_ESP;
940                 info.len = pst->pattern->size;
941                 break;
942         default:
943                 return 0;
944         }
945
946         npc_get_hw_supp_mask(pst, &info, lid, lt);
947         rc = npc_parse_item_basic(pst->pattern, &info);
948         if (rc != 0)
949                 return rc;
950
951         return npc_update_parse_state(pst, &info, lid, lt, 0);
952 }