common/cnxk: fix uninitialized pointer read
[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.def_mask = NULL;
116         info.hw_mask = &hw_mask;
117         info.len = pst->pattern->size;
118         npc_get_hw_supp_mask(pst, &info, lid, lt);
119         info.spec = NULL;
120         info.mask = NULL;
121
122         /* Basic validation of item parameters */
123         rc = npc_parse_item_basic(pst->pattern, &info);
124         if (rc)
125                 return rc;
126
127         /* Update pst if not validate only? clash check? */
128         return npc_update_parse_state(pst, &info, lid, lt, 0);
129 }
130
131 int
132 npc_parse_higig2_hdr(struct npc_parse_state *pst)
133 {
134         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
135         struct npc_parse_item_info info;
136         int lid, lt;
137         int rc;
138
139         /* Identify the pattern type into lid, lt */
140         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
141                 return 0;
142
143         lid = NPC_LID_LA;
144         lt = NPC_LT_LA_HIGIG2_ETHER;
145         info.hw_hdr_len = 0;
146
147         if (pst->flow->nix_intf == NIX_INTF_TX) {
148                 lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
149                 info.hw_hdr_len = NPC_IH_LENGTH;
150         }
151
152         /* Prepare for parsing the item */
153         info.def_mask = NULL;
154         info.hw_mask = &hw_mask;
155         info.len = pst->pattern->size;
156         npc_get_hw_supp_mask(pst, &info, lid, lt);
157         info.spec = NULL;
158         info.mask = NULL;
159
160         /* Basic validation of item parameters */
161         rc = npc_parse_item_basic(pst->pattern, &info);
162         if (rc)
163                 return rc;
164
165         /* Update pst if not validate only? clash check? */
166         return npc_update_parse_state(pst, &info, lid, lt, 0);
167 }
168
169 int
170 npc_parse_la(struct npc_parse_state *pst)
171 {
172         const struct roc_npc_flow_item_eth *eth_item;
173         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
174         struct npc_parse_item_info info;
175         int lid, lt;
176         int rc;
177
178         /* Identify the pattern type into lid, lt */
179         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
180                 return 0;
181
182         eth_item = pst->pattern->spec;
183
184         lid = NPC_LID_LA;
185         lt = NPC_LT_LA_ETHER;
186         info.hw_hdr_len = 0;
187
188         if (pst->flow->nix_intf == NIX_INTF_TX) {
189                 lt = NPC_LT_LA_IH_NIX_ETHER;
190                 info.hw_hdr_len = NPC_IH_LENGTH;
191                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
192                         lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
193                         info.hw_hdr_len += NPC_HIGIG2_LENGTH;
194                 }
195         } else {
196                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
197                         lt = NPC_LT_LA_HIGIG2_ETHER;
198                         info.hw_hdr_len = NPC_HIGIG2_LENGTH;
199                 }
200         }
201
202         /* Prepare for parsing the item */
203         info.def_mask = NULL;
204         info.hw_mask = &hw_mask;
205         info.len = sizeof(eth_item->hdr);
206         npc_get_hw_supp_mask(pst, &info, lid, lt);
207         info.spec = NULL;
208         info.mask = NULL;
209
210         /* Basic validation of item parameters */
211         rc = npc_parse_item_basic(pst->pattern, &info);
212         if (rc)
213                 return rc;
214
215         rc = npc_update_parse_state(pst, &info, lid, lt, 0);
216         if (rc)
217                 return rc;
218
219         if (eth_item && eth_item->has_vlan)
220                 pst->set_vlan_ltype_mask = true;
221
222         return 0;
223 }
224
225 #define NPC_MAX_SUPPORTED_VLANS 3
226
227 int
228 npc_parse_lb(struct npc_parse_state *pst)
229 {
230         const struct roc_npc_flow_item_vlan *vlan_item[NPC_MAX_SUPPORTED_VLANS];
231         const struct roc_npc_item_info *pattern = pst->pattern;
232         const struct roc_npc_item_info *last_pattern;
233         const struct roc_npc_flow_item_raw *raw_spec;
234         uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
235         uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
236         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
237         struct npc_parse_item_info info;
238         int lid, lt, lflags, len = 0;
239         int nr_vlans = 0;
240         int rc;
241
242         info.def_mask = NULL;
243         info.spec = NULL;
244         info.mask = NULL;
245         info.def_mask = NULL;
246         info.hw_hdr_len = NPC_TPID_LENGTH;
247
248         lid = NPC_LID_LB;
249         lflags = 0;
250         last_pattern = pattern;
251
252         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
253                 /* RTE vlan is either 802.1q or 802.1ad,
254                  * this maps to either CTAG/STAG. We need to decide
255                  * based on number of VLANS present. Matching is
256                  * supported on first tag only.
257                  */
258                 info.hw_mask = NULL;
259                 info.len = sizeof(vlan_item[0]->hdr);
260
261                 pattern = pst->pattern;
262                 while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
263                         if (nr_vlans > NPC_MAX_SUPPORTED_VLANS - 1)
264                                 return NPC_ERR_PATTERN_NOTSUP;
265
266                         vlan_item[nr_vlans] = pattern->spec;
267                         nr_vlans++;
268
269                         /* Basic validation of Second/Third vlan item */
270                         if (nr_vlans > 1) {
271                                 rc = npc_parse_item_basic(pattern, &info);
272                                 if (rc != 0)
273                                         return rc;
274                         }
275                         last_pattern = pattern;
276                         pattern++;
277                         pattern = npc_parse_skip_void_and_any_items(pattern);
278                 }
279
280                 switch (nr_vlans) {
281                 case 1:
282                         lt = NPC_LT_LB_CTAG;
283                         if (vlan_item[0] && vlan_item[0]->has_more_vlan)
284                                 lt = NPC_LT_LB_STAG_QINQ;
285                         break;
286                 case 2:
287                         if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
288                                 if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
289                                       0x3ULL << NPC_LFLAG_LB_OFFSET))
290                                         return NPC_ERR_PATTERN_NOTSUP;
291
292                                 /* This lflag value will match either one of
293                                  * NPC_F_LB_L_WITH_STAG_STAG,
294                                  * NPC_F_LB_L_WITH_QINQ_CTAG,
295                                  * NPC_F_LB_L_WITH_QINQ_QINQ and
296                                  * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
297                                  * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
298                                  * hence will not match.
299                                  */
300
301                                 lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
302                                          NPC_F_LB_L_WITH_QINQ_QINQ &
303                                          NPC_F_LB_L_WITH_STAG_STAG;
304                         } else {
305                                 lflags = NPC_F_LB_L_WITH_CTAG;
306                         }
307                         lt = NPC_LT_LB_STAG_QINQ;
308                         break;
309                 case 3:
310                         if (vlan_item[2] && vlan_item[2]->has_more_vlan)
311                                 return NPC_ERR_PATTERN_NOTSUP;
312                         lt = NPC_LT_LB_STAG_QINQ;
313                         lflags = NPC_F_STAG_STAG_CTAG;
314                         break;
315                 default:
316                         return NPC_ERR_PATTERN_NOTSUP;
317                 }
318         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
319                 /* we can support ETAG and match a subsequent CTAG
320                  * without any matching support.
321                  */
322                 lt = NPC_LT_LB_ETAG;
323                 lflags = 0;
324
325                 last_pattern = pst->pattern;
326                 pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
327                 if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
328                         /* set supported mask to NULL for vlan tag */
329                         info.hw_mask = NULL;
330                         info.len = pattern->size;
331                         rc = npc_parse_item_basic(pattern, &info);
332                         if (rc != 0)
333                                 return rc;
334
335                         lflags = NPC_F_ETAG_CTAG;
336                         last_pattern = pattern;
337                 }
338                 info.len = pattern->size;
339         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
340                 vlan_item[0] = pst->pattern->spec;
341                 info.hw_mask = NULL;
342                 info.len = sizeof(vlan_item[0]->hdr);
343                 lt = NPC_LT_LB_STAG_QINQ;
344                 lflags = NPC_F_STAG_CTAG;
345                 if (vlan_item[0] && vlan_item[0]->has_more_vlan) {
346                         lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
347                                  NPC_F_LB_L_WITH_QINQ_QINQ;
348                 }
349         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
350                 raw_spec = pst->pattern->spec;
351                 if (raw_spec->relative)
352                         return 0;
353                 len = raw_spec->length + raw_spec->offset;
354                 if (len > NPC_MAX_RAW_ITEM_LEN)
355                         return -EINVAL;
356
357                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
358                         lt = NPC_LT_LB_VLAN_EXDSA;
359                 } else if (pst->npc->switch_header_type ==
360                            ROC_PRIV_FLAGS_EXDSA) {
361                         lt = NPC_LT_LB_EXDSA;
362                 } else {
363                         return -EINVAL;
364                 }
365
366                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
367                                                   pst->pattern->spec,
368                                           (const struct roc_npc_flow_item_raw *)
369                                                   pst->pattern->mask,
370                                           &info, raw_spec_buf, raw_mask_buf);
371
372                 info.hw_hdr_len = 0;
373         } else {
374                 return 0;
375         }
376
377         info.hw_mask = &hw_mask;
378         npc_get_hw_supp_mask(pst, &info, lid, lt);
379
380         rc = npc_parse_item_basic(pst->pattern, &info);
381         if (rc != 0)
382                 return rc;
383
384         /* Point pattern to last item consumed */
385         pst->pattern = last_pattern;
386         return npc_update_parse_state(pst, &info, lid, lt, lflags);
387 }
388
389 static int
390 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
391 {
392         uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
393                                NPC_F_MPLS_4_LABELS};
394         const struct roc_npc_item_info *pattern = pst->pattern;
395         struct npc_parse_item_info info;
396         int nr_labels = 0;
397         int rc;
398
399         /*
400          * pst->pattern points to first MPLS label. We only check
401          * that subsequent labels do not have anything to match.
402          */
403         info.def_mask = NULL;
404         info.hw_mask = NULL;
405         info.len = pattern->size;
406         info.spec = NULL;
407         info.mask = NULL;
408         info.hw_hdr_len = 0;
409
410         while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
411                 nr_labels++;
412
413                 /* Basic validation of Second/Third/Fourth mpls item */
414                 if (nr_labels > 1) {
415                         rc = npc_parse_item_basic(pattern, &info);
416                         if (rc != 0)
417                                 return rc;
418                 }
419                 pst->last_pattern = pattern;
420                 pattern++;
421                 pattern = npc_parse_skip_void_and_any_items(pattern);
422         }
423
424         if (nr_labels < 1 || nr_labels > 4)
425                 return NPC_ERR_PATTERN_NOTSUP;
426
427         *flag = flag_list[nr_labels - 1];
428         return 0;
429 }
430
431 static int
432 npc_parse_mpls(struct npc_parse_state *pst, int lid)
433 {
434         /* Find number of MPLS labels */
435         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
436         struct npc_parse_item_info info;
437         int lt, lflags;
438         int rc;
439
440         lflags = 0;
441
442         if (lid == NPC_LID_LC)
443                 lt = NPC_LT_LC_MPLS;
444         else if (lid == NPC_LID_LD)
445                 lt = NPC_LT_LD_TU_MPLS_IN_IP;
446         else
447                 lt = NPC_LT_LE_TU_MPLS_IN_UDP;
448
449         /* Prepare for parsing the first item */
450         info.hw_mask = &hw_mask;
451         info.len = pst->pattern->size;
452         info.spec = NULL;
453         info.mask = NULL;
454         info.def_mask = NULL;
455         info.hw_hdr_len = 0;
456
457         npc_get_hw_supp_mask(pst, &info, lid, lt);
458         rc = npc_parse_item_basic(pst->pattern, &info);
459         if (rc != 0)
460                 return rc;
461
462         /*
463          * Parse for more labels.
464          * This sets lflags and pst->last_pattern correctly.
465          */
466         rc = npc_parse_mpls_label_stack(pst, &lflags);
467         if (rc != 0)
468                 return rc;
469
470         pst->tunnel = 1;
471         pst->pattern = pst->last_pattern;
472
473         return npc_update_parse_state(pst, &info, lid, lt, lflags);
474 }
475
476 static inline void
477 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
478 {
479         const struct roc_npc_item_info *pattern = pst->pattern + 1;
480
481         pattern = npc_parse_skip_void_and_any_items(pattern);
482         if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
483             pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
484             pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
485                 pst->tunnel = 1;
486 }
487
488 static int
489 npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
490                         struct npc_parse_state *pst, uint8_t *flags)
491 {
492         int flags_count = 0;
493
494         if (ipv6_spec->has_hop_ext) {
495                 *flags = NPC_F_LC_L_EXT_HOP;
496                 flags_count++;
497         }
498         if (ipv6_spec->has_route_ext) {
499                 *flags = NPC_F_LC_L_EXT_ROUT;
500                 flags_count++;
501         }
502         if (ipv6_spec->has_frag_ext) {
503                 *flags = NPC_F_LC_U_IP6_FRAG;
504                 flags_count++;
505         }
506         if (ipv6_spec->has_dest_ext) {
507                 *flags = NPC_F_LC_L_EXT_DEST;
508                 flags_count++;
509         }
510         if (ipv6_spec->has_mobil_ext) {
511                 *flags = NPC_F_LC_L_EXT_MOBILITY;
512                 flags_count++;
513         }
514         if (ipv6_spec->has_hip_ext) {
515                 *flags = NPC_F_LC_L_EXT_HOSTID;
516                 flags_count++;
517         }
518         if (ipv6_spec->has_shim6_ext) {
519                 *flags = NPC_F_LC_L_EXT_SHIM6;
520                 flags_count++;
521         }
522         if (ipv6_spec->has_auth_ext) {
523                 pst->lt[NPC_LID_LD] = NPC_LT_LD_AH;
524                 flags_count++;
525         }
526         if (ipv6_spec->has_esp_ext) {
527                 pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP;
528                 flags_count++;
529         }
530
531         if (flags_count > 1)
532                 return -EINVAL;
533
534         if (flags_count)
535                 pst->set_ipv6ext_ltype_mask = true;
536
537         return 0;
538 }
539
540 int
541 npc_parse_lc(struct npc_parse_state *pst)
542 {
543         const struct roc_npc_flow_item_ipv6 *ipv6_spec;
544         const struct roc_npc_flow_item_raw *raw_spec;
545         uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
546         uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
547         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
548         struct npc_parse_item_info info;
549         int rc, lid, lt, len = 0;
550         uint8_t flags = 0;
551
552         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
553                 return npc_parse_mpls(pst, NPC_LID_LC);
554
555         info.def_mask = NULL;
556         info.hw_mask = &hw_mask;
557         info.spec = NULL;
558         info.mask = NULL;
559         info.hw_hdr_len = 0;
560         lid = NPC_LID_LC;
561
562         switch (pst->pattern->type) {
563         case ROC_NPC_ITEM_TYPE_IPV4:
564                 lt = NPC_LT_LC_IP;
565                 info.len = pst->pattern->size;
566                 break;
567         case ROC_NPC_ITEM_TYPE_IPV6:
568                 ipv6_spec = pst->pattern->spec;
569                 lid = NPC_LID_LC;
570                 lt = NPC_LT_LC_IP6;
571                 if (ipv6_spec) {
572                         rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags);
573                         if (rc)
574                                 return rc;
575                 }
576                 info.len = sizeof(ipv6_spec->hdr);
577                 break;
578         case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
579                 lt = NPC_LT_LC_ARP;
580                 info.len = pst->pattern->size;
581                 break;
582         case ROC_NPC_ITEM_TYPE_IPV6_EXT:
583                 lid = NPC_LID_LC;
584                 lt = NPC_LT_LC_IP6_EXT;
585                 info.len = pst->pattern->size;
586                 info.hw_hdr_len = 40;
587                 break;
588         case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
589                 lt = NPC_LT_LC_CUSTOM0;
590                 info.len = pst->pattern->size;
591                 break;
592         case ROC_NPC_ITEM_TYPE_RAW:
593                 raw_spec = pst->pattern->spec;
594                 if (!raw_spec->relative)
595                         return 0;
596
597                 len = raw_spec->length + raw_spec->offset;
598                 if (len > NPC_MAX_RAW_ITEM_LEN)
599                         return -EINVAL;
600
601                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
602                                                   pst->pattern->spec,
603                                           (const struct roc_npc_flow_item_raw *)
604                                                   pst->pattern->mask,
605                                           &info, raw_spec_buf, raw_mask_buf);
606
607                 lid = NPC_LID_LC;
608                 lt = NPC_LT_LC_NGIO;
609                 info.hw_mask = &hw_mask;
610                 npc_get_hw_supp_mask(pst, &info, lid, lt);
611                 break;
612         default:
613                 /* No match at this layer */
614                 return 0;
615         }
616
617         /* Identify if IP tunnels MPLS or IPv4/v6 */
618         npc_check_lc_ip_tunnel(pst);
619
620         npc_get_hw_supp_mask(pst, &info, lid, lt);
621         rc = npc_parse_item_basic(pst->pattern, &info);
622
623         if (rc != 0)
624                 return rc;
625
626         return npc_update_parse_state(pst, &info, lid, lt, flags);
627 }
628
629 int
630 npc_parse_ld(struct npc_parse_state *pst)
631 {
632         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
633         struct npc_parse_item_info info;
634         int lid, lt, lflags;
635         int rc;
636
637         if (pst->tunnel) {
638                 /* We have already parsed MPLS or IPv4/v6 followed
639                  * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
640                  * would be parsed as tunneled versions. Skip
641                  * this layer, except for tunneled MPLS. If LC is
642                  * MPLS, we have anyway skipped all stacked MPLS
643                  * labels.
644                  */
645                 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
646                         return npc_parse_mpls(pst, NPC_LID_LD);
647                 return 0;
648         }
649         info.def_mask = NULL;
650         info.hw_mask = &hw_mask;
651         info.spec = NULL;
652         info.mask = NULL;
653         info.len = 0;
654         info.hw_hdr_len = 0;
655
656         lid = NPC_LID_LD;
657         lflags = 0;
658
659         switch (pst->pattern->type) {
660         case ROC_NPC_ITEM_TYPE_ICMP:
661                 if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
662                         lt = NPC_LT_LD_ICMP6;
663                 else
664                         lt = NPC_LT_LD_ICMP;
665                 info.len = pst->pattern->size;
666                 break;
667         case ROC_NPC_ITEM_TYPE_UDP:
668                 lt = NPC_LT_LD_UDP;
669                 info.len = pst->pattern->size;
670                 break;
671         case ROC_NPC_ITEM_TYPE_IGMP:
672                 lt = NPC_LT_LD_IGMP;
673                 info.len = pst->pattern->size;
674                 break;
675         case ROC_NPC_ITEM_TYPE_TCP:
676                 lt = NPC_LT_LD_TCP;
677                 info.len = pst->pattern->size;
678                 break;
679         case ROC_NPC_ITEM_TYPE_SCTP:
680                 lt = NPC_LT_LD_SCTP;
681                 info.len = pst->pattern->size;
682                 break;
683         case ROC_NPC_ITEM_TYPE_GRE:
684                 lt = NPC_LT_LD_GRE;
685                 info.len = pst->pattern->size;
686                 break;
687         case ROC_NPC_ITEM_TYPE_GRE_KEY:
688                 lt = NPC_LT_LD_GRE;
689                 info.len = pst->pattern->size;
690                 info.hw_hdr_len = 4;
691                 break;
692         case ROC_NPC_ITEM_TYPE_NVGRE:
693                 lt = NPC_LT_LD_NVGRE;
694                 lflags = NPC_F_GRE_NVGRE;
695                 info.len = pst->pattern->size;
696                 /* Further IP/Ethernet are parsed as tunneled */
697                 pst->tunnel = 1;
698                 break;
699         default:
700                 return 0;
701         }
702
703         npc_get_hw_supp_mask(pst, &info, lid, lt);
704         rc = npc_parse_item_basic(pst->pattern, &info);
705         if (rc != 0)
706                 return rc;
707
708         return npc_update_parse_state(pst, &info, lid, lt, lflags);
709 }
710
711 int
712 npc_parse_le(struct npc_parse_state *pst)
713 {
714         const struct roc_npc_item_info *pattern = pst->pattern;
715         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
716         struct npc_parse_item_info info;
717         int lid, lt, lflags;
718         int rc;
719
720         if (pst->tunnel)
721                 return 0;
722
723         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
724                 return npc_parse_mpls(pst, NPC_LID_LE);
725
726         info.spec = NULL;
727         info.mask = NULL;
728         info.hw_mask = NULL;
729         info.def_mask = NULL;
730         info.len = 0;
731         info.hw_hdr_len = 0;
732         lid = NPC_LID_LE;
733         lflags = 0;
734
735         /* Ensure we are not matching anything in UDP */
736         rc = npc_parse_item_basic(pattern, &info);
737         if (rc)
738                 return rc;
739
740         info.hw_mask = &hw_mask;
741         pattern = npc_parse_skip_void_and_any_items(pattern);
742         switch (pattern->type) {
743         case ROC_NPC_ITEM_TYPE_VXLAN:
744                 lflags = NPC_F_UDP_VXLAN;
745                 info.len = pattern->size;
746                 lt = NPC_LT_LE_VXLAN;
747                 break;
748         case ROC_NPC_ITEM_TYPE_GTPC:
749                 lflags = NPC_F_UDP_GTP_GTPC;
750                 info.len = pattern->size;
751                 lt = NPC_LT_LE_GTPC;
752                 break;
753         case ROC_NPC_ITEM_TYPE_GTPU:
754                 lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
755                 info.len = pattern->size;
756                 lt = NPC_LT_LE_GTPU;
757                 break;
758         case ROC_NPC_ITEM_TYPE_GENEVE:
759                 lflags = NPC_F_UDP_GENEVE;
760                 info.len = pattern->size;
761                 lt = NPC_LT_LE_GENEVE;
762                 break;
763         case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
764                 lflags = NPC_F_UDP_VXLANGPE;
765                 info.len = pattern->size;
766                 lt = NPC_LT_LE_VXLANGPE;
767                 break;
768         case ROC_NPC_ITEM_TYPE_ESP:
769                 lt = NPC_LT_LE_ESP;
770                 info.len = pst->pattern->size;
771                 break;
772         default:
773                 return 0;
774         }
775
776         pst->tunnel = 1;
777
778         npc_get_hw_supp_mask(pst, &info, lid, lt);
779         rc = npc_parse_item_basic(pattern, &info);
780         if (rc != 0)
781                 return rc;
782
783         return npc_update_parse_state(pst, &info, lid, lt, lflags);
784 }
785
786 int
787 npc_parse_lf(struct npc_parse_state *pst)
788 {
789         const struct roc_npc_item_info *pattern, *last_pattern;
790         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
791         struct npc_parse_item_info info;
792         int lid, lt, lflags;
793         int nr_vlans = 0;
794         int rc;
795
796         /* We hit this layer if there is a tunneling protocol */
797         if (!pst->tunnel)
798                 return 0;
799
800         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
801                 return 0;
802
803         lid = NPC_LID_LF;
804         lt = NPC_LT_LF_TU_ETHER;
805         lflags = 0;
806
807         /* No match support for vlan tags */
808         info.def_mask = NULL;
809         info.hw_mask = NULL;
810         info.len = pst->pattern->size;
811         info.spec = NULL;
812         info.mask = NULL;
813         info.hw_hdr_len = 0;
814
815         /* Look ahead and find out any VLAN tags. These can be
816          * detected but no data matching is available.
817          */
818         last_pattern = pst->pattern;
819         pattern = pst->pattern + 1;
820         pattern = npc_parse_skip_void_and_any_items(pattern);
821         while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
822                 nr_vlans++;
823                 last_pattern = pattern;
824                 pattern++;
825                 pattern = npc_parse_skip_void_and_any_items(pattern);
826         }
827         switch (nr_vlans) {
828         case 0:
829                 break;
830         case 1:
831                 lflags = NPC_F_TU_ETHER_CTAG;
832                 break;
833         case 2:
834                 lflags = NPC_F_TU_ETHER_STAG_CTAG;
835                 break;
836         default:
837                 return NPC_ERR_PATTERN_NOTSUP;
838         }
839
840         info.hw_mask = &hw_mask;
841         info.len = pst->pattern->size;
842         info.hw_hdr_len = 0;
843         npc_get_hw_supp_mask(pst, &info, lid, lt);
844         info.spec = NULL;
845         info.mask = NULL;
846
847         rc = npc_parse_item_basic(pst->pattern, &info);
848         if (rc != 0)
849                 return rc;
850
851         pst->pattern = last_pattern;
852
853         return npc_update_parse_state(pst, &info, lid, lt, lflags);
854 }
855
856 int
857 npc_parse_lg(struct npc_parse_state *pst)
858 {
859         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
860         struct npc_parse_item_info info;
861         int lid, lt;
862         int rc;
863
864         if (!pst->tunnel)
865                 return 0;
866
867         info.def_mask = NULL;
868         info.hw_mask = &hw_mask;
869         info.spec = NULL;
870         info.mask = NULL;
871         info.hw_hdr_len = 0;
872         lid = NPC_LID_LG;
873
874         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
875                 lt = NPC_LT_LG_TU_IP;
876                 info.len = pst->pattern->size;
877         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
878                 lt = NPC_LT_LG_TU_IP6;
879                 info.len = pst->pattern->size;
880         } else {
881                 /* There is no tunneled IP header */
882                 return 0;
883         }
884
885         npc_get_hw_supp_mask(pst, &info, lid, lt);
886         rc = npc_parse_item_basic(pst->pattern, &info);
887         if (rc != 0)
888                 return rc;
889
890         return npc_update_parse_state(pst, &info, lid, lt, 0);
891 }
892
893 int
894 npc_parse_lh(struct npc_parse_state *pst)
895 {
896         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
897         struct npc_parse_item_info info;
898         int lid, lt;
899         int rc;
900
901         if (!pst->tunnel)
902                 return 0;
903
904         info.def_mask = NULL;
905         info.hw_mask = &hw_mask;
906         info.spec = NULL;
907         info.mask = NULL;
908         info.hw_hdr_len = 0;
909         lid = NPC_LID_LH;
910
911         switch (pst->pattern->type) {
912         case ROC_NPC_ITEM_TYPE_UDP:
913                 lt = NPC_LT_LH_TU_UDP;
914                 info.len = pst->pattern->size;
915                 break;
916         case ROC_NPC_ITEM_TYPE_TCP:
917                 lt = NPC_LT_LH_TU_TCP;
918                 info.len = pst->pattern->size;
919                 break;
920         case ROC_NPC_ITEM_TYPE_SCTP:
921                 lt = NPC_LT_LH_TU_SCTP;
922                 info.len = pst->pattern->size;
923                 break;
924         case ROC_NPC_ITEM_TYPE_ESP:
925                 lt = NPC_LT_LH_TU_ESP;
926                 info.len = pst->pattern->size;
927                 break;
928         default:
929                 return 0;
930         }
931
932         npc_get_hw_supp_mask(pst, &info, lid, lt);
933         rc = npc_parse_item_basic(pst->pattern, &info);
934         if (rc != 0)
935                 return rc;
936
937         return npc_update_parse_state(pst, &info, lid, lt, 0);
938 }