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