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