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