1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 Intel Corporation 3 */ 4 5 #include <stdlib.h> 6 7 #include <rte_common.h> 8 #include <rte_cycles.h> 9 #include <rte_lcore.h> 10 #include <rte_ring.h> 11 12 #include <rte_table_acl.h> 13 #include <rte_table_array.h> 14 #include <rte_table_hash.h> 15 #include <rte_table_lpm.h> 16 #include <rte_table_lpm_ipv6.h> 17 #include "rte_eth_softnic_internals.h" 18 19 /** 20 * Master thread: data plane thread init 21 */ 22 void 23 softnic_thread_free(struct pmd_internals *softnic) 24 { 25 uint32_t i; 26 27 RTE_LCORE_FOREACH_SLAVE(i) { 28 struct softnic_thread *t = &softnic->thread[i]; 29 30 /* MSGQs */ 31 if (t->msgq_req) 32 rte_ring_free(t->msgq_req); 33 34 if (t->msgq_rsp) 35 rte_ring_free(t->msgq_rsp); 36 } 37 } 38 39 int 40 softnic_thread_init(struct pmd_internals *softnic) 41 { 42 uint32_t i; 43 44 RTE_LCORE_FOREACH_SLAVE(i) { 45 char ring_name[NAME_MAX]; 46 struct rte_ring *msgq_req, *msgq_rsp; 47 struct softnic_thread *t = &softnic->thread[i]; 48 struct softnic_thread_data *t_data = &softnic->thread_data[i]; 49 uint32_t cpu_id = rte_lcore_to_socket_id(i); 50 51 /* MSGQs */ 52 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ", 53 softnic->params.name, 54 i); 55 56 msgq_req = rte_ring_create(ring_name, 57 THREAD_MSGQ_SIZE, 58 cpu_id, 59 RING_F_SP_ENQ | RING_F_SC_DEQ); 60 61 if (msgq_req == NULL) { 62 softnic_thread_free(softnic); 63 return -1; 64 } 65 66 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP", 67 softnic->params.name, 68 i); 69 70 msgq_rsp = rte_ring_create(ring_name, 71 THREAD_MSGQ_SIZE, 72 cpu_id, 73 RING_F_SP_ENQ | RING_F_SC_DEQ); 74 75 if (msgq_rsp == NULL) { 76 softnic_thread_free(softnic); 77 return -1; 78 } 79 80 /* Master thread records */ 81 t->msgq_req = msgq_req; 82 t->msgq_rsp = msgq_rsp; 83 t->enabled = 1; 84 85 /* Data plane thread records */ 86 t_data->n_pipelines = 0; 87 t_data->msgq_req = msgq_req; 88 t_data->msgq_rsp = msgq_rsp; 89 t_data->timer_period = 90 (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000; 91 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period; 92 t_data->time_next_min = t_data->time_next; 93 } 94 95 return 0; 96 } 97 98 static inline int 99 thread_is_running(uint32_t thread_id) 100 { 101 enum rte_lcore_state_t thread_state; 102 103 thread_state = rte_eal_get_lcore_state(thread_id); 104 return (thread_state == RUNNING)? 1 : 0; 105 } 106 107 /** 108 * Pipeline is running when: 109 * (A) Pipeline is mapped to a data plane thread AND 110 * (B) Its data plane thread is in RUNNING state. 111 */ 112 static inline int 113 pipeline_is_running(struct pipeline *p) 114 { 115 if (p->enabled == 0) 116 return 0; 117 118 return thread_is_running(p->thread_id); 119 } 120 121 /** 122 * Master thread & data plane threads: message passing 123 */ 124 enum thread_req_type { 125 THREAD_REQ_PIPELINE_ENABLE = 0, 126 THREAD_REQ_PIPELINE_DISABLE, 127 THREAD_REQ_MAX 128 }; 129 130 struct thread_msg_req { 131 enum thread_req_type type; 132 133 union { 134 struct { 135 struct rte_pipeline *p; 136 struct { 137 struct rte_table_action *a; 138 } table[RTE_PIPELINE_TABLE_MAX]; 139 struct rte_ring *msgq_req; 140 struct rte_ring *msgq_rsp; 141 uint32_t timer_period_ms; 142 uint32_t n_tables; 143 } pipeline_enable; 144 145 struct { 146 struct rte_pipeline *p; 147 } pipeline_disable; 148 }; 149 }; 150 151 struct thread_msg_rsp { 152 int status; 153 }; 154 155 /** 156 * Master thread 157 */ 158 static struct thread_msg_req * 159 thread_msg_alloc(void) 160 { 161 size_t size = RTE_MAX(sizeof(struct thread_msg_req), 162 sizeof(struct thread_msg_rsp)); 163 164 return calloc(1, size); 165 } 166 167 static void 168 thread_msg_free(struct thread_msg_rsp *rsp) 169 { 170 free(rsp); 171 } 172 173 static struct thread_msg_rsp * 174 thread_msg_send_recv(struct pmd_internals *softnic, 175 uint32_t thread_id, 176 struct thread_msg_req *req) 177 { 178 struct softnic_thread *t = &softnic->thread[thread_id]; 179 struct rte_ring *msgq_req = t->msgq_req; 180 struct rte_ring *msgq_rsp = t->msgq_rsp; 181 struct thread_msg_rsp *rsp; 182 int status; 183 184 /* send */ 185 do { 186 status = rte_ring_sp_enqueue(msgq_req, req); 187 } while (status == -ENOBUFS); 188 189 /* recv */ 190 do { 191 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp); 192 } while (status != 0); 193 194 return rsp; 195 } 196 197 int 198 softnic_thread_pipeline_enable(struct pmd_internals *softnic, 199 uint32_t thread_id, 200 const char *pipeline_name) 201 { 202 struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name); 203 struct softnic_thread *t; 204 struct thread_msg_req *req; 205 struct thread_msg_rsp *rsp; 206 uint32_t i; 207 int status; 208 209 /* Check input params */ 210 if ((thread_id >= RTE_MAX_LCORE) || 211 (p == NULL) || 212 (p->n_ports_in == 0) || 213 (p->n_ports_out == 0) || 214 (p->n_tables == 0)) 215 return -1; 216 217 t = &softnic->thread[thread_id]; 218 if ((t->enabled == 0) || 219 p->enabled) 220 return -1; 221 222 if (!thread_is_running(thread_id)) { 223 struct softnic_thread_data *td = &softnic->thread_data[thread_id]; 224 struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines]; 225 226 if (td->n_pipelines >= THREAD_PIPELINES_MAX) 227 return -1; 228 229 /* Data plane thread */ 230 td->p[td->n_pipelines] = p->p; 231 232 tdp->p = p->p; 233 for (i = 0; i < p->n_tables; i++) 234 tdp->table_data[i].a = 235 p->table[i].a; 236 tdp->n_tables = p->n_tables; 237 238 tdp->msgq_req = p->msgq_req; 239 tdp->msgq_rsp = p->msgq_rsp; 240 tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000; 241 tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period; 242 243 td->n_pipelines++; 244 245 /* Pipeline */ 246 p->thread_id = thread_id; 247 p->enabled = 1; 248 249 return 0; 250 } 251 252 /* Allocate request */ 253 req = thread_msg_alloc(); 254 if (req == NULL) 255 return -1; 256 257 /* Write request */ 258 req->type = THREAD_REQ_PIPELINE_ENABLE; 259 req->pipeline_enable.p = p->p; 260 for (i = 0; i < p->n_tables; i++) 261 req->pipeline_enable.table[i].a = 262 p->table[i].a; 263 req->pipeline_enable.msgq_req = p->msgq_req; 264 req->pipeline_enable.msgq_rsp = p->msgq_rsp; 265 req->pipeline_enable.timer_period_ms = p->timer_period_ms; 266 req->pipeline_enable.n_tables = p->n_tables; 267 268 /* Send request and wait for response */ 269 rsp = thread_msg_send_recv(softnic, thread_id, req); 270 if (rsp == NULL) 271 return -1; 272 273 /* Read response */ 274 status = rsp->status; 275 276 /* Free response */ 277 thread_msg_free(rsp); 278 279 /* Request completion */ 280 if (status) 281 return status; 282 283 p->thread_id = thread_id; 284 p->enabled = 1; 285 286 return 0; 287 } 288 289 int 290 softnic_thread_pipeline_disable(struct pmd_internals *softnic, 291 uint32_t thread_id, 292 const char *pipeline_name) 293 { 294 struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name); 295 struct softnic_thread *t; 296 struct thread_msg_req *req; 297 struct thread_msg_rsp *rsp; 298 int status; 299 300 /* Check input params */ 301 if ((thread_id >= RTE_MAX_LCORE) || 302 (p == NULL)) 303 return -1; 304 305 t = &softnic->thread[thread_id]; 306 if (t->enabled == 0) 307 return -1; 308 309 if (p->enabled == 0) 310 return 0; 311 312 if (p->thread_id != thread_id) 313 return -1; 314 315 if (!thread_is_running(thread_id)) { 316 struct softnic_thread_data *td = &softnic->thread_data[thread_id]; 317 uint32_t i; 318 319 for (i = 0; i < td->n_pipelines; i++) { 320 struct pipeline_data *tdp = &td->pipeline_data[i]; 321 322 if (tdp->p != p->p) 323 continue; 324 325 /* Data plane thread */ 326 if (i < td->n_pipelines - 1) { 327 struct rte_pipeline *pipeline_last = 328 td->p[td->n_pipelines - 1]; 329 struct pipeline_data *tdp_last = 330 &td->pipeline_data[td->n_pipelines - 1]; 331 332 td->p[i] = pipeline_last; 333 memcpy(tdp, tdp_last, sizeof(*tdp)); 334 } 335 336 td->n_pipelines--; 337 338 /* Pipeline */ 339 p->enabled = 0; 340 341 break; 342 } 343 344 return 0; 345 } 346 347 /* Allocate request */ 348 req = thread_msg_alloc(); 349 if (req == NULL) 350 return -1; 351 352 /* Write request */ 353 req->type = THREAD_REQ_PIPELINE_DISABLE; 354 req->pipeline_disable.p = p->p; 355 356 /* Send request and wait for response */ 357 rsp = thread_msg_send_recv(softnic, thread_id, req); 358 if (rsp == NULL) 359 return -1; 360 361 /* Read response */ 362 status = rsp->status; 363 364 /* Free response */ 365 thread_msg_free(rsp); 366 367 /* Request completion */ 368 if (status) 369 return status; 370 371 p->enabled = 0; 372 373 return 0; 374 } 375 376 /** 377 * Data plane threads: message handling 378 */ 379 static inline struct thread_msg_req * 380 thread_msg_recv(struct rte_ring *msgq_req) 381 { 382 struct thread_msg_req *req; 383 384 int status = rte_ring_sc_dequeue(msgq_req, (void **)&req); 385 386 if (status != 0) 387 return NULL; 388 389 return req; 390 } 391 392 static inline void 393 thread_msg_send(struct rte_ring *msgq_rsp, 394 struct thread_msg_rsp *rsp) 395 { 396 int status; 397 398 do { 399 status = rte_ring_sp_enqueue(msgq_rsp, rsp); 400 } while (status == -ENOBUFS); 401 } 402 403 static struct thread_msg_rsp * 404 thread_msg_handle_pipeline_enable(struct softnic_thread_data *t, 405 struct thread_msg_req *req) 406 { 407 struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req; 408 struct pipeline_data *p = &t->pipeline_data[t->n_pipelines]; 409 uint32_t i; 410 411 /* Request */ 412 if (t->n_pipelines >= THREAD_PIPELINES_MAX) { 413 rsp->status = -1; 414 return rsp; 415 } 416 417 t->p[t->n_pipelines] = req->pipeline_enable.p; 418 419 p->p = req->pipeline_enable.p; 420 for (i = 0; i < req->pipeline_enable.n_tables; i++) 421 p->table_data[i].a = 422 req->pipeline_enable.table[i].a; 423 424 p->n_tables = req->pipeline_enable.n_tables; 425 426 p->msgq_req = req->pipeline_enable.msgq_req; 427 p->msgq_rsp = req->pipeline_enable.msgq_rsp; 428 p->timer_period = 429 (rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000; 430 p->time_next = rte_get_tsc_cycles() + p->timer_period; 431 432 t->n_pipelines++; 433 434 /* Response */ 435 rsp->status = 0; 436 return rsp; 437 } 438 439 static struct thread_msg_rsp * 440 thread_msg_handle_pipeline_disable(struct softnic_thread_data *t, 441 struct thread_msg_req *req) 442 { 443 struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req; 444 uint32_t n_pipelines = t->n_pipelines; 445 struct rte_pipeline *pipeline = req->pipeline_disable.p; 446 uint32_t i; 447 448 /* find pipeline */ 449 for (i = 0; i < n_pipelines; i++) { 450 struct pipeline_data *p = &t->pipeline_data[i]; 451 452 if (p->p != pipeline) 453 continue; 454 455 if (i < n_pipelines - 1) { 456 struct rte_pipeline *pipeline_last = 457 t->p[n_pipelines - 1]; 458 struct pipeline_data *p_last = 459 &t->pipeline_data[n_pipelines - 1]; 460 461 t->p[i] = pipeline_last; 462 memcpy(p, p_last, sizeof(*p)); 463 } 464 465 t->n_pipelines--; 466 467 rsp->status = 0; 468 return rsp; 469 } 470 471 /* should not get here */ 472 rsp->status = 0; 473 return rsp; 474 } 475 476 static void 477 thread_msg_handle(struct softnic_thread_data *t) 478 { 479 for ( ; ; ) { 480 struct thread_msg_req *req; 481 struct thread_msg_rsp *rsp; 482 483 req = thread_msg_recv(t->msgq_req); 484 if (req == NULL) 485 break; 486 487 switch (req->type) { 488 case THREAD_REQ_PIPELINE_ENABLE: 489 rsp = thread_msg_handle_pipeline_enable(t, req); 490 break; 491 492 case THREAD_REQ_PIPELINE_DISABLE: 493 rsp = thread_msg_handle_pipeline_disable(t, req); 494 break; 495 496 default: 497 rsp = (struct thread_msg_rsp *)req; 498 rsp->status = -1; 499 } 500 501 thread_msg_send(t->msgq_rsp, rsp); 502 } 503 } 504 505 /** 506 * Master thread & data plane threads: message passing 507 */ 508 enum pipeline_req_type { 509 /* Port IN */ 510 PIPELINE_REQ_PORT_IN_STATS_READ, 511 PIPELINE_REQ_PORT_IN_ENABLE, 512 PIPELINE_REQ_PORT_IN_DISABLE, 513 514 /* Port OUT */ 515 PIPELINE_REQ_PORT_OUT_STATS_READ, 516 517 /* Table */ 518 PIPELINE_REQ_TABLE_STATS_READ, 519 PIPELINE_REQ_TABLE_RULE_ADD, 520 PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT, 521 PIPELINE_REQ_TABLE_RULE_ADD_BULK, 522 PIPELINE_REQ_TABLE_RULE_DELETE, 523 PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT, 524 PIPELINE_REQ_TABLE_RULE_STATS_READ, 525 PIPELINE_REQ_TABLE_MTR_PROFILE_ADD, 526 PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE, 527 PIPELINE_REQ_TABLE_RULE_MTR_READ, 528 PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE, 529 PIPELINE_REQ_TABLE_RULE_TTL_READ, 530 PIPELINE_REQ_MAX 531 }; 532 533 struct pipeline_msg_req_port_in_stats_read { 534 int clear; 535 }; 536 537 struct pipeline_msg_req_port_out_stats_read { 538 int clear; 539 }; 540 541 struct pipeline_msg_req_table_stats_read { 542 int clear; 543 }; 544 545 struct pipeline_msg_req_table_rule_add { 546 struct softnic_table_rule_match match; 547 struct softnic_table_rule_action action; 548 }; 549 550 struct pipeline_msg_req_table_rule_add_default { 551 struct softnic_table_rule_action action; 552 }; 553 554 struct pipeline_msg_req_table_rule_add_bulk { 555 struct softnic_table_rule_match *match; 556 struct softnic_table_rule_action *action; 557 void **data; 558 uint32_t n_rules; 559 int bulk; 560 }; 561 562 struct pipeline_msg_req_table_rule_delete { 563 struct softnic_table_rule_match match; 564 }; 565 566 struct pipeline_msg_req_table_rule_stats_read { 567 void *data; 568 int clear; 569 }; 570 571 struct pipeline_msg_req_table_mtr_profile_add { 572 uint32_t meter_profile_id; 573 struct rte_table_action_meter_profile profile; 574 }; 575 576 struct pipeline_msg_req_table_mtr_profile_delete { 577 uint32_t meter_profile_id; 578 }; 579 580 struct pipeline_msg_req_table_rule_mtr_read { 581 void *data; 582 uint32_t tc_mask; 583 int clear; 584 }; 585 586 struct pipeline_msg_req_table_dscp_table_update { 587 uint64_t dscp_mask; 588 struct rte_table_action_dscp_table dscp_table; 589 }; 590 591 struct pipeline_msg_req_table_rule_ttl_read { 592 void *data; 593 int clear; 594 }; 595 596 struct pipeline_msg_req { 597 enum pipeline_req_type type; 598 uint32_t id; /* Port IN, port OUT or table ID */ 599 600 RTE_STD_C11 601 union { 602 struct pipeline_msg_req_port_in_stats_read port_in_stats_read; 603 struct pipeline_msg_req_port_out_stats_read port_out_stats_read; 604 struct pipeline_msg_req_table_stats_read table_stats_read; 605 struct pipeline_msg_req_table_rule_add table_rule_add; 606 struct pipeline_msg_req_table_rule_add_default table_rule_add_default; 607 struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk; 608 struct pipeline_msg_req_table_rule_delete table_rule_delete; 609 struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read; 610 struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add; 611 struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete; 612 struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read; 613 struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update; 614 struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read; 615 }; 616 }; 617 618 struct pipeline_msg_rsp_port_in_stats_read { 619 struct rte_pipeline_port_in_stats stats; 620 }; 621 622 struct pipeline_msg_rsp_port_out_stats_read { 623 struct rte_pipeline_port_out_stats stats; 624 }; 625 626 struct pipeline_msg_rsp_table_stats_read { 627 struct rte_pipeline_table_stats stats; 628 }; 629 630 struct pipeline_msg_rsp_table_rule_add { 631 void *data; 632 }; 633 634 struct pipeline_msg_rsp_table_rule_add_default { 635 void *data; 636 }; 637 638 struct pipeline_msg_rsp_table_rule_add_bulk { 639 uint32_t n_rules; 640 }; 641 642 struct pipeline_msg_rsp_table_rule_stats_read { 643 struct rte_table_action_stats_counters stats; 644 }; 645 646 struct pipeline_msg_rsp_table_rule_mtr_read { 647 struct rte_table_action_mtr_counters stats; 648 }; 649 650 struct pipeline_msg_rsp_table_rule_ttl_read { 651 struct rte_table_action_ttl_counters stats; 652 }; 653 654 struct pipeline_msg_rsp { 655 int status; 656 657 RTE_STD_C11 658 union { 659 struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read; 660 struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read; 661 struct pipeline_msg_rsp_table_stats_read table_stats_read; 662 struct pipeline_msg_rsp_table_rule_add table_rule_add; 663 struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default; 664 struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk; 665 struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read; 666 struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read; 667 struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read; 668 }; 669 }; 670 671 /** 672 * Master thread 673 */ 674 static struct pipeline_msg_req * 675 pipeline_msg_alloc(void) 676 { 677 size_t size = RTE_MAX(sizeof(struct pipeline_msg_req), 678 sizeof(struct pipeline_msg_rsp)); 679 680 return calloc(1, size); 681 } 682 683 static void 684 pipeline_msg_free(struct pipeline_msg_rsp *rsp) 685 { 686 free(rsp); 687 } 688 689 static struct pipeline_msg_rsp * 690 pipeline_msg_send_recv(struct pipeline *p, 691 struct pipeline_msg_req *req) 692 { 693 struct rte_ring *msgq_req = p->msgq_req; 694 struct rte_ring *msgq_rsp = p->msgq_rsp; 695 struct pipeline_msg_rsp *rsp; 696 int status; 697 698 /* send */ 699 do { 700 status = rte_ring_sp_enqueue(msgq_req, req); 701 } while (status == -ENOBUFS); 702 703 /* recv */ 704 do { 705 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp); 706 } while (status != 0); 707 708 return rsp; 709 } 710 711 int 712 softnic_pipeline_port_in_stats_read(struct pmd_internals *softnic, 713 const char *pipeline_name, 714 uint32_t port_id, 715 struct rte_pipeline_port_in_stats *stats, 716 int clear) 717 { 718 struct pipeline *p; 719 struct pipeline_msg_req *req; 720 struct pipeline_msg_rsp *rsp; 721 int status; 722 723 /* Check input params */ 724 if (pipeline_name == NULL || 725 stats == NULL) 726 return -1; 727 728 p = softnic_pipeline_find(softnic, pipeline_name); 729 if (p == NULL || 730 port_id >= p->n_ports_in) 731 return -1; 732 733 if (!pipeline_is_running(p)) { 734 status = rte_pipeline_port_in_stats_read(p->p, 735 port_id, 736 stats, 737 clear); 738 739 return status; 740 } 741 742 /* Allocate request */ 743 req = pipeline_msg_alloc(); 744 if (req == NULL) 745 return -1; 746 747 /* Write request */ 748 req->type = PIPELINE_REQ_PORT_IN_STATS_READ; 749 req->id = port_id; 750 req->port_in_stats_read.clear = clear; 751 752 /* Send request and wait for response */ 753 rsp = pipeline_msg_send_recv(p, req); 754 if (rsp == NULL) 755 return -1; 756 757 /* Read response */ 758 status = rsp->status; 759 if (status) 760 memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats)); 761 762 /* Free response */ 763 pipeline_msg_free(rsp); 764 765 return status; 766 } 767 768 int 769 softnic_pipeline_port_in_enable(struct pmd_internals *softnic, 770 const char *pipeline_name, 771 uint32_t port_id) 772 { 773 struct pipeline *p; 774 struct pipeline_msg_req *req; 775 struct pipeline_msg_rsp *rsp; 776 int status; 777 778 /* Check input params */ 779 if (pipeline_name == NULL) 780 return -1; 781 782 p = softnic_pipeline_find(softnic, pipeline_name); 783 if (p == NULL || 784 port_id >= p->n_ports_in) 785 return -1; 786 787 if (!pipeline_is_running(p)) { 788 status = rte_pipeline_port_in_enable(p->p, port_id); 789 return status; 790 } 791 792 /* Allocate request */ 793 req = pipeline_msg_alloc(); 794 if (req == NULL) 795 return -1; 796 797 /* Write request */ 798 req->type = PIPELINE_REQ_PORT_IN_ENABLE; 799 req->id = port_id; 800 801 /* Send request and wait for response */ 802 rsp = pipeline_msg_send_recv(p, req); 803 if (rsp == NULL) 804 return -1; 805 806 /* Read response */ 807 status = rsp->status; 808 809 /* Free response */ 810 pipeline_msg_free(rsp); 811 812 return status; 813 } 814 815 int 816 softnic_pipeline_port_in_disable(struct pmd_internals *softnic, 817 const char *pipeline_name, 818 uint32_t port_id) 819 { 820 struct pipeline *p; 821 struct pipeline_msg_req *req; 822 struct pipeline_msg_rsp *rsp; 823 int status; 824 825 /* Check input params */ 826 if (pipeline_name == NULL) 827 return -1; 828 829 p = softnic_pipeline_find(softnic, pipeline_name); 830 if (p == NULL || 831 port_id >= p->n_ports_in) 832 return -1; 833 834 if (!pipeline_is_running(p)) { 835 status = rte_pipeline_port_in_disable(p->p, port_id); 836 return status; 837 } 838 839 /* Allocate request */ 840 req = pipeline_msg_alloc(); 841 if (req == NULL) 842 return -1; 843 844 /* Write request */ 845 req->type = PIPELINE_REQ_PORT_IN_DISABLE; 846 req->id = port_id; 847 848 /* Send request and wait for response */ 849 rsp = pipeline_msg_send_recv(p, req); 850 if (rsp == NULL) 851 return -1; 852 853 /* Read response */ 854 status = rsp->status; 855 856 /* Free response */ 857 pipeline_msg_free(rsp); 858 859 return status; 860 } 861 862 int 863 softnic_pipeline_port_out_stats_read(struct pmd_internals *softnic, 864 const char *pipeline_name, 865 uint32_t port_id, 866 struct rte_pipeline_port_out_stats *stats, 867 int clear) 868 { 869 struct pipeline *p; 870 struct pipeline_msg_req *req; 871 struct pipeline_msg_rsp *rsp; 872 int status; 873 874 /* Check input params */ 875 if (pipeline_name == NULL || 876 stats == NULL) 877 return -1; 878 879 p = softnic_pipeline_find(softnic, pipeline_name); 880 if (p == NULL || 881 port_id >= p->n_ports_out) 882 return -1; 883 884 if (!pipeline_is_running(p)) { 885 status = rte_pipeline_port_out_stats_read(p->p, 886 port_id, 887 stats, 888 clear); 889 890 return status; 891 } 892 893 /* Allocate request */ 894 req = pipeline_msg_alloc(); 895 if (req == NULL) 896 return -1; 897 898 /* Write request */ 899 req->type = PIPELINE_REQ_PORT_OUT_STATS_READ; 900 req->id = port_id; 901 req->port_out_stats_read.clear = clear; 902 903 /* Send request and wait for response */ 904 rsp = pipeline_msg_send_recv(p, req); 905 if (rsp == NULL) 906 return -1; 907 908 /* Read response */ 909 status = rsp->status; 910 if (status) 911 memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats)); 912 913 /* Free response */ 914 pipeline_msg_free(rsp); 915 916 return status; 917 } 918 919 int 920 softnic_pipeline_table_stats_read(struct pmd_internals *softnic, 921 const char *pipeline_name, 922 uint32_t table_id, 923 struct rte_pipeline_table_stats *stats, 924 int clear) 925 { 926 struct pipeline *p; 927 struct pipeline_msg_req *req; 928 struct pipeline_msg_rsp *rsp; 929 int status; 930 931 /* Check input params */ 932 if (pipeline_name == NULL || 933 stats == NULL) 934 return -1; 935 936 p = softnic_pipeline_find(softnic, pipeline_name); 937 if (p == NULL || 938 table_id >= p->n_tables) 939 return -1; 940 941 if (!pipeline_is_running(p)) { 942 status = rte_pipeline_table_stats_read(p->p, 943 table_id, 944 stats, 945 clear); 946 947 return status; 948 } 949 950 /* Allocate request */ 951 req = pipeline_msg_alloc(); 952 if (req == NULL) 953 return -1; 954 955 /* Write request */ 956 req->type = PIPELINE_REQ_TABLE_STATS_READ; 957 req->id = table_id; 958 req->table_stats_read.clear = clear; 959 960 /* Send request and wait for response */ 961 rsp = pipeline_msg_send_recv(p, req); 962 if (rsp == NULL) 963 return -1; 964 965 /* Read response */ 966 status = rsp->status; 967 if (status) 968 memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats)); 969 970 /* Free response */ 971 pipeline_msg_free(rsp); 972 973 return status; 974 } 975 976 static int 977 match_check(struct softnic_table_rule_match *match, 978 struct pipeline *p, 979 uint32_t table_id) 980 { 981 struct softnic_table *table; 982 983 if (match == NULL || 984 p == NULL || 985 table_id >= p->n_tables) 986 return -1; 987 988 table = &p->table[table_id]; 989 if (match->match_type != table->params.match_type) 990 return -1; 991 992 switch (match->match_type) { 993 case TABLE_ACL: 994 { 995 struct softnic_table_acl_params *t = &table->params.match.acl; 996 struct softnic_table_rule_match_acl *r = &match->match.acl; 997 998 if ((r->ip_version && (t->ip_version == 0)) || 999 ((r->ip_version == 0) && t->ip_version)) 1000 return -1; 1001 1002 if (r->ip_version) { 1003 if (r->sa_depth > 32 || 1004 r->da_depth > 32) 1005 return -1; 1006 } else { 1007 if (r->sa_depth > 128 || 1008 r->da_depth > 128) 1009 return -1; 1010 } 1011 return 0; 1012 } 1013 1014 case TABLE_ARRAY: 1015 return 0; 1016 1017 case TABLE_HASH: 1018 return 0; 1019 1020 case TABLE_LPM: 1021 { 1022 struct softnic_table_lpm_params *t = &table->params.match.lpm; 1023 struct softnic_table_rule_match_lpm *r = &match->match.lpm; 1024 1025 if ((r->ip_version && (t->key_size != 4)) || 1026 ((r->ip_version == 0) && (t->key_size != 16))) 1027 return -1; 1028 1029 if (r->ip_version) { 1030 if (r->depth > 32) 1031 return -1; 1032 } else { 1033 if (r->depth > 128) 1034 return -1; 1035 } 1036 return 0; 1037 } 1038 1039 case TABLE_STUB: 1040 return -1; 1041 1042 default: 1043 return -1; 1044 } 1045 } 1046 1047 static int 1048 action_check(struct softnic_table_rule_action *action, 1049 struct pipeline *p, 1050 uint32_t table_id) 1051 { 1052 struct softnic_table_action_profile *ap; 1053 1054 if (action == NULL || 1055 p == NULL || 1056 table_id >= p->n_tables) 1057 return -1; 1058 1059 ap = p->table[table_id].ap; 1060 if (action->action_mask != ap->params.action_mask) 1061 return -1; 1062 1063 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) { 1064 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT && 1065 action->fwd.id >= p->n_ports_out) 1066 return -1; 1067 1068 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE && 1069 action->fwd.id >= p->n_tables) 1070 return -1; 1071 } 1072 1073 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) { 1074 uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1; 1075 uint32_t tc_mask1 = action->mtr.tc_mask; 1076 1077 if (tc_mask1 != tc_mask0) 1078 return -1; 1079 } 1080 1081 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) { 1082 uint32_t n_subports_per_port = 1083 ap->params.tm.n_subports_per_port; 1084 uint32_t n_pipes_per_subport = 1085 ap->params.tm.n_pipes_per_subport; 1086 uint32_t subport_id = action->tm.subport_id; 1087 uint32_t pipe_id = action->tm.pipe_id; 1088 1089 if (subport_id >= n_subports_per_port || 1090 pipe_id >= n_pipes_per_subport) 1091 return -1; 1092 } 1093 1094 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) { 1095 uint64_t encap_mask = ap->params.encap.encap_mask; 1096 enum rte_table_action_encap_type type = action->encap.type; 1097 1098 if ((encap_mask & (1LLU << type)) == 0) 1099 return -1; 1100 } 1101 1102 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { 1103 int ip_version0 = ap->params.common.ip_version; 1104 int ip_version1 = action->nat.ip_version; 1105 1106 if ((ip_version1 && (ip_version0 == 0)) || 1107 ((ip_version1 == 0) && ip_version0)) 1108 return -1; 1109 } 1110 1111 return 0; 1112 } 1113 1114 static int 1115 action_default_check(struct softnic_table_rule_action *action, 1116 struct pipeline *p, 1117 uint32_t table_id) 1118 { 1119 if (action == NULL || 1120 action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD) || 1121 p == NULL || 1122 table_id >= p->n_tables) 1123 return -1; 1124 1125 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) { 1126 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT && 1127 action->fwd.id >= p->n_ports_out) 1128 return -1; 1129 1130 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE && 1131 action->fwd.id >= p->n_tables) 1132 return -1; 1133 } 1134 1135 return 0; 1136 } 1137 1138 union table_rule_match_low_level { 1139 struct rte_table_acl_rule_add_params acl_add; 1140 struct rte_table_acl_rule_delete_params acl_delete; 1141 struct rte_table_array_key array; 1142 uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX]; 1143 struct rte_table_lpm_key lpm_ipv4; 1144 struct rte_table_lpm_ipv6_key lpm_ipv6; 1145 }; 1146 1147 static int 1148 match_convert(struct softnic_table_rule_match *mh, 1149 union table_rule_match_low_level *ml, 1150 int add); 1151 1152 static int 1153 action_convert(struct rte_table_action *a, 1154 struct softnic_table_rule_action *action, 1155 struct rte_pipeline_table_entry *data); 1156 1157 int 1158 softnic_pipeline_table_rule_add(struct pmd_internals *softnic, 1159 const char *pipeline_name, 1160 uint32_t table_id, 1161 struct softnic_table_rule_match *match, 1162 struct softnic_table_rule_action *action, 1163 void **data) 1164 { 1165 struct pipeline *p; 1166 struct pipeline_msg_req *req; 1167 struct pipeline_msg_rsp *rsp; 1168 int status; 1169 1170 /* Check input params */ 1171 if (pipeline_name == NULL || 1172 match == NULL || 1173 action == NULL || 1174 data == NULL) 1175 return -1; 1176 1177 p = softnic_pipeline_find(softnic, pipeline_name); 1178 if (p == NULL || 1179 table_id >= p->n_tables || 1180 match_check(match, p, table_id) || 1181 action_check(action, p, table_id)) 1182 return -1; 1183 1184 if (!pipeline_is_running(p)) { 1185 struct rte_table_action *a = p->table[table_id].a; 1186 union table_rule_match_low_level match_ll; 1187 struct rte_pipeline_table_entry *data_in, *data_out; 1188 int key_found; 1189 uint8_t *buffer; 1190 1191 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t)); 1192 if (buffer == NULL) 1193 return -1; 1194 1195 /* Table match-action rule conversion */ 1196 data_in = (struct rte_pipeline_table_entry *)buffer; 1197 1198 status = match_convert(match, &match_ll, 1); 1199 if (status) { 1200 free(buffer); 1201 return -1; 1202 } 1203 1204 status = action_convert(a, action, data_in); 1205 if (status) { 1206 free(buffer); 1207 return -1; 1208 } 1209 1210 /* Add rule (match, action) to table */ 1211 status = rte_pipeline_table_entry_add(p->p, 1212 table_id, 1213 &match_ll, 1214 data_in, 1215 &key_found, 1216 &data_out); 1217 if (status) { 1218 free(buffer); 1219 return -1; 1220 } 1221 1222 /* Write Response */ 1223 *data = data_out; 1224 1225 free(buffer); 1226 return 0; 1227 } 1228 1229 /* Allocate request */ 1230 req = pipeline_msg_alloc(); 1231 if (req == NULL) 1232 return -1; 1233 1234 /* Write request */ 1235 req->type = PIPELINE_REQ_TABLE_RULE_ADD; 1236 req->id = table_id; 1237 memcpy(&req->table_rule_add.match, match, sizeof(*match)); 1238 memcpy(&req->table_rule_add.action, action, sizeof(*action)); 1239 1240 /* Send request and wait for response */ 1241 rsp = pipeline_msg_send_recv(p, req); 1242 if (rsp == NULL) 1243 return -1; 1244 1245 /* Read response */ 1246 status = rsp->status; 1247 if (status == 0) 1248 *data = rsp->table_rule_add.data; 1249 1250 /* Free response */ 1251 pipeline_msg_free(rsp); 1252 1253 return status; 1254 } 1255 1256 int 1257 softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic, 1258 const char *pipeline_name, 1259 uint32_t table_id, 1260 struct softnic_table_rule_action *action, 1261 void **data) 1262 { 1263 struct pipeline *p; 1264 struct pipeline_msg_req *req; 1265 struct pipeline_msg_rsp *rsp; 1266 int status; 1267 1268 /* Check input params */ 1269 if (pipeline_name == NULL || 1270 action == NULL || 1271 data == NULL) 1272 return -1; 1273 1274 p = softnic_pipeline_find(softnic, pipeline_name); 1275 if (p == NULL || 1276 table_id >= p->n_tables || 1277 action_default_check(action, p, table_id)) 1278 return -1; 1279 1280 if (!pipeline_is_running(p)) { 1281 struct rte_pipeline_table_entry *data_in, *data_out; 1282 uint8_t *buffer; 1283 1284 buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t)); 1285 if (buffer == NULL) 1286 return -1; 1287 1288 /* Apply actions */ 1289 data_in = (struct rte_pipeline_table_entry *)buffer; 1290 1291 data_in->action = action->fwd.action; 1292 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT) 1293 data_in->port_id = action->fwd.id; 1294 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE) 1295 data_in->table_id = action->fwd.id; 1296 1297 /* Add default rule to table */ 1298 status = rte_pipeline_table_default_entry_add(p->p, 1299 table_id, 1300 data_in, 1301 &data_out); 1302 if (status) { 1303 free(buffer); 1304 return -1; 1305 } 1306 1307 /* Write Response */ 1308 *data = data_out; 1309 1310 free(buffer); 1311 return 0; 1312 } 1313 1314 /* Allocate request */ 1315 req = pipeline_msg_alloc(); 1316 if (req == NULL) 1317 return -1; 1318 1319 /* Write request */ 1320 req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT; 1321 req->id = table_id; 1322 memcpy(&req->table_rule_add_default.action, action, sizeof(*action)); 1323 1324 /* Send request and wait for response */ 1325 rsp = pipeline_msg_send_recv(p, req); 1326 if (rsp == NULL) 1327 return -1; 1328 1329 /* Read response */ 1330 status = rsp->status; 1331 if (status == 0) 1332 *data = rsp->table_rule_add_default.data; 1333 1334 /* Free response */ 1335 pipeline_msg_free(rsp); 1336 1337 return status; 1338 } 1339 1340 int 1341 softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic, 1342 const char *pipeline_name, 1343 uint32_t table_id, 1344 struct softnic_table_rule_match *match, 1345 struct softnic_table_rule_action *action, 1346 void **data, 1347 uint32_t *n_rules) 1348 { 1349 struct pipeline *p; 1350 struct pipeline_msg_req *req; 1351 struct pipeline_msg_rsp *rsp; 1352 uint32_t i; 1353 int status; 1354 1355 /* Check input params */ 1356 if (pipeline_name == NULL || 1357 match == NULL || 1358 action == NULL || 1359 data == NULL || 1360 n_rules == NULL || 1361 (*n_rules == 0)) 1362 return -1; 1363 1364 p = softnic_pipeline_find(softnic, pipeline_name); 1365 if (p == NULL || 1366 table_id >= p->n_tables) 1367 return -1; 1368 1369 for (i = 0; i < *n_rules; i++) 1370 if (match_check(match, p, table_id) || 1371 action_check(action, p, table_id)) 1372 return -1; 1373 1374 if (!pipeline_is_running(p)) { 1375 struct rte_table_action *a = p->table[table_id].a; 1376 union table_rule_match_low_level *match_ll; 1377 uint8_t *action_ll; 1378 void **match_ll_ptr; 1379 struct rte_pipeline_table_entry **action_ll_ptr; 1380 struct rte_pipeline_table_entry **entries_ptr = 1381 (struct rte_pipeline_table_entry **)data; 1382 uint32_t bulk = 1383 (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0; 1384 int *found; 1385 1386 /* Memory allocation */ 1387 match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level)); 1388 action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX); 1389 match_ll_ptr = calloc(*n_rules, sizeof(void *)); 1390 action_ll_ptr = 1391 calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *)); 1392 found = calloc(*n_rules, sizeof(int)); 1393 1394 if (match_ll == NULL || 1395 action_ll == NULL || 1396 match_ll_ptr == NULL || 1397 action_ll_ptr == NULL || 1398 found == NULL) 1399 goto fail; 1400 1401 for (i = 0; i < *n_rules; i++) { 1402 match_ll_ptr[i] = (void *)&match_ll[i]; 1403 action_ll_ptr[i] = 1404 (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX]; 1405 } 1406 1407 /* Rule match conversion */ 1408 for (i = 0; i < *n_rules; i++) { 1409 status = match_convert(&match[i], match_ll_ptr[i], 1); 1410 if (status) 1411 goto fail; 1412 } 1413 1414 /* Rule action conversion */ 1415 for (i = 0; i < *n_rules; i++) { 1416 status = action_convert(a, &action[i], action_ll_ptr[i]); 1417 if (status) 1418 goto fail; 1419 } 1420 1421 /* Add rule (match, action) to table */ 1422 if (bulk) { 1423 status = rte_pipeline_table_entry_add_bulk(p->p, 1424 table_id, 1425 match_ll_ptr, 1426 action_ll_ptr, 1427 *n_rules, 1428 found, 1429 entries_ptr); 1430 if (status) 1431 *n_rules = 0; 1432 } else { 1433 for (i = 0; i < *n_rules; i++) { 1434 status = rte_pipeline_table_entry_add(p->p, 1435 table_id, 1436 match_ll_ptr[i], 1437 action_ll_ptr[i], 1438 &found[i], 1439 &entries_ptr[i]); 1440 if (status) { 1441 *n_rules = i; 1442 break; 1443 } 1444 } 1445 } 1446 1447 /* Free */ 1448 free(found); 1449 free(action_ll_ptr); 1450 free(match_ll_ptr); 1451 free(action_ll); 1452 free(match_ll); 1453 1454 return status; 1455 1456 fail: 1457 free(found); 1458 free(action_ll_ptr); 1459 free(match_ll_ptr); 1460 free(action_ll); 1461 free(match_ll); 1462 1463 *n_rules = 0; 1464 return -1; 1465 } 1466 1467 /* Allocate request */ 1468 req = pipeline_msg_alloc(); 1469 if (req == NULL) 1470 return -1; 1471 1472 /* Write request */ 1473 req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK; 1474 req->id = table_id; 1475 req->table_rule_add_bulk.match = match; 1476 req->table_rule_add_bulk.action = action; 1477 req->table_rule_add_bulk.data = data; 1478 req->table_rule_add_bulk.n_rules = *n_rules; 1479 req->table_rule_add_bulk.bulk = 1480 (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0; 1481 1482 /* Send request and wait for response */ 1483 rsp = pipeline_msg_send_recv(p, req); 1484 if (rsp == NULL) 1485 return -1; 1486 1487 /* Read response */ 1488 status = rsp->status; 1489 if (status == 0) 1490 *n_rules = rsp->table_rule_add_bulk.n_rules; 1491 1492 /* Free response */ 1493 pipeline_msg_free(rsp); 1494 1495 return status; 1496 } 1497 1498 int 1499 softnic_pipeline_table_rule_delete(struct pmd_internals *softnic, 1500 const char *pipeline_name, 1501 uint32_t table_id, 1502 struct softnic_table_rule_match *match) 1503 { 1504 struct pipeline *p; 1505 struct pipeline_msg_req *req; 1506 struct pipeline_msg_rsp *rsp; 1507 int status; 1508 1509 /* Check input params */ 1510 if (pipeline_name == NULL || 1511 match == NULL) 1512 return -1; 1513 1514 p = softnic_pipeline_find(softnic, pipeline_name); 1515 if (p == NULL || 1516 table_id >= p->n_tables || 1517 match_check(match, p, table_id)) 1518 return -1; 1519 1520 if (!pipeline_is_running(p)) { 1521 union table_rule_match_low_level match_ll; 1522 int key_found; 1523 1524 status = match_convert(match, &match_ll, 0); 1525 if (status) 1526 return -1; 1527 1528 status = rte_pipeline_table_entry_delete(p->p, 1529 table_id, 1530 &match_ll, 1531 &key_found, 1532 NULL); 1533 1534 return status; 1535 } 1536 1537 /* Allocate request */ 1538 req = pipeline_msg_alloc(); 1539 if (req == NULL) 1540 return -1; 1541 1542 /* Write request */ 1543 req->type = PIPELINE_REQ_TABLE_RULE_DELETE; 1544 req->id = table_id; 1545 memcpy(&req->table_rule_delete.match, match, sizeof(*match)); 1546 1547 /* Send request and wait for response */ 1548 rsp = pipeline_msg_send_recv(p, req); 1549 if (rsp == NULL) 1550 return -1; 1551 1552 /* Read response */ 1553 status = rsp->status; 1554 1555 /* Free response */ 1556 pipeline_msg_free(rsp); 1557 1558 return status; 1559 } 1560 1561 int 1562 softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic, 1563 const char *pipeline_name, 1564 uint32_t table_id) 1565 { 1566 struct pipeline *p; 1567 struct pipeline_msg_req *req; 1568 struct pipeline_msg_rsp *rsp; 1569 int status; 1570 1571 /* Check input params */ 1572 if (pipeline_name == NULL) 1573 return -1; 1574 1575 p = softnic_pipeline_find(softnic, pipeline_name); 1576 if (p == NULL || 1577 table_id >= p->n_tables) 1578 return -1; 1579 1580 if (!pipeline_is_running(p)) { 1581 status = rte_pipeline_table_default_entry_delete(p->p, 1582 table_id, 1583 NULL); 1584 1585 return status; 1586 } 1587 1588 /* Allocate request */ 1589 req = pipeline_msg_alloc(); 1590 if (req == NULL) 1591 return -1; 1592 1593 /* Write request */ 1594 req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT; 1595 req->id = table_id; 1596 1597 /* Send request and wait for response */ 1598 rsp = pipeline_msg_send_recv(p, req); 1599 if (rsp == NULL) 1600 return -1; 1601 1602 /* Read response */ 1603 status = rsp->status; 1604 1605 /* Free response */ 1606 pipeline_msg_free(rsp); 1607 1608 return status; 1609 } 1610 1611 int 1612 softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic, 1613 const char *pipeline_name, 1614 uint32_t table_id, 1615 void *data, 1616 struct rte_table_action_stats_counters *stats, 1617 int clear) 1618 { 1619 struct pipeline *p; 1620 struct pipeline_msg_req *req; 1621 struct pipeline_msg_rsp *rsp; 1622 int status; 1623 1624 /* Check input params */ 1625 if (pipeline_name == NULL || 1626 data == NULL || 1627 stats == NULL) 1628 return -1; 1629 1630 p = softnic_pipeline_find(softnic, pipeline_name); 1631 if (p == NULL || 1632 table_id >= p->n_tables) 1633 return -1; 1634 1635 if (!pipeline_is_running(p)) { 1636 struct rte_table_action *a = p->table[table_id].a; 1637 1638 status = rte_table_action_stats_read(a, 1639 data, 1640 stats, 1641 clear); 1642 1643 return status; 1644 } 1645 1646 /* Allocate request */ 1647 req = pipeline_msg_alloc(); 1648 if (req == NULL) 1649 return -1; 1650 1651 /* Write request */ 1652 req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ; 1653 req->id = table_id; 1654 req->table_rule_stats_read.data = data; 1655 req->table_rule_stats_read.clear = clear; 1656 1657 /* Send request and wait for response */ 1658 rsp = pipeline_msg_send_recv(p, req); 1659 if (rsp == NULL) 1660 return -1; 1661 1662 /* Read response */ 1663 status = rsp->status; 1664 if (status) 1665 memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats)); 1666 1667 /* Free response */ 1668 pipeline_msg_free(rsp); 1669 1670 return status; 1671 } 1672 1673 int 1674 softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic, 1675 const char *pipeline_name, 1676 uint32_t table_id, 1677 uint32_t meter_profile_id, 1678 struct rte_table_action_meter_profile *profile) 1679 { 1680 struct pipeline *p; 1681 struct pipeline_msg_req *req; 1682 struct pipeline_msg_rsp *rsp; 1683 struct softnic_table *table; 1684 struct softnic_table_meter_profile *mp; 1685 int status; 1686 1687 /* Check input params */ 1688 if (pipeline_name == NULL || 1689 profile == NULL) 1690 return -1; 1691 1692 p = softnic_pipeline_find(softnic, pipeline_name); 1693 if (p == NULL || 1694 table_id >= p->n_tables) 1695 return -1; 1696 1697 table = &p->table[table_id]; 1698 mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id); 1699 if (mp) 1700 return -1; 1701 1702 /* Resource Allocation */ 1703 mp = calloc(1, sizeof(struct softnic_table_meter_profile)); 1704 if (mp == NULL) 1705 return -1; 1706 1707 mp->meter_profile_id = meter_profile_id; 1708 memcpy(&mp->profile, profile, sizeof(mp->profile)); 1709 1710 if (!pipeline_is_running(p)) { 1711 status = rte_table_action_meter_profile_add(table->a, 1712 meter_profile_id, 1713 profile); 1714 if (status) { 1715 free(mp); 1716 return status; 1717 } 1718 1719 /* Add profile to the table. */ 1720 TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node); 1721 1722 return status; 1723 } 1724 1725 /* Allocate request */ 1726 req = pipeline_msg_alloc(); 1727 if (req == NULL) { 1728 free(mp); 1729 return -1; 1730 } 1731 1732 /* Write request */ 1733 req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD; 1734 req->id = table_id; 1735 req->table_mtr_profile_add.meter_profile_id = meter_profile_id; 1736 memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile)); 1737 1738 /* Send request and wait for response */ 1739 rsp = pipeline_msg_send_recv(p, req); 1740 if (rsp == NULL) { 1741 free(mp); 1742 return -1; 1743 } 1744 1745 /* Read response */ 1746 status = rsp->status; 1747 if (status == 0) 1748 TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node); 1749 else 1750 free(mp); 1751 1752 /* Free response */ 1753 pipeline_msg_free(rsp); 1754 1755 return status; 1756 } 1757 1758 int 1759 softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *softnic, 1760 const char *pipeline_name, 1761 uint32_t table_id, 1762 uint32_t meter_profile_id) 1763 { 1764 struct pipeline *p; 1765 struct pipeline_msg_req *req; 1766 struct pipeline_msg_rsp *rsp; 1767 int status; 1768 1769 /* Check input params */ 1770 if (pipeline_name == NULL) 1771 return -1; 1772 1773 p = softnic_pipeline_find(softnic, pipeline_name); 1774 if (p == NULL || 1775 table_id >= p->n_tables) 1776 return -1; 1777 1778 if (!pipeline_is_running(p)) { 1779 struct rte_table_action *a = p->table[table_id].a; 1780 1781 status = rte_table_action_meter_profile_delete(a, 1782 meter_profile_id); 1783 1784 return status; 1785 } 1786 1787 /* Allocate request */ 1788 req = pipeline_msg_alloc(); 1789 if (req == NULL) 1790 return -1; 1791 1792 /* Write request */ 1793 req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE; 1794 req->id = table_id; 1795 req->table_mtr_profile_delete.meter_profile_id = meter_profile_id; 1796 1797 /* Send request and wait for response */ 1798 rsp = pipeline_msg_send_recv(p, req); 1799 if (rsp == NULL) 1800 return -1; 1801 1802 /* Read response */ 1803 status = rsp->status; 1804 1805 /* Free response */ 1806 pipeline_msg_free(rsp); 1807 1808 return status; 1809 } 1810 1811 int 1812 softnic_pipeline_table_rule_mtr_read(struct pmd_internals *softnic, 1813 const char *pipeline_name, 1814 uint32_t table_id, 1815 void *data, 1816 uint32_t tc_mask, 1817 struct rte_table_action_mtr_counters *stats, 1818 int clear) 1819 { 1820 struct pipeline *p; 1821 struct pipeline_msg_req *req; 1822 struct pipeline_msg_rsp *rsp; 1823 int status; 1824 1825 /* Check input params */ 1826 if (pipeline_name == NULL || 1827 data == NULL || 1828 stats == NULL) 1829 return -1; 1830 1831 p = softnic_pipeline_find(softnic, pipeline_name); 1832 if (p == NULL || 1833 table_id >= p->n_tables) 1834 return -1; 1835 1836 if (!pipeline_is_running(p)) { 1837 struct rte_table_action *a = p->table[table_id].a; 1838 1839 status = rte_table_action_meter_read(a, 1840 data, 1841 tc_mask, 1842 stats, 1843 clear); 1844 1845 return status; 1846 } 1847 1848 /* Allocate request */ 1849 req = pipeline_msg_alloc(); 1850 if (req == NULL) 1851 return -1; 1852 1853 /* Write request */ 1854 req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ; 1855 req->id = table_id; 1856 req->table_rule_mtr_read.data = data; 1857 req->table_rule_mtr_read.tc_mask = tc_mask; 1858 req->table_rule_mtr_read.clear = clear; 1859 1860 /* Send request and wait for response */ 1861 rsp = pipeline_msg_send_recv(p, req); 1862 if (rsp == NULL) 1863 return -1; 1864 1865 /* Read response */ 1866 status = rsp->status; 1867 if (status) 1868 memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats)); 1869 1870 /* Free response */ 1871 pipeline_msg_free(rsp); 1872 1873 return status; 1874 } 1875 1876 int 1877 softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic, 1878 const char *pipeline_name, 1879 uint32_t table_id, 1880 uint64_t dscp_mask, 1881 struct rte_table_action_dscp_table *dscp_table) 1882 { 1883 struct pipeline *p; 1884 struct pipeline_msg_req *req; 1885 struct pipeline_msg_rsp *rsp; 1886 int status; 1887 1888 /* Check input params */ 1889 if (pipeline_name == NULL || 1890 dscp_table == NULL) 1891 return -1; 1892 1893 p = softnic_pipeline_find(softnic, pipeline_name); 1894 if (p == NULL || 1895 table_id >= p->n_tables) 1896 return -1; 1897 1898 if (!pipeline_is_running(p)) { 1899 struct rte_table_action *a = p->table[table_id].a; 1900 1901 status = rte_table_action_dscp_table_update(a, 1902 dscp_mask, 1903 dscp_table); 1904 1905 /* Update table dscp table */ 1906 if (!status) 1907 memcpy(&p->table[table_id].dscp_table, dscp_table, 1908 sizeof(p->table[table_id].dscp_table)); 1909 1910 return status; 1911 } 1912 1913 /* Allocate request */ 1914 req = pipeline_msg_alloc(); 1915 if (req == NULL) 1916 return -1; 1917 1918 /* Write request */ 1919 req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE; 1920 req->id = table_id; 1921 req->table_dscp_table_update.dscp_mask = dscp_mask; 1922 memcpy(&req->table_dscp_table_update.dscp_table, 1923 dscp_table, sizeof(*dscp_table)); 1924 1925 /* Send request and wait for response */ 1926 rsp = pipeline_msg_send_recv(p, req); 1927 if (rsp == NULL) 1928 return -1; 1929 1930 /* Read response */ 1931 status = rsp->status; 1932 1933 /* Update table dscp table */ 1934 if (!status) 1935 memcpy(&p->table[table_id].dscp_table, dscp_table, 1936 sizeof(p->table[table_id].dscp_table)); 1937 1938 /* Free response */ 1939 pipeline_msg_free(rsp); 1940 1941 return status; 1942 } 1943 1944 int 1945 softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic, 1946 const char *pipeline_name, 1947 uint32_t table_id, 1948 void *data, 1949 struct rte_table_action_ttl_counters *stats, 1950 int clear) 1951 { 1952 struct pipeline *p; 1953 struct pipeline_msg_req *req; 1954 struct pipeline_msg_rsp *rsp; 1955 int status; 1956 1957 /* Check input params */ 1958 if (pipeline_name == NULL || 1959 data == NULL || 1960 stats == NULL) 1961 return -1; 1962 1963 p = softnic_pipeline_find(softnic, pipeline_name); 1964 if (p == NULL || 1965 table_id >= p->n_tables) 1966 return -1; 1967 1968 if (!pipeline_is_running(p)) { 1969 struct rte_table_action *a = p->table[table_id].a; 1970 1971 status = rte_table_action_ttl_read(a, 1972 data, 1973 stats, 1974 clear); 1975 1976 return status; 1977 } 1978 1979 /* Allocate request */ 1980 req = pipeline_msg_alloc(); 1981 if (req == NULL) 1982 return -1; 1983 1984 /* Write request */ 1985 req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ; 1986 req->id = table_id; 1987 req->table_rule_ttl_read.data = data; 1988 req->table_rule_ttl_read.clear = clear; 1989 1990 /* Send request and wait for response */ 1991 rsp = pipeline_msg_send_recv(p, req); 1992 if (rsp == NULL) 1993 return -1; 1994 1995 /* Read response */ 1996 status = rsp->status; 1997 if (status) 1998 memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats)); 1999 2000 /* Free response */ 2001 pipeline_msg_free(rsp); 2002 2003 return status; 2004 } 2005 2006 /** 2007 * Data plane threads: message handling 2008 */ 2009 static inline struct pipeline_msg_req * 2010 pipeline_msg_recv(struct rte_ring *msgq_req) 2011 { 2012 struct pipeline_msg_req *req; 2013 2014 int status = rte_ring_sc_dequeue(msgq_req, (void **)&req); 2015 2016 if (status != 0) 2017 return NULL; 2018 2019 return req; 2020 } 2021 2022 static inline void 2023 pipeline_msg_send(struct rte_ring *msgq_rsp, 2024 struct pipeline_msg_rsp *rsp) 2025 { 2026 int status; 2027 2028 do { 2029 status = rte_ring_sp_enqueue(msgq_rsp, rsp); 2030 } while (status == -ENOBUFS); 2031 } 2032 2033 static struct pipeline_msg_rsp * 2034 pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p, 2035 struct pipeline_msg_req *req) 2036 { 2037 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2038 uint32_t port_id = req->id; 2039 int clear = req->port_in_stats_read.clear; 2040 2041 rsp->status = rte_pipeline_port_in_stats_read(p->p, 2042 port_id, 2043 &rsp->port_in_stats_read.stats, 2044 clear); 2045 2046 return rsp; 2047 } 2048 2049 static struct pipeline_msg_rsp * 2050 pipeline_msg_handle_port_in_enable(struct pipeline_data *p, 2051 struct pipeline_msg_req *req) 2052 { 2053 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2054 uint32_t port_id = req->id; 2055 2056 rsp->status = rte_pipeline_port_in_enable(p->p, 2057 port_id); 2058 2059 return rsp; 2060 } 2061 2062 static struct pipeline_msg_rsp * 2063 pipeline_msg_handle_port_in_disable(struct pipeline_data *p, 2064 struct pipeline_msg_req *req) 2065 { 2066 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2067 uint32_t port_id = req->id; 2068 2069 rsp->status = rte_pipeline_port_in_disable(p->p, 2070 port_id); 2071 2072 return rsp; 2073 } 2074 2075 static struct pipeline_msg_rsp * 2076 pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p, 2077 struct pipeline_msg_req *req) 2078 { 2079 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2080 uint32_t port_id = req->id; 2081 int clear = req->port_out_stats_read.clear; 2082 2083 rsp->status = rte_pipeline_port_out_stats_read(p->p, 2084 port_id, 2085 &rsp->port_out_stats_read.stats, 2086 clear); 2087 2088 return rsp; 2089 } 2090 2091 static struct pipeline_msg_rsp * 2092 pipeline_msg_handle_table_stats_read(struct pipeline_data *p, 2093 struct pipeline_msg_req *req) 2094 { 2095 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2096 uint32_t port_id = req->id; 2097 int clear = req->table_stats_read.clear; 2098 2099 rsp->status = rte_pipeline_table_stats_read(p->p, 2100 port_id, 2101 &rsp->table_stats_read.stats, 2102 clear); 2103 2104 return rsp; 2105 } 2106 2107 static int 2108 match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32) 2109 { 2110 if (depth > 128) 2111 return -1; 2112 2113 switch (depth / 32) { 2114 case 0: 2115 depth32[0] = depth; 2116 depth32[1] = 0; 2117 depth32[2] = 0; 2118 depth32[3] = 0; 2119 return 0; 2120 2121 case 1: 2122 depth32[0] = 32; 2123 depth32[1] = depth - 32; 2124 depth32[2] = 0; 2125 depth32[3] = 0; 2126 return 0; 2127 2128 case 2: 2129 depth32[0] = 32; 2130 depth32[1] = 32; 2131 depth32[2] = depth - 64; 2132 depth32[3] = 0; 2133 return 0; 2134 2135 case 3: 2136 depth32[0] = 32; 2137 depth32[1] = 32; 2138 depth32[2] = 32; 2139 depth32[3] = depth - 96; 2140 return 0; 2141 2142 case 4: 2143 depth32[0] = 32; 2144 depth32[1] = 32; 2145 depth32[2] = 32; 2146 depth32[3] = 32; 2147 return 0; 2148 2149 default: 2150 return -1; 2151 } 2152 } 2153 2154 static int 2155 match_convert(struct softnic_table_rule_match *mh, 2156 union table_rule_match_low_level *ml, 2157 int add) 2158 { 2159 memset(ml, 0, sizeof(*ml)); 2160 2161 switch (mh->match_type) { 2162 case TABLE_ACL: 2163 if (mh->match.acl.ip_version) 2164 if (add) { 2165 ml->acl_add.field_value[0].value.u8 = 2166 mh->match.acl.proto; 2167 ml->acl_add.field_value[0].mask_range.u8 = 2168 mh->match.acl.proto_mask; 2169 2170 ml->acl_add.field_value[1].value.u32 = 2171 mh->match.acl.ipv4.sa; 2172 ml->acl_add.field_value[1].mask_range.u32 = 2173 mh->match.acl.sa_depth; 2174 2175 ml->acl_add.field_value[2].value.u32 = 2176 mh->match.acl.ipv4.da; 2177 ml->acl_add.field_value[2].mask_range.u32 = 2178 mh->match.acl.da_depth; 2179 2180 ml->acl_add.field_value[3].value.u16 = 2181 mh->match.acl.sp0; 2182 ml->acl_add.field_value[3].mask_range.u16 = 2183 mh->match.acl.sp1; 2184 2185 ml->acl_add.field_value[4].value.u16 = 2186 mh->match.acl.dp0; 2187 ml->acl_add.field_value[4].mask_range.u16 = 2188 mh->match.acl.dp1; 2189 2190 ml->acl_add.priority = 2191 (int32_t)mh->match.acl.priority; 2192 } else { 2193 ml->acl_delete.field_value[0].value.u8 = 2194 mh->match.acl.proto; 2195 ml->acl_delete.field_value[0].mask_range.u8 = 2196 mh->match.acl.proto_mask; 2197 2198 ml->acl_delete.field_value[1].value.u32 = 2199 mh->match.acl.ipv4.sa; 2200 ml->acl_delete.field_value[1].mask_range.u32 = 2201 mh->match.acl.sa_depth; 2202 2203 ml->acl_delete.field_value[2].value.u32 = 2204 mh->match.acl.ipv4.da; 2205 ml->acl_delete.field_value[2].mask_range.u32 = 2206 mh->match.acl.da_depth; 2207 2208 ml->acl_delete.field_value[3].value.u16 = 2209 mh->match.acl.sp0; 2210 ml->acl_delete.field_value[3].mask_range.u16 = 2211 mh->match.acl.sp1; 2212 2213 ml->acl_delete.field_value[4].value.u16 = 2214 mh->match.acl.dp0; 2215 ml->acl_delete.field_value[4].mask_range.u16 = 2216 mh->match.acl.dp1; 2217 } 2218 else 2219 if (add) { 2220 uint32_t *sa32 = 2221 (uint32_t *)mh->match.acl.ipv6.sa; 2222 uint32_t *da32 = 2223 (uint32_t *)mh->match.acl.ipv6.da; 2224 uint32_t sa32_depth[4], da32_depth[4]; 2225 int status; 2226 2227 status = match_convert_ipv6_depth(mh->match.acl.sa_depth, 2228 sa32_depth); 2229 if (status) 2230 return status; 2231 2232 status = match_convert_ipv6_depth( 2233 mh->match.acl.da_depth, 2234 da32_depth); 2235 if (status) 2236 return status; 2237 2238 ml->acl_add.field_value[0].value.u8 = 2239 mh->match.acl.proto; 2240 ml->acl_add.field_value[0].mask_range.u8 = 2241 mh->match.acl.proto_mask; 2242 2243 ml->acl_add.field_value[1].value.u32 = 2244 rte_be_to_cpu_32(sa32[0]); 2245 ml->acl_add.field_value[1].mask_range.u32 = 2246 sa32_depth[0]; 2247 ml->acl_add.field_value[2].value.u32 = 2248 rte_be_to_cpu_32(sa32[1]); 2249 ml->acl_add.field_value[2].mask_range.u32 = 2250 sa32_depth[1]; 2251 ml->acl_add.field_value[3].value.u32 = 2252 rte_be_to_cpu_32(sa32[2]); 2253 ml->acl_add.field_value[3].mask_range.u32 = 2254 sa32_depth[2]; 2255 ml->acl_add.field_value[4].value.u32 = 2256 rte_be_to_cpu_32(sa32[3]); 2257 ml->acl_add.field_value[4].mask_range.u32 = 2258 sa32_depth[3]; 2259 2260 ml->acl_add.field_value[5].value.u32 = 2261 rte_be_to_cpu_32(da32[0]); 2262 ml->acl_add.field_value[5].mask_range.u32 = 2263 da32_depth[0]; 2264 ml->acl_add.field_value[6].value.u32 = 2265 rte_be_to_cpu_32(da32[1]); 2266 ml->acl_add.field_value[6].mask_range.u32 = 2267 da32_depth[1]; 2268 ml->acl_add.field_value[7].value.u32 = 2269 rte_be_to_cpu_32(da32[2]); 2270 ml->acl_add.field_value[7].mask_range.u32 = 2271 da32_depth[2]; 2272 ml->acl_add.field_value[8].value.u32 = 2273 rte_be_to_cpu_32(da32[3]); 2274 ml->acl_add.field_value[8].mask_range.u32 = 2275 da32_depth[3]; 2276 2277 ml->acl_add.field_value[9].value.u16 = 2278 mh->match.acl.sp0; 2279 ml->acl_add.field_value[9].mask_range.u16 = 2280 mh->match.acl.sp1; 2281 2282 ml->acl_add.field_value[10].value.u16 = 2283 mh->match.acl.dp0; 2284 ml->acl_add.field_value[10].mask_range.u16 = 2285 mh->match.acl.dp1; 2286 2287 ml->acl_add.priority = 2288 (int32_t)mh->match.acl.priority; 2289 } else { 2290 uint32_t *sa32 = 2291 (uint32_t *)mh->match.acl.ipv6.sa; 2292 uint32_t *da32 = 2293 (uint32_t *)mh->match.acl.ipv6.da; 2294 uint32_t sa32_depth[4], da32_depth[4]; 2295 int status; 2296 2297 status = match_convert_ipv6_depth(mh->match.acl.sa_depth, 2298 sa32_depth); 2299 if (status) 2300 return status; 2301 2302 status = match_convert_ipv6_depth(mh->match.acl.da_depth, 2303 da32_depth); 2304 if (status) 2305 return status; 2306 2307 ml->acl_delete.field_value[0].value.u8 = 2308 mh->match.acl.proto; 2309 ml->acl_delete.field_value[0].mask_range.u8 = 2310 mh->match.acl.proto_mask; 2311 2312 ml->acl_delete.field_value[1].value.u32 = 2313 rte_be_to_cpu_32(sa32[0]); 2314 ml->acl_delete.field_value[1].mask_range.u32 = 2315 sa32_depth[0]; 2316 ml->acl_delete.field_value[2].value.u32 = 2317 rte_be_to_cpu_32(sa32[1]); 2318 ml->acl_delete.field_value[2].mask_range.u32 = 2319 sa32_depth[1]; 2320 ml->acl_delete.field_value[3].value.u32 = 2321 rte_be_to_cpu_32(sa32[2]); 2322 ml->acl_delete.field_value[3].mask_range.u32 = 2323 sa32_depth[2]; 2324 ml->acl_delete.field_value[4].value.u32 = 2325 rte_be_to_cpu_32(sa32[3]); 2326 ml->acl_delete.field_value[4].mask_range.u32 = 2327 sa32_depth[3]; 2328 2329 ml->acl_delete.field_value[5].value.u32 = 2330 rte_be_to_cpu_32(da32[0]); 2331 ml->acl_delete.field_value[5].mask_range.u32 = 2332 da32_depth[0]; 2333 ml->acl_delete.field_value[6].value.u32 = 2334 rte_be_to_cpu_32(da32[1]); 2335 ml->acl_delete.field_value[6].mask_range.u32 = 2336 da32_depth[1]; 2337 ml->acl_delete.field_value[7].value.u32 = 2338 rte_be_to_cpu_32(da32[2]); 2339 ml->acl_delete.field_value[7].mask_range.u32 = 2340 da32_depth[2]; 2341 ml->acl_delete.field_value[8].value.u32 = 2342 rte_be_to_cpu_32(da32[3]); 2343 ml->acl_delete.field_value[8].mask_range.u32 = 2344 da32_depth[3]; 2345 2346 ml->acl_delete.field_value[9].value.u16 = 2347 mh->match.acl.sp0; 2348 ml->acl_delete.field_value[9].mask_range.u16 = 2349 mh->match.acl.sp1; 2350 2351 ml->acl_delete.field_value[10].value.u16 = 2352 mh->match.acl.dp0; 2353 ml->acl_delete.field_value[10].mask_range.u16 = 2354 mh->match.acl.dp1; 2355 } 2356 return 0; 2357 2358 case TABLE_ARRAY: 2359 ml->array.pos = mh->match.array.pos; 2360 return 0; 2361 2362 case TABLE_HASH: 2363 memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash)); 2364 return 0; 2365 2366 case TABLE_LPM: 2367 if (mh->match.lpm.ip_version) { 2368 ml->lpm_ipv4.ip = mh->match.lpm.ipv4; 2369 ml->lpm_ipv4.depth = mh->match.lpm.depth; 2370 } else { 2371 memcpy(ml->lpm_ipv6.ip, 2372 mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip)); 2373 ml->lpm_ipv6.depth = mh->match.lpm.depth; 2374 } 2375 2376 return 0; 2377 2378 default: 2379 return -1; 2380 } 2381 } 2382 2383 static int 2384 action_convert(struct rte_table_action *a, 2385 struct softnic_table_rule_action *action, 2386 struct rte_pipeline_table_entry *data) 2387 { 2388 int status; 2389 2390 /* Apply actions */ 2391 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) { 2392 status = rte_table_action_apply(a, 2393 data, 2394 RTE_TABLE_ACTION_FWD, 2395 &action->fwd); 2396 2397 if (status) 2398 return status; 2399 } 2400 2401 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) { 2402 status = rte_table_action_apply(a, 2403 data, 2404 RTE_TABLE_ACTION_LB, 2405 &action->lb); 2406 2407 if (status) 2408 return status; 2409 } 2410 2411 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) { 2412 status = rte_table_action_apply(a, 2413 data, 2414 RTE_TABLE_ACTION_MTR, 2415 &action->mtr); 2416 2417 if (status) 2418 return status; 2419 } 2420 2421 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) { 2422 status = rte_table_action_apply(a, 2423 data, 2424 RTE_TABLE_ACTION_TM, 2425 &action->tm); 2426 2427 if (status) 2428 return status; 2429 } 2430 2431 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) { 2432 status = rte_table_action_apply(a, 2433 data, 2434 RTE_TABLE_ACTION_ENCAP, 2435 &action->encap); 2436 2437 if (status) 2438 return status; 2439 } 2440 2441 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { 2442 status = rte_table_action_apply(a, 2443 data, 2444 RTE_TABLE_ACTION_NAT, 2445 &action->nat); 2446 2447 if (status) 2448 return status; 2449 } 2450 2451 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) { 2452 status = rte_table_action_apply(a, 2453 data, 2454 RTE_TABLE_ACTION_TTL, 2455 &action->ttl); 2456 2457 if (status) 2458 return status; 2459 } 2460 2461 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) { 2462 status = rte_table_action_apply(a, 2463 data, 2464 RTE_TABLE_ACTION_STATS, 2465 &action->stats); 2466 2467 if (status) 2468 return status; 2469 } 2470 2471 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) { 2472 status = rte_table_action_apply(a, 2473 data, 2474 RTE_TABLE_ACTION_TIME, 2475 &action->time); 2476 2477 if (status) 2478 return status; 2479 } 2480 2481 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) { 2482 status = rte_table_action_apply(a, 2483 data, 2484 RTE_TABLE_ACTION_TAG, 2485 &action->tag); 2486 2487 if (status) 2488 return status; 2489 } 2490 2491 if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) { 2492 status = rte_table_action_apply(a, 2493 data, 2494 RTE_TABLE_ACTION_DECAP, 2495 &action->decap); 2496 2497 if (status) 2498 return status; 2499 } 2500 2501 return 0; 2502 } 2503 2504 static struct pipeline_msg_rsp * 2505 pipeline_msg_handle_table_rule_add(struct pipeline_data *p, 2506 struct pipeline_msg_req *req) 2507 { 2508 union table_rule_match_low_level match_ll; 2509 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2510 struct softnic_table_rule_match *match = &req->table_rule_add.match; 2511 struct softnic_table_rule_action *action = &req->table_rule_add.action; 2512 struct rte_pipeline_table_entry *data_in, *data_out; 2513 uint32_t table_id = req->id; 2514 int key_found, status; 2515 struct rte_table_action *a = p->table_data[table_id].a; 2516 2517 /* Apply actions */ 2518 memset(p->buffer, 0, sizeof(p->buffer)); 2519 data_in = (struct rte_pipeline_table_entry *)p->buffer; 2520 2521 status = match_convert(match, &match_ll, 1); 2522 if (status) { 2523 rsp->status = -1; 2524 return rsp; 2525 } 2526 2527 status = action_convert(a, action, data_in); 2528 if (status) { 2529 rsp->status = -1; 2530 return rsp; 2531 } 2532 2533 status = rte_pipeline_table_entry_add(p->p, 2534 table_id, 2535 &match_ll, 2536 data_in, 2537 &key_found, 2538 &data_out); 2539 if (status) { 2540 rsp->status = -1; 2541 return rsp; 2542 } 2543 2544 /* Write response */ 2545 rsp->status = 0; 2546 rsp->table_rule_add.data = data_out; 2547 2548 return rsp; 2549 } 2550 2551 static struct pipeline_msg_rsp * 2552 pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p, 2553 struct pipeline_msg_req *req) 2554 { 2555 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2556 struct softnic_table_rule_action *action = &req->table_rule_add_default.action; 2557 struct rte_pipeline_table_entry *data_in, *data_out; 2558 uint32_t table_id = req->id; 2559 int status; 2560 2561 /* Apply actions */ 2562 memset(p->buffer, 0, sizeof(p->buffer)); 2563 data_in = (struct rte_pipeline_table_entry *)p->buffer; 2564 2565 data_in->action = action->fwd.action; 2566 if (action->fwd.action == RTE_PIPELINE_ACTION_PORT) 2567 data_in->port_id = action->fwd.id; 2568 if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE) 2569 data_in->table_id = action->fwd.id; 2570 2571 /* Add default rule to table */ 2572 status = rte_pipeline_table_default_entry_add(p->p, 2573 table_id, 2574 data_in, 2575 &data_out); 2576 if (status) { 2577 rsp->status = -1; 2578 return rsp; 2579 } 2580 2581 /* Write response */ 2582 rsp->status = 0; 2583 rsp->table_rule_add_default.data = data_out; 2584 2585 return rsp; 2586 } 2587 2588 static struct pipeline_msg_rsp * 2589 pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p, 2590 struct pipeline_msg_req *req) 2591 { 2592 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2593 2594 uint32_t table_id = req->id; 2595 struct softnic_table_rule_match *match = req->table_rule_add_bulk.match; 2596 struct softnic_table_rule_action *action = req->table_rule_add_bulk.action; 2597 struct rte_pipeline_table_entry **data = 2598 (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data; 2599 uint32_t n_rules = req->table_rule_add_bulk.n_rules; 2600 uint32_t bulk = req->table_rule_add_bulk.bulk; 2601 2602 struct rte_table_action *a = p->table_data[table_id].a; 2603 union table_rule_match_low_level *match_ll; 2604 uint8_t *action_ll; 2605 void **match_ll_ptr; 2606 struct rte_pipeline_table_entry **action_ll_ptr; 2607 int *found, status; 2608 uint32_t i; 2609 2610 /* Memory allocation */ 2611 match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level)); 2612 action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX); 2613 match_ll_ptr = calloc(n_rules, sizeof(void *)); 2614 action_ll_ptr = 2615 calloc(n_rules, sizeof(struct rte_pipeline_table_entry *)); 2616 found = calloc(n_rules, sizeof(int)); 2617 2618 if (match_ll == NULL || 2619 action_ll == NULL || 2620 match_ll_ptr == NULL || 2621 action_ll_ptr == NULL || 2622 found == NULL) 2623 goto fail; 2624 2625 for (i = 0; i < n_rules; i++) { 2626 match_ll_ptr[i] = (void *)&match_ll[i]; 2627 action_ll_ptr[i] = 2628 (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX]; 2629 } 2630 2631 /* Rule match conversion */ 2632 for (i = 0; i < n_rules; i++) { 2633 status = match_convert(&match[i], match_ll_ptr[i], 1); 2634 if (status) 2635 goto fail; 2636 } 2637 2638 /* Rule action conversion */ 2639 for (i = 0; i < n_rules; i++) { 2640 status = action_convert(a, &action[i], action_ll_ptr[i]); 2641 if (status) 2642 goto fail; 2643 } 2644 2645 /* Add rule (match, action) to table */ 2646 if (bulk) { 2647 status = rte_pipeline_table_entry_add_bulk(p->p, 2648 table_id, 2649 match_ll_ptr, 2650 action_ll_ptr, 2651 n_rules, 2652 found, 2653 data); 2654 if (status) 2655 n_rules = 0; 2656 } else { 2657 for (i = 0; i < n_rules; i++) { 2658 status = rte_pipeline_table_entry_add(p->p, 2659 table_id, 2660 match_ll_ptr[i], 2661 action_ll_ptr[i], 2662 &found[i], 2663 &data[i]); 2664 if (status) { 2665 n_rules = i; 2666 break; 2667 } 2668 } 2669 } 2670 2671 /* Write response */ 2672 rsp->status = 0; 2673 rsp->table_rule_add_bulk.n_rules = n_rules; 2674 2675 /* Free */ 2676 free(found); 2677 free(action_ll_ptr); 2678 free(match_ll_ptr); 2679 free(action_ll); 2680 free(match_ll); 2681 2682 return rsp; 2683 2684 fail: 2685 free(found); 2686 free(action_ll_ptr); 2687 free(match_ll_ptr); 2688 free(action_ll); 2689 free(match_ll); 2690 2691 rsp->status = -1; 2692 rsp->table_rule_add_bulk.n_rules = 0; 2693 return rsp; 2694 } 2695 2696 static struct pipeline_msg_rsp * 2697 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p, 2698 struct pipeline_msg_req *req) 2699 { 2700 union table_rule_match_low_level match_ll; 2701 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2702 struct softnic_table_rule_match *match = &req->table_rule_delete.match; 2703 uint32_t table_id = req->id; 2704 int key_found, status; 2705 2706 status = match_convert(match, &match_ll, 0); 2707 if (status) { 2708 rsp->status = -1; 2709 return rsp; 2710 } 2711 2712 rsp->status = rte_pipeline_table_entry_delete(p->p, 2713 table_id, 2714 &match_ll, 2715 &key_found, 2716 NULL); 2717 2718 return rsp; 2719 } 2720 2721 static struct pipeline_msg_rsp * 2722 pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p, 2723 struct pipeline_msg_req *req) 2724 { 2725 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2726 uint32_t table_id = req->id; 2727 2728 rsp->status = rte_pipeline_table_default_entry_delete(p->p, 2729 table_id, 2730 NULL); 2731 2732 return rsp; 2733 } 2734 2735 static struct pipeline_msg_rsp * 2736 pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p, 2737 struct pipeline_msg_req *req) 2738 { 2739 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2740 uint32_t table_id = req->id; 2741 void *data = req->table_rule_stats_read.data; 2742 int clear = req->table_rule_stats_read.clear; 2743 struct rte_table_action *a = p->table_data[table_id].a; 2744 2745 rsp->status = rte_table_action_stats_read(a, 2746 data, 2747 &rsp->table_rule_stats_read.stats, 2748 clear); 2749 2750 return rsp; 2751 } 2752 2753 static struct pipeline_msg_rsp * 2754 pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p, 2755 struct pipeline_msg_req *req) 2756 { 2757 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2758 uint32_t table_id = req->id; 2759 uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id; 2760 struct rte_table_action_meter_profile *profile = 2761 &req->table_mtr_profile_add.profile; 2762 struct rte_table_action *a = p->table_data[table_id].a; 2763 2764 rsp->status = rte_table_action_meter_profile_add(a, 2765 meter_profile_id, 2766 profile); 2767 2768 return rsp; 2769 } 2770 2771 static struct pipeline_msg_rsp * 2772 pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p, 2773 struct pipeline_msg_req *req) 2774 { 2775 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2776 uint32_t table_id = req->id; 2777 uint32_t meter_profile_id = 2778 req->table_mtr_profile_delete.meter_profile_id; 2779 struct rte_table_action *a = p->table_data[table_id].a; 2780 2781 rsp->status = rte_table_action_meter_profile_delete(a, 2782 meter_profile_id); 2783 2784 return rsp; 2785 } 2786 2787 static struct pipeline_msg_rsp * 2788 pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p, 2789 struct pipeline_msg_req *req) 2790 { 2791 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2792 uint32_t table_id = req->id; 2793 void *data = req->table_rule_mtr_read.data; 2794 uint32_t tc_mask = req->table_rule_mtr_read.tc_mask; 2795 int clear = req->table_rule_mtr_read.clear; 2796 struct rte_table_action *a = p->table_data[table_id].a; 2797 2798 rsp->status = rte_table_action_meter_read(a, 2799 data, 2800 tc_mask, 2801 &rsp->table_rule_mtr_read.stats, 2802 clear); 2803 2804 return rsp; 2805 } 2806 2807 static struct pipeline_msg_rsp * 2808 pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p, 2809 struct pipeline_msg_req *req) 2810 { 2811 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2812 uint32_t table_id = req->id; 2813 uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask; 2814 struct rte_table_action_dscp_table *dscp_table = 2815 &req->table_dscp_table_update.dscp_table; 2816 struct rte_table_action *a = p->table_data[table_id].a; 2817 2818 rsp->status = rte_table_action_dscp_table_update(a, 2819 dscp_mask, 2820 dscp_table); 2821 2822 return rsp; 2823 } 2824 2825 static struct pipeline_msg_rsp * 2826 pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p, 2827 struct pipeline_msg_req *req) 2828 { 2829 struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req; 2830 uint32_t table_id = req->id; 2831 void *data = req->table_rule_ttl_read.data; 2832 int clear = req->table_rule_ttl_read.clear; 2833 struct rte_table_action *a = p->table_data[table_id].a; 2834 2835 rsp->status = rte_table_action_ttl_read(a, 2836 data, 2837 &rsp->table_rule_ttl_read.stats, 2838 clear); 2839 2840 return rsp; 2841 } 2842 2843 static void 2844 pipeline_msg_handle(struct pipeline_data *p) 2845 { 2846 for ( ; ; ) { 2847 struct pipeline_msg_req *req; 2848 struct pipeline_msg_rsp *rsp; 2849 2850 req = pipeline_msg_recv(p->msgq_req); 2851 if (req == NULL) 2852 break; 2853 2854 switch (req->type) { 2855 case PIPELINE_REQ_PORT_IN_STATS_READ: 2856 rsp = pipeline_msg_handle_port_in_stats_read(p, req); 2857 break; 2858 2859 case PIPELINE_REQ_PORT_IN_ENABLE: 2860 rsp = pipeline_msg_handle_port_in_enable(p, req); 2861 break; 2862 2863 case PIPELINE_REQ_PORT_IN_DISABLE: 2864 rsp = pipeline_msg_handle_port_in_disable(p, req); 2865 break; 2866 2867 case PIPELINE_REQ_PORT_OUT_STATS_READ: 2868 rsp = pipeline_msg_handle_port_out_stats_read(p, req); 2869 break; 2870 2871 case PIPELINE_REQ_TABLE_STATS_READ: 2872 rsp = pipeline_msg_handle_table_stats_read(p, req); 2873 break; 2874 2875 case PIPELINE_REQ_TABLE_RULE_ADD: 2876 rsp = pipeline_msg_handle_table_rule_add(p, req); 2877 break; 2878 2879 case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT: 2880 rsp = pipeline_msg_handle_table_rule_add_default(p, req); 2881 break; 2882 2883 case PIPELINE_REQ_TABLE_RULE_ADD_BULK: 2884 rsp = pipeline_msg_handle_table_rule_add_bulk(p, req); 2885 break; 2886 2887 case PIPELINE_REQ_TABLE_RULE_DELETE: 2888 rsp = pipeline_msg_handle_table_rule_delete(p, req); 2889 break; 2890 2891 case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT: 2892 rsp = pipeline_msg_handle_table_rule_delete_default(p, req); 2893 break; 2894 2895 case PIPELINE_REQ_TABLE_RULE_STATS_READ: 2896 rsp = pipeline_msg_handle_table_rule_stats_read(p, req); 2897 break; 2898 2899 case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD: 2900 rsp = pipeline_msg_handle_table_mtr_profile_add(p, req); 2901 break; 2902 2903 case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE: 2904 rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req); 2905 break; 2906 2907 case PIPELINE_REQ_TABLE_RULE_MTR_READ: 2908 rsp = pipeline_msg_handle_table_rule_mtr_read(p, req); 2909 break; 2910 2911 case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE: 2912 rsp = pipeline_msg_handle_table_dscp_table_update(p, req); 2913 break; 2914 2915 case PIPELINE_REQ_TABLE_RULE_TTL_READ: 2916 rsp = pipeline_msg_handle_table_rule_ttl_read(p, req); 2917 break; 2918 2919 default: 2920 rsp = (struct pipeline_msg_rsp *)req; 2921 rsp->status = -1; 2922 } 2923 2924 pipeline_msg_send(p->msgq_rsp, rsp); 2925 } 2926 } 2927 2928 /** 2929 * Data plane threads: main 2930 */ 2931 int 2932 rte_pmd_softnic_run(uint16_t port_id) 2933 { 2934 struct rte_eth_dev *dev = &rte_eth_devices[port_id]; 2935 struct pmd_internals *softnic; 2936 struct softnic_thread_data *t; 2937 uint32_t thread_id, j; 2938 2939 #ifdef RTE_LIBRTE_ETHDEV_DEBUG 2940 RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0); 2941 #endif 2942 2943 softnic = dev->data->dev_private; 2944 thread_id = rte_lcore_id(); 2945 t = &softnic->thread_data[thread_id]; 2946 t->iter++; 2947 2948 /* Data Plane */ 2949 for (j = 0; j < t->n_pipelines; j++) 2950 rte_pipeline_run(t->p[j]); 2951 2952 /* Control Plane */ 2953 if ((t->iter & 0xFLLU) == 0) { 2954 uint64_t time = rte_get_tsc_cycles(); 2955 uint64_t time_next_min = UINT64_MAX; 2956 2957 if (time < t->time_next_min) 2958 return 0; 2959 2960 /* Pipeline message queues */ 2961 for (j = 0; j < t->n_pipelines; j++) { 2962 struct pipeline_data *p = 2963 &t->pipeline_data[j]; 2964 uint64_t time_next = p->time_next; 2965 2966 if (time_next <= time) { 2967 pipeline_msg_handle(p); 2968 rte_pipeline_flush(p->p); 2969 time_next = time + p->timer_period; 2970 p->time_next = time_next; 2971 } 2972 2973 if (time_next < time_next_min) 2974 time_next_min = time_next; 2975 } 2976 2977 /* Thread message queues */ 2978 { 2979 uint64_t time_next = t->time_next; 2980 2981 if (time_next <= time) { 2982 thread_msg_handle(t); 2983 time_next = time + t->timer_period; 2984 t->time_next = time_next; 2985 } 2986 2987 if (time_next < time_next_min) 2988 time_next_min = time_next; 2989 } 2990 2991 t->time_next_min = time_next_min; 2992 } 2993 2994 return 0; 2995 } 2996