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