1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <errno.h> 7 #include <dlfcn.h> 8 9 #include <rte_jhash.h> 10 #include <rte_hash_crc.h> 11 12 #include <rte_swx_port_ethdev.h> 13 #include <rte_swx_port_fd.h> 14 #include <rte_swx_port_ring.h> 15 #include "rte_swx_port_source_sink.h" 16 17 #include <rte_swx_table_em.h> 18 #include <rte_swx_table_wm.h> 19 20 #include "rte_swx_pipeline_internal.h" 21 22 #define CHECK(condition, err_code) \ 23 do { \ 24 if (!(condition)) \ 25 return -(err_code); \ 26 } while (0) 27 28 #define CHECK_NAME(name, err_code) \ 29 CHECK((name) && \ 30 (name)[0] && \ 31 (strnlen((name), RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), \ 32 err_code) 33 34 #define CHECK_INSTRUCTION(instr, err_code) \ 35 CHECK((instr) && \ 36 (instr)[0] && \ 37 (strnlen((instr), RTE_SWX_INSTRUCTION_SIZE) < \ 38 RTE_SWX_INSTRUCTION_SIZE), \ 39 err_code) 40 41 /* 42 * Environment. 43 */ 44 #ifndef RTE_SWX_PIPELINE_HUGE_PAGES_DISABLE 45 46 #include <rte_malloc.h> 47 48 static void * 49 env_malloc(size_t size, size_t alignment, int numa_node) 50 { 51 return rte_zmalloc_socket(NULL, size, alignment, numa_node); 52 } 53 54 static void 55 env_free(void *start, size_t size __rte_unused) 56 { 57 rte_free(start); 58 } 59 60 #else 61 62 #include <numa.h> 63 64 static void * 65 env_malloc(size_t size, size_t alignment __rte_unused, int numa_node) 66 { 67 void *start; 68 69 if (numa_available() == -1) 70 return NULL; 71 72 start = numa_alloc_onnode(size, numa_node); 73 if (!start) 74 return NULL; 75 76 memset(start, 0, size); 77 return start; 78 } 79 80 static void 81 env_free(void *start, size_t size) 82 { 83 if (numa_available() == -1) 84 return; 85 86 numa_free(start, size); 87 } 88 89 #endif 90 91 /* 92 * Struct. 93 */ 94 static struct struct_type * 95 struct_type_find(struct rte_swx_pipeline *p, const char *name) 96 { 97 struct struct_type *elem; 98 99 TAILQ_FOREACH(elem, &p->struct_types, node) 100 if (strcmp(elem->name, name) == 0) 101 return elem; 102 103 return NULL; 104 } 105 106 static struct field * 107 struct_type_field_find(struct struct_type *st, const char *name) 108 { 109 uint32_t i; 110 111 for (i = 0; i < st->n_fields; i++) { 112 struct field *f = &st->fields[i]; 113 114 if (strcmp(f->name, name) == 0) 115 return f; 116 } 117 118 return NULL; 119 } 120 121 int 122 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p, 123 const char *name, 124 struct rte_swx_field_params *fields, 125 uint32_t n_fields, 126 int last_field_has_variable_size) 127 { 128 struct struct_type *st; 129 uint32_t i; 130 131 CHECK(p, EINVAL); 132 CHECK_NAME(name, EINVAL); 133 CHECK(fields, EINVAL); 134 CHECK(n_fields, EINVAL); 135 136 for (i = 0; i < n_fields; i++) { 137 struct rte_swx_field_params *f = &fields[i]; 138 int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0; 139 uint32_t j; 140 141 CHECK_NAME(f->name, EINVAL); 142 CHECK(f->n_bits, EINVAL); 143 CHECK((f->n_bits <= 64) || var_size, EINVAL); 144 CHECK((f->n_bits & 7) == 0, EINVAL); 145 146 for (j = 0; j < i; j++) { 147 struct rte_swx_field_params *f_prev = &fields[j]; 148 149 CHECK(strcmp(f->name, f_prev->name), EINVAL); 150 } 151 } 152 153 CHECK(!struct_type_find(p, name), EEXIST); 154 155 /* Node allocation. */ 156 st = calloc(1, sizeof(struct struct_type)); 157 CHECK(st, ENOMEM); 158 159 st->fields = calloc(n_fields, sizeof(struct field)); 160 if (!st->fields) { 161 free(st); 162 CHECK(0, ENOMEM); 163 } 164 165 /* Node initialization. */ 166 strcpy(st->name, name); 167 for (i = 0; i < n_fields; i++) { 168 struct field *dst = &st->fields[i]; 169 struct rte_swx_field_params *src = &fields[i]; 170 int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0; 171 172 strcpy(dst->name, src->name); 173 dst->n_bits = src->n_bits; 174 dst->offset = st->n_bits; 175 dst->var_size = var_size; 176 177 st->n_bits += src->n_bits; 178 st->n_bits_min += var_size ? 0 : src->n_bits; 179 } 180 st->n_fields = n_fields; 181 st->var_size = last_field_has_variable_size; 182 183 /* Node add to tailq. */ 184 TAILQ_INSERT_TAIL(&p->struct_types, st, node); 185 186 return 0; 187 } 188 189 static int 190 struct_build(struct rte_swx_pipeline *p) 191 { 192 uint32_t i; 193 194 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 195 struct thread *t = &p->threads[i]; 196 197 t->structs = calloc(p->n_structs, sizeof(uint8_t *)); 198 CHECK(t->structs, ENOMEM); 199 } 200 201 return 0; 202 } 203 204 static void 205 struct_build_free(struct rte_swx_pipeline *p) 206 { 207 uint32_t i; 208 209 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 210 struct thread *t = &p->threads[i]; 211 212 free(t->structs); 213 t->structs = NULL; 214 } 215 } 216 217 static void 218 struct_free(struct rte_swx_pipeline *p) 219 { 220 struct_build_free(p); 221 222 /* Struct types. */ 223 for ( ; ; ) { 224 struct struct_type *elem; 225 226 elem = TAILQ_FIRST(&p->struct_types); 227 if (!elem) 228 break; 229 230 TAILQ_REMOVE(&p->struct_types, elem, node); 231 free(elem->fields); 232 free(elem); 233 } 234 } 235 236 /* 237 * Input port. 238 */ 239 static struct port_in_type * 240 port_in_type_find(struct rte_swx_pipeline *p, const char *name) 241 { 242 struct port_in_type *elem; 243 244 if (!name) 245 return NULL; 246 247 TAILQ_FOREACH(elem, &p->port_in_types, node) 248 if (strcmp(elem->name, name) == 0) 249 return elem; 250 251 return NULL; 252 } 253 254 int 255 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p, 256 const char *name, 257 struct rte_swx_port_in_ops *ops) 258 { 259 struct port_in_type *elem; 260 261 CHECK(p, EINVAL); 262 CHECK_NAME(name, EINVAL); 263 CHECK(ops, EINVAL); 264 CHECK(ops->create, EINVAL); 265 CHECK(ops->free, EINVAL); 266 CHECK(ops->pkt_rx, EINVAL); 267 CHECK(ops->stats_read, EINVAL); 268 269 CHECK(!port_in_type_find(p, name), EEXIST); 270 271 /* Node allocation. */ 272 elem = calloc(1, sizeof(struct port_in_type)); 273 CHECK(elem, ENOMEM); 274 275 /* Node initialization. */ 276 strcpy(elem->name, name); 277 memcpy(&elem->ops, ops, sizeof(*ops)); 278 279 /* Node add to tailq. */ 280 TAILQ_INSERT_TAIL(&p->port_in_types, elem, node); 281 282 return 0; 283 } 284 285 static struct port_in * 286 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id) 287 { 288 struct port_in *port; 289 290 TAILQ_FOREACH(port, &p->ports_in, node) 291 if (port->id == port_id) 292 return port; 293 294 return NULL; 295 } 296 297 int 298 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p, 299 uint32_t port_id, 300 const char *port_type_name, 301 void *args) 302 { 303 struct port_in_type *type = NULL; 304 struct port_in *port = NULL; 305 void *obj = NULL; 306 307 CHECK(p, EINVAL); 308 309 CHECK(!port_in_find(p, port_id), EINVAL); 310 311 CHECK_NAME(port_type_name, EINVAL); 312 type = port_in_type_find(p, port_type_name); 313 CHECK(type, EINVAL); 314 315 obj = type->ops.create(args); 316 CHECK(obj, ENODEV); 317 318 /* Node allocation. */ 319 port = calloc(1, sizeof(struct port_in)); 320 CHECK(port, ENOMEM); 321 322 /* Node initialization. */ 323 port->type = type; 324 port->obj = obj; 325 port->id = port_id; 326 327 /* Node add to tailq. */ 328 TAILQ_INSERT_TAIL(&p->ports_in, port, node); 329 if (p->n_ports_in < port_id + 1) 330 p->n_ports_in = port_id + 1; 331 332 return 0; 333 } 334 335 static int 336 port_in_build(struct rte_swx_pipeline *p) 337 { 338 struct port_in *port; 339 uint32_t i; 340 341 CHECK(p->n_ports_in, EINVAL); 342 CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL); 343 344 for (i = 0; i < p->n_ports_in; i++) 345 CHECK(port_in_find(p, i), EINVAL); 346 347 p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime)); 348 CHECK(p->in, ENOMEM); 349 350 TAILQ_FOREACH(port, &p->ports_in, node) { 351 struct port_in_runtime *in = &p->in[port->id]; 352 353 in->pkt_rx = port->type->ops.pkt_rx; 354 in->obj = port->obj; 355 } 356 357 return 0; 358 } 359 360 static void 361 port_in_build_free(struct rte_swx_pipeline *p) 362 { 363 free(p->in); 364 p->in = NULL; 365 } 366 367 static void 368 port_in_free(struct rte_swx_pipeline *p) 369 { 370 port_in_build_free(p); 371 372 /* Input ports. */ 373 for ( ; ; ) { 374 struct port_in *port; 375 376 port = TAILQ_FIRST(&p->ports_in); 377 if (!port) 378 break; 379 380 TAILQ_REMOVE(&p->ports_in, port, node); 381 port->type->ops.free(port->obj); 382 free(port); 383 } 384 385 /* Input port types. */ 386 for ( ; ; ) { 387 struct port_in_type *elem; 388 389 elem = TAILQ_FIRST(&p->port_in_types); 390 if (!elem) 391 break; 392 393 TAILQ_REMOVE(&p->port_in_types, elem, node); 394 free(elem); 395 } 396 } 397 398 /* 399 * Output port. 400 */ 401 static struct port_out_type * 402 port_out_type_find(struct rte_swx_pipeline *p, const char *name) 403 { 404 struct port_out_type *elem; 405 406 if (!name) 407 return NULL; 408 409 TAILQ_FOREACH(elem, &p->port_out_types, node) 410 if (!strcmp(elem->name, name)) 411 return elem; 412 413 return NULL; 414 } 415 416 int 417 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p, 418 const char *name, 419 struct rte_swx_port_out_ops *ops) 420 { 421 struct port_out_type *elem; 422 423 CHECK(p, EINVAL); 424 CHECK_NAME(name, EINVAL); 425 CHECK(ops, EINVAL); 426 CHECK(ops->create, EINVAL); 427 CHECK(ops->free, EINVAL); 428 CHECK(ops->pkt_tx, EINVAL); 429 CHECK(ops->pkt_fast_clone_tx, EINVAL); 430 CHECK(ops->pkt_clone_tx, EINVAL); 431 CHECK(ops->stats_read, EINVAL); 432 433 CHECK(!port_out_type_find(p, name), EEXIST); 434 435 /* Node allocation. */ 436 elem = calloc(1, sizeof(struct port_out_type)); 437 CHECK(elem, ENOMEM); 438 439 /* Node initialization. */ 440 strcpy(elem->name, name); 441 memcpy(&elem->ops, ops, sizeof(*ops)); 442 443 /* Node add to tailq. */ 444 TAILQ_INSERT_TAIL(&p->port_out_types, elem, node); 445 446 return 0; 447 } 448 449 static struct port_out * 450 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id) 451 { 452 struct port_out *port; 453 454 TAILQ_FOREACH(port, &p->ports_out, node) 455 if (port->id == port_id) 456 return port; 457 458 return NULL; 459 } 460 461 int 462 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p, 463 uint32_t port_id, 464 const char *port_type_name, 465 void *args) 466 { 467 struct port_out_type *type = NULL; 468 struct port_out *port = NULL; 469 void *obj = NULL; 470 471 CHECK(p, EINVAL); 472 473 CHECK(!port_out_find(p, port_id), EINVAL); 474 475 CHECK_NAME(port_type_name, EINVAL); 476 type = port_out_type_find(p, port_type_name); 477 CHECK(type, EINVAL); 478 479 obj = type->ops.create(args); 480 CHECK(obj, ENODEV); 481 482 /* Node allocation. */ 483 port = calloc(1, sizeof(struct port_out)); 484 CHECK(port, ENOMEM); 485 486 /* Node initialization. */ 487 port->type = type; 488 port->obj = obj; 489 port->id = port_id; 490 491 /* Node add to tailq. */ 492 TAILQ_INSERT_TAIL(&p->ports_out, port, node); 493 if (p->n_ports_out < port_id + 1) 494 p->n_ports_out = port_id + 1; 495 496 return 0; 497 } 498 499 static int 500 port_out_build(struct rte_swx_pipeline *p) 501 { 502 struct port_out *port; 503 uint32_t i; 504 505 CHECK(p->n_ports_out, EINVAL); 506 507 for (i = 0; i < p->n_ports_out; i++) 508 CHECK(port_out_find(p, i), EINVAL); 509 510 p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime)); 511 CHECK(p->out, ENOMEM); 512 513 TAILQ_FOREACH(port, &p->ports_out, node) { 514 struct port_out_runtime *out = &p->out[port->id]; 515 516 out->pkt_tx = port->type->ops.pkt_tx; 517 out->pkt_fast_clone_tx = port->type->ops.pkt_fast_clone_tx; 518 out->pkt_clone_tx = port->type->ops.pkt_clone_tx; 519 out->flush = port->type->ops.flush; 520 out->obj = port->obj; 521 } 522 523 return 0; 524 } 525 526 static void 527 port_out_build_free(struct rte_swx_pipeline *p) 528 { 529 free(p->out); 530 p->out = NULL; 531 } 532 533 static void 534 port_out_free(struct rte_swx_pipeline *p) 535 { 536 port_out_build_free(p); 537 538 /* Output ports. */ 539 for ( ; ; ) { 540 struct port_out *port; 541 542 port = TAILQ_FIRST(&p->ports_out); 543 if (!port) 544 break; 545 546 TAILQ_REMOVE(&p->ports_out, port, node); 547 port->type->ops.free(port->obj); 548 free(port); 549 } 550 551 /* Output port types. */ 552 for ( ; ; ) { 553 struct port_out_type *elem; 554 555 elem = TAILQ_FIRST(&p->port_out_types); 556 if (!elem) 557 break; 558 559 TAILQ_REMOVE(&p->port_out_types, elem, node); 560 free(elem); 561 } 562 } 563 564 /* 565 * Packet mirroring. 566 */ 567 int 568 rte_swx_pipeline_mirroring_config(struct rte_swx_pipeline *p, 569 struct rte_swx_pipeline_mirroring_params *params) 570 { 571 CHECK(p, EINVAL); 572 CHECK(params, EINVAL); 573 CHECK(params->n_slots, EINVAL); 574 CHECK(params->n_sessions, EINVAL); 575 CHECK(!p->build_done, EEXIST); 576 577 p->n_mirroring_slots = rte_align32pow2(params->n_slots); 578 if (p->n_mirroring_slots > 64) 579 p->n_mirroring_slots = 64; 580 581 p->n_mirroring_sessions = rte_align32pow2(params->n_sessions); 582 583 return 0; 584 } 585 586 static void 587 mirroring_build_free(struct rte_swx_pipeline *p) 588 { 589 uint32_t i; 590 591 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 592 struct thread *t = &p->threads[i]; 593 594 /* mirroring_slots. */ 595 free(t->mirroring_slots); 596 t->mirroring_slots = NULL; 597 } 598 599 /* mirroring_sessions. */ 600 free(p->mirroring_sessions); 601 p->mirroring_sessions = NULL; 602 } 603 604 static void 605 mirroring_free(struct rte_swx_pipeline *p) 606 { 607 mirroring_build_free(p); 608 } 609 610 static int 611 mirroring_build(struct rte_swx_pipeline *p) 612 { 613 uint32_t i; 614 615 if (!p->n_mirroring_slots || !p->n_mirroring_sessions) 616 return 0; 617 618 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 619 struct thread *t = &p->threads[i]; 620 621 /* mirroring_slots. */ 622 t->mirroring_slots = calloc(p->n_mirroring_slots, sizeof(uint32_t)); 623 if (!t->mirroring_slots) 624 goto error; 625 } 626 627 /* mirroring_sessions. */ 628 p->mirroring_sessions = calloc(p->n_mirroring_sessions, sizeof(struct mirroring_session)); 629 if (!p->mirroring_sessions) 630 goto error; 631 632 return 0; 633 634 error: 635 mirroring_build_free(p); 636 return -ENOMEM; 637 } 638 639 /* 640 * Extern object. 641 */ 642 static struct extern_type * 643 extern_type_find(struct rte_swx_pipeline *p, const char *name) 644 { 645 struct extern_type *elem; 646 647 TAILQ_FOREACH(elem, &p->extern_types, node) 648 if (strcmp(elem->name, name) == 0) 649 return elem; 650 651 return NULL; 652 } 653 654 static struct extern_type_member_func * 655 extern_type_member_func_find(struct extern_type *type, const char *name) 656 { 657 struct extern_type_member_func *elem; 658 659 TAILQ_FOREACH(elem, &type->funcs, node) 660 if (strcmp(elem->name, name) == 0) 661 return elem; 662 663 return NULL; 664 } 665 666 static struct extern_obj * 667 extern_obj_find(struct rte_swx_pipeline *p, const char *name) 668 { 669 struct extern_obj *elem; 670 671 TAILQ_FOREACH(elem, &p->extern_objs, node) 672 if (strcmp(elem->name, name) == 0) 673 return elem; 674 675 return NULL; 676 } 677 678 static struct extern_type_member_func * 679 extern_obj_member_func_parse(struct rte_swx_pipeline *p, 680 const char *name, 681 struct extern_obj **obj) 682 { 683 struct extern_obj *object; 684 struct extern_type_member_func *func; 685 char *object_name, *func_name; 686 687 if (name[0] != 'e' || name[1] != '.') 688 return NULL; 689 690 object_name = strdup(&name[2]); 691 if (!object_name) 692 return NULL; 693 694 func_name = strchr(object_name, '.'); 695 if (!func_name) { 696 free(object_name); 697 return NULL; 698 } 699 700 *func_name = 0; 701 func_name++; 702 703 object = extern_obj_find(p, object_name); 704 if (!object) { 705 free(object_name); 706 return NULL; 707 } 708 709 func = extern_type_member_func_find(object->type, func_name); 710 if (!func) { 711 free(object_name); 712 return NULL; 713 } 714 715 if (obj) 716 *obj = object; 717 718 free(object_name); 719 return func; 720 } 721 722 static struct field * 723 extern_obj_mailbox_field_parse(struct rte_swx_pipeline *p, 724 const char *name, 725 struct extern_obj **object) 726 { 727 struct extern_obj *obj; 728 struct field *f; 729 char *obj_name, *field_name; 730 731 if ((name[0] != 'e') || (name[1] != '.')) 732 return NULL; 733 734 obj_name = strdup(&name[2]); 735 if (!obj_name) 736 return NULL; 737 738 field_name = strchr(obj_name, '.'); 739 if (!field_name) { 740 free(obj_name); 741 return NULL; 742 } 743 744 *field_name = 0; 745 field_name++; 746 747 obj = extern_obj_find(p, obj_name); 748 if (!obj) { 749 free(obj_name); 750 return NULL; 751 } 752 753 f = struct_type_field_find(obj->type->mailbox_struct_type, field_name); 754 if (!f) { 755 free(obj_name); 756 return NULL; 757 } 758 759 if (object) 760 *object = obj; 761 762 free(obj_name); 763 return f; 764 } 765 766 int 767 rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p, 768 const char *name, 769 const char *mailbox_struct_type_name, 770 rte_swx_extern_type_constructor_t constructor, 771 rte_swx_extern_type_destructor_t destructor) 772 { 773 struct extern_type *elem; 774 struct struct_type *mailbox_struct_type; 775 776 CHECK(p, EINVAL); 777 778 CHECK_NAME(name, EINVAL); 779 CHECK(!extern_type_find(p, name), EEXIST); 780 781 CHECK_NAME(mailbox_struct_type_name, EINVAL); 782 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name); 783 CHECK(mailbox_struct_type, EINVAL); 784 CHECK(!mailbox_struct_type->var_size, EINVAL); 785 786 CHECK(constructor, EINVAL); 787 CHECK(destructor, EINVAL); 788 789 /* Node allocation. */ 790 elem = calloc(1, sizeof(struct extern_type)); 791 CHECK(elem, ENOMEM); 792 793 /* Node initialization. */ 794 strcpy(elem->name, name); 795 elem->mailbox_struct_type = mailbox_struct_type; 796 elem->constructor = constructor; 797 elem->destructor = destructor; 798 TAILQ_INIT(&elem->funcs); 799 800 /* Node add to tailq. */ 801 TAILQ_INSERT_TAIL(&p->extern_types, elem, node); 802 803 return 0; 804 } 805 806 int 807 rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p, 808 const char *extern_type_name, 809 const char *name, 810 rte_swx_extern_type_member_func_t member_func) 811 { 812 struct extern_type *type; 813 struct extern_type_member_func *type_member; 814 815 CHECK(p, EINVAL); 816 817 CHECK_NAME(extern_type_name, EINVAL); 818 type = extern_type_find(p, extern_type_name); 819 CHECK(type, EINVAL); 820 CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC); 821 822 CHECK_NAME(name, EINVAL); 823 CHECK(!extern_type_member_func_find(type, name), EEXIST); 824 825 CHECK(member_func, EINVAL); 826 827 /* Node allocation. */ 828 type_member = calloc(1, sizeof(struct extern_type_member_func)); 829 CHECK(type_member, ENOMEM); 830 831 /* Node initialization. */ 832 strcpy(type_member->name, name); 833 type_member->func = member_func; 834 type_member->id = type->n_funcs; 835 836 /* Node add to tailq. */ 837 TAILQ_INSERT_TAIL(&type->funcs, type_member, node); 838 type->n_funcs++; 839 840 return 0; 841 } 842 843 int 844 rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p, 845 const char *extern_type_name, 846 const char *name, 847 const char *args) 848 { 849 struct extern_type *type; 850 struct extern_obj *obj; 851 void *obj_handle; 852 853 CHECK(p, EINVAL); 854 855 CHECK_NAME(extern_type_name, EINVAL); 856 type = extern_type_find(p, extern_type_name); 857 CHECK(type, EINVAL); 858 859 CHECK_NAME(name, EINVAL); 860 CHECK(!extern_obj_find(p, name), EEXIST); 861 862 /* Node allocation. */ 863 obj = calloc(1, sizeof(struct extern_obj)); 864 CHECK(obj, ENOMEM); 865 866 /* Object construction. */ 867 obj_handle = type->constructor(args); 868 if (!obj_handle) { 869 free(obj); 870 CHECK(0, ENODEV); 871 } 872 873 /* Node initialization. */ 874 strcpy(obj->name, name); 875 obj->type = type; 876 obj->obj = obj_handle; 877 obj->struct_id = p->n_structs; 878 obj->id = p->n_extern_objs; 879 880 /* Node add to tailq. */ 881 TAILQ_INSERT_TAIL(&p->extern_objs, obj, node); 882 p->n_extern_objs++; 883 p->n_structs++; 884 885 return 0; 886 } 887 888 static int 889 extern_obj_build(struct rte_swx_pipeline *p) 890 { 891 uint32_t i; 892 893 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 894 struct thread *t = &p->threads[i]; 895 struct extern_obj *obj; 896 897 t->extern_objs = calloc(p->n_extern_objs, 898 sizeof(struct extern_obj_runtime)); 899 CHECK(t->extern_objs, ENOMEM); 900 901 TAILQ_FOREACH(obj, &p->extern_objs, node) { 902 struct extern_obj_runtime *r = 903 &t->extern_objs[obj->id]; 904 struct extern_type_member_func *func; 905 uint32_t mailbox_size = 906 obj->type->mailbox_struct_type->n_bits / 8; 907 908 r->obj = obj->obj; 909 910 r->mailbox = calloc(1, mailbox_size); 911 CHECK(r->mailbox, ENOMEM); 912 913 TAILQ_FOREACH(func, &obj->type->funcs, node) 914 r->funcs[func->id] = func->func; 915 916 t->structs[obj->struct_id] = r->mailbox; 917 } 918 } 919 920 return 0; 921 } 922 923 static void 924 extern_obj_build_free(struct rte_swx_pipeline *p) 925 { 926 uint32_t i; 927 928 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 929 struct thread *t = &p->threads[i]; 930 uint32_t j; 931 932 if (!t->extern_objs) 933 continue; 934 935 for (j = 0; j < p->n_extern_objs; j++) { 936 struct extern_obj_runtime *r = &t->extern_objs[j]; 937 938 free(r->mailbox); 939 } 940 941 free(t->extern_objs); 942 t->extern_objs = NULL; 943 } 944 } 945 946 static void 947 extern_obj_free(struct rte_swx_pipeline *p) 948 { 949 extern_obj_build_free(p); 950 951 /* Extern objects. */ 952 for ( ; ; ) { 953 struct extern_obj *elem; 954 955 elem = TAILQ_FIRST(&p->extern_objs); 956 if (!elem) 957 break; 958 959 TAILQ_REMOVE(&p->extern_objs, elem, node); 960 if (elem->obj) 961 elem->type->destructor(elem->obj); 962 free(elem); 963 } 964 965 /* Extern types. */ 966 for ( ; ; ) { 967 struct extern_type *elem; 968 969 elem = TAILQ_FIRST(&p->extern_types); 970 if (!elem) 971 break; 972 973 TAILQ_REMOVE(&p->extern_types, elem, node); 974 975 for ( ; ; ) { 976 struct extern_type_member_func *func; 977 978 func = TAILQ_FIRST(&elem->funcs); 979 if (!func) 980 break; 981 982 TAILQ_REMOVE(&elem->funcs, func, node); 983 free(func); 984 } 985 986 free(elem); 987 } 988 } 989 990 /* 991 * Extern function. 992 */ 993 static struct extern_func * 994 extern_func_find(struct rte_swx_pipeline *p, const char *name) 995 { 996 struct extern_func *elem; 997 998 TAILQ_FOREACH(elem, &p->extern_funcs, node) 999 if (strcmp(elem->name, name) == 0) 1000 return elem; 1001 1002 return NULL; 1003 } 1004 1005 static struct extern_func * 1006 extern_func_parse(struct rte_swx_pipeline *p, 1007 const char *name) 1008 { 1009 if (name[0] != 'f' || name[1] != '.') 1010 return NULL; 1011 1012 return extern_func_find(p, &name[2]); 1013 } 1014 1015 static struct field * 1016 extern_func_mailbox_field_parse(struct rte_swx_pipeline *p, 1017 const char *name, 1018 struct extern_func **function) 1019 { 1020 struct extern_func *func; 1021 struct field *f; 1022 char *func_name, *field_name; 1023 1024 if ((name[0] != 'f') || (name[1] != '.')) 1025 return NULL; 1026 1027 func_name = strdup(&name[2]); 1028 if (!func_name) 1029 return NULL; 1030 1031 field_name = strchr(func_name, '.'); 1032 if (!field_name) { 1033 free(func_name); 1034 return NULL; 1035 } 1036 1037 *field_name = 0; 1038 field_name++; 1039 1040 func = extern_func_find(p, func_name); 1041 if (!func) { 1042 free(func_name); 1043 return NULL; 1044 } 1045 1046 f = struct_type_field_find(func->mailbox_struct_type, field_name); 1047 if (!f) { 1048 free(func_name); 1049 return NULL; 1050 } 1051 1052 if (function) 1053 *function = func; 1054 1055 free(func_name); 1056 return f; 1057 } 1058 1059 int 1060 rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p, 1061 const char *name, 1062 const char *mailbox_struct_type_name, 1063 rte_swx_extern_func_t func) 1064 { 1065 struct extern_func *f; 1066 struct struct_type *mailbox_struct_type; 1067 1068 CHECK(p, EINVAL); 1069 1070 CHECK_NAME(name, EINVAL); 1071 CHECK(!extern_func_find(p, name), EEXIST); 1072 1073 CHECK_NAME(mailbox_struct_type_name, EINVAL); 1074 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name); 1075 CHECK(mailbox_struct_type, EINVAL); 1076 CHECK(!mailbox_struct_type->var_size, EINVAL); 1077 1078 CHECK(func, EINVAL); 1079 1080 /* Node allocation. */ 1081 f = calloc(1, sizeof(struct extern_func)); 1082 CHECK(func, ENOMEM); 1083 1084 /* Node initialization. */ 1085 strcpy(f->name, name); 1086 f->mailbox_struct_type = mailbox_struct_type; 1087 f->func = func; 1088 f->struct_id = p->n_structs; 1089 f->id = p->n_extern_funcs; 1090 1091 /* Node add to tailq. */ 1092 TAILQ_INSERT_TAIL(&p->extern_funcs, f, node); 1093 p->n_extern_funcs++; 1094 p->n_structs++; 1095 1096 return 0; 1097 } 1098 1099 static int 1100 extern_func_build(struct rte_swx_pipeline *p) 1101 { 1102 uint32_t i; 1103 1104 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1105 struct thread *t = &p->threads[i]; 1106 struct extern_func *func; 1107 1108 /* Memory allocation. */ 1109 t->extern_funcs = calloc(p->n_extern_funcs, 1110 sizeof(struct extern_func_runtime)); 1111 CHECK(t->extern_funcs, ENOMEM); 1112 1113 /* Extern function. */ 1114 TAILQ_FOREACH(func, &p->extern_funcs, node) { 1115 struct extern_func_runtime *r = 1116 &t->extern_funcs[func->id]; 1117 uint32_t mailbox_size = 1118 func->mailbox_struct_type->n_bits / 8; 1119 1120 r->func = func->func; 1121 1122 r->mailbox = calloc(1, mailbox_size); 1123 CHECK(r->mailbox, ENOMEM); 1124 1125 t->structs[func->struct_id] = r->mailbox; 1126 } 1127 } 1128 1129 return 0; 1130 } 1131 1132 static void 1133 extern_func_build_free(struct rte_swx_pipeline *p) 1134 { 1135 uint32_t i; 1136 1137 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1138 struct thread *t = &p->threads[i]; 1139 uint32_t j; 1140 1141 if (!t->extern_funcs) 1142 continue; 1143 1144 for (j = 0; j < p->n_extern_funcs; j++) { 1145 struct extern_func_runtime *r = &t->extern_funcs[j]; 1146 1147 free(r->mailbox); 1148 } 1149 1150 free(t->extern_funcs); 1151 t->extern_funcs = NULL; 1152 } 1153 } 1154 1155 static void 1156 extern_func_free(struct rte_swx_pipeline *p) 1157 { 1158 extern_func_build_free(p); 1159 1160 for ( ; ; ) { 1161 struct extern_func *elem; 1162 1163 elem = TAILQ_FIRST(&p->extern_funcs); 1164 if (!elem) 1165 break; 1166 1167 TAILQ_REMOVE(&p->extern_funcs, elem, node); 1168 free(elem); 1169 } 1170 } 1171 1172 /* 1173 * Hash function. 1174 */ 1175 static struct hash_func * 1176 hash_func_find(struct rte_swx_pipeline *p, const char *name) 1177 { 1178 struct hash_func *elem; 1179 1180 TAILQ_FOREACH(elem, &p->hash_funcs, node) 1181 if (strcmp(elem->name, name) == 0) 1182 return elem; 1183 1184 return NULL; 1185 } 1186 1187 int 1188 rte_swx_pipeline_hash_func_register(struct rte_swx_pipeline *p, 1189 const char *name, 1190 rte_swx_hash_func_t func) 1191 { 1192 struct hash_func *f; 1193 1194 CHECK(p, EINVAL); 1195 1196 CHECK_NAME(name, EINVAL); 1197 CHECK(!hash_func_find(p, name), EEXIST); 1198 1199 CHECK(func, EINVAL); 1200 1201 /* Node allocation. */ 1202 f = calloc(1, sizeof(struct hash_func)); 1203 CHECK(func, ENOMEM); 1204 1205 /* Node initialization. */ 1206 strcpy(f->name, name); 1207 f->func = func; 1208 f->id = p->n_hash_funcs; 1209 1210 /* Node add to tailq. */ 1211 TAILQ_INSERT_TAIL(&p->hash_funcs, f, node); 1212 p->n_hash_funcs++; 1213 1214 return 0; 1215 } 1216 1217 static int 1218 hash_func_build(struct rte_swx_pipeline *p) 1219 { 1220 struct hash_func *func; 1221 1222 /* Memory allocation. */ 1223 p->hash_func_runtime = calloc(p->n_hash_funcs, sizeof(struct hash_func_runtime)); 1224 CHECK(p->hash_func_runtime, ENOMEM); 1225 1226 /* Hash function. */ 1227 TAILQ_FOREACH(func, &p->hash_funcs, node) { 1228 struct hash_func_runtime *r = &p->hash_func_runtime[func->id]; 1229 1230 r->func = func->func; 1231 } 1232 1233 return 0; 1234 } 1235 1236 static void 1237 hash_func_build_free(struct rte_swx_pipeline *p) 1238 { 1239 free(p->hash_func_runtime); 1240 p->hash_func_runtime = NULL; 1241 } 1242 1243 static void 1244 hash_func_free(struct rte_swx_pipeline *p) 1245 { 1246 hash_func_build_free(p); 1247 1248 for ( ; ; ) { 1249 struct hash_func *elem; 1250 1251 elem = TAILQ_FIRST(&p->hash_funcs); 1252 if (!elem) 1253 break; 1254 1255 TAILQ_REMOVE(&p->hash_funcs, elem, node); 1256 free(elem); 1257 } 1258 } 1259 1260 /* 1261 * Header. 1262 */ 1263 static struct header * 1264 header_find(struct rte_swx_pipeline *p, const char *name) 1265 { 1266 struct header *elem; 1267 1268 TAILQ_FOREACH(elem, &p->headers, node) 1269 if (strcmp(elem->name, name) == 0) 1270 return elem; 1271 1272 return NULL; 1273 } 1274 1275 static struct header * 1276 header_find_by_struct_id(struct rte_swx_pipeline *p, uint32_t struct_id) 1277 { 1278 struct header *elem; 1279 1280 TAILQ_FOREACH(elem, &p->headers, node) 1281 if (elem->struct_id == struct_id) 1282 return elem; 1283 1284 return NULL; 1285 } 1286 1287 static struct header * 1288 header_parse(struct rte_swx_pipeline *p, 1289 const char *name) 1290 { 1291 if (name[0] != 'h' || name[1] != '.') 1292 return NULL; 1293 1294 return header_find(p, &name[2]); 1295 } 1296 1297 static struct field * 1298 header_field_parse(struct rte_swx_pipeline *p, 1299 const char *name, 1300 struct header **header) 1301 { 1302 struct header *h; 1303 struct field *f; 1304 char *header_name, *field_name; 1305 1306 if ((name[0] != 'h') || (name[1] != '.')) 1307 return NULL; 1308 1309 header_name = strdup(&name[2]); 1310 if (!header_name) 1311 return NULL; 1312 1313 field_name = strchr(header_name, '.'); 1314 if (!field_name) { 1315 free(header_name); 1316 return NULL; 1317 } 1318 1319 *field_name = 0; 1320 field_name++; 1321 1322 h = header_find(p, header_name); 1323 if (!h) { 1324 free(header_name); 1325 return NULL; 1326 } 1327 1328 f = struct_type_field_find(h->st, field_name); 1329 if (!f) { 1330 free(header_name); 1331 return NULL; 1332 } 1333 1334 if (header) 1335 *header = h; 1336 1337 free(header_name); 1338 return f; 1339 } 1340 1341 int 1342 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p, 1343 const char *name, 1344 const char *struct_type_name) 1345 { 1346 struct struct_type *st; 1347 struct header *h; 1348 size_t n_headers_max; 1349 1350 CHECK(p, EINVAL); 1351 CHECK_NAME(name, EINVAL); 1352 CHECK_NAME(struct_type_name, EINVAL); 1353 1354 CHECK(!header_find(p, name), EEXIST); 1355 1356 st = struct_type_find(p, struct_type_name); 1357 CHECK(st, EINVAL); 1358 1359 n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8; 1360 CHECK(p->n_headers < n_headers_max, ENOSPC); 1361 1362 /* Node allocation. */ 1363 h = calloc(1, sizeof(struct header)); 1364 CHECK(h, ENOMEM); 1365 1366 /* Node initialization. */ 1367 strcpy(h->name, name); 1368 h->st = st; 1369 h->struct_id = p->n_structs; 1370 h->id = p->n_headers; 1371 1372 /* Node add to tailq. */ 1373 TAILQ_INSERT_TAIL(&p->headers, h, node); 1374 p->n_headers++; 1375 p->n_structs++; 1376 1377 return 0; 1378 } 1379 1380 static int 1381 header_build(struct rte_swx_pipeline *p) 1382 { 1383 struct header *h; 1384 uint32_t n_bytes = 0, i; 1385 1386 TAILQ_FOREACH(h, &p->headers, node) { 1387 n_bytes += h->st->n_bits / 8; 1388 } 1389 1390 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1391 struct thread *t = &p->threads[i]; 1392 uint32_t offset = 0; 1393 1394 t->headers = calloc(p->n_headers, 1395 sizeof(struct header_runtime)); 1396 CHECK(t->headers, ENOMEM); 1397 1398 t->headers_out = calloc(p->n_headers, 1399 sizeof(struct header_out_runtime)); 1400 CHECK(t->headers_out, ENOMEM); 1401 1402 t->header_storage = calloc(1, n_bytes); 1403 CHECK(t->header_storage, ENOMEM); 1404 1405 t->header_out_storage = calloc(1, n_bytes); 1406 CHECK(t->header_out_storage, ENOMEM); 1407 1408 TAILQ_FOREACH(h, &p->headers, node) { 1409 uint8_t *header_storage; 1410 uint32_t n_bytes = h->st->n_bits / 8; 1411 1412 header_storage = &t->header_storage[offset]; 1413 offset += n_bytes; 1414 1415 t->headers[h->id].ptr0 = header_storage; 1416 t->headers[h->id].n_bytes = n_bytes; 1417 1418 t->structs[h->struct_id] = header_storage; 1419 } 1420 } 1421 1422 return 0; 1423 } 1424 1425 static void 1426 header_build_free(struct rte_swx_pipeline *p) 1427 { 1428 uint32_t i; 1429 1430 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1431 struct thread *t = &p->threads[i]; 1432 1433 free(t->headers_out); 1434 t->headers_out = NULL; 1435 1436 free(t->headers); 1437 t->headers = NULL; 1438 1439 free(t->header_out_storage); 1440 t->header_out_storage = NULL; 1441 1442 free(t->header_storage); 1443 t->header_storage = NULL; 1444 } 1445 } 1446 1447 static void 1448 header_free(struct rte_swx_pipeline *p) 1449 { 1450 header_build_free(p); 1451 1452 for ( ; ; ) { 1453 struct header *elem; 1454 1455 elem = TAILQ_FIRST(&p->headers); 1456 if (!elem) 1457 break; 1458 1459 TAILQ_REMOVE(&p->headers, elem, node); 1460 free(elem); 1461 } 1462 } 1463 1464 /* 1465 * Meta-data. 1466 */ 1467 static struct field * 1468 metadata_field_parse(struct rte_swx_pipeline *p, const char *name) 1469 { 1470 if (!p->metadata_st) 1471 return NULL; 1472 1473 if (name[0] != 'm' || name[1] != '.') 1474 return NULL; 1475 1476 return struct_type_field_find(p->metadata_st, &name[2]); 1477 } 1478 1479 int 1480 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p, 1481 const char *struct_type_name) 1482 { 1483 struct struct_type *st = NULL; 1484 1485 CHECK(p, EINVAL); 1486 1487 CHECK_NAME(struct_type_name, EINVAL); 1488 st = struct_type_find(p, struct_type_name); 1489 CHECK(st, EINVAL); 1490 CHECK(!st->var_size, EINVAL); 1491 CHECK(!p->metadata_st, EINVAL); 1492 1493 p->metadata_st = st; 1494 p->metadata_struct_id = p->n_structs; 1495 1496 p->n_structs++; 1497 1498 return 0; 1499 } 1500 1501 static int 1502 metadata_build(struct rte_swx_pipeline *p) 1503 { 1504 uint32_t n_bytes = p->metadata_st->n_bits / 8; 1505 uint32_t i; 1506 1507 /* Thread-level initialization. */ 1508 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1509 struct thread *t = &p->threads[i]; 1510 uint8_t *metadata; 1511 1512 metadata = calloc(1, n_bytes); 1513 CHECK(metadata, ENOMEM); 1514 1515 t->metadata = metadata; 1516 t->structs[p->metadata_struct_id] = metadata; 1517 } 1518 1519 return 0; 1520 } 1521 1522 static void 1523 metadata_build_free(struct rte_swx_pipeline *p) 1524 { 1525 uint32_t i; 1526 1527 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 1528 struct thread *t = &p->threads[i]; 1529 1530 free(t->metadata); 1531 t->metadata = NULL; 1532 } 1533 } 1534 1535 static void 1536 metadata_free(struct rte_swx_pipeline *p) 1537 { 1538 metadata_build_free(p); 1539 } 1540 1541 /* 1542 * Instruction. 1543 */ 1544 static int 1545 instruction_is_tx(enum instruction_type type) 1546 { 1547 switch (type) { 1548 case INSTR_TX: 1549 case INSTR_TX_I: 1550 case INSTR_DROP: 1551 return 1; 1552 1553 default: 1554 return 0; 1555 } 1556 } 1557 1558 static int 1559 instruction_does_tx(struct instruction *instr) 1560 { 1561 switch (instr->type) { 1562 case INSTR_TX: 1563 case INSTR_TX_I: 1564 case INSTR_DROP: 1565 case INSTR_HDR_EMIT_TX: 1566 case INSTR_HDR_EMIT2_TX: 1567 case INSTR_HDR_EMIT3_TX: 1568 case INSTR_HDR_EMIT4_TX: 1569 case INSTR_HDR_EMIT5_TX: 1570 case INSTR_HDR_EMIT6_TX: 1571 case INSTR_HDR_EMIT7_TX: 1572 case INSTR_HDR_EMIT8_TX: 1573 return 1; 1574 default: 1575 return 0; 1576 } 1577 } 1578 1579 static int 1580 instruction_is_jmp(struct instruction *instr) 1581 { 1582 switch (instr->type) { 1583 case INSTR_JMP: 1584 case INSTR_JMP_VALID: 1585 case INSTR_JMP_INVALID: 1586 case INSTR_JMP_HIT: 1587 case INSTR_JMP_MISS: 1588 case INSTR_JMP_ACTION_HIT: 1589 case INSTR_JMP_ACTION_MISS: 1590 case INSTR_JMP_EQ: 1591 case INSTR_JMP_EQ_MH: 1592 case INSTR_JMP_EQ_HM: 1593 case INSTR_JMP_EQ_HH: 1594 case INSTR_JMP_EQ_I: 1595 case INSTR_JMP_NEQ: 1596 case INSTR_JMP_NEQ_MH: 1597 case INSTR_JMP_NEQ_HM: 1598 case INSTR_JMP_NEQ_HH: 1599 case INSTR_JMP_NEQ_I: 1600 case INSTR_JMP_LT: 1601 case INSTR_JMP_LT_MH: 1602 case INSTR_JMP_LT_HM: 1603 case INSTR_JMP_LT_HH: 1604 case INSTR_JMP_LT_MI: 1605 case INSTR_JMP_LT_HI: 1606 case INSTR_JMP_GT: 1607 case INSTR_JMP_GT_MH: 1608 case INSTR_JMP_GT_HM: 1609 case INSTR_JMP_GT_HH: 1610 case INSTR_JMP_GT_MI: 1611 case INSTR_JMP_GT_HI: 1612 return 1; 1613 1614 default: 1615 return 0; 1616 } 1617 } 1618 1619 static int 1620 instruction_does_thread_yield(struct instruction *instr) 1621 { 1622 switch (instr->type) { 1623 case INSTR_RX: 1624 case INSTR_TABLE: 1625 case INSTR_TABLE_AF: 1626 case INSTR_SELECTOR: 1627 case INSTR_LEARNER: 1628 case INSTR_LEARNER_AF: 1629 case INSTR_EXTERN_OBJ: 1630 case INSTR_EXTERN_FUNC: 1631 return 1; 1632 default: 1633 return 0; 1634 } 1635 } 1636 1637 static struct field * 1638 action_field_parse(struct action *action, const char *name); 1639 1640 static struct field * 1641 struct_field_parse(struct rte_swx_pipeline *p, 1642 struct action *action, 1643 const char *name, 1644 uint32_t *struct_id) 1645 { 1646 struct field *f; 1647 1648 switch (name[0]) { 1649 case 'h': 1650 { 1651 struct header *header; 1652 1653 f = header_field_parse(p, name, &header); 1654 if (!f) 1655 return NULL; 1656 1657 *struct_id = header->struct_id; 1658 return f; 1659 } 1660 1661 case 'm': 1662 { 1663 f = metadata_field_parse(p, name); 1664 if (!f) 1665 return NULL; 1666 1667 *struct_id = p->metadata_struct_id; 1668 return f; 1669 } 1670 1671 case 't': 1672 { 1673 if (!action) 1674 return NULL; 1675 1676 f = action_field_parse(action, name); 1677 if (!f) 1678 return NULL; 1679 1680 *struct_id = 0; 1681 return f; 1682 } 1683 1684 case 'e': 1685 { 1686 struct extern_obj *obj; 1687 1688 f = extern_obj_mailbox_field_parse(p, name, &obj); 1689 if (!f) 1690 return NULL; 1691 1692 *struct_id = obj->struct_id; 1693 return f; 1694 } 1695 1696 case 'f': 1697 { 1698 struct extern_func *func; 1699 1700 f = extern_func_mailbox_field_parse(p, name, &func); 1701 if (!f) 1702 return NULL; 1703 1704 *struct_id = func->struct_id; 1705 return f; 1706 } 1707 1708 default: 1709 return NULL; 1710 } 1711 } 1712 1713 /* 1714 * rx. 1715 */ 1716 static int 1717 instr_rx_translate(struct rte_swx_pipeline *p, 1718 struct action *action, 1719 char **tokens, 1720 int n_tokens, 1721 struct instruction *instr, 1722 struct instruction_data *data __rte_unused) 1723 { 1724 struct field *f; 1725 1726 CHECK(!action, EINVAL); 1727 CHECK(n_tokens == 2, EINVAL); 1728 1729 f = metadata_field_parse(p, tokens[1]); 1730 CHECK(f, EINVAL); 1731 1732 instr->type = INSTR_RX; 1733 instr->io.io.offset = f->offset / 8; 1734 instr->io.io.n_bits = f->n_bits; 1735 return 0; 1736 } 1737 1738 /* 1739 * tx. 1740 */ 1741 static int 1742 instr_tx_translate(struct rte_swx_pipeline *p, 1743 struct action *action __rte_unused, 1744 char **tokens, 1745 int n_tokens, 1746 struct instruction *instr, 1747 struct instruction_data *data __rte_unused) 1748 { 1749 char *port = tokens[1]; 1750 struct field *f; 1751 uint32_t port_val; 1752 1753 CHECK(n_tokens == 2, EINVAL); 1754 1755 f = metadata_field_parse(p, port); 1756 if (f) { 1757 instr->type = INSTR_TX; 1758 instr->io.io.offset = f->offset / 8; 1759 instr->io.io.n_bits = f->n_bits; 1760 return 0; 1761 } 1762 1763 /* TX_I. */ 1764 port_val = strtoul(port, &port, 0); 1765 CHECK(!port[0], EINVAL); 1766 1767 instr->type = INSTR_TX_I; 1768 instr->io.io.val = port_val; 1769 return 0; 1770 } 1771 1772 static int 1773 instr_drop_translate(struct rte_swx_pipeline *p __rte_unused, 1774 struct action *action __rte_unused, 1775 char **tokens __rte_unused, 1776 int n_tokens, 1777 struct instruction *instr, 1778 struct instruction_data *data __rte_unused) 1779 { 1780 CHECK(n_tokens == 1, EINVAL); 1781 1782 /* DROP. */ 1783 instr->type = INSTR_DROP; 1784 return 0; 1785 } 1786 1787 static inline void 1788 instr_tx_exec(struct rte_swx_pipeline *p) 1789 { 1790 struct thread *t = &p->threads[p->thread_id]; 1791 struct instruction *ip = t->ip; 1792 1793 __instr_tx_exec(p, t, ip); 1794 1795 /* Thread. */ 1796 thread_ip_reset(p, t); 1797 instr_rx_exec(p); 1798 } 1799 1800 static inline void 1801 instr_tx_i_exec(struct rte_swx_pipeline *p) 1802 { 1803 struct thread *t = &p->threads[p->thread_id]; 1804 struct instruction *ip = t->ip; 1805 1806 __instr_tx_i_exec(p, t, ip); 1807 1808 /* Thread. */ 1809 thread_ip_reset(p, t); 1810 instr_rx_exec(p); 1811 } 1812 1813 static inline void 1814 instr_drop_exec(struct rte_swx_pipeline *p) 1815 { 1816 struct thread *t = &p->threads[p->thread_id]; 1817 struct instruction *ip = t->ip; 1818 1819 __instr_drop_exec(p, t, ip); 1820 1821 /* Thread. */ 1822 thread_ip_reset(p, t); 1823 instr_rx_exec(p); 1824 } 1825 1826 /* 1827 * mirror. 1828 */ 1829 static int 1830 instr_mirror_translate(struct rte_swx_pipeline *p, 1831 struct action *action, 1832 char **tokens, 1833 int n_tokens, 1834 struct instruction *instr, 1835 struct instruction_data *data __rte_unused) 1836 { 1837 char *dst = tokens[1], *src = tokens[2]; 1838 struct field *fdst, *fsrc; 1839 uint32_t dst_struct_id = 0, src_struct_id = 0; 1840 1841 CHECK(n_tokens == 3, EINVAL); 1842 1843 fdst = struct_field_parse(p, action, dst, &dst_struct_id); 1844 CHECK(fdst, EINVAL); 1845 CHECK(dst[0] != 'h', EINVAL); 1846 CHECK(!fdst->var_size, EINVAL); 1847 1848 fsrc = struct_field_parse(p, action, src, &src_struct_id); 1849 CHECK(fsrc, EINVAL); 1850 CHECK(src[0] != 'h', EINVAL); 1851 CHECK(!fsrc->var_size, EINVAL); 1852 1853 instr->type = INSTR_MIRROR; 1854 instr->mirror.dst.struct_id = (uint8_t)dst_struct_id; 1855 instr->mirror.dst.n_bits = fdst->n_bits; 1856 instr->mirror.dst.offset = fdst->offset / 8; 1857 instr->mirror.src.struct_id = (uint8_t)src_struct_id; 1858 instr->mirror.src.n_bits = fsrc->n_bits; 1859 instr->mirror.src.offset = fsrc->offset / 8; 1860 1861 return 0; 1862 } 1863 1864 static inline void 1865 instr_mirror_exec(struct rte_swx_pipeline *p) 1866 { 1867 struct thread *t = &p->threads[p->thread_id]; 1868 struct instruction *ip = t->ip; 1869 1870 __instr_mirror_exec(p, t, ip); 1871 1872 /* Thread. */ 1873 thread_ip_inc(p); 1874 } 1875 1876 /* 1877 * recirculate. 1878 */ 1879 static int 1880 instr_recirculate_translate(struct rte_swx_pipeline *p __rte_unused, 1881 struct action *action __rte_unused, 1882 char **tokens __rte_unused, 1883 int n_tokens, 1884 struct instruction *instr, 1885 struct instruction_data *data __rte_unused) 1886 { 1887 CHECK(n_tokens == 1, EINVAL); 1888 1889 instr->type = INSTR_RECIRCULATE; 1890 return 0; 1891 } 1892 1893 static int 1894 instr_recircid_translate(struct rte_swx_pipeline *p, 1895 struct action *action __rte_unused, 1896 char **tokens, 1897 int n_tokens, 1898 struct instruction *instr, 1899 struct instruction_data *data __rte_unused) 1900 { 1901 struct field *f; 1902 1903 CHECK(n_tokens == 2, EINVAL); 1904 1905 f = metadata_field_parse(p, tokens[1]); 1906 CHECK(f, EINVAL); 1907 1908 instr->type = INSTR_RECIRCID; 1909 instr->io.io.offset = f->offset / 8; 1910 instr->io.io.n_bits = f->n_bits; 1911 return 0; 1912 } 1913 1914 static inline void 1915 instr_recirculate_exec(struct rte_swx_pipeline *p) 1916 { 1917 struct thread *t = &p->threads[p->thread_id]; 1918 struct instruction *ip = t->ip; 1919 1920 __instr_recirculate_exec(p, t, ip); 1921 1922 /* Thread. */ 1923 thread_ip_inc(p); 1924 } 1925 1926 static inline void 1927 instr_recircid_exec(struct rte_swx_pipeline *p) 1928 { 1929 struct thread *t = &p->threads[p->thread_id]; 1930 struct instruction *ip = t->ip; 1931 1932 __instr_recircid_exec(p, t, ip); 1933 1934 /* Thread. */ 1935 thread_ip_inc(p); 1936 } 1937 1938 /* 1939 * extract. 1940 */ 1941 static int 1942 instr_hdr_extract_translate(struct rte_swx_pipeline *p, 1943 struct action *action, 1944 char **tokens, 1945 int n_tokens, 1946 struct instruction *instr, 1947 struct instruction_data *data __rte_unused) 1948 { 1949 struct header *h; 1950 1951 CHECK(!action, EINVAL); 1952 CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL); 1953 1954 h = header_parse(p, tokens[1]); 1955 CHECK(h, EINVAL); 1956 1957 if (n_tokens == 2) { 1958 CHECK(!h->st->var_size, EINVAL); 1959 1960 instr->type = INSTR_HDR_EXTRACT; 1961 instr->io.hdr.header_id[0] = h->id; 1962 instr->io.hdr.struct_id[0] = h->struct_id; 1963 instr->io.hdr.n_bytes[0] = h->st->n_bits / 8; 1964 } else { 1965 struct field *mf; 1966 1967 CHECK(h->st->var_size, EINVAL); 1968 1969 mf = metadata_field_parse(p, tokens[2]); 1970 CHECK(mf, EINVAL); 1971 CHECK(!mf->var_size, EINVAL); 1972 1973 instr->type = INSTR_HDR_EXTRACT_M; 1974 instr->io.io.offset = mf->offset / 8; 1975 instr->io.io.n_bits = mf->n_bits; 1976 instr->io.hdr.header_id[0] = h->id; 1977 instr->io.hdr.struct_id[0] = h->struct_id; 1978 instr->io.hdr.n_bytes[0] = h->st->n_bits_min / 8; 1979 } 1980 1981 return 0; 1982 } 1983 1984 static int 1985 instr_hdr_lookahead_translate(struct rte_swx_pipeline *p, 1986 struct action *action, 1987 char **tokens, 1988 int n_tokens, 1989 struct instruction *instr, 1990 struct instruction_data *data __rte_unused) 1991 { 1992 struct header *h; 1993 1994 CHECK(!action, EINVAL); 1995 CHECK(n_tokens == 2, EINVAL); 1996 1997 h = header_parse(p, tokens[1]); 1998 CHECK(h, EINVAL); 1999 CHECK(!h->st->var_size, EINVAL); 2000 2001 instr->type = INSTR_HDR_LOOKAHEAD; 2002 instr->io.hdr.header_id[0] = h->id; 2003 instr->io.hdr.struct_id[0] = h->struct_id; 2004 instr->io.hdr.n_bytes[0] = 0; /* Unused. */ 2005 2006 return 0; 2007 } 2008 2009 static inline void 2010 instr_hdr_extract_exec(struct rte_swx_pipeline *p) 2011 { 2012 struct thread *t = &p->threads[p->thread_id]; 2013 struct instruction *ip = t->ip; 2014 2015 __instr_hdr_extract_exec(p, t, ip); 2016 2017 /* Thread. */ 2018 thread_ip_inc(p); 2019 } 2020 2021 static inline void 2022 instr_hdr_extract2_exec(struct rte_swx_pipeline *p) 2023 { 2024 struct thread *t = &p->threads[p->thread_id]; 2025 struct instruction *ip = t->ip; 2026 2027 __instr_hdr_extract2_exec(p, t, ip); 2028 2029 /* Thread. */ 2030 thread_ip_inc(p); 2031 } 2032 2033 static inline void 2034 instr_hdr_extract3_exec(struct rte_swx_pipeline *p) 2035 { 2036 struct thread *t = &p->threads[p->thread_id]; 2037 struct instruction *ip = t->ip; 2038 2039 __instr_hdr_extract3_exec(p, t, ip); 2040 2041 /* Thread. */ 2042 thread_ip_inc(p); 2043 } 2044 2045 static inline void 2046 instr_hdr_extract4_exec(struct rte_swx_pipeline *p) 2047 { 2048 struct thread *t = &p->threads[p->thread_id]; 2049 struct instruction *ip = t->ip; 2050 2051 __instr_hdr_extract4_exec(p, t, ip); 2052 2053 /* Thread. */ 2054 thread_ip_inc(p); 2055 } 2056 2057 static inline void 2058 instr_hdr_extract5_exec(struct rte_swx_pipeline *p) 2059 { 2060 struct thread *t = &p->threads[p->thread_id]; 2061 struct instruction *ip = t->ip; 2062 2063 __instr_hdr_extract5_exec(p, t, ip); 2064 2065 /* Thread. */ 2066 thread_ip_inc(p); 2067 } 2068 2069 static inline void 2070 instr_hdr_extract6_exec(struct rte_swx_pipeline *p) 2071 { 2072 struct thread *t = &p->threads[p->thread_id]; 2073 struct instruction *ip = t->ip; 2074 2075 __instr_hdr_extract6_exec(p, t, ip); 2076 2077 /* Thread. */ 2078 thread_ip_inc(p); 2079 } 2080 2081 static inline void 2082 instr_hdr_extract7_exec(struct rte_swx_pipeline *p) 2083 { 2084 struct thread *t = &p->threads[p->thread_id]; 2085 struct instruction *ip = t->ip; 2086 2087 __instr_hdr_extract7_exec(p, t, ip); 2088 2089 /* Thread. */ 2090 thread_ip_inc(p); 2091 } 2092 2093 static inline void 2094 instr_hdr_extract8_exec(struct rte_swx_pipeline *p) 2095 { 2096 struct thread *t = &p->threads[p->thread_id]; 2097 struct instruction *ip = t->ip; 2098 2099 __instr_hdr_extract8_exec(p, t, ip); 2100 2101 /* Thread. */ 2102 thread_ip_inc(p); 2103 } 2104 2105 static inline void 2106 instr_hdr_extract_m_exec(struct rte_swx_pipeline *p) 2107 { 2108 struct thread *t = &p->threads[p->thread_id]; 2109 struct instruction *ip = t->ip; 2110 2111 __instr_hdr_extract_m_exec(p, t, ip); 2112 2113 /* Thread. */ 2114 thread_ip_inc(p); 2115 } 2116 2117 static inline void 2118 instr_hdr_lookahead_exec(struct rte_swx_pipeline *p) 2119 { 2120 struct thread *t = &p->threads[p->thread_id]; 2121 struct instruction *ip = t->ip; 2122 2123 __instr_hdr_lookahead_exec(p, t, ip); 2124 2125 /* Thread. */ 2126 thread_ip_inc(p); 2127 } 2128 2129 /* 2130 * emit. 2131 */ 2132 static int 2133 instr_hdr_emit_translate(struct rte_swx_pipeline *p, 2134 struct action *action __rte_unused, 2135 char **tokens, 2136 int n_tokens, 2137 struct instruction *instr, 2138 struct instruction_data *data __rte_unused) 2139 { 2140 struct header *h; 2141 2142 CHECK(n_tokens == 2, EINVAL); 2143 2144 h = header_parse(p, tokens[1]); 2145 CHECK(h, EINVAL); 2146 2147 instr->type = INSTR_HDR_EMIT; 2148 instr->io.hdr.header_id[0] = h->id; 2149 instr->io.hdr.struct_id[0] = h->struct_id; 2150 instr->io.hdr.n_bytes[0] = h->st->n_bits / 8; 2151 return 0; 2152 } 2153 2154 static inline void 2155 instr_hdr_emit_exec(struct rte_swx_pipeline *p) 2156 { 2157 struct thread *t = &p->threads[p->thread_id]; 2158 struct instruction *ip = t->ip; 2159 2160 __instr_hdr_emit_exec(p, t, ip); 2161 2162 /* Thread. */ 2163 thread_ip_inc(p); 2164 } 2165 2166 static inline void 2167 instr_hdr_emit_tx_exec(struct rte_swx_pipeline *p) 2168 { 2169 struct thread *t = &p->threads[p->thread_id]; 2170 struct instruction *ip = t->ip; 2171 2172 __instr_hdr_emit_tx_exec(p, t, ip); 2173 2174 /* Thread. */ 2175 thread_ip_reset(p, t); 2176 instr_rx_exec(p); 2177 } 2178 2179 static inline void 2180 instr_hdr_emit2_tx_exec(struct rte_swx_pipeline *p) 2181 { 2182 struct thread *t = &p->threads[p->thread_id]; 2183 struct instruction *ip = t->ip; 2184 2185 __instr_hdr_emit2_tx_exec(p, t, ip); 2186 2187 /* Thread. */ 2188 thread_ip_reset(p, t); 2189 instr_rx_exec(p); 2190 } 2191 2192 static inline void 2193 instr_hdr_emit3_tx_exec(struct rte_swx_pipeline *p) 2194 { 2195 struct thread *t = &p->threads[p->thread_id]; 2196 struct instruction *ip = t->ip; 2197 2198 __instr_hdr_emit3_tx_exec(p, t, ip); 2199 2200 /* Thread. */ 2201 thread_ip_reset(p, t); 2202 instr_rx_exec(p); 2203 } 2204 2205 static inline void 2206 instr_hdr_emit4_tx_exec(struct rte_swx_pipeline *p) 2207 { 2208 struct thread *t = &p->threads[p->thread_id]; 2209 struct instruction *ip = t->ip; 2210 2211 __instr_hdr_emit4_tx_exec(p, t, ip); 2212 2213 /* Thread. */ 2214 thread_ip_reset(p, t); 2215 instr_rx_exec(p); 2216 } 2217 2218 static inline void 2219 instr_hdr_emit5_tx_exec(struct rte_swx_pipeline *p) 2220 { 2221 struct thread *t = &p->threads[p->thread_id]; 2222 struct instruction *ip = t->ip; 2223 2224 __instr_hdr_emit5_tx_exec(p, t, ip); 2225 2226 /* Thread. */ 2227 thread_ip_reset(p, t); 2228 instr_rx_exec(p); 2229 } 2230 2231 static inline void 2232 instr_hdr_emit6_tx_exec(struct rte_swx_pipeline *p) 2233 { 2234 struct thread *t = &p->threads[p->thread_id]; 2235 struct instruction *ip = t->ip; 2236 2237 __instr_hdr_emit6_tx_exec(p, t, ip); 2238 2239 /* Thread. */ 2240 thread_ip_reset(p, t); 2241 instr_rx_exec(p); 2242 } 2243 2244 static inline void 2245 instr_hdr_emit7_tx_exec(struct rte_swx_pipeline *p) 2246 { 2247 struct thread *t = &p->threads[p->thread_id]; 2248 struct instruction *ip = t->ip; 2249 2250 __instr_hdr_emit7_tx_exec(p, t, ip); 2251 2252 /* Thread. */ 2253 thread_ip_reset(p, t); 2254 instr_rx_exec(p); 2255 } 2256 2257 static inline void 2258 instr_hdr_emit8_tx_exec(struct rte_swx_pipeline *p) 2259 { 2260 struct thread *t = &p->threads[p->thread_id]; 2261 struct instruction *ip = t->ip; 2262 2263 __instr_hdr_emit8_tx_exec(p, t, ip); 2264 2265 /* Thread. */ 2266 thread_ip_reset(p, t); 2267 instr_rx_exec(p); 2268 } 2269 2270 /* 2271 * validate. 2272 */ 2273 static int 2274 instr_hdr_validate_translate(struct rte_swx_pipeline *p, 2275 struct action *action __rte_unused, 2276 char **tokens, 2277 int n_tokens, 2278 struct instruction *instr, 2279 struct instruction_data *data __rte_unused) 2280 { 2281 struct header *h; 2282 2283 CHECK(n_tokens == 2, EINVAL); 2284 2285 h = header_parse(p, tokens[1]); 2286 CHECK(h, EINVAL); 2287 2288 instr->type = INSTR_HDR_VALIDATE; 2289 instr->valid.header_id = h->id; 2290 return 0; 2291 } 2292 2293 static inline void 2294 instr_hdr_validate_exec(struct rte_swx_pipeline *p) 2295 { 2296 struct thread *t = &p->threads[p->thread_id]; 2297 struct instruction *ip = t->ip; 2298 2299 __instr_hdr_validate_exec(p, t, ip); 2300 2301 /* Thread. */ 2302 thread_ip_inc(p); 2303 } 2304 2305 /* 2306 * invalidate. 2307 */ 2308 static int 2309 instr_hdr_invalidate_translate(struct rte_swx_pipeline *p, 2310 struct action *action __rte_unused, 2311 char **tokens, 2312 int n_tokens, 2313 struct instruction *instr, 2314 struct instruction_data *data __rte_unused) 2315 { 2316 struct header *h; 2317 2318 CHECK(n_tokens == 2, EINVAL); 2319 2320 h = header_parse(p, tokens[1]); 2321 CHECK(h, EINVAL); 2322 2323 instr->type = INSTR_HDR_INVALIDATE; 2324 instr->valid.header_id = h->id; 2325 return 0; 2326 } 2327 2328 static inline void 2329 instr_hdr_invalidate_exec(struct rte_swx_pipeline *p) 2330 { 2331 struct thread *t = &p->threads[p->thread_id]; 2332 struct instruction *ip = t->ip; 2333 2334 __instr_hdr_invalidate_exec(p, t, ip); 2335 2336 /* Thread. */ 2337 thread_ip_inc(p); 2338 } 2339 2340 /* 2341 * table. 2342 */ 2343 static struct table * 2344 table_find(struct rte_swx_pipeline *p, const char *name); 2345 2346 static struct selector * 2347 selector_find(struct rte_swx_pipeline *p, const char *name); 2348 2349 static struct learner * 2350 learner_find(struct rte_swx_pipeline *p, const char *name); 2351 2352 static int 2353 instr_table_translate(struct rte_swx_pipeline *p, 2354 struct action *action, 2355 char **tokens, 2356 int n_tokens, 2357 struct instruction *instr, 2358 struct instruction_data *data __rte_unused) 2359 { 2360 struct table *t; 2361 struct selector *s; 2362 struct learner *l; 2363 2364 CHECK(!action, EINVAL); 2365 CHECK(n_tokens == 2, EINVAL); 2366 2367 t = table_find(p, tokens[1]); 2368 if (t) { 2369 instr->type = INSTR_TABLE; 2370 instr->table.table_id = t->id; 2371 return 0; 2372 } 2373 2374 s = selector_find(p, tokens[1]); 2375 if (s) { 2376 instr->type = INSTR_SELECTOR; 2377 instr->table.table_id = s->id; 2378 return 0; 2379 } 2380 2381 l = learner_find(p, tokens[1]); 2382 if (l) { 2383 instr->type = INSTR_LEARNER; 2384 instr->table.table_id = l->id; 2385 return 0; 2386 } 2387 2388 CHECK(0, EINVAL); 2389 } 2390 2391 static inline void 2392 instr_table_exec(struct rte_swx_pipeline *p) 2393 { 2394 struct thread *t = &p->threads[p->thread_id]; 2395 struct instruction *ip = t->ip; 2396 uint32_t table_id = ip->table.table_id; 2397 struct rte_swx_table_state *ts = &t->table_state[table_id]; 2398 struct table_runtime *table = &t->tables[table_id]; 2399 struct table_statistics *stats = &p->table_stats[table_id]; 2400 uint64_t action_id, n_pkts_hit, n_pkts_action; 2401 uint8_t *action_data; 2402 int done, hit; 2403 2404 /* Table. */ 2405 done = table->func(ts->obj, 2406 table->mailbox, 2407 table->key, 2408 &action_id, 2409 &action_data, 2410 &hit); 2411 if (!done) { 2412 /* Thread. */ 2413 TRACE("[Thread %2u] table %u (not finalized)\n", 2414 p->thread_id, 2415 table_id); 2416 2417 thread_yield(p); 2418 return; 2419 } 2420 2421 action_id = hit ? action_id : ts->default_action_id; 2422 action_data = hit ? action_data : ts->default_action_data; 2423 n_pkts_hit = stats->n_pkts_hit[hit]; 2424 n_pkts_action = stats->n_pkts_action[action_id]; 2425 2426 TRACE("[Thread %2u] table %u (%s, action %u)\n", 2427 p->thread_id, 2428 table_id, 2429 hit ? "hit" : "miss", 2430 (uint32_t)action_id); 2431 2432 t->action_id = action_id; 2433 t->structs[0] = action_data; 2434 t->hit = hit; 2435 stats->n_pkts_hit[hit] = n_pkts_hit + 1; 2436 stats->n_pkts_action[action_id] = n_pkts_action + 1; 2437 2438 /* Thread. */ 2439 thread_ip_action_call(p, t, action_id); 2440 } 2441 2442 static inline void 2443 instr_table_af_exec(struct rte_swx_pipeline *p) 2444 { 2445 struct thread *t = &p->threads[p->thread_id]; 2446 struct instruction *ip = t->ip; 2447 uint32_t table_id = ip->table.table_id; 2448 struct rte_swx_table_state *ts = &t->table_state[table_id]; 2449 struct table_runtime *table = &t->tables[table_id]; 2450 struct table_statistics *stats = &p->table_stats[table_id]; 2451 uint64_t action_id, n_pkts_hit, n_pkts_action; 2452 uint8_t *action_data; 2453 action_func_t action_func; 2454 int done, hit; 2455 2456 /* Table. */ 2457 done = table->func(ts->obj, 2458 table->mailbox, 2459 table->key, 2460 &action_id, 2461 &action_data, 2462 &hit); 2463 if (!done) { 2464 /* Thread. */ 2465 TRACE("[Thread %2u] table %u (not finalized)\n", 2466 p->thread_id, 2467 table_id); 2468 2469 thread_yield(p); 2470 return; 2471 } 2472 2473 action_id = hit ? action_id : ts->default_action_id; 2474 action_data = hit ? action_data : ts->default_action_data; 2475 action_func = p->action_funcs[action_id]; 2476 n_pkts_hit = stats->n_pkts_hit[hit]; 2477 n_pkts_action = stats->n_pkts_action[action_id]; 2478 2479 TRACE("[Thread %2u] table %u (%s, action %u)\n", 2480 p->thread_id, 2481 table_id, 2482 hit ? "hit" : "miss", 2483 (uint32_t)action_id); 2484 2485 t->action_id = action_id; 2486 t->structs[0] = action_data; 2487 t->hit = hit; 2488 stats->n_pkts_hit[hit] = n_pkts_hit + 1; 2489 stats->n_pkts_action[action_id] = n_pkts_action + 1; 2490 2491 /* Thread. */ 2492 thread_ip_inc(p); 2493 2494 /* Action. */ 2495 action_func(p); 2496 } 2497 2498 static inline void 2499 instr_selector_exec(struct rte_swx_pipeline *p) 2500 { 2501 struct thread *t = &p->threads[p->thread_id]; 2502 struct instruction *ip = t->ip; 2503 uint32_t selector_id = ip->table.table_id; 2504 struct rte_swx_table_state *ts = &t->table_state[p->n_tables + selector_id]; 2505 struct selector_runtime *selector = &t->selectors[selector_id]; 2506 struct selector_statistics *stats = &p->selector_stats[selector_id]; 2507 uint64_t n_pkts = stats->n_pkts; 2508 int done; 2509 2510 /* Table. */ 2511 done = rte_swx_table_selector_select(ts->obj, 2512 selector->mailbox, 2513 selector->group_id_buffer, 2514 selector->selector_buffer, 2515 selector->member_id_buffer); 2516 if (!done) { 2517 /* Thread. */ 2518 TRACE("[Thread %2u] selector %u (not finalized)\n", 2519 p->thread_id, 2520 selector_id); 2521 2522 thread_yield(p); 2523 return; 2524 } 2525 2526 2527 TRACE("[Thread %2u] selector %u\n", 2528 p->thread_id, 2529 selector_id); 2530 2531 stats->n_pkts = n_pkts + 1; 2532 2533 /* Thread. */ 2534 thread_ip_inc(p); 2535 } 2536 2537 static inline void 2538 instr_learner_exec(struct rte_swx_pipeline *p) 2539 { 2540 struct thread *t = &p->threads[p->thread_id]; 2541 struct instruction *ip = t->ip; 2542 uint32_t learner_id = ip->table.table_id; 2543 struct rte_swx_table_state *ts = &t->table_state[p->n_tables + 2544 p->n_selectors + learner_id]; 2545 struct learner_runtime *l = &t->learners[learner_id]; 2546 struct learner_statistics *stats = &p->learner_stats[learner_id]; 2547 uint64_t action_id, n_pkts_hit, n_pkts_action, time; 2548 uint8_t *action_data; 2549 int done, hit; 2550 2551 /* Table. */ 2552 time = rte_get_tsc_cycles(); 2553 2554 done = rte_swx_table_learner_lookup(ts->obj, 2555 l->mailbox, 2556 time, 2557 l->key, 2558 &action_id, 2559 &action_data, 2560 &hit); 2561 if (!done) { 2562 /* Thread. */ 2563 TRACE("[Thread %2u] learner %u (not finalized)\n", 2564 p->thread_id, 2565 learner_id); 2566 2567 thread_yield(p); 2568 return; 2569 } 2570 2571 action_id = hit ? action_id : ts->default_action_id; 2572 action_data = hit ? action_data : ts->default_action_data; 2573 n_pkts_hit = stats->n_pkts_hit[hit]; 2574 n_pkts_action = stats->n_pkts_action[action_id]; 2575 2576 TRACE("[Thread %2u] learner %u (%s, action %u)\n", 2577 p->thread_id, 2578 learner_id, 2579 hit ? "hit" : "miss", 2580 (uint32_t)action_id); 2581 2582 t->action_id = action_id; 2583 t->structs[0] = action_data; 2584 t->hit = hit; 2585 t->learner_id = learner_id; 2586 t->time = time; 2587 stats->n_pkts_hit[hit] = n_pkts_hit + 1; 2588 stats->n_pkts_action[action_id] = n_pkts_action + 1; 2589 2590 /* Thread. */ 2591 thread_ip_action_call(p, t, action_id); 2592 } 2593 2594 static inline void 2595 instr_learner_af_exec(struct rte_swx_pipeline *p) 2596 { 2597 struct thread *t = &p->threads[p->thread_id]; 2598 struct instruction *ip = t->ip; 2599 uint32_t learner_id = ip->table.table_id; 2600 struct rte_swx_table_state *ts = &t->table_state[p->n_tables + 2601 p->n_selectors + learner_id]; 2602 struct learner_runtime *l = &t->learners[learner_id]; 2603 struct learner_statistics *stats = &p->learner_stats[learner_id]; 2604 uint64_t action_id, n_pkts_hit, n_pkts_action, time; 2605 uint8_t *action_data; 2606 action_func_t action_func; 2607 int done, hit; 2608 2609 /* Table. */ 2610 time = rte_get_tsc_cycles(); 2611 2612 done = rte_swx_table_learner_lookup(ts->obj, 2613 l->mailbox, 2614 time, 2615 l->key, 2616 &action_id, 2617 &action_data, 2618 &hit); 2619 if (!done) { 2620 /* Thread. */ 2621 TRACE("[Thread %2u] learner %u (not finalized)\n", 2622 p->thread_id, 2623 learner_id); 2624 2625 thread_yield(p); 2626 return; 2627 } 2628 2629 action_id = hit ? action_id : ts->default_action_id; 2630 action_data = hit ? action_data : ts->default_action_data; 2631 action_func = p->action_funcs[action_id]; 2632 n_pkts_hit = stats->n_pkts_hit[hit]; 2633 n_pkts_action = stats->n_pkts_action[action_id]; 2634 2635 TRACE("[Thread %2u] learner %u (%s, action %u)\n", 2636 p->thread_id, 2637 learner_id, 2638 hit ? "hit" : "miss", 2639 (uint32_t)action_id); 2640 2641 t->action_id = action_id; 2642 t->structs[0] = action_data; 2643 t->hit = hit; 2644 t->learner_id = learner_id; 2645 t->time = time; 2646 stats->n_pkts_hit[hit] = n_pkts_hit + 1; 2647 stats->n_pkts_action[action_id] = n_pkts_action + 1; 2648 2649 /* Thread. */ 2650 thread_ip_inc(p); 2651 2652 /* Action */ 2653 action_func(p); 2654 } 2655 2656 /* 2657 * learn. 2658 */ 2659 static struct action * 2660 action_find(struct rte_swx_pipeline *p, const char *name); 2661 2662 static int 2663 action_has_nbo_args(struct action *a); 2664 2665 static int 2666 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name); 2667 2668 static int 2669 instr_learn_translate(struct rte_swx_pipeline *p, 2670 struct action *action, 2671 char **tokens, 2672 int n_tokens, 2673 struct instruction *instr, 2674 struct instruction_data *data __rte_unused) 2675 { 2676 struct action *a; 2677 struct field *mf_first_arg = NULL, *mf_timeout_id = NULL; 2678 const char *mf_first_arg_name, *mf_timeout_id_name; 2679 2680 CHECK(action, EINVAL); 2681 CHECK((n_tokens == 3) || (n_tokens == 4), EINVAL); 2682 2683 /* Action. */ 2684 a = action_find(p, tokens[1]); 2685 CHECK(a, EINVAL); 2686 CHECK(!action_has_nbo_args(a), EINVAL); 2687 2688 /* Action first argument. */ 2689 mf_first_arg_name = (n_tokens == 4) ? tokens[2] : NULL; 2690 CHECK(!learner_action_args_check(p, a, mf_first_arg_name), EINVAL); 2691 2692 if (mf_first_arg_name) { 2693 mf_first_arg = metadata_field_parse(p, mf_first_arg_name); 2694 CHECK(mf_first_arg, EINVAL); 2695 } 2696 2697 /* Timeout ID. */ 2698 mf_timeout_id_name = (n_tokens == 4) ? tokens[3] : tokens[2]; 2699 CHECK_NAME(mf_timeout_id_name, EINVAL); 2700 mf_timeout_id = metadata_field_parse(p, mf_timeout_id_name); 2701 CHECK(mf_timeout_id, EINVAL); 2702 2703 /* Instruction. */ 2704 instr->type = INSTR_LEARNER_LEARN; 2705 instr->learn.action_id = a->id; 2706 instr->learn.mf_first_arg_offset = mf_first_arg ? (mf_first_arg->offset / 8) : 0; 2707 instr->learn.mf_timeout_id_offset = mf_timeout_id->offset / 8; 2708 instr->learn.mf_timeout_id_n_bits = mf_timeout_id->n_bits; 2709 2710 return 0; 2711 } 2712 2713 static inline void 2714 instr_learn_exec(struct rte_swx_pipeline *p) 2715 { 2716 struct thread *t = &p->threads[p->thread_id]; 2717 struct instruction *ip = t->ip; 2718 2719 __instr_learn_exec(p, t, ip); 2720 2721 /* Thread. */ 2722 thread_ip_inc(p); 2723 } 2724 2725 /* 2726 * rearm. 2727 */ 2728 static int 2729 instr_rearm_translate(struct rte_swx_pipeline *p, 2730 struct action *action, 2731 char **tokens, 2732 int n_tokens, 2733 struct instruction *instr, 2734 struct instruction_data *data __rte_unused) 2735 { 2736 struct field *mf_timeout_id; 2737 const char *mf_timeout_id_name; 2738 2739 CHECK(action, EINVAL); 2740 CHECK((n_tokens == 1) || (n_tokens == 2), EINVAL); 2741 2742 /* INSTR_LEARNER_REARM. */ 2743 if (n_tokens == 1) { 2744 instr->type = INSTR_LEARNER_REARM; 2745 return 0; 2746 } 2747 2748 /* INSTR_LEARNER_REARM_NEW. */ 2749 mf_timeout_id_name = tokens[1]; 2750 CHECK_NAME(mf_timeout_id_name, EINVAL); 2751 mf_timeout_id = metadata_field_parse(p, mf_timeout_id_name); 2752 CHECK(mf_timeout_id, EINVAL); 2753 2754 instr->type = INSTR_LEARNER_REARM_NEW; 2755 instr->learn.mf_timeout_id_offset = mf_timeout_id->offset / 8; 2756 instr->learn.mf_timeout_id_n_bits = mf_timeout_id->n_bits; 2757 2758 return 0; 2759 } 2760 2761 static inline void 2762 instr_rearm_exec(struct rte_swx_pipeline *p) 2763 { 2764 struct thread *t = &p->threads[p->thread_id]; 2765 struct instruction *ip = t->ip; 2766 2767 __instr_rearm_exec(p, t, ip); 2768 2769 /* Thread. */ 2770 thread_ip_inc(p); 2771 } 2772 2773 static inline void 2774 instr_rearm_new_exec(struct rte_swx_pipeline *p) 2775 { 2776 struct thread *t = &p->threads[p->thread_id]; 2777 struct instruction *ip = t->ip; 2778 2779 __instr_rearm_new_exec(p, t, ip); 2780 2781 /* Thread. */ 2782 thread_ip_inc(p); 2783 } 2784 2785 /* 2786 * forget. 2787 */ 2788 static int 2789 instr_forget_translate(struct rte_swx_pipeline *p __rte_unused, 2790 struct action *action, 2791 char **tokens __rte_unused, 2792 int n_tokens, 2793 struct instruction *instr, 2794 struct instruction_data *data __rte_unused) 2795 { 2796 CHECK(action, EINVAL); 2797 CHECK(n_tokens == 1, EINVAL); 2798 2799 instr->type = INSTR_LEARNER_FORGET; 2800 2801 return 0; 2802 } 2803 2804 static inline void 2805 instr_forget_exec(struct rte_swx_pipeline *p) 2806 { 2807 struct thread *t = &p->threads[p->thread_id]; 2808 struct instruction *ip = t->ip; 2809 2810 __instr_forget_exec(p, t, ip); 2811 2812 /* Thread. */ 2813 thread_ip_inc(p); 2814 } 2815 2816 /* 2817 * extern. 2818 */ 2819 static int 2820 instr_extern_translate(struct rte_swx_pipeline *p, 2821 struct action *action __rte_unused, 2822 char **tokens, 2823 int n_tokens, 2824 struct instruction *instr, 2825 struct instruction_data *data __rte_unused) 2826 { 2827 char *token = tokens[1]; 2828 2829 CHECK(n_tokens == 2, EINVAL); 2830 2831 if (token[0] == 'e') { 2832 struct extern_obj *obj; 2833 struct extern_type_member_func *func; 2834 2835 func = extern_obj_member_func_parse(p, token, &obj); 2836 CHECK(func, EINVAL); 2837 2838 instr->type = INSTR_EXTERN_OBJ; 2839 instr->ext_obj.ext_obj_id = obj->id; 2840 instr->ext_obj.func_id = func->id; 2841 2842 return 0; 2843 } 2844 2845 if (token[0] == 'f') { 2846 struct extern_func *func; 2847 2848 func = extern_func_parse(p, token); 2849 CHECK(func, EINVAL); 2850 2851 instr->type = INSTR_EXTERN_FUNC; 2852 instr->ext_func.ext_func_id = func->id; 2853 2854 return 0; 2855 } 2856 2857 CHECK(0, EINVAL); 2858 } 2859 2860 static inline void 2861 instr_extern_obj_exec(struct rte_swx_pipeline *p) 2862 { 2863 struct thread *t = &p->threads[p->thread_id]; 2864 struct instruction *ip = t->ip; 2865 uint32_t done; 2866 2867 /* Extern object member function execute. */ 2868 done = __instr_extern_obj_exec(p, t, ip); 2869 2870 /* Thread. */ 2871 thread_ip_inc_cond(t, done); 2872 thread_yield_cond(p, done ^ 1); 2873 } 2874 2875 static inline void 2876 instr_extern_func_exec(struct rte_swx_pipeline *p) 2877 { 2878 struct thread *t = &p->threads[p->thread_id]; 2879 struct instruction *ip = t->ip; 2880 uint32_t done; 2881 2882 /* Extern function execute. */ 2883 done = __instr_extern_func_exec(p, t, ip); 2884 2885 /* Thread. */ 2886 thread_ip_inc_cond(t, done); 2887 thread_yield_cond(p, done ^ 1); 2888 } 2889 2890 /* 2891 * hash. 2892 */ 2893 static int 2894 instr_hash_translate(struct rte_swx_pipeline *p, 2895 struct action *action, 2896 char **tokens, 2897 int n_tokens, 2898 struct instruction *instr, 2899 struct instruction_data *data __rte_unused) 2900 { 2901 struct hash_func *func; 2902 struct field *dst, *src_first, *src_last; 2903 uint32_t src_struct_id_first = 0, src_struct_id_last = 0; 2904 2905 CHECK(n_tokens == 5, EINVAL); 2906 2907 func = hash_func_find(p, tokens[1]); 2908 CHECK(func, EINVAL); 2909 2910 dst = metadata_field_parse(p, tokens[2]); 2911 CHECK(dst, EINVAL); 2912 2913 src_first = struct_field_parse(p, action, tokens[3], &src_struct_id_first); 2914 CHECK(src_first, EINVAL); 2915 2916 src_last = struct_field_parse(p, action, tokens[4], &src_struct_id_last); 2917 CHECK(src_last, EINVAL); 2918 CHECK(src_struct_id_first == src_struct_id_last, EINVAL); 2919 2920 instr->type = INSTR_HASH_FUNC; 2921 instr->hash_func.hash_func_id = (uint8_t)func->id; 2922 instr->hash_func.dst.offset = (uint8_t)dst->offset / 8; 2923 instr->hash_func.dst.n_bits = (uint8_t)dst->n_bits; 2924 instr->hash_func.src.struct_id = (uint8_t)src_struct_id_first; 2925 instr->hash_func.src.offset = (uint16_t)src_first->offset / 8; 2926 instr->hash_func.src.n_bytes = (uint16_t)((src_last->offset + src_last->n_bits - 2927 src_first->offset) / 8); 2928 2929 return 0; 2930 } 2931 2932 static inline void 2933 instr_hash_func_exec(struct rte_swx_pipeline *p) 2934 { 2935 struct thread *t = &p->threads[p->thread_id]; 2936 struct instruction *ip = t->ip; 2937 2938 /* Extern function execute. */ 2939 __instr_hash_func_exec(p, t, ip); 2940 2941 /* Thread. */ 2942 thread_ip_inc(p); 2943 } 2944 2945 /* 2946 * mov. 2947 */ 2948 static int 2949 instr_mov_translate(struct rte_swx_pipeline *p, 2950 struct action *action, 2951 char **tokens, 2952 int n_tokens, 2953 struct instruction *instr, 2954 struct instruction_data *data __rte_unused) 2955 { 2956 char *dst = tokens[1], *src = tokens[2]; 2957 struct field *fdst, *fsrc; 2958 uint64_t src_val; 2959 uint32_t dst_struct_id = 0, src_struct_id = 0; 2960 2961 CHECK(n_tokens == 3, EINVAL); 2962 2963 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 2964 CHECK(fdst, EINVAL); 2965 CHECK(!fdst->var_size, EINVAL); 2966 2967 /* MOV, MOV_MH, MOV_HM or MOV_HH. */ 2968 fsrc = struct_field_parse(p, action, src, &src_struct_id); 2969 if (fsrc) { 2970 CHECK(!fsrc->var_size, EINVAL); 2971 2972 instr->type = INSTR_MOV; 2973 if (dst[0] != 'h' && src[0] == 'h') 2974 instr->type = INSTR_MOV_MH; 2975 if (dst[0] == 'h' && src[0] != 'h') 2976 instr->type = INSTR_MOV_HM; 2977 if (dst[0] == 'h' && src[0] == 'h') 2978 instr->type = INSTR_MOV_HH; 2979 2980 instr->mov.dst.struct_id = (uint8_t)dst_struct_id; 2981 instr->mov.dst.n_bits = fdst->n_bits; 2982 instr->mov.dst.offset = fdst->offset / 8; 2983 instr->mov.src.struct_id = (uint8_t)src_struct_id; 2984 instr->mov.src.n_bits = fsrc->n_bits; 2985 instr->mov.src.offset = fsrc->offset / 8; 2986 return 0; 2987 } 2988 2989 /* MOV_I. */ 2990 src_val = strtoull(src, &src, 0); 2991 CHECK(!src[0], EINVAL); 2992 2993 if (dst[0] == 'h') 2994 src_val = hton64(src_val) >> (64 - fdst->n_bits); 2995 2996 instr->type = INSTR_MOV_I; 2997 instr->mov.dst.struct_id = (uint8_t)dst_struct_id; 2998 instr->mov.dst.n_bits = fdst->n_bits; 2999 instr->mov.dst.offset = fdst->offset / 8; 3000 instr->mov.src_val = src_val; 3001 return 0; 3002 } 3003 3004 static inline void 3005 instr_mov_exec(struct rte_swx_pipeline *p) 3006 { 3007 struct thread *t = &p->threads[p->thread_id]; 3008 struct instruction *ip = t->ip; 3009 3010 __instr_mov_exec(p, t, ip); 3011 3012 /* Thread. */ 3013 thread_ip_inc(p); 3014 } 3015 3016 static inline void 3017 instr_mov_mh_exec(struct rte_swx_pipeline *p) 3018 { 3019 struct thread *t = &p->threads[p->thread_id]; 3020 struct instruction *ip = t->ip; 3021 3022 __instr_mov_mh_exec(p, t, ip); 3023 3024 /* Thread. */ 3025 thread_ip_inc(p); 3026 } 3027 3028 static inline void 3029 instr_mov_hm_exec(struct rte_swx_pipeline *p) 3030 { 3031 struct thread *t = &p->threads[p->thread_id]; 3032 struct instruction *ip = t->ip; 3033 3034 __instr_mov_hm_exec(p, t, ip); 3035 3036 /* Thread. */ 3037 thread_ip_inc(p); 3038 } 3039 3040 static inline void 3041 instr_mov_hh_exec(struct rte_swx_pipeline *p) 3042 { 3043 struct thread *t = &p->threads[p->thread_id]; 3044 struct instruction *ip = t->ip; 3045 3046 __instr_mov_hh_exec(p, t, ip); 3047 3048 /* Thread. */ 3049 thread_ip_inc(p); 3050 } 3051 3052 static inline void 3053 instr_mov_i_exec(struct rte_swx_pipeline *p) 3054 { 3055 struct thread *t = &p->threads[p->thread_id]; 3056 struct instruction *ip = t->ip; 3057 3058 __instr_mov_i_exec(p, t, ip); 3059 3060 /* Thread. */ 3061 thread_ip_inc(p); 3062 } 3063 3064 /* 3065 * dma. 3066 */ 3067 static inline void 3068 instr_dma_ht_exec(struct rte_swx_pipeline *p) 3069 { 3070 struct thread *t = &p->threads[p->thread_id]; 3071 struct instruction *ip = t->ip; 3072 3073 __instr_dma_ht_exec(p, t, ip); 3074 3075 /* Thread. */ 3076 thread_ip_inc(p); 3077 } 3078 3079 static inline void 3080 instr_dma_ht2_exec(struct rte_swx_pipeline *p) 3081 { 3082 struct thread *t = &p->threads[p->thread_id]; 3083 struct instruction *ip = t->ip; 3084 3085 __instr_dma_ht2_exec(p, t, ip); 3086 3087 /* Thread. */ 3088 thread_ip_inc(p); 3089 } 3090 3091 static inline void 3092 instr_dma_ht3_exec(struct rte_swx_pipeline *p) 3093 { 3094 struct thread *t = &p->threads[p->thread_id]; 3095 struct instruction *ip = t->ip; 3096 3097 __instr_dma_ht3_exec(p, t, ip); 3098 3099 /* Thread. */ 3100 thread_ip_inc(p); 3101 } 3102 3103 static inline void 3104 instr_dma_ht4_exec(struct rte_swx_pipeline *p) 3105 { 3106 struct thread *t = &p->threads[p->thread_id]; 3107 struct instruction *ip = t->ip; 3108 3109 __instr_dma_ht4_exec(p, t, ip); 3110 3111 /* Thread. */ 3112 thread_ip_inc(p); 3113 } 3114 3115 static inline void 3116 instr_dma_ht5_exec(struct rte_swx_pipeline *p) 3117 { 3118 struct thread *t = &p->threads[p->thread_id]; 3119 struct instruction *ip = t->ip; 3120 3121 __instr_dma_ht5_exec(p, t, ip); 3122 3123 /* Thread. */ 3124 thread_ip_inc(p); 3125 } 3126 3127 static inline void 3128 instr_dma_ht6_exec(struct rte_swx_pipeline *p) 3129 { 3130 struct thread *t = &p->threads[p->thread_id]; 3131 struct instruction *ip = t->ip; 3132 3133 __instr_dma_ht6_exec(p, t, ip); 3134 3135 /* Thread. */ 3136 thread_ip_inc(p); 3137 } 3138 3139 static inline void 3140 instr_dma_ht7_exec(struct rte_swx_pipeline *p) 3141 { 3142 struct thread *t = &p->threads[p->thread_id]; 3143 struct instruction *ip = t->ip; 3144 3145 __instr_dma_ht7_exec(p, t, ip); 3146 3147 /* Thread. */ 3148 thread_ip_inc(p); 3149 } 3150 3151 static inline void 3152 instr_dma_ht8_exec(struct rte_swx_pipeline *p) 3153 { 3154 struct thread *t = &p->threads[p->thread_id]; 3155 struct instruction *ip = t->ip; 3156 3157 __instr_dma_ht8_exec(p, t, ip); 3158 3159 /* Thread. */ 3160 thread_ip_inc(p); 3161 } 3162 3163 /* 3164 * alu. 3165 */ 3166 static int 3167 instr_alu_add_translate(struct rte_swx_pipeline *p, 3168 struct action *action, 3169 char **tokens, 3170 int n_tokens, 3171 struct instruction *instr, 3172 struct instruction_data *data __rte_unused) 3173 { 3174 char *dst = tokens[1], *src = tokens[2]; 3175 struct field *fdst, *fsrc; 3176 uint64_t src_val; 3177 uint32_t dst_struct_id = 0, src_struct_id = 0; 3178 3179 CHECK(n_tokens == 3, EINVAL); 3180 3181 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3182 CHECK(fdst, EINVAL); 3183 CHECK(!fdst->var_size, EINVAL); 3184 3185 /* ADD, ADD_HM, ADD_MH, ADD_HH. */ 3186 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3187 if (fsrc) { 3188 CHECK(!fsrc->var_size, EINVAL); 3189 3190 instr->type = INSTR_ALU_ADD; 3191 if (dst[0] == 'h' && src[0] != 'h') 3192 instr->type = INSTR_ALU_ADD_HM; 3193 if (dst[0] != 'h' && src[0] == 'h') 3194 instr->type = INSTR_ALU_ADD_MH; 3195 if (dst[0] == 'h' && src[0] == 'h') 3196 instr->type = INSTR_ALU_ADD_HH; 3197 3198 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3199 instr->alu.dst.n_bits = fdst->n_bits; 3200 instr->alu.dst.offset = fdst->offset / 8; 3201 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3202 instr->alu.src.n_bits = fsrc->n_bits; 3203 instr->alu.src.offset = fsrc->offset / 8; 3204 return 0; 3205 } 3206 3207 /* ADD_MI, ADD_HI. */ 3208 src_val = strtoull(src, &src, 0); 3209 CHECK(!src[0], EINVAL); 3210 3211 instr->type = INSTR_ALU_ADD_MI; 3212 if (dst[0] == 'h') 3213 instr->type = INSTR_ALU_ADD_HI; 3214 3215 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3216 instr->alu.dst.n_bits = fdst->n_bits; 3217 instr->alu.dst.offset = fdst->offset / 8; 3218 instr->alu.src_val = src_val; 3219 return 0; 3220 } 3221 3222 static int 3223 instr_alu_sub_translate(struct rte_swx_pipeline *p, 3224 struct action *action, 3225 char **tokens, 3226 int n_tokens, 3227 struct instruction *instr, 3228 struct instruction_data *data __rte_unused) 3229 { 3230 char *dst = tokens[1], *src = tokens[2]; 3231 struct field *fdst, *fsrc; 3232 uint64_t src_val; 3233 uint32_t dst_struct_id = 0, src_struct_id = 0; 3234 3235 CHECK(n_tokens == 3, EINVAL); 3236 3237 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3238 CHECK(fdst, EINVAL); 3239 CHECK(!fdst->var_size, EINVAL); 3240 3241 /* SUB, SUB_HM, SUB_MH, SUB_HH. */ 3242 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3243 if (fsrc) { 3244 CHECK(!fsrc->var_size, EINVAL); 3245 3246 instr->type = INSTR_ALU_SUB; 3247 if (dst[0] == 'h' && src[0] != 'h') 3248 instr->type = INSTR_ALU_SUB_HM; 3249 if (dst[0] != 'h' && src[0] == 'h') 3250 instr->type = INSTR_ALU_SUB_MH; 3251 if (dst[0] == 'h' && src[0] == 'h') 3252 instr->type = INSTR_ALU_SUB_HH; 3253 3254 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3255 instr->alu.dst.n_bits = fdst->n_bits; 3256 instr->alu.dst.offset = fdst->offset / 8; 3257 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3258 instr->alu.src.n_bits = fsrc->n_bits; 3259 instr->alu.src.offset = fsrc->offset / 8; 3260 return 0; 3261 } 3262 3263 /* SUB_MI, SUB_HI. */ 3264 src_val = strtoull(src, &src, 0); 3265 CHECK(!src[0], EINVAL); 3266 3267 instr->type = INSTR_ALU_SUB_MI; 3268 if (dst[0] == 'h') 3269 instr->type = INSTR_ALU_SUB_HI; 3270 3271 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3272 instr->alu.dst.n_bits = fdst->n_bits; 3273 instr->alu.dst.offset = fdst->offset / 8; 3274 instr->alu.src_val = src_val; 3275 return 0; 3276 } 3277 3278 static int 3279 instr_alu_ckadd_translate(struct rte_swx_pipeline *p, 3280 struct action *action __rte_unused, 3281 char **tokens, 3282 int n_tokens, 3283 struct instruction *instr, 3284 struct instruction_data *data __rte_unused) 3285 { 3286 char *dst = tokens[1], *src = tokens[2]; 3287 struct header *hdst, *hsrc; 3288 struct field *fdst, *fsrc; 3289 3290 CHECK(n_tokens == 3, EINVAL); 3291 3292 fdst = header_field_parse(p, dst, &hdst); 3293 CHECK(fdst, EINVAL); 3294 CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL); 3295 3296 /* CKADD_FIELD. */ 3297 fsrc = header_field_parse(p, src, &hsrc); 3298 if (fsrc) { 3299 CHECK(!fsrc->var_size, EINVAL); 3300 3301 instr->type = INSTR_ALU_CKADD_FIELD; 3302 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id; 3303 instr->alu.dst.n_bits = fdst->n_bits; 3304 instr->alu.dst.offset = fdst->offset / 8; 3305 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id; 3306 instr->alu.src.n_bits = fsrc->n_bits; 3307 instr->alu.src.offset = fsrc->offset / 8; 3308 return 0; 3309 } 3310 3311 /* CKADD_STRUCT, CKADD_STRUCT20. */ 3312 hsrc = header_parse(p, src); 3313 CHECK(hsrc, EINVAL); 3314 3315 instr->type = INSTR_ALU_CKADD_STRUCT; 3316 if (!hsrc->st->var_size && ((hsrc->st->n_bits / 8) == 20)) 3317 instr->type = INSTR_ALU_CKADD_STRUCT20; 3318 3319 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id; 3320 instr->alu.dst.n_bits = fdst->n_bits; 3321 instr->alu.dst.offset = fdst->offset / 8; 3322 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id; 3323 instr->alu.src.n_bits = (uint8_t)hsrc->id; /* The src header ID is stored here. */ 3324 instr->alu.src.offset = 0; /* Unused. */ 3325 return 0; 3326 } 3327 3328 static int 3329 instr_alu_cksub_translate(struct rte_swx_pipeline *p, 3330 struct action *action __rte_unused, 3331 char **tokens, 3332 int n_tokens, 3333 struct instruction *instr, 3334 struct instruction_data *data __rte_unused) 3335 { 3336 char *dst = tokens[1], *src = tokens[2]; 3337 struct header *hdst, *hsrc; 3338 struct field *fdst, *fsrc; 3339 3340 CHECK(n_tokens == 3, EINVAL); 3341 3342 fdst = header_field_parse(p, dst, &hdst); 3343 CHECK(fdst, EINVAL); 3344 CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL); 3345 3346 fsrc = header_field_parse(p, src, &hsrc); 3347 CHECK(fsrc, EINVAL); 3348 CHECK(!fsrc->var_size, EINVAL); 3349 3350 instr->type = INSTR_ALU_CKSUB_FIELD; 3351 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id; 3352 instr->alu.dst.n_bits = fdst->n_bits; 3353 instr->alu.dst.offset = fdst->offset / 8; 3354 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id; 3355 instr->alu.src.n_bits = fsrc->n_bits; 3356 instr->alu.src.offset = fsrc->offset / 8; 3357 return 0; 3358 } 3359 3360 static int 3361 instr_alu_shl_translate(struct rte_swx_pipeline *p, 3362 struct action *action, 3363 char **tokens, 3364 int n_tokens, 3365 struct instruction *instr, 3366 struct instruction_data *data __rte_unused) 3367 { 3368 char *dst = tokens[1], *src = tokens[2]; 3369 struct field *fdst, *fsrc; 3370 uint64_t src_val; 3371 uint32_t dst_struct_id = 0, src_struct_id = 0; 3372 3373 CHECK(n_tokens == 3, EINVAL); 3374 3375 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3376 CHECK(fdst, EINVAL); 3377 CHECK(!fdst->var_size, EINVAL); 3378 3379 /* SHL, SHL_HM, SHL_MH, SHL_HH. */ 3380 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3381 if (fsrc) { 3382 CHECK(!fsrc->var_size, EINVAL); 3383 3384 instr->type = INSTR_ALU_SHL; 3385 if (dst[0] == 'h' && src[0] != 'h') 3386 instr->type = INSTR_ALU_SHL_HM; 3387 if (dst[0] != 'h' && src[0] == 'h') 3388 instr->type = INSTR_ALU_SHL_MH; 3389 if (dst[0] == 'h' && src[0] == 'h') 3390 instr->type = INSTR_ALU_SHL_HH; 3391 3392 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3393 instr->alu.dst.n_bits = fdst->n_bits; 3394 instr->alu.dst.offset = fdst->offset / 8; 3395 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3396 instr->alu.src.n_bits = fsrc->n_bits; 3397 instr->alu.src.offset = fsrc->offset / 8; 3398 return 0; 3399 } 3400 3401 /* SHL_MI, SHL_HI. */ 3402 src_val = strtoull(src, &src, 0); 3403 CHECK(!src[0], EINVAL); 3404 3405 instr->type = INSTR_ALU_SHL_MI; 3406 if (dst[0] == 'h') 3407 instr->type = INSTR_ALU_SHL_HI; 3408 3409 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3410 instr->alu.dst.n_bits = fdst->n_bits; 3411 instr->alu.dst.offset = fdst->offset / 8; 3412 instr->alu.src_val = src_val; 3413 return 0; 3414 } 3415 3416 static int 3417 instr_alu_shr_translate(struct rte_swx_pipeline *p, 3418 struct action *action, 3419 char **tokens, 3420 int n_tokens, 3421 struct instruction *instr, 3422 struct instruction_data *data __rte_unused) 3423 { 3424 char *dst = tokens[1], *src = tokens[2]; 3425 struct field *fdst, *fsrc; 3426 uint64_t src_val; 3427 uint32_t dst_struct_id = 0, src_struct_id = 0; 3428 3429 CHECK(n_tokens == 3, EINVAL); 3430 3431 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3432 CHECK(fdst, EINVAL); 3433 CHECK(!fdst->var_size, EINVAL); 3434 3435 /* SHR, SHR_HM, SHR_MH, SHR_HH. */ 3436 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3437 if (fsrc) { 3438 CHECK(!fsrc->var_size, EINVAL); 3439 3440 instr->type = INSTR_ALU_SHR; 3441 if (dst[0] == 'h' && src[0] != 'h') 3442 instr->type = INSTR_ALU_SHR_HM; 3443 if (dst[0] != 'h' && src[0] == 'h') 3444 instr->type = INSTR_ALU_SHR_MH; 3445 if (dst[0] == 'h' && src[0] == 'h') 3446 instr->type = INSTR_ALU_SHR_HH; 3447 3448 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3449 instr->alu.dst.n_bits = fdst->n_bits; 3450 instr->alu.dst.offset = fdst->offset / 8; 3451 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3452 instr->alu.src.n_bits = fsrc->n_bits; 3453 instr->alu.src.offset = fsrc->offset / 8; 3454 return 0; 3455 } 3456 3457 /* SHR_MI, SHR_HI. */ 3458 src_val = strtoull(src, &src, 0); 3459 CHECK(!src[0], EINVAL); 3460 3461 instr->type = INSTR_ALU_SHR_MI; 3462 if (dst[0] == 'h') 3463 instr->type = INSTR_ALU_SHR_HI; 3464 3465 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3466 instr->alu.dst.n_bits = fdst->n_bits; 3467 instr->alu.dst.offset = fdst->offset / 8; 3468 instr->alu.src_val = src_val; 3469 return 0; 3470 } 3471 3472 static int 3473 instr_alu_and_translate(struct rte_swx_pipeline *p, 3474 struct action *action, 3475 char **tokens, 3476 int n_tokens, 3477 struct instruction *instr, 3478 struct instruction_data *data __rte_unused) 3479 { 3480 char *dst = tokens[1], *src = tokens[2]; 3481 struct field *fdst, *fsrc; 3482 uint64_t src_val; 3483 uint32_t dst_struct_id = 0, src_struct_id = 0; 3484 3485 CHECK(n_tokens == 3, EINVAL); 3486 3487 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3488 CHECK(fdst, EINVAL); 3489 CHECK(!fdst->var_size, EINVAL); 3490 3491 /* AND, AND_MH, AND_HM, AND_HH. */ 3492 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3493 if (fsrc) { 3494 CHECK(!fsrc->var_size, EINVAL); 3495 3496 instr->type = INSTR_ALU_AND; 3497 if (dst[0] != 'h' && src[0] == 'h') 3498 instr->type = INSTR_ALU_AND_MH; 3499 if (dst[0] == 'h' && src[0] != 'h') 3500 instr->type = INSTR_ALU_AND_HM; 3501 if (dst[0] == 'h' && src[0] == 'h') 3502 instr->type = INSTR_ALU_AND_HH; 3503 3504 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3505 instr->alu.dst.n_bits = fdst->n_bits; 3506 instr->alu.dst.offset = fdst->offset / 8; 3507 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3508 instr->alu.src.n_bits = fsrc->n_bits; 3509 instr->alu.src.offset = fsrc->offset / 8; 3510 return 0; 3511 } 3512 3513 /* AND_I. */ 3514 src_val = strtoull(src, &src, 0); 3515 CHECK(!src[0], EINVAL); 3516 3517 if (dst[0] == 'h') 3518 src_val = hton64(src_val) >> (64 - fdst->n_bits); 3519 3520 instr->type = INSTR_ALU_AND_I; 3521 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3522 instr->alu.dst.n_bits = fdst->n_bits; 3523 instr->alu.dst.offset = fdst->offset / 8; 3524 instr->alu.src_val = src_val; 3525 return 0; 3526 } 3527 3528 static int 3529 instr_alu_or_translate(struct rte_swx_pipeline *p, 3530 struct action *action, 3531 char **tokens, 3532 int n_tokens, 3533 struct instruction *instr, 3534 struct instruction_data *data __rte_unused) 3535 { 3536 char *dst = tokens[1], *src = tokens[2]; 3537 struct field *fdst, *fsrc; 3538 uint64_t src_val; 3539 uint32_t dst_struct_id = 0, src_struct_id = 0; 3540 3541 CHECK(n_tokens == 3, EINVAL); 3542 3543 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3544 CHECK(fdst, EINVAL); 3545 CHECK(!fdst->var_size, EINVAL); 3546 3547 /* OR, OR_MH, OR_HM, OR_HH. */ 3548 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3549 if (fsrc) { 3550 CHECK(!fsrc->var_size, EINVAL); 3551 3552 instr->type = INSTR_ALU_OR; 3553 if (dst[0] != 'h' && src[0] == 'h') 3554 instr->type = INSTR_ALU_OR_MH; 3555 if (dst[0] == 'h' && src[0] != 'h') 3556 instr->type = INSTR_ALU_OR_HM; 3557 if (dst[0] == 'h' && src[0] == 'h') 3558 instr->type = INSTR_ALU_OR_HH; 3559 3560 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3561 instr->alu.dst.n_bits = fdst->n_bits; 3562 instr->alu.dst.offset = fdst->offset / 8; 3563 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3564 instr->alu.src.n_bits = fsrc->n_bits; 3565 instr->alu.src.offset = fsrc->offset / 8; 3566 return 0; 3567 } 3568 3569 /* OR_I. */ 3570 src_val = strtoull(src, &src, 0); 3571 CHECK(!src[0], EINVAL); 3572 3573 if (dst[0] == 'h') 3574 src_val = hton64(src_val) >> (64 - fdst->n_bits); 3575 3576 instr->type = INSTR_ALU_OR_I; 3577 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3578 instr->alu.dst.n_bits = fdst->n_bits; 3579 instr->alu.dst.offset = fdst->offset / 8; 3580 instr->alu.src_val = src_val; 3581 return 0; 3582 } 3583 3584 static int 3585 instr_alu_xor_translate(struct rte_swx_pipeline *p, 3586 struct action *action, 3587 char **tokens, 3588 int n_tokens, 3589 struct instruction *instr, 3590 struct instruction_data *data __rte_unused) 3591 { 3592 char *dst = tokens[1], *src = tokens[2]; 3593 struct field *fdst, *fsrc; 3594 uint64_t src_val; 3595 uint32_t dst_struct_id = 0, src_struct_id = 0; 3596 3597 CHECK(n_tokens == 3, EINVAL); 3598 3599 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 3600 CHECK(fdst, EINVAL); 3601 CHECK(!fdst->var_size, EINVAL); 3602 3603 /* XOR, XOR_MH, XOR_HM, XOR_HH. */ 3604 fsrc = struct_field_parse(p, action, src, &src_struct_id); 3605 if (fsrc) { 3606 CHECK(!fsrc->var_size, EINVAL); 3607 3608 instr->type = INSTR_ALU_XOR; 3609 if (dst[0] != 'h' && src[0] == 'h') 3610 instr->type = INSTR_ALU_XOR_MH; 3611 if (dst[0] == 'h' && src[0] != 'h') 3612 instr->type = INSTR_ALU_XOR_HM; 3613 if (dst[0] == 'h' && src[0] == 'h') 3614 instr->type = INSTR_ALU_XOR_HH; 3615 3616 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3617 instr->alu.dst.n_bits = fdst->n_bits; 3618 instr->alu.dst.offset = fdst->offset / 8; 3619 instr->alu.src.struct_id = (uint8_t)src_struct_id; 3620 instr->alu.src.n_bits = fsrc->n_bits; 3621 instr->alu.src.offset = fsrc->offset / 8; 3622 return 0; 3623 } 3624 3625 /* XOR_I. */ 3626 src_val = strtoull(src, &src, 0); 3627 CHECK(!src[0], EINVAL); 3628 3629 if (dst[0] == 'h') 3630 src_val = hton64(src_val) >> (64 - fdst->n_bits); 3631 3632 instr->type = INSTR_ALU_XOR_I; 3633 instr->alu.dst.struct_id = (uint8_t)dst_struct_id; 3634 instr->alu.dst.n_bits = fdst->n_bits; 3635 instr->alu.dst.offset = fdst->offset / 8; 3636 instr->alu.src_val = src_val; 3637 return 0; 3638 } 3639 3640 static inline void 3641 instr_alu_add_exec(struct rte_swx_pipeline *p) 3642 { 3643 struct thread *t = &p->threads[p->thread_id]; 3644 struct instruction *ip = t->ip; 3645 3646 /* Structs */ 3647 __instr_alu_add_exec(p, t, ip); 3648 3649 /* Thread. */ 3650 thread_ip_inc(p); 3651 } 3652 3653 static inline void 3654 instr_alu_add_mh_exec(struct rte_swx_pipeline *p) 3655 { 3656 struct thread *t = &p->threads[p->thread_id]; 3657 struct instruction *ip = t->ip; 3658 3659 /* Structs. */ 3660 __instr_alu_add_mh_exec(p, t, ip); 3661 3662 /* Thread. */ 3663 thread_ip_inc(p); 3664 } 3665 3666 static inline void 3667 instr_alu_add_hm_exec(struct rte_swx_pipeline *p) 3668 { 3669 struct thread *t = &p->threads[p->thread_id]; 3670 struct instruction *ip = t->ip; 3671 3672 /* Structs. */ 3673 __instr_alu_add_hm_exec(p, t, ip); 3674 3675 /* Thread. */ 3676 thread_ip_inc(p); 3677 } 3678 3679 static inline void 3680 instr_alu_add_hh_exec(struct rte_swx_pipeline *p) 3681 { 3682 struct thread *t = &p->threads[p->thread_id]; 3683 struct instruction *ip = t->ip; 3684 3685 /* Structs. */ 3686 __instr_alu_add_hh_exec(p, t, ip); 3687 3688 /* Thread. */ 3689 thread_ip_inc(p); 3690 } 3691 3692 static inline void 3693 instr_alu_add_mi_exec(struct rte_swx_pipeline *p) 3694 { 3695 struct thread *t = &p->threads[p->thread_id]; 3696 struct instruction *ip = t->ip; 3697 3698 /* Structs. */ 3699 __instr_alu_add_mi_exec(p, t, ip); 3700 3701 /* Thread. */ 3702 thread_ip_inc(p); 3703 } 3704 3705 static inline void 3706 instr_alu_add_hi_exec(struct rte_swx_pipeline *p) 3707 { 3708 struct thread *t = &p->threads[p->thread_id]; 3709 struct instruction *ip = t->ip; 3710 3711 /* Structs. */ 3712 __instr_alu_add_hi_exec(p, t, ip); 3713 3714 /* Thread. */ 3715 thread_ip_inc(p); 3716 } 3717 3718 static inline void 3719 instr_alu_sub_exec(struct rte_swx_pipeline *p) 3720 { 3721 struct thread *t = &p->threads[p->thread_id]; 3722 struct instruction *ip = t->ip; 3723 3724 /* Structs. */ 3725 __instr_alu_sub_exec(p, t, ip); 3726 3727 /* Thread. */ 3728 thread_ip_inc(p); 3729 } 3730 3731 static inline void 3732 instr_alu_sub_mh_exec(struct rte_swx_pipeline *p) 3733 { 3734 struct thread *t = &p->threads[p->thread_id]; 3735 struct instruction *ip = t->ip; 3736 3737 /* Structs. */ 3738 __instr_alu_sub_mh_exec(p, t, ip); 3739 3740 /* Thread. */ 3741 thread_ip_inc(p); 3742 } 3743 3744 static inline void 3745 instr_alu_sub_hm_exec(struct rte_swx_pipeline *p) 3746 { 3747 struct thread *t = &p->threads[p->thread_id]; 3748 struct instruction *ip = t->ip; 3749 3750 /* Structs. */ 3751 __instr_alu_sub_hm_exec(p, t, ip); 3752 3753 /* Thread. */ 3754 thread_ip_inc(p); 3755 } 3756 3757 static inline void 3758 instr_alu_sub_hh_exec(struct rte_swx_pipeline *p) 3759 { 3760 struct thread *t = &p->threads[p->thread_id]; 3761 struct instruction *ip = t->ip; 3762 3763 /* Structs. */ 3764 __instr_alu_sub_hh_exec(p, t, ip); 3765 3766 /* Thread. */ 3767 thread_ip_inc(p); 3768 } 3769 3770 static inline void 3771 instr_alu_sub_mi_exec(struct rte_swx_pipeline *p) 3772 { 3773 struct thread *t = &p->threads[p->thread_id]; 3774 struct instruction *ip = t->ip; 3775 3776 /* Structs. */ 3777 __instr_alu_sub_mi_exec(p, t, ip); 3778 3779 /* Thread. */ 3780 thread_ip_inc(p); 3781 } 3782 3783 static inline void 3784 instr_alu_sub_hi_exec(struct rte_swx_pipeline *p) 3785 { 3786 struct thread *t = &p->threads[p->thread_id]; 3787 struct instruction *ip = t->ip; 3788 3789 /* Structs. */ 3790 __instr_alu_sub_hi_exec(p, t, ip); 3791 3792 /* Thread. */ 3793 thread_ip_inc(p); 3794 } 3795 3796 static inline void 3797 instr_alu_shl_exec(struct rte_swx_pipeline *p) 3798 { 3799 struct thread *t = &p->threads[p->thread_id]; 3800 struct instruction *ip = t->ip; 3801 3802 /* Structs. */ 3803 __instr_alu_shl_exec(p, t, ip); 3804 3805 /* Thread. */ 3806 thread_ip_inc(p); 3807 } 3808 3809 static inline void 3810 instr_alu_shl_mh_exec(struct rte_swx_pipeline *p) 3811 { 3812 struct thread *t = &p->threads[p->thread_id]; 3813 struct instruction *ip = t->ip; 3814 3815 /* Structs. */ 3816 __instr_alu_shl_mh_exec(p, t, ip); 3817 3818 /* Thread. */ 3819 thread_ip_inc(p); 3820 } 3821 3822 static inline void 3823 instr_alu_shl_hm_exec(struct rte_swx_pipeline *p) 3824 { 3825 struct thread *t = &p->threads[p->thread_id]; 3826 struct instruction *ip = t->ip; 3827 3828 /* Structs. */ 3829 __instr_alu_shl_hm_exec(p, t, ip); 3830 3831 /* Thread. */ 3832 thread_ip_inc(p); 3833 } 3834 3835 static inline void 3836 instr_alu_shl_hh_exec(struct rte_swx_pipeline *p) 3837 { 3838 struct thread *t = &p->threads[p->thread_id]; 3839 struct instruction *ip = t->ip; 3840 3841 /* Structs. */ 3842 __instr_alu_shl_hh_exec(p, t, ip); 3843 3844 /* Thread. */ 3845 thread_ip_inc(p); 3846 } 3847 3848 static inline void 3849 instr_alu_shl_mi_exec(struct rte_swx_pipeline *p) 3850 { 3851 struct thread *t = &p->threads[p->thread_id]; 3852 struct instruction *ip = t->ip; 3853 3854 /* Structs. */ 3855 __instr_alu_shl_mi_exec(p, t, ip); 3856 3857 /* Thread. */ 3858 thread_ip_inc(p); 3859 } 3860 3861 static inline void 3862 instr_alu_shl_hi_exec(struct rte_swx_pipeline *p) 3863 { 3864 struct thread *t = &p->threads[p->thread_id]; 3865 struct instruction *ip = t->ip; 3866 3867 /* Structs. */ 3868 __instr_alu_shl_hi_exec(p, t, ip); 3869 3870 /* Thread. */ 3871 thread_ip_inc(p); 3872 } 3873 3874 static inline void 3875 instr_alu_shr_exec(struct rte_swx_pipeline *p) 3876 { 3877 struct thread *t = &p->threads[p->thread_id]; 3878 struct instruction *ip = t->ip; 3879 3880 /* Structs. */ 3881 __instr_alu_shr_exec(p, t, ip); 3882 3883 /* Thread. */ 3884 thread_ip_inc(p); 3885 } 3886 3887 static inline void 3888 instr_alu_shr_mh_exec(struct rte_swx_pipeline *p) 3889 { 3890 struct thread *t = &p->threads[p->thread_id]; 3891 struct instruction *ip = t->ip; 3892 3893 /* Structs. */ 3894 __instr_alu_shr_mh_exec(p, t, ip); 3895 3896 /* Thread. */ 3897 thread_ip_inc(p); 3898 } 3899 3900 static inline void 3901 instr_alu_shr_hm_exec(struct rte_swx_pipeline *p) 3902 { 3903 struct thread *t = &p->threads[p->thread_id]; 3904 struct instruction *ip = t->ip; 3905 3906 /* Structs. */ 3907 __instr_alu_shr_hm_exec(p, t, ip); 3908 3909 /* Thread. */ 3910 thread_ip_inc(p); 3911 } 3912 3913 static inline void 3914 instr_alu_shr_hh_exec(struct rte_swx_pipeline *p) 3915 { 3916 struct thread *t = &p->threads[p->thread_id]; 3917 struct instruction *ip = t->ip; 3918 3919 /* Structs. */ 3920 __instr_alu_shr_hh_exec(p, t, ip); 3921 3922 /* Thread. */ 3923 thread_ip_inc(p); 3924 } 3925 3926 static inline void 3927 instr_alu_shr_mi_exec(struct rte_swx_pipeline *p) 3928 { 3929 struct thread *t = &p->threads[p->thread_id]; 3930 struct instruction *ip = t->ip; 3931 3932 /* Structs. */ 3933 __instr_alu_shr_mi_exec(p, t, ip); 3934 3935 /* Thread. */ 3936 thread_ip_inc(p); 3937 } 3938 3939 static inline void 3940 instr_alu_shr_hi_exec(struct rte_swx_pipeline *p) 3941 { 3942 struct thread *t = &p->threads[p->thread_id]; 3943 struct instruction *ip = t->ip; 3944 3945 /* Structs. */ 3946 __instr_alu_shr_hi_exec(p, t, ip); 3947 3948 /* Thread. */ 3949 thread_ip_inc(p); 3950 } 3951 3952 static inline void 3953 instr_alu_and_exec(struct rte_swx_pipeline *p) 3954 { 3955 struct thread *t = &p->threads[p->thread_id]; 3956 struct instruction *ip = t->ip; 3957 3958 /* Structs. */ 3959 __instr_alu_and_exec(p, t, ip); 3960 3961 /* Thread. */ 3962 thread_ip_inc(p); 3963 } 3964 3965 static inline void 3966 instr_alu_and_mh_exec(struct rte_swx_pipeline *p) 3967 { 3968 struct thread *t = &p->threads[p->thread_id]; 3969 struct instruction *ip = t->ip; 3970 3971 /* Structs. */ 3972 __instr_alu_and_mh_exec(p, t, ip); 3973 3974 /* Thread. */ 3975 thread_ip_inc(p); 3976 } 3977 3978 static inline void 3979 instr_alu_and_hm_exec(struct rte_swx_pipeline *p) 3980 { 3981 struct thread *t = &p->threads[p->thread_id]; 3982 struct instruction *ip = t->ip; 3983 3984 /* Structs. */ 3985 __instr_alu_and_hm_exec(p, t, ip); 3986 3987 /* Thread. */ 3988 thread_ip_inc(p); 3989 } 3990 3991 static inline void 3992 instr_alu_and_hh_exec(struct rte_swx_pipeline *p) 3993 { 3994 struct thread *t = &p->threads[p->thread_id]; 3995 struct instruction *ip = t->ip; 3996 3997 /* Structs. */ 3998 __instr_alu_and_hh_exec(p, t, ip); 3999 4000 /* Thread. */ 4001 thread_ip_inc(p); 4002 } 4003 4004 static inline void 4005 instr_alu_and_i_exec(struct rte_swx_pipeline *p) 4006 { 4007 struct thread *t = &p->threads[p->thread_id]; 4008 struct instruction *ip = t->ip; 4009 4010 /* Structs. */ 4011 __instr_alu_and_i_exec(p, t, ip); 4012 4013 /* Thread. */ 4014 thread_ip_inc(p); 4015 } 4016 4017 static inline void 4018 instr_alu_or_exec(struct rte_swx_pipeline *p) 4019 { 4020 struct thread *t = &p->threads[p->thread_id]; 4021 struct instruction *ip = t->ip; 4022 4023 /* Structs. */ 4024 __instr_alu_or_exec(p, t, ip); 4025 4026 /* Thread. */ 4027 thread_ip_inc(p); 4028 } 4029 4030 static inline void 4031 instr_alu_or_mh_exec(struct rte_swx_pipeline *p) 4032 { 4033 struct thread *t = &p->threads[p->thread_id]; 4034 struct instruction *ip = t->ip; 4035 4036 /* Structs. */ 4037 __instr_alu_or_mh_exec(p, t, ip); 4038 4039 /* Thread. */ 4040 thread_ip_inc(p); 4041 } 4042 4043 static inline void 4044 instr_alu_or_hm_exec(struct rte_swx_pipeline *p) 4045 { 4046 struct thread *t = &p->threads[p->thread_id]; 4047 struct instruction *ip = t->ip; 4048 4049 /* Structs. */ 4050 __instr_alu_or_hm_exec(p, t, ip); 4051 4052 /* Thread. */ 4053 thread_ip_inc(p); 4054 } 4055 4056 static inline void 4057 instr_alu_or_hh_exec(struct rte_swx_pipeline *p) 4058 { 4059 struct thread *t = &p->threads[p->thread_id]; 4060 struct instruction *ip = t->ip; 4061 4062 /* Structs. */ 4063 __instr_alu_or_hh_exec(p, t, ip); 4064 4065 /* Thread. */ 4066 thread_ip_inc(p); 4067 } 4068 4069 static inline void 4070 instr_alu_or_i_exec(struct rte_swx_pipeline *p) 4071 { 4072 struct thread *t = &p->threads[p->thread_id]; 4073 struct instruction *ip = t->ip; 4074 4075 /* Structs. */ 4076 __instr_alu_or_i_exec(p, t, ip); 4077 4078 /* Thread. */ 4079 thread_ip_inc(p); 4080 } 4081 4082 static inline void 4083 instr_alu_xor_exec(struct rte_swx_pipeline *p) 4084 { 4085 struct thread *t = &p->threads[p->thread_id]; 4086 struct instruction *ip = t->ip; 4087 4088 /* Structs. */ 4089 __instr_alu_xor_exec(p, t, ip); 4090 4091 /* Thread. */ 4092 thread_ip_inc(p); 4093 } 4094 4095 static inline void 4096 instr_alu_xor_mh_exec(struct rte_swx_pipeline *p) 4097 { 4098 struct thread *t = &p->threads[p->thread_id]; 4099 struct instruction *ip = t->ip; 4100 4101 /* Structs. */ 4102 __instr_alu_xor_mh_exec(p, t, ip); 4103 4104 /* Thread. */ 4105 thread_ip_inc(p); 4106 } 4107 4108 static inline void 4109 instr_alu_xor_hm_exec(struct rte_swx_pipeline *p) 4110 { 4111 struct thread *t = &p->threads[p->thread_id]; 4112 struct instruction *ip = t->ip; 4113 4114 /* Structs. */ 4115 __instr_alu_xor_hm_exec(p, t, ip); 4116 4117 /* Thread. */ 4118 thread_ip_inc(p); 4119 } 4120 4121 static inline void 4122 instr_alu_xor_hh_exec(struct rte_swx_pipeline *p) 4123 { 4124 struct thread *t = &p->threads[p->thread_id]; 4125 struct instruction *ip = t->ip; 4126 4127 /* Structs. */ 4128 __instr_alu_xor_hh_exec(p, t, ip); 4129 4130 /* Thread. */ 4131 thread_ip_inc(p); 4132 } 4133 4134 static inline void 4135 instr_alu_xor_i_exec(struct rte_swx_pipeline *p) 4136 { 4137 struct thread *t = &p->threads[p->thread_id]; 4138 struct instruction *ip = t->ip; 4139 4140 /* Structs. */ 4141 __instr_alu_xor_i_exec(p, t, ip); 4142 4143 /* Thread. */ 4144 thread_ip_inc(p); 4145 } 4146 4147 static inline void 4148 instr_alu_ckadd_field_exec(struct rte_swx_pipeline *p) 4149 { 4150 struct thread *t = &p->threads[p->thread_id]; 4151 struct instruction *ip = t->ip; 4152 4153 /* Structs. */ 4154 __instr_alu_ckadd_field_exec(p, t, ip); 4155 4156 /* Thread. */ 4157 thread_ip_inc(p); 4158 } 4159 4160 static inline void 4161 instr_alu_cksub_field_exec(struct rte_swx_pipeline *p) 4162 { 4163 struct thread *t = &p->threads[p->thread_id]; 4164 struct instruction *ip = t->ip; 4165 4166 /* Structs. */ 4167 __instr_alu_cksub_field_exec(p, t, ip); 4168 4169 /* Thread. */ 4170 thread_ip_inc(p); 4171 } 4172 4173 static inline void 4174 instr_alu_ckadd_struct20_exec(struct rte_swx_pipeline *p) 4175 { 4176 struct thread *t = &p->threads[p->thread_id]; 4177 struct instruction *ip = t->ip; 4178 4179 /* Structs. */ 4180 __instr_alu_ckadd_struct20_exec(p, t, ip); 4181 4182 /* Thread. */ 4183 thread_ip_inc(p); 4184 } 4185 4186 static inline void 4187 instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p) 4188 { 4189 struct thread *t = &p->threads[p->thread_id]; 4190 struct instruction *ip = t->ip; 4191 4192 /* Structs. */ 4193 __instr_alu_ckadd_struct_exec(p, t, ip); 4194 4195 /* Thread. */ 4196 thread_ip_inc(p); 4197 } 4198 4199 /* 4200 * Register array. 4201 */ 4202 static struct regarray * 4203 regarray_find(struct rte_swx_pipeline *p, const char *name); 4204 4205 static int 4206 instr_regprefetch_translate(struct rte_swx_pipeline *p, 4207 struct action *action, 4208 char **tokens, 4209 int n_tokens, 4210 struct instruction *instr, 4211 struct instruction_data *data __rte_unused) 4212 { 4213 char *regarray = tokens[1], *idx = tokens[2]; 4214 struct regarray *r; 4215 struct field *fidx; 4216 uint32_t idx_struct_id, idx_val; 4217 4218 CHECK(n_tokens == 3, EINVAL); 4219 4220 r = regarray_find(p, regarray); 4221 CHECK(r, EINVAL); 4222 4223 /* REGPREFETCH_RH, REGPREFETCH_RM. */ 4224 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4225 if (fidx) { 4226 CHECK(!fidx->var_size, EINVAL); 4227 4228 instr->type = INSTR_REGPREFETCH_RM; 4229 if (idx[0] == 'h') 4230 instr->type = INSTR_REGPREFETCH_RH; 4231 4232 instr->regarray.regarray_id = r->id; 4233 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4234 instr->regarray.idx.n_bits = fidx->n_bits; 4235 instr->regarray.idx.offset = fidx->offset / 8; 4236 instr->regarray.dstsrc_val = 0; /* Unused. */ 4237 return 0; 4238 } 4239 4240 /* REGPREFETCH_RI. */ 4241 idx_val = strtoul(idx, &idx, 0); 4242 CHECK(!idx[0], EINVAL); 4243 4244 instr->type = INSTR_REGPREFETCH_RI; 4245 instr->regarray.regarray_id = r->id; 4246 instr->regarray.idx_val = idx_val; 4247 instr->regarray.dstsrc_val = 0; /* Unused. */ 4248 return 0; 4249 } 4250 4251 static int 4252 instr_regrd_translate(struct rte_swx_pipeline *p, 4253 struct action *action, 4254 char **tokens, 4255 int n_tokens, 4256 struct instruction *instr, 4257 struct instruction_data *data __rte_unused) 4258 { 4259 char *dst = tokens[1], *regarray = tokens[2], *idx = tokens[3]; 4260 struct regarray *r; 4261 struct field *fdst, *fidx; 4262 uint32_t dst_struct_id, idx_struct_id, idx_val; 4263 4264 CHECK(n_tokens == 4, EINVAL); 4265 4266 r = regarray_find(p, regarray); 4267 CHECK(r, EINVAL); 4268 4269 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id); 4270 CHECK(fdst, EINVAL); 4271 CHECK(!fdst->var_size, EINVAL); 4272 4273 /* REGRD_HRH, REGRD_HRM, REGRD_MRH, REGRD_MRM. */ 4274 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4275 if (fidx) { 4276 CHECK(!fidx->var_size, EINVAL); 4277 4278 instr->type = INSTR_REGRD_MRM; 4279 if (dst[0] == 'h' && idx[0] != 'h') 4280 instr->type = INSTR_REGRD_HRM; 4281 if (dst[0] != 'h' && idx[0] == 'h') 4282 instr->type = INSTR_REGRD_MRH; 4283 if (dst[0] == 'h' && idx[0] == 'h') 4284 instr->type = INSTR_REGRD_HRH; 4285 4286 instr->regarray.regarray_id = r->id; 4287 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4288 instr->regarray.idx.n_bits = fidx->n_bits; 4289 instr->regarray.idx.offset = fidx->offset / 8; 4290 instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id; 4291 instr->regarray.dstsrc.n_bits = fdst->n_bits; 4292 instr->regarray.dstsrc.offset = fdst->offset / 8; 4293 return 0; 4294 } 4295 4296 /* REGRD_MRI, REGRD_HRI. */ 4297 idx_val = strtoul(idx, &idx, 0); 4298 CHECK(!idx[0], EINVAL); 4299 4300 instr->type = INSTR_REGRD_MRI; 4301 if (dst[0] == 'h') 4302 instr->type = INSTR_REGRD_HRI; 4303 4304 instr->regarray.regarray_id = r->id; 4305 instr->regarray.idx_val = idx_val; 4306 instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id; 4307 instr->regarray.dstsrc.n_bits = fdst->n_bits; 4308 instr->regarray.dstsrc.offset = fdst->offset / 8; 4309 return 0; 4310 } 4311 4312 static int 4313 instr_regwr_translate(struct rte_swx_pipeline *p, 4314 struct action *action, 4315 char **tokens, 4316 int n_tokens, 4317 struct instruction *instr, 4318 struct instruction_data *data __rte_unused) 4319 { 4320 char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3]; 4321 struct regarray *r; 4322 struct field *fidx, *fsrc; 4323 uint64_t src_val; 4324 uint32_t idx_struct_id, idx_val, src_struct_id; 4325 4326 CHECK(n_tokens == 4, EINVAL); 4327 4328 r = regarray_find(p, regarray); 4329 CHECK(r, EINVAL); 4330 4331 /* REGWR_RHH, REGWR_RHM, REGWR_RMH, REGWR_RMM. */ 4332 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4333 fsrc = struct_field_parse(p, action, src, &src_struct_id); 4334 if (fidx && fsrc) { 4335 CHECK(!fidx->var_size, EINVAL); 4336 CHECK(!fsrc->var_size, EINVAL); 4337 4338 instr->type = INSTR_REGWR_RMM; 4339 if (idx[0] == 'h' && src[0] != 'h') 4340 instr->type = INSTR_REGWR_RHM; 4341 if (idx[0] != 'h' && src[0] == 'h') 4342 instr->type = INSTR_REGWR_RMH; 4343 if (idx[0] == 'h' && src[0] == 'h') 4344 instr->type = INSTR_REGWR_RHH; 4345 4346 instr->regarray.regarray_id = r->id; 4347 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4348 instr->regarray.idx.n_bits = fidx->n_bits; 4349 instr->regarray.idx.offset = fidx->offset / 8; 4350 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id; 4351 instr->regarray.dstsrc.n_bits = fsrc->n_bits; 4352 instr->regarray.dstsrc.offset = fsrc->offset / 8; 4353 return 0; 4354 } 4355 4356 /* REGWR_RHI, REGWR_RMI. */ 4357 if (fidx && !fsrc) { 4358 CHECK(!fidx->var_size, EINVAL); 4359 4360 src_val = strtoull(src, &src, 0); 4361 CHECK(!src[0], EINVAL); 4362 4363 instr->type = INSTR_REGWR_RMI; 4364 if (idx[0] == 'h') 4365 instr->type = INSTR_REGWR_RHI; 4366 4367 instr->regarray.regarray_id = r->id; 4368 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4369 instr->regarray.idx.n_bits = fidx->n_bits; 4370 instr->regarray.idx.offset = fidx->offset / 8; 4371 instr->regarray.dstsrc_val = src_val; 4372 return 0; 4373 } 4374 4375 /* REGWR_RIH, REGWR_RIM. */ 4376 if (!fidx && fsrc) { 4377 idx_val = strtoul(idx, &idx, 0); 4378 CHECK(!idx[0], EINVAL); 4379 4380 CHECK(!fsrc->var_size, EINVAL); 4381 4382 instr->type = INSTR_REGWR_RIM; 4383 if (src[0] == 'h') 4384 instr->type = INSTR_REGWR_RIH; 4385 4386 instr->regarray.regarray_id = r->id; 4387 instr->regarray.idx_val = idx_val; 4388 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id; 4389 instr->regarray.dstsrc.n_bits = fsrc->n_bits; 4390 instr->regarray.dstsrc.offset = fsrc->offset / 8; 4391 return 0; 4392 } 4393 4394 /* REGWR_RII. */ 4395 src_val = strtoull(src, &src, 0); 4396 CHECK(!src[0], EINVAL); 4397 4398 idx_val = strtoul(idx, &idx, 0); 4399 CHECK(!idx[0], EINVAL); 4400 4401 instr->type = INSTR_REGWR_RII; 4402 instr->regarray.idx_val = idx_val; 4403 instr->regarray.dstsrc_val = src_val; 4404 4405 return 0; 4406 } 4407 4408 static int 4409 instr_regadd_translate(struct rte_swx_pipeline *p, 4410 struct action *action, 4411 char **tokens, 4412 int n_tokens, 4413 struct instruction *instr, 4414 struct instruction_data *data __rte_unused) 4415 { 4416 char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3]; 4417 struct regarray *r; 4418 struct field *fidx, *fsrc; 4419 uint64_t src_val; 4420 uint32_t idx_struct_id, idx_val, src_struct_id; 4421 4422 CHECK(n_tokens == 4, EINVAL); 4423 4424 r = regarray_find(p, regarray); 4425 CHECK(r, EINVAL); 4426 4427 /* REGADD_RHH, REGADD_RHM, REGADD_RMH, REGADD_RMM. */ 4428 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4429 fsrc = struct_field_parse(p, action, src, &src_struct_id); 4430 if (fidx && fsrc) { 4431 CHECK(!fidx->var_size, EINVAL); 4432 CHECK(!fsrc->var_size, EINVAL); 4433 4434 instr->type = INSTR_REGADD_RMM; 4435 if (idx[0] == 'h' && src[0] != 'h') 4436 instr->type = INSTR_REGADD_RHM; 4437 if (idx[0] != 'h' && src[0] == 'h') 4438 instr->type = INSTR_REGADD_RMH; 4439 if (idx[0] == 'h' && src[0] == 'h') 4440 instr->type = INSTR_REGADD_RHH; 4441 4442 instr->regarray.regarray_id = r->id; 4443 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4444 instr->regarray.idx.n_bits = fidx->n_bits; 4445 instr->regarray.idx.offset = fidx->offset / 8; 4446 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id; 4447 instr->regarray.dstsrc.n_bits = fsrc->n_bits; 4448 instr->regarray.dstsrc.offset = fsrc->offset / 8; 4449 return 0; 4450 } 4451 4452 /* REGADD_RHI, REGADD_RMI. */ 4453 if (fidx && !fsrc) { 4454 CHECK(!fidx->var_size, EINVAL); 4455 4456 src_val = strtoull(src, &src, 0); 4457 CHECK(!src[0], EINVAL); 4458 4459 instr->type = INSTR_REGADD_RMI; 4460 if (idx[0] == 'h') 4461 instr->type = INSTR_REGADD_RHI; 4462 4463 instr->regarray.regarray_id = r->id; 4464 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id; 4465 instr->regarray.idx.n_bits = fidx->n_bits; 4466 instr->regarray.idx.offset = fidx->offset / 8; 4467 instr->regarray.dstsrc_val = src_val; 4468 return 0; 4469 } 4470 4471 /* REGADD_RIH, REGADD_RIM. */ 4472 if (!fidx && fsrc) { 4473 idx_val = strtoul(idx, &idx, 0); 4474 CHECK(!idx[0], EINVAL); 4475 4476 CHECK(!fsrc->var_size, EINVAL); 4477 4478 instr->type = INSTR_REGADD_RIM; 4479 if (src[0] == 'h') 4480 instr->type = INSTR_REGADD_RIH; 4481 4482 instr->regarray.regarray_id = r->id; 4483 instr->regarray.idx_val = idx_val; 4484 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id; 4485 instr->regarray.dstsrc.n_bits = fsrc->n_bits; 4486 instr->regarray.dstsrc.offset = fsrc->offset / 8; 4487 return 0; 4488 } 4489 4490 /* REGADD_RII. */ 4491 src_val = strtoull(src, &src, 0); 4492 CHECK(!src[0], EINVAL); 4493 4494 idx_val = strtoul(idx, &idx, 0); 4495 CHECK(!idx[0], EINVAL); 4496 4497 instr->type = INSTR_REGADD_RII; 4498 instr->regarray.idx_val = idx_val; 4499 instr->regarray.dstsrc_val = src_val; 4500 return 0; 4501 } 4502 4503 static inline void 4504 instr_regprefetch_rh_exec(struct rte_swx_pipeline *p) 4505 { 4506 struct thread *t = &p->threads[p->thread_id]; 4507 struct instruction *ip = t->ip; 4508 4509 /* Structs. */ 4510 __instr_regprefetch_rh_exec(p, t, ip); 4511 4512 /* Thread. */ 4513 thread_ip_inc(p); 4514 } 4515 4516 static inline void 4517 instr_regprefetch_rm_exec(struct rte_swx_pipeline *p) 4518 { 4519 struct thread *t = &p->threads[p->thread_id]; 4520 struct instruction *ip = t->ip; 4521 4522 /* Structs. */ 4523 __instr_regprefetch_rm_exec(p, t, ip); 4524 4525 /* Thread. */ 4526 thread_ip_inc(p); 4527 } 4528 4529 static inline void 4530 instr_regprefetch_ri_exec(struct rte_swx_pipeline *p) 4531 { 4532 struct thread *t = &p->threads[p->thread_id]; 4533 struct instruction *ip = t->ip; 4534 4535 /* Structs. */ 4536 __instr_regprefetch_ri_exec(p, t, ip); 4537 4538 /* Thread. */ 4539 thread_ip_inc(p); 4540 } 4541 4542 static inline void 4543 instr_regrd_hrh_exec(struct rte_swx_pipeline *p) 4544 { 4545 struct thread *t = &p->threads[p->thread_id]; 4546 struct instruction *ip = t->ip; 4547 4548 /* Structs. */ 4549 __instr_regrd_hrh_exec(p, t, ip); 4550 4551 /* Thread. */ 4552 thread_ip_inc(p); 4553 } 4554 4555 static inline void 4556 instr_regrd_hrm_exec(struct rte_swx_pipeline *p) 4557 { 4558 struct thread *t = &p->threads[p->thread_id]; 4559 struct instruction *ip = t->ip; 4560 4561 /* Structs. */ 4562 __instr_regrd_hrm_exec(p, t, ip); 4563 4564 /* Thread. */ 4565 thread_ip_inc(p); 4566 } 4567 4568 static inline void 4569 instr_regrd_mrh_exec(struct rte_swx_pipeline *p) 4570 { 4571 struct thread *t = &p->threads[p->thread_id]; 4572 struct instruction *ip = t->ip; 4573 4574 /* Structs. */ 4575 __instr_regrd_mrh_exec(p, t, ip); 4576 4577 /* Thread. */ 4578 thread_ip_inc(p); 4579 } 4580 4581 static inline void 4582 instr_regrd_mrm_exec(struct rte_swx_pipeline *p) 4583 { 4584 struct thread *t = &p->threads[p->thread_id]; 4585 struct instruction *ip = t->ip; 4586 4587 /* Structs. */ 4588 __instr_regrd_mrm_exec(p, t, ip); 4589 4590 /* Thread. */ 4591 thread_ip_inc(p); 4592 } 4593 4594 static inline void 4595 instr_regrd_hri_exec(struct rte_swx_pipeline *p) 4596 { 4597 struct thread *t = &p->threads[p->thread_id]; 4598 struct instruction *ip = t->ip; 4599 4600 /* Structs. */ 4601 __instr_regrd_hri_exec(p, t, ip); 4602 4603 /* Thread. */ 4604 thread_ip_inc(p); 4605 } 4606 4607 static inline void 4608 instr_regrd_mri_exec(struct rte_swx_pipeline *p) 4609 { 4610 struct thread *t = &p->threads[p->thread_id]; 4611 struct instruction *ip = t->ip; 4612 4613 /* Structs. */ 4614 __instr_regrd_mri_exec(p, t, ip); 4615 4616 /* Thread. */ 4617 thread_ip_inc(p); 4618 } 4619 4620 static inline void 4621 instr_regwr_rhh_exec(struct rte_swx_pipeline *p) 4622 { 4623 struct thread *t = &p->threads[p->thread_id]; 4624 struct instruction *ip = t->ip; 4625 4626 /* Structs. */ 4627 __instr_regwr_rhh_exec(p, t, ip); 4628 4629 /* Thread. */ 4630 thread_ip_inc(p); 4631 } 4632 4633 static inline void 4634 instr_regwr_rhm_exec(struct rte_swx_pipeline *p) 4635 { 4636 struct thread *t = &p->threads[p->thread_id]; 4637 struct instruction *ip = t->ip; 4638 4639 /* Structs. */ 4640 __instr_regwr_rhm_exec(p, t, ip); 4641 4642 /* Thread. */ 4643 thread_ip_inc(p); 4644 } 4645 4646 static inline void 4647 instr_regwr_rmh_exec(struct rte_swx_pipeline *p) 4648 { 4649 struct thread *t = &p->threads[p->thread_id]; 4650 struct instruction *ip = t->ip; 4651 4652 /* Structs. */ 4653 __instr_regwr_rmh_exec(p, t, ip); 4654 4655 /* Thread. */ 4656 thread_ip_inc(p); 4657 } 4658 4659 static inline void 4660 instr_regwr_rmm_exec(struct rte_swx_pipeline *p) 4661 { 4662 struct thread *t = &p->threads[p->thread_id]; 4663 struct instruction *ip = t->ip; 4664 4665 /* Structs. */ 4666 __instr_regwr_rmm_exec(p, t, ip); 4667 4668 /* Thread. */ 4669 thread_ip_inc(p); 4670 } 4671 4672 static inline void 4673 instr_regwr_rhi_exec(struct rte_swx_pipeline *p) 4674 { 4675 struct thread *t = &p->threads[p->thread_id]; 4676 struct instruction *ip = t->ip; 4677 4678 /* Structs. */ 4679 __instr_regwr_rhi_exec(p, t, ip); 4680 4681 /* Thread. */ 4682 thread_ip_inc(p); 4683 } 4684 4685 static inline void 4686 instr_regwr_rmi_exec(struct rte_swx_pipeline *p) 4687 { 4688 struct thread *t = &p->threads[p->thread_id]; 4689 struct instruction *ip = t->ip; 4690 4691 /* Structs. */ 4692 __instr_regwr_rmi_exec(p, t, ip); 4693 4694 /* Thread. */ 4695 thread_ip_inc(p); 4696 } 4697 4698 static inline void 4699 instr_regwr_rih_exec(struct rte_swx_pipeline *p) 4700 { 4701 struct thread *t = &p->threads[p->thread_id]; 4702 struct instruction *ip = t->ip; 4703 4704 /* Structs. */ 4705 __instr_regwr_rih_exec(p, t, ip); 4706 4707 /* Thread. */ 4708 thread_ip_inc(p); 4709 } 4710 4711 static inline void 4712 instr_regwr_rim_exec(struct rte_swx_pipeline *p) 4713 { 4714 struct thread *t = &p->threads[p->thread_id]; 4715 struct instruction *ip = t->ip; 4716 4717 /* Structs. */ 4718 __instr_regwr_rim_exec(p, t, ip); 4719 4720 /* Thread. */ 4721 thread_ip_inc(p); 4722 } 4723 4724 static inline void 4725 instr_regwr_rii_exec(struct rte_swx_pipeline *p) 4726 { 4727 struct thread *t = &p->threads[p->thread_id]; 4728 struct instruction *ip = t->ip; 4729 4730 /* Structs. */ 4731 __instr_regwr_rii_exec(p, t, ip); 4732 4733 /* Thread. */ 4734 thread_ip_inc(p); 4735 } 4736 4737 static inline void 4738 instr_regadd_rhh_exec(struct rte_swx_pipeline *p) 4739 { 4740 struct thread *t = &p->threads[p->thread_id]; 4741 struct instruction *ip = t->ip; 4742 4743 /* Structs. */ 4744 __instr_regadd_rhh_exec(p, t, ip); 4745 4746 /* Thread. */ 4747 thread_ip_inc(p); 4748 } 4749 4750 static inline void 4751 instr_regadd_rhm_exec(struct rte_swx_pipeline *p) 4752 { 4753 struct thread *t = &p->threads[p->thread_id]; 4754 struct instruction *ip = t->ip; 4755 4756 /* Structs. */ 4757 __instr_regadd_rhm_exec(p, t, ip); 4758 4759 /* Thread. */ 4760 thread_ip_inc(p); 4761 } 4762 4763 static inline void 4764 instr_regadd_rmh_exec(struct rte_swx_pipeline *p) 4765 { 4766 struct thread *t = &p->threads[p->thread_id]; 4767 struct instruction *ip = t->ip; 4768 4769 /* Structs. */ 4770 __instr_regadd_rmh_exec(p, t, ip); 4771 4772 /* Thread. */ 4773 thread_ip_inc(p); 4774 } 4775 4776 static inline void 4777 instr_regadd_rmm_exec(struct rte_swx_pipeline *p) 4778 { 4779 struct thread *t = &p->threads[p->thread_id]; 4780 struct instruction *ip = t->ip; 4781 4782 /* Structs. */ 4783 __instr_regadd_rmm_exec(p, t, ip); 4784 4785 /* Thread. */ 4786 thread_ip_inc(p); 4787 } 4788 4789 static inline void 4790 instr_regadd_rhi_exec(struct rte_swx_pipeline *p) 4791 { 4792 struct thread *t = &p->threads[p->thread_id]; 4793 struct instruction *ip = t->ip; 4794 4795 /* Structs. */ 4796 __instr_regadd_rhi_exec(p, t, ip); 4797 4798 /* Thread. */ 4799 thread_ip_inc(p); 4800 } 4801 4802 static inline void 4803 instr_regadd_rmi_exec(struct rte_swx_pipeline *p) 4804 { 4805 struct thread *t = &p->threads[p->thread_id]; 4806 struct instruction *ip = t->ip; 4807 4808 /* Structs. */ 4809 __instr_regadd_rmi_exec(p, t, ip); 4810 4811 /* Thread. */ 4812 thread_ip_inc(p); 4813 } 4814 4815 static inline void 4816 instr_regadd_rih_exec(struct rte_swx_pipeline *p) 4817 { 4818 struct thread *t = &p->threads[p->thread_id]; 4819 struct instruction *ip = t->ip; 4820 4821 /* Structs. */ 4822 __instr_regadd_rih_exec(p, t, ip); 4823 4824 /* Thread. */ 4825 thread_ip_inc(p); 4826 } 4827 4828 static inline void 4829 instr_regadd_rim_exec(struct rte_swx_pipeline *p) 4830 { 4831 struct thread *t = &p->threads[p->thread_id]; 4832 struct instruction *ip = t->ip; 4833 4834 /* Structs. */ 4835 __instr_regadd_rim_exec(p, t, ip); 4836 4837 /* Thread. */ 4838 thread_ip_inc(p); 4839 } 4840 4841 static inline void 4842 instr_regadd_rii_exec(struct rte_swx_pipeline *p) 4843 { 4844 struct thread *t = &p->threads[p->thread_id]; 4845 struct instruction *ip = t->ip; 4846 4847 /* Structs. */ 4848 __instr_regadd_rii_exec(p, t, ip); 4849 4850 /* Thread. */ 4851 thread_ip_inc(p); 4852 } 4853 4854 /* 4855 * metarray. 4856 */ 4857 static struct metarray * 4858 metarray_find(struct rte_swx_pipeline *p, const char *name); 4859 4860 static int 4861 instr_metprefetch_translate(struct rte_swx_pipeline *p, 4862 struct action *action, 4863 char **tokens, 4864 int n_tokens, 4865 struct instruction *instr, 4866 struct instruction_data *data __rte_unused) 4867 { 4868 char *metarray = tokens[1], *idx = tokens[2]; 4869 struct metarray *m; 4870 struct field *fidx; 4871 uint32_t idx_struct_id, idx_val; 4872 4873 CHECK(n_tokens == 3, EINVAL); 4874 4875 m = metarray_find(p, metarray); 4876 CHECK(m, EINVAL); 4877 4878 /* METPREFETCH_H, METPREFETCH_M. */ 4879 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4880 if (fidx) { 4881 CHECK(!fidx->var_size, EINVAL); 4882 4883 instr->type = INSTR_METPREFETCH_M; 4884 if (idx[0] == 'h') 4885 instr->type = INSTR_METPREFETCH_H; 4886 4887 instr->meter.metarray_id = m->id; 4888 instr->meter.idx.struct_id = (uint8_t)idx_struct_id; 4889 instr->meter.idx.n_bits = fidx->n_bits; 4890 instr->meter.idx.offset = fidx->offset / 8; 4891 return 0; 4892 } 4893 4894 /* METPREFETCH_I. */ 4895 idx_val = strtoul(idx, &idx, 0); 4896 CHECK(!idx[0], EINVAL); 4897 4898 instr->type = INSTR_METPREFETCH_I; 4899 instr->meter.metarray_id = m->id; 4900 instr->meter.idx_val = idx_val; 4901 return 0; 4902 } 4903 4904 static int 4905 instr_meter_translate(struct rte_swx_pipeline *p, 4906 struct action *action, 4907 char **tokens, 4908 int n_tokens, 4909 struct instruction *instr, 4910 struct instruction_data *data __rte_unused) 4911 { 4912 char *metarray = tokens[1], *idx = tokens[2], *length = tokens[3]; 4913 char *color_in = tokens[4], *color_out = tokens[5]; 4914 struct metarray *m; 4915 struct field *fidx, *flength, *fcin, *fcout; 4916 uint32_t idx_struct_id, length_struct_id; 4917 uint32_t color_in_struct_id, color_out_struct_id; 4918 4919 CHECK(n_tokens == 6, EINVAL); 4920 4921 m = metarray_find(p, metarray); 4922 CHECK(m, EINVAL); 4923 4924 fidx = struct_field_parse(p, action, idx, &idx_struct_id); 4925 4926 flength = struct_field_parse(p, action, length, &length_struct_id); 4927 CHECK(flength, EINVAL); 4928 CHECK(!flength->var_size, EINVAL); 4929 4930 fcin = struct_field_parse(p, action, color_in, &color_in_struct_id); 4931 4932 fcout = struct_field_parse(p, NULL, color_out, &color_out_struct_id); 4933 CHECK(fcout, EINVAL); 4934 CHECK(!fcout->var_size, EINVAL); 4935 4936 /* index = HMEFT, length = HMEFT, color_in = MEFT, color_out = MEF. */ 4937 if (fidx && fcin) { 4938 CHECK(!fidx->var_size, EINVAL); 4939 CHECK(!fcin->var_size, EINVAL); 4940 4941 instr->type = INSTR_METER_MMM; 4942 if (idx[0] == 'h' && length[0] == 'h') 4943 instr->type = INSTR_METER_HHM; 4944 if (idx[0] == 'h' && length[0] != 'h') 4945 instr->type = INSTR_METER_HMM; 4946 if (idx[0] != 'h' && length[0] == 'h') 4947 instr->type = INSTR_METER_MHM; 4948 4949 instr->meter.metarray_id = m->id; 4950 4951 instr->meter.idx.struct_id = (uint8_t)idx_struct_id; 4952 instr->meter.idx.n_bits = fidx->n_bits; 4953 instr->meter.idx.offset = fidx->offset / 8; 4954 4955 instr->meter.length.struct_id = (uint8_t)length_struct_id; 4956 instr->meter.length.n_bits = flength->n_bits; 4957 instr->meter.length.offset = flength->offset / 8; 4958 4959 instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id; 4960 instr->meter.color_in.n_bits = fcin->n_bits; 4961 instr->meter.color_in.offset = fcin->offset / 8; 4962 4963 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 4964 instr->meter.color_out.n_bits = fcout->n_bits; 4965 instr->meter.color_out.offset = fcout->offset / 8; 4966 } 4967 4968 /* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */ 4969 if (fidx && !fcin) { 4970 uint32_t color_in_val; 4971 4972 CHECK(!fidx->var_size, EINVAL); 4973 4974 color_in_val = strtoul(color_in, &color_in, 0); 4975 CHECK(!color_in[0], EINVAL); 4976 4977 instr->type = INSTR_METER_MMI; 4978 if (idx[0] == 'h' && length[0] == 'h') 4979 instr->type = INSTR_METER_HHI; 4980 if (idx[0] == 'h' && length[0] != 'h') 4981 instr->type = INSTR_METER_HMI; 4982 if (idx[0] != 'h' && length[0] == 'h') 4983 instr->type = INSTR_METER_MHI; 4984 4985 instr->meter.metarray_id = m->id; 4986 4987 instr->meter.idx.struct_id = (uint8_t)idx_struct_id; 4988 instr->meter.idx.n_bits = fidx->n_bits; 4989 instr->meter.idx.offset = fidx->offset / 8; 4990 4991 instr->meter.length.struct_id = (uint8_t)length_struct_id; 4992 instr->meter.length.n_bits = flength->n_bits; 4993 instr->meter.length.offset = flength->offset / 8; 4994 4995 instr->meter.color_in_val = color_in_val; 4996 4997 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 4998 instr->meter.color_out.n_bits = fcout->n_bits; 4999 instr->meter.color_out.offset = fcout->offset / 8; 5000 } 5001 5002 /* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */ 5003 if (!fidx && fcin) { 5004 uint32_t idx_val; 5005 5006 idx_val = strtoul(idx, &idx, 0); 5007 CHECK(!idx[0], EINVAL); 5008 5009 CHECK(!fcin->var_size, EINVAL); 5010 5011 instr->type = INSTR_METER_IMM; 5012 if (length[0] == 'h') 5013 instr->type = INSTR_METER_IHM; 5014 5015 instr->meter.metarray_id = m->id; 5016 5017 instr->meter.idx_val = idx_val; 5018 5019 instr->meter.length.struct_id = (uint8_t)length_struct_id; 5020 instr->meter.length.n_bits = flength->n_bits; 5021 instr->meter.length.offset = flength->offset / 8; 5022 5023 instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id; 5024 instr->meter.color_in.n_bits = fcin->n_bits; 5025 instr->meter.color_in.offset = fcin->offset / 8; 5026 5027 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 5028 instr->meter.color_out.n_bits = fcout->n_bits; 5029 instr->meter.color_out.offset = fcout->offset / 8; 5030 } 5031 5032 /* index = I, length = HMEFT, color_in = I, color_out = MEF. */ 5033 if (!fidx && !fcin) { 5034 uint32_t idx_val, color_in_val; 5035 5036 idx_val = strtoul(idx, &idx, 0); 5037 CHECK(!idx[0], EINVAL); 5038 5039 color_in_val = strtoul(color_in, &color_in, 0); 5040 CHECK(!color_in[0], EINVAL); 5041 5042 instr->type = INSTR_METER_IMI; 5043 if (length[0] == 'h') 5044 instr->type = INSTR_METER_IHI; 5045 5046 instr->meter.metarray_id = m->id; 5047 5048 instr->meter.idx_val = idx_val; 5049 5050 instr->meter.length.struct_id = (uint8_t)length_struct_id; 5051 instr->meter.length.n_bits = flength->n_bits; 5052 instr->meter.length.offset = flength->offset / 8; 5053 5054 instr->meter.color_in_val = color_in_val; 5055 5056 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 5057 instr->meter.color_out.n_bits = fcout->n_bits; 5058 instr->meter.color_out.offset = fcout->offset / 8; 5059 } 5060 5061 return 0; 5062 } 5063 5064 static inline void 5065 instr_metprefetch_h_exec(struct rte_swx_pipeline *p) 5066 { 5067 struct thread *t = &p->threads[p->thread_id]; 5068 struct instruction *ip = t->ip; 5069 5070 /* Structs. */ 5071 __instr_metprefetch_h_exec(p, t, ip); 5072 5073 /* Thread. */ 5074 thread_ip_inc(p); 5075 } 5076 5077 static inline void 5078 instr_metprefetch_m_exec(struct rte_swx_pipeline *p) 5079 { 5080 struct thread *t = &p->threads[p->thread_id]; 5081 struct instruction *ip = t->ip; 5082 5083 /* Structs. */ 5084 __instr_metprefetch_m_exec(p, t, ip); 5085 5086 /* Thread. */ 5087 thread_ip_inc(p); 5088 } 5089 5090 static inline void 5091 instr_metprefetch_i_exec(struct rte_swx_pipeline *p) 5092 { 5093 struct thread *t = &p->threads[p->thread_id]; 5094 struct instruction *ip = t->ip; 5095 5096 /* Structs. */ 5097 __instr_metprefetch_i_exec(p, t, ip); 5098 5099 /* Thread. */ 5100 thread_ip_inc(p); 5101 } 5102 5103 static inline void 5104 instr_meter_hhm_exec(struct rte_swx_pipeline *p) 5105 { 5106 struct thread *t = &p->threads[p->thread_id]; 5107 struct instruction *ip = t->ip; 5108 5109 /* Structs. */ 5110 __instr_meter_hhm_exec(p, t, ip); 5111 5112 /* Thread. */ 5113 thread_ip_inc(p); 5114 } 5115 5116 static inline void 5117 instr_meter_hhi_exec(struct rte_swx_pipeline *p) 5118 { 5119 struct thread *t = &p->threads[p->thread_id]; 5120 struct instruction *ip = t->ip; 5121 5122 /* Structs. */ 5123 __instr_meter_hhi_exec(p, t, ip); 5124 5125 /* Thread. */ 5126 thread_ip_inc(p); 5127 } 5128 5129 static inline void 5130 instr_meter_hmm_exec(struct rte_swx_pipeline *p) 5131 { 5132 struct thread *t = &p->threads[p->thread_id]; 5133 struct instruction *ip = t->ip; 5134 5135 /* Structs. */ 5136 __instr_meter_hmm_exec(p, t, ip); 5137 5138 /* Thread. */ 5139 thread_ip_inc(p); 5140 } 5141 5142 static inline void 5143 instr_meter_hmi_exec(struct rte_swx_pipeline *p) 5144 { 5145 struct thread *t = &p->threads[p->thread_id]; 5146 struct instruction *ip = t->ip; 5147 5148 /* Structs. */ 5149 __instr_meter_hmi_exec(p, t, ip); 5150 5151 /* Thread. */ 5152 thread_ip_inc(p); 5153 } 5154 5155 static inline void 5156 instr_meter_mhm_exec(struct rte_swx_pipeline *p) 5157 { 5158 struct thread *t = &p->threads[p->thread_id]; 5159 struct instruction *ip = t->ip; 5160 5161 /* Structs. */ 5162 __instr_meter_mhm_exec(p, t, ip); 5163 5164 /* Thread. */ 5165 thread_ip_inc(p); 5166 } 5167 5168 static inline void 5169 instr_meter_mhi_exec(struct rte_swx_pipeline *p) 5170 { 5171 struct thread *t = &p->threads[p->thread_id]; 5172 struct instruction *ip = t->ip; 5173 5174 /* Structs. */ 5175 __instr_meter_mhi_exec(p, t, ip); 5176 5177 /* Thread. */ 5178 thread_ip_inc(p); 5179 } 5180 5181 static inline void 5182 instr_meter_mmm_exec(struct rte_swx_pipeline *p) 5183 { 5184 struct thread *t = &p->threads[p->thread_id]; 5185 struct instruction *ip = t->ip; 5186 5187 /* Structs. */ 5188 __instr_meter_mmm_exec(p, t, ip); 5189 5190 /* Thread. */ 5191 thread_ip_inc(p); 5192 } 5193 5194 static inline void 5195 instr_meter_mmi_exec(struct rte_swx_pipeline *p) 5196 { 5197 struct thread *t = &p->threads[p->thread_id]; 5198 struct instruction *ip = t->ip; 5199 5200 /* Structs. */ 5201 __instr_meter_mmi_exec(p, t, ip); 5202 5203 /* Thread. */ 5204 thread_ip_inc(p); 5205 } 5206 5207 static inline void 5208 instr_meter_ihm_exec(struct rte_swx_pipeline *p) 5209 { 5210 struct thread *t = &p->threads[p->thread_id]; 5211 struct instruction *ip = t->ip; 5212 5213 /* Structs. */ 5214 __instr_meter_ihm_exec(p, t, ip); 5215 5216 /* Thread. */ 5217 thread_ip_inc(p); 5218 } 5219 5220 static inline void 5221 instr_meter_ihi_exec(struct rte_swx_pipeline *p) 5222 { 5223 struct thread *t = &p->threads[p->thread_id]; 5224 struct instruction *ip = t->ip; 5225 5226 /* Structs. */ 5227 __instr_meter_ihi_exec(p, t, ip); 5228 5229 /* Thread. */ 5230 thread_ip_inc(p); 5231 } 5232 5233 static inline void 5234 instr_meter_imm_exec(struct rte_swx_pipeline *p) 5235 { 5236 struct thread *t = &p->threads[p->thread_id]; 5237 struct instruction *ip = t->ip; 5238 5239 /* Structs. */ 5240 __instr_meter_imm_exec(p, t, ip); 5241 5242 /* Thread. */ 5243 thread_ip_inc(p); 5244 } 5245 5246 static inline void 5247 instr_meter_imi_exec(struct rte_swx_pipeline *p) 5248 { 5249 struct thread *t = &p->threads[p->thread_id]; 5250 struct instruction *ip = t->ip; 5251 5252 /* Structs. */ 5253 __instr_meter_imi_exec(p, t, ip); 5254 5255 /* Thread. */ 5256 thread_ip_inc(p); 5257 } 5258 5259 /* 5260 * jmp. 5261 */ 5262 static int 5263 instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused, 5264 struct action *action __rte_unused, 5265 char **tokens, 5266 int n_tokens, 5267 struct instruction *instr, 5268 struct instruction_data *data) 5269 { 5270 CHECK(n_tokens == 2, EINVAL); 5271 5272 strcpy(data->jmp_label, tokens[1]); 5273 5274 instr->type = INSTR_JMP; 5275 instr->jmp.ip = NULL; /* Resolved later. */ 5276 return 0; 5277 } 5278 5279 static int 5280 instr_jmp_valid_translate(struct rte_swx_pipeline *p, 5281 struct action *action __rte_unused, 5282 char **tokens, 5283 int n_tokens, 5284 struct instruction *instr, 5285 struct instruction_data *data) 5286 { 5287 struct header *h; 5288 5289 CHECK(n_tokens == 3, EINVAL); 5290 5291 strcpy(data->jmp_label, tokens[1]); 5292 5293 h = header_parse(p, tokens[2]); 5294 CHECK(h, EINVAL); 5295 5296 instr->type = INSTR_JMP_VALID; 5297 instr->jmp.ip = NULL; /* Resolved later. */ 5298 instr->jmp.header_id = h->id; 5299 return 0; 5300 } 5301 5302 static int 5303 instr_jmp_invalid_translate(struct rte_swx_pipeline *p, 5304 struct action *action __rte_unused, 5305 char **tokens, 5306 int n_tokens, 5307 struct instruction *instr, 5308 struct instruction_data *data) 5309 { 5310 struct header *h; 5311 5312 CHECK(n_tokens == 3, EINVAL); 5313 5314 strcpy(data->jmp_label, tokens[1]); 5315 5316 h = header_parse(p, tokens[2]); 5317 CHECK(h, EINVAL); 5318 5319 instr->type = INSTR_JMP_INVALID; 5320 instr->jmp.ip = NULL; /* Resolved later. */ 5321 instr->jmp.header_id = h->id; 5322 return 0; 5323 } 5324 5325 static int 5326 instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused, 5327 struct action *action, 5328 char **tokens, 5329 int n_tokens, 5330 struct instruction *instr, 5331 struct instruction_data *data) 5332 { 5333 CHECK(!action, EINVAL); 5334 CHECK(n_tokens == 2, EINVAL); 5335 5336 strcpy(data->jmp_label, tokens[1]); 5337 5338 instr->type = INSTR_JMP_HIT; 5339 instr->jmp.ip = NULL; /* Resolved later. */ 5340 return 0; 5341 } 5342 5343 static int 5344 instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused, 5345 struct action *action, 5346 char **tokens, 5347 int n_tokens, 5348 struct instruction *instr, 5349 struct instruction_data *data) 5350 { 5351 CHECK(!action, EINVAL); 5352 CHECK(n_tokens == 2, EINVAL); 5353 5354 strcpy(data->jmp_label, tokens[1]); 5355 5356 instr->type = INSTR_JMP_MISS; 5357 instr->jmp.ip = NULL; /* Resolved later. */ 5358 return 0; 5359 } 5360 5361 static int 5362 instr_jmp_action_hit_translate(struct rte_swx_pipeline *p, 5363 struct action *action, 5364 char **tokens, 5365 int n_tokens, 5366 struct instruction *instr, 5367 struct instruction_data *data) 5368 { 5369 struct action *a; 5370 5371 CHECK(!action, EINVAL); 5372 CHECK(n_tokens == 3, EINVAL); 5373 5374 strcpy(data->jmp_label, tokens[1]); 5375 5376 a = action_find(p, tokens[2]); 5377 CHECK(a, EINVAL); 5378 5379 instr->type = INSTR_JMP_ACTION_HIT; 5380 instr->jmp.ip = NULL; /* Resolved later. */ 5381 instr->jmp.action_id = a->id; 5382 return 0; 5383 } 5384 5385 static int 5386 instr_jmp_action_miss_translate(struct rte_swx_pipeline *p, 5387 struct action *action, 5388 char **tokens, 5389 int n_tokens, 5390 struct instruction *instr, 5391 struct instruction_data *data) 5392 { 5393 struct action *a; 5394 5395 CHECK(!action, EINVAL); 5396 CHECK(n_tokens == 3, EINVAL); 5397 5398 strcpy(data->jmp_label, tokens[1]); 5399 5400 a = action_find(p, tokens[2]); 5401 CHECK(a, EINVAL); 5402 5403 instr->type = INSTR_JMP_ACTION_MISS; 5404 instr->jmp.ip = NULL; /* Resolved later. */ 5405 instr->jmp.action_id = a->id; 5406 return 0; 5407 } 5408 5409 static int 5410 instr_jmp_eq_translate(struct rte_swx_pipeline *p, 5411 struct action *action, 5412 char **tokens, 5413 int n_tokens, 5414 struct instruction *instr, 5415 struct instruction_data *data) 5416 { 5417 char *a = tokens[2], *b = tokens[3]; 5418 struct field *fa, *fb; 5419 uint64_t b_val; 5420 uint32_t a_struct_id, b_struct_id; 5421 5422 CHECK(n_tokens == 4, EINVAL); 5423 5424 strcpy(data->jmp_label, tokens[1]); 5425 5426 fa = struct_field_parse(p, action, a, &a_struct_id); 5427 CHECK(fa, EINVAL); 5428 CHECK(!fa->var_size, EINVAL); 5429 5430 /* JMP_EQ, JMP_EQ_MH, JMP_EQ_HM, JMP_EQ_HH. */ 5431 fb = struct_field_parse(p, action, b, &b_struct_id); 5432 if (fb) { 5433 CHECK(!fb->var_size, EINVAL); 5434 5435 instr->type = INSTR_JMP_EQ; 5436 if (a[0] != 'h' && b[0] == 'h') 5437 instr->type = INSTR_JMP_EQ_MH; 5438 if (a[0] == 'h' && b[0] != 'h') 5439 instr->type = INSTR_JMP_EQ_HM; 5440 if (a[0] == 'h' && b[0] == 'h') 5441 instr->type = INSTR_JMP_EQ_HH; 5442 instr->jmp.ip = NULL; /* Resolved later. */ 5443 5444 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5445 instr->jmp.a.n_bits = fa->n_bits; 5446 instr->jmp.a.offset = fa->offset / 8; 5447 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5448 instr->jmp.b.n_bits = fb->n_bits; 5449 instr->jmp.b.offset = fb->offset / 8; 5450 return 0; 5451 } 5452 5453 /* JMP_EQ_I. */ 5454 b_val = strtoull(b, &b, 0); 5455 CHECK(!b[0], EINVAL); 5456 5457 if (a[0] == 'h') 5458 b_val = hton64(b_val) >> (64 - fa->n_bits); 5459 5460 instr->type = INSTR_JMP_EQ_I; 5461 instr->jmp.ip = NULL; /* Resolved later. */ 5462 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5463 instr->jmp.a.n_bits = fa->n_bits; 5464 instr->jmp.a.offset = fa->offset / 8; 5465 instr->jmp.b_val = b_val; 5466 return 0; 5467 } 5468 5469 static int 5470 instr_jmp_neq_translate(struct rte_swx_pipeline *p, 5471 struct action *action, 5472 char **tokens, 5473 int n_tokens, 5474 struct instruction *instr, 5475 struct instruction_data *data) 5476 { 5477 char *a = tokens[2], *b = tokens[3]; 5478 struct field *fa, *fb; 5479 uint64_t b_val; 5480 uint32_t a_struct_id, b_struct_id; 5481 5482 CHECK(n_tokens == 4, EINVAL); 5483 5484 strcpy(data->jmp_label, tokens[1]); 5485 5486 fa = struct_field_parse(p, action, a, &a_struct_id); 5487 CHECK(fa, EINVAL); 5488 CHECK(!fa->var_size, EINVAL); 5489 5490 /* JMP_NEQ, JMP_NEQ_MH, JMP_NEQ_HM, JMP_NEQ_HH. */ 5491 fb = struct_field_parse(p, action, b, &b_struct_id); 5492 if (fb) { 5493 CHECK(!fb->var_size, EINVAL); 5494 5495 instr->type = INSTR_JMP_NEQ; 5496 if (a[0] != 'h' && b[0] == 'h') 5497 instr->type = INSTR_JMP_NEQ_MH; 5498 if (a[0] == 'h' && b[0] != 'h') 5499 instr->type = INSTR_JMP_NEQ_HM; 5500 if (a[0] == 'h' && b[0] == 'h') 5501 instr->type = INSTR_JMP_NEQ_HH; 5502 instr->jmp.ip = NULL; /* Resolved later. */ 5503 5504 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5505 instr->jmp.a.n_bits = fa->n_bits; 5506 instr->jmp.a.offset = fa->offset / 8; 5507 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5508 instr->jmp.b.n_bits = fb->n_bits; 5509 instr->jmp.b.offset = fb->offset / 8; 5510 return 0; 5511 } 5512 5513 /* JMP_NEQ_I. */ 5514 b_val = strtoull(b, &b, 0); 5515 CHECK(!b[0], EINVAL); 5516 5517 if (a[0] == 'h') 5518 b_val = hton64(b_val) >> (64 - fa->n_bits); 5519 5520 instr->type = INSTR_JMP_NEQ_I; 5521 instr->jmp.ip = NULL; /* Resolved later. */ 5522 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5523 instr->jmp.a.n_bits = fa->n_bits; 5524 instr->jmp.a.offset = fa->offset / 8; 5525 instr->jmp.b_val = b_val; 5526 return 0; 5527 } 5528 5529 static int 5530 instr_jmp_lt_translate(struct rte_swx_pipeline *p, 5531 struct action *action, 5532 char **tokens, 5533 int n_tokens, 5534 struct instruction *instr, 5535 struct instruction_data *data) 5536 { 5537 char *a = tokens[2], *b = tokens[3]; 5538 struct field *fa, *fb; 5539 uint64_t b_val; 5540 uint32_t a_struct_id, b_struct_id; 5541 5542 CHECK(n_tokens == 4, EINVAL); 5543 5544 strcpy(data->jmp_label, tokens[1]); 5545 5546 fa = struct_field_parse(p, action, a, &a_struct_id); 5547 CHECK(fa, EINVAL); 5548 CHECK(!fa->var_size, EINVAL); 5549 5550 /* JMP_LT, JMP_LT_MH, JMP_LT_HM, JMP_LT_HH. */ 5551 fb = struct_field_parse(p, action, b, &b_struct_id); 5552 if (fb) { 5553 CHECK(!fb->var_size, EINVAL); 5554 5555 instr->type = INSTR_JMP_LT; 5556 if (a[0] == 'h' && b[0] != 'h') 5557 instr->type = INSTR_JMP_LT_HM; 5558 if (a[0] != 'h' && b[0] == 'h') 5559 instr->type = INSTR_JMP_LT_MH; 5560 if (a[0] == 'h' && b[0] == 'h') 5561 instr->type = INSTR_JMP_LT_HH; 5562 instr->jmp.ip = NULL; /* Resolved later. */ 5563 5564 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5565 instr->jmp.a.n_bits = fa->n_bits; 5566 instr->jmp.a.offset = fa->offset / 8; 5567 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5568 instr->jmp.b.n_bits = fb->n_bits; 5569 instr->jmp.b.offset = fb->offset / 8; 5570 return 0; 5571 } 5572 5573 /* JMP_LT_MI, JMP_LT_HI. */ 5574 b_val = strtoull(b, &b, 0); 5575 CHECK(!b[0], EINVAL); 5576 5577 instr->type = INSTR_JMP_LT_MI; 5578 if (a[0] == 'h') 5579 instr->type = INSTR_JMP_LT_HI; 5580 instr->jmp.ip = NULL; /* Resolved later. */ 5581 5582 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5583 instr->jmp.a.n_bits = fa->n_bits; 5584 instr->jmp.a.offset = fa->offset / 8; 5585 instr->jmp.b_val = b_val; 5586 return 0; 5587 } 5588 5589 static int 5590 instr_jmp_gt_translate(struct rte_swx_pipeline *p, 5591 struct action *action, 5592 char **tokens, 5593 int n_tokens, 5594 struct instruction *instr, 5595 struct instruction_data *data) 5596 { 5597 char *a = tokens[2], *b = tokens[3]; 5598 struct field *fa, *fb; 5599 uint64_t b_val; 5600 uint32_t a_struct_id, b_struct_id; 5601 5602 CHECK(n_tokens == 4, EINVAL); 5603 5604 strcpy(data->jmp_label, tokens[1]); 5605 5606 fa = struct_field_parse(p, action, a, &a_struct_id); 5607 CHECK(fa, EINVAL); 5608 CHECK(!fa->var_size, EINVAL); 5609 5610 /* JMP_GT, JMP_GT_MH, JMP_GT_HM, JMP_GT_HH. */ 5611 fb = struct_field_parse(p, action, b, &b_struct_id); 5612 if (fb) { 5613 CHECK(!fb->var_size, EINVAL); 5614 5615 instr->type = INSTR_JMP_GT; 5616 if (a[0] == 'h' && b[0] != 'h') 5617 instr->type = INSTR_JMP_GT_HM; 5618 if (a[0] != 'h' && b[0] == 'h') 5619 instr->type = INSTR_JMP_GT_MH; 5620 if (a[0] == 'h' && b[0] == 'h') 5621 instr->type = INSTR_JMP_GT_HH; 5622 instr->jmp.ip = NULL; /* Resolved later. */ 5623 5624 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5625 instr->jmp.a.n_bits = fa->n_bits; 5626 instr->jmp.a.offset = fa->offset / 8; 5627 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5628 instr->jmp.b.n_bits = fb->n_bits; 5629 instr->jmp.b.offset = fb->offset / 8; 5630 return 0; 5631 } 5632 5633 /* JMP_GT_MI, JMP_GT_HI. */ 5634 b_val = strtoull(b, &b, 0); 5635 CHECK(!b[0], EINVAL); 5636 5637 instr->type = INSTR_JMP_GT_MI; 5638 if (a[0] == 'h') 5639 instr->type = INSTR_JMP_GT_HI; 5640 instr->jmp.ip = NULL; /* Resolved later. */ 5641 5642 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5643 instr->jmp.a.n_bits = fa->n_bits; 5644 instr->jmp.a.offset = fa->offset / 8; 5645 instr->jmp.b_val = b_val; 5646 return 0; 5647 } 5648 5649 static inline void 5650 instr_jmp_exec(struct rte_swx_pipeline *p) 5651 { 5652 struct thread *t = &p->threads[p->thread_id]; 5653 struct instruction *ip = t->ip; 5654 5655 TRACE("[Thread %2u] jmp\n", p->thread_id); 5656 5657 thread_ip_set(t, ip->jmp.ip); 5658 } 5659 5660 static inline void 5661 instr_jmp_valid_exec(struct rte_swx_pipeline *p) 5662 { 5663 struct thread *t = &p->threads[p->thread_id]; 5664 struct instruction *ip = t->ip; 5665 uint32_t header_id = ip->jmp.header_id; 5666 5667 TRACE("[Thread %2u] jmpv\n", p->thread_id); 5668 5669 t->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1); 5670 } 5671 5672 static inline void 5673 instr_jmp_invalid_exec(struct rte_swx_pipeline *p) 5674 { 5675 struct thread *t = &p->threads[p->thread_id]; 5676 struct instruction *ip = t->ip; 5677 uint32_t header_id = ip->jmp.header_id; 5678 5679 TRACE("[Thread %2u] jmpnv\n", p->thread_id); 5680 5681 t->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip; 5682 } 5683 5684 static inline void 5685 instr_jmp_hit_exec(struct rte_swx_pipeline *p) 5686 { 5687 struct thread *t = &p->threads[p->thread_id]; 5688 struct instruction *ip = t->ip; 5689 struct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip}; 5690 5691 TRACE("[Thread %2u] jmph\n", p->thread_id); 5692 5693 t->ip = ip_next[t->hit]; 5694 } 5695 5696 static inline void 5697 instr_jmp_miss_exec(struct rte_swx_pipeline *p) 5698 { 5699 struct thread *t = &p->threads[p->thread_id]; 5700 struct instruction *ip = t->ip; 5701 struct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1}; 5702 5703 TRACE("[Thread %2u] jmpnh\n", p->thread_id); 5704 5705 t->ip = ip_next[t->hit]; 5706 } 5707 5708 static inline void 5709 instr_jmp_action_hit_exec(struct rte_swx_pipeline *p) 5710 { 5711 struct thread *t = &p->threads[p->thread_id]; 5712 struct instruction *ip = t->ip; 5713 5714 TRACE("[Thread %2u] jmpa\n", p->thread_id); 5715 5716 t->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1); 5717 } 5718 5719 static inline void 5720 instr_jmp_action_miss_exec(struct rte_swx_pipeline *p) 5721 { 5722 struct thread *t = &p->threads[p->thread_id]; 5723 struct instruction *ip = t->ip; 5724 5725 TRACE("[Thread %2u] jmpna\n", p->thread_id); 5726 5727 t->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip; 5728 } 5729 5730 static inline void 5731 instr_jmp_eq_exec(struct rte_swx_pipeline *p) 5732 { 5733 struct thread *t = &p->threads[p->thread_id]; 5734 struct instruction *ip = t->ip; 5735 5736 TRACE("[Thread %2u] jmpeq\n", p->thread_id); 5737 5738 JMP_CMP(t, ip, ==); 5739 } 5740 5741 static inline void 5742 instr_jmp_eq_mh_exec(struct rte_swx_pipeline *p) 5743 { 5744 struct thread *t = &p->threads[p->thread_id]; 5745 struct instruction *ip = t->ip; 5746 5747 TRACE("[Thread %2u] jmpeq (mh)\n", p->thread_id); 5748 5749 JMP_CMP_MH(t, ip, ==); 5750 } 5751 5752 static inline void 5753 instr_jmp_eq_hm_exec(struct rte_swx_pipeline *p) 5754 { 5755 struct thread *t = &p->threads[p->thread_id]; 5756 struct instruction *ip = t->ip; 5757 5758 TRACE("[Thread %2u] jmpeq (hm)\n", p->thread_id); 5759 5760 JMP_CMP_HM(t, ip, ==); 5761 } 5762 5763 static inline void 5764 instr_jmp_eq_hh_exec(struct rte_swx_pipeline *p) 5765 { 5766 struct thread *t = &p->threads[p->thread_id]; 5767 struct instruction *ip = t->ip; 5768 5769 TRACE("[Thread %2u] jmpeq (hh)\n", p->thread_id); 5770 5771 JMP_CMP_HH_FAST(t, ip, ==); 5772 } 5773 5774 static inline void 5775 instr_jmp_eq_i_exec(struct rte_swx_pipeline *p) 5776 { 5777 struct thread *t = &p->threads[p->thread_id]; 5778 struct instruction *ip = t->ip; 5779 5780 TRACE("[Thread %2u] jmpeq (i)\n", p->thread_id); 5781 5782 JMP_CMP_I(t, ip, ==); 5783 } 5784 5785 static inline void 5786 instr_jmp_neq_exec(struct rte_swx_pipeline *p) 5787 { 5788 struct thread *t = &p->threads[p->thread_id]; 5789 struct instruction *ip = t->ip; 5790 5791 TRACE("[Thread %2u] jmpneq\n", p->thread_id); 5792 5793 JMP_CMP(t, ip, !=); 5794 } 5795 5796 static inline void 5797 instr_jmp_neq_mh_exec(struct rte_swx_pipeline *p) 5798 { 5799 struct thread *t = &p->threads[p->thread_id]; 5800 struct instruction *ip = t->ip; 5801 5802 TRACE("[Thread %2u] jmpneq (mh)\n", p->thread_id); 5803 5804 JMP_CMP_MH(t, ip, !=); 5805 } 5806 5807 static inline void 5808 instr_jmp_neq_hm_exec(struct rte_swx_pipeline *p) 5809 { 5810 struct thread *t = &p->threads[p->thread_id]; 5811 struct instruction *ip = t->ip; 5812 5813 TRACE("[Thread %2u] jmpneq (hm)\n", p->thread_id); 5814 5815 JMP_CMP_HM(t, ip, !=); 5816 } 5817 5818 static inline void 5819 instr_jmp_neq_hh_exec(struct rte_swx_pipeline *p) 5820 { 5821 struct thread *t = &p->threads[p->thread_id]; 5822 struct instruction *ip = t->ip; 5823 5824 TRACE("[Thread %2u] jmpneq (hh)\n", p->thread_id); 5825 5826 JMP_CMP_HH_FAST(t, ip, !=); 5827 } 5828 5829 static inline void 5830 instr_jmp_neq_i_exec(struct rte_swx_pipeline *p) 5831 { 5832 struct thread *t = &p->threads[p->thread_id]; 5833 struct instruction *ip = t->ip; 5834 5835 TRACE("[Thread %2u] jmpneq (i)\n", p->thread_id); 5836 5837 JMP_CMP_I(t, ip, !=); 5838 } 5839 5840 static inline void 5841 instr_jmp_lt_exec(struct rte_swx_pipeline *p) 5842 { 5843 struct thread *t = &p->threads[p->thread_id]; 5844 struct instruction *ip = t->ip; 5845 5846 TRACE("[Thread %2u] jmplt\n", p->thread_id); 5847 5848 JMP_CMP(t, ip, <); 5849 } 5850 5851 static inline void 5852 instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p) 5853 { 5854 struct thread *t = &p->threads[p->thread_id]; 5855 struct instruction *ip = t->ip; 5856 5857 TRACE("[Thread %2u] jmplt (mh)\n", p->thread_id); 5858 5859 JMP_CMP_MH(t, ip, <); 5860 } 5861 5862 static inline void 5863 instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p) 5864 { 5865 struct thread *t = &p->threads[p->thread_id]; 5866 struct instruction *ip = t->ip; 5867 5868 TRACE("[Thread %2u] jmplt (hm)\n", p->thread_id); 5869 5870 JMP_CMP_HM(t, ip, <); 5871 } 5872 5873 static inline void 5874 instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p) 5875 { 5876 struct thread *t = &p->threads[p->thread_id]; 5877 struct instruction *ip = t->ip; 5878 5879 TRACE("[Thread %2u] jmplt (hh)\n", p->thread_id); 5880 5881 JMP_CMP_HH(t, ip, <); 5882 } 5883 5884 static inline void 5885 instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p) 5886 { 5887 struct thread *t = &p->threads[p->thread_id]; 5888 struct instruction *ip = t->ip; 5889 5890 TRACE("[Thread %2u] jmplt (mi)\n", p->thread_id); 5891 5892 JMP_CMP_MI(t, ip, <); 5893 } 5894 5895 static inline void 5896 instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p) 5897 { 5898 struct thread *t = &p->threads[p->thread_id]; 5899 struct instruction *ip = t->ip; 5900 5901 TRACE("[Thread %2u] jmplt (hi)\n", p->thread_id); 5902 5903 JMP_CMP_HI(t, ip, <); 5904 } 5905 5906 static inline void 5907 instr_jmp_gt_exec(struct rte_swx_pipeline *p) 5908 { 5909 struct thread *t = &p->threads[p->thread_id]; 5910 struct instruction *ip = t->ip; 5911 5912 TRACE("[Thread %2u] jmpgt\n", p->thread_id); 5913 5914 JMP_CMP(t, ip, >); 5915 } 5916 5917 static inline void 5918 instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p) 5919 { 5920 struct thread *t = &p->threads[p->thread_id]; 5921 struct instruction *ip = t->ip; 5922 5923 TRACE("[Thread %2u] jmpgt (mh)\n", p->thread_id); 5924 5925 JMP_CMP_MH(t, ip, >); 5926 } 5927 5928 static inline void 5929 instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p) 5930 { 5931 struct thread *t = &p->threads[p->thread_id]; 5932 struct instruction *ip = t->ip; 5933 5934 TRACE("[Thread %2u] jmpgt (hm)\n", p->thread_id); 5935 5936 JMP_CMP_HM(t, ip, >); 5937 } 5938 5939 static inline void 5940 instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p) 5941 { 5942 struct thread *t = &p->threads[p->thread_id]; 5943 struct instruction *ip = t->ip; 5944 5945 TRACE("[Thread %2u] jmpgt (hh)\n", p->thread_id); 5946 5947 JMP_CMP_HH(t, ip, >); 5948 } 5949 5950 static inline void 5951 instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p) 5952 { 5953 struct thread *t = &p->threads[p->thread_id]; 5954 struct instruction *ip = t->ip; 5955 5956 TRACE("[Thread %2u] jmpgt (mi)\n", p->thread_id); 5957 5958 JMP_CMP_MI(t, ip, >); 5959 } 5960 5961 static inline void 5962 instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p) 5963 { 5964 struct thread *t = &p->threads[p->thread_id]; 5965 struct instruction *ip = t->ip; 5966 5967 TRACE("[Thread %2u] jmpgt (hi)\n", p->thread_id); 5968 5969 JMP_CMP_HI(t, ip, >); 5970 } 5971 5972 /* 5973 * return. 5974 */ 5975 static int 5976 instr_return_translate(struct rte_swx_pipeline *p __rte_unused, 5977 struct action *action, 5978 char **tokens __rte_unused, 5979 int n_tokens, 5980 struct instruction *instr, 5981 struct instruction_data *data __rte_unused) 5982 { 5983 CHECK(action, EINVAL); 5984 CHECK(n_tokens == 1, EINVAL); 5985 5986 instr->type = INSTR_RETURN; 5987 return 0; 5988 } 5989 5990 static inline void 5991 instr_return_exec(struct rte_swx_pipeline *p) 5992 { 5993 struct thread *t = &p->threads[p->thread_id]; 5994 5995 TRACE("[Thread %2u] return\n", p->thread_id); 5996 5997 t->ip = t->ret; 5998 } 5999 6000 static int 6001 instr_translate(struct rte_swx_pipeline *p, 6002 struct action *action, 6003 char *string, 6004 struct instruction *instr, 6005 struct instruction_data *data) 6006 { 6007 char *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX]; 6008 int n_tokens = 0, tpos = 0; 6009 6010 /* Parse the instruction string into tokens. */ 6011 for ( ; ; ) { 6012 char *token; 6013 6014 token = strtok_r(string, " \t\v", &string); 6015 if (!token) 6016 break; 6017 6018 CHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL); 6019 CHECK_NAME(token, EINVAL); 6020 6021 tokens[n_tokens] = token; 6022 n_tokens++; 6023 } 6024 6025 CHECK(n_tokens, EINVAL); 6026 6027 /* Handle the optional instruction label. */ 6028 if ((n_tokens >= 2) && !strcmp(tokens[1], ":")) { 6029 strcpy(data->label, tokens[0]); 6030 6031 tpos += 2; 6032 CHECK(n_tokens - tpos, EINVAL); 6033 } 6034 6035 /* Identify the instruction type. */ 6036 if (!strcmp(tokens[tpos], "rx")) 6037 return instr_rx_translate(p, 6038 action, 6039 &tokens[tpos], 6040 n_tokens - tpos, 6041 instr, 6042 data); 6043 6044 if (!strcmp(tokens[tpos], "tx")) 6045 return instr_tx_translate(p, 6046 action, 6047 &tokens[tpos], 6048 n_tokens - tpos, 6049 instr, 6050 data); 6051 6052 if (!strcmp(tokens[tpos], "drop")) 6053 return instr_drop_translate(p, 6054 action, 6055 &tokens[tpos], 6056 n_tokens - tpos, 6057 instr, 6058 data); 6059 6060 if (!strcmp(tokens[tpos], "mirror")) 6061 return instr_mirror_translate(p, 6062 action, 6063 &tokens[tpos], 6064 n_tokens - tpos, 6065 instr, 6066 data); 6067 6068 if (!strcmp(tokens[tpos], "recirculate")) 6069 return instr_recirculate_translate(p, 6070 action, 6071 &tokens[tpos], 6072 n_tokens - tpos, 6073 instr, 6074 data); 6075 6076 if (!strcmp(tokens[tpos], "recircid")) 6077 return instr_recircid_translate(p, 6078 action, 6079 &tokens[tpos], 6080 n_tokens - tpos, 6081 instr, 6082 data); 6083 6084 if (!strcmp(tokens[tpos], "extract")) 6085 return instr_hdr_extract_translate(p, 6086 action, 6087 &tokens[tpos], 6088 n_tokens - tpos, 6089 instr, 6090 data); 6091 6092 if (!strcmp(tokens[tpos], "lookahead")) 6093 return instr_hdr_lookahead_translate(p, 6094 action, 6095 &tokens[tpos], 6096 n_tokens - tpos, 6097 instr, 6098 data); 6099 6100 if (!strcmp(tokens[tpos], "emit")) 6101 return instr_hdr_emit_translate(p, 6102 action, 6103 &tokens[tpos], 6104 n_tokens - tpos, 6105 instr, 6106 data); 6107 6108 if (!strcmp(tokens[tpos], "validate")) 6109 return instr_hdr_validate_translate(p, 6110 action, 6111 &tokens[tpos], 6112 n_tokens - tpos, 6113 instr, 6114 data); 6115 6116 if (!strcmp(tokens[tpos], "invalidate")) 6117 return instr_hdr_invalidate_translate(p, 6118 action, 6119 &tokens[tpos], 6120 n_tokens - tpos, 6121 instr, 6122 data); 6123 6124 if (!strcmp(tokens[tpos], "mov")) 6125 return instr_mov_translate(p, 6126 action, 6127 &tokens[tpos], 6128 n_tokens - tpos, 6129 instr, 6130 data); 6131 6132 if (!strcmp(tokens[tpos], "add")) 6133 return instr_alu_add_translate(p, 6134 action, 6135 &tokens[tpos], 6136 n_tokens - tpos, 6137 instr, 6138 data); 6139 6140 if (!strcmp(tokens[tpos], "sub")) 6141 return instr_alu_sub_translate(p, 6142 action, 6143 &tokens[tpos], 6144 n_tokens - tpos, 6145 instr, 6146 data); 6147 6148 if (!strcmp(tokens[tpos], "ckadd")) 6149 return instr_alu_ckadd_translate(p, 6150 action, 6151 &tokens[tpos], 6152 n_tokens - tpos, 6153 instr, 6154 data); 6155 6156 if (!strcmp(tokens[tpos], "cksub")) 6157 return instr_alu_cksub_translate(p, 6158 action, 6159 &tokens[tpos], 6160 n_tokens - tpos, 6161 instr, 6162 data); 6163 6164 if (!strcmp(tokens[tpos], "and")) 6165 return instr_alu_and_translate(p, 6166 action, 6167 &tokens[tpos], 6168 n_tokens - tpos, 6169 instr, 6170 data); 6171 6172 if (!strcmp(tokens[tpos], "or")) 6173 return instr_alu_or_translate(p, 6174 action, 6175 &tokens[tpos], 6176 n_tokens - tpos, 6177 instr, 6178 data); 6179 6180 if (!strcmp(tokens[tpos], "xor")) 6181 return instr_alu_xor_translate(p, 6182 action, 6183 &tokens[tpos], 6184 n_tokens - tpos, 6185 instr, 6186 data); 6187 6188 if (!strcmp(tokens[tpos], "shl")) 6189 return instr_alu_shl_translate(p, 6190 action, 6191 &tokens[tpos], 6192 n_tokens - tpos, 6193 instr, 6194 data); 6195 6196 if (!strcmp(tokens[tpos], "shr")) 6197 return instr_alu_shr_translate(p, 6198 action, 6199 &tokens[tpos], 6200 n_tokens - tpos, 6201 instr, 6202 data); 6203 6204 if (!strcmp(tokens[tpos], "regprefetch")) 6205 return instr_regprefetch_translate(p, 6206 action, 6207 &tokens[tpos], 6208 n_tokens - tpos, 6209 instr, 6210 data); 6211 6212 if (!strcmp(tokens[tpos], "regrd")) 6213 return instr_regrd_translate(p, 6214 action, 6215 &tokens[tpos], 6216 n_tokens - tpos, 6217 instr, 6218 data); 6219 6220 if (!strcmp(tokens[tpos], "regwr")) 6221 return instr_regwr_translate(p, 6222 action, 6223 &tokens[tpos], 6224 n_tokens - tpos, 6225 instr, 6226 data); 6227 6228 if (!strcmp(tokens[tpos], "regadd")) 6229 return instr_regadd_translate(p, 6230 action, 6231 &tokens[tpos], 6232 n_tokens - tpos, 6233 instr, 6234 data); 6235 6236 if (!strcmp(tokens[tpos], "metprefetch")) 6237 return instr_metprefetch_translate(p, 6238 action, 6239 &tokens[tpos], 6240 n_tokens - tpos, 6241 instr, 6242 data); 6243 6244 if (!strcmp(tokens[tpos], "meter")) 6245 return instr_meter_translate(p, 6246 action, 6247 &tokens[tpos], 6248 n_tokens - tpos, 6249 instr, 6250 data); 6251 6252 if (!strcmp(tokens[tpos], "table")) 6253 return instr_table_translate(p, 6254 action, 6255 &tokens[tpos], 6256 n_tokens - tpos, 6257 instr, 6258 data); 6259 6260 if (!strcmp(tokens[tpos], "learn")) 6261 return instr_learn_translate(p, 6262 action, 6263 &tokens[tpos], 6264 n_tokens - tpos, 6265 instr, 6266 data); 6267 if (!strcmp(tokens[tpos], "rearm")) 6268 return instr_rearm_translate(p, 6269 action, 6270 &tokens[tpos], 6271 n_tokens - tpos, 6272 instr, 6273 data); 6274 6275 if (!strcmp(tokens[tpos], "forget")) 6276 return instr_forget_translate(p, 6277 action, 6278 &tokens[tpos], 6279 n_tokens - tpos, 6280 instr, 6281 data); 6282 6283 if (!strcmp(tokens[tpos], "extern")) 6284 return instr_extern_translate(p, 6285 action, 6286 &tokens[tpos], 6287 n_tokens - tpos, 6288 instr, 6289 data); 6290 6291 if (!strcmp(tokens[tpos], "hash")) 6292 return instr_hash_translate(p, 6293 action, 6294 &tokens[tpos], 6295 n_tokens - tpos, 6296 instr, 6297 data); 6298 6299 if (!strcmp(tokens[tpos], "jmp")) 6300 return instr_jmp_translate(p, 6301 action, 6302 &tokens[tpos], 6303 n_tokens - tpos, 6304 instr, 6305 data); 6306 6307 if (!strcmp(tokens[tpos], "jmpv")) 6308 return instr_jmp_valid_translate(p, 6309 action, 6310 &tokens[tpos], 6311 n_tokens - tpos, 6312 instr, 6313 data); 6314 6315 if (!strcmp(tokens[tpos], "jmpnv")) 6316 return instr_jmp_invalid_translate(p, 6317 action, 6318 &tokens[tpos], 6319 n_tokens - tpos, 6320 instr, 6321 data); 6322 6323 if (!strcmp(tokens[tpos], "jmph")) 6324 return instr_jmp_hit_translate(p, 6325 action, 6326 &tokens[tpos], 6327 n_tokens - tpos, 6328 instr, 6329 data); 6330 6331 if (!strcmp(tokens[tpos], "jmpnh")) 6332 return instr_jmp_miss_translate(p, 6333 action, 6334 &tokens[tpos], 6335 n_tokens - tpos, 6336 instr, 6337 data); 6338 6339 if (!strcmp(tokens[tpos], "jmpa")) 6340 return instr_jmp_action_hit_translate(p, 6341 action, 6342 &tokens[tpos], 6343 n_tokens - tpos, 6344 instr, 6345 data); 6346 6347 if (!strcmp(tokens[tpos], "jmpna")) 6348 return instr_jmp_action_miss_translate(p, 6349 action, 6350 &tokens[tpos], 6351 n_tokens - tpos, 6352 instr, 6353 data); 6354 6355 if (!strcmp(tokens[tpos], "jmpeq")) 6356 return instr_jmp_eq_translate(p, 6357 action, 6358 &tokens[tpos], 6359 n_tokens - tpos, 6360 instr, 6361 data); 6362 6363 if (!strcmp(tokens[tpos], "jmpneq")) 6364 return instr_jmp_neq_translate(p, 6365 action, 6366 &tokens[tpos], 6367 n_tokens - tpos, 6368 instr, 6369 data); 6370 6371 if (!strcmp(tokens[tpos], "jmplt")) 6372 return instr_jmp_lt_translate(p, 6373 action, 6374 &tokens[tpos], 6375 n_tokens - tpos, 6376 instr, 6377 data); 6378 6379 if (!strcmp(tokens[tpos], "jmpgt")) 6380 return instr_jmp_gt_translate(p, 6381 action, 6382 &tokens[tpos], 6383 n_tokens - tpos, 6384 instr, 6385 data); 6386 6387 if (!strcmp(tokens[tpos], "return")) 6388 return instr_return_translate(p, 6389 action, 6390 &tokens[tpos], 6391 n_tokens - tpos, 6392 instr, 6393 data); 6394 6395 return -EINVAL; 6396 } 6397 6398 static struct instruction_data * 6399 label_find(struct instruction_data *data, uint32_t n, const char *label) 6400 { 6401 uint32_t i; 6402 6403 for (i = 0; i < n; i++) 6404 if (!strcmp(label, data[i].label)) 6405 return &data[i]; 6406 6407 return NULL; 6408 } 6409 6410 static uint32_t 6411 label_is_used(struct instruction_data *data, uint32_t n, const char *label) 6412 { 6413 uint32_t count = 0, i; 6414 6415 if (!label[0]) 6416 return 0; 6417 6418 for (i = 0; i < n; i++) 6419 if (!strcmp(label, data[i].jmp_label)) 6420 count++; 6421 6422 return count; 6423 } 6424 6425 static int 6426 instr_label_check(struct instruction_data *instruction_data, 6427 uint32_t n_instructions) 6428 { 6429 uint32_t i; 6430 6431 /* Check that all instruction labels are unique. */ 6432 for (i = 0; i < n_instructions; i++) { 6433 struct instruction_data *data = &instruction_data[i]; 6434 char *label = data->label; 6435 uint32_t j; 6436 6437 if (!label[0]) 6438 continue; 6439 6440 for (j = i + 1; j < n_instructions; j++) 6441 CHECK(strcmp(label, instruction_data[j].label), EINVAL); 6442 } 6443 6444 /* Check that no jump instruction (either conditional or not) can jump to itself (loop). */ 6445 for (i = 0; i < n_instructions; i++) { 6446 struct instruction_data *data = &instruction_data[i]; 6447 char *label = data->label; 6448 char *jmp_label = data->jmp_label; 6449 6450 /* Continue if this instruction does not have a label or it is not a jump. */ 6451 if (!label[0] || !jmp_label[0]) 6452 continue; 6453 6454 CHECK(strcmp(label, jmp_label), EINVAL); 6455 } 6456 6457 /* Get users for each instruction label. */ 6458 for (i = 0; i < n_instructions; i++) { 6459 struct instruction_data *data = &instruction_data[i]; 6460 char *label = data->label; 6461 6462 data->n_users = label_is_used(instruction_data, 6463 n_instructions, 6464 label); 6465 } 6466 6467 return 0; 6468 } 6469 6470 static int 6471 instr_jmp_resolve(struct instruction *instructions, 6472 struct instruction_data *instruction_data, 6473 uint32_t n_instructions) 6474 { 6475 uint32_t i; 6476 6477 for (i = 0; i < n_instructions; i++) { 6478 struct instruction *instr = &instructions[i]; 6479 struct instruction_data *data = &instruction_data[i]; 6480 struct instruction_data *found; 6481 6482 if (!instruction_is_jmp(instr)) 6483 continue; 6484 6485 found = label_find(instruction_data, 6486 n_instructions, 6487 data->jmp_label); 6488 CHECK(found, EINVAL); 6489 6490 instr->jmp.ip = &instructions[found - instruction_data]; 6491 } 6492 6493 return 0; 6494 } 6495 6496 static int 6497 instr_verify(struct rte_swx_pipeline *p __rte_unused, 6498 struct action *a, 6499 struct instruction *instr, 6500 struct instruction_data *data __rte_unused, 6501 uint32_t n_instructions) 6502 { 6503 if (!a) { 6504 enum instruction_type type; 6505 uint32_t i; 6506 6507 /* Check that the first instruction is rx. */ 6508 CHECK(instr[0].type == INSTR_RX, EINVAL); 6509 6510 /* Check that there is at least one tx instruction. */ 6511 for (i = 0; i < n_instructions; i++) { 6512 type = instr[i].type; 6513 6514 if (instruction_is_tx(type)) 6515 break; 6516 } 6517 CHECK(i < n_instructions, EINVAL); 6518 6519 /* Check that the last instruction is either tx or unconditional 6520 * jump. 6521 */ 6522 type = instr[n_instructions - 1].type; 6523 CHECK(instruction_is_tx(type) || (type == INSTR_JMP), EINVAL); 6524 } 6525 6526 if (a) { 6527 enum instruction_type type; 6528 uint32_t i; 6529 6530 /* Check that there is at least one return or tx instruction. */ 6531 for (i = 0; i < n_instructions; i++) { 6532 type = instr[i].type; 6533 6534 if ((type == INSTR_RETURN) || instruction_is_tx(type)) 6535 break; 6536 } 6537 CHECK(i < n_instructions, EINVAL); 6538 } 6539 6540 return 0; 6541 } 6542 6543 static uint32_t 6544 instr_compact(struct instruction *instructions, 6545 struct instruction_data *instruction_data, 6546 uint32_t n_instructions) 6547 { 6548 uint32_t i, pos = 0; 6549 6550 /* Eliminate the invalid instructions that have been optimized out. */ 6551 for (i = 0; i < n_instructions; i++) { 6552 struct instruction *instr = &instructions[i]; 6553 struct instruction_data *data = &instruction_data[i]; 6554 6555 if (data->invalid) 6556 continue; 6557 6558 if (i != pos) { 6559 memcpy(&instructions[pos], instr, sizeof(*instr)); 6560 memcpy(&instruction_data[pos], data, sizeof(*data)); 6561 } 6562 6563 pos++; 6564 } 6565 6566 return pos; 6567 } 6568 6569 static int 6570 instr_pattern_extract_many_search(struct instruction *instr, 6571 struct instruction_data *data, 6572 uint32_t n_instr, 6573 uint32_t *n_pattern_instr) 6574 { 6575 uint32_t i; 6576 6577 for (i = 0; i < n_instr; i++) { 6578 if (data[i].invalid) 6579 break; 6580 6581 if (instr[i].type != INSTR_HDR_EXTRACT) 6582 break; 6583 6584 if (i == RTE_DIM(instr->io.hdr.header_id)) 6585 break; 6586 6587 if (i && data[i].n_users) 6588 break; 6589 } 6590 6591 if (i < 2) 6592 return 0; 6593 6594 *n_pattern_instr = i; 6595 return 1; 6596 } 6597 6598 static void 6599 instr_pattern_extract_many_replace(struct instruction *instr, 6600 struct instruction_data *data, 6601 uint32_t n_instr) 6602 { 6603 uint32_t i; 6604 6605 for (i = 1; i < n_instr; i++) { 6606 instr[0].type++; 6607 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0]; 6608 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0]; 6609 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0]; 6610 6611 data[i].invalid = 1; 6612 } 6613 } 6614 6615 static uint32_t 6616 instr_pattern_extract_many_optimize(struct instruction *instructions, 6617 struct instruction_data *instruction_data, 6618 uint32_t n_instructions) 6619 { 6620 uint32_t i; 6621 6622 for (i = 0; i < n_instructions; ) { 6623 struct instruction *instr = &instructions[i]; 6624 struct instruction_data *data = &instruction_data[i]; 6625 uint32_t n_instr = 0; 6626 int detected; 6627 6628 /* Extract many. */ 6629 detected = instr_pattern_extract_many_search(instr, 6630 data, 6631 n_instructions - i, 6632 &n_instr); 6633 if (detected) { 6634 instr_pattern_extract_many_replace(instr, 6635 data, 6636 n_instr); 6637 i += n_instr; 6638 continue; 6639 } 6640 6641 /* No pattern starting at the current instruction. */ 6642 i++; 6643 } 6644 6645 /* Eliminate the invalid instructions that have been optimized out. */ 6646 n_instructions = instr_compact(instructions, 6647 instruction_data, 6648 n_instructions); 6649 6650 return n_instructions; 6651 } 6652 6653 static int 6654 instr_pattern_emit_many_tx_search(struct instruction *instr, 6655 struct instruction_data *data, 6656 uint32_t n_instr, 6657 uint32_t *n_pattern_instr) 6658 { 6659 uint32_t i; 6660 6661 for (i = 0; i < n_instr; i++) { 6662 if (data[i].invalid) 6663 break; 6664 6665 if (instr[i].type != INSTR_HDR_EMIT) 6666 break; 6667 6668 if (i == RTE_DIM(instr->io.hdr.header_id)) 6669 break; 6670 6671 if (i && data[i].n_users) 6672 break; 6673 } 6674 6675 if (!i) 6676 return 0; 6677 6678 if (instr[i].type != INSTR_TX) 6679 return 0; 6680 6681 if (data[i].n_users) 6682 return 0; 6683 6684 i++; 6685 6686 *n_pattern_instr = i; 6687 return 1; 6688 } 6689 6690 static void 6691 instr_pattern_emit_many_tx_replace(struct instruction *instr, 6692 struct instruction_data *data, 6693 uint32_t n_instr) 6694 { 6695 uint32_t i; 6696 6697 /* Any emit instruction in addition to the first one. */ 6698 for (i = 1; i < n_instr - 1; i++) { 6699 instr[0].type++; 6700 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0]; 6701 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0]; 6702 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0]; 6703 6704 data[i].invalid = 1; 6705 } 6706 6707 /* The TX instruction is the last one in the pattern. */ 6708 instr[0].type++; 6709 instr[0].io.io.offset = instr[i].io.io.offset; 6710 instr[0].io.io.n_bits = instr[i].io.io.n_bits; 6711 data[i].invalid = 1; 6712 } 6713 6714 static uint32_t 6715 instr_pattern_emit_many_tx_optimize(struct instruction *instructions, 6716 struct instruction_data *instruction_data, 6717 uint32_t n_instructions) 6718 { 6719 uint32_t i; 6720 6721 for (i = 0; i < n_instructions; ) { 6722 struct instruction *instr = &instructions[i]; 6723 struct instruction_data *data = &instruction_data[i]; 6724 uint32_t n_instr = 0; 6725 int detected; 6726 6727 /* Emit many + TX. */ 6728 detected = instr_pattern_emit_many_tx_search(instr, 6729 data, 6730 n_instructions - i, 6731 &n_instr); 6732 if (detected) { 6733 instr_pattern_emit_many_tx_replace(instr, 6734 data, 6735 n_instr); 6736 i += n_instr; 6737 continue; 6738 } 6739 6740 /* No pattern starting at the current instruction. */ 6741 i++; 6742 } 6743 6744 /* Eliminate the invalid instructions that have been optimized out. */ 6745 n_instructions = instr_compact(instructions, 6746 instruction_data, 6747 n_instructions); 6748 6749 return n_instructions; 6750 } 6751 6752 static uint32_t 6753 action_arg_src_mov_count(struct action *a, 6754 uint32_t arg_id, 6755 struct instruction *instructions, 6756 struct instruction_data *instruction_data, 6757 uint32_t n_instructions); 6758 6759 static int 6760 instr_pattern_mov_all_validate_search(struct rte_swx_pipeline *p, 6761 struct action *a, 6762 struct instruction *instr, 6763 struct instruction_data *data, 6764 uint32_t n_instr, 6765 struct instruction *instructions, 6766 struct instruction_data *instruction_data, 6767 uint32_t n_instructions, 6768 uint32_t *n_pattern_instr) 6769 { 6770 struct header *h; 6771 uint32_t src_field_id, i, j; 6772 6773 /* Prerequisites. */ 6774 if (!a || !a->st) 6775 return 0; 6776 6777 /* First instruction: MOV_HM. */ 6778 if (data[0].invalid || (instr[0].type != INSTR_MOV_HM)) 6779 return 0; 6780 6781 h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id); 6782 if (!h || h->st->var_size) 6783 return 0; 6784 6785 for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++) 6786 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8) 6787 break; 6788 6789 if (src_field_id == a->st->n_fields) 6790 return 0; 6791 6792 if (instr[0].mov.dst.offset || 6793 (instr[0].mov.dst.n_bits != h->st->fields[0].n_bits) || 6794 instr[0].mov.src.struct_id || 6795 (instr[0].mov.src.n_bits != a->st->fields[src_field_id].n_bits) || 6796 (instr[0].mov.dst.n_bits != instr[0].mov.src.n_bits)) 6797 return 0; 6798 6799 if ((n_instr < h->st->n_fields + 1) || 6800 (a->st->n_fields < src_field_id + h->st->n_fields + 1)) 6801 return 0; 6802 6803 /* Subsequent instructions: MOV_HM. */ 6804 for (i = 1; i < h->st->n_fields; i++) 6805 if (data[i].invalid || 6806 data[i].n_users || 6807 (instr[i].type != INSTR_MOV_HM) || 6808 (instr[i].mov.dst.struct_id != h->struct_id) || 6809 (instr[i].mov.dst.offset != h->st->fields[i].offset / 8) || 6810 (instr[i].mov.dst.n_bits != h->st->fields[i].n_bits) || 6811 instr[i].mov.src.struct_id || 6812 (instr[i].mov.src.offset != a->st->fields[src_field_id + i].offset / 8) || 6813 (instr[i].mov.src.n_bits != a->st->fields[src_field_id + i].n_bits) || 6814 (instr[i].mov.dst.n_bits != instr[i].mov.src.n_bits)) 6815 return 0; 6816 6817 /* Last instruction: HDR_VALIDATE. */ 6818 if ((instr[i].type != INSTR_HDR_VALIDATE) || 6819 (instr[i].valid.header_id != h->id)) 6820 return 0; 6821 6822 /* Check that none of the action args that are used as source for this 6823 * DMA transfer are not used as source in any other mov instruction. 6824 */ 6825 for (j = src_field_id; j < src_field_id + h->st->n_fields; j++) { 6826 uint32_t n_users; 6827 6828 n_users = action_arg_src_mov_count(a, 6829 j, 6830 instructions, 6831 instruction_data, 6832 n_instructions); 6833 if (n_users > 1) 6834 return 0; 6835 } 6836 6837 *n_pattern_instr = 1 + i; 6838 return 1; 6839 } 6840 6841 static void 6842 instr_pattern_mov_all_validate_replace(struct rte_swx_pipeline *p, 6843 struct action *a, 6844 struct instruction *instr, 6845 struct instruction_data *data, 6846 uint32_t n_instr) 6847 { 6848 struct header *h; 6849 uint32_t src_field_id, src_offset, i; 6850 6851 /* Read from the instructions before they are modified. */ 6852 h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id); 6853 if (!h) 6854 return; 6855 6856 for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++) 6857 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8) 6858 break; 6859 6860 if (src_field_id == a->st->n_fields) 6861 return; 6862 6863 src_offset = instr[0].mov.src.offset; 6864 6865 /* Modify the instructions. */ 6866 instr[0].type = INSTR_DMA_HT; 6867 instr[0].dma.dst.header_id[0] = h->id; 6868 instr[0].dma.dst.struct_id[0] = h->struct_id; 6869 instr[0].dma.src.offset[0] = (uint8_t)src_offset; 6870 instr[0].dma.n_bytes[0] = h->st->n_bits / 8; 6871 6872 for (i = 1; i < n_instr; i++) 6873 data[i].invalid = 1; 6874 6875 /* Update the endianness of the action arguments to header endianness. */ 6876 for (i = 0; i < h->st->n_fields; i++) 6877 a->args_endianness[src_field_id + i] = 1; 6878 } 6879 6880 static uint32_t 6881 instr_pattern_mov_all_validate_optimize(struct rte_swx_pipeline *p, 6882 struct action *a, 6883 struct instruction *instructions, 6884 struct instruction_data *instruction_data, 6885 uint32_t n_instructions) 6886 { 6887 uint32_t i; 6888 6889 if (!a || !a->st) 6890 return n_instructions; 6891 6892 for (i = 0; i < n_instructions; ) { 6893 struct instruction *instr = &instructions[i]; 6894 struct instruction_data *data = &instruction_data[i]; 6895 uint32_t n_instr = 0; 6896 int detected; 6897 6898 /* Mov all + validate. */ 6899 detected = instr_pattern_mov_all_validate_search(p, 6900 a, 6901 instr, 6902 data, 6903 n_instructions - i, 6904 instructions, 6905 instruction_data, 6906 n_instructions, 6907 &n_instr); 6908 if (detected) { 6909 instr_pattern_mov_all_validate_replace(p, a, instr, data, n_instr); 6910 i += n_instr; 6911 continue; 6912 } 6913 6914 /* No pattern starting at the current instruction. */ 6915 i++; 6916 } 6917 6918 /* Eliminate the invalid instructions that have been optimized out. */ 6919 n_instructions = instr_compact(instructions, 6920 instruction_data, 6921 n_instructions); 6922 6923 return n_instructions; 6924 } 6925 6926 static int 6927 instr_pattern_dma_many_search(struct instruction *instr, 6928 struct instruction_data *data, 6929 uint32_t n_instr, 6930 uint32_t *n_pattern_instr) 6931 { 6932 uint32_t i; 6933 6934 for (i = 0; i < n_instr; i++) { 6935 if (data[i].invalid) 6936 break; 6937 6938 if (instr[i].type != INSTR_DMA_HT) 6939 break; 6940 6941 if (i == RTE_DIM(instr->dma.dst.header_id)) 6942 break; 6943 6944 if (i && data[i].n_users) 6945 break; 6946 } 6947 6948 if (i < 2) 6949 return 0; 6950 6951 *n_pattern_instr = i; 6952 return 1; 6953 } 6954 6955 static void 6956 instr_pattern_dma_many_replace(struct instruction *instr, 6957 struct instruction_data *data, 6958 uint32_t n_instr) 6959 { 6960 uint32_t i; 6961 6962 for (i = 1; i < n_instr; i++) { 6963 instr[0].type++; 6964 instr[0].dma.dst.header_id[i] = instr[i].dma.dst.header_id[0]; 6965 instr[0].dma.dst.struct_id[i] = instr[i].dma.dst.struct_id[0]; 6966 instr[0].dma.src.offset[i] = instr[i].dma.src.offset[0]; 6967 instr[0].dma.n_bytes[i] = instr[i].dma.n_bytes[0]; 6968 6969 data[i].invalid = 1; 6970 } 6971 } 6972 6973 static uint32_t 6974 instr_pattern_dma_many_optimize(struct instruction *instructions, 6975 struct instruction_data *instruction_data, 6976 uint32_t n_instructions) 6977 { 6978 uint32_t i; 6979 6980 for (i = 0; i < n_instructions; ) { 6981 struct instruction *instr = &instructions[i]; 6982 struct instruction_data *data = &instruction_data[i]; 6983 uint32_t n_instr = 0; 6984 int detected; 6985 6986 /* DMA many. */ 6987 detected = instr_pattern_dma_many_search(instr, 6988 data, 6989 n_instructions - i, 6990 &n_instr); 6991 if (detected) { 6992 instr_pattern_dma_many_replace(instr, data, n_instr); 6993 i += n_instr; 6994 continue; 6995 } 6996 6997 /* No pattern starting at the current instruction. */ 6998 i++; 6999 } 7000 7001 /* Eliminate the invalid instructions that have been optimized out. */ 7002 n_instructions = instr_compact(instructions, 7003 instruction_data, 7004 n_instructions); 7005 7006 return n_instructions; 7007 } 7008 7009 static uint32_t 7010 instr_optimize(struct rte_swx_pipeline *p, 7011 struct action *a, 7012 struct instruction *instructions, 7013 struct instruction_data *instruction_data, 7014 uint32_t n_instructions) 7015 { 7016 /* Extract many. */ 7017 n_instructions = instr_pattern_extract_many_optimize(instructions, 7018 instruction_data, 7019 n_instructions); 7020 7021 /* Emit many + TX. */ 7022 n_instructions = instr_pattern_emit_many_tx_optimize(instructions, 7023 instruction_data, 7024 n_instructions); 7025 7026 /* Mov all + validate. */ 7027 n_instructions = instr_pattern_mov_all_validate_optimize(p, 7028 a, 7029 instructions, 7030 instruction_data, 7031 n_instructions); 7032 7033 /* DMA many. */ 7034 n_instructions = instr_pattern_dma_many_optimize(instructions, 7035 instruction_data, 7036 n_instructions); 7037 7038 return n_instructions; 7039 } 7040 7041 static int 7042 instruction_config(struct rte_swx_pipeline *p, 7043 struct action *a, 7044 const char **instructions, 7045 uint32_t n_instructions) 7046 { 7047 struct instruction *instr = NULL; 7048 struct instruction_data *data = NULL; 7049 int err = 0; 7050 uint32_t i; 7051 7052 CHECK(n_instructions, EINVAL); 7053 CHECK(instructions, EINVAL); 7054 for (i = 0; i < n_instructions; i++) 7055 CHECK_INSTRUCTION(instructions[i], EINVAL); 7056 7057 /* Memory allocation. */ 7058 instr = calloc(n_instructions, sizeof(struct instruction)); 7059 if (!instr) { 7060 err = -ENOMEM; 7061 goto error; 7062 } 7063 7064 data = calloc(n_instructions, sizeof(struct instruction_data)); 7065 if (!data) { 7066 err = -ENOMEM; 7067 goto error; 7068 } 7069 7070 for (i = 0; i < n_instructions; i++) { 7071 char *string = strdup(instructions[i]); 7072 if (!string) { 7073 err = -ENOMEM; 7074 goto error; 7075 } 7076 7077 err = instr_translate(p, a, string, &instr[i], &data[i]); 7078 if (err) { 7079 free(string); 7080 goto error; 7081 } 7082 7083 free(string); 7084 } 7085 7086 err = instr_label_check(data, n_instructions); 7087 if (err) 7088 goto error; 7089 7090 err = instr_verify(p, a, instr, data, n_instructions); 7091 if (err) 7092 goto error; 7093 7094 n_instructions = instr_optimize(p, a, instr, data, n_instructions); 7095 7096 err = instr_jmp_resolve(instr, data, n_instructions); 7097 if (err) 7098 goto error; 7099 7100 if (a) { 7101 a->instructions = instr; 7102 a->instruction_data = data; 7103 a->n_instructions = n_instructions; 7104 } else { 7105 p->instructions = instr; 7106 p->instruction_data = data; 7107 p->n_instructions = n_instructions; 7108 } 7109 7110 return 0; 7111 7112 error: 7113 free(data); 7114 free(instr); 7115 return err; 7116 } 7117 7118 static instr_exec_t instruction_table[] = { 7119 [INSTR_RX] = instr_rx_exec, 7120 [INSTR_TX] = instr_tx_exec, 7121 [INSTR_TX_I] = instr_tx_i_exec, 7122 [INSTR_DROP] = instr_drop_exec, 7123 [INSTR_MIRROR] = instr_mirror_exec, 7124 [INSTR_RECIRCULATE] = instr_recirculate_exec, 7125 [INSTR_RECIRCID] = instr_recircid_exec, 7126 7127 [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec, 7128 [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec, 7129 [INSTR_HDR_EXTRACT3] = instr_hdr_extract3_exec, 7130 [INSTR_HDR_EXTRACT4] = instr_hdr_extract4_exec, 7131 [INSTR_HDR_EXTRACT5] = instr_hdr_extract5_exec, 7132 [INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec, 7133 [INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec, 7134 [INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec, 7135 [INSTR_HDR_EXTRACT_M] = instr_hdr_extract_m_exec, 7136 [INSTR_HDR_LOOKAHEAD] = instr_hdr_lookahead_exec, 7137 7138 [INSTR_HDR_EMIT] = instr_hdr_emit_exec, 7139 [INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec, 7140 [INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec, 7141 [INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec, 7142 [INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec, 7143 [INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec, 7144 [INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec, 7145 [INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec, 7146 [INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec, 7147 7148 [INSTR_HDR_VALIDATE] = instr_hdr_validate_exec, 7149 [INSTR_HDR_INVALIDATE] = instr_hdr_invalidate_exec, 7150 7151 [INSTR_MOV] = instr_mov_exec, 7152 [INSTR_MOV_MH] = instr_mov_mh_exec, 7153 [INSTR_MOV_HM] = instr_mov_hm_exec, 7154 [INSTR_MOV_HH] = instr_mov_hh_exec, 7155 [INSTR_MOV_I] = instr_mov_i_exec, 7156 7157 [INSTR_DMA_HT] = instr_dma_ht_exec, 7158 [INSTR_DMA_HT2] = instr_dma_ht2_exec, 7159 [INSTR_DMA_HT3] = instr_dma_ht3_exec, 7160 [INSTR_DMA_HT4] = instr_dma_ht4_exec, 7161 [INSTR_DMA_HT5] = instr_dma_ht5_exec, 7162 [INSTR_DMA_HT6] = instr_dma_ht6_exec, 7163 [INSTR_DMA_HT7] = instr_dma_ht7_exec, 7164 [INSTR_DMA_HT8] = instr_dma_ht8_exec, 7165 7166 [INSTR_ALU_ADD] = instr_alu_add_exec, 7167 [INSTR_ALU_ADD_MH] = instr_alu_add_mh_exec, 7168 [INSTR_ALU_ADD_HM] = instr_alu_add_hm_exec, 7169 [INSTR_ALU_ADD_HH] = instr_alu_add_hh_exec, 7170 [INSTR_ALU_ADD_MI] = instr_alu_add_mi_exec, 7171 [INSTR_ALU_ADD_HI] = instr_alu_add_hi_exec, 7172 7173 [INSTR_ALU_SUB] = instr_alu_sub_exec, 7174 [INSTR_ALU_SUB_MH] = instr_alu_sub_mh_exec, 7175 [INSTR_ALU_SUB_HM] = instr_alu_sub_hm_exec, 7176 [INSTR_ALU_SUB_HH] = instr_alu_sub_hh_exec, 7177 [INSTR_ALU_SUB_MI] = instr_alu_sub_mi_exec, 7178 [INSTR_ALU_SUB_HI] = instr_alu_sub_hi_exec, 7179 7180 [INSTR_ALU_CKADD_FIELD] = instr_alu_ckadd_field_exec, 7181 [INSTR_ALU_CKADD_STRUCT] = instr_alu_ckadd_struct_exec, 7182 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_ckadd_struct20_exec, 7183 [INSTR_ALU_CKSUB_FIELD] = instr_alu_cksub_field_exec, 7184 7185 [INSTR_ALU_AND] = instr_alu_and_exec, 7186 [INSTR_ALU_AND_MH] = instr_alu_and_mh_exec, 7187 [INSTR_ALU_AND_HM] = instr_alu_and_hm_exec, 7188 [INSTR_ALU_AND_HH] = instr_alu_and_hh_exec, 7189 [INSTR_ALU_AND_I] = instr_alu_and_i_exec, 7190 7191 [INSTR_ALU_OR] = instr_alu_or_exec, 7192 [INSTR_ALU_OR_MH] = instr_alu_or_mh_exec, 7193 [INSTR_ALU_OR_HM] = instr_alu_or_hm_exec, 7194 [INSTR_ALU_OR_HH] = instr_alu_or_hh_exec, 7195 [INSTR_ALU_OR_I] = instr_alu_or_i_exec, 7196 7197 [INSTR_ALU_XOR] = instr_alu_xor_exec, 7198 [INSTR_ALU_XOR_MH] = instr_alu_xor_mh_exec, 7199 [INSTR_ALU_XOR_HM] = instr_alu_xor_hm_exec, 7200 [INSTR_ALU_XOR_HH] = instr_alu_xor_hh_exec, 7201 [INSTR_ALU_XOR_I] = instr_alu_xor_i_exec, 7202 7203 [INSTR_ALU_SHL] = instr_alu_shl_exec, 7204 [INSTR_ALU_SHL_MH] = instr_alu_shl_mh_exec, 7205 [INSTR_ALU_SHL_HM] = instr_alu_shl_hm_exec, 7206 [INSTR_ALU_SHL_HH] = instr_alu_shl_hh_exec, 7207 [INSTR_ALU_SHL_MI] = instr_alu_shl_mi_exec, 7208 [INSTR_ALU_SHL_HI] = instr_alu_shl_hi_exec, 7209 7210 [INSTR_ALU_SHR] = instr_alu_shr_exec, 7211 [INSTR_ALU_SHR_MH] = instr_alu_shr_mh_exec, 7212 [INSTR_ALU_SHR_HM] = instr_alu_shr_hm_exec, 7213 [INSTR_ALU_SHR_HH] = instr_alu_shr_hh_exec, 7214 [INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec, 7215 [INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec, 7216 7217 [INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec, 7218 [INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec, 7219 [INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec, 7220 7221 [INSTR_REGRD_HRH] = instr_regrd_hrh_exec, 7222 [INSTR_REGRD_HRM] = instr_regrd_hrm_exec, 7223 [INSTR_REGRD_MRH] = instr_regrd_mrh_exec, 7224 [INSTR_REGRD_MRM] = instr_regrd_mrm_exec, 7225 [INSTR_REGRD_HRI] = instr_regrd_hri_exec, 7226 [INSTR_REGRD_MRI] = instr_regrd_mri_exec, 7227 7228 [INSTR_REGWR_RHH] = instr_regwr_rhh_exec, 7229 [INSTR_REGWR_RHM] = instr_regwr_rhm_exec, 7230 [INSTR_REGWR_RMH] = instr_regwr_rmh_exec, 7231 [INSTR_REGWR_RMM] = instr_regwr_rmm_exec, 7232 [INSTR_REGWR_RHI] = instr_regwr_rhi_exec, 7233 [INSTR_REGWR_RMI] = instr_regwr_rmi_exec, 7234 [INSTR_REGWR_RIH] = instr_regwr_rih_exec, 7235 [INSTR_REGWR_RIM] = instr_regwr_rim_exec, 7236 [INSTR_REGWR_RII] = instr_regwr_rii_exec, 7237 7238 [INSTR_REGADD_RHH] = instr_regadd_rhh_exec, 7239 [INSTR_REGADD_RHM] = instr_regadd_rhm_exec, 7240 [INSTR_REGADD_RMH] = instr_regadd_rmh_exec, 7241 [INSTR_REGADD_RMM] = instr_regadd_rmm_exec, 7242 [INSTR_REGADD_RHI] = instr_regadd_rhi_exec, 7243 [INSTR_REGADD_RMI] = instr_regadd_rmi_exec, 7244 [INSTR_REGADD_RIH] = instr_regadd_rih_exec, 7245 [INSTR_REGADD_RIM] = instr_regadd_rim_exec, 7246 [INSTR_REGADD_RII] = instr_regadd_rii_exec, 7247 7248 [INSTR_METPREFETCH_H] = instr_metprefetch_h_exec, 7249 [INSTR_METPREFETCH_M] = instr_metprefetch_m_exec, 7250 [INSTR_METPREFETCH_I] = instr_metprefetch_i_exec, 7251 7252 [INSTR_METER_HHM] = instr_meter_hhm_exec, 7253 [INSTR_METER_HHI] = instr_meter_hhi_exec, 7254 [INSTR_METER_HMM] = instr_meter_hmm_exec, 7255 [INSTR_METER_HMI] = instr_meter_hmi_exec, 7256 [INSTR_METER_MHM] = instr_meter_mhm_exec, 7257 [INSTR_METER_MHI] = instr_meter_mhi_exec, 7258 [INSTR_METER_MMM] = instr_meter_mmm_exec, 7259 [INSTR_METER_MMI] = instr_meter_mmi_exec, 7260 [INSTR_METER_IHM] = instr_meter_ihm_exec, 7261 [INSTR_METER_IHI] = instr_meter_ihi_exec, 7262 [INSTR_METER_IMM] = instr_meter_imm_exec, 7263 [INSTR_METER_IMI] = instr_meter_imi_exec, 7264 7265 [INSTR_TABLE] = instr_table_exec, 7266 [INSTR_TABLE_AF] = instr_table_af_exec, 7267 [INSTR_SELECTOR] = instr_selector_exec, 7268 [INSTR_LEARNER] = instr_learner_exec, 7269 [INSTR_LEARNER_AF] = instr_learner_af_exec, 7270 [INSTR_LEARNER_LEARN] = instr_learn_exec, 7271 [INSTR_LEARNER_REARM] = instr_rearm_exec, 7272 [INSTR_LEARNER_REARM_NEW] = instr_rearm_new_exec, 7273 [INSTR_LEARNER_FORGET] = instr_forget_exec, 7274 [INSTR_EXTERN_OBJ] = instr_extern_obj_exec, 7275 [INSTR_EXTERN_FUNC] = instr_extern_func_exec, 7276 [INSTR_HASH_FUNC] = instr_hash_func_exec, 7277 7278 [INSTR_JMP] = instr_jmp_exec, 7279 [INSTR_JMP_VALID] = instr_jmp_valid_exec, 7280 [INSTR_JMP_INVALID] = instr_jmp_invalid_exec, 7281 [INSTR_JMP_HIT] = instr_jmp_hit_exec, 7282 [INSTR_JMP_MISS] = instr_jmp_miss_exec, 7283 [INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec, 7284 [INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec, 7285 7286 [INSTR_JMP_EQ] = instr_jmp_eq_exec, 7287 [INSTR_JMP_EQ_MH] = instr_jmp_eq_mh_exec, 7288 [INSTR_JMP_EQ_HM] = instr_jmp_eq_hm_exec, 7289 [INSTR_JMP_EQ_HH] = instr_jmp_eq_hh_exec, 7290 [INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec, 7291 7292 [INSTR_JMP_NEQ] = instr_jmp_neq_exec, 7293 [INSTR_JMP_NEQ_MH] = instr_jmp_neq_mh_exec, 7294 [INSTR_JMP_NEQ_HM] = instr_jmp_neq_hm_exec, 7295 [INSTR_JMP_NEQ_HH] = instr_jmp_neq_hh_exec, 7296 [INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec, 7297 7298 [INSTR_JMP_LT] = instr_jmp_lt_exec, 7299 [INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec, 7300 [INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec, 7301 [INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec, 7302 [INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec, 7303 [INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec, 7304 7305 [INSTR_JMP_GT] = instr_jmp_gt_exec, 7306 [INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec, 7307 [INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec, 7308 [INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec, 7309 [INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec, 7310 [INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec, 7311 7312 [INSTR_RETURN] = instr_return_exec, 7313 }; 7314 7315 static int 7316 instruction_table_build(struct rte_swx_pipeline *p) 7317 { 7318 p->instruction_table = calloc(RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX, 7319 sizeof(struct instr_exec_t *)); 7320 if (!p->instruction_table) 7321 return -EINVAL; 7322 7323 memcpy(p->instruction_table, instruction_table, sizeof(instruction_table)); 7324 7325 return 0; 7326 } 7327 7328 static void 7329 instruction_table_build_free(struct rte_swx_pipeline *p) 7330 { 7331 if (!p->instruction_table) 7332 return; 7333 7334 free(p->instruction_table); 7335 p->instruction_table = NULL; 7336 } 7337 7338 static void 7339 instruction_table_free(struct rte_swx_pipeline *p) 7340 { 7341 instruction_table_build_free(p); 7342 } 7343 7344 static inline void 7345 instr_exec(struct rte_swx_pipeline *p) 7346 { 7347 struct thread *t = &p->threads[p->thread_id]; 7348 struct instruction *ip = t->ip; 7349 instr_exec_t instr = p->instruction_table[ip->type]; 7350 7351 instr(p); 7352 } 7353 7354 /* 7355 * Action. 7356 */ 7357 static struct action * 7358 action_find(struct rte_swx_pipeline *p, const char *name) 7359 { 7360 struct action *elem; 7361 7362 if (!name) 7363 return NULL; 7364 7365 TAILQ_FOREACH(elem, &p->actions, node) 7366 if (strcmp(elem->name, name) == 0) 7367 return elem; 7368 7369 return NULL; 7370 } 7371 7372 static struct action * 7373 action_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 7374 { 7375 struct action *action = NULL; 7376 7377 TAILQ_FOREACH(action, &p->actions, node) 7378 if (action->id == id) 7379 return action; 7380 7381 return NULL; 7382 } 7383 7384 static struct field * 7385 action_field_find(struct action *a, const char *name) 7386 { 7387 return a->st ? struct_type_field_find(a->st, name) : NULL; 7388 } 7389 7390 static struct field * 7391 action_field_parse(struct action *action, const char *name) 7392 { 7393 if (name[0] != 't' || name[1] != '.') 7394 return NULL; 7395 7396 return action_field_find(action, &name[2]); 7397 } 7398 7399 static int 7400 action_has_nbo_args(struct action *a) 7401 { 7402 uint32_t i; 7403 7404 /* Return if the action does not have any args. */ 7405 if (!a->st) 7406 return 0; /* FALSE */ 7407 7408 for (i = 0; i < a->st->n_fields; i++) 7409 if (a->args_endianness[i]) 7410 return 1; /* TRUE */ 7411 7412 return 0; /* FALSE */ 7413 } 7414 7415 static int 7416 action_does_learning(struct action *a) 7417 { 7418 uint32_t i; 7419 7420 for (i = 0; i < a->n_instructions; i++) 7421 switch (a->instructions[i].type) { 7422 case INSTR_LEARNER_LEARN: 7423 return 1; /* TRUE */ 7424 7425 case INSTR_LEARNER_FORGET: 7426 return 1; /* TRUE */ 7427 7428 default: 7429 continue; 7430 } 7431 7432 return 0; /* FALSE */ 7433 } 7434 7435 int 7436 rte_swx_pipeline_action_config(struct rte_swx_pipeline *p, 7437 const char *name, 7438 const char *args_struct_type_name, 7439 const char **instructions, 7440 uint32_t n_instructions) 7441 { 7442 struct struct_type *args_struct_type = NULL; 7443 struct action *a = NULL; 7444 int status = 0; 7445 7446 CHECK(p, EINVAL); 7447 7448 CHECK_NAME(name, EINVAL); 7449 CHECK(!action_find(p, name), EEXIST); 7450 7451 if (args_struct_type_name) { 7452 CHECK_NAME(args_struct_type_name, EINVAL); 7453 args_struct_type = struct_type_find(p, args_struct_type_name); 7454 CHECK(args_struct_type, EINVAL); 7455 CHECK(!args_struct_type->var_size, EINVAL); 7456 } 7457 7458 /* Node allocation. */ 7459 a = calloc(1, sizeof(struct action)); 7460 if (!a) { 7461 status = -ENOMEM; 7462 goto error; 7463 } 7464 7465 if (args_struct_type) { 7466 a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int)); 7467 if (!a->args_endianness) { 7468 status = -ENOMEM; 7469 goto error; 7470 } 7471 } 7472 7473 /* Node initialization. */ 7474 strcpy(a->name, name); 7475 a->st = args_struct_type; 7476 a->id = p->n_actions; 7477 7478 /* Instruction translation. */ 7479 status = instruction_config(p, a, instructions, n_instructions); 7480 if (status) 7481 goto error; 7482 7483 /* Node add to tailq. */ 7484 TAILQ_INSERT_TAIL(&p->actions, a, node); 7485 p->n_actions++; 7486 7487 return 0; 7488 7489 error: 7490 if (!a) 7491 return status; 7492 7493 free(a->args_endianness); 7494 free(a->instructions); 7495 free(a->instruction_data); 7496 free(a); 7497 7498 return status; 7499 } 7500 7501 static int 7502 action_build(struct rte_swx_pipeline *p) 7503 { 7504 struct action *action; 7505 7506 /* p->action_instructions. */ 7507 p->action_instructions = calloc(p->n_actions, sizeof(struct instruction *)); 7508 CHECK(p->action_instructions, ENOMEM); 7509 7510 TAILQ_FOREACH(action, &p->actions, node) 7511 p->action_instructions[action->id] = action->instructions; 7512 7513 /* p->action_funcs. */ 7514 p->action_funcs = calloc(p->n_actions, sizeof(action_func_t)); 7515 CHECK(p->action_funcs, ENOMEM); 7516 7517 return 0; 7518 } 7519 7520 static void 7521 action_build_free(struct rte_swx_pipeline *p) 7522 { 7523 free(p->action_funcs); 7524 p->action_funcs = NULL; 7525 7526 free(p->action_instructions); 7527 p->action_instructions = NULL; 7528 } 7529 7530 static void 7531 action_free(struct rte_swx_pipeline *p) 7532 { 7533 action_build_free(p); 7534 7535 for ( ; ; ) { 7536 struct action *action; 7537 7538 action = TAILQ_FIRST(&p->actions); 7539 if (!action) 7540 break; 7541 7542 TAILQ_REMOVE(&p->actions, action, node); 7543 free(action->args_endianness); 7544 free(action->instructions); 7545 free(action->instruction_data); 7546 free(action); 7547 } 7548 } 7549 7550 static uint32_t 7551 action_arg_src_mov_count(struct action *a, 7552 uint32_t arg_id, 7553 struct instruction *instructions, 7554 struct instruction_data *instruction_data, 7555 uint32_t n_instructions) 7556 { 7557 uint32_t offset, n_users = 0, i; 7558 7559 if (!a->st || 7560 (arg_id >= a->st->n_fields) || 7561 !instructions || 7562 !instruction_data || 7563 !n_instructions) 7564 return 0; 7565 7566 offset = a->st->fields[arg_id].offset / 8; 7567 7568 for (i = 0; i < n_instructions; i++) { 7569 struct instruction *instr = &instructions[i]; 7570 struct instruction_data *data = &instruction_data[i]; 7571 7572 if (data->invalid || 7573 ((instr->type != INSTR_MOV) && (instr->type != INSTR_MOV_HM)) || 7574 instr->mov.src.struct_id || 7575 (instr->mov.src.offset != offset)) 7576 continue; 7577 7578 n_users++; 7579 } 7580 7581 return n_users; 7582 } 7583 7584 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 7585 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits))) 7586 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits))) 7587 #else 7588 #define field_ntoh(val, n_bits) (val) 7589 #define field_hton(val, n_bits) (val) 7590 #endif 7591 7592 #define ACTION_ARGS_TOKENS_MAX 256 7593 7594 static int 7595 action_args_parse(struct action *a, const char *args, uint8_t *data) 7596 { 7597 char *tokens[ACTION_ARGS_TOKENS_MAX], *s0 = NULL, *s; 7598 uint32_t n_tokens = 0, offset = 0, i; 7599 int status = 0; 7600 7601 /* Checks. */ 7602 if (!a->st || !args || !args[0]) { 7603 status = -EINVAL; 7604 goto error; 7605 } 7606 7607 /* Memory allocation. */ 7608 s0 = strdup(args); 7609 if (!s0) { 7610 status = -ENOMEM; 7611 goto error; 7612 } 7613 7614 /* Parse the string into tokens. */ 7615 for (s = s0; ; ) { 7616 char *token; 7617 7618 token = strtok_r(s, " \f\n\r\t\v", &s); 7619 if (!token) 7620 break; 7621 7622 if (n_tokens >= RTE_DIM(tokens)) { 7623 status = -EINVAL; 7624 goto error; 7625 } 7626 7627 tokens[n_tokens] = token; 7628 n_tokens++; 7629 } 7630 7631 /* More checks. */ 7632 if (n_tokens != a->st->n_fields * 2) { 7633 status = -EINVAL; 7634 goto error; 7635 } 7636 7637 /* Process the action arguments. */ 7638 for (i = 0; i < a->st->n_fields; i++) { 7639 struct field *f = &a->st->fields[i]; 7640 char *arg_name = tokens[i * 2]; 7641 char *arg_val = tokens[i * 2 + 1]; 7642 uint64_t val; 7643 7644 if (strcmp(arg_name, f->name)) { 7645 status = -EINVAL; 7646 goto error; 7647 } 7648 7649 val = strtoull(arg_val, &arg_val, 0); 7650 if (arg_val[0]) { 7651 status = -EINVAL; 7652 goto error; 7653 } 7654 7655 /* Endianness conversion. */ 7656 if (a->args_endianness[i]) 7657 val = field_hton(val, f->n_bits); 7658 7659 /* Copy to entry. */ 7660 memcpy(&data[offset], (uint8_t *)&val, f->n_bits / 8); 7661 offset += f->n_bits / 8; 7662 } 7663 7664 error: 7665 free(s0); 7666 return status; 7667 } 7668 7669 /* 7670 * Table. 7671 */ 7672 static struct table_type * 7673 table_type_find(struct rte_swx_pipeline *p, const char *name) 7674 { 7675 struct table_type *elem; 7676 7677 TAILQ_FOREACH(elem, &p->table_types, node) 7678 if (strcmp(elem->name, name) == 0) 7679 return elem; 7680 7681 return NULL; 7682 } 7683 7684 static struct table_type * 7685 table_type_resolve(struct rte_swx_pipeline *p, 7686 const char *recommended_type_name, 7687 enum rte_swx_table_match_type match_type) 7688 { 7689 struct table_type *elem; 7690 7691 /* Only consider the recommended type if the match type is correct. */ 7692 if (recommended_type_name) 7693 TAILQ_FOREACH(elem, &p->table_types, node) 7694 if (!strcmp(elem->name, recommended_type_name) && 7695 (elem->match_type == match_type)) 7696 return elem; 7697 7698 /* Ignore the recommended type and get the first element with this match 7699 * type. 7700 */ 7701 TAILQ_FOREACH(elem, &p->table_types, node) 7702 if (elem->match_type == match_type) 7703 return elem; 7704 7705 return NULL; 7706 } 7707 7708 static struct table * 7709 table_find(struct rte_swx_pipeline *p, const char *name) 7710 { 7711 struct table *elem; 7712 7713 TAILQ_FOREACH(elem, &p->tables, node) 7714 if (strcmp(elem->name, name) == 0) 7715 return elem; 7716 7717 return NULL; 7718 } 7719 7720 static struct table * 7721 table_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 7722 { 7723 struct table *table = NULL; 7724 7725 TAILQ_FOREACH(table, &p->tables, node) 7726 if (table->id == id) 7727 return table; 7728 7729 return NULL; 7730 } 7731 7732 int 7733 rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p, 7734 const char *name, 7735 enum rte_swx_table_match_type match_type, 7736 struct rte_swx_table_ops *ops) 7737 { 7738 struct table_type *elem; 7739 7740 CHECK(p, EINVAL); 7741 7742 CHECK_NAME(name, EINVAL); 7743 CHECK(!table_type_find(p, name), EEXIST); 7744 7745 CHECK(ops, EINVAL); 7746 CHECK(ops->create, EINVAL); 7747 CHECK(ops->lkp, EINVAL); 7748 CHECK(ops->free, EINVAL); 7749 7750 /* Node allocation. */ 7751 elem = calloc(1, sizeof(struct table_type)); 7752 CHECK(elem, ENOMEM); 7753 7754 /* Node initialization. */ 7755 strcpy(elem->name, name); 7756 elem->match_type = match_type; 7757 memcpy(&elem->ops, ops, sizeof(*ops)); 7758 7759 /* Node add to tailq. */ 7760 TAILQ_INSERT_TAIL(&p->table_types, elem, node); 7761 7762 return 0; 7763 } 7764 7765 static int 7766 table_match_type_resolve(struct rte_swx_match_field_params *fields, 7767 uint32_t n_fields, 7768 enum rte_swx_table_match_type *match_type) 7769 { 7770 uint32_t n_fields_em = 0, n_fields_lpm = 0, i; 7771 7772 for (i = 0; i < n_fields; i++) { 7773 struct rte_swx_match_field_params *f = &fields[i]; 7774 7775 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT) 7776 n_fields_em++; 7777 7778 if (f->match_type == RTE_SWX_TABLE_MATCH_LPM) 7779 n_fields_lpm++; 7780 } 7781 7782 if ((n_fields_lpm > 1) || 7783 (n_fields_lpm && (n_fields_em != n_fields - 1))) 7784 return -EINVAL; 7785 7786 *match_type = (n_fields_em == n_fields) ? 7787 RTE_SWX_TABLE_MATCH_EXACT : 7788 RTE_SWX_TABLE_MATCH_WILDCARD; 7789 7790 return 0; 7791 } 7792 7793 static int 7794 table_match_fields_check(struct rte_swx_pipeline *p, 7795 struct rte_swx_pipeline_table_params *params, 7796 struct header **header) 7797 { 7798 struct header *h0 = NULL; 7799 struct field *hf, *mf; 7800 uint32_t *offset = NULL, i; 7801 int status = 0; 7802 7803 /* Return if no match fields. */ 7804 if (!params->n_fields) { 7805 if (params->fields) { 7806 status = -EINVAL; 7807 goto end; 7808 } 7809 7810 if (header) 7811 *header = NULL; 7812 7813 return 0; 7814 } 7815 7816 /* Memory allocation. */ 7817 offset = calloc(params->n_fields, sizeof(uint32_t)); 7818 if (!offset) { 7819 status = -ENOMEM; 7820 goto end; 7821 } 7822 7823 /* Check that all the match fields belong to either the same header or 7824 * to the meta-data. 7825 */ 7826 hf = header_field_parse(p, params->fields[0].name, &h0); 7827 mf = metadata_field_parse(p, params->fields[0].name); 7828 if ((!hf && !mf) || (hf && hf->var_size)) { 7829 status = -EINVAL; 7830 goto end; 7831 } 7832 7833 offset[0] = h0 ? hf->offset : mf->offset; 7834 7835 for (i = 1; i < params->n_fields; i++) 7836 if (h0) { 7837 struct header *h; 7838 7839 hf = header_field_parse(p, params->fields[i].name, &h); 7840 if (!hf || (h->id != h0->id) || hf->var_size) { 7841 status = -EINVAL; 7842 goto end; 7843 } 7844 7845 offset[i] = hf->offset; 7846 } else { 7847 mf = metadata_field_parse(p, params->fields[i].name); 7848 if (!mf) { 7849 status = -EINVAL; 7850 goto end; 7851 } 7852 7853 offset[i] = mf->offset; 7854 } 7855 7856 /* Check that there are no duplicated match fields. */ 7857 for (i = 0; i < params->n_fields; i++) { 7858 uint32_t j; 7859 7860 for (j = 0; j < i; j++) 7861 if (offset[j] == offset[i]) { 7862 status = -EINVAL; 7863 goto end; 7864 } 7865 } 7866 7867 /* Return. */ 7868 if (header) 7869 *header = h0; 7870 7871 end: 7872 free(offset); 7873 return status; 7874 } 7875 7876 int 7877 rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, 7878 const char *name, 7879 struct rte_swx_pipeline_table_params *params, 7880 const char *recommended_table_type_name, 7881 const char *args, 7882 uint32_t size) 7883 { 7884 struct table_type *type; 7885 struct table *t = NULL; 7886 struct action *default_action; 7887 struct header *header = NULL; 7888 uint32_t action_data_size_max = 0, i; 7889 int status = 0; 7890 7891 CHECK(p, EINVAL); 7892 7893 CHECK_NAME(name, EINVAL); 7894 CHECK(!table_find(p, name), EEXIST); 7895 CHECK(!selector_find(p, name), EEXIST); 7896 CHECK(!learner_find(p, name), EEXIST); 7897 7898 CHECK(params, EINVAL); 7899 7900 /* Match checks. */ 7901 status = table_match_fields_check(p, params, &header); 7902 if (status) 7903 return status; 7904 7905 /* Action checks. */ 7906 CHECK(params->n_actions, EINVAL); 7907 CHECK(params->action_names, EINVAL); 7908 for (i = 0; i < params->n_actions; i++) { 7909 const char *action_name = params->action_names[i]; 7910 struct action *a; 7911 uint32_t action_data_size; 7912 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 7913 7914 CHECK_NAME(action_name, EINVAL); 7915 7916 a = action_find(p, action_name); 7917 CHECK(a, EINVAL); 7918 CHECK(!action_does_learning(a), EINVAL); 7919 7920 action_data_size = a->st ? a->st->n_bits / 8 : 0; 7921 if (action_data_size > action_data_size_max) 7922 action_data_size_max = action_data_size; 7923 7924 if (params->action_is_for_table_entries) 7925 action_is_for_table_entries = params->action_is_for_table_entries[i]; 7926 if (params->action_is_for_default_entry) 7927 action_is_for_default_entry = params->action_is_for_default_entry[i]; 7928 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 7929 } 7930 7931 CHECK_NAME(params->default_action_name, EINVAL); 7932 for (i = 0; i < p->n_actions; i++) 7933 if (!strcmp(params->action_names[i], 7934 params->default_action_name)) 7935 break; 7936 CHECK(i < params->n_actions, EINVAL); 7937 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 7938 EINVAL); 7939 7940 default_action = action_find(p, params->default_action_name); 7941 CHECK((default_action->st && params->default_action_args) || !params->default_action_args, 7942 EINVAL); 7943 7944 /* Table type checks. */ 7945 if (recommended_table_type_name) 7946 CHECK_NAME(recommended_table_type_name, EINVAL); 7947 7948 if (params->n_fields) { 7949 enum rte_swx_table_match_type match_type; 7950 7951 status = table_match_type_resolve(params->fields, params->n_fields, &match_type); 7952 if (status) 7953 return status; 7954 7955 type = table_type_resolve(p, recommended_table_type_name, match_type); 7956 CHECK(type, EINVAL); 7957 } else { 7958 type = NULL; 7959 } 7960 7961 /* Memory allocation. */ 7962 t = calloc(1, sizeof(struct table)); 7963 if (!t) { 7964 status = -ENOMEM; 7965 goto error; 7966 } 7967 7968 t->fields = calloc(params->n_fields, sizeof(struct match_field)); 7969 if (!t->fields) { 7970 status = -ENOMEM; 7971 goto error; 7972 } 7973 7974 t->actions = calloc(params->n_actions, sizeof(struct action *)); 7975 if (!t->actions) { 7976 status = -ENOMEM; 7977 goto error; 7978 } 7979 7980 if (action_data_size_max) { 7981 t->default_action_data = calloc(1, action_data_size_max); 7982 if (!t->default_action_data) { 7983 status = -ENOMEM; 7984 goto error; 7985 } 7986 } 7987 7988 t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 7989 if (!t->action_is_for_table_entries) { 7990 status = -ENOMEM; 7991 goto error; 7992 } 7993 7994 t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 7995 if (!t->action_is_for_default_entry) { 7996 status = -ENOMEM; 7997 goto error; 7998 } 7999 8000 /* Node initialization. */ 8001 strcpy(t->name, name); 8002 if (args && args[0]) 8003 strcpy(t->args, args); 8004 t->type = type; 8005 8006 for (i = 0; i < params->n_fields; i++) { 8007 struct rte_swx_match_field_params *field = ¶ms->fields[i]; 8008 struct match_field *f = &t->fields[i]; 8009 8010 f->match_type = field->match_type; 8011 f->field = header ? 8012 header_field_parse(p, field->name, NULL) : 8013 metadata_field_parse(p, field->name); 8014 } 8015 t->n_fields = params->n_fields; 8016 t->header = header; 8017 8018 for (i = 0; i < params->n_actions; i++) { 8019 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8020 8021 if (params->action_is_for_table_entries) 8022 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8023 if (params->action_is_for_default_entry) 8024 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8025 8026 t->actions[i] = action_find(p, params->action_names[i]); 8027 t->action_is_for_table_entries[i] = action_is_for_table_entries; 8028 t->action_is_for_default_entry[i] = action_is_for_default_entry; 8029 } 8030 t->default_action = default_action; 8031 if (default_action->st) { 8032 status = action_args_parse(default_action, 8033 params->default_action_args, 8034 t->default_action_data); 8035 if (status) 8036 goto error; 8037 } 8038 8039 t->n_actions = params->n_actions; 8040 t->default_action_is_const = params->default_action_is_const; 8041 t->action_data_size_max = action_data_size_max; 8042 8043 t->size = size; 8044 t->id = p->n_tables; 8045 8046 /* Node add to tailq. */ 8047 TAILQ_INSERT_TAIL(&p->tables, t, node); 8048 p->n_tables++; 8049 8050 return 0; 8051 8052 error: 8053 if (!t) 8054 return status; 8055 8056 free(t->action_is_for_default_entry); 8057 free(t->action_is_for_table_entries); 8058 free(t->default_action_data); 8059 free(t->actions); 8060 free(t->fields); 8061 free(t); 8062 8063 return status; 8064 } 8065 8066 static struct rte_swx_table_params * 8067 table_params_get(struct table *table) 8068 { 8069 struct rte_swx_table_params *params; 8070 struct field *first, *last; 8071 uint8_t *key_mask; 8072 uint32_t key_size, key_offset, action_data_size, i; 8073 8074 /* Memory allocation. */ 8075 params = calloc(1, sizeof(struct rte_swx_table_params)); 8076 if (!params) 8077 return NULL; 8078 8079 /* Find first (smallest offset) and last (biggest offset) match fields. */ 8080 first = table->fields[0].field; 8081 last = table->fields[0].field; 8082 8083 for (i = 0; i < table->n_fields; i++) { 8084 struct field *f = table->fields[i].field; 8085 8086 if (f->offset < first->offset) 8087 first = f; 8088 8089 if (f->offset > last->offset) 8090 last = f; 8091 } 8092 8093 /* Key offset and size. */ 8094 key_offset = first->offset / 8; 8095 key_size = (last->offset + last->n_bits - first->offset) / 8; 8096 8097 /* Memory allocation. */ 8098 key_mask = calloc(1, key_size); 8099 if (!key_mask) { 8100 free(params); 8101 return NULL; 8102 } 8103 8104 /* Key mask. */ 8105 for (i = 0; i < table->n_fields; i++) { 8106 struct field *f = table->fields[i].field; 8107 uint32_t start = (f->offset - first->offset) / 8; 8108 size_t size = f->n_bits / 8; 8109 8110 memset(&key_mask[start], 0xFF, size); 8111 } 8112 8113 /* Action data size. */ 8114 action_data_size = 0; 8115 for (i = 0; i < table->n_actions; i++) { 8116 struct action *action = table->actions[i]; 8117 uint32_t ads = action->st ? action->st->n_bits / 8 : 0; 8118 8119 if (ads > action_data_size) 8120 action_data_size = ads; 8121 } 8122 8123 /* Fill in. */ 8124 params->match_type = table->type->match_type; 8125 params->key_size = key_size; 8126 params->key_offset = key_offset; 8127 params->key_mask0 = key_mask; 8128 params->action_data_size = action_data_size; 8129 params->n_keys_max = table->size; 8130 8131 return params; 8132 } 8133 8134 static void 8135 table_params_free(struct rte_swx_table_params *params) 8136 { 8137 if (!params) 8138 return; 8139 8140 free(params->key_mask0); 8141 free(params); 8142 } 8143 8144 static int 8145 table_stub_lkp(void *table __rte_unused, 8146 void *mailbox __rte_unused, 8147 uint8_t **key __rte_unused, 8148 uint64_t *action_id __rte_unused, 8149 uint8_t **action_data __rte_unused, 8150 int *hit) 8151 { 8152 *hit = 0; 8153 return 1; /* DONE. */ 8154 } 8155 8156 static int 8157 table_build(struct rte_swx_pipeline *p) 8158 { 8159 uint32_t i; 8160 8161 /* Per pipeline: table statistics. */ 8162 p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics)); 8163 CHECK(p->table_stats, ENOMEM); 8164 8165 for (i = 0; i < p->n_tables; i++) { 8166 p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 8167 CHECK(p->table_stats[i].n_pkts_action, ENOMEM); 8168 } 8169 8170 /* Per thread: table runt-time. */ 8171 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8172 struct thread *t = &p->threads[i]; 8173 struct table *table; 8174 8175 t->tables = calloc(p->n_tables, sizeof(struct table_runtime)); 8176 CHECK(t->tables, ENOMEM); 8177 8178 TAILQ_FOREACH(table, &p->tables, node) { 8179 struct table_runtime *r = &t->tables[table->id]; 8180 8181 if (table->type) { 8182 uint64_t size; 8183 8184 size = table->type->ops.mailbox_size_get(); 8185 8186 /* r->func. */ 8187 r->func = table->type->ops.lkp; 8188 8189 /* r->mailbox. */ 8190 if (size) { 8191 r->mailbox = calloc(1, size); 8192 CHECK(r->mailbox, ENOMEM); 8193 } 8194 8195 /* r->key. */ 8196 r->key = table->header ? 8197 &t->structs[table->header->struct_id] : 8198 &t->structs[p->metadata_struct_id]; 8199 } else { 8200 r->func = table_stub_lkp; 8201 } 8202 } 8203 } 8204 8205 return 0; 8206 } 8207 8208 static void 8209 table_build_free(struct rte_swx_pipeline *p) 8210 { 8211 uint32_t i; 8212 8213 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8214 struct thread *t = &p->threads[i]; 8215 uint32_t j; 8216 8217 if (!t->tables) 8218 continue; 8219 8220 for (j = 0; j < p->n_tables; j++) { 8221 struct table_runtime *r = &t->tables[j]; 8222 8223 free(r->mailbox); 8224 } 8225 8226 free(t->tables); 8227 t->tables = NULL; 8228 } 8229 8230 if (p->table_stats) { 8231 for (i = 0; i < p->n_tables; i++) 8232 free(p->table_stats[i].n_pkts_action); 8233 8234 free(p->table_stats); 8235 } 8236 } 8237 8238 static void 8239 table_free(struct rte_swx_pipeline *p) 8240 { 8241 table_build_free(p); 8242 8243 /* Tables. */ 8244 for ( ; ; ) { 8245 struct table *elem; 8246 8247 elem = TAILQ_FIRST(&p->tables); 8248 if (!elem) 8249 break; 8250 8251 TAILQ_REMOVE(&p->tables, elem, node); 8252 free(elem->fields); 8253 free(elem->actions); 8254 free(elem->default_action_data); 8255 free(elem); 8256 } 8257 8258 /* Table types. */ 8259 for ( ; ; ) { 8260 struct table_type *elem; 8261 8262 elem = TAILQ_FIRST(&p->table_types); 8263 if (!elem) 8264 break; 8265 8266 TAILQ_REMOVE(&p->table_types, elem, node); 8267 free(elem); 8268 } 8269 } 8270 8271 /* 8272 * Selector. 8273 */ 8274 static struct selector * 8275 selector_find(struct rte_swx_pipeline *p, const char *name) 8276 { 8277 struct selector *s; 8278 8279 TAILQ_FOREACH(s, &p->selectors, node) 8280 if (strcmp(s->name, name) == 0) 8281 return s; 8282 8283 return NULL; 8284 } 8285 8286 static struct selector * 8287 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8288 { 8289 struct selector *s = NULL; 8290 8291 TAILQ_FOREACH(s, &p->selectors, node) 8292 if (s->id == id) 8293 return s; 8294 8295 return NULL; 8296 } 8297 8298 static int 8299 selector_fields_check(struct rte_swx_pipeline *p, 8300 struct rte_swx_pipeline_selector_params *params, 8301 struct header **header) 8302 { 8303 struct header *h0 = NULL; 8304 struct field *hf, *mf; 8305 uint32_t i; 8306 8307 /* Return if no selector fields. */ 8308 if (!params->n_selector_fields || !params->selector_field_names) 8309 return -EINVAL; 8310 8311 /* Check that all the selector fields either belong to the same header 8312 * or are all meta-data fields. 8313 */ 8314 hf = header_field_parse(p, params->selector_field_names[0], &h0); 8315 mf = metadata_field_parse(p, params->selector_field_names[0]); 8316 if (!hf && !mf) 8317 return -EINVAL; 8318 8319 for (i = 1; i < params->n_selector_fields; i++) 8320 if (h0) { 8321 struct header *h; 8322 8323 hf = header_field_parse(p, params->selector_field_names[i], &h); 8324 if (!hf || (h->id != h0->id)) 8325 return -EINVAL; 8326 } else { 8327 mf = metadata_field_parse(p, params->selector_field_names[i]); 8328 if (!mf) 8329 return -EINVAL; 8330 } 8331 8332 /* Check that there are no duplicated match fields. */ 8333 for (i = 0; i < params->n_selector_fields; i++) { 8334 const char *field_name = params->selector_field_names[i]; 8335 uint32_t j; 8336 8337 for (j = i + 1; j < params->n_selector_fields; j++) 8338 if (!strcmp(params->selector_field_names[j], field_name)) 8339 return -EINVAL; 8340 } 8341 8342 /* Return. */ 8343 if (header) 8344 *header = h0; 8345 8346 return 0; 8347 } 8348 8349 int 8350 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p, 8351 const char *name, 8352 struct rte_swx_pipeline_selector_params *params) 8353 { 8354 struct selector *s; 8355 struct header *selector_header = NULL; 8356 struct field *group_id_field, *member_id_field; 8357 uint32_t i; 8358 int status = 0; 8359 8360 CHECK(p, EINVAL); 8361 8362 CHECK_NAME(name, EINVAL); 8363 CHECK(!table_find(p, name), EEXIST); 8364 CHECK(!selector_find(p, name), EEXIST); 8365 CHECK(!learner_find(p, name), EEXIST); 8366 8367 CHECK(params, EINVAL); 8368 8369 CHECK_NAME(params->group_id_field_name, EINVAL); 8370 group_id_field = metadata_field_parse(p, params->group_id_field_name); 8371 CHECK(group_id_field, EINVAL); 8372 8373 for (i = 0; i < params->n_selector_fields; i++) { 8374 const char *field_name = params->selector_field_names[i]; 8375 8376 CHECK_NAME(field_name, EINVAL); 8377 } 8378 status = selector_fields_check(p, params, &selector_header); 8379 if (status) 8380 return status; 8381 8382 CHECK_NAME(params->member_id_field_name, EINVAL); 8383 member_id_field = metadata_field_parse(p, params->member_id_field_name); 8384 CHECK(member_id_field, EINVAL); 8385 8386 CHECK(params->n_groups_max, EINVAL); 8387 8388 CHECK(params->n_members_per_group_max, EINVAL); 8389 8390 /* Memory allocation. */ 8391 s = calloc(1, sizeof(struct selector)); 8392 if (!s) { 8393 status = -ENOMEM; 8394 goto error; 8395 } 8396 8397 s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *)); 8398 if (!s->selector_fields) { 8399 status = -ENOMEM; 8400 goto error; 8401 } 8402 8403 /* Node initialization. */ 8404 strcpy(s->name, name); 8405 8406 s->group_id_field = group_id_field; 8407 8408 for (i = 0; i < params->n_selector_fields; i++) { 8409 const char *field_name = params->selector_field_names[i]; 8410 8411 s->selector_fields[i] = selector_header ? 8412 header_field_parse(p, field_name, NULL) : 8413 metadata_field_parse(p, field_name); 8414 } 8415 8416 s->n_selector_fields = params->n_selector_fields; 8417 8418 s->selector_header = selector_header; 8419 8420 s->member_id_field = member_id_field; 8421 8422 s->n_groups_max = params->n_groups_max; 8423 8424 s->n_members_per_group_max = params->n_members_per_group_max; 8425 8426 s->id = p->n_selectors; 8427 8428 /* Node add to tailq. */ 8429 TAILQ_INSERT_TAIL(&p->selectors, s, node); 8430 p->n_selectors++; 8431 8432 return 0; 8433 8434 error: 8435 if (!s) 8436 return status; 8437 8438 free(s->selector_fields); 8439 8440 free(s); 8441 8442 return status; 8443 } 8444 8445 static void 8446 selector_params_free(struct rte_swx_table_selector_params *params) 8447 { 8448 if (!params) 8449 return; 8450 8451 free(params->selector_mask); 8452 8453 free(params); 8454 } 8455 8456 static struct rte_swx_table_selector_params * 8457 selector_table_params_get(struct selector *s) 8458 { 8459 struct rte_swx_table_selector_params *params = NULL; 8460 struct field *first, *last; 8461 uint32_t i; 8462 8463 /* Memory allocation. */ 8464 params = calloc(1, sizeof(struct rte_swx_table_selector_params)); 8465 if (!params) 8466 goto error; 8467 8468 /* Group ID. */ 8469 params->group_id_offset = s->group_id_field->offset / 8; 8470 8471 /* Find first (smallest offset) and last (biggest offset) selector fields. */ 8472 first = s->selector_fields[0]; 8473 last = s->selector_fields[0]; 8474 8475 for (i = 0; i < s->n_selector_fields; i++) { 8476 struct field *f = s->selector_fields[i]; 8477 8478 if (f->offset < first->offset) 8479 first = f; 8480 8481 if (f->offset > last->offset) 8482 last = f; 8483 } 8484 8485 /* Selector offset and size. */ 8486 params->selector_offset = first->offset / 8; 8487 params->selector_size = (last->offset + last->n_bits - first->offset) / 8; 8488 8489 /* Memory allocation. */ 8490 params->selector_mask = calloc(1, params->selector_size); 8491 if (!params->selector_mask) 8492 goto error; 8493 8494 /* Selector mask. */ 8495 for (i = 0; i < s->n_selector_fields; i++) { 8496 struct field *f = s->selector_fields[i]; 8497 uint32_t start = (f->offset - first->offset) / 8; 8498 size_t size = f->n_bits / 8; 8499 8500 memset(¶ms->selector_mask[start], 0xFF, size); 8501 } 8502 8503 /* Member ID. */ 8504 params->member_id_offset = s->member_id_field->offset / 8; 8505 8506 /* Maximum number of groups. */ 8507 params->n_groups_max = s->n_groups_max; 8508 8509 /* Maximum number of members per group. */ 8510 params->n_members_per_group_max = s->n_members_per_group_max; 8511 8512 return params; 8513 8514 error: 8515 selector_params_free(params); 8516 return NULL; 8517 } 8518 8519 static void 8520 selector_build_free(struct rte_swx_pipeline *p) 8521 { 8522 uint32_t i; 8523 8524 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8525 struct thread *t = &p->threads[i]; 8526 uint32_t j; 8527 8528 if (!t->selectors) 8529 continue; 8530 8531 for (j = 0; j < p->n_selectors; j++) { 8532 struct selector_runtime *r = &t->selectors[j]; 8533 8534 free(r->mailbox); 8535 } 8536 8537 free(t->selectors); 8538 t->selectors = NULL; 8539 } 8540 8541 free(p->selector_stats); 8542 p->selector_stats = NULL; 8543 } 8544 8545 static int 8546 selector_build(struct rte_swx_pipeline *p) 8547 { 8548 uint32_t i; 8549 int status = 0; 8550 8551 /* Per pipeline: selector statistics. */ 8552 p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics)); 8553 if (!p->selector_stats) { 8554 status = -ENOMEM; 8555 goto error; 8556 } 8557 8558 /* Per thread: selector run-time. */ 8559 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8560 struct thread *t = &p->threads[i]; 8561 struct selector *s; 8562 8563 t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime)); 8564 if (!t->selectors) { 8565 status = -ENOMEM; 8566 goto error; 8567 } 8568 8569 TAILQ_FOREACH(s, &p->selectors, node) { 8570 struct selector_runtime *r = &t->selectors[s->id]; 8571 uint64_t size; 8572 8573 /* r->mailbox. */ 8574 size = rte_swx_table_selector_mailbox_size_get(); 8575 if (size) { 8576 r->mailbox = calloc(1, size); 8577 if (!r->mailbox) { 8578 status = -ENOMEM; 8579 goto error; 8580 } 8581 } 8582 8583 /* r->group_id_buffer. */ 8584 r->group_id_buffer = &t->structs[p->metadata_struct_id]; 8585 8586 /* r->selector_buffer. */ 8587 r->selector_buffer = s->selector_header ? 8588 &t->structs[s->selector_header->struct_id] : 8589 &t->structs[p->metadata_struct_id]; 8590 8591 /* r->member_id_buffer. */ 8592 r->member_id_buffer = &t->structs[p->metadata_struct_id]; 8593 } 8594 } 8595 8596 return 0; 8597 8598 error: 8599 selector_build_free(p); 8600 return status; 8601 } 8602 8603 static void 8604 selector_free(struct rte_swx_pipeline *p) 8605 { 8606 selector_build_free(p); 8607 8608 /* Selector tables. */ 8609 for ( ; ; ) { 8610 struct selector *elem; 8611 8612 elem = TAILQ_FIRST(&p->selectors); 8613 if (!elem) 8614 break; 8615 8616 TAILQ_REMOVE(&p->selectors, elem, node); 8617 free(elem->selector_fields); 8618 free(elem); 8619 } 8620 } 8621 8622 /* 8623 * Learner table. 8624 */ 8625 static struct learner * 8626 learner_find(struct rte_swx_pipeline *p, const char *name) 8627 { 8628 struct learner *l; 8629 8630 TAILQ_FOREACH(l, &p->learners, node) 8631 if (!strcmp(l->name, name)) 8632 return l; 8633 8634 return NULL; 8635 } 8636 8637 static struct learner * 8638 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8639 { 8640 struct learner *l = NULL; 8641 8642 TAILQ_FOREACH(l, &p->learners, node) 8643 if (l->id == id) 8644 return l; 8645 8646 return NULL; 8647 } 8648 8649 static int 8650 learner_match_fields_check(struct rte_swx_pipeline *p, 8651 struct rte_swx_pipeline_learner_params *params, 8652 struct header **header) 8653 { 8654 struct header *h0 = NULL; 8655 struct field *hf, *mf; 8656 uint32_t i; 8657 8658 /* Return if no match fields. */ 8659 if (!params->n_fields || !params->field_names) 8660 return -EINVAL; 8661 8662 /* Check that all the match fields either belong to the same header 8663 * or are all meta-data fields. 8664 */ 8665 hf = header_field_parse(p, params->field_names[0], &h0); 8666 mf = metadata_field_parse(p, params->field_names[0]); 8667 if (!hf && !mf) 8668 return -EINVAL; 8669 8670 for (i = 1; i < params->n_fields; i++) 8671 if (h0) { 8672 struct header *h; 8673 8674 hf = header_field_parse(p, params->field_names[i], &h); 8675 if (!hf || (h->id != h0->id)) 8676 return -EINVAL; 8677 } else { 8678 mf = metadata_field_parse(p, params->field_names[i]); 8679 if (!mf) 8680 return -EINVAL; 8681 } 8682 8683 /* Check that there are no duplicated match fields. */ 8684 for (i = 0; i < params->n_fields; i++) { 8685 const char *field_name = params->field_names[i]; 8686 uint32_t j; 8687 8688 for (j = i + 1; j < params->n_fields; j++) 8689 if (!strcmp(params->field_names[j], field_name)) 8690 return -EINVAL; 8691 } 8692 8693 /* Return. */ 8694 if (header) 8695 *header = h0; 8696 8697 return 0; 8698 } 8699 8700 static int 8701 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name) 8702 { 8703 struct struct_type *mst = p->metadata_st, *ast = a->st; 8704 struct field *mf, *af; 8705 uint32_t mf_pos, i; 8706 8707 if (!ast) { 8708 if (mf_name) 8709 return -EINVAL; 8710 8711 return 0; 8712 } 8713 8714 /* Check that mf_name is the name of a valid meta-data field. */ 8715 CHECK_NAME(mf_name, EINVAL); 8716 mf = metadata_field_parse(p, mf_name); 8717 CHECK(mf, EINVAL); 8718 8719 /* Check that there are enough meta-data fields, starting with the mf_name field, to cover 8720 * all the action arguments. 8721 */ 8722 mf_pos = mf - mst->fields; 8723 CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL); 8724 8725 /* Check that the size of each of the identified meta-data fields matches exactly the size 8726 * of the corresponding action argument. 8727 */ 8728 for (i = 0; i < ast->n_fields; i++) { 8729 mf = &mst->fields[mf_pos + i]; 8730 af = &ast->fields[i]; 8731 8732 CHECK(mf->n_bits == af->n_bits, EINVAL); 8733 } 8734 8735 return 0; 8736 } 8737 8738 static int 8739 learner_action_learning_check(struct rte_swx_pipeline *p, 8740 struct action *action, 8741 const char **action_names, 8742 uint32_t n_actions) 8743 { 8744 uint32_t i; 8745 8746 /* For each "learn" instruction of the current action, check that the learned action (i.e. 8747 * the action passed as argument to the "learn" instruction) is also enabled for the 8748 * current learner table. 8749 */ 8750 for (i = 0; i < action->n_instructions; i++) { 8751 struct instruction *instr = &action->instructions[i]; 8752 uint32_t found = 0, j; 8753 8754 if (instr->type != INSTR_LEARNER_LEARN) 8755 continue; 8756 8757 for (j = 0; j < n_actions; j++) { 8758 struct action *a; 8759 8760 a = action_find(p, action_names[j]); 8761 if (!a) 8762 return -EINVAL; 8763 8764 if (a->id == instr->learn.action_id) 8765 found = 1; 8766 } 8767 8768 if (!found) 8769 return -EINVAL; 8770 } 8771 8772 return 0; 8773 } 8774 8775 int 8776 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, 8777 const char *name, 8778 struct rte_swx_pipeline_learner_params *params, 8779 uint32_t size, 8780 uint32_t *timeout, 8781 uint32_t n_timeouts) 8782 { 8783 struct learner *l = NULL; 8784 struct action *default_action; 8785 struct header *header = NULL; 8786 uint32_t action_data_size_max = 0, i; 8787 int status = 0; 8788 8789 CHECK(p, EINVAL); 8790 8791 CHECK_NAME(name, EINVAL); 8792 CHECK(!table_find(p, name), EEXIST); 8793 CHECK(!selector_find(p, name), EEXIST); 8794 CHECK(!learner_find(p, name), EEXIST); 8795 8796 CHECK(params, EINVAL); 8797 8798 /* Match checks. */ 8799 status = learner_match_fields_check(p, params, &header); 8800 if (status) 8801 return status; 8802 8803 /* Action checks. */ 8804 CHECK(params->n_actions, EINVAL); 8805 CHECK(params->action_names, EINVAL); 8806 for (i = 0; i < params->n_actions; i++) { 8807 const char *action_name = params->action_names[i]; 8808 struct action *a; 8809 uint32_t action_data_size; 8810 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8811 8812 CHECK_NAME(action_name, EINVAL); 8813 8814 a = action_find(p, action_name); 8815 CHECK(a, EINVAL); 8816 8817 status = learner_action_learning_check(p, 8818 a, 8819 params->action_names, 8820 params->n_actions); 8821 if (status) 8822 return status; 8823 8824 action_data_size = a->st ? a->st->n_bits / 8 : 0; 8825 if (action_data_size > action_data_size_max) 8826 action_data_size_max = action_data_size; 8827 8828 if (params->action_is_for_table_entries) 8829 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8830 if (params->action_is_for_default_entry) 8831 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8832 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 8833 } 8834 8835 CHECK_NAME(params->default_action_name, EINVAL); 8836 for (i = 0; i < p->n_actions; i++) 8837 if (!strcmp(params->action_names[i], 8838 params->default_action_name)) 8839 break; 8840 CHECK(i < params->n_actions, EINVAL); 8841 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 8842 EINVAL); 8843 8844 default_action = action_find(p, params->default_action_name); 8845 CHECK((default_action->st && params->default_action_args) || !params->default_action_args, 8846 EINVAL); 8847 8848 /* Any other checks. */ 8849 CHECK(size, EINVAL); 8850 CHECK(timeout, EINVAL); 8851 CHECK(n_timeouts && (n_timeouts < RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX), EINVAL); 8852 8853 /* Memory allocation. */ 8854 l = calloc(1, sizeof(struct learner)); 8855 if (!l) { 8856 status = -ENOMEM; 8857 goto error; 8858 } 8859 8860 l->fields = calloc(params->n_fields, sizeof(struct field *)); 8861 if (!l->fields) { 8862 status = -ENOMEM; 8863 goto error; 8864 } 8865 8866 l->actions = calloc(params->n_actions, sizeof(struct action *)); 8867 if (!l->actions) { 8868 status = -ENOMEM; 8869 goto error; 8870 } 8871 8872 if (action_data_size_max) { 8873 l->default_action_data = calloc(1, action_data_size_max); 8874 if (!l->default_action_data) { 8875 status = -ENOMEM; 8876 goto error; 8877 } 8878 } 8879 8880 l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 8881 if (!l->action_is_for_table_entries) { 8882 status = -ENOMEM; 8883 goto error; 8884 } 8885 8886 l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 8887 if (!l->action_is_for_default_entry) { 8888 status = -ENOMEM; 8889 goto error; 8890 } 8891 8892 /* Node initialization. */ 8893 strcpy(l->name, name); 8894 8895 for (i = 0; i < params->n_fields; i++) { 8896 const char *field_name = params->field_names[i]; 8897 8898 l->fields[i] = header ? 8899 header_field_parse(p, field_name, NULL) : 8900 metadata_field_parse(p, field_name); 8901 } 8902 8903 l->n_fields = params->n_fields; 8904 8905 l->header = header; 8906 8907 for (i = 0; i < params->n_actions; i++) { 8908 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8909 8910 if (params->action_is_for_table_entries) 8911 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8912 if (params->action_is_for_default_entry) 8913 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8914 8915 l->actions[i] = action_find(p, params->action_names[i]); 8916 l->action_is_for_table_entries[i] = action_is_for_table_entries; 8917 l->action_is_for_default_entry[i] = action_is_for_default_entry; 8918 } 8919 8920 l->default_action = default_action; 8921 8922 if (default_action->st) { 8923 status = action_args_parse(default_action, 8924 params->default_action_args, 8925 l->default_action_data); 8926 if (status) 8927 goto error; 8928 } 8929 8930 l->n_actions = params->n_actions; 8931 8932 l->default_action_is_const = params->default_action_is_const; 8933 8934 l->action_data_size_max = action_data_size_max; 8935 8936 l->size = size; 8937 8938 for (i = 0; i < n_timeouts; i++) 8939 l->timeout[i] = timeout[i]; 8940 8941 l->n_timeouts = n_timeouts; 8942 8943 l->id = p->n_learners; 8944 8945 /* Node add to tailq. */ 8946 TAILQ_INSERT_TAIL(&p->learners, l, node); 8947 p->n_learners++; 8948 8949 return 0; 8950 8951 error: 8952 if (!l) 8953 return status; 8954 8955 free(l->action_is_for_default_entry); 8956 free(l->action_is_for_table_entries); 8957 free(l->default_action_data); 8958 free(l->actions); 8959 free(l->fields); 8960 free(l); 8961 8962 return status; 8963 } 8964 8965 static void 8966 learner_params_free(struct rte_swx_table_learner_params *params) 8967 { 8968 if (!params) 8969 return; 8970 8971 free(params->key_mask0); 8972 8973 free(params->key_timeout); 8974 8975 free(params); 8976 } 8977 8978 static struct rte_swx_table_learner_params * 8979 learner_params_get(struct learner *l) 8980 { 8981 struct rte_swx_table_learner_params *params = NULL; 8982 struct field *first, *last; 8983 uint32_t i; 8984 8985 /* Memory allocation. */ 8986 params = calloc(1, sizeof(struct rte_swx_table_learner_params)); 8987 if (!params) 8988 goto error; 8989 8990 /* Find first (smallest offset) and last (biggest offset) match fields. */ 8991 first = l->fields[0]; 8992 last = l->fields[0]; 8993 8994 for (i = 0; i < l->n_fields; i++) { 8995 struct field *f = l->fields[i]; 8996 8997 if (f->offset < first->offset) 8998 first = f; 8999 9000 if (f->offset > last->offset) 9001 last = f; 9002 } 9003 9004 /* Key offset and size. */ 9005 params->key_offset = first->offset / 8; 9006 params->key_size = (last->offset + last->n_bits - first->offset) / 8; 9007 9008 /* Memory allocation. */ 9009 params->key_mask0 = calloc(1, params->key_size); 9010 if (!params->key_mask0) 9011 goto error; 9012 9013 /* Key mask. */ 9014 for (i = 0; i < l->n_fields; i++) { 9015 struct field *f = l->fields[i]; 9016 uint32_t start = (f->offset - first->offset) / 8; 9017 size_t size = f->n_bits / 8; 9018 9019 memset(¶ms->key_mask0[start], 0xFF, size); 9020 } 9021 9022 /* Action data size. */ 9023 params->action_data_size = l->action_data_size_max; 9024 9025 /* Maximum number of keys. */ 9026 params->n_keys_max = l->size; 9027 9028 /* Memory allocation. */ 9029 params->key_timeout = calloc(l->n_timeouts, sizeof(uint32_t)); 9030 if (!params->key_timeout) 9031 goto error; 9032 9033 /* Timeout. */ 9034 for (i = 0; i < l->n_timeouts; i++) 9035 params->key_timeout[i] = l->timeout[i]; 9036 9037 params->n_key_timeouts = l->n_timeouts; 9038 9039 return params; 9040 9041 error: 9042 learner_params_free(params); 9043 return NULL; 9044 } 9045 9046 static void 9047 learner_build_free(struct rte_swx_pipeline *p) 9048 { 9049 uint32_t i; 9050 9051 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9052 struct thread *t = &p->threads[i]; 9053 uint32_t j; 9054 9055 if (!t->learners) 9056 continue; 9057 9058 for (j = 0; j < p->n_learners; j++) { 9059 struct learner_runtime *r = &t->learners[j]; 9060 9061 free(r->mailbox); 9062 } 9063 9064 free(t->learners); 9065 t->learners = NULL; 9066 } 9067 9068 if (p->learner_stats) { 9069 for (i = 0; i < p->n_learners; i++) 9070 free(p->learner_stats[i].n_pkts_action); 9071 9072 free(p->learner_stats); 9073 } 9074 } 9075 9076 static int 9077 learner_build(struct rte_swx_pipeline *p) 9078 { 9079 uint32_t i; 9080 int status = 0; 9081 9082 /* Per pipeline: learner statistics. */ 9083 p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics)); 9084 CHECK(p->learner_stats, ENOMEM); 9085 9086 for (i = 0; i < p->n_learners; i++) { 9087 p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 9088 CHECK(p->learner_stats[i].n_pkts_action, ENOMEM); 9089 } 9090 9091 /* Per thread: learner run-time. */ 9092 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9093 struct thread *t = &p->threads[i]; 9094 struct learner *l; 9095 9096 t->learners = calloc(p->n_learners, sizeof(struct learner_runtime)); 9097 if (!t->learners) { 9098 status = -ENOMEM; 9099 goto error; 9100 } 9101 9102 TAILQ_FOREACH(l, &p->learners, node) { 9103 struct learner_runtime *r = &t->learners[l->id]; 9104 uint64_t size; 9105 9106 /* r->mailbox. */ 9107 size = rte_swx_table_learner_mailbox_size_get(); 9108 if (size) { 9109 r->mailbox = calloc(1, size); 9110 if (!r->mailbox) { 9111 status = -ENOMEM; 9112 goto error; 9113 } 9114 } 9115 9116 /* r->key. */ 9117 r->key = l->header ? 9118 &t->structs[l->header->struct_id] : 9119 &t->structs[p->metadata_struct_id]; 9120 } 9121 } 9122 9123 return 0; 9124 9125 error: 9126 learner_build_free(p); 9127 return status; 9128 } 9129 9130 static void 9131 learner_free(struct rte_swx_pipeline *p) 9132 { 9133 learner_build_free(p); 9134 9135 /* Learner tables. */ 9136 for ( ; ; ) { 9137 struct learner *l; 9138 9139 l = TAILQ_FIRST(&p->learners); 9140 if (!l) 9141 break; 9142 9143 TAILQ_REMOVE(&p->learners, l, node); 9144 free(l->fields); 9145 free(l->actions); 9146 free(l->default_action_data); 9147 free(l); 9148 } 9149 } 9150 9151 /* 9152 * Table state. 9153 */ 9154 static int 9155 table_state_build(struct rte_swx_pipeline *p) 9156 { 9157 struct table *table; 9158 struct selector *s; 9159 struct learner *l; 9160 9161 p->table_state = calloc(p->n_tables + p->n_selectors + p->n_learners, 9162 sizeof(struct rte_swx_table_state)); 9163 CHECK(p->table_state, ENOMEM); 9164 9165 TAILQ_FOREACH(table, &p->tables, node) { 9166 struct rte_swx_table_state *ts = &p->table_state[table->id]; 9167 9168 if (table->type) { 9169 struct rte_swx_table_params *params; 9170 9171 /* ts->obj. */ 9172 params = table_params_get(table); 9173 CHECK(params, ENOMEM); 9174 9175 ts->obj = table->type->ops.create(params, 9176 NULL, 9177 table->args, 9178 p->numa_node); 9179 9180 table_params_free(params); 9181 CHECK(ts->obj, ENODEV); 9182 } 9183 9184 /* ts->default_action_data. */ 9185 if (table->action_data_size_max) { 9186 ts->default_action_data = 9187 malloc(table->action_data_size_max); 9188 CHECK(ts->default_action_data, ENOMEM); 9189 9190 memcpy(ts->default_action_data, 9191 table->default_action_data, 9192 table->action_data_size_max); 9193 } 9194 9195 /* ts->default_action_id. */ 9196 ts->default_action_id = table->default_action->id; 9197 } 9198 9199 TAILQ_FOREACH(s, &p->selectors, node) { 9200 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id]; 9201 struct rte_swx_table_selector_params *params; 9202 9203 /* ts->obj. */ 9204 params = selector_table_params_get(s); 9205 CHECK(params, ENOMEM); 9206 9207 ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node); 9208 9209 selector_params_free(params); 9210 CHECK(ts->obj, ENODEV); 9211 } 9212 9213 TAILQ_FOREACH(l, &p->learners, node) { 9214 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + 9215 p->n_selectors + l->id]; 9216 struct rte_swx_table_learner_params *params; 9217 9218 /* ts->obj. */ 9219 params = learner_params_get(l); 9220 CHECK(params, ENOMEM); 9221 9222 ts->obj = rte_swx_table_learner_create(params, p->numa_node); 9223 learner_params_free(params); 9224 CHECK(ts->obj, ENODEV); 9225 9226 /* ts->default_action_data. */ 9227 if (l->action_data_size_max) { 9228 ts->default_action_data = malloc(l->action_data_size_max); 9229 CHECK(ts->default_action_data, ENOMEM); 9230 9231 memcpy(ts->default_action_data, 9232 l->default_action_data, 9233 l->action_data_size_max); 9234 } 9235 9236 /* ts->default_action_id. */ 9237 ts->default_action_id = l->default_action->id; 9238 } 9239 9240 return 0; 9241 } 9242 9243 static void 9244 table_state_build_free(struct rte_swx_pipeline *p) 9245 { 9246 uint32_t i; 9247 9248 if (!p->table_state) 9249 return; 9250 9251 for (i = 0; i < p->n_tables; i++) { 9252 struct rte_swx_table_state *ts = &p->table_state[i]; 9253 struct table *table = table_find_by_id(p, i); 9254 9255 /* ts->obj. */ 9256 if (table->type && ts->obj) 9257 table->type->ops.free(ts->obj); 9258 9259 /* ts->default_action_data. */ 9260 free(ts->default_action_data); 9261 } 9262 9263 for (i = 0; i < p->n_selectors; i++) { 9264 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i]; 9265 9266 /* ts->obj. */ 9267 if (ts->obj) 9268 rte_swx_table_selector_free(ts->obj); 9269 } 9270 9271 for (i = 0; i < p->n_learners; i++) { 9272 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i]; 9273 9274 /* ts->obj. */ 9275 if (ts->obj) 9276 rte_swx_table_learner_free(ts->obj); 9277 9278 /* ts->default_action_data. */ 9279 free(ts->default_action_data); 9280 } 9281 9282 free(p->table_state); 9283 p->table_state = NULL; 9284 } 9285 9286 static void 9287 table_state_free(struct rte_swx_pipeline *p) 9288 { 9289 table_state_build_free(p); 9290 } 9291 9292 /* 9293 * Register array. 9294 */ 9295 static struct regarray * 9296 regarray_find(struct rte_swx_pipeline *p, const char *name) 9297 { 9298 struct regarray *elem; 9299 9300 TAILQ_FOREACH(elem, &p->regarrays, node) 9301 if (!strcmp(elem->name, name)) 9302 return elem; 9303 9304 return NULL; 9305 } 9306 9307 static struct regarray * 9308 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 9309 { 9310 struct regarray *elem = NULL; 9311 9312 TAILQ_FOREACH(elem, &p->regarrays, node) 9313 if (elem->id == id) 9314 return elem; 9315 9316 return NULL; 9317 } 9318 9319 int 9320 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p, 9321 const char *name, 9322 uint32_t size, 9323 uint64_t init_val) 9324 { 9325 struct regarray *r; 9326 9327 CHECK(p, EINVAL); 9328 9329 CHECK_NAME(name, EINVAL); 9330 CHECK(!regarray_find(p, name), EEXIST); 9331 9332 CHECK(size, EINVAL); 9333 size = rte_align32pow2(size); 9334 9335 /* Memory allocation. */ 9336 r = calloc(1, sizeof(struct regarray)); 9337 CHECK(r, ENOMEM); 9338 9339 /* Node initialization. */ 9340 strcpy(r->name, name); 9341 r->init_val = init_val; 9342 r->size = size; 9343 r->id = p->n_regarrays; 9344 9345 /* Node add to tailq. */ 9346 TAILQ_INSERT_TAIL(&p->regarrays, r, node); 9347 p->n_regarrays++; 9348 9349 return 0; 9350 } 9351 9352 static int 9353 regarray_build(struct rte_swx_pipeline *p) 9354 { 9355 struct regarray *regarray; 9356 9357 if (!p->n_regarrays) 9358 return 0; 9359 9360 p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime)); 9361 CHECK(p->regarray_runtime, ENOMEM); 9362 9363 TAILQ_FOREACH(regarray, &p->regarrays, node) { 9364 struct regarray_runtime *r = &p->regarray_runtime[regarray->id]; 9365 uint32_t i; 9366 9367 r->regarray = env_malloc(regarray->size * sizeof(uint64_t), 9368 RTE_CACHE_LINE_SIZE, 9369 p->numa_node); 9370 CHECK(r->regarray, ENOMEM); 9371 9372 if (regarray->init_val) 9373 for (i = 0; i < regarray->size; i++) 9374 r->regarray[i] = regarray->init_val; 9375 9376 r->size_mask = regarray->size - 1; 9377 } 9378 9379 return 0; 9380 } 9381 9382 static void 9383 regarray_build_free(struct rte_swx_pipeline *p) 9384 { 9385 uint32_t i; 9386 9387 if (!p->regarray_runtime) 9388 return; 9389 9390 for (i = 0; i < p->n_regarrays; i++) { 9391 struct regarray *regarray = regarray_find_by_id(p, i); 9392 struct regarray_runtime *r = &p->regarray_runtime[i]; 9393 9394 env_free(r->regarray, regarray->size * sizeof(uint64_t)); 9395 } 9396 9397 free(p->regarray_runtime); 9398 p->regarray_runtime = NULL; 9399 } 9400 9401 static void 9402 regarray_free(struct rte_swx_pipeline *p) 9403 { 9404 regarray_build_free(p); 9405 9406 for ( ; ; ) { 9407 struct regarray *elem; 9408 9409 elem = TAILQ_FIRST(&p->regarrays); 9410 if (!elem) 9411 break; 9412 9413 TAILQ_REMOVE(&p->regarrays, elem, node); 9414 free(elem); 9415 } 9416 } 9417 9418 /* 9419 * Meter array. 9420 */ 9421 static struct meter_profile * 9422 meter_profile_find(struct rte_swx_pipeline *p, const char *name) 9423 { 9424 struct meter_profile *elem; 9425 9426 TAILQ_FOREACH(elem, &p->meter_profiles, node) 9427 if (!strcmp(elem->name, name)) 9428 return elem; 9429 9430 return NULL; 9431 } 9432 9433 static struct metarray * 9434 metarray_find(struct rte_swx_pipeline *p, const char *name) 9435 { 9436 struct metarray *elem; 9437 9438 TAILQ_FOREACH(elem, &p->metarrays, node) 9439 if (!strcmp(elem->name, name)) 9440 return elem; 9441 9442 return NULL; 9443 } 9444 9445 static struct metarray * 9446 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 9447 { 9448 struct metarray *elem = NULL; 9449 9450 TAILQ_FOREACH(elem, &p->metarrays, node) 9451 if (elem->id == id) 9452 return elem; 9453 9454 return NULL; 9455 } 9456 9457 int 9458 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p, 9459 const char *name, 9460 uint32_t size) 9461 { 9462 struct metarray *m; 9463 9464 CHECK(p, EINVAL); 9465 9466 CHECK_NAME(name, EINVAL); 9467 CHECK(!metarray_find(p, name), EEXIST); 9468 9469 CHECK(size, EINVAL); 9470 size = rte_align32pow2(size); 9471 9472 /* Memory allocation. */ 9473 m = calloc(1, sizeof(struct metarray)); 9474 CHECK(m, ENOMEM); 9475 9476 /* Node initialization. */ 9477 strcpy(m->name, name); 9478 m->size = size; 9479 m->id = p->n_metarrays; 9480 9481 /* Node add to tailq. */ 9482 TAILQ_INSERT_TAIL(&p->metarrays, m, node); 9483 p->n_metarrays++; 9484 9485 return 0; 9486 } 9487 9488 struct meter_profile meter_profile_default = { 9489 .node = {0}, 9490 .name = "", 9491 .params = {0}, 9492 9493 .profile = { 9494 .cbs = 10000, 9495 .pbs = 10000, 9496 .cir_period = 1, 9497 .cir_bytes_per_period = 1, 9498 .pir_period = 1, 9499 .pir_bytes_per_period = 1, 9500 }, 9501 9502 .n_users = 0, 9503 }; 9504 9505 static void 9506 meter_init(struct meter *m) 9507 { 9508 memset(m, 0, sizeof(struct meter)); 9509 rte_meter_trtcm_config(&m->m, &meter_profile_default.profile); 9510 m->profile = &meter_profile_default; 9511 m->color_mask = RTE_COLOR_GREEN; 9512 9513 meter_profile_default.n_users++; 9514 } 9515 9516 static int 9517 metarray_build(struct rte_swx_pipeline *p) 9518 { 9519 struct metarray *m; 9520 9521 if (!p->n_metarrays) 9522 return 0; 9523 9524 p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime)); 9525 CHECK(p->metarray_runtime, ENOMEM); 9526 9527 TAILQ_FOREACH(m, &p->metarrays, node) { 9528 struct metarray_runtime *r = &p->metarray_runtime[m->id]; 9529 uint32_t i; 9530 9531 r->metarray = env_malloc(m->size * sizeof(struct meter), 9532 RTE_CACHE_LINE_SIZE, 9533 p->numa_node); 9534 CHECK(r->metarray, ENOMEM); 9535 9536 for (i = 0; i < m->size; i++) 9537 meter_init(&r->metarray[i]); 9538 9539 r->size_mask = m->size - 1; 9540 } 9541 9542 return 0; 9543 } 9544 9545 static void 9546 metarray_build_free(struct rte_swx_pipeline *p) 9547 { 9548 uint32_t i; 9549 9550 if (!p->metarray_runtime) 9551 return; 9552 9553 for (i = 0; i < p->n_metarrays; i++) { 9554 struct metarray *m = metarray_find_by_id(p, i); 9555 struct metarray_runtime *r = &p->metarray_runtime[i]; 9556 9557 env_free(r->metarray, m->size * sizeof(struct meter)); 9558 } 9559 9560 free(p->metarray_runtime); 9561 p->metarray_runtime = NULL; 9562 } 9563 9564 static void 9565 metarray_free(struct rte_swx_pipeline *p) 9566 { 9567 metarray_build_free(p); 9568 9569 /* Meter arrays. */ 9570 for ( ; ; ) { 9571 struct metarray *elem; 9572 9573 elem = TAILQ_FIRST(&p->metarrays); 9574 if (!elem) 9575 break; 9576 9577 TAILQ_REMOVE(&p->metarrays, elem, node); 9578 free(elem); 9579 } 9580 9581 /* Meter profiles. */ 9582 for ( ; ; ) { 9583 struct meter_profile *elem; 9584 9585 elem = TAILQ_FIRST(&p->meter_profiles); 9586 if (!elem) 9587 break; 9588 9589 TAILQ_REMOVE(&p->meter_profiles, elem, node); 9590 free(elem); 9591 } 9592 } 9593 9594 /* 9595 * Pipeline. 9596 */ 9597 void 9598 rte_swx_pipeline_free(struct rte_swx_pipeline *p) 9599 { 9600 void *lib; 9601 9602 if (!p) 9603 return; 9604 9605 lib = p->lib; 9606 9607 free(p->instruction_data); 9608 free(p->instructions); 9609 9610 metarray_free(p); 9611 regarray_free(p); 9612 table_state_free(p); 9613 learner_free(p); 9614 selector_free(p); 9615 table_free(p); 9616 action_free(p); 9617 instruction_table_free(p); 9618 metadata_free(p); 9619 header_free(p); 9620 hash_func_free(p); 9621 extern_func_free(p); 9622 extern_obj_free(p); 9623 mirroring_free(p); 9624 port_out_free(p); 9625 port_in_free(p); 9626 struct_free(p); 9627 9628 free(p); 9629 9630 if (lib) 9631 dlclose(lib); 9632 } 9633 9634 static int 9635 port_in_types_register(struct rte_swx_pipeline *p) 9636 { 9637 int status; 9638 9639 status = rte_swx_pipeline_port_in_type_register(p, 9640 "ethdev", 9641 &rte_swx_port_ethdev_reader_ops); 9642 if (status) 9643 return status; 9644 9645 status = rte_swx_pipeline_port_in_type_register(p, 9646 "ring", 9647 &rte_swx_port_ring_reader_ops); 9648 if (status) 9649 return status; 9650 9651 #ifdef RTE_PORT_PCAP 9652 status = rte_swx_pipeline_port_in_type_register(p, 9653 "source", 9654 &rte_swx_port_source_ops); 9655 if (status) 9656 return status; 9657 #endif 9658 9659 status = rte_swx_pipeline_port_in_type_register(p, 9660 "fd", 9661 &rte_swx_port_fd_reader_ops); 9662 if (status) 9663 return status; 9664 9665 return 0; 9666 } 9667 9668 static int 9669 port_out_types_register(struct rte_swx_pipeline *p) 9670 { 9671 int status; 9672 9673 status = rte_swx_pipeline_port_out_type_register(p, 9674 "ethdev", 9675 &rte_swx_port_ethdev_writer_ops); 9676 if (status) 9677 return status; 9678 9679 status = rte_swx_pipeline_port_out_type_register(p, 9680 "ring", 9681 &rte_swx_port_ring_writer_ops); 9682 if (status) 9683 return status; 9684 9685 status = rte_swx_pipeline_port_out_type_register(p, 9686 "sink", 9687 &rte_swx_port_sink_ops); 9688 if (status) 9689 return status; 9690 9691 status = rte_swx_pipeline_port_out_type_register(p, 9692 "fd", 9693 &rte_swx_port_fd_writer_ops); 9694 if (status) 9695 return status; 9696 9697 return 0; 9698 } 9699 9700 static int 9701 table_types_register(struct rte_swx_pipeline *p) 9702 { 9703 int status; 9704 9705 status = rte_swx_pipeline_table_type_register(p, 9706 "exact", 9707 RTE_SWX_TABLE_MATCH_EXACT, 9708 &rte_swx_table_exact_match_ops); 9709 if (status) 9710 return status; 9711 9712 status = rte_swx_pipeline_table_type_register(p, 9713 "wildcard", 9714 RTE_SWX_TABLE_MATCH_WILDCARD, 9715 &rte_swx_table_wildcard_match_ops); 9716 if (status) 9717 return status; 9718 9719 return 0; 9720 } 9721 9722 static int 9723 hash_funcs_register(struct rte_swx_pipeline *p) 9724 { 9725 int status; 9726 9727 status = rte_swx_pipeline_hash_func_register(p, "jhash", rte_jhash); 9728 if (status) 9729 return status; 9730 9731 status = rte_swx_pipeline_hash_func_register(p, "crc32", rte_hash_crc); 9732 if (status) 9733 return status; 9734 9735 return 0; 9736 } 9737 9738 int 9739 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) 9740 { 9741 struct rte_swx_pipeline *pipeline = NULL; 9742 int status = 0; 9743 9744 /* Check input parameters. */ 9745 CHECK(p, EINVAL); 9746 9747 /* Memory allocation. */ 9748 pipeline = calloc(1, sizeof(struct rte_swx_pipeline)); 9749 if (!pipeline) { 9750 status = -ENOMEM; 9751 goto error; 9752 } 9753 9754 /* Initialization. */ 9755 TAILQ_INIT(&pipeline->struct_types); 9756 TAILQ_INIT(&pipeline->port_in_types); 9757 TAILQ_INIT(&pipeline->ports_in); 9758 TAILQ_INIT(&pipeline->port_out_types); 9759 TAILQ_INIT(&pipeline->ports_out); 9760 TAILQ_INIT(&pipeline->extern_types); 9761 TAILQ_INIT(&pipeline->extern_objs); 9762 TAILQ_INIT(&pipeline->extern_funcs); 9763 TAILQ_INIT(&pipeline->hash_funcs); 9764 TAILQ_INIT(&pipeline->headers); 9765 TAILQ_INIT(&pipeline->actions); 9766 TAILQ_INIT(&pipeline->table_types); 9767 TAILQ_INIT(&pipeline->tables); 9768 TAILQ_INIT(&pipeline->selectors); 9769 TAILQ_INIT(&pipeline->learners); 9770 TAILQ_INIT(&pipeline->regarrays); 9771 TAILQ_INIT(&pipeline->meter_profiles); 9772 TAILQ_INIT(&pipeline->metarrays); 9773 9774 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */ 9775 pipeline->numa_node = numa_node; 9776 9777 status = port_in_types_register(pipeline); 9778 if (status) 9779 goto error; 9780 9781 status = port_out_types_register(pipeline); 9782 if (status) 9783 goto error; 9784 9785 status = table_types_register(pipeline); 9786 if (status) 9787 goto error; 9788 9789 status = hash_funcs_register(pipeline); 9790 if (status) 9791 goto error; 9792 9793 *p = pipeline; 9794 return 0; 9795 9796 error: 9797 rte_swx_pipeline_free(pipeline); 9798 return status; 9799 } 9800 9801 int 9802 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p, 9803 const char **instructions, 9804 uint32_t n_instructions) 9805 { 9806 int err; 9807 uint32_t i; 9808 9809 err = instruction_config(p, NULL, instructions, n_instructions); 9810 if (err) 9811 return err; 9812 9813 /* Thread instruction pointer reset. */ 9814 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9815 struct thread *t = &p->threads[i]; 9816 9817 thread_ip_reset(p, t); 9818 } 9819 9820 return 0; 9821 } 9822 9823 static int 9824 pipeline_compile(struct rte_swx_pipeline *p); 9825 9826 int 9827 rte_swx_pipeline_build(struct rte_swx_pipeline *p) 9828 { 9829 struct rte_swx_port_sink_params drop_port_params = { 9830 .file_name = NULL, 9831 }; 9832 int status; 9833 9834 CHECK(p, EINVAL); 9835 CHECK(p->build_done == 0, EEXIST); 9836 9837 status = port_in_build(p); 9838 if (status) 9839 goto error; 9840 9841 /* Drop port. */ 9842 status = rte_swx_pipeline_port_out_config(p, 9843 p->n_ports_out, 9844 "sink", 9845 &drop_port_params); 9846 if (status) 9847 goto error; 9848 9849 status = port_out_build(p); 9850 if (status) 9851 goto error; 9852 9853 status = mirroring_build(p); 9854 if (status) 9855 goto error; 9856 9857 status = struct_build(p); 9858 if (status) 9859 goto error; 9860 9861 status = extern_obj_build(p); 9862 if (status) 9863 goto error; 9864 9865 status = extern_func_build(p); 9866 if (status) 9867 goto error; 9868 9869 status = hash_func_build(p); 9870 if (status) 9871 goto error; 9872 9873 status = header_build(p); 9874 if (status) 9875 goto error; 9876 9877 status = metadata_build(p); 9878 if (status) 9879 goto error; 9880 9881 status = instruction_table_build(p); 9882 if (status) 9883 goto error; 9884 9885 status = action_build(p); 9886 if (status) 9887 goto error; 9888 9889 status = table_build(p); 9890 if (status) 9891 goto error; 9892 9893 status = selector_build(p); 9894 if (status) 9895 goto error; 9896 9897 status = learner_build(p); 9898 if (status) 9899 goto error; 9900 9901 status = table_state_build(p); 9902 if (status) 9903 goto error; 9904 9905 status = regarray_build(p); 9906 if (status) 9907 goto error; 9908 9909 status = metarray_build(p); 9910 if (status) 9911 goto error; 9912 9913 p->build_done = 1; 9914 9915 pipeline_compile(p); 9916 9917 return 0; 9918 9919 error: 9920 metarray_build_free(p); 9921 regarray_build_free(p); 9922 table_state_build_free(p); 9923 learner_build_free(p); 9924 selector_build_free(p); 9925 table_build_free(p); 9926 action_build_free(p); 9927 instruction_table_build_free(p); 9928 metadata_build_free(p); 9929 header_build_free(p); 9930 hash_func_build_free(p); 9931 extern_func_build_free(p); 9932 extern_obj_build_free(p); 9933 mirroring_build_free(p); 9934 port_out_build_free(p); 9935 port_in_build_free(p); 9936 struct_build_free(p); 9937 9938 return status; 9939 } 9940 9941 void 9942 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions) 9943 { 9944 uint32_t i; 9945 9946 for (i = 0; i < n_instructions; i++) 9947 instr_exec(p); 9948 } 9949 9950 void 9951 rte_swx_pipeline_flush(struct rte_swx_pipeline *p) 9952 { 9953 uint32_t i; 9954 9955 for (i = 0; i < p->n_ports_out; i++) { 9956 struct port_out_runtime *port = &p->out[i]; 9957 9958 if (port->flush) 9959 port->flush(port->obj); 9960 } 9961 } 9962 9963 /* 9964 * Control. 9965 */ 9966 int 9967 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, 9968 struct rte_swx_ctl_pipeline_info *pipeline) 9969 { 9970 struct action *action; 9971 struct table *table; 9972 uint32_t n_actions = 0, n_tables = 0; 9973 9974 if (!p || !pipeline) 9975 return -EINVAL; 9976 9977 TAILQ_FOREACH(action, &p->actions, node) 9978 n_actions++; 9979 9980 TAILQ_FOREACH(table, &p->tables, node) 9981 n_tables++; 9982 9983 pipeline->n_ports_in = p->n_ports_in; 9984 pipeline->n_ports_out = p->n_ports_out; 9985 pipeline->n_mirroring_slots = p->n_mirroring_slots; 9986 pipeline->n_mirroring_sessions = p->n_mirroring_sessions; 9987 pipeline->n_actions = n_actions; 9988 pipeline->n_tables = n_tables; 9989 pipeline->n_selectors = p->n_selectors; 9990 pipeline->n_learners = p->n_learners; 9991 pipeline->n_regarrays = p->n_regarrays; 9992 pipeline->n_metarrays = p->n_metarrays; 9993 9994 return 0; 9995 } 9996 9997 int 9998 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node) 9999 { 10000 if (!p || !numa_node) 10001 return -EINVAL; 10002 10003 *numa_node = p->numa_node; 10004 return 0; 10005 } 10006 10007 int 10008 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, 10009 uint32_t action_id, 10010 struct rte_swx_ctl_action_info *action) 10011 { 10012 struct action *a = NULL; 10013 10014 if (!p || (action_id >= p->n_actions) || !action) 10015 return -EINVAL; 10016 10017 a = action_find_by_id(p, action_id); 10018 if (!a) 10019 return -EINVAL; 10020 10021 strcpy(action->name, a->name); 10022 action->n_args = a->st ? a->st->n_fields : 0; 10023 return 0; 10024 } 10025 10026 int 10027 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, 10028 uint32_t action_id, 10029 uint32_t action_arg_id, 10030 struct rte_swx_ctl_action_arg_info *action_arg) 10031 { 10032 struct action *a = NULL; 10033 struct field *arg = NULL; 10034 10035 if (!p || (action_id >= p->n_actions) || !action_arg) 10036 return -EINVAL; 10037 10038 a = action_find_by_id(p, action_id); 10039 if (!a || !a->st || (action_arg_id >= a->st->n_fields)) 10040 return -EINVAL; 10041 10042 arg = &a->st->fields[action_arg_id]; 10043 strcpy(action_arg->name, arg->name); 10044 action_arg->n_bits = arg->n_bits; 10045 action_arg->is_network_byte_order = a->args_endianness[action_arg_id]; 10046 10047 return 0; 10048 } 10049 10050 int 10051 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, 10052 uint32_t table_id, 10053 struct rte_swx_ctl_table_info *table) 10054 { 10055 struct table *t = NULL; 10056 10057 if (!p || !table) 10058 return -EINVAL; 10059 10060 t = table_find_by_id(p, table_id); 10061 if (!t) 10062 return -EINVAL; 10063 10064 strcpy(table->name, t->name); 10065 strcpy(table->args, t->args); 10066 table->n_match_fields = t->n_fields; 10067 table->n_actions = t->n_actions; 10068 table->default_action_is_const = t->default_action_is_const; 10069 table->size = t->size; 10070 return 0; 10071 } 10072 10073 int 10074 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, 10075 uint32_t table_id, 10076 uint32_t match_field_id, 10077 struct rte_swx_ctl_table_match_field_info *match_field) 10078 { 10079 struct table *t; 10080 struct match_field *f; 10081 10082 if (!p || (table_id >= p->n_tables) || !match_field) 10083 return -EINVAL; 10084 10085 t = table_find_by_id(p, table_id); 10086 if (!t || (match_field_id >= t->n_fields)) 10087 return -EINVAL; 10088 10089 f = &t->fields[match_field_id]; 10090 match_field->match_type = f->match_type; 10091 match_field->is_header = t->header ? 1 : 0; 10092 match_field->n_bits = f->field->n_bits; 10093 match_field->offset = f->field->offset; 10094 10095 return 0; 10096 } 10097 10098 int 10099 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, 10100 uint32_t table_id, 10101 uint32_t table_action_id, 10102 struct rte_swx_ctl_table_action_info *table_action) 10103 { 10104 struct table *t; 10105 10106 if (!p || (table_id >= p->n_tables) || !table_action) 10107 return -EINVAL; 10108 10109 t = table_find_by_id(p, table_id); 10110 if (!t || (table_action_id >= t->n_actions)) 10111 return -EINVAL; 10112 10113 table_action->action_id = t->actions[table_action_id]->id; 10114 10115 table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; 10116 table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; 10117 10118 return 0; 10119 } 10120 10121 int 10122 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, 10123 uint32_t table_id, 10124 struct rte_swx_table_ops *table_ops, 10125 int *is_stub) 10126 { 10127 struct table *t; 10128 10129 if (!p || (table_id >= p->n_tables)) 10130 return -EINVAL; 10131 10132 t = table_find_by_id(p, table_id); 10133 if (!t) 10134 return -EINVAL; 10135 10136 if (t->type) { 10137 if (table_ops) 10138 memcpy(table_ops, &t->type->ops, sizeof(*table_ops)); 10139 *is_stub = 0; 10140 } else { 10141 *is_stub = 1; 10142 } 10143 10144 return 0; 10145 } 10146 10147 int 10148 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p, 10149 uint32_t selector_id, 10150 struct rte_swx_ctl_selector_info *selector) 10151 { 10152 struct selector *s = NULL; 10153 10154 if (!p || !selector) 10155 return -EINVAL; 10156 10157 s = selector_find_by_id(p, selector_id); 10158 if (!s) 10159 return -EINVAL; 10160 10161 strcpy(selector->name, s->name); 10162 10163 selector->n_selector_fields = s->n_selector_fields; 10164 selector->n_groups_max = s->n_groups_max; 10165 selector->n_members_per_group_max = s->n_members_per_group_max; 10166 10167 return 0; 10168 } 10169 10170 int 10171 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p, 10172 uint32_t selector_id, 10173 struct rte_swx_ctl_table_match_field_info *field) 10174 { 10175 struct selector *s; 10176 10177 if (!p || (selector_id >= p->n_selectors) || !field) 10178 return -EINVAL; 10179 10180 s = selector_find_by_id(p, selector_id); 10181 if (!s) 10182 return -EINVAL; 10183 10184 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10185 field->is_header = 0; 10186 field->n_bits = s->group_id_field->n_bits; 10187 field->offset = s->group_id_field->offset; 10188 10189 return 0; 10190 } 10191 10192 int 10193 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p, 10194 uint32_t selector_id, 10195 uint32_t selector_field_id, 10196 struct rte_swx_ctl_table_match_field_info *field) 10197 { 10198 struct selector *s; 10199 struct field *f; 10200 10201 if (!p || (selector_id >= p->n_selectors) || !field) 10202 return -EINVAL; 10203 10204 s = selector_find_by_id(p, selector_id); 10205 if (!s || (selector_field_id >= s->n_selector_fields)) 10206 return -EINVAL; 10207 10208 f = s->selector_fields[selector_field_id]; 10209 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10210 field->is_header = s->selector_header ? 1 : 0; 10211 field->n_bits = f->n_bits; 10212 field->offset = f->offset; 10213 10214 return 0; 10215 } 10216 10217 int 10218 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p, 10219 uint32_t selector_id, 10220 struct rte_swx_ctl_table_match_field_info *field) 10221 { 10222 struct selector *s; 10223 10224 if (!p || (selector_id >= p->n_selectors) || !field) 10225 return -EINVAL; 10226 10227 s = selector_find_by_id(p, selector_id); 10228 if (!s) 10229 return -EINVAL; 10230 10231 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10232 field->is_header = 0; 10233 field->n_bits = s->member_id_field->n_bits; 10234 field->offset = s->member_id_field->offset; 10235 10236 return 0; 10237 } 10238 10239 int 10240 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p, 10241 uint32_t learner_id, 10242 struct rte_swx_ctl_learner_info *learner) 10243 { 10244 struct learner *l = NULL; 10245 10246 if (!p || !learner) 10247 return -EINVAL; 10248 10249 l = learner_find_by_id(p, learner_id); 10250 if (!l) 10251 return -EINVAL; 10252 10253 strcpy(learner->name, l->name); 10254 10255 learner->n_match_fields = l->n_fields; 10256 learner->n_actions = l->n_actions; 10257 learner->default_action_is_const = l->default_action_is_const; 10258 learner->size = l->size; 10259 learner->n_key_timeouts = l->n_timeouts; 10260 10261 return 0; 10262 } 10263 10264 int 10265 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p, 10266 uint32_t learner_id, 10267 uint32_t match_field_id, 10268 struct rte_swx_ctl_table_match_field_info *match_field) 10269 { 10270 struct learner *l; 10271 struct field *f; 10272 10273 if (!p || (learner_id >= p->n_learners) || !match_field) 10274 return -EINVAL; 10275 10276 l = learner_find_by_id(p, learner_id); 10277 if (!l || (match_field_id >= l->n_fields)) 10278 return -EINVAL; 10279 10280 f = l->fields[match_field_id]; 10281 match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10282 match_field->is_header = l->header ? 1 : 0; 10283 match_field->n_bits = f->n_bits; 10284 match_field->offset = f->offset; 10285 10286 return 0; 10287 } 10288 10289 int 10290 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, 10291 uint32_t learner_id, 10292 uint32_t learner_action_id, 10293 struct rte_swx_ctl_table_action_info *learner_action) 10294 { 10295 struct learner *l; 10296 10297 if (!p || (learner_id >= p->n_learners) || !learner_action) 10298 return -EINVAL; 10299 10300 l = learner_find_by_id(p, learner_id); 10301 if (!l || (learner_action_id >= l->n_actions)) 10302 return -EINVAL; 10303 10304 learner_action->action_id = l->actions[learner_action_id]->id; 10305 10306 learner_action->action_is_for_table_entries = 10307 l->action_is_for_table_entries[learner_action_id]; 10308 10309 learner_action->action_is_for_default_entry = 10310 l->action_is_for_default_entry[learner_action_id]; 10311 10312 return 0; 10313 } 10314 10315 int 10316 rte_swx_ctl_pipeline_learner_timeout_get(struct rte_swx_pipeline *p, 10317 uint32_t learner_id, 10318 uint32_t timeout_id, 10319 uint32_t *timeout) 10320 { 10321 struct learner *l; 10322 10323 if (!p || (learner_id >= p->n_learners) || !timeout) 10324 return -EINVAL; 10325 10326 l = learner_find_by_id(p, learner_id); 10327 if (!l || (timeout_id >= l->n_timeouts)) 10328 return -EINVAL; 10329 10330 *timeout = l->timeout[timeout_id]; 10331 return 0; 10332 } 10333 10334 int 10335 rte_swx_ctl_pipeline_learner_timeout_set(struct rte_swx_pipeline *p, 10336 uint32_t learner_id, 10337 uint32_t timeout_id, 10338 uint32_t timeout) 10339 { 10340 struct learner *l; 10341 struct rte_swx_table_state *ts; 10342 int status; 10343 10344 if (!p || (learner_id >= p->n_learners) || !timeout) 10345 return -EINVAL; 10346 10347 l = learner_find_by_id(p, learner_id); 10348 if (!l || (timeout_id >= l->n_timeouts)) 10349 return -EINVAL; 10350 10351 if (!p->build_done) 10352 return -EINVAL; 10353 10354 ts = &p->table_state[p->n_tables + p->n_selectors + l->id]; 10355 10356 status = rte_swx_table_learner_timeout_update(ts->obj, timeout_id, timeout); 10357 if (status) 10358 return -EINVAL; 10359 10360 l->timeout[timeout_id] = timeout; 10361 10362 return 0; 10363 } 10364 10365 int 10366 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p, 10367 struct rte_swx_table_state **table_state) 10368 { 10369 if (!p || !table_state || !p->build_done) 10370 return -EINVAL; 10371 10372 *table_state = p->table_state; 10373 return 0; 10374 } 10375 10376 int 10377 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p, 10378 struct rte_swx_table_state *table_state) 10379 { 10380 if (!p || !table_state || !p->build_done) 10381 return -EINVAL; 10382 10383 p->table_state = table_state; 10384 return 0; 10385 } 10386 10387 int 10388 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, 10389 uint32_t port_id, 10390 struct rte_swx_port_in_stats *stats) 10391 { 10392 struct port_in *port; 10393 10394 if (!p || !stats) 10395 return -EINVAL; 10396 10397 port = port_in_find(p, port_id); 10398 if (!port) 10399 return -EINVAL; 10400 10401 port->type->ops.stats_read(port->obj, stats); 10402 return 0; 10403 } 10404 10405 int 10406 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, 10407 uint32_t port_id, 10408 struct rte_swx_port_out_stats *stats) 10409 { 10410 struct port_out *port; 10411 10412 if (!p || !stats) 10413 return -EINVAL; 10414 10415 port = port_out_find(p, port_id); 10416 if (!port) 10417 return -EINVAL; 10418 10419 port->type->ops.stats_read(port->obj, stats); 10420 return 0; 10421 } 10422 10423 int 10424 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, 10425 const char *table_name, 10426 struct rte_swx_table_stats *stats) 10427 { 10428 struct table *table; 10429 struct table_statistics *table_stats; 10430 10431 if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action) 10432 return -EINVAL; 10433 10434 table = table_find(p, table_name); 10435 if (!table) 10436 return -EINVAL; 10437 10438 table_stats = &p->table_stats[table->id]; 10439 10440 memcpy(stats->n_pkts_action, 10441 table_stats->n_pkts_action, 10442 p->n_actions * sizeof(uint64_t)); 10443 10444 stats->n_pkts_hit = table_stats->n_pkts_hit[1]; 10445 stats->n_pkts_miss = table_stats->n_pkts_hit[0]; 10446 10447 return 0; 10448 } 10449 10450 int 10451 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p, 10452 const char *selector_name, 10453 struct rte_swx_pipeline_selector_stats *stats) 10454 { 10455 struct selector *s; 10456 10457 if (!p || !selector_name || !selector_name[0] || !stats) 10458 return -EINVAL; 10459 10460 s = selector_find(p, selector_name); 10461 if (!s) 10462 return -EINVAL; 10463 10464 stats->n_pkts = p->selector_stats[s->id].n_pkts; 10465 10466 return 0; 10467 } 10468 10469 int 10470 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, 10471 const char *learner_name, 10472 struct rte_swx_learner_stats *stats) 10473 { 10474 struct learner *l; 10475 struct learner_statistics *learner_stats; 10476 10477 if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action) 10478 return -EINVAL; 10479 10480 l = learner_find(p, learner_name); 10481 if (!l) 10482 return -EINVAL; 10483 10484 learner_stats = &p->learner_stats[l->id]; 10485 10486 memcpy(stats->n_pkts_action, 10487 learner_stats->n_pkts_action, 10488 p->n_actions * sizeof(uint64_t)); 10489 10490 stats->n_pkts_hit = learner_stats->n_pkts_hit[1]; 10491 stats->n_pkts_miss = learner_stats->n_pkts_hit[0]; 10492 10493 stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0]; 10494 stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1]; 10495 10496 stats->n_pkts_rearm = learner_stats->n_pkts_rearm; 10497 stats->n_pkts_forget = learner_stats->n_pkts_forget; 10498 10499 return 0; 10500 } 10501 10502 int 10503 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p, 10504 uint32_t regarray_id, 10505 struct rte_swx_ctl_regarray_info *regarray) 10506 { 10507 struct regarray *r; 10508 10509 if (!p || !regarray) 10510 return -EINVAL; 10511 10512 r = regarray_find_by_id(p, regarray_id); 10513 if (!r) 10514 return -EINVAL; 10515 10516 strcpy(regarray->name, r->name); 10517 regarray->size = r->size; 10518 return 0; 10519 } 10520 10521 int 10522 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p, 10523 const char *regarray_name, 10524 uint32_t regarray_index, 10525 uint64_t *value) 10526 { 10527 struct regarray *regarray; 10528 struct regarray_runtime *r; 10529 10530 if (!p || !regarray_name || !value) 10531 return -EINVAL; 10532 10533 regarray = regarray_find(p, regarray_name); 10534 if (!regarray || (regarray_index >= regarray->size)) 10535 return -EINVAL; 10536 10537 r = &p->regarray_runtime[regarray->id]; 10538 *value = r->regarray[regarray_index]; 10539 return 0; 10540 } 10541 10542 int 10543 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p, 10544 const char *regarray_name, 10545 uint32_t regarray_index, 10546 uint64_t value) 10547 { 10548 struct regarray *regarray; 10549 struct regarray_runtime *r; 10550 10551 if (!p || !regarray_name) 10552 return -EINVAL; 10553 10554 regarray = regarray_find(p, regarray_name); 10555 if (!regarray || (regarray_index >= regarray->size)) 10556 return -EINVAL; 10557 10558 r = &p->regarray_runtime[regarray->id]; 10559 r->regarray[regarray_index] = value; 10560 return 0; 10561 } 10562 10563 int 10564 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p, 10565 uint32_t metarray_id, 10566 struct rte_swx_ctl_metarray_info *metarray) 10567 { 10568 struct metarray *m; 10569 10570 if (!p || !metarray) 10571 return -EINVAL; 10572 10573 m = metarray_find_by_id(p, metarray_id); 10574 if (!m) 10575 return -EINVAL; 10576 10577 strcpy(metarray->name, m->name); 10578 metarray->size = m->size; 10579 return 0; 10580 } 10581 10582 int 10583 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p, 10584 const char *name, 10585 struct rte_meter_trtcm_params *params) 10586 { 10587 struct meter_profile *mp; 10588 int status; 10589 10590 CHECK(p, EINVAL); 10591 CHECK_NAME(name, EINVAL); 10592 CHECK(params, EINVAL); 10593 CHECK(!meter_profile_find(p, name), EEXIST); 10594 10595 /* Node allocation. */ 10596 mp = calloc(1, sizeof(struct meter_profile)); 10597 CHECK(mp, ENOMEM); 10598 10599 /* Node initialization. */ 10600 strcpy(mp->name, name); 10601 memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params)); 10602 status = rte_meter_trtcm_profile_config(&mp->profile, params); 10603 if (status) { 10604 free(mp); 10605 CHECK(0, EINVAL); 10606 } 10607 10608 /* Node add to tailq. */ 10609 TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node); 10610 10611 return 0; 10612 } 10613 10614 int 10615 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p, 10616 const char *name) 10617 { 10618 struct meter_profile *mp; 10619 10620 CHECK(p, EINVAL); 10621 CHECK_NAME(name, EINVAL); 10622 10623 mp = meter_profile_find(p, name); 10624 CHECK(mp, EINVAL); 10625 CHECK(!mp->n_users, EBUSY); 10626 10627 /* Remove node from tailq. */ 10628 TAILQ_REMOVE(&p->meter_profiles, mp, node); 10629 free(mp); 10630 10631 return 0; 10632 } 10633 10634 int 10635 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p, 10636 const char *metarray_name, 10637 uint32_t metarray_index) 10638 { 10639 struct meter_profile *mp_old; 10640 struct metarray *metarray; 10641 struct metarray_runtime *metarray_runtime; 10642 struct meter *m; 10643 10644 CHECK(p, EINVAL); 10645 CHECK_NAME(metarray_name, EINVAL); 10646 10647 metarray = metarray_find(p, metarray_name); 10648 CHECK(metarray, EINVAL); 10649 CHECK(metarray_index < metarray->size, EINVAL); 10650 10651 metarray_runtime = &p->metarray_runtime[metarray->id]; 10652 m = &metarray_runtime->metarray[metarray_index]; 10653 mp_old = m->profile; 10654 10655 meter_init(m); 10656 10657 mp_old->n_users--; 10658 10659 return 0; 10660 } 10661 10662 int 10663 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p, 10664 const char *metarray_name, 10665 uint32_t metarray_index, 10666 const char *profile_name) 10667 { 10668 struct meter_profile *mp, *mp_old; 10669 struct metarray *metarray; 10670 struct metarray_runtime *metarray_runtime; 10671 struct meter *m; 10672 10673 CHECK(p, EINVAL); 10674 CHECK_NAME(metarray_name, EINVAL); 10675 10676 metarray = metarray_find(p, metarray_name); 10677 CHECK(metarray, EINVAL); 10678 CHECK(metarray_index < metarray->size, EINVAL); 10679 10680 mp = meter_profile_find(p, profile_name); 10681 CHECK(mp, EINVAL); 10682 10683 metarray_runtime = &p->metarray_runtime[metarray->id]; 10684 m = &metarray_runtime->metarray[metarray_index]; 10685 mp_old = m->profile; 10686 10687 memset(m, 0, sizeof(struct meter)); 10688 rte_meter_trtcm_config(&m->m, &mp->profile); 10689 m->profile = mp; 10690 m->color_mask = RTE_COLORS; 10691 10692 mp->n_users++; 10693 mp_old->n_users--; 10694 10695 return 0; 10696 } 10697 10698 int 10699 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, 10700 const char *metarray_name, 10701 uint32_t metarray_index, 10702 struct rte_swx_ctl_meter_stats *stats) 10703 { 10704 struct metarray *metarray; 10705 struct metarray_runtime *metarray_runtime; 10706 struct meter *m; 10707 10708 CHECK(p, EINVAL); 10709 CHECK_NAME(metarray_name, EINVAL); 10710 10711 metarray = metarray_find(p, metarray_name); 10712 CHECK(metarray, EINVAL); 10713 CHECK(metarray_index < metarray->size, EINVAL); 10714 10715 CHECK(stats, EINVAL); 10716 10717 metarray_runtime = &p->metarray_runtime[metarray->id]; 10718 m = &metarray_runtime->metarray[metarray_index]; 10719 10720 memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts)); 10721 memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes)); 10722 10723 return 0; 10724 } 10725 10726 int 10727 rte_swx_ctl_pipeline_mirroring_session_set(struct rte_swx_pipeline *p, 10728 uint32_t session_id, 10729 struct rte_swx_pipeline_mirroring_session_params *params) 10730 { 10731 struct mirroring_session *s; 10732 10733 CHECK(p, EINVAL); 10734 CHECK(p->build_done, EEXIST); 10735 CHECK(session_id < p->n_mirroring_sessions, EINVAL); 10736 CHECK(params, EINVAL); 10737 CHECK(params->port_id < p->n_ports_out, EINVAL); 10738 10739 s = &p->mirroring_sessions[session_id]; 10740 s->port_id = params->port_id; 10741 s->fast_clone = params->fast_clone; 10742 s->truncation_length = params->truncation_length ? params->truncation_length : UINT32_MAX; 10743 10744 return 0; 10745 } 10746 10747 /* 10748 * Pipeline compilation. 10749 */ 10750 static const char * 10751 instr_type_to_name(struct instruction *instr) 10752 { 10753 switch (instr->type) { 10754 case INSTR_RX: return "INSTR_RX"; 10755 10756 case INSTR_TX: return "INSTR_TX"; 10757 case INSTR_TX_I: return "INSTR_TX_I"; 10758 case INSTR_DROP: return "INSTR_DROP"; 10759 case INSTR_MIRROR: return "INSTR_MIRROR"; 10760 case INSTR_RECIRCULATE: return "INSTR_RECIRCULATE"; 10761 case INSTR_RECIRCID: return "INSTR_RECIRCID"; 10762 10763 case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; 10764 case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; 10765 case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3"; 10766 case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4"; 10767 case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5"; 10768 case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6"; 10769 case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7"; 10770 case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8"; 10771 10772 case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M"; 10773 10774 case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD"; 10775 10776 case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT"; 10777 case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX"; 10778 case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX"; 10779 case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX"; 10780 case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX"; 10781 case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX"; 10782 case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX"; 10783 case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX"; 10784 case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX"; 10785 10786 case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE"; 10787 case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE"; 10788 10789 case INSTR_MOV: return "INSTR_MOV"; 10790 case INSTR_MOV_MH: return "INSTR_MOV_MH"; 10791 case INSTR_MOV_HM: return "INSTR_MOV_HM"; 10792 case INSTR_MOV_HH: return "INSTR_MOV_HH"; 10793 case INSTR_MOV_I: return "INSTR_MOV_I"; 10794 10795 case INSTR_DMA_HT: return "INSTR_DMA_HT"; 10796 case INSTR_DMA_HT2: return "INSTR_DMA_HT2"; 10797 case INSTR_DMA_HT3: return "INSTR_DMA_HT3"; 10798 case INSTR_DMA_HT4: return "INSTR_DMA_HT4"; 10799 case INSTR_DMA_HT5: return "INSTR_DMA_HT5"; 10800 case INSTR_DMA_HT6: return "INSTR_DMA_HT6"; 10801 case INSTR_DMA_HT7: return "INSTR_DMA_HT7"; 10802 case INSTR_DMA_HT8: return "INSTR_DMA_HT8"; 10803 10804 case INSTR_ALU_ADD: return "INSTR_ALU_ADD"; 10805 case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH"; 10806 case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM"; 10807 case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH"; 10808 case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI"; 10809 case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI"; 10810 10811 case INSTR_ALU_SUB: return "INSTR_ALU_SUB"; 10812 case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH"; 10813 case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM"; 10814 case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH"; 10815 case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI"; 10816 case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI"; 10817 10818 case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD"; 10819 case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20"; 10820 case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT"; 10821 case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD"; 10822 10823 case INSTR_ALU_AND: return "INSTR_ALU_AND"; 10824 case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH"; 10825 case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM"; 10826 case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH"; 10827 case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I"; 10828 10829 case INSTR_ALU_OR: return "INSTR_ALU_OR"; 10830 case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH"; 10831 case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM"; 10832 case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH"; 10833 case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I"; 10834 10835 case INSTR_ALU_XOR: return "INSTR_ALU_XOR"; 10836 case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH"; 10837 case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM"; 10838 case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH"; 10839 case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I"; 10840 10841 case INSTR_ALU_SHL: return "INSTR_ALU_SHL"; 10842 case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH"; 10843 case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM"; 10844 case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH"; 10845 case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI"; 10846 case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI"; 10847 10848 case INSTR_ALU_SHR: return "INSTR_ALU_SHR"; 10849 case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH"; 10850 case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM"; 10851 case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH"; 10852 case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI"; 10853 case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI"; 10854 10855 case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH"; 10856 case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM"; 10857 case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI"; 10858 10859 case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH"; 10860 case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM"; 10861 case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI"; 10862 case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH"; 10863 case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM"; 10864 case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI"; 10865 10866 case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH"; 10867 case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM"; 10868 case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI"; 10869 case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH"; 10870 case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM"; 10871 case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI"; 10872 case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH"; 10873 case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM"; 10874 case INSTR_REGWR_RII: return "INSTR_REGWR_RII"; 10875 10876 case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH"; 10877 case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM"; 10878 case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI"; 10879 case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH"; 10880 case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM"; 10881 case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI"; 10882 case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH"; 10883 case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM"; 10884 case INSTR_REGADD_RII: return "INSTR_REGADD_RII"; 10885 10886 case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H"; 10887 case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M"; 10888 case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I"; 10889 10890 case INSTR_METER_HHM: return "INSTR_METER_HHM"; 10891 case INSTR_METER_HHI: return "INSTR_METER_HHI"; 10892 case INSTR_METER_HMM: return "INSTR_METER_HMM"; 10893 case INSTR_METER_HMI: return "INSTR_METER_HMI"; 10894 case INSTR_METER_MHM: return "INSTR_METER_MHM"; 10895 case INSTR_METER_MHI: return "INSTR_METER_MHI"; 10896 case INSTR_METER_MMM: return "INSTR_METER_MMM"; 10897 case INSTR_METER_MMI: return "INSTR_METER_MMI"; 10898 case INSTR_METER_IHM: return "INSTR_METER_IHM"; 10899 case INSTR_METER_IHI: return "INSTR_METER_IHI"; 10900 case INSTR_METER_IMM: return "INSTR_METER_IMM"; 10901 case INSTR_METER_IMI: return "INSTR_METER_IMI"; 10902 10903 case INSTR_TABLE: return "INSTR_TABLE"; 10904 case INSTR_TABLE_AF: return "INSTR_TABLE_AF"; 10905 case INSTR_SELECTOR: return "INSTR_SELECTOR"; 10906 case INSTR_LEARNER: return "INSTR_LEARNER"; 10907 case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; 10908 10909 case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; 10910 case INSTR_LEARNER_REARM: return "INSTR_LEARNER_REARM"; 10911 case INSTR_LEARNER_REARM_NEW: return "INSTR_LEARNER_REARM_NEW"; 10912 case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; 10913 10914 case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; 10915 case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC"; 10916 case INSTR_HASH_FUNC: return "INSTR_HASH_FUNC"; 10917 10918 case INSTR_JMP: return "INSTR_JMP"; 10919 case INSTR_JMP_VALID: return "INSTR_JMP_VALID"; 10920 case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID"; 10921 case INSTR_JMP_HIT: return "INSTR_JMP_HIT"; 10922 case INSTR_JMP_MISS: return "INSTR_JMP_MISS"; 10923 case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT"; 10924 case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS"; 10925 case INSTR_JMP_EQ: return "INSTR_JMP_EQ"; 10926 case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH"; 10927 case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM"; 10928 case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH"; 10929 case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I"; 10930 case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ"; 10931 case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH"; 10932 case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM"; 10933 case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH"; 10934 case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I"; 10935 case INSTR_JMP_LT: return "INSTR_JMP_LT"; 10936 case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH"; 10937 case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM"; 10938 case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH"; 10939 case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI"; 10940 case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI"; 10941 case INSTR_JMP_GT: return "INSTR_JMP_GT"; 10942 case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH"; 10943 case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM"; 10944 case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH"; 10945 case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI"; 10946 case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI"; 10947 10948 case INSTR_RETURN: return "INSTR_RETURN"; 10949 10950 default: return "INSTR_UNKNOWN"; 10951 } 10952 } 10953 10954 typedef void 10955 (*instruction_export_t)(struct instruction *, FILE *); 10956 10957 static void 10958 instr_io_export(struct instruction *instr, FILE *f) 10959 { 10960 uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i; 10961 10962 /* n_io, n_io_imm, n_hdrs. */ 10963 if (instr->type == INSTR_RX || 10964 instr->type == INSTR_TX || 10965 instr->type == INSTR_HDR_EXTRACT_M || 10966 (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)) 10967 n_io = 1; 10968 10969 if (instr->type == INSTR_TX_I) 10970 n_io_imm = 1; 10971 10972 if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8) 10973 n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT); 10974 10975 if (instr->type == INSTR_HDR_EXTRACT_M || 10976 instr->type == INSTR_HDR_LOOKAHEAD || 10977 instr->type == INSTR_HDR_EMIT) 10978 n_hdrs = 1; 10979 10980 if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX) 10981 n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX); 10982 10983 /* instr. */ 10984 fprintf(f, 10985 "\t{\n" 10986 "\t\t.type = %s,\n", 10987 instr_type_to_name(instr)); 10988 10989 /* instr.io. */ 10990 if (n_io || n_io_imm || n_hdrs) 10991 fprintf(f, 10992 "\t\t.io = {\n"); 10993 10994 /* instr.io.io. */ 10995 if (n_io) 10996 fprintf(f, 10997 "\t\t\t.io = {\n" 10998 "\t\t\t\t.offset = %u,\n" 10999 "\t\t\t\t.n_bits = %u,\n" 11000 "\t\t\t},\n", 11001 instr->io.io.offset, 11002 instr->io.io.n_bits); 11003 11004 if (n_io_imm) 11005 fprintf(f, 11006 "\t\t\t.io = {\n" 11007 "\t\t\t\t.val = %u,\n" 11008 "\t\t\t},\n", 11009 instr->io.io.val); 11010 11011 /* instr.io.hdr. */ 11012 if (n_hdrs) { 11013 fprintf(f, 11014 "\t\t.hdr = {\n"); 11015 11016 /* instr.io.hdr.header_id. */ 11017 fprintf(f, 11018 "\t\t\t.header_id = {"); 11019 11020 for (i = 0; i < n_hdrs; i++) 11021 fprintf(f, 11022 "%u, ", 11023 instr->io.hdr.header_id[i]); 11024 11025 fprintf(f, 11026 "},\n"); 11027 11028 /* instr.io.hdr.struct_id. */ 11029 fprintf(f, 11030 "\t\t\t.struct_id = {"); 11031 11032 for (i = 0; i < n_hdrs; i++) 11033 fprintf(f, 11034 "%u, ", 11035 instr->io.hdr.struct_id[i]); 11036 11037 fprintf(f, 11038 "},\n"); 11039 11040 /* instr.io.hdr.n_bytes. */ 11041 fprintf(f, 11042 "\t\t\t.n_bytes = {"); 11043 11044 for (i = 0; i < n_hdrs; i++) 11045 fprintf(f, 11046 "%u, ", 11047 instr->io.hdr.n_bytes[i]); 11048 11049 fprintf(f, 11050 "},\n"); 11051 11052 /* instr.io.hdr - closing curly brace. */ 11053 fprintf(f, 11054 "\t\t\t}\n,"); 11055 } 11056 11057 /* instr.io - closing curly brace. */ 11058 if (n_io || n_io_imm || n_hdrs) 11059 fprintf(f, 11060 "\t\t},\n"); 11061 11062 /* instr - closing curly brace. */ 11063 fprintf(f, 11064 "\t},\n"); 11065 } 11066 11067 static void 11068 instr_mirror_export(struct instruction *instr, FILE *f) 11069 { 11070 fprintf(f, 11071 "\t{\n" 11072 "\t\t.type = %s,\n" 11073 "\t\t.mirror = {\n" 11074 "\t\t\t.dst = {\n" 11075 "\t\t\t\t.struct_id = %u,\n" 11076 "\t\t\t\t.n_bits = %u,\n" 11077 "\t\t\t\t.offset = %u,\n" 11078 "\t\t\t}\n," 11079 "\t\t\t.src = {\n" 11080 "\t\t\t\t.struct_id = %u,\n" 11081 "\t\t\t\t.n_bits = %u,\n" 11082 "\t\t\t\t.offset = %u,\n" 11083 "\t\t\t}\n," 11084 "\t\t},\n" 11085 "\t},\n", 11086 instr_type_to_name(instr), 11087 instr->mirror.dst.struct_id, 11088 instr->mirror.dst.n_bits, 11089 instr->mirror.dst.offset, 11090 instr->mirror.src.struct_id, 11091 instr->mirror.src.n_bits, 11092 instr->mirror.src.offset); 11093 } 11094 11095 static void 11096 instr_recirculate_export(struct instruction *instr, FILE *f) 11097 { 11098 fprintf(f, 11099 "\t{\n" 11100 "\t\t.type = %s,\n" 11101 "\t},\n", 11102 instr_type_to_name(instr)); 11103 } 11104 11105 static void 11106 instr_recircid_export(struct instruction *instr, FILE *f) 11107 { 11108 fprintf(f, 11109 "\t{\n" 11110 "\t\t.type = %s,\n" 11111 "\t\t.io = {\n" 11112 "\t\t\t.offset = %u,\n" 11113 "\t\t\t.n_bits = %u,\n" 11114 "\t\t},\n" 11115 "\t},\n", 11116 instr_type_to_name(instr), 11117 instr->io.io.offset, 11118 instr->io.io.n_bits); 11119 } 11120 11121 static void 11122 instr_hdr_validate_export(struct instruction *instr, FILE *f) 11123 { 11124 fprintf(f, 11125 "\t{\n" 11126 "\t\t.type = %s,\n" 11127 "\t\t.valid = {\n" 11128 "\t\t\t.header_id = %u,\n" 11129 "\t\t},\n" 11130 "\t},\n", 11131 instr_type_to_name(instr), 11132 instr->valid.header_id); 11133 } 11134 11135 static void 11136 instr_mov_export(struct instruction *instr, FILE *f) 11137 { 11138 if (instr->type != INSTR_MOV_I) 11139 fprintf(f, 11140 "\t{\n" 11141 "\t\t.type = %s,\n" 11142 "\t\t.mov = {\n" 11143 "\t\t\t.dst = {\n" 11144 "\t\t\t\t.struct_id = %u,\n" 11145 "\t\t\t\t.n_bits = %u,\n" 11146 "\t\t\t\t.offset = %u,\n" 11147 "\t\t\t},\n" 11148 "\t\t\t.src = {\n" 11149 "\t\t\t\t.struct_id = %u,\n" 11150 "\t\t\t\t.n_bits = %u,\n" 11151 "\t\t\t\t.offset = %u,\n" 11152 "\t\t\t},\n" 11153 "\t\t},\n" 11154 "\t},\n", 11155 instr_type_to_name(instr), 11156 instr->mov.dst.struct_id, 11157 instr->mov.dst.n_bits, 11158 instr->mov.dst.offset, 11159 instr->mov.src.struct_id, 11160 instr->mov.src.n_bits, 11161 instr->mov.src.offset); 11162 else 11163 fprintf(f, 11164 "\t{\n" 11165 "\t\t.type = %s,\n" 11166 "\t\t.mov = {\n" 11167 "\t\t\t.dst = {\n" 11168 "\t\t\t\t.struct_id = %u,\n" 11169 "\t\t\t\t.n_bits = %u,\n" 11170 "\t\t\t\t.offset = %u,\n" 11171 "\t\t\t}\n," 11172 "\t\t\t.src_val = %" PRIu64 ",\n" 11173 "\t\t},\n" 11174 "\t},\n", 11175 instr_type_to_name(instr), 11176 instr->mov.dst.struct_id, 11177 instr->mov.dst.n_bits, 11178 instr->mov.dst.offset, 11179 instr->mov.src_val); 11180 } 11181 11182 static void 11183 instr_dma_ht_export(struct instruction *instr, FILE *f) 11184 { 11185 uint32_t n_dma = 0, i; 11186 11187 /* n_dma. */ 11188 n_dma = 1 + (instr->type - INSTR_DMA_HT); 11189 11190 /* instr. */ 11191 fprintf(f, 11192 "\t{\n" 11193 "\t\t.type = %s,\n", 11194 instr_type_to_name(instr)); 11195 11196 /* instr.dma. */ 11197 fprintf(f, 11198 "\t\t.dma = {\n"); 11199 11200 /* instr.dma.dst. */ 11201 fprintf(f, 11202 "\t\t\t.dst = {\n"); 11203 11204 /* instr.dma.dst.header_id. */ 11205 fprintf(f, 11206 "\t\t\t\t.header_id = {"); 11207 11208 for (i = 0; i < n_dma; i++) 11209 fprintf(f, 11210 "%u, ", 11211 instr->dma.dst.header_id[i]); 11212 11213 fprintf(f, 11214 "},\n"); 11215 11216 /* instr.dma.dst.struct_id. */ 11217 fprintf(f, 11218 "\t\t\t\t.struct_id = {"); 11219 11220 for (i = 0; i < n_dma; i++) 11221 fprintf(f, 11222 "%u, ", 11223 instr->dma.dst.struct_id[i]); 11224 11225 fprintf(f, 11226 "},\n"); 11227 11228 /* instr.dma.dst - closing curly brace. */ 11229 fprintf(f, 11230 "\t\t\t},\n"); 11231 11232 /* instr.dma.src. */ 11233 fprintf(f, 11234 "\t\t\t.src = {\n"); 11235 11236 /* instr.dma.src.offset. */ 11237 fprintf(f, 11238 "\t\t\t\t.offset = {"); 11239 11240 for (i = 0; i < n_dma; i++) 11241 fprintf(f, 11242 "%u, ", 11243 instr->dma.src.offset[i]); 11244 11245 fprintf(f, 11246 "},\n"); 11247 11248 /* instr.dma.src - closing curly brace. */ 11249 fprintf(f, 11250 "\t\t\t},\n"); 11251 11252 /* instr.dma.n_bytes. */ 11253 fprintf(f, 11254 "\t\t\t.n_bytes = {"); 11255 11256 for (i = 0; i < n_dma; i++) 11257 fprintf(f, 11258 "%u, ", 11259 instr->dma.n_bytes[i]); 11260 11261 fprintf(f, 11262 "},\n"); 11263 11264 /* instr.dma - closing curly brace. */ 11265 fprintf(f, 11266 "\t\t},\n"); 11267 11268 /* instr - closing curly brace. */ 11269 fprintf(f, 11270 "\t},\n"); 11271 } 11272 11273 static void 11274 instr_alu_export(struct instruction *instr, FILE *f) 11275 { 11276 int imm = 0; 11277 11278 if (instr->type == INSTR_ALU_ADD_MI || 11279 instr->type == INSTR_ALU_ADD_HI || 11280 instr->type == INSTR_ALU_SUB_MI || 11281 instr->type == INSTR_ALU_SUB_HI || 11282 instr->type == INSTR_ALU_SHL_MI || 11283 instr->type == INSTR_ALU_SHL_HI || 11284 instr->type == INSTR_ALU_SHR_MI || 11285 instr->type == INSTR_ALU_SHR_HI || 11286 instr->type == INSTR_ALU_AND_I || 11287 instr->type == INSTR_ALU_OR_I || 11288 instr->type == INSTR_ALU_XOR_I) 11289 imm = 1; 11290 11291 if (!imm) 11292 fprintf(f, 11293 "\t{\n" 11294 "\t\t.type = %s,\n" 11295 "\t\t.alu = {\n" 11296 "\t\t\t.dst = {\n" 11297 "\t\t\t\t.struct_id = %u,\n" 11298 "\t\t\t\t.n_bits = %u,\n" 11299 "\t\t\t\t.offset = %u,\n" 11300 "\t\t\t},\n" 11301 "\t\t\t.src = {\n" 11302 "\t\t\t\t.struct_id = %u,\n" 11303 "\t\t\t\t.n_bits = %u,\n" 11304 "\t\t\t\t.offset = %u,\n" 11305 "\t\t\t},\n" 11306 "\t\t},\n" 11307 "\t},\n", 11308 instr_type_to_name(instr), 11309 instr->alu.dst.struct_id, 11310 instr->alu.dst.n_bits, 11311 instr->alu.dst.offset, 11312 instr->alu.src.struct_id, 11313 instr->alu.src.n_bits, 11314 instr->alu.src.offset); 11315 else 11316 fprintf(f, 11317 "\t{\n" 11318 "\t\t.type = %s,\n" 11319 "\t\t.alu = {\n" 11320 "\t\t\t.dst = {\n" 11321 "\t\t\t\t.struct_id = %u,\n" 11322 "\t\t\t\t.n_bits = %u,\n" 11323 "\t\t\t\t.offset = %u,\n" 11324 "\t\t\t}\n," 11325 "\t\t\t.src_val = %" PRIu64 ",\n" 11326 "\t\t},\n" 11327 "\t},\n", 11328 instr_type_to_name(instr), 11329 instr->alu.dst.struct_id, 11330 instr->alu.dst.n_bits, 11331 instr->alu.dst.offset, 11332 instr->alu.src_val); 11333 } 11334 11335 static void 11336 instr_hash_export(struct instruction *instr, FILE *f) 11337 { 11338 fprintf(f, 11339 "\t{\n" 11340 "\t\t.type = %s,\n" 11341 "\t\t.hash_func = {\n" 11342 "\t\t\t.hash_func_id = %u,\n" 11343 "\t\t\t.dst = {\n" 11344 "\t\t\t\t.offset = %u,\n" 11345 "\t\t\t\t.n_bits = %u,\n" 11346 "\t\t\t},\n" 11347 "\t\t\t.src = {\n" 11348 "\t\t\t\t.struct_id = %u,\n" 11349 "\t\t\t\t.offset = %u,\n" 11350 "\t\t\t\t.n_bytes = %u,\n" 11351 "\t\t\t},\n" 11352 "\t\t},\n" 11353 "\t},\n", 11354 instr_type_to_name(instr), 11355 instr->hash_func.hash_func_id, 11356 instr->hash_func.dst.offset, 11357 instr->hash_func.dst.n_bits, 11358 instr->hash_func.src.struct_id, 11359 instr->hash_func.src.offset, 11360 instr->hash_func.src.n_bytes); 11361 } 11362 11363 static void 11364 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 11365 { 11366 int prefetch = 0, idx_imm = 0, src_imm = 0; 11367 11368 if (instr->type == INSTR_REGPREFETCH_RH || 11369 instr->type == INSTR_REGPREFETCH_RM || 11370 instr->type == INSTR_REGPREFETCH_RI) 11371 prefetch = 1; 11372 11373 /* index is the 3rd operand for the regrd instruction and the 2nd 11374 * operand for the regwr and regadd instructions. 11375 */ 11376 if (instr->type == INSTR_REGPREFETCH_RI || 11377 instr->type == INSTR_REGRD_HRI || 11378 instr->type == INSTR_REGRD_MRI || 11379 instr->type == INSTR_REGWR_RIH || 11380 instr->type == INSTR_REGWR_RIM || 11381 instr->type == INSTR_REGWR_RII || 11382 instr->type == INSTR_REGADD_RIH || 11383 instr->type == INSTR_REGADD_RIM || 11384 instr->type == INSTR_REGADD_RII) 11385 idx_imm = 1; 11386 11387 /* src is the 3rd operand for the regwr and regadd instructions. */ 11388 if (instr->type == INSTR_REGWR_RHI || 11389 instr->type == INSTR_REGWR_RMI || 11390 instr->type == INSTR_REGWR_RII || 11391 instr->type == INSTR_REGADD_RHI || 11392 instr->type == INSTR_REGADD_RMI || 11393 instr->type == INSTR_REGADD_RII) 11394 src_imm = 1; 11395 11396 /* instr.regarray.regarray_id. */ 11397 fprintf(f, 11398 "\t{\n" 11399 "\t\t.type = %s,\n" 11400 "\t\t.regarray = {\n" 11401 "\t\t\t.regarray_id = %u,\n", 11402 instr_type_to_name(instr), 11403 instr->regarray.regarray_id); 11404 11405 /* instr.regarray.idx / instr.regarray.idx_val. */ 11406 if (!idx_imm) 11407 fprintf(f, 11408 "\t\t\t\t.idx = {\n" 11409 "\t\t\t\t\t.struct_id = %u,\n" 11410 "\t\t\t\t\t.n_bits = %u,\n" 11411 "\t\t\t\t\t.offset = %u,\n" 11412 "\t\t\t\t},\n", 11413 instr->regarray.idx.struct_id, 11414 instr->regarray.idx.n_bits, 11415 instr->regarray.idx.offset); 11416 else 11417 fprintf(f, 11418 "\t\t\t\t.idx_val = %u,\n", 11419 instr->regarray.idx_val); 11420 11421 /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */ 11422 if (!prefetch) { 11423 if (!src_imm) 11424 fprintf(f, 11425 "\t\t\t\t.dstsrc = {\n" 11426 "\t\t\t\t\t.struct_id = %u,\n" 11427 "\t\t\t\t\t.n_bits = %u,\n" 11428 "\t\t\t\t\t.offset = %u,\n" 11429 "\t\t\t\t},\n", 11430 instr->regarray.dstsrc.struct_id, 11431 instr->regarray.dstsrc.n_bits, 11432 instr->regarray.dstsrc.offset); 11433 else 11434 fprintf(f, 11435 "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n", 11436 instr->regarray.dstsrc_val); 11437 } 11438 11439 /* instr.regarray and instr - closing curly braces. */ 11440 fprintf(f, 11441 "\t\t},\n" 11442 "\t},\n"); 11443 } 11444 11445 static void 11446 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 11447 { 11448 int prefetch = 0, idx_imm = 0, color_in_imm = 0; 11449 11450 if (instr->type == INSTR_METPREFETCH_H || 11451 instr->type == INSTR_METPREFETCH_M || 11452 instr->type == INSTR_METPREFETCH_I) 11453 prefetch = 1; 11454 11455 /* idx_imm. */ 11456 if (instr->type == INSTR_METPREFETCH_I || 11457 instr->type == INSTR_METER_IHM || 11458 instr->type == INSTR_METER_IHI || 11459 instr->type == INSTR_METER_IMM || 11460 instr->type == INSTR_METER_IMI) 11461 idx_imm = 1; 11462 11463 /* color_in_imm. */ 11464 if (instr->type == INSTR_METER_HHI || 11465 instr->type == INSTR_METER_HMI || 11466 instr->type == INSTR_METER_MHI || 11467 instr->type == INSTR_METER_MMI || 11468 instr->type == INSTR_METER_IHI || 11469 instr->type == INSTR_METER_IMI) 11470 color_in_imm = 1; 11471 11472 /* instr.meter.metarray_id. */ 11473 fprintf(f, 11474 "\t{\n" 11475 "\t\t.type = %s,\n" 11476 "\t\t.meter = {\n" 11477 "\t\t\t.metarray_id = %u,\n", 11478 instr_type_to_name(instr), 11479 instr->meter.metarray_id); 11480 11481 /* instr.meter.idx / instr.meter.idx_val. */ 11482 if (!idx_imm) 11483 fprintf(f, 11484 "\t\t\t.idx = {\n" 11485 "\t\t\t\t.struct_id = %u,\n" 11486 "\t\t\t\t.n_bits = %u,\n" 11487 "\t\t\t\t.offset = %u,\n" 11488 "\t\t\t},\n", 11489 instr->meter.idx.struct_id, 11490 instr->meter.idx.n_bits, 11491 instr->meter.idx.offset); 11492 else 11493 fprintf(f, 11494 "\t\t\t.idx_val = %u,\n", 11495 instr->meter.idx_val); 11496 11497 if (!prefetch) { 11498 /* instr.meter.length. */ 11499 fprintf(f, 11500 "\t\t\t.length = {\n" 11501 "\t\t\t\t.struct_id = %u,\n" 11502 "\t\t\t\t.n_bits = %u,\n" 11503 "\t\t\t\t.offset = %u,\n" 11504 "\t\t\t},\n", 11505 instr->meter.length.struct_id, 11506 instr->meter.length.n_bits, 11507 instr->meter.length.offset); 11508 11509 /* instr.meter.color_in / instr.meter.color_in_val. */ 11510 if (!color_in_imm) 11511 fprintf(f, 11512 "\t\t\t.color_in = {\n" 11513 "\t\t\t\t.struct_id = %u,\n" 11514 "\t\t\t\t.n_bits = %u,\n" 11515 "\t\t\t\t.offset = %u,\n" 11516 "\t\t\t},\n", 11517 instr->meter.color_in.struct_id, 11518 instr->meter.color_in.n_bits, 11519 instr->meter.color_in.offset); 11520 else 11521 fprintf(f, 11522 "\t\t\t.color_in_val = %u,\n", 11523 (uint32_t)instr->meter.color_in_val); 11524 11525 /* instr.meter.color_out. */ 11526 fprintf(f, 11527 "\t\t\t.color_out = {\n" 11528 "\t\t\t\t.struct_id = %u,\n" 11529 "\t\t\t\t.n_bits = %u,\n" 11530 "\t\t\t\t.offset = %u,\n" 11531 "\t\t\t},\n", 11532 instr->meter.color_out.struct_id, 11533 instr->meter.color_out.n_bits, 11534 instr->meter.color_out.offset); 11535 } 11536 11537 /* instr.meter and instr - closing curly braces. */ 11538 fprintf(f, 11539 "\t\t},\n" 11540 "\t},\n"); 11541 } 11542 11543 static void 11544 instr_table_export(struct instruction *instr, 11545 FILE *f) 11546 { 11547 fprintf(f, 11548 "\t{\n" 11549 "\t\t.type = %s,\n" 11550 "\t\t.table = {\n" 11551 "\t\t\t.table_id = %u,\n" 11552 "\t\t},\n" 11553 "\t},\n", 11554 instr_type_to_name(instr), 11555 instr->table.table_id); 11556 } 11557 11558 static void 11559 instr_learn_export(struct instruction *instr, FILE *f) 11560 { 11561 fprintf(f, 11562 "\t{\n" 11563 "\t\t.type = %s,\n" 11564 "\t\t.learn = {\n" 11565 "\t\t\t.action_id = %u,\n" 11566 "\t\t\t.mf_first_arg_offset = %u,\n" 11567 "\t\t\t.mf_timeout_id_offset = %u,\n" 11568 "\t\t\t.mf_timeout_id_n_bits = %u,\n" 11569 "\t\t},\n" 11570 "\t},\n", 11571 instr_type_to_name(instr), 11572 instr->learn.action_id, 11573 instr->learn.mf_first_arg_offset, 11574 instr->learn.mf_timeout_id_offset, 11575 instr->learn.mf_timeout_id_n_bits); 11576 } 11577 11578 static void 11579 instr_rearm_export(struct instruction *instr, FILE *f) 11580 { 11581 if (instr->type == INSTR_LEARNER_REARM) 11582 fprintf(f, 11583 "\t{\n" 11584 "\t\t.type = %s,\n" 11585 "\t},\n", 11586 instr_type_to_name(instr)); 11587 else 11588 fprintf(f, 11589 "\t{\n" 11590 "\t\t.type = %s,\n" 11591 "\t\t.learn = {\n" 11592 "\t\t\t.mf_timeout_id_offset = %u,\n" 11593 "\t\t\t.mf_timeout_id_n_bits = %u,\n" 11594 "\t\t},\n" 11595 "\t},\n", 11596 instr_type_to_name(instr), 11597 instr->learn.mf_timeout_id_offset, 11598 instr->learn.mf_timeout_id_n_bits); 11599 } 11600 11601 static void 11602 instr_forget_export(struct instruction *instr, FILE *f) 11603 { 11604 fprintf(f, 11605 "\t{\n" 11606 "\t\t.type = %s,\n" 11607 "\t},\n", 11608 instr_type_to_name(instr)); 11609 } 11610 11611 static void 11612 instr_extern_export(struct instruction *instr, FILE *f) 11613 { 11614 if (instr->type == INSTR_EXTERN_OBJ) 11615 fprintf(f, 11616 "\t{\n" 11617 "\t\t.type = %s,\n" 11618 "\t\t.ext_obj = {\n" 11619 "\t\t\t.ext_obj_id = %u,\n" 11620 "\t\t\t.func_id = %u,\n" 11621 "\t\t},\n" 11622 "\t},\n", 11623 instr_type_to_name(instr), 11624 instr->ext_obj.ext_obj_id, 11625 instr->ext_obj.func_id); 11626 else 11627 fprintf(f, 11628 "\t{\n" 11629 "\t\t.type = %s,\n" 11630 "\t\t.ext_func = {\n" 11631 "\t\t\t.ext_func_id = %u,\n" 11632 "\t\t},\n" 11633 "\t},\n", 11634 instr_type_to_name(instr), 11635 instr->ext_func.ext_func_id); 11636 } 11637 11638 static void 11639 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused) 11640 { 11641 fprintf(f, 11642 "\t{\n" 11643 "\t\t.type = %s,\n" 11644 "\t\t.jmp = {\n" 11645 "\t\t\t.ip = NULL,\n", 11646 instr_type_to_name(instr)); 11647 11648 switch (instr->type) { 11649 case INSTR_JMP_VALID: 11650 case INSTR_JMP_INVALID: 11651 fprintf(f, 11652 "\t\t\t.header_id = %u,\n", 11653 instr->jmp.header_id); 11654 break; 11655 11656 case INSTR_JMP_ACTION_HIT: 11657 case INSTR_JMP_ACTION_MISS: 11658 fprintf(f, 11659 "\t\t\t.action_id = %u,\n", 11660 instr->jmp.action_id); 11661 break; 11662 11663 case INSTR_JMP_EQ: 11664 case INSTR_JMP_EQ_MH: 11665 case INSTR_JMP_EQ_HM: 11666 case INSTR_JMP_EQ_HH: 11667 case INSTR_JMP_NEQ: 11668 case INSTR_JMP_NEQ_MH: 11669 case INSTR_JMP_NEQ_HM: 11670 case INSTR_JMP_NEQ_HH: 11671 case INSTR_JMP_LT: 11672 case INSTR_JMP_LT_MH: 11673 case INSTR_JMP_LT_HM: 11674 case INSTR_JMP_LT_HH: 11675 case INSTR_JMP_GT: 11676 case INSTR_JMP_GT_MH: 11677 case INSTR_JMP_GT_HM: 11678 case INSTR_JMP_GT_HH: 11679 fprintf(f, 11680 "\t\t\t.a = {\n" 11681 "\t\t\t\t.struct_id = %u,\n" 11682 "\t\t\t\t.n_bits = %u,\n" 11683 "\t\t\t\t.offset = %u,\n" 11684 "\t\t\t},\n" 11685 "\t\t\t.b = {\n" 11686 "\t\t\t\t.struct_id = %u,\n" 11687 "\t\t\t\t.n_bits = %u,\n" 11688 "\t\t\t\t.offset = %u,\n" 11689 "\t\t\t},\n", 11690 instr->jmp.a.struct_id, 11691 instr->jmp.a.n_bits, 11692 instr->jmp.a.offset, 11693 instr->jmp.b.struct_id, 11694 instr->jmp.b.n_bits, 11695 instr->jmp.b.offset); 11696 break; 11697 11698 case INSTR_JMP_EQ_I: 11699 case INSTR_JMP_NEQ_I: 11700 case INSTR_JMP_LT_MI: 11701 case INSTR_JMP_LT_HI: 11702 case INSTR_JMP_GT_MI: 11703 case INSTR_JMP_GT_HI: 11704 fprintf(f, 11705 "\t\t\t.a = {\n" 11706 "\t\t\t\t.struct_id = %u,\n" 11707 "\t\t\t\t.n_bits = %u,\n" 11708 "\t\t\t\t.offset = %u,\n" 11709 "\t\t\t}\n," 11710 "\t\t\t.b_val = %" PRIu64 ",\n", 11711 instr->jmp.a.struct_id, 11712 instr->jmp.a.n_bits, 11713 instr->jmp.a.offset, 11714 instr->jmp.b_val); 11715 break; 11716 11717 default: 11718 break; 11719 } 11720 11721 fprintf(f, 11722 "\t\t},\n" 11723 "\t},\n"); 11724 } 11725 11726 static void 11727 instr_return_export(struct instruction *instr, 11728 FILE *f) 11729 { 11730 fprintf(f, 11731 "\t{\n" 11732 "\t\t.type = %s,\n", 11733 instr_type_to_name(instr)); 11734 11735 fprintf(f, 11736 "\t},\n"); 11737 } 11738 11739 static instruction_export_t export_table[] = { 11740 [INSTR_RX] = instr_io_export, 11741 11742 [INSTR_TX] = instr_io_export, 11743 [INSTR_TX_I] = instr_io_export, 11744 [INSTR_DROP] = instr_io_export, 11745 [INSTR_MIRROR] = instr_mirror_export, 11746 [INSTR_RECIRCULATE] = instr_recirculate_export, 11747 [INSTR_RECIRCID] = instr_recircid_export, 11748 11749 [INSTR_HDR_EXTRACT] = instr_io_export, 11750 [INSTR_HDR_EXTRACT2] = instr_io_export, 11751 [INSTR_HDR_EXTRACT3] = instr_io_export, 11752 [INSTR_HDR_EXTRACT4] = instr_io_export, 11753 [INSTR_HDR_EXTRACT5] = instr_io_export, 11754 [INSTR_HDR_EXTRACT6] = instr_io_export, 11755 [INSTR_HDR_EXTRACT7] = instr_io_export, 11756 [INSTR_HDR_EXTRACT8] = instr_io_export, 11757 11758 [INSTR_HDR_EXTRACT_M] = instr_io_export, 11759 11760 [INSTR_HDR_LOOKAHEAD] = instr_io_export, 11761 11762 [INSTR_HDR_EMIT] = instr_io_export, 11763 [INSTR_HDR_EMIT_TX] = instr_io_export, 11764 [INSTR_HDR_EMIT2_TX] = instr_io_export, 11765 [INSTR_HDR_EMIT3_TX] = instr_io_export, 11766 [INSTR_HDR_EMIT4_TX] = instr_io_export, 11767 [INSTR_HDR_EMIT5_TX] = instr_io_export, 11768 [INSTR_HDR_EMIT6_TX] = instr_io_export, 11769 [INSTR_HDR_EMIT7_TX] = instr_io_export, 11770 [INSTR_HDR_EMIT8_TX] = instr_io_export, 11771 11772 [INSTR_HDR_VALIDATE] = instr_hdr_validate_export, 11773 [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export, 11774 11775 [INSTR_MOV] = instr_mov_export, 11776 [INSTR_MOV_MH] = instr_mov_export, 11777 [INSTR_MOV_HM] = instr_mov_export, 11778 [INSTR_MOV_HH] = instr_mov_export, 11779 [INSTR_MOV_I] = instr_mov_export, 11780 11781 [INSTR_DMA_HT] = instr_dma_ht_export, 11782 [INSTR_DMA_HT2] = instr_dma_ht_export, 11783 [INSTR_DMA_HT3] = instr_dma_ht_export, 11784 [INSTR_DMA_HT4] = instr_dma_ht_export, 11785 [INSTR_DMA_HT5] = instr_dma_ht_export, 11786 [INSTR_DMA_HT6] = instr_dma_ht_export, 11787 [INSTR_DMA_HT7] = instr_dma_ht_export, 11788 [INSTR_DMA_HT8] = instr_dma_ht_export, 11789 11790 [INSTR_ALU_ADD] = instr_alu_export, 11791 [INSTR_ALU_ADD_MH] = instr_alu_export, 11792 [INSTR_ALU_ADD_HM] = instr_alu_export, 11793 [INSTR_ALU_ADD_HH] = instr_alu_export, 11794 [INSTR_ALU_ADD_MI] = instr_alu_export, 11795 [INSTR_ALU_ADD_HI] = instr_alu_export, 11796 11797 [INSTR_ALU_SUB] = instr_alu_export, 11798 [INSTR_ALU_SUB_MH] = instr_alu_export, 11799 [INSTR_ALU_SUB_HM] = instr_alu_export, 11800 [INSTR_ALU_SUB_HH] = instr_alu_export, 11801 [INSTR_ALU_SUB_MI] = instr_alu_export, 11802 [INSTR_ALU_SUB_HI] = instr_alu_export, 11803 11804 [INSTR_ALU_CKADD_FIELD] = instr_alu_export, 11805 [INSTR_ALU_CKADD_STRUCT] = instr_alu_export, 11806 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export, 11807 [INSTR_ALU_CKSUB_FIELD] = instr_alu_export, 11808 11809 [INSTR_ALU_AND] = instr_alu_export, 11810 [INSTR_ALU_AND_MH] = instr_alu_export, 11811 [INSTR_ALU_AND_HM] = instr_alu_export, 11812 [INSTR_ALU_AND_HH] = instr_alu_export, 11813 [INSTR_ALU_AND_I] = instr_alu_export, 11814 11815 [INSTR_ALU_OR] = instr_alu_export, 11816 [INSTR_ALU_OR_MH] = instr_alu_export, 11817 [INSTR_ALU_OR_HM] = instr_alu_export, 11818 [INSTR_ALU_OR_HH] = instr_alu_export, 11819 [INSTR_ALU_OR_I] = instr_alu_export, 11820 11821 [INSTR_ALU_XOR] = instr_alu_export, 11822 [INSTR_ALU_XOR_MH] = instr_alu_export, 11823 [INSTR_ALU_XOR_HM] = instr_alu_export, 11824 [INSTR_ALU_XOR_HH] = instr_alu_export, 11825 [INSTR_ALU_XOR_I] = instr_alu_export, 11826 11827 [INSTR_ALU_SHL] = instr_alu_export, 11828 [INSTR_ALU_SHL_MH] = instr_alu_export, 11829 [INSTR_ALU_SHL_HM] = instr_alu_export, 11830 [INSTR_ALU_SHL_HH] = instr_alu_export, 11831 [INSTR_ALU_SHL_MI] = instr_alu_export, 11832 [INSTR_ALU_SHL_HI] = instr_alu_export, 11833 11834 [INSTR_ALU_SHR] = instr_alu_export, 11835 [INSTR_ALU_SHR_MH] = instr_alu_export, 11836 [INSTR_ALU_SHR_HM] = instr_alu_export, 11837 [INSTR_ALU_SHR_HH] = instr_alu_export, 11838 [INSTR_ALU_SHR_MI] = instr_alu_export, 11839 [INSTR_ALU_SHR_HI] = instr_alu_export, 11840 11841 [INSTR_REGPREFETCH_RH] = instr_reg_export, 11842 [INSTR_REGPREFETCH_RM] = instr_reg_export, 11843 [INSTR_REGPREFETCH_RI] = instr_reg_export, 11844 11845 [INSTR_REGRD_HRH] = instr_reg_export, 11846 [INSTR_REGRD_HRM] = instr_reg_export, 11847 [INSTR_REGRD_MRH] = instr_reg_export, 11848 [INSTR_REGRD_MRM] = instr_reg_export, 11849 [INSTR_REGRD_HRI] = instr_reg_export, 11850 [INSTR_REGRD_MRI] = instr_reg_export, 11851 11852 [INSTR_REGWR_RHH] = instr_reg_export, 11853 [INSTR_REGWR_RHM] = instr_reg_export, 11854 [INSTR_REGWR_RMH] = instr_reg_export, 11855 [INSTR_REGWR_RMM] = instr_reg_export, 11856 [INSTR_REGWR_RHI] = instr_reg_export, 11857 [INSTR_REGWR_RMI] = instr_reg_export, 11858 [INSTR_REGWR_RIH] = instr_reg_export, 11859 [INSTR_REGWR_RIM] = instr_reg_export, 11860 [INSTR_REGWR_RII] = instr_reg_export, 11861 11862 [INSTR_REGADD_RHH] = instr_reg_export, 11863 [INSTR_REGADD_RHM] = instr_reg_export, 11864 [INSTR_REGADD_RMH] = instr_reg_export, 11865 [INSTR_REGADD_RMM] = instr_reg_export, 11866 [INSTR_REGADD_RHI] = instr_reg_export, 11867 [INSTR_REGADD_RMI] = instr_reg_export, 11868 [INSTR_REGADD_RIH] = instr_reg_export, 11869 [INSTR_REGADD_RIM] = instr_reg_export, 11870 [INSTR_REGADD_RII] = instr_reg_export, 11871 11872 [INSTR_METPREFETCH_H] = instr_meter_export, 11873 [INSTR_METPREFETCH_M] = instr_meter_export, 11874 [INSTR_METPREFETCH_I] = instr_meter_export, 11875 11876 [INSTR_METER_HHM] = instr_meter_export, 11877 [INSTR_METER_HHI] = instr_meter_export, 11878 [INSTR_METER_HMM] = instr_meter_export, 11879 [INSTR_METER_HMI] = instr_meter_export, 11880 [INSTR_METER_MHM] = instr_meter_export, 11881 [INSTR_METER_MHI] = instr_meter_export, 11882 [INSTR_METER_MMM] = instr_meter_export, 11883 [INSTR_METER_MMI] = instr_meter_export, 11884 [INSTR_METER_IHM] = instr_meter_export, 11885 [INSTR_METER_IHI] = instr_meter_export, 11886 [INSTR_METER_IMM] = instr_meter_export, 11887 [INSTR_METER_IMI] = instr_meter_export, 11888 11889 [INSTR_TABLE] = instr_table_export, 11890 [INSTR_TABLE_AF] = instr_table_export, 11891 [INSTR_SELECTOR] = instr_table_export, 11892 [INSTR_LEARNER] = instr_table_export, 11893 [INSTR_LEARNER_AF] = instr_table_export, 11894 11895 [INSTR_LEARNER_LEARN] = instr_learn_export, 11896 [INSTR_LEARNER_REARM] = instr_rearm_export, 11897 [INSTR_LEARNER_REARM_NEW] = instr_rearm_export, 11898 [INSTR_LEARNER_FORGET] = instr_forget_export, 11899 11900 [INSTR_EXTERN_OBJ] = instr_extern_export, 11901 [INSTR_EXTERN_FUNC] = instr_extern_export, 11902 [INSTR_HASH_FUNC] = instr_hash_export, 11903 11904 [INSTR_JMP] = instr_jmp_export, 11905 [INSTR_JMP_VALID] = instr_jmp_export, 11906 [INSTR_JMP_INVALID] = instr_jmp_export, 11907 [INSTR_JMP_HIT] = instr_jmp_export, 11908 [INSTR_JMP_MISS] = instr_jmp_export, 11909 [INSTR_JMP_ACTION_HIT] = instr_jmp_export, 11910 [INSTR_JMP_ACTION_MISS] = instr_jmp_export, 11911 11912 [INSTR_JMP_EQ] = instr_jmp_export, 11913 [INSTR_JMP_EQ_MH] = instr_jmp_export, 11914 [INSTR_JMP_EQ_HM] = instr_jmp_export, 11915 [INSTR_JMP_EQ_HH] = instr_jmp_export, 11916 [INSTR_JMP_EQ_I] = instr_jmp_export, 11917 11918 [INSTR_JMP_NEQ] = instr_jmp_export, 11919 [INSTR_JMP_NEQ_MH] = instr_jmp_export, 11920 [INSTR_JMP_NEQ_HM] = instr_jmp_export, 11921 [INSTR_JMP_NEQ_HH] = instr_jmp_export, 11922 [INSTR_JMP_NEQ_I] = instr_jmp_export, 11923 11924 [INSTR_JMP_LT] = instr_jmp_export, 11925 [INSTR_JMP_LT_MH] = instr_jmp_export, 11926 [INSTR_JMP_LT_HM] = instr_jmp_export, 11927 [INSTR_JMP_LT_HH] = instr_jmp_export, 11928 [INSTR_JMP_LT_MI] = instr_jmp_export, 11929 [INSTR_JMP_LT_HI] = instr_jmp_export, 11930 11931 [INSTR_JMP_GT] = instr_jmp_export, 11932 [INSTR_JMP_GT_MH] = instr_jmp_export, 11933 [INSTR_JMP_GT_HM] = instr_jmp_export, 11934 [INSTR_JMP_GT_HH] = instr_jmp_export, 11935 [INSTR_JMP_GT_MI] = instr_jmp_export, 11936 [INSTR_JMP_GT_HI] = instr_jmp_export, 11937 11938 [INSTR_RETURN] = instr_return_export, 11939 }; 11940 11941 static void 11942 action_data_codegen(struct action *a, FILE *f) 11943 { 11944 uint32_t i; 11945 11946 fprintf(f, 11947 "static const struct instruction action_%s_instructions[] = {\n", 11948 a->name); 11949 11950 for (i = 0; i < a->n_instructions; i++) { 11951 struct instruction *instr = &a->instructions[i]; 11952 instruction_export_t func = export_table[instr->type]; 11953 11954 func(instr, f); 11955 } 11956 11957 fprintf(f, "};\n"); 11958 } 11959 11960 static const char * 11961 instr_type_to_func(struct instruction *instr) 11962 { 11963 switch (instr->type) { 11964 case INSTR_RX: return NULL; 11965 11966 case INSTR_TX: return "__instr_tx_exec"; 11967 case INSTR_TX_I: return "__instr_tx_i_exec"; 11968 case INSTR_DROP: return "__instr_drop_exec"; 11969 case INSTR_MIRROR: return "__instr_mirror_exec"; 11970 case INSTR_RECIRCULATE: return "__instr_recirculate_exec"; 11971 case INSTR_RECIRCID: return "__instr_recircid_exec"; 11972 11973 case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; 11974 case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; 11975 case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec"; 11976 case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec"; 11977 case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec"; 11978 case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec"; 11979 case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec"; 11980 case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec"; 11981 11982 case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec"; 11983 11984 case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec"; 11985 11986 case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec"; 11987 case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec"; 11988 case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec"; 11989 case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec"; 11990 case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec"; 11991 case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec"; 11992 case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec"; 11993 case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec"; 11994 case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec"; 11995 11996 case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec"; 11997 case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec"; 11998 11999 case INSTR_MOV: return "__instr_mov_exec"; 12000 case INSTR_MOV_MH: return "__instr_mov_mh_exec"; 12001 case INSTR_MOV_HM: return "__instr_mov_hm_exec"; 12002 case INSTR_MOV_HH: return "__instr_mov_hh_exec"; 12003 case INSTR_MOV_I: return "__instr_mov_i_exec"; 12004 12005 case INSTR_DMA_HT: return "__instr_dma_ht_exec"; 12006 case INSTR_DMA_HT2: return "__instr_dma_ht2_exec"; 12007 case INSTR_DMA_HT3: return "__instr_dma_ht3_exec"; 12008 case INSTR_DMA_HT4: return "__instr_dma_ht4_exec"; 12009 case INSTR_DMA_HT5: return "__instr_dma_ht5_exec"; 12010 case INSTR_DMA_HT6: return "__instr_dma_ht6_exec"; 12011 case INSTR_DMA_HT7: return "__instr_dma_ht7_exec"; 12012 case INSTR_DMA_HT8: return "__instr_dma_ht8_exec"; 12013 12014 case INSTR_ALU_ADD: return "__instr_alu_add_exec"; 12015 case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec"; 12016 case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec"; 12017 case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec"; 12018 case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec"; 12019 case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec"; 12020 12021 case INSTR_ALU_SUB: return "__instr_alu_sub_exec"; 12022 case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec"; 12023 case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec"; 12024 case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec"; 12025 case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec"; 12026 case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec"; 12027 12028 case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec"; 12029 case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec"; 12030 case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec"; 12031 case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec"; 12032 12033 case INSTR_ALU_AND: return "__instr_alu_and_exec"; 12034 case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec"; 12035 case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec"; 12036 case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec"; 12037 case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec"; 12038 12039 case INSTR_ALU_OR: return "__instr_alu_or_exec"; 12040 case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec"; 12041 case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec"; 12042 case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec"; 12043 case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec"; 12044 12045 case INSTR_ALU_XOR: return "__instr_alu_xor_exec"; 12046 case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec"; 12047 case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec"; 12048 case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec"; 12049 case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec"; 12050 12051 case INSTR_ALU_SHL: return "__instr_alu_shl_exec"; 12052 case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec"; 12053 case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec"; 12054 case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec"; 12055 case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec"; 12056 case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec"; 12057 12058 case INSTR_ALU_SHR: return "__instr_alu_shr_exec"; 12059 case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec"; 12060 case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec"; 12061 case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec"; 12062 case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec"; 12063 case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec"; 12064 12065 case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec"; 12066 case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec"; 12067 case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec"; 12068 12069 case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec"; 12070 case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec"; 12071 case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec"; 12072 case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec"; 12073 case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec"; 12074 case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec"; 12075 12076 case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec"; 12077 case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec"; 12078 case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec"; 12079 case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec"; 12080 case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec"; 12081 case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec"; 12082 case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec"; 12083 case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec"; 12084 case INSTR_REGWR_RII: return "__instr_regwr_rii_exec"; 12085 12086 case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec"; 12087 case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec"; 12088 case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec"; 12089 case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec"; 12090 case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec"; 12091 case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec"; 12092 case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec"; 12093 case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec"; 12094 case INSTR_REGADD_RII: return "__instr_regadd_rii_exec"; 12095 12096 case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec"; 12097 case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec"; 12098 case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec"; 12099 12100 case INSTR_METER_HHM: return "__instr_meter_hhm_exec"; 12101 case INSTR_METER_HHI: return "__instr_meter_hhi_exec"; 12102 case INSTR_METER_HMM: return "__instr_meter_hmm_exec"; 12103 case INSTR_METER_HMI: return "__instr_meter_hmi_exec"; 12104 case INSTR_METER_MHM: return "__instr_meter_mhm_exec"; 12105 case INSTR_METER_MHI: return "__instr_meter_mhi_exec"; 12106 case INSTR_METER_MMM: return "__instr_meter_mmm_exec"; 12107 case INSTR_METER_MMI: return "__instr_meter_mmi_exec"; 12108 case INSTR_METER_IHM: return "__instr_meter_ihm_exec"; 12109 case INSTR_METER_IHI: return "__instr_meter_ihi_exec"; 12110 case INSTR_METER_IMM: return "__instr_meter_imm_exec"; 12111 case INSTR_METER_IMI: return "__instr_meter_imi_exec"; 12112 12113 case INSTR_TABLE: return NULL; 12114 case INSTR_TABLE_AF: return NULL; 12115 case INSTR_SELECTOR: return NULL; 12116 case INSTR_LEARNER: return NULL; 12117 case INSTR_LEARNER_AF: return NULL; 12118 12119 case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; 12120 case INSTR_LEARNER_REARM: return "__instr_rearm_exec"; 12121 case INSTR_LEARNER_REARM_NEW: return "__instr_rearm_new_exec"; 12122 case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; 12123 12124 case INSTR_EXTERN_OBJ: return NULL; 12125 case INSTR_EXTERN_FUNC: return NULL; 12126 case INSTR_HASH_FUNC: return "__instr_hash_func_exec"; 12127 12128 case INSTR_JMP: return NULL; 12129 case INSTR_JMP_VALID: return NULL; 12130 case INSTR_JMP_INVALID: return NULL; 12131 case INSTR_JMP_HIT: return NULL; 12132 case INSTR_JMP_MISS: return NULL; 12133 case INSTR_JMP_ACTION_HIT: return NULL; 12134 case INSTR_JMP_ACTION_MISS: return NULL; 12135 case INSTR_JMP_EQ: return NULL; 12136 case INSTR_JMP_EQ_MH: return NULL; 12137 case INSTR_JMP_EQ_HM: return NULL; 12138 case INSTR_JMP_EQ_HH: return NULL; 12139 case INSTR_JMP_EQ_I: return NULL; 12140 case INSTR_JMP_NEQ: return NULL; 12141 case INSTR_JMP_NEQ_MH: return NULL; 12142 case INSTR_JMP_NEQ_HM: return NULL; 12143 case INSTR_JMP_NEQ_HH: return NULL; 12144 case INSTR_JMP_NEQ_I: return NULL; 12145 case INSTR_JMP_LT: return NULL; 12146 case INSTR_JMP_LT_MH: return NULL; 12147 case INSTR_JMP_LT_HM: return NULL; 12148 case INSTR_JMP_LT_HH: return NULL; 12149 case INSTR_JMP_LT_MI: return NULL; 12150 case INSTR_JMP_LT_HI: return NULL; 12151 case INSTR_JMP_GT: return NULL; 12152 case INSTR_JMP_GT_MH: return NULL; 12153 case INSTR_JMP_GT_HM: return NULL; 12154 case INSTR_JMP_GT_HH: return NULL; 12155 case INSTR_JMP_GT_MI: return NULL; 12156 case INSTR_JMP_GT_HI: return NULL; 12157 12158 case INSTR_RETURN: return NULL; 12159 12160 default: return NULL; 12161 } 12162 } 12163 12164 static void 12165 action_instr_does_tx_codegen(struct action *a, 12166 uint32_t instr_pos, 12167 struct instruction *instr, 12168 FILE *f) 12169 { 12170 fprintf(f, 12171 "%s(p, t, &action_%s_instructions[%u]);\n" 12172 "\tthread_ip_reset(p, t);\n" 12173 "\tinstr_rx_exec(p);\n" 12174 "\treturn;\n", 12175 instr_type_to_func(instr), 12176 a->name, 12177 instr_pos); 12178 } 12179 12180 static void 12181 action_instr_extern_obj_codegen(struct action *a, 12182 uint32_t instr_pos, 12183 FILE *f) 12184 { 12185 fprintf(f, 12186 "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n", 12187 a->name, 12188 instr_pos); 12189 } 12190 12191 static void 12192 action_instr_extern_func_codegen(struct action *a, 12193 uint32_t instr_pos, 12194 FILE *f) 12195 { 12196 fprintf(f, 12197 "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n", 12198 a->name, 12199 instr_pos); 12200 } 12201 12202 static void 12203 action_instr_jmp_codegen(struct action *a, 12204 uint32_t instr_pos, 12205 struct instruction *instr, 12206 struct instruction_data *data, 12207 FILE *f) 12208 { 12209 switch (instr->type) { 12210 case INSTR_JMP: 12211 fprintf(f, 12212 "goto %s;\n", 12213 data->jmp_label); 12214 return; 12215 12216 case INSTR_JMP_VALID: 12217 fprintf(f, 12218 "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 12219 "\t\tgoto %s;\n", 12220 a->name, 12221 instr_pos, 12222 data->jmp_label); 12223 return; 12224 12225 case INSTR_JMP_INVALID: 12226 fprintf(f, 12227 "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 12228 "\t\tgoto %s;\n", 12229 a->name, 12230 instr_pos, 12231 data->jmp_label); 12232 return; 12233 12234 case INSTR_JMP_HIT: 12235 fprintf(f, 12236 "if (t->hit)\n" 12237 "\t\tgoto %s;\n", 12238 data->jmp_label); 12239 return; 12240 12241 case INSTR_JMP_MISS: 12242 fprintf(f, 12243 "if (!t->hit)\n" 12244 "\t\tgoto %s;\n", 12245 data->jmp_label); 12246 return; 12247 12248 case INSTR_JMP_ACTION_HIT: 12249 fprintf(f, 12250 "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n" 12251 "\t\tgoto %s;\n", 12252 a->name, 12253 instr_pos, 12254 data->jmp_label); 12255 return; 12256 12257 case INSTR_JMP_ACTION_MISS: 12258 fprintf(f, 12259 "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n" 12260 "\t\tgoto %s;\n", 12261 a->name, 12262 instr_pos, 12263 data->jmp_label); 12264 return; 12265 12266 case INSTR_JMP_EQ: 12267 fprintf(f, 12268 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 12269 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12270 "\t\tgoto %s;\n", 12271 a->name, 12272 instr_pos, 12273 a->name, 12274 instr_pos, 12275 data->jmp_label); 12276 return; 12277 12278 case INSTR_JMP_EQ_MH: 12279 fprintf(f, 12280 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 12281 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12282 "\t\tgoto %s;\n", 12283 a->name, 12284 instr_pos, 12285 a->name, 12286 instr_pos, 12287 data->jmp_label); 12288 return; 12289 12290 case INSTR_JMP_EQ_HM: 12291 fprintf(f, 12292 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 12293 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12294 "\t\tgoto %s;\n", 12295 a->name, 12296 instr_pos, 12297 a->name, 12298 instr_pos, 12299 data->jmp_label); 12300 return; 12301 12302 case INSTR_JMP_EQ_HH: 12303 fprintf(f, 12304 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 12305 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12306 "\t\tgoto %s;\n", 12307 a->name, 12308 instr_pos, 12309 a->name, 12310 instr_pos, 12311 data->jmp_label); 12312 return; 12313 12314 case INSTR_JMP_EQ_I: 12315 fprintf(f, 12316 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 12317 "action_%s_instructions[%u].jmp.b_val)\n" 12318 "\t\tgoto %s;\n", 12319 a->name, 12320 instr_pos, 12321 a->name, 12322 instr_pos, 12323 data->jmp_label); 12324 return; 12325 12326 case INSTR_JMP_NEQ: 12327 fprintf(f, 12328 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 12329 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12330 "\t\tgoto %s;\n", 12331 a->name, 12332 instr_pos, 12333 a->name, 12334 instr_pos, 12335 data->jmp_label); 12336 return; 12337 12338 case INSTR_JMP_NEQ_MH: 12339 fprintf(f, 12340 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 12341 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12342 "\t\tgoto %s;\n", 12343 a->name, 12344 instr_pos, 12345 a->name, 12346 instr_pos, 12347 data->jmp_label); 12348 return; 12349 12350 case INSTR_JMP_NEQ_HM: 12351 fprintf(f, 12352 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 12353 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12354 "\t\tgoto %s;\n", 12355 a->name, 12356 instr_pos, 12357 a->name, 12358 instr_pos, 12359 data->jmp_label); 12360 return; 12361 12362 case INSTR_JMP_NEQ_HH: 12363 fprintf(f, 12364 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 12365 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12366 "\t\tgoto %s;\n", 12367 a->name, 12368 instr_pos, 12369 a->name, 12370 instr_pos, 12371 data->jmp_label); 12372 return; 12373 12374 case INSTR_JMP_NEQ_I: 12375 fprintf(f, 12376 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 12377 "action_%s_instructions[%u].jmp.b_val)\n" 12378 "\t\tgoto %s;\n", 12379 a->name, 12380 instr_pos, 12381 a->name, 12382 instr_pos, 12383 data->jmp_label); 12384 return; 12385 12386 case INSTR_JMP_LT: 12387 fprintf(f, 12388 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 12389 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12390 "\t\tgoto %s;\n", 12391 a->name, 12392 instr_pos, 12393 a->name, 12394 instr_pos, 12395 data->jmp_label); 12396 return; 12397 12398 case INSTR_JMP_LT_MH: 12399 fprintf(f, 12400 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 12401 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12402 "\t\tgoto %s;\n", 12403 a->name, 12404 instr_pos, 12405 a->name, 12406 instr_pos, 12407 data->jmp_label); 12408 return; 12409 12410 case INSTR_JMP_LT_HM: 12411 fprintf(f, 12412 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 12413 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12414 "\t\tgoto %s;\n", 12415 a->name, 12416 instr_pos, 12417 a->name, 12418 instr_pos, 12419 data->jmp_label); 12420 return; 12421 12422 case INSTR_JMP_LT_HH: 12423 fprintf(f, 12424 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 12425 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12426 "\t\tgoto %s;\n", 12427 a->name, 12428 instr_pos, 12429 a->name, 12430 instr_pos, 12431 data->jmp_label); 12432 return; 12433 12434 case INSTR_JMP_LT_MI: 12435 fprintf(f, 12436 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 12437 "action_%s_instructions[%u].jmp.b_val)\n" 12438 "\t\tgoto %s;\n", 12439 a->name, 12440 instr_pos, 12441 a->name, 12442 instr_pos, 12443 data->jmp_label); 12444 return; 12445 12446 case INSTR_JMP_LT_HI: 12447 fprintf(f, 12448 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 12449 "action_%s_instructions[%u].jmp.b_val)\n" 12450 "\t\tgoto %s;\n", 12451 a->name, 12452 instr_pos, 12453 a->name, 12454 instr_pos, 12455 data->jmp_label); 12456 return; 12457 12458 case INSTR_JMP_GT: 12459 fprintf(f, 12460 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 12461 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12462 "\t\tgoto %s;\n", 12463 a->name, 12464 instr_pos, 12465 a->name, 12466 instr_pos, 12467 data->jmp_label); 12468 return; 12469 12470 case INSTR_JMP_GT_MH: 12471 fprintf(f, 12472 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 12473 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12474 "\t\tgoto %s;\n", 12475 a->name, 12476 instr_pos, 12477 a->name, 12478 instr_pos, 12479 data->jmp_label); 12480 return; 12481 12482 case INSTR_JMP_GT_HM: 12483 fprintf(f, 12484 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 12485 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 12486 "\t\tgoto %s;\n", 12487 a->name, 12488 instr_pos, 12489 a->name, 12490 instr_pos, 12491 data->jmp_label); 12492 return; 12493 12494 case INSTR_JMP_GT_HH: 12495 fprintf(f, 12496 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 12497 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 12498 "\t\tgoto %s;\n", 12499 a->name, 12500 instr_pos, 12501 a->name, 12502 instr_pos, 12503 data->jmp_label); 12504 return; 12505 12506 case INSTR_JMP_GT_MI: 12507 fprintf(f, 12508 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 12509 "action_%s_instructions[%u].jmp.b_val)\n" 12510 "\t\tgoto %s;\n", 12511 a->name, 12512 instr_pos, 12513 a->name, 12514 instr_pos, 12515 data->jmp_label); 12516 return; 12517 12518 case INSTR_JMP_GT_HI: 12519 fprintf(f, 12520 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 12521 "action_%s_instructions[%u].jmp.b_val)\n" 12522 "\t\tgoto %s;\n", 12523 a->name, 12524 instr_pos, 12525 a->name, 12526 instr_pos, 12527 data->jmp_label); 12528 return; 12529 12530 default: 12531 return; 12532 } 12533 } 12534 12535 static void 12536 action_instr_return_codegen(FILE *f) 12537 { 12538 fprintf(f, 12539 "return;\n"); 12540 } 12541 12542 static void 12543 action_instr_codegen(struct action *a, FILE *f) 12544 { 12545 uint32_t i; 12546 12547 fprintf(f, 12548 "void\n" 12549 "action_%s_run(struct rte_swx_pipeline *p)\n" 12550 "{\n" 12551 "\tstruct thread *t = &p->threads[p->thread_id];\n" 12552 "\n", 12553 a->name); 12554 12555 for (i = 0; i < a->n_instructions; i++) { 12556 struct instruction *instr = &a->instructions[i]; 12557 struct instruction_data *data = &a->instruction_data[i]; 12558 12559 /* Label, if present. */ 12560 if (data->label[0]) 12561 fprintf(f, "\n%s : ", data->label); 12562 else 12563 fprintf(f, "\n\t"); 12564 12565 /* TX instruction type. */ 12566 if (instruction_does_tx(instr)) { 12567 action_instr_does_tx_codegen(a, i, instr, f); 12568 continue; 12569 } 12570 12571 /* Extern object/function instruction type. */ 12572 if (instr->type == INSTR_EXTERN_OBJ) { 12573 action_instr_extern_obj_codegen(a, i, f); 12574 continue; 12575 } 12576 12577 if (instr->type == INSTR_EXTERN_FUNC) { 12578 action_instr_extern_func_codegen(a, i, f); 12579 continue; 12580 } 12581 12582 /* Jump instruction type. */ 12583 if (instruction_is_jmp(instr)) { 12584 action_instr_jmp_codegen(a, i, instr, data, f); 12585 continue; 12586 } 12587 12588 /* Return instruction type. */ 12589 if (instr->type == INSTR_RETURN) { 12590 action_instr_return_codegen(f); 12591 continue; 12592 } 12593 12594 /* Any other instruction type. */ 12595 fprintf(f, 12596 "%s(p, t, &action_%s_instructions[%u]);\n", 12597 instr_type_to_func(instr), 12598 a->name, 12599 i); 12600 } 12601 12602 fprintf(f, "}\n\n"); 12603 } 12604 12605 struct instruction_group { 12606 TAILQ_ENTRY(instruction_group) node; 12607 12608 uint32_t group_id; 12609 12610 uint32_t first_instr_id; 12611 12612 uint32_t last_instr_id; 12613 12614 instr_exec_t func; 12615 }; 12616 12617 TAILQ_HEAD(instruction_group_list, instruction_group); 12618 12619 static struct instruction_group * 12620 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id) 12621 { 12622 struct instruction_group *g; 12623 12624 TAILQ_FOREACH(g, igl, node) 12625 if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id)) 12626 return g; 12627 12628 return NULL; 12629 } 12630 12631 static void 12632 instruction_group_list_free(struct instruction_group_list *igl) 12633 { 12634 if (!igl) 12635 return; 12636 12637 for ( ; ; ) { 12638 struct instruction_group *g; 12639 12640 g = TAILQ_FIRST(igl); 12641 if (!g) 12642 break; 12643 12644 TAILQ_REMOVE(igl, g, node); 12645 free(g); 12646 } 12647 12648 free(igl); 12649 } 12650 12651 static struct instruction_group_list * 12652 instruction_group_list_create(struct rte_swx_pipeline *p) 12653 { 12654 struct instruction_group_list *igl = NULL; 12655 struct instruction_group *g = NULL; 12656 uint32_t n_groups = 0, i; 12657 12658 if (!p || !p->instructions || !p->instruction_data || !p->n_instructions) 12659 goto error; 12660 12661 /* List init. */ 12662 igl = calloc(1, sizeof(struct instruction_group_list)); 12663 if (!igl) 12664 goto error; 12665 12666 TAILQ_INIT(igl); 12667 12668 /* Allocate the first group. */ 12669 g = calloc(1, sizeof(struct instruction_group)); 12670 if (!g) 12671 goto error; 12672 12673 /* Iteration 1: Separate the instructions into groups based on the thread yield 12674 * instructions. Do not worry about the jump instructions at this point. 12675 */ 12676 for (i = 0; i < p->n_instructions; i++) { 12677 struct instruction *instr = &p->instructions[i]; 12678 12679 /* Check for thread yield instructions. */ 12680 if (!instruction_does_thread_yield(instr)) 12681 continue; 12682 12683 /* If the current group contains at least one instruction, then finalize it (with 12684 * the previous instruction), add it to the list and allocate a new group (that 12685 * starts with the current instruction). 12686 */ 12687 if (i - g->first_instr_id) { 12688 /* Finalize the group. */ 12689 g->last_instr_id = i - 1; 12690 12691 /* Add the group to the list. Advance the number of groups. */ 12692 TAILQ_INSERT_TAIL(igl, g, node); 12693 n_groups++; 12694 12695 /* Allocate a new group. */ 12696 g = calloc(1, sizeof(struct instruction_group)); 12697 if (!g) 12698 goto error; 12699 12700 /* Initialize the new group. */ 12701 g->group_id = n_groups; 12702 g->first_instr_id = i; 12703 } 12704 12705 /* Finalize the current group (with the current instruction, therefore this group 12706 * contains just the current thread yield instruction), add it to the list and 12707 * allocate a new group (that starts with the next instruction). 12708 */ 12709 12710 /* Finalize the group. */ 12711 g->last_instr_id = i; 12712 12713 /* Add the group to the list. Advance the number of groups. */ 12714 TAILQ_INSERT_TAIL(igl, g, node); 12715 n_groups++; 12716 12717 /* Allocate a new group. */ 12718 g = calloc(1, sizeof(struct instruction_group)); 12719 if (!g) 12720 goto error; 12721 12722 /* Initialize the new group. */ 12723 g->group_id = n_groups; 12724 g->first_instr_id = i + 1; 12725 } 12726 12727 /* Handle the last group. */ 12728 if (i - g->first_instr_id) { 12729 /* Finalize the group. */ 12730 g->last_instr_id = i - 1; 12731 12732 /* Add the group to the list. Advance the number of groups. */ 12733 TAILQ_INSERT_TAIL(igl, g, node); 12734 n_groups++; 12735 } else 12736 free(g); 12737 12738 g = NULL; 12739 12740 /* Iteration 2: Handle jumps. If the current group contains an instruction which represents 12741 * the destination of a jump instruction located in a different group ("far jump"), then the 12742 * current group has to be split, so that the instruction representing the far jump 12743 * destination is at the start of its group. 12744 */ 12745 for ( ; ; ) { 12746 int is_modified = 0; 12747 12748 for (i = 0; i < p->n_instructions; i++) { 12749 struct instruction_data *data = &p->instruction_data[i]; 12750 struct instruction_group *g; 12751 uint32_t j; 12752 12753 /* Continue when the current instruction is not a jump destination. */ 12754 if (!data->n_users) 12755 continue; 12756 12757 g = instruction_group_list_group_find(igl, i); 12758 if (!g) 12759 goto error; 12760 12761 /* Find out all the jump instructions with this destination. */ 12762 for (j = 0; j < p->n_instructions; j++) { 12763 struct instruction *jmp_instr = &p->instructions[j]; 12764 struct instruction_data *jmp_data = &p->instruction_data[j]; 12765 struct instruction_group *jmp_g, *new_g; 12766 12767 /* Continue when not a jump instruction. Even when jump instruction, 12768 * continue when the jump destination is not this instruction. 12769 */ 12770 if (!instruction_is_jmp(jmp_instr) || 12771 strcmp(jmp_data->jmp_label, data->label)) 12772 continue; 12773 12774 jmp_g = instruction_group_list_group_find(igl, j); 12775 if (!jmp_g) 12776 goto error; 12777 12778 /* Continue when both the jump instruction and the jump destination 12779 * instruction are in the same group. Even when in different groups, 12780 * still continue if the jump destination instruction is already the 12781 * first instruction of its group. 12782 */ 12783 if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i)) 12784 continue; 12785 12786 /* Split the group of the current jump destination instruction to 12787 * make this instruction the first instruction of a new group. 12788 */ 12789 new_g = calloc(1, sizeof(struct instruction_group)); 12790 if (!new_g) 12791 goto error; 12792 12793 new_g->group_id = n_groups; 12794 new_g->first_instr_id = i; 12795 new_g->last_instr_id = g->last_instr_id; 12796 12797 g->last_instr_id = i - 1; 12798 12799 TAILQ_INSERT_AFTER(igl, g, new_g, node); 12800 n_groups++; 12801 is_modified = 1; 12802 12803 /* The decision to split this group (to make the current instruction 12804 * the first instruction of a new group) is already taken and fully 12805 * implemented, so no need to search for more reasons to do it. 12806 */ 12807 break; 12808 } 12809 } 12810 12811 /* Re-evaluate everything, as at least one group got split, so some jumps that were 12812 * previously considered local (i.e. the jump destination is in the same group as 12813 * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a 12814 * different group than the jump instruction). Wost case scenario: each instruction 12815 * that is a jump destination ends up as the first instruction of its group. 12816 */ 12817 if (!is_modified) 12818 break; 12819 } 12820 12821 /* Re-assign the group IDs to be in incremental order. */ 12822 i = 0; 12823 TAILQ_FOREACH(g, igl, node) { 12824 g->group_id = i; 12825 12826 i++; 12827 } 12828 12829 return igl; 12830 12831 error: 12832 instruction_group_list_free(igl); 12833 12834 free(g); 12835 12836 return NULL; 12837 } 12838 12839 static void 12840 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused, 12841 uint32_t instr_pos, 12842 struct instruction *instr, 12843 FILE *f) 12844 { 12845 fprintf(f, 12846 "%s(p, t, &pipeline_instructions[%u]);\n" 12847 "\tthread_ip_reset(p, t);\n" 12848 "\tinstr_rx_exec(p);\n" 12849 "\treturn;\n", 12850 instr_type_to_func(instr), 12851 instr_pos); 12852 } 12853 12854 static int 12855 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p, 12856 struct instruction_group_list *igl, 12857 uint32_t jmp_instr_id, 12858 struct instruction *jmp_instr, 12859 struct instruction_data *jmp_data, 12860 FILE *f) 12861 { 12862 struct instruction_group *jmp_g, *g; 12863 struct instruction_data *data; 12864 uint32_t instr_id; 12865 12866 switch (jmp_instr->type) { 12867 case INSTR_JMP: 12868 break; 12869 12870 case INSTR_JMP_VALID: 12871 fprintf(f, 12872 "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 12873 jmp_instr_id); 12874 break; 12875 12876 case INSTR_JMP_INVALID: 12877 fprintf(f, 12878 "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 12879 jmp_instr_id); 12880 break; 12881 12882 case INSTR_JMP_HIT: 12883 fprintf(f, 12884 "if (t->hit)\n"); 12885 break; 12886 12887 case INSTR_JMP_MISS: 12888 fprintf(f, 12889 "if (!t->hit)\n"); 12890 break; 12891 12892 case INSTR_JMP_ACTION_HIT: 12893 fprintf(f, 12894 "if (t->action_id == pipeline_instructions[%u].jmp.action_id)", 12895 jmp_instr_id); 12896 break; 12897 12898 case INSTR_JMP_ACTION_MISS: 12899 fprintf(f, 12900 "if (t->action_id != pipeline_instructions[%u].jmp.action_id)", 12901 jmp_instr_id); 12902 break; 12903 12904 case INSTR_JMP_EQ: 12905 fprintf(f, 12906 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 12907 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12908 jmp_instr_id, 12909 jmp_instr_id); 12910 break; 12911 12912 case INSTR_JMP_EQ_MH: 12913 fprintf(f, 12914 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 12915 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12916 jmp_instr_id, 12917 jmp_instr_id); 12918 break; 12919 12920 case INSTR_JMP_EQ_HM: 12921 fprintf(f, 12922 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 12923 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12924 jmp_instr_id, 12925 jmp_instr_id); 12926 break; 12927 12928 case INSTR_JMP_EQ_HH: 12929 fprintf(f, 12930 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 12931 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12932 jmp_instr_id, 12933 jmp_instr_id); 12934 break; 12935 12936 case INSTR_JMP_EQ_I: 12937 fprintf(f, 12938 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 12939 "pipeline_instructions[%u].jmp.b_val)", 12940 jmp_instr_id, 12941 jmp_instr_id); 12942 break; 12943 12944 case INSTR_JMP_NEQ: 12945 fprintf(f, 12946 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 12947 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12948 jmp_instr_id, 12949 jmp_instr_id); 12950 break; 12951 12952 case INSTR_JMP_NEQ_MH: 12953 fprintf(f, 12954 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 12955 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12956 jmp_instr_id, 12957 jmp_instr_id); 12958 break; 12959 12960 case INSTR_JMP_NEQ_HM: 12961 fprintf(f, 12962 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 12963 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12964 jmp_instr_id, 12965 jmp_instr_id); 12966 break; 12967 12968 case INSTR_JMP_NEQ_HH: 12969 fprintf(f, 12970 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 12971 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12972 jmp_instr_id, 12973 jmp_instr_id); 12974 break; 12975 12976 case INSTR_JMP_NEQ_I: 12977 fprintf(f, 12978 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 12979 "pipeline_instructions[%u].jmp.b_val)", 12980 jmp_instr_id, 12981 jmp_instr_id); 12982 break; 12983 12984 case INSTR_JMP_LT: 12985 fprintf(f, 12986 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12987 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12988 jmp_instr_id, 12989 jmp_instr_id); 12990 break; 12991 12992 case INSTR_JMP_LT_MH: 12993 fprintf(f, 12994 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12995 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12996 jmp_instr_id, 12997 jmp_instr_id); 12998 break; 12999 13000 case INSTR_JMP_LT_HM: 13001 fprintf(f, 13002 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 13003 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 13004 jmp_instr_id, 13005 jmp_instr_id); 13006 break; 13007 13008 case INSTR_JMP_LT_HH: 13009 fprintf(f, 13010 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 13011 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 13012 jmp_instr_id, 13013 jmp_instr_id); 13014 break; 13015 13016 case INSTR_JMP_LT_MI: 13017 fprintf(f, 13018 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 13019 "pipeline_instructions[%u].jmp.b_val)", 13020 jmp_instr_id, 13021 jmp_instr_id); 13022 break; 13023 13024 case INSTR_JMP_LT_HI: 13025 fprintf(f, 13026 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 13027 "pipeline_instructions[%u].jmp.b_val)", 13028 jmp_instr_id, 13029 jmp_instr_id); 13030 break; 13031 13032 case INSTR_JMP_GT: 13033 fprintf(f, 13034 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 13035 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 13036 jmp_instr_id, 13037 jmp_instr_id); 13038 break; 13039 13040 case INSTR_JMP_GT_MH: 13041 fprintf(f, 13042 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 13043 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 13044 jmp_instr_id, 13045 jmp_instr_id); 13046 break; 13047 13048 case INSTR_JMP_GT_HM: 13049 fprintf(f, 13050 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 13051 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 13052 jmp_instr_id, 13053 jmp_instr_id); 13054 break; 13055 13056 case INSTR_JMP_GT_HH: 13057 fprintf(f, 13058 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 13059 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 13060 jmp_instr_id, 13061 jmp_instr_id); 13062 break; 13063 13064 case INSTR_JMP_GT_MI: 13065 fprintf(f, 13066 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 13067 "pipeline_instructions[%u].jmp.b_val)", 13068 jmp_instr_id, 13069 jmp_instr_id); 13070 break; 13071 13072 case INSTR_JMP_GT_HI: 13073 fprintf(f, 13074 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 13075 "pipeline_instructions[%u].jmp.b_val)", 13076 jmp_instr_id, 13077 jmp_instr_id); 13078 break; 13079 13080 default: 13081 break; 13082 } 13083 13084 /* Find the instruction group of the jump instruction. */ 13085 jmp_g = instruction_group_list_group_find(igl, jmp_instr_id); 13086 if (!jmp_g) 13087 return -EINVAL; 13088 13089 /* Find the instruction group of the jump destination instruction. */ 13090 data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label); 13091 if (!data) 13092 return -EINVAL; 13093 13094 instr_id = data - p->instruction_data; 13095 13096 g = instruction_group_list_group_find(igl, instr_id); 13097 if (!g) 13098 return -EINVAL; 13099 13100 /* Code generation for "near" jump (same instruction group) or "far" jump (different 13101 * instruction group). 13102 */ 13103 if (g->group_id == jmp_g->group_id) 13104 fprintf(f, 13105 "\n\t\tgoto %s;\n", 13106 jmp_data->jmp_label); 13107 else 13108 fprintf(f, 13109 " {\n" 13110 "\t\tthread_ip_set(t, &p->instructions[%u]);\n" 13111 "\t\treturn;\n" 13112 "\t}\n\n", 13113 g->group_id); 13114 13115 return 0; 13116 } 13117 13118 static void 13119 instruction_group_list_codegen(struct instruction_group_list *igl, 13120 struct rte_swx_pipeline *p, 13121 FILE *f) 13122 { 13123 struct instruction_group *g; 13124 uint32_t i; 13125 int is_required = 0; 13126 13127 /* Check if code generation is required. */ 13128 TAILQ_FOREACH(g, igl, node) 13129 if (g->first_instr_id < g->last_instr_id) 13130 is_required = 1; 13131 13132 if (!is_required) 13133 return; 13134 13135 /* Generate the code for the pipeline instruction array. */ 13136 fprintf(f, 13137 "static const struct instruction pipeline_instructions[] = {\n"); 13138 13139 for (i = 0; i < p->n_instructions; i++) { 13140 struct instruction *instr = &p->instructions[i]; 13141 instruction_export_t func = export_table[instr->type]; 13142 13143 func(instr, f); 13144 } 13145 13146 fprintf(f, "};\n\n"); 13147 13148 /* Generate the code for the pipeline functions: one function for each instruction group 13149 * that contains more than one instruction. 13150 */ 13151 TAILQ_FOREACH(g, igl, node) { 13152 struct instruction *last_instr; 13153 uint32_t j; 13154 13155 /* Skip if group contains a single instruction. */ 13156 if (g->last_instr_id == g->first_instr_id) 13157 continue; 13158 13159 /* Generate new pipeline function. */ 13160 fprintf(f, 13161 "void\n" 13162 "pipeline_func_%u(struct rte_swx_pipeline *p)\n" 13163 "{\n" 13164 "\tstruct thread *t = &p->threads[p->thread_id];\n" 13165 "\n", 13166 g->group_id); 13167 13168 /* Generate the code for each pipeline instruction. */ 13169 for (j = g->first_instr_id; j <= g->last_instr_id; j++) { 13170 struct instruction *instr = &p->instructions[j]; 13171 struct instruction_data *data = &p->instruction_data[j]; 13172 13173 /* Label, if present. */ 13174 if (data->label[0]) 13175 fprintf(f, "\n%s : ", data->label); 13176 else 13177 fprintf(f, "\n\t"); 13178 13179 /* TX instruction type. */ 13180 if (instruction_does_tx(instr)) { 13181 pipeline_instr_does_tx_codegen(p, j, instr, f); 13182 continue; 13183 } 13184 13185 /* Jump instruction type. */ 13186 if (instruction_is_jmp(instr)) { 13187 pipeline_instr_jmp_codegen(p, igl, j, instr, data, f); 13188 continue; 13189 } 13190 13191 /* Any other instruction type. */ 13192 fprintf(f, 13193 "%s(p, t, &pipeline_instructions[%u]);\n", 13194 instr_type_to_func(instr), 13195 j); 13196 } 13197 13198 /* Finalize the generated pipeline function. For some instructions such as TX, 13199 * emit-many-and-TX and unconditional jump, the next instruction has been already 13200 * decided unconditionally and the instruction pointer of the current thread set 13201 * accordingly; for all the other instructions, the instruction pointer must be 13202 * incremented now. 13203 */ 13204 last_instr = &p->instructions[g->last_instr_id]; 13205 13206 if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP)) 13207 fprintf(f, 13208 "thread_ip_inc(p);\n"); 13209 13210 fprintf(f, 13211 "}\n" 13212 "\n"); 13213 } 13214 } 13215 13216 static uint32_t 13217 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl) 13218 { 13219 struct instruction_group *g; 13220 uint32_t n_custom_instr = 0; 13221 13222 /* Groups with a single instruction: no function is generated for this group, the group 13223 * keeps its current instruction. Groups with more than two instructions: one function and 13224 * the associated custom instruction get generated for each such group. 13225 */ 13226 TAILQ_FOREACH(g, igl, node) { 13227 if (g->first_instr_id == g->last_instr_id) 13228 continue; 13229 13230 n_custom_instr++; 13231 } 13232 13233 return n_custom_instr; 13234 } 13235 13236 static int 13237 pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 13238 { 13239 struct action *a; 13240 FILE *f = NULL; 13241 13242 /* Create the .c file. */ 13243 f = fopen("/tmp/pipeline.c", "w"); 13244 if (!f) 13245 return -EIO; 13246 13247 /* Include the .h file. */ 13248 fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n"); 13249 13250 /* Add the code for each action. */ 13251 TAILQ_FOREACH(a, &p->actions, node) { 13252 fprintf(f, "/**\n * Action %s\n */\n\n", a->name); 13253 13254 action_data_codegen(a, f); 13255 13256 fprintf(f, "\n"); 13257 13258 action_instr_codegen(a, f); 13259 13260 fprintf(f, "\n"); 13261 } 13262 13263 /* Add the pipeline code. */ 13264 instruction_group_list_codegen(igl, p, f); 13265 13266 /* Close the .c file. */ 13267 fclose(f); 13268 13269 return 0; 13270 } 13271 13272 #ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE 13273 #define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096 13274 #endif 13275 13276 static int 13277 pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 13278 { 13279 struct action *a; 13280 struct instruction_group *g; 13281 char *dir_in, *buffer = NULL; 13282 const char *dir_out; 13283 int status = 0; 13284 13285 /* Get the environment variables. */ 13286 dir_in = getenv("RTE_INSTALL_DIR"); 13287 if (!dir_in) { 13288 status = -EINVAL; 13289 goto free; 13290 } 13291 13292 dir_out = "/tmp"; 13293 13294 /* Memory allocation for the command buffer. */ 13295 buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE); 13296 if (!buffer) { 13297 status = -ENOMEM; 13298 goto free; 13299 } 13300 13301 snprintf(buffer, 13302 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 13303 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c " 13304 "-I %s/lib/pipeline " 13305 "-I %s/lib/eal/include " 13306 "-I %s/lib/eal/x86/include " 13307 "-I %s/lib/eal/include/generic " 13308 "-I %s/lib/meter " 13309 "-I %s/lib/port " 13310 "-I %s/lib/table " 13311 "-I %s/lib/pipeline " 13312 "-I %s/config " 13313 "-I %s/build " 13314 "-I %s/lib/eal/linux/include " 13315 ">%s/pipeline.log 2>&1 " 13316 "&& " 13317 "gcc -shared %s/pipeline.o -o %s/libpipeline.so " 13318 ">>%s/pipeline.log 2>&1", 13319 dir_out, 13320 dir_out, 13321 dir_in, 13322 dir_in, 13323 dir_in, 13324 dir_in, 13325 dir_in, 13326 dir_in, 13327 dir_in, 13328 dir_in, 13329 dir_in, 13330 dir_in, 13331 dir_in, 13332 dir_out, 13333 dir_out, 13334 dir_out, 13335 dir_out); 13336 13337 /* Build the shared object library. */ 13338 status = system(buffer); 13339 if (status) 13340 goto free; 13341 13342 /* Open library. */ 13343 snprintf(buffer, 13344 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 13345 "%s/libpipeline.so", 13346 dir_out); 13347 13348 p->lib = dlopen(buffer, RTLD_LAZY); 13349 if (!p->lib) { 13350 status = -EIO; 13351 goto free; 13352 } 13353 13354 /* Get the action function symbols. */ 13355 TAILQ_FOREACH(a, &p->actions, node) { 13356 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name); 13357 13358 p->action_funcs[a->id] = dlsym(p->lib, buffer); 13359 if (!p->action_funcs[a->id]) { 13360 status = -EINVAL; 13361 goto free; 13362 } 13363 } 13364 13365 /* Get the pipeline function symbols. */ 13366 TAILQ_FOREACH(g, igl, node) { 13367 if (g->first_instr_id == g->last_instr_id) 13368 continue; 13369 13370 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id); 13371 13372 g->func = dlsym(p->lib, buffer); 13373 if (!g->func) { 13374 status = -EINVAL; 13375 goto free; 13376 } 13377 } 13378 13379 free: 13380 if (status && p->lib) { 13381 dlclose(p->lib); 13382 p->lib = NULL; 13383 } 13384 13385 free(buffer); 13386 13387 return status; 13388 } 13389 13390 static int 13391 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused, 13392 struct instruction_group_list *igl) 13393 { 13394 uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl); 13395 13396 /* Check that enough space is available within the pipeline instruction table to store all 13397 * the custom instructions. 13398 */ 13399 if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX) 13400 return -ENOSPC; 13401 13402 return 0; 13403 } 13404 13405 static void 13406 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 13407 { 13408 struct instruction_group *g; 13409 uint32_t i; 13410 13411 /* Pipeline table instructions. */ 13412 for (i = 0; i < p->n_instructions; i++) { 13413 struct instruction *instr = &p->instructions[i]; 13414 13415 if (instr->type == INSTR_TABLE) 13416 instr->type = INSTR_TABLE_AF; 13417 13418 if (instr->type == INSTR_LEARNER) 13419 instr->type = INSTR_LEARNER_AF; 13420 } 13421 13422 /* Pipeline custom instructions. */ 13423 i = 0; 13424 TAILQ_FOREACH(g, igl, node) { 13425 struct instruction *instr = &p->instructions[g->first_instr_id]; 13426 uint32_t j; 13427 13428 if (g->first_instr_id == g->last_instr_id) 13429 continue; 13430 13431 /* Install a new custom instruction. */ 13432 p->instruction_table[INSTR_CUSTOM_0 + i] = g->func; 13433 13434 /* First instruction of the group: change its type to the new custom instruction. */ 13435 instr->type = INSTR_CUSTOM_0 + i; 13436 13437 /* All the subsequent instructions of the group: invalidate. */ 13438 for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) { 13439 struct instruction_data *data = &p->instruction_data[j]; 13440 13441 data->invalid = 1; 13442 } 13443 13444 i++; 13445 } 13446 13447 /* Remove the invalidated instructions. */ 13448 p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions); 13449 13450 /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump 13451 * instructions that are the only instruction within their group, so they were left 13452 * unmodified). 13453 */ 13454 instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions); 13455 } 13456 13457 static int 13458 pipeline_compile(struct rte_swx_pipeline *p) 13459 { 13460 struct instruction_group_list *igl = NULL; 13461 int status = 0; 13462 13463 igl = instruction_group_list_create(p); 13464 if (!igl) { 13465 status = -ENOMEM; 13466 goto free; 13467 } 13468 13469 /* Code generation. */ 13470 status = pipeline_codegen(p, igl); 13471 if (status) 13472 goto free; 13473 13474 /* Build and load the shared object library. */ 13475 status = pipeline_libload(p, igl); 13476 if (status) 13477 goto free; 13478 13479 /* Adjust instructions. */ 13480 status = pipeline_adjust_check(p, igl); 13481 if (status) 13482 goto free; 13483 13484 pipeline_adjust(p, igl); 13485 13486 free: 13487 instruction_group_list_free(igl); 13488 13489 return status; 13490 } 13491