common/cnxk: allow reuse of SSO API for inline dev
[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_cpt_hdr(struct npc_parse_state *pst)
26 {
27         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
28         struct npc_parse_item_info info;
29         int lid, lt;
30         int rc;
31
32         /* Identify the pattern type into lid, lt */
33         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR)
34                 return 0;
35
36         lid = NPC_LID_LA;
37         lt = NPC_LT_LA_CPT_HDR;
38         info.hw_hdr_len = 0;
39
40         /* Prepare for parsing the item */
41         info.hw_mask = &hw_mask;
42         info.len = pst->pattern->size;
43         npc_get_hw_supp_mask(pst, &info, lid, lt);
44         info.spec = NULL;
45         info.mask = NULL;
46
47         /* Basic validation of item parameters */
48         rc = npc_parse_item_basic(pst->pattern, &info);
49         if (rc)
50                 return rc;
51
52         /* Update pst if not validate only? clash check? */
53         return npc_update_parse_state(pst, &info, lid, lt, 0);
54 }
55
56 int
57 npc_parse_higig2_hdr(struct npc_parse_state *pst)
58 {
59         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
60         struct npc_parse_item_info info;
61         int lid, lt;
62         int rc;
63
64         /* Identify the pattern type into lid, lt */
65         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
66                 return 0;
67
68         lid = NPC_LID_LA;
69         lt = NPC_LT_LA_HIGIG2_ETHER;
70         info.hw_hdr_len = 0;
71
72         if (pst->flow->nix_intf == NIX_INTF_TX) {
73                 lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
74                 info.hw_hdr_len = NPC_IH_LENGTH;
75         }
76
77         /* Prepare for parsing the item */
78         info.hw_mask = &hw_mask;
79         info.len = pst->pattern->size;
80         npc_get_hw_supp_mask(pst, &info, lid, lt);
81         info.spec = NULL;
82         info.mask = NULL;
83
84         /* Basic validation of item parameters */
85         rc = npc_parse_item_basic(pst->pattern, &info);
86         if (rc)
87                 return rc;
88
89         /* Update pst if not validate only? clash check? */
90         return npc_update_parse_state(pst, &info, lid, lt, 0);
91 }
92
93 int
94 npc_parse_la(struct npc_parse_state *pst)
95 {
96         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
97         struct npc_parse_item_info info;
98         int lid, lt;
99         int rc;
100
101         /* Identify the pattern type into lid, lt */
102         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
103                 return 0;
104
105         lid = NPC_LID_LA;
106         lt = NPC_LT_LA_ETHER;
107         info.hw_hdr_len = 0;
108
109         if (pst->flow->nix_intf == NIX_INTF_TX) {
110                 lt = NPC_LT_LA_IH_NIX_ETHER;
111                 info.hw_hdr_len = NPC_IH_LENGTH;
112                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
113                         lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
114                         info.hw_hdr_len += NPC_HIGIG2_LENGTH;
115                 }
116         } else {
117                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
118                         lt = NPC_LT_LA_HIGIG2_ETHER;
119                         info.hw_hdr_len = NPC_HIGIG2_LENGTH;
120                 }
121         }
122
123         /* Prepare for parsing the item */
124         info.hw_mask = &hw_mask;
125         info.len = pst->pattern->size;
126         npc_get_hw_supp_mask(pst, &info, lid, lt);
127         info.spec = NULL;
128         info.mask = NULL;
129
130         /* Basic validation of item parameters */
131         rc = npc_parse_item_basic(pst->pattern, &info);
132         if (rc)
133                 return rc;
134
135         /* Update pst if not validate only? clash check? */
136         return npc_update_parse_state(pst, &info, lid, lt, 0);
137 }
138
139 static int
140 npc_flow_raw_item_prepare(const struct roc_npc_flow_item_raw *raw_spec,
141                           const struct roc_npc_flow_item_raw *raw_mask,
142                           struct npc_parse_item_info *info, uint8_t *spec_buf,
143                           uint8_t *mask_buf)
144 {
145         uint32_t custom_hdr_size = 0;
146
147         memset(spec_buf, 0, NPC_MAX_RAW_ITEM_LEN);
148         memset(mask_buf, 0, NPC_MAX_RAW_ITEM_LEN);
149         custom_hdr_size = raw_spec->offset + raw_spec->length;
150
151         memcpy(spec_buf + raw_spec->offset, raw_spec->pattern,
152                raw_spec->length);
153
154         if (raw_mask->pattern) {
155                 memcpy(mask_buf + raw_spec->offset, raw_mask->pattern,
156                        raw_spec->length);
157         } else {
158                 memset(mask_buf + raw_spec->offset, 0xFF, raw_spec->length);
159         }
160
161         info->len = custom_hdr_size;
162         info->spec = spec_buf;
163         info->mask = mask_buf;
164
165         return 0;
166 }
167
168 int
169 npc_parse_lb(struct npc_parse_state *pst)
170 {
171         const struct roc_npc_item_info *pattern = pst->pattern;
172         const struct roc_npc_item_info *last_pattern;
173         const struct roc_npc_flow_item_raw *raw_spec;
174         uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
175         uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
176         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
177         struct npc_parse_item_info info;
178         int lid, lt, lflags, len = 0;
179         int nr_vlans = 0;
180         int rc;
181
182         info.spec = NULL;
183         info.mask = NULL;
184         info.def_mask = NULL;
185         info.hw_hdr_len = NPC_TPID_LENGTH;
186
187         lid = NPC_LID_LB;
188         lflags = 0;
189         last_pattern = pattern;
190
191         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
192                 /* RTE vlan is either 802.1q or 802.1ad,
193                  * this maps to either CTAG/STAG. We need to decide
194                  * based on number of VLANS present. Matching is
195                  * supported on first tag only.
196                  */
197                 info.hw_mask = NULL;
198                 info.len = pst->pattern->size;
199
200                 pattern = pst->pattern;
201                 while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
202                         nr_vlans++;
203
204                         /* Basic validation of Second/Third vlan item */
205                         if (nr_vlans > 1) {
206                                 rc = npc_parse_item_basic(pattern, &info);
207                                 if (rc != 0)
208                                         return rc;
209                         }
210                         last_pattern = pattern;
211                         pattern++;
212                         pattern = npc_parse_skip_void_and_any_items(pattern);
213                 }
214
215                 switch (nr_vlans) {
216                 case 1:
217                         lt = NPC_LT_LB_CTAG;
218                         break;
219                 case 2:
220                         lt = NPC_LT_LB_STAG_QINQ;
221                         lflags = NPC_F_STAG_CTAG;
222                         break;
223                 case 3:
224                         lt = NPC_LT_LB_STAG_QINQ;
225                         lflags = NPC_F_STAG_STAG_CTAG;
226                         break;
227                 default:
228                         return NPC_ERR_PATTERN_NOTSUP;
229                 }
230         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
231                 /* we can support ETAG and match a subsequent CTAG
232                  * without any matching support.
233                  */
234                 lt = NPC_LT_LB_ETAG;
235                 lflags = 0;
236
237                 last_pattern = pst->pattern;
238                 pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
239                 if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
240                         /* set supported mask to NULL for vlan tag */
241                         info.hw_mask = NULL;
242                         info.len = pattern->size;
243                         rc = npc_parse_item_basic(pattern, &info);
244                         if (rc != 0)
245                                 return rc;
246
247                         lflags = NPC_F_ETAG_CTAG;
248                         last_pattern = pattern;
249                 }
250                 info.len = pattern->size;
251         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
252                 info.hw_mask = NULL;
253                 info.len = pst->pattern->size;
254                 lt = NPC_LT_LB_STAG_QINQ;
255                 lflags = NPC_F_STAG_CTAG;
256         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
257                 raw_spec = pst->pattern->spec;
258                 if (raw_spec->relative)
259                         return 0;
260                 len = raw_spec->length + raw_spec->offset;
261                 if (len > NPC_MAX_RAW_ITEM_LEN)
262                         return -EINVAL;
263
264                 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) {
265                         lt = NPC_LT_LB_VLAN_EXDSA;
266                 } else if (pst->npc->switch_header_type ==
267                            ROC_PRIV_FLAGS_EXDSA) {
268                         lt = NPC_LT_LB_EXDSA;
269                 } else {
270                         return -EINVAL;
271                 }
272
273                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
274                                                   pst->pattern->spec,
275                                           (const struct roc_npc_flow_item_raw *)
276                                                   pst->pattern->mask,
277                                           &info, raw_spec_buf, raw_mask_buf);
278
279                 info.hw_hdr_len = 0;
280         } else {
281                 return 0;
282         }
283
284         info.hw_mask = &hw_mask;
285         npc_get_hw_supp_mask(pst, &info, lid, lt);
286
287         rc = npc_parse_item_basic(pst->pattern, &info);
288         if (rc != 0)
289                 return rc;
290
291         /* Point pattern to last item consumed */
292         pst->pattern = last_pattern;
293         return npc_update_parse_state(pst, &info, lid, lt, lflags);
294 }
295
296 static int
297 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
298 {
299         uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
300                                NPC_F_MPLS_4_LABELS};
301         const struct roc_npc_item_info *pattern = pst->pattern;
302         struct npc_parse_item_info info;
303         int nr_labels = 0;
304         int rc;
305
306         /*
307          * pst->pattern points to first MPLS label. We only check
308          * that subsequent labels do not have anything to match.
309          */
310         info.hw_mask = NULL;
311         info.len = pattern->size;
312         info.spec = NULL;
313         info.mask = NULL;
314         info.hw_hdr_len = 0;
315         info.def_mask = NULL;
316
317         while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
318                 nr_labels++;
319
320                 /* Basic validation of Second/Third/Fourth mpls item */
321                 if (nr_labels > 1) {
322                         rc = npc_parse_item_basic(pattern, &info);
323                         if (rc != 0)
324                                 return rc;
325                 }
326                 pst->last_pattern = pattern;
327                 pattern++;
328                 pattern = npc_parse_skip_void_and_any_items(pattern);
329         }
330
331         if (nr_labels < 1 || nr_labels > 4)
332                 return NPC_ERR_PATTERN_NOTSUP;
333
334         *flag = flag_list[nr_labels - 1];
335         return 0;
336 }
337
338 static int
339 npc_parse_mpls(struct npc_parse_state *pst, int lid)
340 {
341         /* Find number of MPLS labels */
342         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
343         struct npc_parse_item_info info;
344         int lt, lflags;
345         int rc;
346
347         lflags = 0;
348
349         if (lid == NPC_LID_LC)
350                 lt = NPC_LT_LC_MPLS;
351         else if (lid == NPC_LID_LD)
352                 lt = NPC_LT_LD_TU_MPLS_IN_IP;
353         else
354                 lt = NPC_LT_LE_TU_MPLS_IN_UDP;
355
356         /* Prepare for parsing the first item */
357         info.hw_mask = &hw_mask;
358         info.len = pst->pattern->size;
359         info.spec = NULL;
360         info.mask = NULL;
361         info.hw_hdr_len = 0;
362
363         npc_get_hw_supp_mask(pst, &info, lid, lt);
364         rc = npc_parse_item_basic(pst->pattern, &info);
365         if (rc != 0)
366                 return rc;
367
368         /*
369          * Parse for more labels.
370          * This sets lflags and pst->last_pattern correctly.
371          */
372         rc = npc_parse_mpls_label_stack(pst, &lflags);
373         if (rc != 0)
374                 return rc;
375
376         pst->tunnel = 1;
377         pst->pattern = pst->last_pattern;
378
379         return npc_update_parse_state(pst, &info, lid, lt, lflags);
380 }
381
382 static inline void
383 npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
384 {
385         const struct roc_npc_item_info *pattern = pst->pattern + 1;
386
387         pattern = npc_parse_skip_void_and_any_items(pattern);
388         if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
389             pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
390             pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
391                 pst->tunnel = 1;
392 }
393
394 int
395 npc_parse_lc(struct npc_parse_state *pst)
396 {
397         const struct roc_npc_flow_item_raw *raw_spec;
398         uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN];
399         uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN];
400         uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
401         struct npc_parse_item_info info;
402         int lid, lt, len = 0;
403         int rc;
404
405         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
406                 return npc_parse_mpls(pst, NPC_LID_LC);
407
408         info.hw_mask = &hw_mask;
409         info.spec = NULL;
410         info.mask = NULL;
411         info.hw_hdr_len = 0;
412         lid = NPC_LID_LC;
413
414         switch (pst->pattern->type) {
415         case ROC_NPC_ITEM_TYPE_IPV4:
416                 lt = NPC_LT_LC_IP;
417                 info.len = pst->pattern->size;
418                 break;
419         case ROC_NPC_ITEM_TYPE_IPV6:
420                 lid = NPC_LID_LC;
421                 lt = NPC_LT_LC_IP6;
422                 info.len = pst->pattern->size;
423                 break;
424         case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
425                 lt = NPC_LT_LC_ARP;
426                 info.len = pst->pattern->size;
427                 break;
428         case ROC_NPC_ITEM_TYPE_IPV6_EXT:
429                 lid = NPC_LID_LC;
430                 lt = NPC_LT_LC_IP6_EXT;
431                 info.len = pst->pattern->size;
432                 info.hw_hdr_len = 40;
433                 break;
434         case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
435                 lt = NPC_LT_LC_CUSTOM0;
436                 info.len = pst->pattern->size;
437                 break;
438         case ROC_NPC_ITEM_TYPE_RAW:
439                 raw_spec = pst->pattern->spec;
440                 if (!raw_spec->relative)
441                         return 0;
442
443                 len = raw_spec->length + raw_spec->offset;
444                 if (len > NPC_MAX_RAW_ITEM_LEN)
445                         return -EINVAL;
446
447                 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *)
448                                                   pst->pattern->spec,
449                                           (const struct roc_npc_flow_item_raw *)
450                                                   pst->pattern->mask,
451                                           &info, raw_spec_buf, raw_mask_buf);
452
453                 lid = NPC_LID_LC;
454                 lt = NPC_LT_LC_NGIO;
455                 info.hw_mask = &hw_mask;
456                 npc_get_hw_supp_mask(pst, &info, lid, lt);
457                 break;
458         default:
459                 /* No match at this layer */
460                 return 0;
461         }
462
463         /* Identify if IP tunnels MPLS or IPv4/v6 */
464         npc_check_lc_ip_tunnel(pst);
465
466         npc_get_hw_supp_mask(pst, &info, lid, lt);
467         rc = npc_parse_item_basic(pst->pattern, &info);
468
469         if (rc != 0)
470                 return rc;
471
472         return npc_update_parse_state(pst, &info, lid, lt, 0);
473 }
474
475 int
476 npc_parse_ld(struct npc_parse_state *pst)
477 {
478         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
479         struct npc_parse_item_info info;
480         int lid, lt, lflags;
481         int rc;
482
483         if (pst->tunnel) {
484                 /* We have already parsed MPLS or IPv4/v6 followed
485                  * by MPLS or IPv4/v6. Subsequent TCP/UDP etc
486                  * would be parsed as tunneled versions. Skip
487                  * this layer, except for tunneled MPLS. If LC is
488                  * MPLS, we have anyway skipped all stacked MPLS
489                  * labels.
490                  */
491                 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
492                         return npc_parse_mpls(pst, NPC_LID_LD);
493                 return 0;
494         }
495         info.hw_mask = &hw_mask;
496         info.spec = NULL;
497         info.mask = NULL;
498         info.def_mask = NULL;
499         info.len = 0;
500         info.hw_hdr_len = 0;
501
502         lid = NPC_LID_LD;
503         lflags = 0;
504
505         switch (pst->pattern->type) {
506         case ROC_NPC_ITEM_TYPE_ICMP:
507                 if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
508                         lt = NPC_LT_LD_ICMP6;
509                 else
510                         lt = NPC_LT_LD_ICMP;
511                 info.len = pst->pattern->size;
512                 break;
513         case ROC_NPC_ITEM_TYPE_UDP:
514                 lt = NPC_LT_LD_UDP;
515                 info.len = pst->pattern->size;
516                 break;
517         case ROC_NPC_ITEM_TYPE_IGMP:
518                 lt = NPC_LT_LD_IGMP;
519                 info.len = pst->pattern->size;
520                 break;
521         case ROC_NPC_ITEM_TYPE_TCP:
522                 lt = NPC_LT_LD_TCP;
523                 info.len = pst->pattern->size;
524                 break;
525         case ROC_NPC_ITEM_TYPE_SCTP:
526                 lt = NPC_LT_LD_SCTP;
527                 info.len = pst->pattern->size;
528                 break;
529         case ROC_NPC_ITEM_TYPE_GRE:
530                 lt = NPC_LT_LD_GRE;
531                 info.len = pst->pattern->size;
532                 break;
533         case ROC_NPC_ITEM_TYPE_GRE_KEY:
534                 lt = NPC_LT_LD_GRE;
535                 info.len = pst->pattern->size;
536                 info.hw_hdr_len = 4;
537                 break;
538         case ROC_NPC_ITEM_TYPE_NVGRE:
539                 lt = NPC_LT_LD_NVGRE;
540                 lflags = NPC_F_GRE_NVGRE;
541                 info.len = pst->pattern->size;
542                 /* Further IP/Ethernet are parsed as tunneled */
543                 pst->tunnel = 1;
544                 break;
545         default:
546                 return 0;
547         }
548
549         npc_get_hw_supp_mask(pst, &info, lid, lt);
550         rc = npc_parse_item_basic(pst->pattern, &info);
551         if (rc != 0)
552                 return rc;
553
554         return npc_update_parse_state(pst, &info, lid, lt, lflags);
555 }
556
557 int
558 npc_parse_le(struct npc_parse_state *pst)
559 {
560         const struct roc_npc_item_info *pattern = pst->pattern;
561         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
562         struct npc_parse_item_info info;
563         int lid, lt, lflags;
564         int rc;
565
566         if (pst->tunnel)
567                 return 0;
568
569         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
570                 return npc_parse_mpls(pst, NPC_LID_LE);
571
572         info.spec = NULL;
573         info.mask = NULL;
574         info.hw_mask = NULL;
575         info.def_mask = NULL;
576         info.len = 0;
577         info.hw_hdr_len = 0;
578         lid = NPC_LID_LE;
579         lflags = 0;
580
581         /* Ensure we are not matching anything in UDP */
582         rc = npc_parse_item_basic(pattern, &info);
583         if (rc)
584                 return rc;
585
586         info.hw_mask = &hw_mask;
587         pattern = npc_parse_skip_void_and_any_items(pattern);
588         switch (pattern->type) {
589         case ROC_NPC_ITEM_TYPE_VXLAN:
590                 lflags = NPC_F_UDP_VXLAN;
591                 info.len = pattern->size;
592                 lt = NPC_LT_LE_VXLAN;
593                 break;
594         case ROC_NPC_ITEM_TYPE_GTPC:
595                 lflags = NPC_F_UDP_GTP_GTPC;
596                 info.len = pattern->size;
597                 lt = NPC_LT_LE_GTPC;
598                 break;
599         case ROC_NPC_ITEM_TYPE_GTPU:
600                 lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
601                 info.len = pattern->size;
602                 lt = NPC_LT_LE_GTPU;
603                 break;
604         case ROC_NPC_ITEM_TYPE_GENEVE:
605                 lflags = NPC_F_UDP_GENEVE;
606                 info.len = pattern->size;
607                 lt = NPC_LT_LE_GENEVE;
608                 break;
609         case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
610                 lflags = NPC_F_UDP_VXLANGPE;
611                 info.len = pattern->size;
612                 lt = NPC_LT_LE_VXLANGPE;
613                 break;
614         case ROC_NPC_ITEM_TYPE_ESP:
615                 lt = NPC_LT_LE_ESP;
616                 info.len = pst->pattern->size;
617                 break;
618         default:
619                 return 0;
620         }
621
622         pst->tunnel = 1;
623
624         npc_get_hw_supp_mask(pst, &info, lid, lt);
625         rc = npc_parse_item_basic(pattern, &info);
626         if (rc != 0)
627                 return rc;
628
629         return npc_update_parse_state(pst, &info, lid, lt, lflags);
630 }
631
632 int
633 npc_parse_lf(struct npc_parse_state *pst)
634 {
635         const struct roc_npc_item_info *pattern, *last_pattern;
636         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
637         struct npc_parse_item_info info;
638         int lid, lt, lflags;
639         int nr_vlans = 0;
640         int rc;
641
642         /* We hit this layer if there is a tunneling protocol */
643         if (!pst->tunnel)
644                 return 0;
645
646         if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
647                 return 0;
648
649         lid = NPC_LID_LF;
650         lt = NPC_LT_LF_TU_ETHER;
651         lflags = 0;
652
653         /* No match support for vlan tags */
654         info.hw_mask = NULL;
655         info.len = pst->pattern->size;
656         info.spec = NULL;
657         info.mask = NULL;
658         info.hw_hdr_len = 0;
659
660         /* Look ahead and find out any VLAN tags. These can be
661          * detected but no data matching is available.
662          */
663         last_pattern = pst->pattern;
664         pattern = pst->pattern + 1;
665         pattern = npc_parse_skip_void_and_any_items(pattern);
666         while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
667                 nr_vlans++;
668                 last_pattern = pattern;
669                 pattern++;
670                 pattern = npc_parse_skip_void_and_any_items(pattern);
671         }
672         switch (nr_vlans) {
673         case 0:
674                 break;
675         case 1:
676                 lflags = NPC_F_TU_ETHER_CTAG;
677                 break;
678         case 2:
679                 lflags = NPC_F_TU_ETHER_STAG_CTAG;
680                 break;
681         default:
682                 return NPC_ERR_PATTERN_NOTSUP;
683         }
684
685         info.hw_mask = &hw_mask;
686         info.len = pst->pattern->size;
687         info.hw_hdr_len = 0;
688         npc_get_hw_supp_mask(pst, &info, lid, lt);
689         info.spec = NULL;
690         info.mask = NULL;
691
692         rc = npc_parse_item_basic(pst->pattern, &info);
693         if (rc != 0)
694                 return rc;
695
696         pst->pattern = last_pattern;
697
698         return npc_update_parse_state(pst, &info, lid, lt, lflags);
699 }
700
701 int
702 npc_parse_lg(struct npc_parse_state *pst)
703 {
704         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
705         struct npc_parse_item_info info;
706         int lid, lt;
707         int rc;
708
709         if (!pst->tunnel)
710                 return 0;
711
712         info.hw_mask = &hw_mask;
713         info.spec = NULL;
714         info.mask = NULL;
715         info.hw_hdr_len = 0;
716         lid = NPC_LID_LG;
717
718         if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
719                 lt = NPC_LT_LG_TU_IP;
720                 info.len = pst->pattern->size;
721         } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
722                 lt = NPC_LT_LG_TU_IP6;
723                 info.len = pst->pattern->size;
724         } else {
725                 /* There is no tunneled IP header */
726                 return 0;
727         }
728
729         npc_get_hw_supp_mask(pst, &info, lid, lt);
730         rc = npc_parse_item_basic(pst->pattern, &info);
731         if (rc != 0)
732                 return rc;
733
734         return npc_update_parse_state(pst, &info, lid, lt, 0);
735 }
736
737 int
738 npc_parse_lh(struct npc_parse_state *pst)
739 {
740         char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
741         struct npc_parse_item_info info;
742         int lid, lt;
743         int rc;
744
745         if (!pst->tunnel)
746                 return 0;
747
748         info.hw_mask = &hw_mask;
749         info.spec = NULL;
750         info.mask = NULL;
751         info.hw_hdr_len = 0;
752         lid = NPC_LID_LH;
753
754         switch (pst->pattern->type) {
755         case ROC_NPC_ITEM_TYPE_UDP:
756                 lt = NPC_LT_LH_TU_UDP;
757                 info.len = pst->pattern->size;
758                 break;
759         case ROC_NPC_ITEM_TYPE_TCP:
760                 lt = NPC_LT_LH_TU_TCP;
761                 info.len = pst->pattern->size;
762                 break;
763         case ROC_NPC_ITEM_TYPE_SCTP:
764                 lt = NPC_LT_LH_TU_SCTP;
765                 info.len = pst->pattern->size;
766                 break;
767         case ROC_NPC_ITEM_TYPE_ESP:
768                 lt = NPC_LT_LH_TU_ESP;
769                 info.len = pst->pattern->size;
770                 break;
771         default:
772                 return 0;
773         }
774
775         npc_get_hw_supp_mask(pst, &info, lid, lt);
776         rc = npc_parse_item_basic(pst->pattern, &info);
777         if (rc != 0)
778                 return rc;
779
780         return npc_update_parse_state(pst, &info, lid, lt, 0);
781 }