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