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