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