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