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