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 p->table_stats = NULL; 8669 } 8670 } 8671 8672 static void 8673 table_free(struct rte_swx_pipeline *p) 8674 { 8675 table_build_free(p); 8676 8677 /* Tables. */ 8678 for ( ; ; ) { 8679 struct table *elem; 8680 8681 elem = TAILQ_FIRST(&p->tables); 8682 if (!elem) 8683 break; 8684 8685 TAILQ_REMOVE(&p->tables, elem, node); 8686 free(elem->fields); 8687 free(elem->actions); 8688 free(elem->default_action_data); 8689 free(elem); 8690 } 8691 8692 /* Table types. */ 8693 for ( ; ; ) { 8694 struct table_type *elem; 8695 8696 elem = TAILQ_FIRST(&p->table_types); 8697 if (!elem) 8698 break; 8699 8700 TAILQ_REMOVE(&p->table_types, elem, node); 8701 free(elem); 8702 } 8703 } 8704 8705 /* 8706 * Selector. 8707 */ 8708 static struct selector * 8709 selector_find(struct rte_swx_pipeline *p, const char *name) 8710 { 8711 struct selector *s; 8712 8713 TAILQ_FOREACH(s, &p->selectors, node) 8714 if (strcmp(s->name, name) == 0) 8715 return s; 8716 8717 return NULL; 8718 } 8719 8720 static struct selector * 8721 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8722 { 8723 struct selector *s = NULL; 8724 8725 TAILQ_FOREACH(s, &p->selectors, node) 8726 if (s->id == id) 8727 return s; 8728 8729 return NULL; 8730 } 8731 8732 static int 8733 selector_fields_check(struct rte_swx_pipeline *p, 8734 struct rte_swx_pipeline_selector_params *params, 8735 struct header **header) 8736 { 8737 struct header *h0 = NULL; 8738 struct field *hf, *mf; 8739 uint32_t i; 8740 8741 /* Return if no selector fields. */ 8742 if (!params->n_selector_fields || !params->selector_field_names) 8743 return -EINVAL; 8744 8745 /* Check that all the selector fields either belong to the same header 8746 * or are all meta-data fields. 8747 */ 8748 hf = header_field_parse(p, params->selector_field_names[0], &h0); 8749 mf = metadata_field_parse(p, params->selector_field_names[0]); 8750 if (!hf && !mf) 8751 return -EINVAL; 8752 8753 for (i = 1; i < params->n_selector_fields; i++) 8754 if (h0) { 8755 struct header *h; 8756 8757 hf = header_field_parse(p, params->selector_field_names[i], &h); 8758 if (!hf || (h->id != h0->id)) 8759 return -EINVAL; 8760 } else { 8761 mf = metadata_field_parse(p, params->selector_field_names[i]); 8762 if (!mf) 8763 return -EINVAL; 8764 } 8765 8766 /* Check that there are no duplicated match fields. */ 8767 for (i = 0; i < params->n_selector_fields; i++) { 8768 const char *field_name = params->selector_field_names[i]; 8769 uint32_t j; 8770 8771 for (j = i + 1; j < params->n_selector_fields; j++) 8772 if (!strcmp(params->selector_field_names[j], field_name)) 8773 return -EINVAL; 8774 } 8775 8776 /* Return. */ 8777 if (header) 8778 *header = h0; 8779 8780 return 0; 8781 } 8782 8783 int 8784 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p, 8785 const char *name, 8786 struct rte_swx_pipeline_selector_params *params) 8787 { 8788 struct selector *s; 8789 struct header *selector_header = NULL; 8790 struct field *group_id_field, *member_id_field; 8791 uint32_t i; 8792 int status = 0; 8793 8794 CHECK(p, EINVAL); 8795 8796 CHECK_NAME(name, EINVAL); 8797 CHECK(!table_find(p, name), EEXIST); 8798 CHECK(!selector_find(p, name), EEXIST); 8799 CHECK(!learner_find(p, name), EEXIST); 8800 8801 CHECK(params, EINVAL); 8802 8803 CHECK_NAME(params->group_id_field_name, EINVAL); 8804 group_id_field = metadata_field_parse(p, params->group_id_field_name); 8805 CHECK(group_id_field, EINVAL); 8806 8807 for (i = 0; i < params->n_selector_fields; i++) { 8808 const char *field_name = params->selector_field_names[i]; 8809 8810 CHECK_NAME(field_name, EINVAL); 8811 } 8812 status = selector_fields_check(p, params, &selector_header); 8813 if (status) 8814 return status; 8815 8816 CHECK_NAME(params->member_id_field_name, EINVAL); 8817 member_id_field = metadata_field_parse(p, params->member_id_field_name); 8818 CHECK(member_id_field, EINVAL); 8819 8820 CHECK(params->n_groups_max, EINVAL); 8821 8822 CHECK(params->n_members_per_group_max, EINVAL); 8823 8824 /* Memory allocation. */ 8825 s = calloc(1, sizeof(struct selector)); 8826 if (!s) { 8827 status = -ENOMEM; 8828 goto error; 8829 } 8830 8831 s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *)); 8832 if (!s->selector_fields) { 8833 status = -ENOMEM; 8834 goto error; 8835 } 8836 8837 /* Node initialization. */ 8838 strcpy(s->name, name); 8839 8840 s->group_id_field = group_id_field; 8841 8842 for (i = 0; i < params->n_selector_fields; i++) { 8843 const char *field_name = params->selector_field_names[i]; 8844 8845 s->selector_fields[i] = selector_header ? 8846 header_field_parse(p, field_name, NULL) : 8847 metadata_field_parse(p, field_name); 8848 } 8849 8850 s->n_selector_fields = params->n_selector_fields; 8851 8852 s->selector_header = selector_header; 8853 8854 s->member_id_field = member_id_field; 8855 8856 s->n_groups_max = params->n_groups_max; 8857 8858 s->n_members_per_group_max = params->n_members_per_group_max; 8859 8860 s->id = p->n_selectors; 8861 8862 /* Node add to tailq. */ 8863 TAILQ_INSERT_TAIL(&p->selectors, s, node); 8864 p->n_selectors++; 8865 8866 return 0; 8867 8868 error: 8869 if (!s) 8870 return status; 8871 8872 free(s->selector_fields); 8873 8874 free(s); 8875 8876 return status; 8877 } 8878 8879 static void 8880 selector_params_free(struct rte_swx_table_selector_params *params) 8881 { 8882 if (!params) 8883 return; 8884 8885 free(params->selector_mask); 8886 8887 free(params); 8888 } 8889 8890 static struct rte_swx_table_selector_params * 8891 selector_table_params_get(struct selector *s) 8892 { 8893 struct rte_swx_table_selector_params *params = NULL; 8894 struct field *first, *last; 8895 uint32_t i; 8896 8897 /* Memory allocation. */ 8898 params = calloc(1, sizeof(struct rte_swx_table_selector_params)); 8899 if (!params) 8900 goto error; 8901 8902 /* Group ID. */ 8903 params->group_id_offset = s->group_id_field->offset / 8; 8904 8905 /* Find first (smallest offset) and last (biggest offset) selector fields. */ 8906 first = s->selector_fields[0]; 8907 last = s->selector_fields[0]; 8908 8909 for (i = 0; i < s->n_selector_fields; i++) { 8910 struct field *f = s->selector_fields[i]; 8911 8912 if (f->offset < first->offset) 8913 first = f; 8914 8915 if (f->offset > last->offset) 8916 last = f; 8917 } 8918 8919 /* Selector offset and size. */ 8920 params->selector_offset = first->offset / 8; 8921 params->selector_size = (last->offset + last->n_bits - first->offset) / 8; 8922 8923 /* Memory allocation. */ 8924 params->selector_mask = calloc(1, params->selector_size); 8925 if (!params->selector_mask) 8926 goto error; 8927 8928 /* Selector mask. */ 8929 for (i = 0; i < s->n_selector_fields; i++) { 8930 struct field *f = s->selector_fields[i]; 8931 uint32_t start = (f->offset - first->offset) / 8; 8932 size_t size = f->n_bits / 8; 8933 8934 memset(¶ms->selector_mask[start], 0xFF, size); 8935 } 8936 8937 /* Member ID. */ 8938 params->member_id_offset = s->member_id_field->offset / 8; 8939 8940 /* Maximum number of groups. */ 8941 params->n_groups_max = s->n_groups_max; 8942 8943 /* Maximum number of members per group. */ 8944 params->n_members_per_group_max = s->n_members_per_group_max; 8945 8946 return params; 8947 8948 error: 8949 selector_params_free(params); 8950 return NULL; 8951 } 8952 8953 static void 8954 selector_build_free(struct rte_swx_pipeline *p) 8955 { 8956 uint32_t i; 8957 8958 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8959 struct thread *t = &p->threads[i]; 8960 uint32_t j; 8961 8962 if (!t->selectors) 8963 continue; 8964 8965 for (j = 0; j < p->n_selectors; j++) { 8966 struct selector_runtime *r = &t->selectors[j]; 8967 8968 free(r->mailbox); 8969 } 8970 8971 free(t->selectors); 8972 t->selectors = NULL; 8973 } 8974 8975 free(p->selector_stats); 8976 p->selector_stats = NULL; 8977 } 8978 8979 static int 8980 selector_build(struct rte_swx_pipeline *p) 8981 { 8982 uint32_t i; 8983 int status = 0; 8984 8985 /* Per pipeline: selector statistics. */ 8986 p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics)); 8987 if (!p->selector_stats) { 8988 status = -ENOMEM; 8989 goto error; 8990 } 8991 8992 /* Per thread: selector run-time. */ 8993 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8994 struct thread *t = &p->threads[i]; 8995 struct selector *s; 8996 8997 t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime)); 8998 if (!t->selectors) { 8999 status = -ENOMEM; 9000 goto error; 9001 } 9002 9003 TAILQ_FOREACH(s, &p->selectors, node) { 9004 struct selector_runtime *r = &t->selectors[s->id]; 9005 uint64_t size; 9006 9007 /* r->mailbox. */ 9008 size = rte_swx_table_selector_mailbox_size_get(); 9009 if (size) { 9010 r->mailbox = calloc(1, size); 9011 if (!r->mailbox) { 9012 status = -ENOMEM; 9013 goto error; 9014 } 9015 } 9016 9017 /* r->group_id_buffer. */ 9018 r->group_id_buffer = &t->structs[p->metadata_struct_id]; 9019 9020 /* r->selector_buffer. */ 9021 r->selector_buffer = s->selector_header ? 9022 &t->structs[s->selector_header->struct_id] : 9023 &t->structs[p->metadata_struct_id]; 9024 9025 /* r->member_id_buffer. */ 9026 r->member_id_buffer = &t->structs[p->metadata_struct_id]; 9027 } 9028 } 9029 9030 return 0; 9031 9032 error: 9033 selector_build_free(p); 9034 return status; 9035 } 9036 9037 static void 9038 selector_free(struct rte_swx_pipeline *p) 9039 { 9040 selector_build_free(p); 9041 9042 /* Selector tables. */ 9043 for ( ; ; ) { 9044 struct selector *elem; 9045 9046 elem = TAILQ_FIRST(&p->selectors); 9047 if (!elem) 9048 break; 9049 9050 TAILQ_REMOVE(&p->selectors, elem, node); 9051 free(elem->selector_fields); 9052 free(elem); 9053 } 9054 } 9055 9056 /* 9057 * Learner table. 9058 */ 9059 static struct learner * 9060 learner_find(struct rte_swx_pipeline *p, const char *name) 9061 { 9062 struct learner *l; 9063 9064 TAILQ_FOREACH(l, &p->learners, node) 9065 if (!strcmp(l->name, name)) 9066 return l; 9067 9068 return NULL; 9069 } 9070 9071 static struct learner * 9072 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 9073 { 9074 struct learner *l = NULL; 9075 9076 TAILQ_FOREACH(l, &p->learners, node) 9077 if (l->id == id) 9078 return l; 9079 9080 return NULL; 9081 } 9082 9083 static int 9084 learner_match_fields_check(struct rte_swx_pipeline *p, 9085 struct rte_swx_pipeline_learner_params *params, 9086 struct header **header) 9087 { 9088 struct header *h0 = NULL; 9089 struct field *hf, *mf; 9090 uint32_t *offset = NULL, *n_bits = NULL, n_fields_with_valid_next = 0, i; 9091 int status = 0; 9092 9093 /* Return if no match fields. */ 9094 if (!params->n_fields || !params->field_names) 9095 return -EINVAL; 9096 9097 /* Memory allocation. */ 9098 offset = calloc(params->n_fields, sizeof(uint32_t)); 9099 n_bits = calloc(params->n_fields, sizeof(uint32_t)); 9100 if (!offset || !n_bits) { 9101 status = -ENOMEM; 9102 goto end; 9103 } 9104 9105 /* Check that all the match fields either belong to the same header 9106 * or are all meta-data fields. 9107 */ 9108 hf = header_field_parse(p, params->field_names[0], &h0); 9109 mf = metadata_field_parse(p, params->field_names[0]); 9110 if ((!hf && !mf) || (hf && hf->var_size)) { 9111 status = -EINVAL; 9112 goto end; 9113 } 9114 9115 offset[0] = h0 ? hf->offset : mf->offset; 9116 n_bits[0] = h0 ? hf->n_bits : mf->n_bits; 9117 9118 for (i = 1; i < params->n_fields; i++) 9119 if (h0) { 9120 struct header *h; 9121 9122 hf = header_field_parse(p, params->field_names[i], &h); 9123 if (!hf || (h->id != h0->id) || hf->var_size) { 9124 status = -EINVAL; 9125 goto end; 9126 } 9127 9128 offset[i] = hf->offset; 9129 n_bits[i] = hf->n_bits; 9130 } else { 9131 mf = metadata_field_parse(p, params->field_names[i]); 9132 if (!mf) { 9133 status = -EINVAL; 9134 goto end; 9135 } 9136 9137 offset[i] = mf->offset; 9138 n_bits[i] = mf->n_bits; 9139 } 9140 9141 /* Check that there are no duplicated match fields. */ 9142 for (i = 0; i < params->n_fields; i++) { 9143 const char *field_name = params->field_names[i]; 9144 uint32_t j; 9145 9146 for (j = i + 1; j < params->n_fields; j++) 9147 if (!strcmp(params->field_names[j], field_name)) { 9148 status = -EINVAL; 9149 goto end; 9150 } 9151 } 9152 9153 /* Check that the match fields are contiguous. */ 9154 for (i = 0; i < params->n_fields; i++) { 9155 uint32_t offset_next = offset[i] + n_bits[i]; 9156 uint32_t j; 9157 9158 for (j = 0; j < params->n_fields; j++) 9159 if (offset[j] == offset_next) { 9160 n_fields_with_valid_next++; 9161 break; 9162 } 9163 } 9164 9165 if (n_fields_with_valid_next != params->n_fields - 1) { 9166 status = -EINVAL; 9167 goto end; 9168 } 9169 9170 /* Return. */ 9171 if (header) 9172 *header = h0; 9173 9174 end: 9175 free(offset); 9176 free(n_bits); 9177 return status; 9178 } 9179 9180 static int 9181 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name) 9182 { 9183 struct struct_type *mst = p->metadata_st, *ast = a->st; 9184 struct field *mf, *af; 9185 uint32_t mf_pos, i; 9186 9187 if (!ast) { 9188 if (mf_name) 9189 return -EINVAL; 9190 9191 return 0; 9192 } 9193 9194 /* Check that mf_name is the name of a valid meta-data field. */ 9195 CHECK_NAME(mf_name, EINVAL); 9196 mf = metadata_field_parse(p, mf_name); 9197 CHECK(mf, EINVAL); 9198 9199 /* Check that there are enough meta-data fields, starting with the mf_name field, to cover 9200 * all the action arguments. 9201 */ 9202 mf_pos = mf - mst->fields; 9203 CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL); 9204 9205 /* Check that the size of each of the identified meta-data fields matches exactly the size 9206 * of the corresponding action argument. 9207 */ 9208 for (i = 0; i < ast->n_fields; i++) { 9209 mf = &mst->fields[mf_pos + i]; 9210 af = &ast->fields[i]; 9211 9212 CHECK(mf->n_bits == af->n_bits, EINVAL); 9213 } 9214 9215 return 0; 9216 } 9217 9218 static int 9219 learner_action_learning_check(struct rte_swx_pipeline *p, 9220 struct action *action, 9221 const char **action_names, 9222 uint32_t n_actions) 9223 { 9224 uint32_t i; 9225 9226 /* For each "learn" instruction of the current action, check that the learned action (i.e. 9227 * the action passed as argument to the "learn" instruction) is also enabled for the 9228 * current learner table. 9229 */ 9230 for (i = 0; i < action->n_instructions; i++) { 9231 struct instruction *instr = &action->instructions[i]; 9232 uint32_t found = 0, j; 9233 9234 if (instr->type != INSTR_LEARNER_LEARN) 9235 continue; 9236 9237 for (j = 0; j < n_actions; j++) { 9238 struct action *a; 9239 9240 a = action_find(p, action_names[j]); 9241 if (!a) 9242 return -EINVAL; 9243 9244 if (a->id == instr->learn.action_id) 9245 found = 1; 9246 } 9247 9248 if (!found) 9249 return -EINVAL; 9250 } 9251 9252 return 0; 9253 } 9254 9255 int 9256 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, 9257 const char *name, 9258 struct rte_swx_pipeline_learner_params *params, 9259 uint32_t size, 9260 uint32_t *timeout, 9261 uint32_t n_timeouts) 9262 { 9263 struct learner *l = NULL; 9264 struct action *default_action; 9265 struct header *header = NULL; 9266 struct hash_func *hf = NULL; 9267 uint32_t action_data_size_max = 0, i; 9268 int status = 0; 9269 9270 CHECK(p, EINVAL); 9271 9272 CHECK_NAME(name, EINVAL); 9273 CHECK(!table_find(p, name), EEXIST); 9274 CHECK(!selector_find(p, name), EEXIST); 9275 CHECK(!learner_find(p, name), EEXIST); 9276 9277 CHECK(params, EINVAL); 9278 9279 /* Match checks. */ 9280 status = learner_match_fields_check(p, params, &header); 9281 if (status) 9282 return status; 9283 9284 /* Action checks. */ 9285 CHECK(params->n_actions, EINVAL); 9286 CHECK(params->action_names, EINVAL); 9287 for (i = 0; i < params->n_actions; i++) { 9288 const char *action_name = params->action_names[i]; 9289 struct action *a; 9290 uint32_t action_data_size; 9291 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 9292 9293 CHECK_NAME(action_name, EINVAL); 9294 9295 a = action_find(p, action_name); 9296 CHECK(a, EINVAL); 9297 9298 status = learner_action_learning_check(p, 9299 a, 9300 params->action_names, 9301 params->n_actions); 9302 if (status) 9303 return status; 9304 9305 action_data_size = a->st ? a->st->n_bits / 8 : 0; 9306 if (action_data_size > action_data_size_max) 9307 action_data_size_max = action_data_size; 9308 9309 if (params->action_is_for_table_entries) 9310 action_is_for_table_entries = params->action_is_for_table_entries[i]; 9311 if (params->action_is_for_default_entry) 9312 action_is_for_default_entry = params->action_is_for_default_entry[i]; 9313 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 9314 } 9315 9316 CHECK_NAME(params->default_action_name, EINVAL); 9317 for (i = 0; i < p->n_actions; i++) 9318 if (!strcmp(params->action_names[i], 9319 params->default_action_name)) 9320 break; 9321 CHECK(i < params->n_actions, EINVAL); 9322 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 9323 EINVAL); 9324 9325 default_action = action_find(p, params->default_action_name); 9326 CHECK((default_action->st && params->default_action_args) || !params->default_action_args, 9327 EINVAL); 9328 9329 /* Hash function checks. */ 9330 if (params->hash_func_name) { 9331 hf = hash_func_find(p, params->hash_func_name); 9332 CHECK(hf, EINVAL); 9333 } 9334 9335 /* Any other checks. */ 9336 CHECK(size, EINVAL); 9337 CHECK(timeout, EINVAL); 9338 CHECK(n_timeouts && (n_timeouts <= RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX), EINVAL); 9339 9340 /* Memory allocation. */ 9341 l = calloc(1, sizeof(struct learner)); 9342 if (!l) { 9343 status = -ENOMEM; 9344 goto error; 9345 } 9346 9347 l->fields = calloc(params->n_fields, sizeof(struct field *)); 9348 if (!l->fields) { 9349 status = -ENOMEM; 9350 goto error; 9351 } 9352 9353 l->actions = calloc(params->n_actions, sizeof(struct action *)); 9354 if (!l->actions) { 9355 status = -ENOMEM; 9356 goto error; 9357 } 9358 9359 if (action_data_size_max) { 9360 l->default_action_data = calloc(1, action_data_size_max); 9361 if (!l->default_action_data) { 9362 status = -ENOMEM; 9363 goto error; 9364 } 9365 } 9366 9367 l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 9368 if (!l->action_is_for_table_entries) { 9369 status = -ENOMEM; 9370 goto error; 9371 } 9372 9373 l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 9374 if (!l->action_is_for_default_entry) { 9375 status = -ENOMEM; 9376 goto error; 9377 } 9378 9379 /* Node initialization. */ 9380 strcpy(l->name, name); 9381 9382 for (i = 0; i < params->n_fields; i++) { 9383 const char *field_name = params->field_names[i]; 9384 9385 l->fields[i] = header ? 9386 header_field_parse(p, field_name, NULL) : 9387 metadata_field_parse(p, field_name); 9388 } 9389 9390 l->n_fields = params->n_fields; 9391 9392 l->header = header; 9393 9394 for (i = 0; i < params->n_actions; i++) { 9395 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 9396 9397 if (params->action_is_for_table_entries) 9398 action_is_for_table_entries = params->action_is_for_table_entries[i]; 9399 if (params->action_is_for_default_entry) 9400 action_is_for_default_entry = params->action_is_for_default_entry[i]; 9401 9402 l->actions[i] = action_find(p, params->action_names[i]); 9403 l->action_is_for_table_entries[i] = action_is_for_table_entries; 9404 l->action_is_for_default_entry[i] = action_is_for_default_entry; 9405 } 9406 9407 l->default_action = default_action; 9408 9409 if (default_action->st) { 9410 status = action_args_parse(default_action, 9411 params->default_action_args, 9412 l->default_action_data); 9413 if (status) 9414 goto error; 9415 } 9416 9417 l->n_actions = params->n_actions; 9418 9419 l->default_action_is_const = params->default_action_is_const; 9420 9421 l->action_data_size_max = action_data_size_max; 9422 9423 l->hf = hf; 9424 9425 l->size = size; 9426 9427 for (i = 0; i < n_timeouts; i++) 9428 l->timeout[i] = timeout[i]; 9429 9430 l->n_timeouts = n_timeouts; 9431 9432 l->id = p->n_learners; 9433 9434 /* Node add to tailq. */ 9435 TAILQ_INSERT_TAIL(&p->learners, l, node); 9436 p->n_learners++; 9437 9438 return 0; 9439 9440 error: 9441 if (!l) 9442 return status; 9443 9444 free(l->action_is_for_default_entry); 9445 free(l->action_is_for_table_entries); 9446 free(l->default_action_data); 9447 free(l->actions); 9448 free(l->fields); 9449 free(l); 9450 9451 return status; 9452 } 9453 9454 static uint32_t 9455 learner_params_offset_get(struct learner *l) 9456 { 9457 struct field *first; 9458 uint32_t i; 9459 9460 first = l->fields[0]; 9461 9462 for (i = 1; i < l->n_fields; i++) { 9463 struct field *f = l->fields[i]; 9464 9465 if (f->offset < first->offset) 9466 first = f; 9467 } 9468 9469 return first->offset / 8; 9470 } 9471 9472 static void 9473 learner_params_free(struct rte_swx_table_learner_params *params) 9474 { 9475 if (!params) 9476 return; 9477 9478 free(params->key_mask0); 9479 9480 free(params->key_timeout); 9481 9482 free(params); 9483 } 9484 9485 static struct rte_swx_table_learner_params * 9486 learner_params_get(struct learner *l) 9487 { 9488 struct rte_swx_table_learner_params *params = NULL; 9489 struct field *first, *last; 9490 uint32_t i; 9491 9492 /* Memory allocation. */ 9493 params = calloc(1, sizeof(struct rte_swx_table_learner_params)); 9494 if (!params) 9495 goto error; 9496 9497 /* Find first (smallest offset) and last (biggest offset) match fields. */ 9498 first = l->fields[0]; 9499 last = l->fields[0]; 9500 9501 for (i = 0; i < l->n_fields; i++) { 9502 struct field *f = l->fields[i]; 9503 9504 if (f->offset < first->offset) 9505 first = f; 9506 9507 if (f->offset > last->offset) 9508 last = f; 9509 } 9510 9511 /* Key offset and size. */ 9512 params->key_offset = first->offset / 8; 9513 params->key_size = (last->offset + last->n_bits - first->offset) / 8; 9514 9515 /* Memory allocation. */ 9516 params->key_mask0 = calloc(1, params->key_size); 9517 if (!params->key_mask0) 9518 goto error; 9519 9520 /* Key mask. */ 9521 for (i = 0; i < l->n_fields; i++) { 9522 struct field *f = l->fields[i]; 9523 uint32_t start = (f->offset - first->offset) / 8; 9524 size_t size = f->n_bits / 8; 9525 9526 memset(¶ms->key_mask0[start], 0xFF, size); 9527 } 9528 9529 /* Action data size. */ 9530 params->action_data_size = l->action_data_size_max; 9531 9532 /* Hash function. */ 9533 params->hash_func = l->hf ? l->hf->func : NULL; 9534 9535 /* Maximum number of keys. */ 9536 params->n_keys_max = l->size; 9537 9538 /* Memory allocation. */ 9539 params->key_timeout = calloc(l->n_timeouts, sizeof(uint32_t)); 9540 if (!params->key_timeout) 9541 goto error; 9542 9543 /* Timeout. */ 9544 for (i = 0; i < l->n_timeouts; i++) 9545 params->key_timeout[i] = l->timeout[i]; 9546 9547 params->n_key_timeouts = l->n_timeouts; 9548 9549 return params; 9550 9551 error: 9552 learner_params_free(params); 9553 return NULL; 9554 } 9555 9556 static void 9557 learner_build_free(struct rte_swx_pipeline *p) 9558 { 9559 uint32_t i; 9560 9561 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9562 struct thread *t = &p->threads[i]; 9563 uint32_t j; 9564 9565 if (!t->learners) 9566 continue; 9567 9568 for (j = 0; j < p->n_learners; j++) { 9569 struct learner_runtime *r = &t->learners[j]; 9570 9571 free(r->mailbox); 9572 } 9573 9574 free(t->learners); 9575 t->learners = NULL; 9576 } 9577 9578 if (p->learner_stats) { 9579 for (i = 0; i < p->n_learners; i++) 9580 free(p->learner_stats[i].n_pkts_action); 9581 9582 free(p->learner_stats); 9583 p->learner_stats = NULL; 9584 } 9585 } 9586 9587 static int 9588 learner_build(struct rte_swx_pipeline *p) 9589 { 9590 uint32_t i; 9591 int status = 0; 9592 9593 /* Per pipeline: learner statistics. */ 9594 p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics)); 9595 CHECK(p->learner_stats, ENOMEM); 9596 9597 for (i = 0; i < p->n_learners; i++) { 9598 p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 9599 CHECK(p->learner_stats[i].n_pkts_action, ENOMEM); 9600 } 9601 9602 /* Per thread: learner run-time. */ 9603 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9604 struct thread *t = &p->threads[i]; 9605 struct learner *l; 9606 9607 t->learners = calloc(p->n_learners, sizeof(struct learner_runtime)); 9608 if (!t->learners) { 9609 status = -ENOMEM; 9610 goto error; 9611 } 9612 9613 TAILQ_FOREACH(l, &p->learners, node) { 9614 struct learner_runtime *r = &t->learners[l->id]; 9615 uint64_t size; 9616 9617 /* r->mailbox. */ 9618 size = rte_swx_table_learner_mailbox_size_get(); 9619 if (size) { 9620 r->mailbox = calloc(1, size); 9621 if (!r->mailbox) { 9622 status = -ENOMEM; 9623 goto error; 9624 } 9625 } 9626 9627 /* r->key. */ 9628 r->key = l->header ? 9629 &t->structs[l->header->struct_id] : 9630 &t->structs[p->metadata_struct_id]; 9631 } 9632 } 9633 9634 return 0; 9635 9636 error: 9637 learner_build_free(p); 9638 return status; 9639 } 9640 9641 static void 9642 learner_free(struct rte_swx_pipeline *p) 9643 { 9644 learner_build_free(p); 9645 9646 /* Learner tables. */ 9647 for ( ; ; ) { 9648 struct learner *l; 9649 9650 l = TAILQ_FIRST(&p->learners); 9651 if (!l) 9652 break; 9653 9654 TAILQ_REMOVE(&p->learners, l, node); 9655 free(l->fields); 9656 free(l->actions); 9657 free(l->default_action_data); 9658 free(l); 9659 } 9660 } 9661 9662 /* 9663 * Table state. 9664 */ 9665 static int 9666 table_state_build(struct rte_swx_pipeline *p) 9667 { 9668 struct table *table; 9669 struct selector *s; 9670 struct learner *l; 9671 9672 p->table_state = calloc(p->n_tables + p->n_selectors + p->n_learners, 9673 sizeof(struct rte_swx_table_state)); 9674 CHECK(p->table_state, ENOMEM); 9675 9676 TAILQ_FOREACH(table, &p->tables, node) { 9677 struct rte_swx_table_state *ts = &p->table_state[table->id]; 9678 9679 if (table->type) { 9680 struct rte_swx_table_params *params; 9681 9682 /* ts->obj. */ 9683 params = table_params_get(table); 9684 CHECK(params, ENOMEM); 9685 9686 ts->obj = table->type->ops.create(params, 9687 NULL, 9688 table->args, 9689 p->numa_node); 9690 9691 table_params_free(params); 9692 CHECK(ts->obj, ENODEV); 9693 } 9694 9695 /* ts->default_action_data. */ 9696 if (table->action_data_size_max) { 9697 ts->default_action_data = 9698 malloc(table->action_data_size_max); 9699 CHECK(ts->default_action_data, ENOMEM); 9700 9701 memcpy(ts->default_action_data, 9702 table->default_action_data, 9703 table->action_data_size_max); 9704 } 9705 9706 /* ts->default_action_id. */ 9707 ts->default_action_id = table->default_action->id; 9708 } 9709 9710 TAILQ_FOREACH(s, &p->selectors, node) { 9711 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id]; 9712 struct rte_swx_table_selector_params *params; 9713 9714 /* ts->obj. */ 9715 params = selector_table_params_get(s); 9716 CHECK(params, ENOMEM); 9717 9718 ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node); 9719 9720 selector_params_free(params); 9721 CHECK(ts->obj, ENODEV); 9722 } 9723 9724 TAILQ_FOREACH(l, &p->learners, node) { 9725 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + 9726 p->n_selectors + l->id]; 9727 struct rte_swx_table_learner_params *params; 9728 9729 /* ts->obj. */ 9730 params = learner_params_get(l); 9731 CHECK(params, ENOMEM); 9732 9733 ts->obj = rte_swx_table_learner_create(params, p->numa_node); 9734 learner_params_free(params); 9735 CHECK(ts->obj, ENODEV); 9736 9737 /* ts->default_action_data. */ 9738 if (l->action_data_size_max) { 9739 ts->default_action_data = malloc(l->action_data_size_max); 9740 CHECK(ts->default_action_data, ENOMEM); 9741 9742 memcpy(ts->default_action_data, 9743 l->default_action_data, 9744 l->action_data_size_max); 9745 } 9746 9747 /* ts->default_action_id. */ 9748 ts->default_action_id = l->default_action->id; 9749 } 9750 9751 return 0; 9752 } 9753 9754 static void 9755 table_state_build_free(struct rte_swx_pipeline *p) 9756 { 9757 uint32_t i; 9758 9759 if (!p->table_state) 9760 return; 9761 9762 for (i = 0; i < p->n_tables; i++) { 9763 struct rte_swx_table_state *ts = &p->table_state[i]; 9764 struct table *table = table_find_by_id(p, i); 9765 9766 /* ts->obj. */ 9767 if (table->type && ts->obj) 9768 table->type->ops.free(ts->obj); 9769 9770 /* ts->default_action_data. */ 9771 free(ts->default_action_data); 9772 } 9773 9774 for (i = 0; i < p->n_selectors; i++) { 9775 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i]; 9776 9777 /* ts->obj. */ 9778 rte_swx_table_selector_free(ts->obj); 9779 } 9780 9781 for (i = 0; i < p->n_learners; i++) { 9782 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i]; 9783 9784 /* ts->obj. */ 9785 rte_swx_table_learner_free(ts->obj); 9786 9787 /* ts->default_action_data. */ 9788 free(ts->default_action_data); 9789 } 9790 9791 free(p->table_state); 9792 p->table_state = NULL; 9793 } 9794 9795 static void 9796 table_state_free(struct rte_swx_pipeline *p) 9797 { 9798 table_state_build_free(p); 9799 } 9800 9801 /* 9802 * Register array. 9803 */ 9804 static struct regarray * 9805 regarray_find(struct rte_swx_pipeline *p, const char *name) 9806 { 9807 struct regarray *elem; 9808 9809 TAILQ_FOREACH(elem, &p->regarrays, node) 9810 if (!strcmp(elem->name, name)) 9811 return elem; 9812 9813 return NULL; 9814 } 9815 9816 static struct regarray * 9817 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 9818 { 9819 struct regarray *elem = NULL; 9820 9821 TAILQ_FOREACH(elem, &p->regarrays, node) 9822 if (elem->id == id) 9823 return elem; 9824 9825 return NULL; 9826 } 9827 9828 int 9829 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p, 9830 const char *name, 9831 uint32_t size, 9832 uint64_t init_val) 9833 { 9834 struct regarray *r; 9835 9836 CHECK(p, EINVAL); 9837 9838 CHECK_NAME(name, EINVAL); 9839 CHECK(!regarray_find(p, name), EEXIST); 9840 9841 CHECK(size, EINVAL); 9842 size = rte_align32pow2(size); 9843 9844 /* Memory allocation. */ 9845 r = calloc(1, sizeof(struct regarray)); 9846 CHECK(r, ENOMEM); 9847 9848 /* Node initialization. */ 9849 strcpy(r->name, name); 9850 r->init_val = init_val; 9851 r->size = size; 9852 r->id = p->n_regarrays; 9853 9854 /* Node add to tailq. */ 9855 TAILQ_INSERT_TAIL(&p->regarrays, r, node); 9856 p->n_regarrays++; 9857 9858 return 0; 9859 } 9860 9861 static int 9862 regarray_build(struct rte_swx_pipeline *p) 9863 { 9864 struct regarray *regarray; 9865 9866 if (!p->n_regarrays) 9867 return 0; 9868 9869 p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime)); 9870 CHECK(p->regarray_runtime, ENOMEM); 9871 9872 TAILQ_FOREACH(regarray, &p->regarrays, node) { 9873 struct regarray_runtime *r = &p->regarray_runtime[regarray->id]; 9874 uint32_t i; 9875 9876 r->regarray = env_malloc(regarray->size * sizeof(uint64_t), 9877 RTE_CACHE_LINE_SIZE, 9878 p->numa_node); 9879 CHECK(r->regarray, ENOMEM); 9880 9881 if (regarray->init_val) 9882 for (i = 0; i < regarray->size; i++) 9883 r->regarray[i] = regarray->init_val; 9884 9885 r->size_mask = regarray->size - 1; 9886 } 9887 9888 return 0; 9889 } 9890 9891 static void 9892 regarray_build_free(struct rte_swx_pipeline *p) 9893 { 9894 uint32_t i; 9895 9896 if (!p->regarray_runtime) 9897 return; 9898 9899 for (i = 0; i < p->n_regarrays; i++) { 9900 struct regarray *regarray = regarray_find_by_id(p, i); 9901 struct regarray_runtime *r = &p->regarray_runtime[i]; 9902 9903 env_free(r->regarray, regarray->size * sizeof(uint64_t)); 9904 } 9905 9906 free(p->regarray_runtime); 9907 p->regarray_runtime = NULL; 9908 } 9909 9910 static void 9911 regarray_free(struct rte_swx_pipeline *p) 9912 { 9913 regarray_build_free(p); 9914 9915 for ( ; ; ) { 9916 struct regarray *elem; 9917 9918 elem = TAILQ_FIRST(&p->regarrays); 9919 if (!elem) 9920 break; 9921 9922 TAILQ_REMOVE(&p->regarrays, elem, node); 9923 free(elem); 9924 } 9925 } 9926 9927 /* 9928 * Meter array. 9929 */ 9930 static struct meter_profile * 9931 meter_profile_find(struct rte_swx_pipeline *p, const char *name) 9932 { 9933 struct meter_profile *elem; 9934 9935 TAILQ_FOREACH(elem, &p->meter_profiles, node) 9936 if (!strcmp(elem->name, name)) 9937 return elem; 9938 9939 return NULL; 9940 } 9941 9942 static struct metarray * 9943 metarray_find(struct rte_swx_pipeline *p, const char *name) 9944 { 9945 struct metarray *elem; 9946 9947 TAILQ_FOREACH(elem, &p->metarrays, node) 9948 if (!strcmp(elem->name, name)) 9949 return elem; 9950 9951 return NULL; 9952 } 9953 9954 static struct metarray * 9955 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 9956 { 9957 struct metarray *elem = NULL; 9958 9959 TAILQ_FOREACH(elem, &p->metarrays, node) 9960 if (elem->id == id) 9961 return elem; 9962 9963 return NULL; 9964 } 9965 9966 int 9967 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p, 9968 const char *name, 9969 uint32_t size) 9970 { 9971 struct metarray *m; 9972 9973 CHECK(p, EINVAL); 9974 9975 CHECK_NAME(name, EINVAL); 9976 CHECK(!metarray_find(p, name), EEXIST); 9977 9978 CHECK(size, EINVAL); 9979 size = rte_align32pow2(size); 9980 9981 /* Memory allocation. */ 9982 m = calloc(1, sizeof(struct metarray)); 9983 CHECK(m, ENOMEM); 9984 9985 /* Node initialization. */ 9986 strcpy(m->name, name); 9987 m->size = size; 9988 m->id = p->n_metarrays; 9989 9990 /* Node add to tailq. */ 9991 TAILQ_INSERT_TAIL(&p->metarrays, m, node); 9992 p->n_metarrays++; 9993 9994 return 0; 9995 } 9996 9997 struct meter_profile meter_profile_default = { 9998 .node = {0}, 9999 .name = "", 10000 .params = {0}, 10001 10002 .profile = { 10003 .cbs = 10000, 10004 .pbs = 10000, 10005 .cir_period = 1, 10006 .cir_bytes_per_period = 1, 10007 .pir_period = 1, 10008 .pir_bytes_per_period = 1, 10009 }, 10010 10011 .n_users = 0, 10012 }; 10013 10014 static void 10015 meter_init(struct meter *m) 10016 { 10017 memset(m, 0, sizeof(struct meter)); 10018 rte_meter_trtcm_config(&m->m, &meter_profile_default.profile); 10019 m->profile = &meter_profile_default; 10020 m->color_mask = RTE_COLOR_GREEN; 10021 10022 meter_profile_default.n_users++; 10023 } 10024 10025 static int 10026 metarray_build(struct rte_swx_pipeline *p) 10027 { 10028 struct metarray *m; 10029 10030 if (!p->n_metarrays) 10031 return 0; 10032 10033 p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime)); 10034 CHECK(p->metarray_runtime, ENOMEM); 10035 10036 TAILQ_FOREACH(m, &p->metarrays, node) { 10037 struct metarray_runtime *r = &p->metarray_runtime[m->id]; 10038 uint32_t i; 10039 10040 r->metarray = env_malloc(m->size * sizeof(struct meter), 10041 RTE_CACHE_LINE_SIZE, 10042 p->numa_node); 10043 CHECK(r->metarray, ENOMEM); 10044 10045 for (i = 0; i < m->size; i++) 10046 meter_init(&r->metarray[i]); 10047 10048 r->size_mask = m->size - 1; 10049 } 10050 10051 return 0; 10052 } 10053 10054 static void 10055 metarray_build_free(struct rte_swx_pipeline *p) 10056 { 10057 uint32_t i; 10058 10059 if (!p->metarray_runtime) 10060 return; 10061 10062 for (i = 0; i < p->n_metarrays; i++) { 10063 struct metarray *m = metarray_find_by_id(p, i); 10064 struct metarray_runtime *r = &p->metarray_runtime[i]; 10065 10066 env_free(r->metarray, m->size * sizeof(struct meter)); 10067 } 10068 10069 free(p->metarray_runtime); 10070 p->metarray_runtime = NULL; 10071 } 10072 10073 static void 10074 metarray_free(struct rte_swx_pipeline *p) 10075 { 10076 metarray_build_free(p); 10077 10078 /* Meter arrays. */ 10079 for ( ; ; ) { 10080 struct metarray *elem; 10081 10082 elem = TAILQ_FIRST(&p->metarrays); 10083 if (!elem) 10084 break; 10085 10086 TAILQ_REMOVE(&p->metarrays, elem, node); 10087 free(elem); 10088 } 10089 10090 /* Meter profiles. */ 10091 for ( ; ; ) { 10092 struct meter_profile *elem; 10093 10094 elem = TAILQ_FIRST(&p->meter_profiles); 10095 if (!elem) 10096 break; 10097 10098 TAILQ_REMOVE(&p->meter_profiles, elem, node); 10099 free(elem); 10100 } 10101 } 10102 10103 /* 10104 * Pipeline. 10105 */ 10106 10107 /* Global list of pipeline instances. */ 10108 TAILQ_HEAD(rte_swx_pipeline_list, rte_tailq_entry); 10109 10110 static struct rte_tailq_elem rte_swx_pipeline_tailq = { 10111 .name = "RTE_SWX_PIPELINE", 10112 }; 10113 10114 EAL_REGISTER_TAILQ(rte_swx_pipeline_tailq) 10115 10116 struct rte_swx_pipeline * 10117 rte_swx_pipeline_find(const char *name) 10118 { 10119 struct rte_swx_pipeline_list *pipeline_list; 10120 struct rte_tailq_entry *te = NULL; 10121 10122 if (!name || !name[0] || (strnlen(name, RTE_SWX_NAME_SIZE) >= RTE_SWX_NAME_SIZE)) 10123 return NULL; 10124 10125 pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list); 10126 10127 rte_mcfg_tailq_read_lock(); 10128 10129 TAILQ_FOREACH(te, pipeline_list, next) { 10130 struct rte_swx_pipeline *p = (struct rte_swx_pipeline *)te->data; 10131 10132 if (!strncmp(name, p->name, sizeof(p->name))) { 10133 rte_mcfg_tailq_read_unlock(); 10134 return p; 10135 } 10136 } 10137 10138 rte_mcfg_tailq_read_unlock(); 10139 return NULL; 10140 } 10141 10142 static int 10143 pipeline_register(struct rte_swx_pipeline *p) 10144 { 10145 struct rte_swx_pipeline_list *pipeline_list; 10146 struct rte_tailq_entry *te = NULL; 10147 10148 pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list); 10149 10150 rte_mcfg_tailq_write_lock(); 10151 10152 TAILQ_FOREACH(te, pipeline_list, next) { 10153 struct rte_swx_pipeline *pipeline = (struct rte_swx_pipeline *)te->data; 10154 10155 if (!strncmp(p->name, pipeline->name, sizeof(p->name))) { 10156 rte_mcfg_tailq_write_unlock(); 10157 return -EEXIST; 10158 } 10159 } 10160 10161 te = calloc(1, sizeof(struct rte_tailq_entry)); 10162 if (!te) { 10163 rte_mcfg_tailq_write_unlock(); 10164 return -ENOMEM; 10165 } 10166 10167 te->data = (void *)p; 10168 TAILQ_INSERT_TAIL(pipeline_list, te, next); 10169 rte_mcfg_tailq_write_unlock(); 10170 return 0; 10171 } 10172 10173 static void 10174 pipeline_unregister(struct rte_swx_pipeline *p) 10175 { 10176 struct rte_swx_pipeline_list *pipeline_list; 10177 struct rte_tailq_entry *te = NULL; 10178 10179 pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list); 10180 10181 rte_mcfg_tailq_write_lock(); 10182 10183 TAILQ_FOREACH(te, pipeline_list, next) { 10184 if (te->data == (void *)p) { 10185 TAILQ_REMOVE(pipeline_list, te, next); 10186 rte_mcfg_tailq_write_unlock(); 10187 free(te); 10188 return; 10189 } 10190 } 10191 10192 rte_mcfg_tailq_write_unlock(); 10193 } 10194 10195 void 10196 rte_swx_pipeline_free(struct rte_swx_pipeline *p) 10197 { 10198 void *lib; 10199 10200 if (!p) 10201 return; 10202 10203 if (p->name[0]) 10204 pipeline_unregister(p); 10205 10206 lib = p->lib; 10207 10208 free(p->instruction_data); 10209 free(p->instructions); 10210 10211 metarray_free(p); 10212 regarray_free(p); 10213 table_state_free(p); 10214 learner_free(p); 10215 selector_free(p); 10216 table_free(p); 10217 action_free(p); 10218 instruction_table_free(p); 10219 metadata_free(p); 10220 header_free(p); 10221 rss_free(p); 10222 hash_func_free(p); 10223 extern_func_free(p); 10224 extern_obj_free(p); 10225 mirroring_free(p); 10226 port_out_free(p); 10227 port_in_free(p); 10228 struct_free(p); 10229 10230 free(p); 10231 10232 if (lib) 10233 dlclose(lib); 10234 } 10235 10236 static int 10237 port_in_types_register(struct rte_swx_pipeline *p) 10238 { 10239 int status; 10240 10241 status = rte_swx_pipeline_port_in_type_register(p, 10242 "ethdev", 10243 &rte_swx_port_ethdev_reader_ops); 10244 if (status) 10245 return status; 10246 10247 status = rte_swx_pipeline_port_in_type_register(p, 10248 "ring", 10249 &rte_swx_port_ring_reader_ops); 10250 if (status) 10251 return status; 10252 10253 #ifdef RTE_PORT_PCAP 10254 status = rte_swx_pipeline_port_in_type_register(p, 10255 "source", 10256 &rte_swx_port_source_ops); 10257 if (status) 10258 return status; 10259 #endif 10260 10261 status = rte_swx_pipeline_port_in_type_register(p, 10262 "fd", 10263 &rte_swx_port_fd_reader_ops); 10264 if (status) 10265 return status; 10266 10267 return 0; 10268 } 10269 10270 static int 10271 port_out_types_register(struct rte_swx_pipeline *p) 10272 { 10273 int status; 10274 10275 status = rte_swx_pipeline_port_out_type_register(p, 10276 "ethdev", 10277 &rte_swx_port_ethdev_writer_ops); 10278 if (status) 10279 return status; 10280 10281 status = rte_swx_pipeline_port_out_type_register(p, 10282 "ring", 10283 &rte_swx_port_ring_writer_ops); 10284 if (status) 10285 return status; 10286 10287 status = rte_swx_pipeline_port_out_type_register(p, 10288 "sink", 10289 &rte_swx_port_sink_ops); 10290 if (status) 10291 return status; 10292 10293 status = rte_swx_pipeline_port_out_type_register(p, 10294 "fd", 10295 &rte_swx_port_fd_writer_ops); 10296 if (status) 10297 return status; 10298 10299 return 0; 10300 } 10301 10302 static int 10303 table_types_register(struct rte_swx_pipeline *p) 10304 { 10305 int status; 10306 10307 status = rte_swx_pipeline_table_type_register(p, 10308 "exact", 10309 RTE_SWX_TABLE_MATCH_EXACT, 10310 &rte_swx_table_exact_match_ops); 10311 if (status) 10312 return status; 10313 10314 status = rte_swx_pipeline_table_type_register(p, 10315 "wildcard", 10316 RTE_SWX_TABLE_MATCH_WILDCARD, 10317 &rte_swx_table_wildcard_match_ops); 10318 if (status) 10319 return status; 10320 10321 return 0; 10322 } 10323 10324 static int 10325 hash_funcs_register(struct rte_swx_pipeline *p) 10326 { 10327 int status; 10328 10329 status = rte_swx_pipeline_hash_func_register(p, "jhash", rte_jhash); 10330 if (status) 10331 return status; 10332 10333 status = rte_swx_pipeline_hash_func_register(p, "crc32", rte_hash_crc); 10334 if (status) 10335 return status; 10336 10337 return 0; 10338 } 10339 10340 int 10341 rte_swx_pipeline_config(struct rte_swx_pipeline **p, const char *name, int numa_node) 10342 { 10343 struct rte_swx_pipeline *pipeline = NULL; 10344 int status = 0; 10345 10346 /* Check input parameters. */ 10347 CHECK(p, EINVAL); 10348 CHECK(!name || (strnlen(name, RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), EINVAL); 10349 10350 /* Memory allocation. */ 10351 pipeline = calloc(1, sizeof(struct rte_swx_pipeline)); 10352 if (!pipeline) { 10353 status = -ENOMEM; 10354 goto error; 10355 } 10356 10357 /* Initialization. */ 10358 if (name) 10359 strcpy(pipeline->name, name); 10360 10361 TAILQ_INIT(&pipeline->struct_types); 10362 TAILQ_INIT(&pipeline->port_in_types); 10363 TAILQ_INIT(&pipeline->ports_in); 10364 TAILQ_INIT(&pipeline->port_out_types); 10365 TAILQ_INIT(&pipeline->ports_out); 10366 TAILQ_INIT(&pipeline->extern_types); 10367 TAILQ_INIT(&pipeline->extern_objs); 10368 TAILQ_INIT(&pipeline->extern_funcs); 10369 TAILQ_INIT(&pipeline->hash_funcs); 10370 TAILQ_INIT(&pipeline->rss); 10371 TAILQ_INIT(&pipeline->headers); 10372 TAILQ_INIT(&pipeline->actions); 10373 TAILQ_INIT(&pipeline->table_types); 10374 TAILQ_INIT(&pipeline->tables); 10375 TAILQ_INIT(&pipeline->selectors); 10376 TAILQ_INIT(&pipeline->learners); 10377 TAILQ_INIT(&pipeline->regarrays); 10378 TAILQ_INIT(&pipeline->meter_profiles); 10379 TAILQ_INIT(&pipeline->metarrays); 10380 10381 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */ 10382 pipeline->n_mirroring_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT; 10383 pipeline->n_mirroring_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT; 10384 pipeline->numa_node = numa_node; 10385 10386 status = port_in_types_register(pipeline); 10387 if (status) 10388 goto error; 10389 10390 status = port_out_types_register(pipeline); 10391 if (status) 10392 goto error; 10393 10394 status = table_types_register(pipeline); 10395 if (status) 10396 goto error; 10397 10398 status = hash_funcs_register(pipeline); 10399 if (status) 10400 goto error; 10401 10402 if (pipeline->name[0]) { 10403 status = pipeline_register(pipeline); 10404 if (status) 10405 goto error; 10406 } 10407 10408 *p = pipeline; 10409 return 0; 10410 10411 error: 10412 rte_swx_pipeline_free(pipeline); 10413 return status; 10414 } 10415 10416 int 10417 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p, 10418 const char **instructions, 10419 uint32_t n_instructions) 10420 { 10421 int err; 10422 uint32_t i; 10423 10424 err = instruction_config(p, NULL, instructions, n_instructions); 10425 if (err) 10426 return err; 10427 10428 /* Thread instruction pointer reset. */ 10429 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 10430 struct thread *t = &p->threads[i]; 10431 10432 thread_ip_reset(p, t); 10433 } 10434 10435 return 0; 10436 } 10437 10438 int 10439 rte_swx_pipeline_build(struct rte_swx_pipeline *p) 10440 { 10441 struct rte_swx_port_sink_params drop_port_params = { 10442 .file_name = NULL, 10443 }; 10444 int status; 10445 10446 CHECK(p, EINVAL); 10447 CHECK(p->build_done == 0, EEXIST); 10448 10449 status = port_in_build(p); 10450 if (status) 10451 goto error; 10452 10453 /* Drop port. */ 10454 status = rte_swx_pipeline_port_out_config(p, 10455 p->n_ports_out, 10456 "sink", 10457 &drop_port_params); 10458 if (status) 10459 goto error; 10460 10461 status = port_out_build(p); 10462 if (status) 10463 goto error; 10464 10465 status = mirroring_build(p); 10466 if (status) 10467 goto error; 10468 10469 status = struct_build(p); 10470 if (status) 10471 goto error; 10472 10473 status = extern_obj_build(p); 10474 if (status) 10475 goto error; 10476 10477 status = extern_func_build(p); 10478 if (status) 10479 goto error; 10480 10481 status = hash_func_build(p); 10482 if (status) 10483 goto error; 10484 10485 status = rss_build(p); 10486 if (status) 10487 goto error; 10488 10489 status = header_build(p); 10490 if (status) 10491 goto error; 10492 10493 status = metadata_build(p); 10494 if (status) 10495 goto error; 10496 10497 status = instruction_table_build(p); 10498 if (status) 10499 goto error; 10500 10501 status = action_build(p); 10502 if (status) 10503 goto error; 10504 10505 status = table_build(p); 10506 if (status) 10507 goto error; 10508 10509 status = selector_build(p); 10510 if (status) 10511 goto error; 10512 10513 status = learner_build(p); 10514 if (status) 10515 goto error; 10516 10517 status = table_state_build(p); 10518 if (status) 10519 goto error; 10520 10521 status = regarray_build(p); 10522 if (status) 10523 goto error; 10524 10525 status = metarray_build(p); 10526 if (status) 10527 goto error; 10528 10529 p->build_done = 1; 10530 10531 return 0; 10532 10533 error: 10534 metarray_build_free(p); 10535 regarray_build_free(p); 10536 table_state_build_free(p); 10537 learner_build_free(p); 10538 selector_build_free(p); 10539 table_build_free(p); 10540 action_build_free(p); 10541 instruction_table_build_free(p); 10542 metadata_build_free(p); 10543 header_build_free(p); 10544 rss_build_free(p); 10545 hash_func_build_free(p); 10546 extern_func_build_free(p); 10547 extern_obj_build_free(p); 10548 mirroring_build_free(p); 10549 port_out_build_free(p); 10550 port_in_build_free(p); 10551 struct_build_free(p); 10552 10553 return status; 10554 } 10555 10556 void 10557 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions) 10558 { 10559 uint32_t i; 10560 10561 for (i = 0; i < n_instructions; i++) 10562 instr_exec(p); 10563 } 10564 10565 void 10566 rte_swx_pipeline_flush(struct rte_swx_pipeline *p) 10567 { 10568 uint32_t i; 10569 10570 for (i = 0; i < p->n_ports_out; i++) { 10571 struct port_out_runtime *port = &p->out[i]; 10572 10573 if (port->flush) 10574 port->flush(port->obj); 10575 } 10576 } 10577 10578 /* 10579 * Control. 10580 */ 10581 int 10582 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, 10583 struct rte_swx_ctl_pipeline_info *pipeline) 10584 { 10585 struct action *action; 10586 struct table *table; 10587 uint32_t n_actions = 0, n_tables = 0; 10588 10589 if (!p || !pipeline) 10590 return -EINVAL; 10591 10592 TAILQ_FOREACH(action, &p->actions, node) 10593 n_actions++; 10594 10595 TAILQ_FOREACH(table, &p->tables, node) 10596 n_tables++; 10597 10598 strcpy(pipeline->name, p->name); 10599 pipeline->n_ports_in = p->n_ports_in; 10600 pipeline->n_ports_out = p->n_ports_out; 10601 pipeline->n_mirroring_slots = p->n_mirroring_slots; 10602 pipeline->n_mirroring_sessions = p->n_mirroring_sessions; 10603 pipeline->n_actions = n_actions; 10604 pipeline->n_tables = n_tables; 10605 pipeline->n_selectors = p->n_selectors; 10606 pipeline->n_learners = p->n_learners; 10607 pipeline->n_regarrays = p->n_regarrays; 10608 pipeline->n_metarrays = p->n_metarrays; 10609 pipeline->n_rss = p->n_rss; 10610 10611 return 0; 10612 } 10613 10614 int 10615 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node) 10616 { 10617 if (!p || !numa_node) 10618 return -EINVAL; 10619 10620 *numa_node = p->numa_node; 10621 return 0; 10622 } 10623 10624 int 10625 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, 10626 uint32_t action_id, 10627 struct rte_swx_ctl_action_info *action) 10628 { 10629 struct action *a = NULL; 10630 10631 if (!p || (action_id >= p->n_actions) || !action) 10632 return -EINVAL; 10633 10634 a = action_find_by_id(p, action_id); 10635 if (!a) 10636 return -EINVAL; 10637 10638 strcpy(action->name, a->name); 10639 action->n_args = a->st ? a->st->n_fields : 0; 10640 return 0; 10641 } 10642 10643 int 10644 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, 10645 uint32_t action_id, 10646 uint32_t action_arg_id, 10647 struct rte_swx_ctl_action_arg_info *action_arg) 10648 { 10649 struct action *a = NULL; 10650 struct field *arg = NULL; 10651 10652 if (!p || (action_id >= p->n_actions) || !action_arg) 10653 return -EINVAL; 10654 10655 a = action_find_by_id(p, action_id); 10656 if (!a || !a->st || (action_arg_id >= a->st->n_fields)) 10657 return -EINVAL; 10658 10659 arg = &a->st->fields[action_arg_id]; 10660 strcpy(action_arg->name, arg->name); 10661 action_arg->n_bits = arg->n_bits; 10662 action_arg->is_network_byte_order = a->args_endianness[action_arg_id]; 10663 10664 return 0; 10665 } 10666 10667 int 10668 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, 10669 uint32_t table_id, 10670 struct rte_swx_ctl_table_info *table) 10671 { 10672 struct table *t = NULL; 10673 10674 if (!p || !table) 10675 return -EINVAL; 10676 10677 t = table_find_by_id(p, table_id); 10678 if (!t) 10679 return -EINVAL; 10680 10681 strcpy(table->name, t->name); 10682 strcpy(table->args, t->args); 10683 table->n_match_fields = t->n_fields; 10684 table->n_actions = t->n_actions; 10685 table->default_action_is_const = t->default_action_is_const; 10686 table->hash_func = t->hf ? t->hf->func : NULL; 10687 table->size = t->size; 10688 return 0; 10689 } 10690 10691 int 10692 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, 10693 uint32_t table_id, 10694 uint32_t match_field_id, 10695 struct rte_swx_ctl_table_match_field_info *match_field) 10696 { 10697 struct table *t; 10698 struct match_field *f; 10699 10700 if (!p || (table_id >= p->n_tables) || !match_field) 10701 return -EINVAL; 10702 10703 t = table_find_by_id(p, table_id); 10704 if (!t || (match_field_id >= t->n_fields)) 10705 return -EINVAL; 10706 10707 f = &t->fields[match_field_id]; 10708 match_field->match_type = f->match_type; 10709 match_field->is_header = t->header ? 1 : 0; 10710 match_field->n_bits = f->field->n_bits; 10711 match_field->offset = f->field->offset; 10712 10713 return 0; 10714 } 10715 10716 int 10717 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, 10718 uint32_t table_id, 10719 uint32_t table_action_id, 10720 struct rte_swx_ctl_table_action_info *table_action) 10721 { 10722 struct table *t; 10723 10724 if (!p || (table_id >= p->n_tables) || !table_action) 10725 return -EINVAL; 10726 10727 t = table_find_by_id(p, table_id); 10728 if (!t || (table_action_id >= t->n_actions)) 10729 return -EINVAL; 10730 10731 table_action->action_id = t->actions[table_action_id]->id; 10732 10733 table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; 10734 table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; 10735 10736 return 0; 10737 } 10738 10739 int 10740 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, 10741 uint32_t table_id, 10742 struct rte_swx_table_ops *table_ops, 10743 int *is_stub) 10744 { 10745 struct table *t; 10746 10747 if (!p || (table_id >= p->n_tables)) 10748 return -EINVAL; 10749 10750 t = table_find_by_id(p, table_id); 10751 if (!t) 10752 return -EINVAL; 10753 10754 if (t->type) { 10755 if (table_ops) 10756 memcpy(table_ops, &t->type->ops, sizeof(*table_ops)); 10757 *is_stub = 0; 10758 } else { 10759 *is_stub = 1; 10760 } 10761 10762 return 0; 10763 } 10764 10765 int 10766 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p, 10767 uint32_t selector_id, 10768 struct rte_swx_ctl_selector_info *selector) 10769 { 10770 struct selector *s = NULL; 10771 10772 if (!p || !selector) 10773 return -EINVAL; 10774 10775 s = selector_find_by_id(p, selector_id); 10776 if (!s) 10777 return -EINVAL; 10778 10779 strcpy(selector->name, s->name); 10780 10781 selector->n_selector_fields = s->n_selector_fields; 10782 selector->n_groups_max = s->n_groups_max; 10783 selector->n_members_per_group_max = s->n_members_per_group_max; 10784 10785 return 0; 10786 } 10787 10788 int 10789 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p, 10790 uint32_t selector_id, 10791 struct rte_swx_ctl_table_match_field_info *field) 10792 { 10793 struct selector *s; 10794 10795 if (!p || (selector_id >= p->n_selectors) || !field) 10796 return -EINVAL; 10797 10798 s = selector_find_by_id(p, selector_id); 10799 if (!s) 10800 return -EINVAL; 10801 10802 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10803 field->is_header = 0; 10804 field->n_bits = s->group_id_field->n_bits; 10805 field->offset = s->group_id_field->offset; 10806 10807 return 0; 10808 } 10809 10810 int 10811 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p, 10812 uint32_t selector_id, 10813 uint32_t selector_field_id, 10814 struct rte_swx_ctl_table_match_field_info *field) 10815 { 10816 struct selector *s; 10817 struct field *f; 10818 10819 if (!p || (selector_id >= p->n_selectors) || !field) 10820 return -EINVAL; 10821 10822 s = selector_find_by_id(p, selector_id); 10823 if (!s || (selector_field_id >= s->n_selector_fields)) 10824 return -EINVAL; 10825 10826 f = s->selector_fields[selector_field_id]; 10827 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10828 field->is_header = s->selector_header ? 1 : 0; 10829 field->n_bits = f->n_bits; 10830 field->offset = f->offset; 10831 10832 return 0; 10833 } 10834 10835 int 10836 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p, 10837 uint32_t selector_id, 10838 struct rte_swx_ctl_table_match_field_info *field) 10839 { 10840 struct selector *s; 10841 10842 if (!p || (selector_id >= p->n_selectors) || !field) 10843 return -EINVAL; 10844 10845 s = selector_find_by_id(p, selector_id); 10846 if (!s) 10847 return -EINVAL; 10848 10849 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10850 field->is_header = 0; 10851 field->n_bits = s->member_id_field->n_bits; 10852 field->offset = s->member_id_field->offset; 10853 10854 return 0; 10855 } 10856 10857 int 10858 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p, 10859 uint32_t learner_id, 10860 struct rte_swx_ctl_learner_info *learner) 10861 { 10862 struct learner *l = NULL; 10863 10864 if (!p || !learner) 10865 return -EINVAL; 10866 10867 l = learner_find_by_id(p, learner_id); 10868 if (!l) 10869 return -EINVAL; 10870 10871 strcpy(learner->name, l->name); 10872 10873 learner->n_match_fields = l->n_fields; 10874 learner->n_actions = l->n_actions; 10875 learner->default_action_is_const = l->default_action_is_const; 10876 learner->size = l->size; 10877 learner->n_key_timeouts = l->n_timeouts; 10878 10879 return 0; 10880 } 10881 10882 int 10883 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p, 10884 uint32_t learner_id, 10885 uint32_t match_field_id, 10886 struct rte_swx_ctl_table_match_field_info *match_field) 10887 { 10888 struct learner *l; 10889 struct field *f; 10890 10891 if (!p || (learner_id >= p->n_learners) || !match_field) 10892 return -EINVAL; 10893 10894 l = learner_find_by_id(p, learner_id); 10895 if (!l || (match_field_id >= l->n_fields)) 10896 return -EINVAL; 10897 10898 f = l->fields[match_field_id]; 10899 match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 10900 match_field->is_header = l->header ? 1 : 0; 10901 match_field->n_bits = f->n_bits; 10902 match_field->offset = f->offset; 10903 10904 return 0; 10905 } 10906 10907 int 10908 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, 10909 uint32_t learner_id, 10910 uint32_t learner_action_id, 10911 struct rte_swx_ctl_table_action_info *learner_action) 10912 { 10913 struct learner *l; 10914 10915 if (!p || (learner_id >= p->n_learners) || !learner_action) 10916 return -EINVAL; 10917 10918 l = learner_find_by_id(p, learner_id); 10919 if (!l || (learner_action_id >= l->n_actions)) 10920 return -EINVAL; 10921 10922 learner_action->action_id = l->actions[learner_action_id]->id; 10923 10924 learner_action->action_is_for_table_entries = 10925 l->action_is_for_table_entries[learner_action_id]; 10926 10927 learner_action->action_is_for_default_entry = 10928 l->action_is_for_default_entry[learner_action_id]; 10929 10930 return 0; 10931 } 10932 10933 int 10934 rte_swx_ctl_pipeline_learner_timeout_get(struct rte_swx_pipeline *p, 10935 uint32_t learner_id, 10936 uint32_t timeout_id, 10937 uint32_t *timeout) 10938 { 10939 struct learner *l; 10940 10941 if (!p || (learner_id >= p->n_learners) || !timeout) 10942 return -EINVAL; 10943 10944 l = learner_find_by_id(p, learner_id); 10945 if (!l || (timeout_id >= l->n_timeouts)) 10946 return -EINVAL; 10947 10948 *timeout = l->timeout[timeout_id]; 10949 return 0; 10950 } 10951 10952 int 10953 rte_swx_ctl_pipeline_learner_timeout_set(struct rte_swx_pipeline *p, 10954 uint32_t learner_id, 10955 uint32_t timeout_id, 10956 uint32_t timeout) 10957 { 10958 struct learner *l; 10959 struct rte_swx_table_state *ts; 10960 int status; 10961 10962 if (!p || (learner_id >= p->n_learners) || !timeout) 10963 return -EINVAL; 10964 10965 l = learner_find_by_id(p, learner_id); 10966 if (!l || (timeout_id >= l->n_timeouts)) 10967 return -EINVAL; 10968 10969 if (!p->build_done) 10970 return -EINVAL; 10971 10972 ts = &p->table_state[p->n_tables + p->n_selectors + l->id]; 10973 10974 status = rte_swx_table_learner_timeout_update(ts->obj, timeout_id, timeout); 10975 if (status) 10976 return -EINVAL; 10977 10978 l->timeout[timeout_id] = timeout; 10979 10980 return 0; 10981 } 10982 10983 int 10984 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p, 10985 struct rte_swx_table_state **table_state) 10986 { 10987 if (!p || !table_state || !p->build_done) 10988 return -EINVAL; 10989 10990 *table_state = p->table_state; 10991 return 0; 10992 } 10993 10994 int 10995 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p, 10996 struct rte_swx_table_state *table_state) 10997 { 10998 if (!p || !table_state || !p->build_done) 10999 return -EINVAL; 11000 11001 p->table_state = table_state; 11002 return 0; 11003 } 11004 11005 int 11006 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, 11007 uint32_t port_id, 11008 struct rte_swx_port_in_stats *stats) 11009 { 11010 struct port_in *port; 11011 11012 if (!p || !stats) 11013 return -EINVAL; 11014 11015 port = port_in_find(p, port_id); 11016 if (!port) 11017 return -EINVAL; 11018 11019 port->type->ops.stats_read(port->obj, stats); 11020 return 0; 11021 } 11022 11023 int 11024 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, 11025 uint32_t port_id, 11026 struct rte_swx_port_out_stats *stats) 11027 { 11028 struct port_out *port; 11029 11030 if (!p || !stats) 11031 return -EINVAL; 11032 11033 port = port_out_find(p, port_id); 11034 if (!port) 11035 return -EINVAL; 11036 11037 port->type->ops.stats_read(port->obj, stats); 11038 return 0; 11039 } 11040 11041 int 11042 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, 11043 const char *table_name, 11044 struct rte_swx_table_stats *stats) 11045 { 11046 struct table *table; 11047 struct table_statistics *table_stats; 11048 11049 if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action) 11050 return -EINVAL; 11051 11052 table = table_find(p, table_name); 11053 if (!table) 11054 return -EINVAL; 11055 11056 table_stats = &p->table_stats[table->id]; 11057 11058 memcpy(stats->n_pkts_action, 11059 table_stats->n_pkts_action, 11060 p->n_actions * sizeof(uint64_t)); 11061 11062 stats->n_pkts_hit = table_stats->n_pkts_hit[1]; 11063 stats->n_pkts_miss = table_stats->n_pkts_hit[0]; 11064 11065 return 0; 11066 } 11067 11068 int 11069 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p, 11070 const char *selector_name, 11071 struct rte_swx_pipeline_selector_stats *stats) 11072 { 11073 struct selector *s; 11074 11075 if (!p || !selector_name || !selector_name[0] || !stats) 11076 return -EINVAL; 11077 11078 s = selector_find(p, selector_name); 11079 if (!s) 11080 return -EINVAL; 11081 11082 stats->n_pkts = p->selector_stats[s->id].n_pkts; 11083 11084 return 0; 11085 } 11086 11087 int 11088 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, 11089 const char *learner_name, 11090 struct rte_swx_learner_stats *stats) 11091 { 11092 struct learner *l; 11093 struct learner_statistics *learner_stats; 11094 11095 if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action) 11096 return -EINVAL; 11097 11098 l = learner_find(p, learner_name); 11099 if (!l) 11100 return -EINVAL; 11101 11102 learner_stats = &p->learner_stats[l->id]; 11103 11104 memcpy(stats->n_pkts_action, 11105 learner_stats->n_pkts_action, 11106 p->n_actions * sizeof(uint64_t)); 11107 11108 stats->n_pkts_hit = learner_stats->n_pkts_hit[1]; 11109 stats->n_pkts_miss = learner_stats->n_pkts_hit[0]; 11110 11111 stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0]; 11112 stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1]; 11113 11114 stats->n_pkts_rearm = learner_stats->n_pkts_rearm; 11115 stats->n_pkts_forget = learner_stats->n_pkts_forget; 11116 11117 return 0; 11118 } 11119 11120 int 11121 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p, 11122 uint32_t regarray_id, 11123 struct rte_swx_ctl_regarray_info *regarray) 11124 { 11125 struct regarray *r; 11126 11127 if (!p || !regarray) 11128 return -EINVAL; 11129 11130 r = regarray_find_by_id(p, regarray_id); 11131 if (!r) 11132 return -EINVAL; 11133 11134 strcpy(regarray->name, r->name); 11135 regarray->size = r->size; 11136 return 0; 11137 } 11138 11139 int 11140 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p, 11141 const char *regarray_name, 11142 uint32_t regarray_index, 11143 uint64_t *value) 11144 { 11145 struct regarray *regarray; 11146 struct regarray_runtime *r; 11147 11148 if (!p || !regarray_name || !value) 11149 return -EINVAL; 11150 11151 regarray = regarray_find(p, regarray_name); 11152 if (!regarray || (regarray_index >= regarray->size)) 11153 return -EINVAL; 11154 11155 r = &p->regarray_runtime[regarray->id]; 11156 *value = r->regarray[regarray_index]; 11157 return 0; 11158 } 11159 11160 int 11161 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p, 11162 const char *regarray_name, 11163 uint32_t regarray_index, 11164 uint64_t value) 11165 { 11166 struct regarray *regarray; 11167 struct regarray_runtime *r; 11168 11169 if (!p || !regarray_name) 11170 return -EINVAL; 11171 11172 regarray = regarray_find(p, regarray_name); 11173 if (!regarray || (regarray_index >= regarray->size)) 11174 return -EINVAL; 11175 11176 r = &p->regarray_runtime[regarray->id]; 11177 r->regarray[regarray_index] = value; 11178 return 0; 11179 } 11180 11181 int 11182 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p, 11183 uint32_t metarray_id, 11184 struct rte_swx_ctl_metarray_info *metarray) 11185 { 11186 struct metarray *m; 11187 11188 if (!p || !metarray) 11189 return -EINVAL; 11190 11191 m = metarray_find_by_id(p, metarray_id); 11192 if (!m) 11193 return -EINVAL; 11194 11195 strcpy(metarray->name, m->name); 11196 metarray->size = m->size; 11197 return 0; 11198 } 11199 11200 int 11201 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p, 11202 const char *name, 11203 struct rte_meter_trtcm_params *params) 11204 { 11205 struct meter_profile *mp; 11206 int status; 11207 11208 CHECK(p, EINVAL); 11209 CHECK_NAME(name, EINVAL); 11210 CHECK(params, EINVAL); 11211 CHECK(!meter_profile_find(p, name), EEXIST); 11212 11213 /* Node allocation. */ 11214 mp = calloc(1, sizeof(struct meter_profile)); 11215 CHECK(mp, ENOMEM); 11216 11217 /* Node initialization. */ 11218 strcpy(mp->name, name); 11219 memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params)); 11220 status = rte_meter_trtcm_profile_config(&mp->profile, params); 11221 if (status) { 11222 free(mp); 11223 CHECK(0, EINVAL); 11224 } 11225 11226 /* Node add to tailq. */ 11227 TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node); 11228 11229 return 0; 11230 } 11231 11232 int 11233 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p, 11234 const char *name) 11235 { 11236 struct meter_profile *mp; 11237 11238 CHECK(p, EINVAL); 11239 CHECK_NAME(name, EINVAL); 11240 11241 mp = meter_profile_find(p, name); 11242 CHECK(mp, EINVAL); 11243 CHECK(!mp->n_users, EBUSY); 11244 11245 /* Remove node from tailq. */ 11246 TAILQ_REMOVE(&p->meter_profiles, mp, node); 11247 free(mp); 11248 11249 return 0; 11250 } 11251 11252 int 11253 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p, 11254 const char *metarray_name, 11255 uint32_t metarray_index) 11256 { 11257 struct meter_profile *mp_old; 11258 struct metarray *metarray; 11259 struct metarray_runtime *metarray_runtime; 11260 struct meter *m; 11261 11262 CHECK(p, EINVAL); 11263 CHECK_NAME(metarray_name, EINVAL); 11264 11265 metarray = metarray_find(p, metarray_name); 11266 CHECK(metarray, EINVAL); 11267 CHECK(metarray_index < metarray->size, EINVAL); 11268 11269 metarray_runtime = &p->metarray_runtime[metarray->id]; 11270 m = &metarray_runtime->metarray[metarray_index]; 11271 mp_old = m->profile; 11272 11273 meter_init(m); 11274 11275 mp_old->n_users--; 11276 11277 return 0; 11278 } 11279 11280 int 11281 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p, 11282 const char *metarray_name, 11283 uint32_t metarray_index, 11284 const char *profile_name) 11285 { 11286 struct meter_profile *mp, *mp_old; 11287 struct metarray *metarray; 11288 struct metarray_runtime *metarray_runtime; 11289 struct meter *m; 11290 11291 CHECK(p, EINVAL); 11292 CHECK_NAME(metarray_name, EINVAL); 11293 11294 metarray = metarray_find(p, metarray_name); 11295 CHECK(metarray, EINVAL); 11296 CHECK(metarray_index < metarray->size, EINVAL); 11297 11298 mp = meter_profile_find(p, profile_name); 11299 CHECK(mp, EINVAL); 11300 11301 metarray_runtime = &p->metarray_runtime[metarray->id]; 11302 m = &metarray_runtime->metarray[metarray_index]; 11303 mp_old = m->profile; 11304 11305 memset(m, 0, sizeof(struct meter)); 11306 rte_meter_trtcm_config(&m->m, &mp->profile); 11307 m->profile = mp; 11308 m->color_mask = RTE_COLORS; 11309 11310 mp->n_users++; 11311 mp_old->n_users--; 11312 11313 return 0; 11314 } 11315 11316 int 11317 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, 11318 const char *metarray_name, 11319 uint32_t metarray_index, 11320 struct rte_swx_ctl_meter_stats *stats) 11321 { 11322 struct metarray *metarray; 11323 struct metarray_runtime *metarray_runtime; 11324 struct meter *m; 11325 11326 CHECK(p, EINVAL); 11327 CHECK_NAME(metarray_name, EINVAL); 11328 11329 metarray = metarray_find(p, metarray_name); 11330 CHECK(metarray, EINVAL); 11331 CHECK(metarray_index < metarray->size, EINVAL); 11332 11333 CHECK(stats, EINVAL); 11334 11335 metarray_runtime = &p->metarray_runtime[metarray->id]; 11336 m = &metarray_runtime->metarray[metarray_index]; 11337 11338 memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts)); 11339 memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes)); 11340 11341 return 0; 11342 } 11343 11344 int 11345 rte_swx_ctl_pipeline_mirroring_session_set(struct rte_swx_pipeline *p, 11346 uint32_t session_id, 11347 struct rte_swx_pipeline_mirroring_session_params *params) 11348 { 11349 struct mirroring_session *s; 11350 11351 CHECK(p, EINVAL); 11352 CHECK(p->build_done, EEXIST); 11353 CHECK(session_id < p->n_mirroring_sessions, EINVAL); 11354 CHECK(params, EINVAL); 11355 CHECK(params->port_id < p->n_ports_out, EINVAL); 11356 11357 s = &p->mirroring_sessions[session_id]; 11358 s->port_id = params->port_id; 11359 s->fast_clone = params->fast_clone; 11360 s->truncation_length = params->truncation_length ? params->truncation_length : UINT32_MAX; 11361 11362 return 0; 11363 } 11364 11365 static int 11366 rte_swx_ctl_pipeline_table_lookup(struct rte_swx_pipeline *p, 11367 const char *table_name, 11368 uint8_t *key, 11369 uint64_t *action_id, 11370 uint8_t **action_data, 11371 size_t *entry_id, 11372 int *hit) 11373 { 11374 struct table *t; 11375 void *mailbox = NULL; 11376 11377 /* Check input arguments. */ 11378 if (!p || 11379 !p->build_done || 11380 !table_name || 11381 !table_name[0] || 11382 !key || 11383 !entry_id || 11384 !hit) 11385 return -EINVAL; 11386 11387 /* Find the table. */ 11388 t = table_find(p, table_name); 11389 if (!t) 11390 return -EINVAL; 11391 11392 if (!t->type) { 11393 *hit = 0; 11394 return 0; 11395 } 11396 11397 /* Setup mailbox. */ 11398 if (t->type->ops.mailbox_size_get) { 11399 uint64_t mailbox_size; 11400 11401 mailbox_size = t->type->ops.mailbox_size_get(); 11402 if (mailbox_size) { 11403 mailbox = calloc(1, mailbox_size); 11404 if (!mailbox) 11405 return -ENOMEM; 11406 } 11407 } 11408 11409 /* Table lookup operation. */ 11410 key -= table_params_offset_get(t); 11411 11412 for ( ; ; ) { 11413 struct rte_swx_table_state *ts = &p->table_state[t->id]; 11414 int done; 11415 11416 done = t->type->ops.lkp(ts->obj, 11417 mailbox, 11418 &key, 11419 action_id, 11420 action_data, 11421 entry_id, 11422 hit); 11423 if (done) 11424 break; 11425 } 11426 11427 /* Free mailbox. */ 11428 free(mailbox); 11429 11430 return 0; 11431 } 11432 11433 static int 11434 rte_swx_ctl_pipeline_learner_lookup(struct rte_swx_pipeline *p, 11435 const char *learner_name, 11436 uint8_t *key, 11437 uint64_t *action_id, 11438 uint8_t **action_data, 11439 size_t *entry_id, 11440 int *hit) 11441 { 11442 struct learner *l; 11443 void *mailbox = NULL; 11444 uint64_t mailbox_size, time; 11445 11446 /* Check input arguments. */ 11447 if (!p || 11448 !p->build_done || 11449 !learner_name || 11450 !learner_name[0] || 11451 !key || 11452 !entry_id || 11453 !hit) 11454 return -EINVAL; 11455 11456 /* Find the learner table. */ 11457 l = learner_find(p, learner_name); 11458 if (!l) 11459 return -EINVAL; 11460 11461 /* Setup mailbox. */ 11462 mailbox_size = rte_swx_table_learner_mailbox_size_get(); 11463 if (mailbox_size) { 11464 mailbox = calloc(1, mailbox_size); 11465 if (!mailbox) 11466 return -ENOMEM; 11467 } 11468 11469 /* Learner table lookup operation. */ 11470 key -= learner_params_offset_get(l); 11471 11472 time = rte_get_tsc_cycles(); 11473 11474 for ( ; ; ) { 11475 uint32_t pos = p->n_tables + p->n_selectors + l->id; 11476 struct rte_swx_table_state *ts = &p->table_state[pos]; 11477 int done; 11478 11479 done = rte_swx_table_learner_lookup(ts->obj, 11480 mailbox, 11481 time, 11482 &key, 11483 action_id, 11484 action_data, 11485 entry_id, 11486 hit); 11487 if (done) 11488 break; 11489 } 11490 11491 /* Free mailbox. */ 11492 free(mailbox); 11493 11494 return 0; 11495 } 11496 11497 static int 11498 rte_swx_ctl_pipeline_table_entry_id_get(struct rte_swx_pipeline *p, 11499 const char *table_name, 11500 uint8_t *table_key, 11501 size_t *table_entry_id) 11502 { 11503 struct table *t; 11504 struct learner *l; 11505 uint64_t action_id; 11506 uint8_t *action_data; 11507 size_t entry_id = 0; 11508 int hit = 0, status; 11509 11510 /* Check input arguments. */ 11511 if (!p || 11512 !p->build_done || 11513 !table_name || 11514 !table_name[0] || 11515 !table_key || 11516 !table_entry_id) 11517 return -EINVAL; 11518 11519 t = table_find(p, table_name); 11520 l = learner_find(p, table_name); 11521 if (!t && !l) 11522 return -EINVAL; 11523 11524 /* Table lookup operation. */ 11525 if (t) 11526 status = rte_swx_ctl_pipeline_table_lookup(p, 11527 table_name, 11528 table_key, 11529 &action_id, 11530 &action_data, 11531 &entry_id, 11532 &hit); 11533 else 11534 status = rte_swx_ctl_pipeline_learner_lookup(p, 11535 table_name, 11536 table_key, 11537 &action_id, 11538 &action_data, 11539 &entry_id, 11540 &hit); 11541 if (status) 11542 return status; 11543 11544 /* Reserve entry ID 0 for the table default entry. */ 11545 *table_entry_id = hit ? (1 + entry_id) : 0; 11546 11547 return 0; 11548 } 11549 11550 int 11551 rte_swx_ctl_pipeline_regarray_read_with_key(struct rte_swx_pipeline *p, 11552 const char *regarray_name, 11553 const char *table_name, 11554 uint8_t *table_key, 11555 uint64_t *value) 11556 { 11557 size_t entry_id = 0; 11558 int status; 11559 11560 status = rte_swx_ctl_pipeline_table_entry_id_get(p, table_name, table_key, &entry_id); 11561 if (status) 11562 return status; 11563 11564 return rte_swx_ctl_pipeline_regarray_read(p, regarray_name, entry_id, value); 11565 } 11566 11567 int 11568 rte_swx_ctl_pipeline_regarray_write_with_key(struct rte_swx_pipeline *p, 11569 const char *regarray_name, 11570 const char *table_name, 11571 uint8_t *table_key, 11572 uint64_t value) 11573 { 11574 size_t entry_id = 0; 11575 int status; 11576 11577 status = rte_swx_ctl_pipeline_table_entry_id_get(p, table_name, table_key, &entry_id); 11578 if (status) 11579 return status; 11580 11581 return rte_swx_ctl_pipeline_regarray_write(p, regarray_name, entry_id, value); 11582 } 11583 11584 int 11585 rte_swx_ctl_meter_reset_with_key(struct rte_swx_pipeline *p, 11586 const char *metarray_name, 11587 const char *table_name, 11588 uint8_t *table_key) 11589 { 11590 size_t entry_id = 0; 11591 int status; 11592 11593 status = rte_swx_ctl_pipeline_table_entry_id_get(p, table_name, table_key, &entry_id); 11594 if (status) 11595 return status; 11596 11597 return rte_swx_ctl_meter_reset(p, metarray_name, entry_id); 11598 } 11599 11600 int 11601 rte_swx_ctl_meter_set_with_key(struct rte_swx_pipeline *p, 11602 const char *metarray_name, 11603 const char *table_name, 11604 uint8_t *table_key, 11605 const char *profile_name) 11606 { 11607 size_t entry_id = 0; 11608 int status; 11609 11610 status = rte_swx_ctl_pipeline_table_entry_id_get(p, table_name, table_key, &entry_id); 11611 if (status) 11612 return status; 11613 11614 return rte_swx_ctl_meter_set(p, metarray_name, entry_id, profile_name); 11615 } 11616 11617 int 11618 rte_swx_ctl_meter_stats_read_with_key(struct rte_swx_pipeline *p, 11619 const char *metarray_name, 11620 const char *table_name, 11621 uint8_t *table_key, 11622 struct rte_swx_ctl_meter_stats *stats) 11623 { 11624 size_t entry_id = 0; 11625 int status; 11626 11627 status = rte_swx_ctl_pipeline_table_entry_id_get(p, table_name, table_key, &entry_id); 11628 if (status) 11629 return status; 11630 11631 return rte_swx_ctl_meter_stats_read(p, metarray_name, entry_id, stats); 11632 } 11633 11634 int 11635 rte_swx_ctl_rss_info_get(struct rte_swx_pipeline *p, 11636 uint32_t rss_obj_id, 11637 struct rte_swx_ctl_rss_info *info) 11638 { 11639 struct rss *rss; 11640 11641 /* Check the input arguments. */ 11642 if (!p || !info) 11643 return -EINVAL; 11644 11645 rss = rss_find_by_id(p, rss_obj_id); 11646 if (!rss) 11647 return -EINVAL; 11648 11649 /* Read from the internal data structures. */ 11650 strcpy(info->name, rss->name); 11651 return 0; 11652 } 11653 11654 int 11655 rte_swx_ctl_pipeline_rss_key_size_read(struct rte_swx_pipeline *p, 11656 const char *rss_name, 11657 uint32_t *key_size) 11658 { 11659 struct rss *rss; 11660 struct rss_runtime *r; 11661 11662 /* Check the input arguments. */ 11663 CHECK(p, EINVAL); 11664 11665 CHECK_NAME(rss_name, EINVAL); 11666 rss = rss_find(p, rss_name); 11667 CHECK(rss, EINVAL); 11668 r = p->rss_runtime[rss->id]; 11669 11670 CHECK(key_size, EINVAL); 11671 11672 /* Read from the internal data structures. */ 11673 *key_size = r->key_size; 11674 11675 return 0; 11676 } 11677 11678 int 11679 rte_swx_ctl_pipeline_rss_key_read(struct rte_swx_pipeline *p, 11680 const char *rss_name, 11681 uint8_t *key) 11682 { 11683 struct rss *rss; 11684 struct rss_runtime *r; 11685 11686 /* Check the input arguments. */ 11687 CHECK(p, EINVAL); 11688 11689 CHECK_NAME(rss_name, EINVAL); 11690 rss = rss_find(p, rss_name); 11691 CHECK(rss, EINVAL); 11692 r = p->rss_runtime[rss->id]; 11693 11694 CHECK(key, EINVAL); 11695 11696 /* Read from the internal data structures. */ 11697 memcpy(key, r->key, r->key_size); 11698 11699 return 0; 11700 } 11701 11702 int 11703 rte_swx_ctl_pipeline_rss_key_write(struct rte_swx_pipeline *p, 11704 const char *rss_name, 11705 uint32_t key_size, 11706 uint8_t *key) 11707 { 11708 struct rss *rss; 11709 struct rss_runtime *r, *r_new; 11710 11711 /* Check the input arguments. */ 11712 CHECK(p, EINVAL); 11713 11714 CHECK_NAME(rss_name, EINVAL); 11715 rss = rss_find(p, rss_name); 11716 CHECK(rss, EINVAL); 11717 r = p->rss_runtime[rss->id]; 11718 11719 CHECK(key_size >= 4, EINVAL); 11720 CHECK(key, EINVAL); 11721 11722 /* Allocate new RSS run-time entry. */ 11723 r_new = malloc(sizeof(struct rss_runtime) + key_size * sizeof(uint32_t)); 11724 if (!r_new) 11725 return -ENOMEM; 11726 11727 /* Fill in the new RSS run-time entry. */ 11728 r_new->key_size = key_size; 11729 memcpy(r_new->key, key, key_size); 11730 11731 /* Commit the RSS run-time change atomically. */ 11732 p->rss_runtime[rss->id] = r_new; 11733 11734 /* Free the old RSS run-time entry. */ 11735 free(r); 11736 11737 return 0; 11738 } 11739 11740 /* 11741 * Pipeline compilation. 11742 */ 11743 static const char * 11744 instr_type_to_name(struct instruction *instr) 11745 { 11746 switch (instr->type) { 11747 case INSTR_RX: return "INSTR_RX"; 11748 11749 case INSTR_TX: return "INSTR_TX"; 11750 case INSTR_TX_I: return "INSTR_TX_I"; 11751 case INSTR_DROP: return "INSTR_DROP"; 11752 case INSTR_MIRROR: return "INSTR_MIRROR"; 11753 case INSTR_RECIRCULATE: return "INSTR_RECIRCULATE"; 11754 case INSTR_RECIRCID: return "INSTR_RECIRCID"; 11755 11756 case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; 11757 case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; 11758 case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3"; 11759 case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4"; 11760 case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5"; 11761 case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6"; 11762 case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7"; 11763 case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8"; 11764 11765 case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M"; 11766 11767 case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD"; 11768 11769 case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT"; 11770 case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX"; 11771 case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX"; 11772 case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX"; 11773 case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX"; 11774 case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX"; 11775 case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX"; 11776 case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX"; 11777 case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX"; 11778 11779 case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE"; 11780 case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE"; 11781 11782 case INSTR_MOV: return "INSTR_MOV"; 11783 case INSTR_MOV_MH: return "INSTR_MOV_MH"; 11784 case INSTR_MOV_HM: return "INSTR_MOV_HM"; 11785 case INSTR_MOV_HH: return "INSTR_MOV_HH"; 11786 case INSTR_MOV_DMA: return "INSTR_MOV_DMA"; 11787 case INSTR_MOV_128: return "INSTR_MOV_128"; 11788 case INSTR_MOV_128_32: return "INSTR_MOV_128_32"; 11789 case INSTR_MOV_I: return "INSTR_MOV_I"; 11790 11791 case INSTR_DMA_HT: return "INSTR_DMA_HT"; 11792 case INSTR_DMA_HT2: return "INSTR_DMA_HT2"; 11793 case INSTR_DMA_HT3: return "INSTR_DMA_HT3"; 11794 case INSTR_DMA_HT4: return "INSTR_DMA_HT4"; 11795 case INSTR_DMA_HT5: return "INSTR_DMA_HT5"; 11796 case INSTR_DMA_HT6: return "INSTR_DMA_HT6"; 11797 case INSTR_DMA_HT7: return "INSTR_DMA_HT7"; 11798 case INSTR_DMA_HT8: return "INSTR_DMA_HT8"; 11799 11800 case INSTR_ALU_ADD: return "INSTR_ALU_ADD"; 11801 case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH"; 11802 case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM"; 11803 case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH"; 11804 case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI"; 11805 case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI"; 11806 11807 case INSTR_ALU_SUB: return "INSTR_ALU_SUB"; 11808 case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH"; 11809 case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM"; 11810 case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH"; 11811 case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI"; 11812 case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI"; 11813 11814 case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD"; 11815 case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20"; 11816 case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT"; 11817 case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD"; 11818 11819 case INSTR_ALU_AND: return "INSTR_ALU_AND"; 11820 case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH"; 11821 case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM"; 11822 case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH"; 11823 case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I"; 11824 11825 case INSTR_ALU_OR: return "INSTR_ALU_OR"; 11826 case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH"; 11827 case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM"; 11828 case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH"; 11829 case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I"; 11830 11831 case INSTR_ALU_XOR: return "INSTR_ALU_XOR"; 11832 case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH"; 11833 case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM"; 11834 case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH"; 11835 case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I"; 11836 11837 case INSTR_ALU_SHL: return "INSTR_ALU_SHL"; 11838 case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH"; 11839 case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM"; 11840 case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH"; 11841 case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI"; 11842 case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI"; 11843 11844 case INSTR_ALU_SHR: return "INSTR_ALU_SHR"; 11845 case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH"; 11846 case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM"; 11847 case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH"; 11848 case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI"; 11849 case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI"; 11850 11851 case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH"; 11852 case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM"; 11853 case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI"; 11854 11855 case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH"; 11856 case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM"; 11857 case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI"; 11858 case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH"; 11859 case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM"; 11860 case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI"; 11861 11862 case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH"; 11863 case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM"; 11864 case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI"; 11865 case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH"; 11866 case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM"; 11867 case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI"; 11868 case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH"; 11869 case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM"; 11870 case INSTR_REGWR_RII: return "INSTR_REGWR_RII"; 11871 11872 case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH"; 11873 case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM"; 11874 case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI"; 11875 case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH"; 11876 case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM"; 11877 case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI"; 11878 case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH"; 11879 case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM"; 11880 case INSTR_REGADD_RII: return "INSTR_REGADD_RII"; 11881 11882 case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H"; 11883 case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M"; 11884 case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I"; 11885 11886 case INSTR_METER_HHM: return "INSTR_METER_HHM"; 11887 case INSTR_METER_HHI: return "INSTR_METER_HHI"; 11888 case INSTR_METER_HMM: return "INSTR_METER_HMM"; 11889 case INSTR_METER_HMI: return "INSTR_METER_HMI"; 11890 case INSTR_METER_MHM: return "INSTR_METER_MHM"; 11891 case INSTR_METER_MHI: return "INSTR_METER_MHI"; 11892 case INSTR_METER_MMM: return "INSTR_METER_MMM"; 11893 case INSTR_METER_MMI: return "INSTR_METER_MMI"; 11894 case INSTR_METER_IHM: return "INSTR_METER_IHM"; 11895 case INSTR_METER_IHI: return "INSTR_METER_IHI"; 11896 case INSTR_METER_IMM: return "INSTR_METER_IMM"; 11897 case INSTR_METER_IMI: return "INSTR_METER_IMI"; 11898 11899 case INSTR_TABLE: return "INSTR_TABLE"; 11900 case INSTR_TABLE_AF: return "INSTR_TABLE_AF"; 11901 case INSTR_SELECTOR: return "INSTR_SELECTOR"; 11902 case INSTR_LEARNER: return "INSTR_LEARNER"; 11903 case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; 11904 11905 case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; 11906 case INSTR_LEARNER_REARM: return "INSTR_LEARNER_REARM"; 11907 case INSTR_LEARNER_REARM_NEW: return "INSTR_LEARNER_REARM_NEW"; 11908 case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; 11909 case INSTR_ENTRYID: return "INSTR_ENTRYID"; 11910 11911 case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; 11912 case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC"; 11913 case INSTR_HASH_FUNC: return "INSTR_HASH_FUNC"; 11914 case INSTR_RSS: return "INSTR_RSS"; 11915 11916 case INSTR_JMP: return "INSTR_JMP"; 11917 case INSTR_JMP_VALID: return "INSTR_JMP_VALID"; 11918 case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID"; 11919 case INSTR_JMP_HIT: return "INSTR_JMP_HIT"; 11920 case INSTR_JMP_MISS: return "INSTR_JMP_MISS"; 11921 case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT"; 11922 case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS"; 11923 case INSTR_JMP_EQ: return "INSTR_JMP_EQ"; 11924 case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH"; 11925 case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM"; 11926 case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH"; 11927 case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I"; 11928 case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ"; 11929 case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH"; 11930 case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM"; 11931 case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH"; 11932 case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I"; 11933 case INSTR_JMP_LT: return "INSTR_JMP_LT"; 11934 case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH"; 11935 case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM"; 11936 case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH"; 11937 case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI"; 11938 case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI"; 11939 case INSTR_JMP_GT: return "INSTR_JMP_GT"; 11940 case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH"; 11941 case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM"; 11942 case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH"; 11943 case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI"; 11944 case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI"; 11945 11946 case INSTR_RETURN: return "INSTR_RETURN"; 11947 11948 default: return "INSTR_UNKNOWN"; 11949 } 11950 } 11951 11952 typedef void 11953 (*instruction_export_t)(struct instruction *, FILE *); 11954 11955 static void 11956 instr_io_export(struct instruction *instr, FILE *f) 11957 { 11958 uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i; 11959 11960 /* n_io, n_io_imm, n_hdrs. */ 11961 if (instr->type == INSTR_RX || 11962 instr->type == INSTR_TX || 11963 instr->type == INSTR_HDR_EXTRACT_M || 11964 (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)) 11965 n_io = 1; 11966 11967 if (instr->type == INSTR_TX_I) 11968 n_io_imm = 1; 11969 11970 if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8) 11971 n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT); 11972 11973 if (instr->type == INSTR_HDR_EXTRACT_M || 11974 instr->type == INSTR_HDR_LOOKAHEAD || 11975 instr->type == INSTR_HDR_EMIT) 11976 n_hdrs = 1; 11977 11978 if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX) 11979 n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX); 11980 11981 /* instr. */ 11982 fprintf(f, 11983 "\t{\n" 11984 "\t\t.type = %s,\n", 11985 instr_type_to_name(instr)); 11986 11987 /* instr.io. */ 11988 if (n_io || n_io_imm || n_hdrs) 11989 fprintf(f, 11990 "\t\t.io = {\n"); 11991 11992 /* instr.io.io. */ 11993 if (n_io) 11994 fprintf(f, 11995 "\t\t\t.io = {\n" 11996 "\t\t\t\t.offset = %u,\n" 11997 "\t\t\t\t.n_bits = %u,\n" 11998 "\t\t\t},\n", 11999 instr->io.io.offset, 12000 instr->io.io.n_bits); 12001 12002 if (n_io_imm) 12003 fprintf(f, 12004 "\t\t\t.io = {\n" 12005 "\t\t\t\t.val = %u,\n" 12006 "\t\t\t},\n", 12007 instr->io.io.val); 12008 12009 /* instr.io.hdr. */ 12010 if (n_hdrs) { 12011 fprintf(f, 12012 "\t\t.hdr = {\n"); 12013 12014 /* instr.io.hdr.header_id. */ 12015 fprintf(f, 12016 "\t\t\t.header_id = {"); 12017 12018 for (i = 0; i < n_hdrs; i++) 12019 fprintf(f, 12020 "%u, ", 12021 instr->io.hdr.header_id[i]); 12022 12023 fprintf(f, 12024 "},\n"); 12025 12026 /* instr.io.hdr.struct_id. */ 12027 fprintf(f, 12028 "\t\t\t.struct_id = {"); 12029 12030 for (i = 0; i < n_hdrs; i++) 12031 fprintf(f, 12032 "%u, ", 12033 instr->io.hdr.struct_id[i]); 12034 12035 fprintf(f, 12036 "},\n"); 12037 12038 /* instr.io.hdr.n_bytes. */ 12039 fprintf(f, 12040 "\t\t\t.n_bytes = {"); 12041 12042 for (i = 0; i < n_hdrs; i++) 12043 fprintf(f, 12044 "%u, ", 12045 instr->io.hdr.n_bytes[i]); 12046 12047 fprintf(f, 12048 "},\n"); 12049 12050 /* instr.io.hdr - closing curly brace. */ 12051 fprintf(f, 12052 "\t\t\t}\n,"); 12053 } 12054 12055 /* instr.io - closing curly brace. */ 12056 if (n_io || n_io_imm || n_hdrs) 12057 fprintf(f, 12058 "\t\t},\n"); 12059 12060 /* instr - closing curly brace. */ 12061 fprintf(f, 12062 "\t},\n"); 12063 } 12064 12065 static void 12066 instr_mirror_export(struct instruction *instr, FILE *f) 12067 { 12068 fprintf(f, 12069 "\t{\n" 12070 "\t\t.type = %s,\n" 12071 "\t\t.mirror = {\n" 12072 "\t\t\t.dst = {\n" 12073 "\t\t\t\t.struct_id = %u,\n" 12074 "\t\t\t\t.n_bits = %u,\n" 12075 "\t\t\t\t.offset = %u,\n" 12076 "\t\t\t}\n," 12077 "\t\t\t.src = {\n" 12078 "\t\t\t\t.struct_id = %u,\n" 12079 "\t\t\t\t.n_bits = %u,\n" 12080 "\t\t\t\t.offset = %u,\n" 12081 "\t\t\t}\n," 12082 "\t\t},\n" 12083 "\t},\n", 12084 instr_type_to_name(instr), 12085 instr->mirror.dst.struct_id, 12086 instr->mirror.dst.n_bits, 12087 instr->mirror.dst.offset, 12088 instr->mirror.src.struct_id, 12089 instr->mirror.src.n_bits, 12090 instr->mirror.src.offset); 12091 } 12092 12093 static void 12094 instr_recirculate_export(struct instruction *instr, FILE *f) 12095 { 12096 fprintf(f, 12097 "\t{\n" 12098 "\t\t.type = %s,\n" 12099 "\t},\n", 12100 instr_type_to_name(instr)); 12101 } 12102 12103 static void 12104 instr_recircid_export(struct instruction *instr, FILE *f) 12105 { 12106 fprintf(f, 12107 "\t{\n" 12108 "\t\t.type = %s,\n" 12109 "\t\t.io = {\n" 12110 "\t\t\t.io = {\n" 12111 "\t\t\t\t.offset = %u,\n" 12112 "\t\t\t\t.n_bits = %u,\n" 12113 "\t\t\t},\n" 12114 "\t\t},\n" 12115 "\t},\n", 12116 instr_type_to_name(instr), 12117 instr->io.io.offset, 12118 instr->io.io.n_bits); 12119 } 12120 12121 static void 12122 instr_hdr_validate_export(struct instruction *instr, FILE *f) 12123 { 12124 fprintf(f, 12125 "\t{\n" 12126 "\t\t.type = %s,\n" 12127 "\t\t.valid = {\n" 12128 "\t\t\t.header_id = %u,\n" 12129 "\t\t\t.struct_id = %u,\n" 12130 "\t\t},\n" 12131 "\t},\n", 12132 instr_type_to_name(instr), 12133 instr->valid.header_id, 12134 instr->valid.struct_id); 12135 } 12136 12137 static void 12138 instr_mov_export(struct instruction *instr, FILE *f) 12139 { 12140 if (instr->type != INSTR_MOV_I) 12141 fprintf(f, 12142 "\t{\n" 12143 "\t\t.type = %s,\n" 12144 "\t\t.mov = {\n" 12145 "\t\t\t.dst = {\n" 12146 "\t\t\t\t.struct_id = %u,\n" 12147 "\t\t\t\t.n_bits = %u,\n" 12148 "\t\t\t\t.offset = %u,\n" 12149 "\t\t\t},\n" 12150 "\t\t\t.src = {\n" 12151 "\t\t\t\t.struct_id = %u,\n" 12152 "\t\t\t\t.n_bits = %u,\n" 12153 "\t\t\t\t.offset = %u,\n" 12154 "\t\t\t},\n" 12155 "\t\t},\n" 12156 "\t},\n", 12157 instr_type_to_name(instr), 12158 instr->mov.dst.struct_id, 12159 instr->mov.dst.n_bits, 12160 instr->mov.dst.offset, 12161 instr->mov.src.struct_id, 12162 instr->mov.src.n_bits, 12163 instr->mov.src.offset); 12164 else 12165 fprintf(f, 12166 "\t{\n" 12167 "\t\t.type = %s,\n" 12168 "\t\t.mov = {\n" 12169 "\t\t\t.dst = {\n" 12170 "\t\t\t\t.struct_id = %u,\n" 12171 "\t\t\t\t.n_bits = %u,\n" 12172 "\t\t\t\t.offset = %u,\n" 12173 "\t\t\t}\n," 12174 "\t\t\t.src_val = %" PRIu64 ",\n" 12175 "\t\t},\n" 12176 "\t},\n", 12177 instr_type_to_name(instr), 12178 instr->mov.dst.struct_id, 12179 instr->mov.dst.n_bits, 12180 instr->mov.dst.offset, 12181 instr->mov.src_val); 12182 } 12183 12184 static void 12185 instr_dma_ht_export(struct instruction *instr, FILE *f) 12186 { 12187 uint32_t n_dma = 0, i; 12188 12189 /* n_dma. */ 12190 n_dma = 1 + (instr->type - INSTR_DMA_HT); 12191 12192 /* instr. */ 12193 fprintf(f, 12194 "\t{\n" 12195 "\t\t.type = %s,\n", 12196 instr_type_to_name(instr)); 12197 12198 /* instr.dma. */ 12199 fprintf(f, 12200 "\t\t.dma = {\n"); 12201 12202 /* instr.dma.dst. */ 12203 fprintf(f, 12204 "\t\t\t.dst = {\n"); 12205 12206 /* instr.dma.dst.header_id. */ 12207 fprintf(f, 12208 "\t\t\t\t.header_id = {"); 12209 12210 for (i = 0; i < n_dma; i++) 12211 fprintf(f, 12212 "%u, ", 12213 instr->dma.dst.header_id[i]); 12214 12215 fprintf(f, 12216 "},\n"); 12217 12218 /* instr.dma.dst.struct_id. */ 12219 fprintf(f, 12220 "\t\t\t\t.struct_id = {"); 12221 12222 for (i = 0; i < n_dma; i++) 12223 fprintf(f, 12224 "%u, ", 12225 instr->dma.dst.struct_id[i]); 12226 12227 fprintf(f, 12228 "},\n"); 12229 12230 /* instr.dma.dst - closing curly brace. */ 12231 fprintf(f, 12232 "\t\t\t},\n"); 12233 12234 /* instr.dma.src. */ 12235 fprintf(f, 12236 "\t\t\t.src = {\n"); 12237 12238 /* instr.dma.src.offset. */ 12239 fprintf(f, 12240 "\t\t\t\t.offset = {"); 12241 12242 for (i = 0; i < n_dma; i++) 12243 fprintf(f, 12244 "%u, ", 12245 instr->dma.src.offset[i]); 12246 12247 fprintf(f, 12248 "},\n"); 12249 12250 /* instr.dma.src - closing curly brace. */ 12251 fprintf(f, 12252 "\t\t\t},\n"); 12253 12254 /* instr.dma.n_bytes. */ 12255 fprintf(f, 12256 "\t\t\t.n_bytes = {"); 12257 12258 for (i = 0; i < n_dma; i++) 12259 fprintf(f, 12260 "%u, ", 12261 instr->dma.n_bytes[i]); 12262 12263 fprintf(f, 12264 "},\n"); 12265 12266 /* instr.dma - closing curly brace. */ 12267 fprintf(f, 12268 "\t\t},\n"); 12269 12270 /* instr - closing curly brace. */ 12271 fprintf(f, 12272 "\t},\n"); 12273 } 12274 12275 static void 12276 instr_alu_export(struct instruction *instr, FILE *f) 12277 { 12278 int imm = 0; 12279 12280 if (instr->type == INSTR_ALU_ADD_MI || 12281 instr->type == INSTR_ALU_ADD_HI || 12282 instr->type == INSTR_ALU_SUB_MI || 12283 instr->type == INSTR_ALU_SUB_HI || 12284 instr->type == INSTR_ALU_SHL_MI || 12285 instr->type == INSTR_ALU_SHL_HI || 12286 instr->type == INSTR_ALU_SHR_MI || 12287 instr->type == INSTR_ALU_SHR_HI || 12288 instr->type == INSTR_ALU_AND_I || 12289 instr->type == INSTR_ALU_OR_I || 12290 instr->type == INSTR_ALU_XOR_I) 12291 imm = 1; 12292 12293 if (!imm) 12294 fprintf(f, 12295 "\t{\n" 12296 "\t\t.type = %s,\n" 12297 "\t\t.alu = {\n" 12298 "\t\t\t.dst = {\n" 12299 "\t\t\t\t.struct_id = %u,\n" 12300 "\t\t\t\t.n_bits = %u,\n" 12301 "\t\t\t\t.offset = %u,\n" 12302 "\t\t\t},\n" 12303 "\t\t\t.src = {\n" 12304 "\t\t\t\t.struct_id = %u,\n" 12305 "\t\t\t\t.n_bits = %u,\n" 12306 "\t\t\t\t.offset = %u,\n" 12307 "\t\t\t},\n" 12308 "\t\t},\n" 12309 "\t},\n", 12310 instr_type_to_name(instr), 12311 instr->alu.dst.struct_id, 12312 instr->alu.dst.n_bits, 12313 instr->alu.dst.offset, 12314 instr->alu.src.struct_id, 12315 instr->alu.src.n_bits, 12316 instr->alu.src.offset); 12317 else 12318 fprintf(f, 12319 "\t{\n" 12320 "\t\t.type = %s,\n" 12321 "\t\t.alu = {\n" 12322 "\t\t\t.dst = {\n" 12323 "\t\t\t\t.struct_id = %u,\n" 12324 "\t\t\t\t.n_bits = %u,\n" 12325 "\t\t\t\t.offset = %u,\n" 12326 "\t\t\t}\n," 12327 "\t\t\t.src_val = %" PRIu64 ",\n" 12328 "\t\t},\n" 12329 "\t},\n", 12330 instr_type_to_name(instr), 12331 instr->alu.dst.struct_id, 12332 instr->alu.dst.n_bits, 12333 instr->alu.dst.offset, 12334 instr->alu.src_val); 12335 } 12336 12337 static void 12338 instr_hash_export(struct instruction *instr, FILE *f) 12339 { 12340 fprintf(f, 12341 "\t{\n" 12342 "\t\t.type = %s,\n" 12343 "\t\t.hash_func = {\n" 12344 "\t\t\t.hash_func_id = %u,\n" 12345 "\t\t\t.dst = {\n" 12346 "\t\t\t\t.offset = %u,\n" 12347 "\t\t\t\t.n_bits = %u,\n" 12348 "\t\t\t},\n" 12349 "\t\t\t.src = {\n" 12350 "\t\t\t\t.struct_id = %u,\n" 12351 "\t\t\t\t.offset = %u,\n" 12352 "\t\t\t\t.n_bytes = %u,\n" 12353 "\t\t\t},\n" 12354 "\t\t},\n" 12355 "\t},\n", 12356 instr_type_to_name(instr), 12357 instr->hash_func.hash_func_id, 12358 instr->hash_func.dst.offset, 12359 instr->hash_func.dst.n_bits, 12360 instr->hash_func.src.struct_id, 12361 instr->hash_func.src.offset, 12362 instr->hash_func.src.n_bytes); 12363 } 12364 12365 static void 12366 instr_rss_export(struct instruction *instr, FILE *f) 12367 { 12368 fprintf(f, 12369 "\t{\n" 12370 "\t\t.type = %s,\n" 12371 "\t\t.rss = {\n" 12372 "\t\t\t.rss_obj_id = %u,\n" 12373 "\t\t\t.dst = {\n" 12374 "\t\t\t\t.offset = %u,\n" 12375 "\t\t\t\t.n_bits = %u,\n" 12376 "\t\t\t},\n" 12377 "\t\t\t.src = {\n" 12378 "\t\t\t\t.struct_id = %u,\n" 12379 "\t\t\t\t.offset = %u,\n" 12380 "\t\t\t\t.n_bytes = %u,\n" 12381 "\t\t\t},\n" 12382 "\t\t},\n" 12383 "\t},\n", 12384 instr_type_to_name(instr), 12385 instr->rss.rss_obj_id, 12386 instr->rss.dst.offset, 12387 instr->rss.dst.n_bits, 12388 instr->rss.src.struct_id, 12389 instr->rss.src.offset, 12390 instr->rss.src.n_bytes); 12391 } 12392 12393 static void 12394 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 12395 { 12396 int prefetch = 0, idx_imm = 0, src_imm = 0; 12397 12398 if (instr->type == INSTR_REGPREFETCH_RH || 12399 instr->type == INSTR_REGPREFETCH_RM || 12400 instr->type == INSTR_REGPREFETCH_RI) 12401 prefetch = 1; 12402 12403 /* index is the 3rd operand for the regrd instruction and the 2nd 12404 * operand for the regwr and regadd instructions. 12405 */ 12406 if (instr->type == INSTR_REGPREFETCH_RI || 12407 instr->type == INSTR_REGRD_HRI || 12408 instr->type == INSTR_REGRD_MRI || 12409 instr->type == INSTR_REGWR_RIH || 12410 instr->type == INSTR_REGWR_RIM || 12411 instr->type == INSTR_REGWR_RII || 12412 instr->type == INSTR_REGADD_RIH || 12413 instr->type == INSTR_REGADD_RIM || 12414 instr->type == INSTR_REGADD_RII) 12415 idx_imm = 1; 12416 12417 /* src is the 3rd operand for the regwr and regadd instructions. */ 12418 if (instr->type == INSTR_REGWR_RHI || 12419 instr->type == INSTR_REGWR_RMI || 12420 instr->type == INSTR_REGWR_RII || 12421 instr->type == INSTR_REGADD_RHI || 12422 instr->type == INSTR_REGADD_RMI || 12423 instr->type == INSTR_REGADD_RII) 12424 src_imm = 1; 12425 12426 /* instr.regarray.regarray_id. */ 12427 fprintf(f, 12428 "\t{\n" 12429 "\t\t.type = %s,\n" 12430 "\t\t.regarray = {\n" 12431 "\t\t\t.regarray_id = %u,\n", 12432 instr_type_to_name(instr), 12433 instr->regarray.regarray_id); 12434 12435 /* instr.regarray.idx / instr.regarray.idx_val. */ 12436 if (!idx_imm) 12437 fprintf(f, 12438 "\t\t\t\t.idx = {\n" 12439 "\t\t\t\t\t.struct_id = %u,\n" 12440 "\t\t\t\t\t.n_bits = %u,\n" 12441 "\t\t\t\t\t.offset = %u,\n" 12442 "\t\t\t\t},\n", 12443 instr->regarray.idx.struct_id, 12444 instr->regarray.idx.n_bits, 12445 instr->regarray.idx.offset); 12446 else 12447 fprintf(f, 12448 "\t\t\t\t.idx_val = %u,\n", 12449 instr->regarray.idx_val); 12450 12451 /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */ 12452 if (!prefetch) { 12453 if (!src_imm) 12454 fprintf(f, 12455 "\t\t\t\t.dstsrc = {\n" 12456 "\t\t\t\t\t.struct_id = %u,\n" 12457 "\t\t\t\t\t.n_bits = %u,\n" 12458 "\t\t\t\t\t.offset = %u,\n" 12459 "\t\t\t\t},\n", 12460 instr->regarray.dstsrc.struct_id, 12461 instr->regarray.dstsrc.n_bits, 12462 instr->regarray.dstsrc.offset); 12463 else 12464 fprintf(f, 12465 "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n", 12466 instr->regarray.dstsrc_val); 12467 } 12468 12469 /* instr.regarray and instr - closing curly braces. */ 12470 fprintf(f, 12471 "\t\t},\n" 12472 "\t},\n"); 12473 } 12474 12475 static void 12476 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 12477 { 12478 int prefetch = 0, idx_imm = 0, color_in_imm = 0; 12479 12480 if (instr->type == INSTR_METPREFETCH_H || 12481 instr->type == INSTR_METPREFETCH_M || 12482 instr->type == INSTR_METPREFETCH_I) 12483 prefetch = 1; 12484 12485 /* idx_imm. */ 12486 if (instr->type == INSTR_METPREFETCH_I || 12487 instr->type == INSTR_METER_IHM || 12488 instr->type == INSTR_METER_IHI || 12489 instr->type == INSTR_METER_IMM || 12490 instr->type == INSTR_METER_IMI) 12491 idx_imm = 1; 12492 12493 /* color_in_imm. */ 12494 if (instr->type == INSTR_METER_HHI || 12495 instr->type == INSTR_METER_HMI || 12496 instr->type == INSTR_METER_MHI || 12497 instr->type == INSTR_METER_MMI || 12498 instr->type == INSTR_METER_IHI || 12499 instr->type == INSTR_METER_IMI) 12500 color_in_imm = 1; 12501 12502 /* instr.meter.metarray_id. */ 12503 fprintf(f, 12504 "\t{\n" 12505 "\t\t.type = %s,\n" 12506 "\t\t.meter = {\n" 12507 "\t\t\t.metarray_id = %u,\n", 12508 instr_type_to_name(instr), 12509 instr->meter.metarray_id); 12510 12511 /* instr.meter.idx / instr.meter.idx_val. */ 12512 if (!idx_imm) 12513 fprintf(f, 12514 "\t\t\t.idx = {\n" 12515 "\t\t\t\t.struct_id = %u,\n" 12516 "\t\t\t\t.n_bits = %u,\n" 12517 "\t\t\t\t.offset = %u,\n" 12518 "\t\t\t},\n", 12519 instr->meter.idx.struct_id, 12520 instr->meter.idx.n_bits, 12521 instr->meter.idx.offset); 12522 else 12523 fprintf(f, 12524 "\t\t\t.idx_val = %u,\n", 12525 instr->meter.idx_val); 12526 12527 if (!prefetch) { 12528 /* instr.meter.length. */ 12529 fprintf(f, 12530 "\t\t\t.length = {\n" 12531 "\t\t\t\t.struct_id = %u,\n" 12532 "\t\t\t\t.n_bits = %u,\n" 12533 "\t\t\t\t.offset = %u,\n" 12534 "\t\t\t},\n", 12535 instr->meter.length.struct_id, 12536 instr->meter.length.n_bits, 12537 instr->meter.length.offset); 12538 12539 /* instr.meter.color_in / instr.meter.color_in_val. */ 12540 if (!color_in_imm) 12541 fprintf(f, 12542 "\t\t\t.color_in = {\n" 12543 "\t\t\t\t.struct_id = %u,\n" 12544 "\t\t\t\t.n_bits = %u,\n" 12545 "\t\t\t\t.offset = %u,\n" 12546 "\t\t\t},\n", 12547 instr->meter.color_in.struct_id, 12548 instr->meter.color_in.n_bits, 12549 instr->meter.color_in.offset); 12550 else 12551 fprintf(f, 12552 "\t\t\t.color_in_val = %u,\n", 12553 (uint32_t)instr->meter.color_in_val); 12554 12555 /* instr.meter.color_out. */ 12556 fprintf(f, 12557 "\t\t\t.color_out = {\n" 12558 "\t\t\t\t.struct_id = %u,\n" 12559 "\t\t\t\t.n_bits = %u,\n" 12560 "\t\t\t\t.offset = %u,\n" 12561 "\t\t\t},\n", 12562 instr->meter.color_out.struct_id, 12563 instr->meter.color_out.n_bits, 12564 instr->meter.color_out.offset); 12565 } 12566 12567 /* instr.meter and instr - closing curly braces. */ 12568 fprintf(f, 12569 "\t\t},\n" 12570 "\t},\n"); 12571 } 12572 12573 static void 12574 instr_table_export(struct instruction *instr, 12575 FILE *f) 12576 { 12577 fprintf(f, 12578 "\t{\n" 12579 "\t\t.type = %s,\n" 12580 "\t\t.table = {\n" 12581 "\t\t\t.table_id = %u,\n" 12582 "\t\t},\n" 12583 "\t},\n", 12584 instr_type_to_name(instr), 12585 instr->table.table_id); 12586 } 12587 12588 static void 12589 instr_learn_export(struct instruction *instr, FILE *f) 12590 { 12591 fprintf(f, 12592 "\t{\n" 12593 "\t\t.type = %s,\n" 12594 "\t\t.learn = {\n" 12595 "\t\t\t.action_id = %u,\n" 12596 "\t\t\t.mf_first_arg_offset = %u,\n" 12597 "\t\t\t.mf_timeout_id_offset = %u,\n" 12598 "\t\t\t.mf_timeout_id_n_bits = %u,\n" 12599 "\t\t},\n" 12600 "\t},\n", 12601 instr_type_to_name(instr), 12602 instr->learn.action_id, 12603 instr->learn.mf_first_arg_offset, 12604 instr->learn.mf_timeout_id_offset, 12605 instr->learn.mf_timeout_id_n_bits); 12606 } 12607 12608 static void 12609 instr_rearm_export(struct instruction *instr, FILE *f) 12610 { 12611 if (instr->type == INSTR_LEARNER_REARM) 12612 fprintf(f, 12613 "\t{\n" 12614 "\t\t.type = %s,\n" 12615 "\t},\n", 12616 instr_type_to_name(instr)); 12617 else 12618 fprintf(f, 12619 "\t{\n" 12620 "\t\t.type = %s,\n" 12621 "\t\t.learn = {\n" 12622 "\t\t\t.mf_timeout_id_offset = %u,\n" 12623 "\t\t\t.mf_timeout_id_n_bits = %u,\n" 12624 "\t\t},\n" 12625 "\t},\n", 12626 instr_type_to_name(instr), 12627 instr->learn.mf_timeout_id_offset, 12628 instr->learn.mf_timeout_id_n_bits); 12629 } 12630 12631 static void 12632 instr_forget_export(struct instruction *instr, FILE *f) 12633 { 12634 fprintf(f, 12635 "\t{\n" 12636 "\t\t.type = %s,\n" 12637 "\t},\n", 12638 instr_type_to_name(instr)); 12639 } 12640 12641 static void 12642 instr_entryid_export(struct instruction *instr, FILE *f) 12643 { 12644 fprintf(f, 12645 "\t{\n" 12646 "\t\t.type = %s,\n" 12647 "\t\t.mov = {\n" 12648 "\t\t\t.dst = {\n" 12649 "\t\t\t\t.n_bits = %u,\n" 12650 "\t\t\t\t.offset = %u,\n" 12651 "\t\t\t},\n" 12652 "\t\t},\n" 12653 "\t},\n", 12654 instr_type_to_name(instr), 12655 instr->mov.dst.n_bits, 12656 instr->mov.dst.offset); 12657 } 12658 12659 static void 12660 instr_extern_export(struct instruction *instr, FILE *f) 12661 { 12662 if (instr->type == INSTR_EXTERN_OBJ) 12663 fprintf(f, 12664 "\t{\n" 12665 "\t\t.type = %s,\n" 12666 "\t\t.ext_obj = {\n" 12667 "\t\t\t.ext_obj_id = %u,\n" 12668 "\t\t\t.func_id = %u,\n" 12669 "\t\t},\n" 12670 "\t},\n", 12671 instr_type_to_name(instr), 12672 instr->ext_obj.ext_obj_id, 12673 instr->ext_obj.func_id); 12674 else 12675 fprintf(f, 12676 "\t{\n" 12677 "\t\t.type = %s,\n" 12678 "\t\t.ext_func = {\n" 12679 "\t\t\t.ext_func_id = %u,\n" 12680 "\t\t},\n" 12681 "\t},\n", 12682 instr_type_to_name(instr), 12683 instr->ext_func.ext_func_id); 12684 } 12685 12686 static void 12687 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused) 12688 { 12689 fprintf(f, 12690 "\t{\n" 12691 "\t\t.type = %s,\n" 12692 "\t\t.jmp = {\n" 12693 "\t\t\t.ip = NULL,\n", 12694 instr_type_to_name(instr)); 12695 12696 switch (instr->type) { 12697 case INSTR_JMP_VALID: 12698 case INSTR_JMP_INVALID: 12699 fprintf(f, 12700 "\t\t\t.header_id = %u,\n", 12701 instr->jmp.header_id); 12702 break; 12703 12704 case INSTR_JMP_ACTION_HIT: 12705 case INSTR_JMP_ACTION_MISS: 12706 fprintf(f, 12707 "\t\t\t.action_id = %u,\n", 12708 instr->jmp.action_id); 12709 break; 12710 12711 case INSTR_JMP_EQ: 12712 case INSTR_JMP_EQ_MH: 12713 case INSTR_JMP_EQ_HM: 12714 case INSTR_JMP_EQ_HH: 12715 case INSTR_JMP_NEQ: 12716 case INSTR_JMP_NEQ_MH: 12717 case INSTR_JMP_NEQ_HM: 12718 case INSTR_JMP_NEQ_HH: 12719 case INSTR_JMP_LT: 12720 case INSTR_JMP_LT_MH: 12721 case INSTR_JMP_LT_HM: 12722 case INSTR_JMP_LT_HH: 12723 case INSTR_JMP_GT: 12724 case INSTR_JMP_GT_MH: 12725 case INSTR_JMP_GT_HM: 12726 case INSTR_JMP_GT_HH: 12727 fprintf(f, 12728 "\t\t\t.a = {\n" 12729 "\t\t\t\t.struct_id = %u,\n" 12730 "\t\t\t\t.n_bits = %u,\n" 12731 "\t\t\t\t.offset = %u,\n" 12732 "\t\t\t},\n" 12733 "\t\t\t.b = {\n" 12734 "\t\t\t\t.struct_id = %u,\n" 12735 "\t\t\t\t.n_bits = %u,\n" 12736 "\t\t\t\t.offset = %u,\n" 12737 "\t\t\t},\n", 12738 instr->jmp.a.struct_id, 12739 instr->jmp.a.n_bits, 12740 instr->jmp.a.offset, 12741 instr->jmp.b.struct_id, 12742 instr->jmp.b.n_bits, 12743 instr->jmp.b.offset); 12744 break; 12745 12746 case INSTR_JMP_EQ_I: 12747 case INSTR_JMP_NEQ_I: 12748 case INSTR_JMP_LT_MI: 12749 case INSTR_JMP_LT_HI: 12750 case INSTR_JMP_GT_MI: 12751 case INSTR_JMP_GT_HI: 12752 fprintf(f, 12753 "\t\t\t.a = {\n" 12754 "\t\t\t\t.struct_id = %u,\n" 12755 "\t\t\t\t.n_bits = %u,\n" 12756 "\t\t\t\t.offset = %u,\n" 12757 "\t\t\t}\n," 12758 "\t\t\t.b_val = %" PRIu64 ",\n", 12759 instr->jmp.a.struct_id, 12760 instr->jmp.a.n_bits, 12761 instr->jmp.a.offset, 12762 instr->jmp.b_val); 12763 break; 12764 12765 default: 12766 break; 12767 } 12768 12769 fprintf(f, 12770 "\t\t},\n" 12771 "\t},\n"); 12772 } 12773 12774 static void 12775 instr_return_export(struct instruction *instr, 12776 FILE *f) 12777 { 12778 fprintf(f, 12779 "\t{\n" 12780 "\t\t.type = %s,\n", 12781 instr_type_to_name(instr)); 12782 12783 fprintf(f, 12784 "\t},\n"); 12785 } 12786 12787 static instruction_export_t export_table[] = { 12788 [INSTR_RX] = instr_io_export, 12789 12790 [INSTR_TX] = instr_io_export, 12791 [INSTR_TX_I] = instr_io_export, 12792 [INSTR_DROP] = instr_io_export, 12793 [INSTR_MIRROR] = instr_mirror_export, 12794 [INSTR_RECIRCULATE] = instr_recirculate_export, 12795 [INSTR_RECIRCID] = instr_recircid_export, 12796 12797 [INSTR_HDR_EXTRACT] = instr_io_export, 12798 [INSTR_HDR_EXTRACT2] = instr_io_export, 12799 [INSTR_HDR_EXTRACT3] = instr_io_export, 12800 [INSTR_HDR_EXTRACT4] = instr_io_export, 12801 [INSTR_HDR_EXTRACT5] = instr_io_export, 12802 [INSTR_HDR_EXTRACT6] = instr_io_export, 12803 [INSTR_HDR_EXTRACT7] = instr_io_export, 12804 [INSTR_HDR_EXTRACT8] = instr_io_export, 12805 12806 [INSTR_HDR_EXTRACT_M] = instr_io_export, 12807 12808 [INSTR_HDR_LOOKAHEAD] = instr_io_export, 12809 12810 [INSTR_HDR_EMIT] = instr_io_export, 12811 [INSTR_HDR_EMIT_TX] = instr_io_export, 12812 [INSTR_HDR_EMIT2_TX] = instr_io_export, 12813 [INSTR_HDR_EMIT3_TX] = instr_io_export, 12814 [INSTR_HDR_EMIT4_TX] = instr_io_export, 12815 [INSTR_HDR_EMIT5_TX] = instr_io_export, 12816 [INSTR_HDR_EMIT6_TX] = instr_io_export, 12817 [INSTR_HDR_EMIT7_TX] = instr_io_export, 12818 [INSTR_HDR_EMIT8_TX] = instr_io_export, 12819 12820 [INSTR_HDR_VALIDATE] = instr_hdr_validate_export, 12821 [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export, 12822 12823 [INSTR_MOV] = instr_mov_export, 12824 [INSTR_MOV_MH] = instr_mov_export, 12825 [INSTR_MOV_HM] = instr_mov_export, 12826 [INSTR_MOV_HH] = instr_mov_export, 12827 [INSTR_MOV_DMA] = instr_mov_export, 12828 [INSTR_MOV_128] = instr_mov_export, 12829 [INSTR_MOV_128_32] = instr_mov_export, 12830 [INSTR_MOV_I] = instr_mov_export, 12831 12832 [INSTR_DMA_HT] = instr_dma_ht_export, 12833 [INSTR_DMA_HT2] = instr_dma_ht_export, 12834 [INSTR_DMA_HT3] = instr_dma_ht_export, 12835 [INSTR_DMA_HT4] = instr_dma_ht_export, 12836 [INSTR_DMA_HT5] = instr_dma_ht_export, 12837 [INSTR_DMA_HT6] = instr_dma_ht_export, 12838 [INSTR_DMA_HT7] = instr_dma_ht_export, 12839 [INSTR_DMA_HT8] = instr_dma_ht_export, 12840 12841 [INSTR_ALU_ADD] = instr_alu_export, 12842 [INSTR_ALU_ADD_MH] = instr_alu_export, 12843 [INSTR_ALU_ADD_HM] = instr_alu_export, 12844 [INSTR_ALU_ADD_HH] = instr_alu_export, 12845 [INSTR_ALU_ADD_MI] = instr_alu_export, 12846 [INSTR_ALU_ADD_HI] = instr_alu_export, 12847 12848 [INSTR_ALU_SUB] = instr_alu_export, 12849 [INSTR_ALU_SUB_MH] = instr_alu_export, 12850 [INSTR_ALU_SUB_HM] = instr_alu_export, 12851 [INSTR_ALU_SUB_HH] = instr_alu_export, 12852 [INSTR_ALU_SUB_MI] = instr_alu_export, 12853 [INSTR_ALU_SUB_HI] = instr_alu_export, 12854 12855 [INSTR_ALU_CKADD_FIELD] = instr_alu_export, 12856 [INSTR_ALU_CKADD_STRUCT] = instr_alu_export, 12857 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export, 12858 [INSTR_ALU_CKSUB_FIELD] = instr_alu_export, 12859 12860 [INSTR_ALU_AND] = instr_alu_export, 12861 [INSTR_ALU_AND_MH] = instr_alu_export, 12862 [INSTR_ALU_AND_HM] = instr_alu_export, 12863 [INSTR_ALU_AND_HH] = instr_alu_export, 12864 [INSTR_ALU_AND_I] = instr_alu_export, 12865 12866 [INSTR_ALU_OR] = instr_alu_export, 12867 [INSTR_ALU_OR_MH] = instr_alu_export, 12868 [INSTR_ALU_OR_HM] = instr_alu_export, 12869 [INSTR_ALU_OR_HH] = instr_alu_export, 12870 [INSTR_ALU_OR_I] = instr_alu_export, 12871 12872 [INSTR_ALU_XOR] = instr_alu_export, 12873 [INSTR_ALU_XOR_MH] = instr_alu_export, 12874 [INSTR_ALU_XOR_HM] = instr_alu_export, 12875 [INSTR_ALU_XOR_HH] = instr_alu_export, 12876 [INSTR_ALU_XOR_I] = instr_alu_export, 12877 12878 [INSTR_ALU_SHL] = instr_alu_export, 12879 [INSTR_ALU_SHL_MH] = instr_alu_export, 12880 [INSTR_ALU_SHL_HM] = instr_alu_export, 12881 [INSTR_ALU_SHL_HH] = instr_alu_export, 12882 [INSTR_ALU_SHL_MI] = instr_alu_export, 12883 [INSTR_ALU_SHL_HI] = instr_alu_export, 12884 12885 [INSTR_ALU_SHR] = instr_alu_export, 12886 [INSTR_ALU_SHR_MH] = instr_alu_export, 12887 [INSTR_ALU_SHR_HM] = instr_alu_export, 12888 [INSTR_ALU_SHR_HH] = instr_alu_export, 12889 [INSTR_ALU_SHR_MI] = instr_alu_export, 12890 [INSTR_ALU_SHR_HI] = instr_alu_export, 12891 12892 [INSTR_REGPREFETCH_RH] = instr_reg_export, 12893 [INSTR_REGPREFETCH_RM] = instr_reg_export, 12894 [INSTR_REGPREFETCH_RI] = instr_reg_export, 12895 12896 [INSTR_REGRD_HRH] = instr_reg_export, 12897 [INSTR_REGRD_HRM] = instr_reg_export, 12898 [INSTR_REGRD_MRH] = instr_reg_export, 12899 [INSTR_REGRD_MRM] = instr_reg_export, 12900 [INSTR_REGRD_HRI] = instr_reg_export, 12901 [INSTR_REGRD_MRI] = instr_reg_export, 12902 12903 [INSTR_REGWR_RHH] = instr_reg_export, 12904 [INSTR_REGWR_RHM] = instr_reg_export, 12905 [INSTR_REGWR_RMH] = instr_reg_export, 12906 [INSTR_REGWR_RMM] = instr_reg_export, 12907 [INSTR_REGWR_RHI] = instr_reg_export, 12908 [INSTR_REGWR_RMI] = instr_reg_export, 12909 [INSTR_REGWR_RIH] = instr_reg_export, 12910 [INSTR_REGWR_RIM] = instr_reg_export, 12911 [INSTR_REGWR_RII] = instr_reg_export, 12912 12913 [INSTR_REGADD_RHH] = instr_reg_export, 12914 [INSTR_REGADD_RHM] = instr_reg_export, 12915 [INSTR_REGADD_RMH] = instr_reg_export, 12916 [INSTR_REGADD_RMM] = instr_reg_export, 12917 [INSTR_REGADD_RHI] = instr_reg_export, 12918 [INSTR_REGADD_RMI] = instr_reg_export, 12919 [INSTR_REGADD_RIH] = instr_reg_export, 12920 [INSTR_REGADD_RIM] = instr_reg_export, 12921 [INSTR_REGADD_RII] = instr_reg_export, 12922 12923 [INSTR_METPREFETCH_H] = instr_meter_export, 12924 [INSTR_METPREFETCH_M] = instr_meter_export, 12925 [INSTR_METPREFETCH_I] = instr_meter_export, 12926 12927 [INSTR_METER_HHM] = instr_meter_export, 12928 [INSTR_METER_HHI] = instr_meter_export, 12929 [INSTR_METER_HMM] = instr_meter_export, 12930 [INSTR_METER_HMI] = instr_meter_export, 12931 [INSTR_METER_MHM] = instr_meter_export, 12932 [INSTR_METER_MHI] = instr_meter_export, 12933 [INSTR_METER_MMM] = instr_meter_export, 12934 [INSTR_METER_MMI] = instr_meter_export, 12935 [INSTR_METER_IHM] = instr_meter_export, 12936 [INSTR_METER_IHI] = instr_meter_export, 12937 [INSTR_METER_IMM] = instr_meter_export, 12938 [INSTR_METER_IMI] = instr_meter_export, 12939 12940 [INSTR_TABLE] = instr_table_export, 12941 [INSTR_TABLE_AF] = instr_table_export, 12942 [INSTR_SELECTOR] = instr_table_export, 12943 [INSTR_LEARNER] = instr_table_export, 12944 [INSTR_LEARNER_AF] = instr_table_export, 12945 12946 [INSTR_LEARNER_LEARN] = instr_learn_export, 12947 [INSTR_LEARNER_REARM] = instr_rearm_export, 12948 [INSTR_LEARNER_REARM_NEW] = instr_rearm_export, 12949 [INSTR_LEARNER_FORGET] = instr_forget_export, 12950 [INSTR_ENTRYID] = instr_entryid_export, 12951 12952 [INSTR_EXTERN_OBJ] = instr_extern_export, 12953 [INSTR_EXTERN_FUNC] = instr_extern_export, 12954 [INSTR_HASH_FUNC] = instr_hash_export, 12955 [INSTR_RSS] = instr_rss_export, 12956 12957 [INSTR_JMP] = instr_jmp_export, 12958 [INSTR_JMP_VALID] = instr_jmp_export, 12959 [INSTR_JMP_INVALID] = instr_jmp_export, 12960 [INSTR_JMP_HIT] = instr_jmp_export, 12961 [INSTR_JMP_MISS] = instr_jmp_export, 12962 [INSTR_JMP_ACTION_HIT] = instr_jmp_export, 12963 [INSTR_JMP_ACTION_MISS] = instr_jmp_export, 12964 12965 [INSTR_JMP_EQ] = instr_jmp_export, 12966 [INSTR_JMP_EQ_MH] = instr_jmp_export, 12967 [INSTR_JMP_EQ_HM] = instr_jmp_export, 12968 [INSTR_JMP_EQ_HH] = instr_jmp_export, 12969 [INSTR_JMP_EQ_I] = instr_jmp_export, 12970 12971 [INSTR_JMP_NEQ] = instr_jmp_export, 12972 [INSTR_JMP_NEQ_MH] = instr_jmp_export, 12973 [INSTR_JMP_NEQ_HM] = instr_jmp_export, 12974 [INSTR_JMP_NEQ_HH] = instr_jmp_export, 12975 [INSTR_JMP_NEQ_I] = instr_jmp_export, 12976 12977 [INSTR_JMP_LT] = instr_jmp_export, 12978 [INSTR_JMP_LT_MH] = instr_jmp_export, 12979 [INSTR_JMP_LT_HM] = instr_jmp_export, 12980 [INSTR_JMP_LT_HH] = instr_jmp_export, 12981 [INSTR_JMP_LT_MI] = instr_jmp_export, 12982 [INSTR_JMP_LT_HI] = instr_jmp_export, 12983 12984 [INSTR_JMP_GT] = instr_jmp_export, 12985 [INSTR_JMP_GT_MH] = instr_jmp_export, 12986 [INSTR_JMP_GT_HM] = instr_jmp_export, 12987 [INSTR_JMP_GT_HH] = instr_jmp_export, 12988 [INSTR_JMP_GT_MI] = instr_jmp_export, 12989 [INSTR_JMP_GT_HI] = instr_jmp_export, 12990 12991 [INSTR_RETURN] = instr_return_export, 12992 }; 12993 12994 static void 12995 action_data_codegen(struct action *a, FILE *f) 12996 { 12997 uint32_t i; 12998 12999 fprintf(f, 13000 "static const struct instruction action_%s_instructions[] = {\n", 13001 a->name); 13002 13003 for (i = 0; i < a->n_instructions; i++) { 13004 struct instruction *instr = &a->instructions[i]; 13005 instruction_export_t func = export_table[instr->type]; 13006 13007 func(instr, f); 13008 } 13009 13010 fprintf(f, "};\n"); 13011 } 13012 13013 static const char * 13014 instr_type_to_func(struct instruction *instr) 13015 { 13016 switch (instr->type) { 13017 case INSTR_RX: return NULL; 13018 13019 case INSTR_TX: return "__instr_tx_exec"; 13020 case INSTR_TX_I: return "__instr_tx_i_exec"; 13021 case INSTR_DROP: return "__instr_drop_exec"; 13022 case INSTR_MIRROR: return "__instr_mirror_exec"; 13023 case INSTR_RECIRCULATE: return "__instr_recirculate_exec"; 13024 case INSTR_RECIRCID: return "__instr_recircid_exec"; 13025 13026 case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; 13027 case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; 13028 case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec"; 13029 case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec"; 13030 case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec"; 13031 case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec"; 13032 case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec"; 13033 case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec"; 13034 13035 case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec"; 13036 13037 case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec"; 13038 13039 case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec"; 13040 case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec"; 13041 case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec"; 13042 case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec"; 13043 case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec"; 13044 case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec"; 13045 case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec"; 13046 case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec"; 13047 case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec"; 13048 13049 case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec"; 13050 case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec"; 13051 13052 case INSTR_MOV: return "__instr_mov_exec"; 13053 case INSTR_MOV_MH: return "__instr_mov_mh_exec"; 13054 case INSTR_MOV_HM: return "__instr_mov_hm_exec"; 13055 case INSTR_MOV_HH: return "__instr_mov_hh_exec"; 13056 case INSTR_MOV_DMA: return "__instr_mov_dma_exec"; 13057 case INSTR_MOV_128: return "__instr_mov_128_exec"; 13058 case INSTR_MOV_128_32: return "__instr_mov_128_32_exec"; 13059 case INSTR_MOV_I: return "__instr_mov_i_exec"; 13060 13061 case INSTR_DMA_HT: return "__instr_dma_ht_exec"; 13062 case INSTR_DMA_HT2: return "__instr_dma_ht2_exec"; 13063 case INSTR_DMA_HT3: return "__instr_dma_ht3_exec"; 13064 case INSTR_DMA_HT4: return "__instr_dma_ht4_exec"; 13065 case INSTR_DMA_HT5: return "__instr_dma_ht5_exec"; 13066 case INSTR_DMA_HT6: return "__instr_dma_ht6_exec"; 13067 case INSTR_DMA_HT7: return "__instr_dma_ht7_exec"; 13068 case INSTR_DMA_HT8: return "__instr_dma_ht8_exec"; 13069 13070 case INSTR_ALU_ADD: return "__instr_alu_add_exec"; 13071 case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec"; 13072 case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec"; 13073 case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec"; 13074 case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec"; 13075 case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec"; 13076 13077 case INSTR_ALU_SUB: return "__instr_alu_sub_exec"; 13078 case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec"; 13079 case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec"; 13080 case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec"; 13081 case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec"; 13082 case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec"; 13083 13084 case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec"; 13085 case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec"; 13086 case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec"; 13087 case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec"; 13088 13089 case INSTR_ALU_AND: return "__instr_alu_and_exec"; 13090 case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec"; 13091 case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec"; 13092 case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec"; 13093 case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec"; 13094 13095 case INSTR_ALU_OR: return "__instr_alu_or_exec"; 13096 case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec"; 13097 case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec"; 13098 case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec"; 13099 case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec"; 13100 13101 case INSTR_ALU_XOR: return "__instr_alu_xor_exec"; 13102 case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec"; 13103 case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec"; 13104 case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec"; 13105 case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec"; 13106 13107 case INSTR_ALU_SHL: return "__instr_alu_shl_exec"; 13108 case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec"; 13109 case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec"; 13110 case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec"; 13111 case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec"; 13112 case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec"; 13113 13114 case INSTR_ALU_SHR: return "__instr_alu_shr_exec"; 13115 case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec"; 13116 case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec"; 13117 case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec"; 13118 case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec"; 13119 case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec"; 13120 13121 case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec"; 13122 case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec"; 13123 case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec"; 13124 13125 case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec"; 13126 case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec"; 13127 case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec"; 13128 case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec"; 13129 case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec"; 13130 case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec"; 13131 13132 case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec"; 13133 case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec"; 13134 case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec"; 13135 case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec"; 13136 case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec"; 13137 case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec"; 13138 case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec"; 13139 case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec"; 13140 case INSTR_REGWR_RII: return "__instr_regwr_rii_exec"; 13141 13142 case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec"; 13143 case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec"; 13144 case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec"; 13145 case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec"; 13146 case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec"; 13147 case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec"; 13148 case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec"; 13149 case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec"; 13150 case INSTR_REGADD_RII: return "__instr_regadd_rii_exec"; 13151 13152 case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec"; 13153 case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec"; 13154 case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec"; 13155 13156 case INSTR_METER_HHM: return "__instr_meter_hhm_exec"; 13157 case INSTR_METER_HHI: return "__instr_meter_hhi_exec"; 13158 case INSTR_METER_HMM: return "__instr_meter_hmm_exec"; 13159 case INSTR_METER_HMI: return "__instr_meter_hmi_exec"; 13160 case INSTR_METER_MHM: return "__instr_meter_mhm_exec"; 13161 case INSTR_METER_MHI: return "__instr_meter_mhi_exec"; 13162 case INSTR_METER_MMM: return "__instr_meter_mmm_exec"; 13163 case INSTR_METER_MMI: return "__instr_meter_mmi_exec"; 13164 case INSTR_METER_IHM: return "__instr_meter_ihm_exec"; 13165 case INSTR_METER_IHI: return "__instr_meter_ihi_exec"; 13166 case INSTR_METER_IMM: return "__instr_meter_imm_exec"; 13167 case INSTR_METER_IMI: return "__instr_meter_imi_exec"; 13168 13169 case INSTR_TABLE: return NULL; 13170 case INSTR_TABLE_AF: return NULL; 13171 case INSTR_SELECTOR: return NULL; 13172 case INSTR_LEARNER: return NULL; 13173 case INSTR_LEARNER_AF: return NULL; 13174 13175 case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; 13176 case INSTR_LEARNER_REARM: return "__instr_rearm_exec"; 13177 case INSTR_LEARNER_REARM_NEW: return "__instr_rearm_new_exec"; 13178 case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; 13179 case INSTR_ENTRYID: return "__instr_entryid_exec"; 13180 13181 case INSTR_EXTERN_OBJ: return NULL; 13182 case INSTR_EXTERN_FUNC: return NULL; 13183 case INSTR_HASH_FUNC: return "__instr_hash_func_exec"; 13184 case INSTR_RSS: return "__instr_rss_exec"; 13185 13186 case INSTR_JMP: return NULL; 13187 case INSTR_JMP_VALID: return NULL; 13188 case INSTR_JMP_INVALID: return NULL; 13189 case INSTR_JMP_HIT: return NULL; 13190 case INSTR_JMP_MISS: return NULL; 13191 case INSTR_JMP_ACTION_HIT: return NULL; 13192 case INSTR_JMP_ACTION_MISS: return NULL; 13193 case INSTR_JMP_EQ: return NULL; 13194 case INSTR_JMP_EQ_MH: return NULL; 13195 case INSTR_JMP_EQ_HM: return NULL; 13196 case INSTR_JMP_EQ_HH: return NULL; 13197 case INSTR_JMP_EQ_I: return NULL; 13198 case INSTR_JMP_NEQ: return NULL; 13199 case INSTR_JMP_NEQ_MH: return NULL; 13200 case INSTR_JMP_NEQ_HM: return NULL; 13201 case INSTR_JMP_NEQ_HH: return NULL; 13202 case INSTR_JMP_NEQ_I: return NULL; 13203 case INSTR_JMP_LT: return NULL; 13204 case INSTR_JMP_LT_MH: return NULL; 13205 case INSTR_JMP_LT_HM: return NULL; 13206 case INSTR_JMP_LT_HH: return NULL; 13207 case INSTR_JMP_LT_MI: return NULL; 13208 case INSTR_JMP_LT_HI: return NULL; 13209 case INSTR_JMP_GT: return NULL; 13210 case INSTR_JMP_GT_MH: return NULL; 13211 case INSTR_JMP_GT_HM: return NULL; 13212 case INSTR_JMP_GT_HH: return NULL; 13213 case INSTR_JMP_GT_MI: return NULL; 13214 case INSTR_JMP_GT_HI: return NULL; 13215 13216 case INSTR_RETURN: return NULL; 13217 13218 default: return NULL; 13219 } 13220 } 13221 13222 static void 13223 action_instr_does_tx_codegen(struct action *a, 13224 uint32_t instr_pos, 13225 struct instruction *instr, 13226 FILE *f) 13227 { 13228 fprintf(f, 13229 "%s(p, t, &action_%s_instructions[%u]);\n" 13230 "\tthread_ip_reset(p, t);\n" 13231 "\tinstr_rx_exec(p);\n" 13232 "\treturn;\n", 13233 instr_type_to_func(instr), 13234 a->name, 13235 instr_pos); 13236 } 13237 13238 static void 13239 action_instr_extern_obj_codegen(struct action *a, 13240 uint32_t instr_pos, 13241 FILE *f) 13242 { 13243 fprintf(f, 13244 "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n", 13245 a->name, 13246 instr_pos); 13247 } 13248 13249 static void 13250 action_instr_extern_func_codegen(struct action *a, 13251 uint32_t instr_pos, 13252 FILE *f) 13253 { 13254 fprintf(f, 13255 "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n", 13256 a->name, 13257 instr_pos); 13258 } 13259 13260 static void 13261 action_instr_jmp_codegen(struct action *a, 13262 uint32_t instr_pos, 13263 struct instruction *instr, 13264 struct instruction_data *data, 13265 FILE *f) 13266 { 13267 switch (instr->type) { 13268 case INSTR_JMP: 13269 fprintf(f, 13270 "goto %s;\n", 13271 data->jmp_label); 13272 return; 13273 13274 case INSTR_JMP_VALID: 13275 fprintf(f, 13276 "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 13277 "\t\tgoto %s;\n", 13278 a->name, 13279 instr_pos, 13280 data->jmp_label); 13281 return; 13282 13283 case INSTR_JMP_INVALID: 13284 fprintf(f, 13285 "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 13286 "\t\tgoto %s;\n", 13287 a->name, 13288 instr_pos, 13289 data->jmp_label); 13290 return; 13291 13292 case INSTR_JMP_HIT: 13293 fprintf(f, 13294 "if (t->hit)\n" 13295 "\t\tgoto %s;\n", 13296 data->jmp_label); 13297 return; 13298 13299 case INSTR_JMP_MISS: 13300 fprintf(f, 13301 "if (!t->hit)\n" 13302 "\t\tgoto %s;\n", 13303 data->jmp_label); 13304 return; 13305 13306 case INSTR_JMP_ACTION_HIT: 13307 fprintf(f, 13308 "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n" 13309 "\t\tgoto %s;\n", 13310 a->name, 13311 instr_pos, 13312 data->jmp_label); 13313 return; 13314 13315 case INSTR_JMP_ACTION_MISS: 13316 fprintf(f, 13317 "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n" 13318 "\t\tgoto %s;\n", 13319 a->name, 13320 instr_pos, 13321 data->jmp_label); 13322 return; 13323 13324 case INSTR_JMP_EQ: 13325 fprintf(f, 13326 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 13327 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13328 "\t\tgoto %s;\n", 13329 a->name, 13330 instr_pos, 13331 a->name, 13332 instr_pos, 13333 data->jmp_label); 13334 return; 13335 13336 case INSTR_JMP_EQ_MH: 13337 fprintf(f, 13338 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 13339 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13340 "\t\tgoto %s;\n", 13341 a->name, 13342 instr_pos, 13343 a->name, 13344 instr_pos, 13345 data->jmp_label); 13346 return; 13347 13348 case INSTR_JMP_EQ_HM: 13349 fprintf(f, 13350 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 13351 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13352 "\t\tgoto %s;\n", 13353 a->name, 13354 instr_pos, 13355 a->name, 13356 instr_pos, 13357 data->jmp_label); 13358 return; 13359 13360 case INSTR_JMP_EQ_HH: 13361 fprintf(f, 13362 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 13363 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13364 "\t\tgoto %s;\n", 13365 a->name, 13366 instr_pos, 13367 a->name, 13368 instr_pos, 13369 data->jmp_label); 13370 return; 13371 13372 case INSTR_JMP_EQ_I: 13373 fprintf(f, 13374 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 13375 "action_%s_instructions[%u].jmp.b_val)\n" 13376 "\t\tgoto %s;\n", 13377 a->name, 13378 instr_pos, 13379 a->name, 13380 instr_pos, 13381 data->jmp_label); 13382 return; 13383 13384 case INSTR_JMP_NEQ: 13385 fprintf(f, 13386 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 13387 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13388 "\t\tgoto %s;\n", 13389 a->name, 13390 instr_pos, 13391 a->name, 13392 instr_pos, 13393 data->jmp_label); 13394 return; 13395 13396 case INSTR_JMP_NEQ_MH: 13397 fprintf(f, 13398 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 13399 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13400 "\t\tgoto %s;\n", 13401 a->name, 13402 instr_pos, 13403 a->name, 13404 instr_pos, 13405 data->jmp_label); 13406 return; 13407 13408 case INSTR_JMP_NEQ_HM: 13409 fprintf(f, 13410 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 13411 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13412 "\t\tgoto %s;\n", 13413 a->name, 13414 instr_pos, 13415 a->name, 13416 instr_pos, 13417 data->jmp_label); 13418 return; 13419 13420 case INSTR_JMP_NEQ_HH: 13421 fprintf(f, 13422 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 13423 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13424 "\t\tgoto %s;\n", 13425 a->name, 13426 instr_pos, 13427 a->name, 13428 instr_pos, 13429 data->jmp_label); 13430 return; 13431 13432 case INSTR_JMP_NEQ_I: 13433 fprintf(f, 13434 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 13435 "action_%s_instructions[%u].jmp.b_val)\n" 13436 "\t\tgoto %s;\n", 13437 a->name, 13438 instr_pos, 13439 a->name, 13440 instr_pos, 13441 data->jmp_label); 13442 return; 13443 13444 case INSTR_JMP_LT: 13445 fprintf(f, 13446 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 13447 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13448 "\t\tgoto %s;\n", 13449 a->name, 13450 instr_pos, 13451 a->name, 13452 instr_pos, 13453 data->jmp_label); 13454 return; 13455 13456 case INSTR_JMP_LT_MH: 13457 fprintf(f, 13458 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 13459 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13460 "\t\tgoto %s;\n", 13461 a->name, 13462 instr_pos, 13463 a->name, 13464 instr_pos, 13465 data->jmp_label); 13466 return; 13467 13468 case INSTR_JMP_LT_HM: 13469 fprintf(f, 13470 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 13471 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13472 "\t\tgoto %s;\n", 13473 a->name, 13474 instr_pos, 13475 a->name, 13476 instr_pos, 13477 data->jmp_label); 13478 return; 13479 13480 case INSTR_JMP_LT_HH: 13481 fprintf(f, 13482 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 13483 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13484 "\t\tgoto %s;\n", 13485 a->name, 13486 instr_pos, 13487 a->name, 13488 instr_pos, 13489 data->jmp_label); 13490 return; 13491 13492 case INSTR_JMP_LT_MI: 13493 fprintf(f, 13494 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 13495 "action_%s_instructions[%u].jmp.b_val)\n" 13496 "\t\tgoto %s;\n", 13497 a->name, 13498 instr_pos, 13499 a->name, 13500 instr_pos, 13501 data->jmp_label); 13502 return; 13503 13504 case INSTR_JMP_LT_HI: 13505 fprintf(f, 13506 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 13507 "action_%s_instructions[%u].jmp.b_val)\n" 13508 "\t\tgoto %s;\n", 13509 a->name, 13510 instr_pos, 13511 a->name, 13512 instr_pos, 13513 data->jmp_label); 13514 return; 13515 13516 case INSTR_JMP_GT: 13517 fprintf(f, 13518 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 13519 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13520 "\t\tgoto %s;\n", 13521 a->name, 13522 instr_pos, 13523 a->name, 13524 instr_pos, 13525 data->jmp_label); 13526 return; 13527 13528 case INSTR_JMP_GT_MH: 13529 fprintf(f, 13530 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 13531 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13532 "\t\tgoto %s;\n", 13533 a->name, 13534 instr_pos, 13535 a->name, 13536 instr_pos, 13537 data->jmp_label); 13538 return; 13539 13540 case INSTR_JMP_GT_HM: 13541 fprintf(f, 13542 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 13543 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 13544 "\t\tgoto %s;\n", 13545 a->name, 13546 instr_pos, 13547 a->name, 13548 instr_pos, 13549 data->jmp_label); 13550 return; 13551 13552 case INSTR_JMP_GT_HH: 13553 fprintf(f, 13554 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 13555 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 13556 "\t\tgoto %s;\n", 13557 a->name, 13558 instr_pos, 13559 a->name, 13560 instr_pos, 13561 data->jmp_label); 13562 return; 13563 13564 case INSTR_JMP_GT_MI: 13565 fprintf(f, 13566 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 13567 "action_%s_instructions[%u].jmp.b_val)\n" 13568 "\t\tgoto %s;\n", 13569 a->name, 13570 instr_pos, 13571 a->name, 13572 instr_pos, 13573 data->jmp_label); 13574 return; 13575 13576 case INSTR_JMP_GT_HI: 13577 fprintf(f, 13578 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 13579 "action_%s_instructions[%u].jmp.b_val)\n" 13580 "\t\tgoto %s;\n", 13581 a->name, 13582 instr_pos, 13583 a->name, 13584 instr_pos, 13585 data->jmp_label); 13586 return; 13587 13588 default: 13589 return; 13590 } 13591 } 13592 13593 static void 13594 action_instr_return_codegen(FILE *f) 13595 { 13596 fprintf(f, 13597 "return;\n"); 13598 } 13599 13600 static void 13601 action_instr_codegen(struct action *a, FILE *f) 13602 { 13603 uint32_t i; 13604 13605 fprintf(f, 13606 "void\n" 13607 "action_%s_run(struct rte_swx_pipeline *p)\n" 13608 "{\n" 13609 "\tstruct thread *t = &p->threads[p->thread_id];\n" 13610 "\n", 13611 a->name); 13612 13613 for (i = 0; i < a->n_instructions; i++) { 13614 struct instruction *instr = &a->instructions[i]; 13615 struct instruction_data *data = &a->instruction_data[i]; 13616 13617 /* Label, if present. */ 13618 if (data->label[0]) 13619 fprintf(f, "\n%s : ", data->label); 13620 else 13621 fprintf(f, "\n\t"); 13622 13623 /* TX instruction type. */ 13624 if (instruction_does_tx(instr)) { 13625 action_instr_does_tx_codegen(a, i, instr, f); 13626 continue; 13627 } 13628 13629 /* Extern object/function instruction type. */ 13630 if (instr->type == INSTR_EXTERN_OBJ) { 13631 action_instr_extern_obj_codegen(a, i, f); 13632 continue; 13633 } 13634 13635 if (instr->type == INSTR_EXTERN_FUNC) { 13636 action_instr_extern_func_codegen(a, i, f); 13637 continue; 13638 } 13639 13640 /* Jump instruction type. */ 13641 if (instruction_is_jmp(instr)) { 13642 action_instr_jmp_codegen(a, i, instr, data, f); 13643 continue; 13644 } 13645 13646 /* Return instruction type. */ 13647 if (instr->type == INSTR_RETURN) { 13648 action_instr_return_codegen(f); 13649 continue; 13650 } 13651 13652 /* Any other instruction type. */ 13653 fprintf(f, 13654 "%s(p, t, &action_%s_instructions[%u]);\n", 13655 instr_type_to_func(instr), 13656 a->name, 13657 i); 13658 } 13659 13660 fprintf(f, "}\n\n"); 13661 } 13662 13663 struct instruction_group { 13664 TAILQ_ENTRY(instruction_group) node; 13665 13666 uint32_t group_id; 13667 13668 uint32_t first_instr_id; 13669 13670 uint32_t last_instr_id; 13671 13672 instr_exec_t func; 13673 }; 13674 13675 TAILQ_HEAD(instruction_group_list, instruction_group); 13676 13677 static struct instruction_group * 13678 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id) 13679 { 13680 struct instruction_group *g; 13681 13682 TAILQ_FOREACH(g, igl, node) 13683 if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id)) 13684 return g; 13685 13686 return NULL; 13687 } 13688 13689 static void 13690 instruction_group_list_free(struct instruction_group_list *igl) 13691 { 13692 if (!igl) 13693 return; 13694 13695 for ( ; ; ) { 13696 struct instruction_group *g; 13697 13698 g = TAILQ_FIRST(igl); 13699 if (!g) 13700 break; 13701 13702 TAILQ_REMOVE(igl, g, node); 13703 free(g); 13704 } 13705 13706 free(igl); 13707 } 13708 13709 static struct instruction_group_list * 13710 instruction_group_list_create(struct rte_swx_pipeline *p) 13711 { 13712 struct instruction_group_list *igl = NULL; 13713 struct instruction_group *g = NULL; 13714 uint32_t n_groups = 0, i; 13715 13716 if (!p || !p->instructions || !p->instruction_data || !p->n_instructions) 13717 goto error; 13718 13719 /* List init. */ 13720 igl = calloc(1, sizeof(struct instruction_group_list)); 13721 if (!igl) 13722 goto error; 13723 13724 TAILQ_INIT(igl); 13725 13726 /* Allocate the first group. */ 13727 g = calloc(1, sizeof(struct instruction_group)); 13728 if (!g) 13729 goto error; 13730 13731 /* Iteration 1: Separate the instructions into groups based on the thread yield 13732 * instructions. Do not worry about the jump instructions at this point. 13733 */ 13734 for (i = 0; i < p->n_instructions; i++) { 13735 struct instruction *instr = &p->instructions[i]; 13736 13737 /* Check for thread yield instructions. */ 13738 if (!instruction_does_thread_yield(instr)) 13739 continue; 13740 13741 /* If the current group contains at least one instruction, then finalize it (with 13742 * the previous instruction), add it to the list and allocate a new group (that 13743 * starts with the current instruction). 13744 */ 13745 if (i - g->first_instr_id) { 13746 /* Finalize the group. */ 13747 g->last_instr_id = i - 1; 13748 13749 /* Add the group to the list. Advance the number of groups. */ 13750 TAILQ_INSERT_TAIL(igl, g, node); 13751 n_groups++; 13752 13753 /* Allocate a new group. */ 13754 g = calloc(1, sizeof(struct instruction_group)); 13755 if (!g) 13756 goto error; 13757 13758 /* Initialize the new group. */ 13759 g->group_id = n_groups; 13760 g->first_instr_id = i; 13761 } 13762 13763 /* Finalize the current group (with the current instruction, therefore this group 13764 * contains just the current thread yield instruction), add it to the list and 13765 * allocate a new group (that starts with the next instruction). 13766 */ 13767 13768 /* Finalize the group. */ 13769 g->last_instr_id = i; 13770 13771 /* Add the group to the list. Advance the number of groups. */ 13772 TAILQ_INSERT_TAIL(igl, g, node); 13773 n_groups++; 13774 13775 /* Allocate a new group. */ 13776 g = calloc(1, sizeof(struct instruction_group)); 13777 if (!g) 13778 goto error; 13779 13780 /* Initialize the new group. */ 13781 g->group_id = n_groups; 13782 g->first_instr_id = i + 1; 13783 } 13784 13785 /* Handle the last group. */ 13786 if (i - g->first_instr_id) { 13787 /* Finalize the group. */ 13788 g->last_instr_id = i - 1; 13789 13790 /* Add the group to the list. Advance the number of groups. */ 13791 TAILQ_INSERT_TAIL(igl, g, node); 13792 n_groups++; 13793 } else 13794 free(g); 13795 13796 g = NULL; 13797 13798 /* Iteration 2: Handle jumps. If the current group contains an instruction which represents 13799 * the destination of a jump instruction located in a different group ("far jump"), then the 13800 * current group has to be split, so that the instruction representing the far jump 13801 * destination is at the start of its group. 13802 */ 13803 for ( ; ; ) { 13804 int is_modified = 0; 13805 13806 for (i = 0; i < p->n_instructions; i++) { 13807 struct instruction_data *data = &p->instruction_data[i]; 13808 struct instruction_group *g; 13809 uint32_t j; 13810 13811 /* Continue when the current instruction is not a jump destination. */ 13812 if (!data->n_users) 13813 continue; 13814 13815 g = instruction_group_list_group_find(igl, i); 13816 if (!g) 13817 goto error; 13818 13819 /* Find out all the jump instructions with this destination. */ 13820 for (j = 0; j < p->n_instructions; j++) { 13821 struct instruction *jmp_instr = &p->instructions[j]; 13822 struct instruction_data *jmp_data = &p->instruction_data[j]; 13823 struct instruction_group *jmp_g, *new_g; 13824 13825 /* Continue when not a jump instruction. Even when jump instruction, 13826 * continue when the jump destination is not this instruction. 13827 */ 13828 if (!instruction_is_jmp(jmp_instr) || 13829 strcmp(jmp_data->jmp_label, data->label)) 13830 continue; 13831 13832 jmp_g = instruction_group_list_group_find(igl, j); 13833 if (!jmp_g) 13834 goto error; 13835 13836 /* Continue when both the jump instruction and the jump destination 13837 * instruction are in the same group. Even when in different groups, 13838 * still continue if the jump destination instruction is already the 13839 * first instruction of its group. 13840 */ 13841 if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i)) 13842 continue; 13843 13844 /* Split the group of the current jump destination instruction to 13845 * make this instruction the first instruction of a new group. 13846 */ 13847 new_g = calloc(1, sizeof(struct instruction_group)); 13848 if (!new_g) 13849 goto error; 13850 13851 new_g->group_id = n_groups; 13852 new_g->first_instr_id = i; 13853 new_g->last_instr_id = g->last_instr_id; 13854 13855 g->last_instr_id = i - 1; 13856 13857 TAILQ_INSERT_AFTER(igl, g, new_g, node); 13858 n_groups++; 13859 is_modified = 1; 13860 13861 /* The decision to split this group (to make the current instruction 13862 * the first instruction of a new group) is already taken and fully 13863 * implemented, so no need to search for more reasons to do it. 13864 */ 13865 break; 13866 } 13867 } 13868 13869 /* Re-evaluate everything, as at least one group got split, so some jumps that were 13870 * previously considered local (i.e. the jump destination is in the same group as 13871 * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a 13872 * different group than the jump instruction). Wost case scenario: each instruction 13873 * that is a jump destination ends up as the first instruction of its group. 13874 */ 13875 if (!is_modified) 13876 break; 13877 } 13878 13879 /* Re-assign the group IDs to be in incremental order. */ 13880 i = 0; 13881 TAILQ_FOREACH(g, igl, node) { 13882 g->group_id = i; 13883 13884 i++; 13885 } 13886 13887 return igl; 13888 13889 error: 13890 instruction_group_list_free(igl); 13891 13892 free(g); 13893 13894 return NULL; 13895 } 13896 13897 static void 13898 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused, 13899 uint32_t instr_pos, 13900 struct instruction *instr, 13901 FILE *f) 13902 { 13903 fprintf(f, 13904 "%s(p, t, &pipeline_instructions[%u]);\n" 13905 "\tthread_ip_reset(p, t);\n" 13906 "\tinstr_rx_exec(p);\n" 13907 "\treturn;\n", 13908 instr_type_to_func(instr), 13909 instr_pos); 13910 } 13911 13912 static int 13913 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p, 13914 struct instruction_group_list *igl, 13915 uint32_t jmp_instr_id, 13916 struct instruction *jmp_instr, 13917 struct instruction_data *jmp_data, 13918 FILE *f) 13919 { 13920 struct instruction_group *jmp_g, *g; 13921 struct instruction_data *data; 13922 uint32_t instr_id; 13923 13924 switch (jmp_instr->type) { 13925 case INSTR_JMP: 13926 break; 13927 13928 case INSTR_JMP_VALID: 13929 fprintf(f, 13930 "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 13931 jmp_instr_id); 13932 break; 13933 13934 case INSTR_JMP_INVALID: 13935 fprintf(f, 13936 "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 13937 jmp_instr_id); 13938 break; 13939 13940 case INSTR_JMP_HIT: 13941 fprintf(f, 13942 "if (t->hit)\n"); 13943 break; 13944 13945 case INSTR_JMP_MISS: 13946 fprintf(f, 13947 "if (!t->hit)\n"); 13948 break; 13949 13950 case INSTR_JMP_ACTION_HIT: 13951 fprintf(f, 13952 "if (t->action_id == pipeline_instructions[%u].jmp.action_id)", 13953 jmp_instr_id); 13954 break; 13955 13956 case INSTR_JMP_ACTION_MISS: 13957 fprintf(f, 13958 "if (t->action_id != pipeline_instructions[%u].jmp.action_id)", 13959 jmp_instr_id); 13960 break; 13961 13962 case INSTR_JMP_EQ: 13963 fprintf(f, 13964 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 13965 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 13966 jmp_instr_id, 13967 jmp_instr_id); 13968 break; 13969 13970 case INSTR_JMP_EQ_MH: 13971 fprintf(f, 13972 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 13973 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 13974 jmp_instr_id, 13975 jmp_instr_id); 13976 break; 13977 13978 case INSTR_JMP_EQ_HM: 13979 fprintf(f, 13980 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 13981 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 13982 jmp_instr_id, 13983 jmp_instr_id); 13984 break; 13985 13986 case INSTR_JMP_EQ_HH: 13987 fprintf(f, 13988 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 13989 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 13990 jmp_instr_id, 13991 jmp_instr_id); 13992 break; 13993 13994 case INSTR_JMP_EQ_I: 13995 fprintf(f, 13996 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 13997 "pipeline_instructions[%u].jmp.b_val)", 13998 jmp_instr_id, 13999 jmp_instr_id); 14000 break; 14001 14002 case INSTR_JMP_NEQ: 14003 fprintf(f, 14004 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 14005 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14006 jmp_instr_id, 14007 jmp_instr_id); 14008 break; 14009 14010 case INSTR_JMP_NEQ_MH: 14011 fprintf(f, 14012 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 14013 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14014 jmp_instr_id, 14015 jmp_instr_id); 14016 break; 14017 14018 case INSTR_JMP_NEQ_HM: 14019 fprintf(f, 14020 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 14021 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14022 jmp_instr_id, 14023 jmp_instr_id); 14024 break; 14025 14026 case INSTR_JMP_NEQ_HH: 14027 fprintf(f, 14028 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 14029 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14030 jmp_instr_id, 14031 jmp_instr_id); 14032 break; 14033 14034 case INSTR_JMP_NEQ_I: 14035 fprintf(f, 14036 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 14037 "pipeline_instructions[%u].jmp.b_val)", 14038 jmp_instr_id, 14039 jmp_instr_id); 14040 break; 14041 14042 case INSTR_JMP_LT: 14043 fprintf(f, 14044 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 14045 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14046 jmp_instr_id, 14047 jmp_instr_id); 14048 break; 14049 14050 case INSTR_JMP_LT_MH: 14051 fprintf(f, 14052 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 14053 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14054 jmp_instr_id, 14055 jmp_instr_id); 14056 break; 14057 14058 case INSTR_JMP_LT_HM: 14059 fprintf(f, 14060 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 14061 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14062 jmp_instr_id, 14063 jmp_instr_id); 14064 break; 14065 14066 case INSTR_JMP_LT_HH: 14067 fprintf(f, 14068 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 14069 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14070 jmp_instr_id, 14071 jmp_instr_id); 14072 break; 14073 14074 case INSTR_JMP_LT_MI: 14075 fprintf(f, 14076 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 14077 "pipeline_instructions[%u].jmp.b_val)", 14078 jmp_instr_id, 14079 jmp_instr_id); 14080 break; 14081 14082 case INSTR_JMP_LT_HI: 14083 fprintf(f, 14084 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 14085 "pipeline_instructions[%u].jmp.b_val)", 14086 jmp_instr_id, 14087 jmp_instr_id); 14088 break; 14089 14090 case INSTR_JMP_GT: 14091 fprintf(f, 14092 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 14093 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14094 jmp_instr_id, 14095 jmp_instr_id); 14096 break; 14097 14098 case INSTR_JMP_GT_MH: 14099 fprintf(f, 14100 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 14101 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14102 jmp_instr_id, 14103 jmp_instr_id); 14104 break; 14105 14106 case INSTR_JMP_GT_HM: 14107 fprintf(f, 14108 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 14109 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 14110 jmp_instr_id, 14111 jmp_instr_id); 14112 break; 14113 14114 case INSTR_JMP_GT_HH: 14115 fprintf(f, 14116 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 14117 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 14118 jmp_instr_id, 14119 jmp_instr_id); 14120 break; 14121 14122 case INSTR_JMP_GT_MI: 14123 fprintf(f, 14124 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 14125 "pipeline_instructions[%u].jmp.b_val)", 14126 jmp_instr_id, 14127 jmp_instr_id); 14128 break; 14129 14130 case INSTR_JMP_GT_HI: 14131 fprintf(f, 14132 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 14133 "pipeline_instructions[%u].jmp.b_val)", 14134 jmp_instr_id, 14135 jmp_instr_id); 14136 break; 14137 14138 default: 14139 break; 14140 } 14141 14142 /* Find the instruction group of the jump instruction. */ 14143 jmp_g = instruction_group_list_group_find(igl, jmp_instr_id); 14144 if (!jmp_g) 14145 return -EINVAL; 14146 14147 /* Find the instruction group of the jump destination instruction. */ 14148 data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label); 14149 if (!data) 14150 return -EINVAL; 14151 14152 instr_id = data - p->instruction_data; 14153 14154 g = instruction_group_list_group_find(igl, instr_id); 14155 if (!g) 14156 return -EINVAL; 14157 14158 /* Code generation for "near" jump (same instruction group) or "far" jump (different 14159 * instruction group). 14160 */ 14161 if (g->group_id == jmp_g->group_id) 14162 fprintf(f, 14163 "\n\t\tgoto %s;\n", 14164 jmp_data->jmp_label); 14165 else 14166 fprintf(f, 14167 " {\n" 14168 "\t\tthread_ip_set(t, &p->instructions[%u]);\n" 14169 "\t\treturn;\n" 14170 "\t}\n\n", 14171 g->group_id); 14172 14173 return 0; 14174 } 14175 14176 static void 14177 instruction_group_list_codegen(struct instruction_group_list *igl, 14178 struct rte_swx_pipeline *p, 14179 FILE *f) 14180 { 14181 struct instruction_group *g; 14182 uint32_t i; 14183 int is_required = 0; 14184 14185 /* Check if code generation is required. */ 14186 TAILQ_FOREACH(g, igl, node) 14187 if (g->first_instr_id < g->last_instr_id) 14188 is_required = 1; 14189 14190 if (!is_required) 14191 return; 14192 14193 /* Generate the code for the pipeline instruction array. */ 14194 fprintf(f, 14195 "static const struct instruction pipeline_instructions[] = {\n"); 14196 14197 for (i = 0; i < p->n_instructions; i++) { 14198 struct instruction *instr = &p->instructions[i]; 14199 instruction_export_t func = export_table[instr->type]; 14200 14201 func(instr, f); 14202 } 14203 14204 fprintf(f, "};\n\n"); 14205 14206 /* Generate the code for the pipeline functions: one function for each instruction group 14207 * that contains more than one instruction. 14208 */ 14209 TAILQ_FOREACH(g, igl, node) { 14210 struct instruction *last_instr; 14211 uint32_t j; 14212 14213 /* Skip if group contains a single instruction. */ 14214 if (g->last_instr_id == g->first_instr_id) 14215 continue; 14216 14217 /* Generate new pipeline function. */ 14218 fprintf(f, 14219 "void\n" 14220 "pipeline_func_%u(struct rte_swx_pipeline *p)\n" 14221 "{\n" 14222 "\tstruct thread *t = &p->threads[p->thread_id];\n" 14223 "\n", 14224 g->group_id); 14225 14226 /* Generate the code for each pipeline instruction. */ 14227 for (j = g->first_instr_id; j <= g->last_instr_id; j++) { 14228 struct instruction *instr = &p->instructions[j]; 14229 struct instruction_data *data = &p->instruction_data[j]; 14230 14231 /* Label, if present. */ 14232 if (data->label[0]) 14233 fprintf(f, "\n%s : ", data->label); 14234 else 14235 fprintf(f, "\n\t"); 14236 14237 /* TX instruction type. */ 14238 if (instruction_does_tx(instr)) { 14239 pipeline_instr_does_tx_codegen(p, j, instr, f); 14240 continue; 14241 } 14242 14243 /* Jump instruction type. */ 14244 if (instruction_is_jmp(instr)) { 14245 pipeline_instr_jmp_codegen(p, igl, j, instr, data, f); 14246 continue; 14247 } 14248 14249 /* Any other instruction type. */ 14250 fprintf(f, 14251 "%s(p, t, &pipeline_instructions[%u]);\n", 14252 instr_type_to_func(instr), 14253 j); 14254 } 14255 14256 /* Finalize the generated pipeline function. For some instructions such as TX, 14257 * emit-many-and-TX and unconditional jump, the next instruction has been already 14258 * decided unconditionally and the instruction pointer of the current thread set 14259 * accordingly; for all the other instructions, the instruction pointer must be 14260 * incremented now. 14261 */ 14262 last_instr = &p->instructions[g->last_instr_id]; 14263 14264 if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP)) 14265 fprintf(f, 14266 "thread_ip_inc(p);\n"); 14267 14268 fprintf(f, 14269 "}\n" 14270 "\n"); 14271 } 14272 } 14273 14274 static uint32_t 14275 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl) 14276 { 14277 struct instruction_group *g; 14278 uint32_t n_custom_instr = 0; 14279 14280 /* Groups with a single instruction: no function is generated for this group, the group 14281 * keeps its current instruction. Groups with more than two instructions: one function and 14282 * the associated custom instruction get generated for each such group. 14283 */ 14284 TAILQ_FOREACH(g, igl, node) { 14285 if (g->first_instr_id == g->last_instr_id) 14286 continue; 14287 14288 n_custom_instr++; 14289 } 14290 14291 return n_custom_instr; 14292 } 14293 14294 static int 14295 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused, 14296 struct instruction_group_list *igl) 14297 { 14298 uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl); 14299 14300 /* Check that enough space is available within the pipeline instruction table to store all 14301 * the custom instructions. 14302 */ 14303 if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX) 14304 return -ENOSPC; 14305 14306 return 0; 14307 } 14308 14309 static void 14310 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 14311 { 14312 struct instruction_group *g; 14313 uint32_t i; 14314 14315 /* Pipeline table instructions. */ 14316 for (i = 0; i < p->n_instructions; i++) { 14317 struct instruction *instr = &p->instructions[i]; 14318 14319 if (instr->type == INSTR_TABLE) 14320 instr->type = INSTR_TABLE_AF; 14321 14322 if (instr->type == INSTR_LEARNER) 14323 instr->type = INSTR_LEARNER_AF; 14324 } 14325 14326 /* Pipeline custom instructions. */ 14327 i = 0; 14328 TAILQ_FOREACH(g, igl, node) { 14329 struct instruction *instr = &p->instructions[g->first_instr_id]; 14330 uint32_t j; 14331 14332 if (g->first_instr_id == g->last_instr_id) 14333 continue; 14334 14335 /* Install a new custom instruction. */ 14336 p->instruction_table[INSTR_CUSTOM_0 + i] = g->func; 14337 14338 /* First instruction of the group: change its type to the new custom instruction. */ 14339 instr->type = INSTR_CUSTOM_0 + i; 14340 14341 /* All the subsequent instructions of the group: invalidate. */ 14342 for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) { 14343 struct instruction_data *data = &p->instruction_data[j]; 14344 14345 data->invalid = 1; 14346 } 14347 14348 i++; 14349 } 14350 14351 /* Remove the invalidated instructions. */ 14352 p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions); 14353 14354 /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump 14355 * instructions that are the only instruction within their group, so they were left 14356 * unmodified). 14357 */ 14358 instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions); 14359 } 14360 14361 int 14362 rte_swx_pipeline_codegen(FILE *spec_file, 14363 FILE *code_file, 14364 uint32_t *err_line, 14365 const char **err_msg) 14366 14367 { 14368 struct rte_swx_pipeline *p = NULL; 14369 struct pipeline_spec *s = NULL; 14370 struct instruction_group_list *igl = NULL; 14371 struct action *a; 14372 int status = 0; 14373 14374 /* Check input arguments. */ 14375 if (!spec_file || !code_file) { 14376 if (err_line) 14377 *err_line = 0; 14378 if (err_msg) 14379 *err_msg = "Invalid input argument."; 14380 status = -EINVAL; 14381 goto free; 14382 } 14383 14384 /* Pipeline configuration. */ 14385 s = pipeline_spec_parse(spec_file, err_line, err_msg); 14386 if (!s) { 14387 status = -EINVAL; 14388 goto free; 14389 } 14390 14391 status = rte_swx_pipeline_config(&p, NULL, 0); 14392 if (status) { 14393 if (err_line) 14394 *err_line = 0; 14395 if (err_msg) 14396 *err_msg = "Pipeline configuration error."; 14397 goto free; 14398 } 14399 14400 status = pipeline_spec_configure(p, s, err_msg); 14401 if (status) { 14402 if (err_line) 14403 *err_line = 0; 14404 goto free; 14405 } 14406 14407 /* 14408 * Pipeline code generation. 14409 */ 14410 14411 /* Instruction Group List (IGL) computation: the pipeline configuration must be done first, 14412 * but there is no need for the pipeline build to be done as well. 14413 */ 14414 igl = instruction_group_list_create(p); 14415 if (!igl) { 14416 if (err_line) 14417 *err_line = 0; 14418 if (err_msg) 14419 *err_msg = "Memory allocation failed."; 14420 status = -ENOMEM; 14421 goto free; 14422 } 14423 14424 /* Header file inclusion. */ 14425 fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n"); 14426 fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n"); 14427 14428 /* Code generation for the pipeline specification. */ 14429 pipeline_spec_codegen(code_file, s); 14430 fprintf(code_file, "\n"); 14431 14432 /* Code generation for the action instructions. */ 14433 TAILQ_FOREACH(a, &p->actions, node) { 14434 fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name); 14435 14436 action_data_codegen(a, code_file); 14437 fprintf(code_file, "\n"); 14438 14439 action_instr_codegen(a, code_file); 14440 fprintf(code_file, "\n"); 14441 } 14442 14443 /* Code generation for the pipeline instructions. */ 14444 instruction_group_list_codegen(igl, p, code_file); 14445 14446 free: 14447 instruction_group_list_free(igl); 14448 rte_swx_pipeline_free(p); 14449 pipeline_spec_free(s); 14450 14451 return status; 14452 } 14453 14454 int 14455 rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **pipeline, 14456 const char *name, 14457 const char *lib_file_name, 14458 FILE *iospec_file, 14459 int numa_node) 14460 { 14461 struct rte_swx_pipeline *p = NULL; 14462 void *lib = NULL; 14463 struct pipeline_iospec *sio = NULL; 14464 struct pipeline_spec *s = NULL; 14465 struct instruction_group_list *igl = NULL; 14466 struct action *a; 14467 struct instruction_group *g; 14468 int status = 0; 14469 14470 /* Check input arguments. */ 14471 if (!pipeline || 14472 !name || 14473 !name[0] || 14474 !lib_file_name || 14475 !lib_file_name[0] || 14476 !iospec_file) { 14477 status = -EINVAL; 14478 goto free; 14479 } 14480 14481 /* Open the library. */ 14482 lib = dlopen(lib_file_name, RTLD_LAZY); 14483 if (!lib) { 14484 status = -EIO; 14485 goto free; 14486 } 14487 14488 /* Get the pipeline specification structures. */ 14489 s = dlsym(lib, "pipeline_spec"); 14490 if (!s) { 14491 status = -EINVAL; 14492 goto free; 14493 } 14494 14495 sio = pipeline_iospec_parse(iospec_file, NULL, NULL); 14496 if (!sio) { 14497 status = -EINVAL; 14498 goto free; 14499 } 14500 14501 /* Pipeline configuration based on the specification structures. */ 14502 status = rte_swx_pipeline_config(&p, name, numa_node); 14503 if (status) 14504 goto free; 14505 14506 status = pipeline_iospec_configure(p, sio, NULL); 14507 if (status) 14508 goto free; 14509 14510 status = pipeline_spec_configure(p, s, NULL); 14511 if (status) 14512 goto free; 14513 14514 /* Pipeline build. */ 14515 status = rte_swx_pipeline_build(p); 14516 if (status) 14517 goto free; 14518 14519 /* Action instructions. */ 14520 TAILQ_FOREACH(a, &p->actions, node) { 14521 char name[RTE_SWX_NAME_SIZE * 2]; 14522 14523 snprintf(name, sizeof(name), "action_%s_run", a->name); 14524 14525 p->action_funcs[a->id] = dlsym(lib, name); 14526 if (!p->action_funcs[a->id]) { 14527 status = -EINVAL; 14528 goto free; 14529 } 14530 } 14531 14532 /* Pipeline instructions. */ 14533 igl = instruction_group_list_create(p); 14534 if (!igl) { 14535 status = -ENOMEM; 14536 goto free; 14537 } 14538 14539 TAILQ_FOREACH(g, igl, node) { 14540 char name[RTE_SWX_NAME_SIZE * 2]; 14541 14542 if (g->first_instr_id == g->last_instr_id) 14543 continue; 14544 14545 snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id); 14546 14547 g->func = dlsym(lib, name); 14548 if (!g->func) { 14549 status = -EINVAL; 14550 goto free; 14551 } 14552 } 14553 14554 status = pipeline_adjust_check(p, igl); 14555 if (status) 14556 goto free; 14557 14558 pipeline_adjust(p, igl); 14559 14560 p->lib = lib; 14561 14562 *pipeline = p; 14563 14564 free: 14565 instruction_group_list_free(igl); 14566 14567 pipeline_iospec_free(sio); 14568 14569 if (status) { 14570 rte_swx_pipeline_free(p); 14571 14572 if (lib) 14573 dlclose(lib); 14574 } 14575 14576 return status; 14577 } 14578