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