1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 Intel Corporation 3 */ 4 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include <rte_common.h> 9 #include <rte_ip.h> 10 #include <rte_tcp.h> 11 12 #include <rte_string_fns.h> 13 #include <rte_port_ethdev.h> 14 #include <rte_port_ring.h> 15 #include <rte_port_source_sink.h> 16 #include <rte_port_fd.h> 17 #include <rte_port_sched.h> 18 #include <rte_port_sym_crypto.h> 19 20 #include <rte_table_acl.h> 21 #include <rte_table_array.h> 22 #include <rte_table_hash.h> 23 #include <rte_table_hash_func.h> 24 #include <rte_table_lpm.h> 25 #include <rte_table_lpm_ipv6.h> 26 #include <rte_table_stub.h> 27 28 #include "rte_eth_softnic_internals.h" 29 30 #ifndef PIPELINE_MSGQ_SIZE 31 #define PIPELINE_MSGQ_SIZE 64 32 #endif 33 34 #ifndef TABLE_LPM_NUMBER_TBL8 35 #define TABLE_LPM_NUMBER_TBL8 256 36 #endif 37 38 int 39 softnic_pipeline_init(struct pmd_internals *p) 40 { 41 TAILQ_INIT(&p->pipeline_list); 42 43 return 0; 44 } 45 46 static void 47 softnic_pipeline_table_free(struct softnic_table *table) 48 { 49 for ( ; ; ) { 50 struct rte_flow *flow; 51 52 flow = TAILQ_FIRST(&table->flows); 53 if (flow == NULL) 54 break; 55 56 TAILQ_REMOVE(&table->flows, flow, node); 57 free(flow); 58 } 59 60 for ( ; ; ) { 61 struct softnic_table_meter_profile *mp; 62 63 mp = TAILQ_FIRST(&table->meter_profiles); 64 if (mp == NULL) 65 break; 66 67 TAILQ_REMOVE(&table->meter_profiles, mp, node); 68 free(mp); 69 } 70 } 71 72 void 73 softnic_pipeline_free(struct pmd_internals *p) 74 { 75 for ( ; ; ) { 76 struct pipeline *pipeline; 77 uint32_t table_id; 78 79 pipeline = TAILQ_FIRST(&p->pipeline_list); 80 if (pipeline == NULL) 81 break; 82 83 TAILQ_REMOVE(&p->pipeline_list, pipeline, node); 84 85 for (table_id = 0; table_id < pipeline->n_tables; table_id++) { 86 struct softnic_table *table = 87 &pipeline->table[table_id]; 88 89 softnic_pipeline_table_free(table); 90 } 91 92 rte_ring_free(pipeline->msgq_req); 93 rte_ring_free(pipeline->msgq_rsp); 94 rte_pipeline_free(pipeline->p); 95 free(pipeline); 96 } 97 } 98 99 void 100 softnic_pipeline_disable_all(struct pmd_internals *p) 101 { 102 struct pipeline *pipeline; 103 104 TAILQ_FOREACH(pipeline, &p->pipeline_list, node) 105 if (pipeline->enabled) 106 softnic_thread_pipeline_disable(p, 107 pipeline->thread_id, 108 pipeline->name); 109 } 110 111 uint32_t 112 softnic_pipeline_thread_count(struct pmd_internals *p, uint32_t thread_id) 113 { 114 struct pipeline *pipeline; 115 uint32_t count = 0; 116 117 TAILQ_FOREACH(pipeline, &p->pipeline_list, node) 118 if ((pipeline->enabled) && (pipeline->thread_id == thread_id)) 119 count++; 120 121 return count; 122 } 123 124 struct pipeline * 125 softnic_pipeline_find(struct pmd_internals *p, 126 const char *name) 127 { 128 struct pipeline *pipeline; 129 130 if (name == NULL) 131 return NULL; 132 133 TAILQ_FOREACH(pipeline, &p->pipeline_list, node) 134 if (strcmp(name, pipeline->name) == 0) 135 return pipeline; 136 137 return NULL; 138 } 139 140 struct pipeline * 141 softnic_pipeline_create(struct pmd_internals *softnic, 142 const char *name, 143 struct pipeline_params *params) 144 { 145 char resource_name[NAME_MAX]; 146 struct rte_pipeline_params pp; 147 struct pipeline *pipeline; 148 struct rte_pipeline *p; 149 struct rte_ring *msgq_req; 150 struct rte_ring *msgq_rsp; 151 152 /* Check input params */ 153 if (name == NULL || 154 softnic_pipeline_find(softnic, name) || 155 params == NULL || 156 params->timer_period_ms == 0) 157 return NULL; 158 159 /* Resource create */ 160 snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ", 161 softnic->params.name, 162 name); 163 164 msgq_req = rte_ring_create(resource_name, 165 PIPELINE_MSGQ_SIZE, 166 softnic->params.cpu_id, 167 RING_F_SP_ENQ | RING_F_SC_DEQ); 168 if (msgq_req == NULL) 169 return NULL; 170 171 snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP", 172 softnic->params.name, 173 name); 174 175 msgq_rsp = rte_ring_create(resource_name, 176 PIPELINE_MSGQ_SIZE, 177 softnic->params.cpu_id, 178 RING_F_SP_ENQ | RING_F_SC_DEQ); 179 if (msgq_rsp == NULL) { 180 rte_ring_free(msgq_req); 181 return NULL; 182 } 183 184 snprintf(resource_name, sizeof(resource_name), "%s_%s", 185 softnic->params.name, 186 name); 187 188 pp.name = resource_name; 189 pp.socket_id = (int)softnic->params.cpu_id; 190 pp.offset_port_id = params->offset_port_id; 191 192 p = rte_pipeline_create(&pp); 193 if (p == NULL) { 194 rte_ring_free(msgq_rsp); 195 rte_ring_free(msgq_req); 196 return NULL; 197 } 198 199 /* Node allocation */ 200 pipeline = calloc(1, sizeof(struct pipeline)); 201 if (pipeline == NULL) { 202 rte_pipeline_free(p); 203 rte_ring_free(msgq_rsp); 204 rte_ring_free(msgq_req); 205 return NULL; 206 } 207 208 /* Node fill in */ 209 strlcpy(pipeline->name, name, sizeof(pipeline->name)); 210 pipeline->p = p; 211 memcpy(&pipeline->params, params, sizeof(*params)); 212 pipeline->n_ports_in = 0; 213 pipeline->n_ports_out = 0; 214 pipeline->n_tables = 0; 215 pipeline->msgq_req = msgq_req; 216 pipeline->msgq_rsp = msgq_rsp; 217 pipeline->timer_period_ms = params->timer_period_ms; 218 pipeline->enabled = 0; 219 pipeline->cpu_id = softnic->params.cpu_id; 220 221 /* Node add to list */ 222 TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node); 223 224 return pipeline; 225 } 226 227 int 228 softnic_pipeline_port_in_create(struct pmd_internals *softnic, 229 const char *pipeline_name, 230 struct softnic_port_in_params *params, 231 int enabled) 232 { 233 struct rte_pipeline_port_in_params p; 234 235 union { 236 struct rte_port_ethdev_reader_params ethdev; 237 struct rte_port_ring_reader_params ring; 238 struct rte_port_sched_reader_params sched; 239 struct rte_port_fd_reader_params fd; 240 struct rte_port_source_params source; 241 struct rte_port_sym_crypto_reader_params cryptodev; 242 } pp; 243 244 struct pipeline *pipeline; 245 struct softnic_port_in *port_in; 246 struct softnic_port_in_action_profile *ap; 247 struct rte_port_in_action *action; 248 uint32_t port_id; 249 int status; 250 251 memset(&p, 0, sizeof(p)); 252 memset(&pp, 0, sizeof(pp)); 253 254 /* Check input params */ 255 if (pipeline_name == NULL || 256 params == NULL || 257 params->burst_size == 0 || 258 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX) 259 return -1; 260 261 pipeline = softnic_pipeline_find(softnic, pipeline_name); 262 if (pipeline == NULL) 263 return -1; 264 265 ap = NULL; 266 if (strlen(params->action_profile_name)) { 267 ap = softnic_port_in_action_profile_find(softnic, 268 params->action_profile_name); 269 if (ap == NULL) 270 return -1; 271 } 272 273 switch (params->type) { 274 case PORT_IN_RXQ: 275 { 276 struct softnic_link *link; 277 278 link = softnic_link_find(softnic, params->dev_name); 279 if (link == NULL) 280 return -1; 281 282 if (params->rxq.queue_id >= link->n_rxq) 283 return -1; 284 285 pp.ethdev.port_id = link->port_id; 286 pp.ethdev.queue_id = params->rxq.queue_id; 287 288 p.ops = &rte_port_ethdev_reader_ops; 289 p.arg_create = &pp.ethdev; 290 break; 291 } 292 293 case PORT_IN_SWQ: 294 { 295 struct softnic_swq *swq; 296 297 swq = softnic_swq_find(softnic, params->dev_name); 298 if (swq == NULL) 299 return -1; 300 301 pp.ring.ring = swq->r; 302 303 p.ops = &rte_port_ring_reader_ops; 304 p.arg_create = &pp.ring; 305 break; 306 } 307 308 case PORT_IN_TMGR: 309 { 310 struct softnic_tmgr_port *tmgr_port; 311 312 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name); 313 if (tmgr_port == NULL) 314 return -1; 315 316 pp.sched.sched = tmgr_port->s; 317 318 p.ops = &rte_port_sched_reader_ops; 319 p.arg_create = &pp.sched; 320 break; 321 } 322 323 case PORT_IN_TAP: 324 { 325 struct softnic_tap *tap; 326 struct softnic_mempool *mempool; 327 328 tap = softnic_tap_find(softnic, params->dev_name); 329 mempool = softnic_mempool_find(softnic, params->tap.mempool_name); 330 if (tap == NULL || mempool == NULL) 331 return -1; 332 333 pp.fd.fd = tap->fd; 334 pp.fd.mempool = mempool->m; 335 pp.fd.mtu = params->tap.mtu; 336 337 p.ops = &rte_port_fd_reader_ops; 338 p.arg_create = &pp.fd; 339 break; 340 } 341 342 case PORT_IN_SOURCE: 343 { 344 struct softnic_mempool *mempool; 345 346 mempool = softnic_mempool_find(softnic, params->source.mempool_name); 347 if (mempool == NULL) 348 return -1; 349 350 pp.source.mempool = mempool->m; 351 pp.source.file_name = params->source.file_name; 352 pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt; 353 354 p.ops = &rte_port_source_ops; 355 p.arg_create = &pp.source; 356 break; 357 } 358 359 case PORT_IN_CRYPTODEV: 360 { 361 struct softnic_cryptodev *cryptodev; 362 363 cryptodev = softnic_cryptodev_find(softnic, params->dev_name); 364 if (cryptodev == NULL) 365 return -1; 366 367 pp.cryptodev.cryptodev_id = cryptodev->dev_id; 368 pp.cryptodev.queue_id = params->cryptodev.queue_id; 369 pp.cryptodev.f_callback = params->cryptodev.f_callback; 370 pp.cryptodev.arg_callback = params->cryptodev.arg_callback; 371 p.ops = &rte_port_sym_crypto_reader_ops; 372 p.arg_create = &pp.cryptodev; 373 break; 374 } 375 376 default: 377 return -1; 378 } 379 380 p.burst_size = params->burst_size; 381 382 /* Resource create */ 383 action = NULL; 384 p.f_action = NULL; 385 p.arg_ah = NULL; 386 387 if (ap) { 388 action = rte_port_in_action_create(ap->ap, 389 softnic->params.cpu_id); 390 if (action == NULL) 391 return -1; 392 393 status = rte_port_in_action_params_get(action, 394 &p); 395 if (status) { 396 rte_port_in_action_free(action); 397 return -1; 398 } 399 } 400 401 status = rte_pipeline_port_in_create(pipeline->p, 402 &p, 403 &port_id); 404 if (status) { 405 rte_port_in_action_free(action); 406 return -1; 407 } 408 409 if (enabled) 410 rte_pipeline_port_in_enable(pipeline->p, port_id); 411 412 /* Pipeline */ 413 port_in = &pipeline->port_in[pipeline->n_ports_in]; 414 memcpy(&port_in->params, params, sizeof(*params)); 415 port_in->ap = ap; 416 port_in->a = action; 417 pipeline->n_ports_in++; 418 419 return 0; 420 } 421 422 int 423 softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic, 424 const char *pipeline_name, 425 uint32_t port_id, 426 uint32_t table_id) 427 { 428 struct pipeline *pipeline; 429 int status; 430 431 /* Check input params */ 432 if (pipeline_name == NULL) 433 return -1; 434 435 pipeline = softnic_pipeline_find(softnic, pipeline_name); 436 if (pipeline == NULL || 437 port_id >= pipeline->n_ports_in || 438 table_id >= pipeline->n_tables) 439 return -1; 440 441 /* Resource */ 442 status = rte_pipeline_port_in_connect_to_table(pipeline->p, 443 port_id, 444 table_id); 445 446 return status; 447 } 448 449 int 450 softnic_pipeline_port_out_create(struct pmd_internals *softnic, 451 const char *pipeline_name, 452 struct softnic_port_out_params *params) 453 { 454 struct rte_pipeline_port_out_params p; 455 456 union { 457 struct rte_port_ethdev_writer_params ethdev; 458 struct rte_port_ring_writer_params ring; 459 struct rte_port_sched_writer_params sched; 460 struct rte_port_fd_writer_params fd; 461 struct rte_port_sink_params sink; 462 struct rte_port_sym_crypto_writer_params cryptodev; 463 } pp; 464 465 union { 466 struct rte_port_ethdev_writer_nodrop_params ethdev; 467 struct rte_port_ring_writer_nodrop_params ring; 468 struct rte_port_fd_writer_nodrop_params fd; 469 struct rte_port_sym_crypto_writer_nodrop_params cryptodev; 470 } pp_nodrop; 471 472 struct pipeline *pipeline; 473 struct softnic_port_out *port_out; 474 uint32_t port_id; 475 int status; 476 477 memset(&p, 0, sizeof(p)); 478 memset(&pp, 0, sizeof(pp)); 479 memset(&pp_nodrop, 0, sizeof(pp_nodrop)); 480 481 /* Check input params */ 482 if (pipeline_name == NULL || 483 params == NULL || 484 params->burst_size == 0 || 485 params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX) 486 return -1; 487 488 pipeline = softnic_pipeline_find(softnic, pipeline_name); 489 if (pipeline == NULL) 490 return -1; 491 492 switch (params->type) { 493 case PORT_OUT_TXQ: 494 { 495 struct softnic_link *link; 496 497 link = softnic_link_find(softnic, params->dev_name); 498 if (link == NULL) 499 return -1; 500 501 if (params->txq.queue_id >= link->n_txq) 502 return -1; 503 504 pp.ethdev.port_id = link->port_id; 505 pp.ethdev.queue_id = params->txq.queue_id; 506 pp.ethdev.tx_burst_sz = params->burst_size; 507 508 pp_nodrop.ethdev.port_id = link->port_id; 509 pp_nodrop.ethdev.queue_id = params->txq.queue_id; 510 pp_nodrop.ethdev.tx_burst_sz = params->burst_size; 511 pp_nodrop.ethdev.n_retries = params->n_retries; 512 513 if (params->retry == 0) { 514 p.ops = &rte_port_ethdev_writer_ops; 515 p.arg_create = &pp.ethdev; 516 } else { 517 p.ops = &rte_port_ethdev_writer_nodrop_ops; 518 p.arg_create = &pp_nodrop.ethdev; 519 } 520 break; 521 } 522 523 case PORT_OUT_SWQ: 524 { 525 struct softnic_swq *swq; 526 527 swq = softnic_swq_find(softnic, params->dev_name); 528 if (swq == NULL) 529 return -1; 530 531 pp.ring.ring = swq->r; 532 pp.ring.tx_burst_sz = params->burst_size; 533 534 pp_nodrop.ring.ring = swq->r; 535 pp_nodrop.ring.tx_burst_sz = params->burst_size; 536 pp_nodrop.ring.n_retries = params->n_retries; 537 538 if (params->retry == 0) { 539 p.ops = &rte_port_ring_writer_ops; 540 p.arg_create = &pp.ring; 541 } else { 542 p.ops = &rte_port_ring_writer_nodrop_ops; 543 p.arg_create = &pp_nodrop.ring; 544 } 545 break; 546 } 547 548 case PORT_OUT_TMGR: 549 { 550 struct softnic_tmgr_port *tmgr_port; 551 552 tmgr_port = softnic_tmgr_port_find(softnic, params->dev_name); 553 if (tmgr_port == NULL) 554 return -1; 555 556 pp.sched.sched = tmgr_port->s; 557 pp.sched.tx_burst_sz = params->burst_size; 558 559 p.ops = &rte_port_sched_writer_ops; 560 p.arg_create = &pp.sched; 561 break; 562 } 563 564 case PORT_OUT_TAP: 565 { 566 struct softnic_tap *tap; 567 568 tap = softnic_tap_find(softnic, params->dev_name); 569 if (tap == NULL) 570 return -1; 571 572 pp.fd.fd = tap->fd; 573 pp.fd.tx_burst_sz = params->burst_size; 574 575 pp_nodrop.fd.fd = tap->fd; 576 pp_nodrop.fd.tx_burst_sz = params->burst_size; 577 pp_nodrop.fd.n_retries = params->n_retries; 578 579 if (params->retry == 0) { 580 p.ops = &rte_port_fd_writer_ops; 581 p.arg_create = &pp.fd; 582 } else { 583 p.ops = &rte_port_fd_writer_nodrop_ops; 584 p.arg_create = &pp_nodrop.fd; 585 } 586 break; 587 } 588 589 case PORT_OUT_SINK: 590 { 591 pp.sink.file_name = params->sink.file_name; 592 pp.sink.max_n_pkts = params->sink.max_n_pkts; 593 594 p.ops = &rte_port_sink_ops; 595 p.arg_create = &pp.sink; 596 break; 597 } 598 599 case PORT_OUT_CRYPTODEV: 600 { 601 struct softnic_cryptodev *cryptodev; 602 603 cryptodev = softnic_cryptodev_find(softnic, params->dev_name); 604 if (cryptodev == NULL) 605 return -1; 606 607 if (params->cryptodev.queue_id >= cryptodev->n_queues) 608 return -1; 609 610 pp.cryptodev.cryptodev_id = cryptodev->dev_id; 611 pp.cryptodev.queue_id = params->cryptodev.queue_id; 612 pp.cryptodev.tx_burst_sz = params->burst_size; 613 pp.cryptodev.crypto_op_offset = params->cryptodev.op_offset; 614 615 pp_nodrop.cryptodev.cryptodev_id = cryptodev->dev_id; 616 pp_nodrop.cryptodev.queue_id = params->cryptodev.queue_id; 617 pp_nodrop.cryptodev.tx_burst_sz = params->burst_size; 618 pp_nodrop.cryptodev.n_retries = params->retry; 619 pp_nodrop.cryptodev.crypto_op_offset = 620 params->cryptodev.op_offset; 621 622 if (params->retry == 0) { 623 p.ops = &rte_port_sym_crypto_writer_ops; 624 p.arg_create = &pp.cryptodev; 625 } else { 626 p.ops = &rte_port_sym_crypto_writer_nodrop_ops; 627 p.arg_create = &pp_nodrop.cryptodev; 628 } 629 630 break; 631 } 632 633 default: 634 return -1; 635 } 636 637 p.f_action = NULL; 638 p.arg_ah = NULL; 639 640 /* Resource create */ 641 status = rte_pipeline_port_out_create(pipeline->p, 642 &p, 643 &port_id); 644 645 if (status) 646 return -1; 647 648 /* Pipeline */ 649 port_out = &pipeline->port_out[pipeline->n_ports_out]; 650 memcpy(&port_out->params, params, sizeof(*params)); 651 pipeline->n_ports_out++; 652 653 return 0; 654 } 655 656 static const struct rte_acl_field_def table_acl_field_format_ipv4[] = { 657 /* Protocol */ 658 [0] = { 659 .type = RTE_ACL_FIELD_TYPE_BITMASK, 660 .size = sizeof(uint8_t), 661 .field_index = 0, 662 .input_index = 0, 663 .offset = offsetof(struct rte_ipv4_hdr, next_proto_id), 664 }, 665 666 /* Source IP address (IPv4) */ 667 [1] = { 668 .type = RTE_ACL_FIELD_TYPE_MASK, 669 .size = sizeof(uint32_t), 670 .field_index = 1, 671 .input_index = 1, 672 .offset = offsetof(struct rte_ipv4_hdr, src_addr), 673 }, 674 675 /* Destination IP address (IPv4) */ 676 [2] = { 677 .type = RTE_ACL_FIELD_TYPE_MASK, 678 .size = sizeof(uint32_t), 679 .field_index = 2, 680 .input_index = 2, 681 .offset = offsetof(struct rte_ipv4_hdr, dst_addr), 682 }, 683 684 /* Source Port */ 685 [3] = { 686 .type = RTE_ACL_FIELD_TYPE_RANGE, 687 .size = sizeof(uint16_t), 688 .field_index = 3, 689 .input_index = 3, 690 .offset = sizeof(struct rte_ipv4_hdr) + 691 offsetof(struct rte_tcp_hdr, src_port), 692 }, 693 694 /* Destination Port */ 695 [4] = { 696 .type = RTE_ACL_FIELD_TYPE_RANGE, 697 .size = sizeof(uint16_t), 698 .field_index = 4, 699 .input_index = 3, 700 .offset = sizeof(struct rte_ipv4_hdr) + 701 offsetof(struct rte_tcp_hdr, dst_port), 702 }, 703 }; 704 705 static const struct rte_acl_field_def table_acl_field_format_ipv6[] = { 706 /* Protocol */ 707 [0] = { 708 .type = RTE_ACL_FIELD_TYPE_BITMASK, 709 .size = sizeof(uint8_t), 710 .field_index = 0, 711 .input_index = 0, 712 .offset = offsetof(struct rte_ipv6_hdr, proto), 713 }, 714 715 /* Source IP address (IPv6) */ 716 [1] = { 717 .type = RTE_ACL_FIELD_TYPE_MASK, 718 .size = sizeof(uint32_t), 719 .field_index = 1, 720 .input_index = 1, 721 .offset = offsetof(struct rte_ipv6_hdr, src_addr[0]), 722 }, 723 724 [2] = { 725 .type = RTE_ACL_FIELD_TYPE_MASK, 726 .size = sizeof(uint32_t), 727 .field_index = 2, 728 .input_index = 2, 729 .offset = offsetof(struct rte_ipv6_hdr, src_addr[4]), 730 }, 731 732 [3] = { 733 .type = RTE_ACL_FIELD_TYPE_MASK, 734 .size = sizeof(uint32_t), 735 .field_index = 3, 736 .input_index = 3, 737 .offset = offsetof(struct rte_ipv6_hdr, src_addr[8]), 738 }, 739 740 [4] = { 741 .type = RTE_ACL_FIELD_TYPE_MASK, 742 .size = sizeof(uint32_t), 743 .field_index = 4, 744 .input_index = 4, 745 .offset = offsetof(struct rte_ipv6_hdr, src_addr[12]), 746 }, 747 748 /* Destination IP address (IPv6) */ 749 [5] = { 750 .type = RTE_ACL_FIELD_TYPE_MASK, 751 .size = sizeof(uint32_t), 752 .field_index = 5, 753 .input_index = 5, 754 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[0]), 755 }, 756 757 [6] = { 758 .type = RTE_ACL_FIELD_TYPE_MASK, 759 .size = sizeof(uint32_t), 760 .field_index = 6, 761 .input_index = 6, 762 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[4]), 763 }, 764 765 [7] = { 766 .type = RTE_ACL_FIELD_TYPE_MASK, 767 .size = sizeof(uint32_t), 768 .field_index = 7, 769 .input_index = 7, 770 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[8]), 771 }, 772 773 [8] = { 774 .type = RTE_ACL_FIELD_TYPE_MASK, 775 .size = sizeof(uint32_t), 776 .field_index = 8, 777 .input_index = 8, 778 .offset = offsetof(struct rte_ipv6_hdr, dst_addr[12]), 779 }, 780 781 /* Source Port */ 782 [9] = { 783 .type = RTE_ACL_FIELD_TYPE_RANGE, 784 .size = sizeof(uint16_t), 785 .field_index = 9, 786 .input_index = 9, 787 .offset = sizeof(struct rte_ipv6_hdr) + 788 offsetof(struct rte_tcp_hdr, src_port), 789 }, 790 791 /* Destination Port */ 792 [10] = { 793 .type = RTE_ACL_FIELD_TYPE_RANGE, 794 .size = sizeof(uint16_t), 795 .field_index = 10, 796 .input_index = 9, 797 .offset = sizeof(struct rte_ipv6_hdr) + 798 offsetof(struct rte_tcp_hdr, dst_port), 799 }, 800 }; 801 802 int 803 softnic_pipeline_table_create(struct pmd_internals *softnic, 804 const char *pipeline_name, 805 struct softnic_table_params *params) 806 { 807 char name[NAME_MAX]; 808 struct rte_pipeline_table_params p; 809 810 union { 811 struct rte_table_acl_params acl; 812 struct rte_table_array_params array; 813 struct rte_table_hash_params hash; 814 struct rte_table_lpm_params lpm; 815 struct rte_table_lpm_ipv6_params lpm_ipv6; 816 } pp; 817 818 struct pipeline *pipeline; 819 struct softnic_table *table; 820 struct softnic_table_action_profile *ap; 821 struct rte_table_action *action; 822 uint32_t table_id; 823 int status; 824 825 memset(&p, 0, sizeof(p)); 826 memset(&pp, 0, sizeof(pp)); 827 828 /* Check input params */ 829 if (pipeline_name == NULL || 830 params == NULL) 831 return -1; 832 833 pipeline = softnic_pipeline_find(softnic, pipeline_name); 834 if (pipeline == NULL || 835 pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX) 836 return -1; 837 838 ap = NULL; 839 if (strlen(params->action_profile_name)) { 840 ap = softnic_table_action_profile_find(softnic, 841 params->action_profile_name); 842 if (ap == NULL) 843 return -1; 844 } 845 846 snprintf(name, NAME_MAX, "%s_%s_table%u", 847 softnic->params.name, pipeline_name, pipeline->n_tables); 848 849 switch (params->match_type) { 850 case TABLE_ACL: 851 { 852 uint32_t ip_header_offset = params->match.acl.ip_header_offset - 853 (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM); 854 uint32_t i; 855 856 if (params->match.acl.n_rules == 0) 857 return -1; 858 859 pp.acl.name = name; 860 pp.acl.n_rules = params->match.acl.n_rules; 861 if (params->match.acl.ip_version) { 862 memcpy(&pp.acl.field_format, 863 &table_acl_field_format_ipv4, 864 sizeof(table_acl_field_format_ipv4)); 865 pp.acl.n_rule_fields = 866 RTE_DIM(table_acl_field_format_ipv4); 867 } else { 868 memcpy(&pp.acl.field_format, 869 &table_acl_field_format_ipv6, 870 sizeof(table_acl_field_format_ipv6)); 871 pp.acl.n_rule_fields = 872 RTE_DIM(table_acl_field_format_ipv6); 873 } 874 875 for (i = 0; i < pp.acl.n_rule_fields; i++) 876 pp.acl.field_format[i].offset += ip_header_offset; 877 878 p.ops = &rte_table_acl_ops; 879 p.arg_create = &pp.acl; 880 break; 881 } 882 883 case TABLE_ARRAY: 884 { 885 if (params->match.array.n_keys == 0) 886 return -1; 887 888 pp.array.n_entries = params->match.array.n_keys; 889 pp.array.offset = params->match.array.key_offset; 890 891 p.ops = &rte_table_array_ops; 892 p.arg_create = &pp.array; 893 break; 894 } 895 896 case TABLE_HASH: 897 { 898 struct rte_table_ops *ops; 899 rte_table_hash_op_hash f_hash; 900 901 if (params->match.hash.n_keys == 0) 902 return -1; 903 904 switch (params->match.hash.key_size) { 905 case 8: 906 f_hash = rte_table_hash_crc_key8; 907 break; 908 case 16: 909 f_hash = rte_table_hash_crc_key16; 910 break; 911 case 24: 912 f_hash = rte_table_hash_crc_key24; 913 break; 914 case 32: 915 f_hash = rte_table_hash_crc_key32; 916 break; 917 case 40: 918 f_hash = rte_table_hash_crc_key40; 919 break; 920 case 48: 921 f_hash = rte_table_hash_crc_key48; 922 break; 923 case 56: 924 f_hash = rte_table_hash_crc_key56; 925 break; 926 case 64: 927 f_hash = rte_table_hash_crc_key64; 928 break; 929 default: 930 return -1; 931 } 932 933 pp.hash.name = name; 934 pp.hash.key_size = params->match.hash.key_size; 935 pp.hash.key_offset = params->match.hash.key_offset; 936 pp.hash.key_mask = params->match.hash.key_mask; 937 pp.hash.n_keys = params->match.hash.n_keys; 938 pp.hash.n_buckets = params->match.hash.n_buckets; 939 pp.hash.f_hash = f_hash; 940 pp.hash.seed = 0; 941 942 if (params->match.hash.extendable_bucket) 943 switch (params->match.hash.key_size) { 944 case 8: 945 ops = &rte_table_hash_key8_ext_ops; 946 break; 947 case 16: 948 ops = &rte_table_hash_key16_ext_ops; 949 break; 950 default: 951 ops = &rte_table_hash_ext_ops; 952 } 953 else 954 switch (params->match.hash.key_size) { 955 case 8: 956 ops = &rte_table_hash_key8_lru_ops; 957 break; 958 case 16: 959 ops = &rte_table_hash_key16_lru_ops; 960 break; 961 default: 962 ops = &rte_table_hash_lru_ops; 963 } 964 965 p.ops = ops; 966 p.arg_create = &pp.hash; 967 break; 968 } 969 970 case TABLE_LPM: 971 { 972 if (params->match.lpm.n_rules == 0) 973 return -1; 974 975 switch (params->match.lpm.key_size) { 976 case 4: 977 { 978 pp.lpm.name = name; 979 pp.lpm.n_rules = params->match.lpm.n_rules; 980 pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8; 981 pp.lpm.flags = 0; 982 pp.lpm.entry_unique_size = p.action_data_size + 983 sizeof(struct rte_pipeline_table_entry); 984 pp.lpm.offset = params->match.lpm.key_offset; 985 986 p.ops = &rte_table_lpm_ops; 987 p.arg_create = &pp.lpm; 988 break; 989 } 990 991 case 16: 992 { 993 pp.lpm_ipv6.name = name; 994 pp.lpm_ipv6.n_rules = params->match.lpm.n_rules; 995 pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8; 996 pp.lpm_ipv6.entry_unique_size = p.action_data_size + 997 sizeof(struct rte_pipeline_table_entry); 998 pp.lpm_ipv6.offset = params->match.lpm.key_offset; 999 1000 p.ops = &rte_table_lpm_ipv6_ops; 1001 p.arg_create = &pp.lpm_ipv6; 1002 break; 1003 } 1004 1005 default: 1006 return -1; 1007 } 1008 1009 break; 1010 } 1011 1012 case TABLE_STUB: 1013 { 1014 p.ops = &rte_table_stub_ops; 1015 p.arg_create = NULL; 1016 break; 1017 } 1018 1019 default: 1020 return -1; 1021 } 1022 1023 /* Resource create */ 1024 action = NULL; 1025 p.f_action_hit = NULL; 1026 p.f_action_miss = NULL; 1027 p.arg_ah = NULL; 1028 1029 if (ap) { 1030 action = rte_table_action_create(ap->ap, 1031 softnic->params.cpu_id); 1032 if (action == NULL) 1033 return -1; 1034 1035 status = rte_table_action_table_params_get(action, 1036 &p); 1037 if (status || 1038 ((p.action_data_size + 1039 sizeof(struct rte_pipeline_table_entry)) > 1040 TABLE_RULE_ACTION_SIZE_MAX)) { 1041 rte_table_action_free(action); 1042 return -1; 1043 } 1044 } 1045 1046 if (params->match_type == TABLE_LPM) { 1047 if (params->match.lpm.key_size == 4) 1048 pp.lpm.entry_unique_size = p.action_data_size + 1049 sizeof(struct rte_pipeline_table_entry); 1050 1051 if (params->match.lpm.key_size == 16) 1052 pp.lpm_ipv6.entry_unique_size = p.action_data_size + 1053 sizeof(struct rte_pipeline_table_entry); 1054 } 1055 1056 status = rte_pipeline_table_create(pipeline->p, 1057 &p, 1058 &table_id); 1059 if (status) { 1060 rte_table_action_free(action); 1061 return -1; 1062 } 1063 1064 /* Pipeline */ 1065 table = &pipeline->table[pipeline->n_tables]; 1066 memcpy(&table->params, params, sizeof(*params)); 1067 table->ap = ap; 1068 table->a = action; 1069 TAILQ_INIT(&table->flows); 1070 TAILQ_INIT(&table->meter_profiles); 1071 memset(&table->dscp_table, 0, sizeof(table->dscp_table)); 1072 pipeline->n_tables++; 1073 1074 return 0; 1075 } 1076 1077 int 1078 softnic_pipeline_port_out_find(struct pmd_internals *softnic, 1079 const char *pipeline_name, 1080 const char *name, 1081 uint32_t *port_id) 1082 { 1083 struct pipeline *pipeline; 1084 uint32_t i; 1085 1086 if (softnic == NULL || 1087 pipeline_name == NULL || 1088 name == NULL || 1089 port_id == NULL) 1090 return -1; 1091 1092 pipeline = softnic_pipeline_find(softnic, pipeline_name); 1093 if (pipeline == NULL) 1094 return -1; 1095 1096 for (i = 0; i < pipeline->n_ports_out; i++) 1097 if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) { 1098 *port_id = i; 1099 return 0; 1100 } 1101 1102 return -1; 1103 } 1104 1105 struct softnic_table_meter_profile * 1106 softnic_pipeline_table_meter_profile_find(struct softnic_table *table, 1107 uint32_t meter_profile_id) 1108 { 1109 struct softnic_table_meter_profile *mp; 1110 1111 TAILQ_FOREACH(mp, &table->meter_profiles, node) 1112 if (mp->meter_profile_id == meter_profile_id) 1113 return mp; 1114 1115 return NULL; 1116 } 1117