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