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