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