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, instruction_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 = NULL; 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 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 7340 7341 CHECK_NAME(action_name, EINVAL); 7342 7343 a = action_find(p, action_name); 7344 CHECK(a, EINVAL); 7345 CHECK(!action_does_learning(a), EINVAL); 7346 7347 action_data_size = a->st ? a->st->n_bits / 8 : 0; 7348 if (action_data_size > action_data_size_max) 7349 action_data_size_max = action_data_size; 7350 7351 if (params->action_is_for_table_entries) 7352 action_is_for_table_entries = params->action_is_for_table_entries[i]; 7353 if (params->action_is_for_default_entry) 7354 action_is_for_default_entry = params->action_is_for_default_entry[i]; 7355 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 7356 } 7357 7358 CHECK_NAME(params->default_action_name, EINVAL); 7359 for (i = 0; i < p->n_actions; i++) 7360 if (!strcmp(params->action_names[i], 7361 params->default_action_name)) 7362 break; 7363 CHECK(i < params->n_actions, EINVAL); 7364 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 7365 EINVAL); 7366 7367 default_action = action_find(p, params->default_action_name); 7368 CHECK((default_action->st && params->default_action_data) || 7369 !params->default_action_data, EINVAL); 7370 7371 /* Table type checks. */ 7372 if (recommended_table_type_name) 7373 CHECK_NAME(recommended_table_type_name, EINVAL); 7374 7375 if (params->n_fields) { 7376 enum rte_swx_table_match_type match_type; 7377 7378 status = table_match_type_resolve(params->fields, params->n_fields, &match_type); 7379 if (status) 7380 return status; 7381 7382 type = table_type_resolve(p, recommended_table_type_name, match_type); 7383 CHECK(type, EINVAL); 7384 } else { 7385 type = NULL; 7386 } 7387 7388 /* Memory allocation. */ 7389 t = calloc(1, sizeof(struct table)); 7390 CHECK(t, ENOMEM); 7391 7392 t->fields = calloc(params->n_fields, sizeof(struct match_field)); 7393 if (!t->fields) 7394 goto nomem; 7395 7396 t->actions = calloc(params->n_actions, sizeof(struct action *)); 7397 if (!t->actions) 7398 goto nomem; 7399 7400 if (action_data_size_max) { 7401 t->default_action_data = calloc(1, action_data_size_max); 7402 if (!t->default_action_data) 7403 goto nomem; 7404 } 7405 7406 t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 7407 if (!t->action_is_for_table_entries) 7408 goto nomem; 7409 7410 t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 7411 if (!t->action_is_for_default_entry) 7412 goto nomem; 7413 7414 /* Node initialization. */ 7415 strcpy(t->name, name); 7416 if (args && args[0]) 7417 strcpy(t->args, args); 7418 t->type = type; 7419 7420 for (i = 0; i < params->n_fields; i++) { 7421 struct rte_swx_match_field_params *field = ¶ms->fields[i]; 7422 struct match_field *f = &t->fields[i]; 7423 7424 f->match_type = field->match_type; 7425 f->field = header ? 7426 header_field_parse(p, field->name, NULL) : 7427 metadata_field_parse(p, field->name); 7428 } 7429 t->n_fields = params->n_fields; 7430 t->header = header; 7431 7432 for (i = 0; i < params->n_actions; i++) { 7433 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 7434 7435 if (params->action_is_for_table_entries) 7436 action_is_for_table_entries = params->action_is_for_table_entries[i]; 7437 if (params->action_is_for_default_entry) 7438 action_is_for_default_entry = params->action_is_for_default_entry[i]; 7439 7440 t->actions[i] = action_find(p, params->action_names[i]); 7441 t->action_is_for_table_entries[i] = action_is_for_table_entries; 7442 t->action_is_for_default_entry[i] = action_is_for_default_entry; 7443 } 7444 t->default_action = default_action; 7445 if (default_action->st) 7446 memcpy(t->default_action_data, 7447 params->default_action_data, 7448 default_action->st->n_bits / 8); 7449 t->n_actions = params->n_actions; 7450 t->default_action_is_const = params->default_action_is_const; 7451 t->action_data_size_max = action_data_size_max; 7452 7453 t->size = size; 7454 t->id = p->n_tables; 7455 7456 /* Node add to tailq. */ 7457 TAILQ_INSERT_TAIL(&p->tables, t, node); 7458 p->n_tables++; 7459 7460 return 0; 7461 7462 nomem: 7463 if (!t) 7464 return -ENOMEM; 7465 7466 free(t->action_is_for_default_entry); 7467 free(t->action_is_for_table_entries); 7468 free(t->default_action_data); 7469 free(t->actions); 7470 free(t->fields); 7471 free(t); 7472 7473 return -ENOMEM; 7474 } 7475 7476 static struct rte_swx_table_params * 7477 table_params_get(struct table *table) 7478 { 7479 struct rte_swx_table_params *params; 7480 struct field *first, *last; 7481 uint8_t *key_mask; 7482 uint32_t key_size, key_offset, action_data_size, i; 7483 7484 /* Memory allocation. */ 7485 params = calloc(1, sizeof(struct rte_swx_table_params)); 7486 if (!params) 7487 return NULL; 7488 7489 /* Find first (smallest offset) and last (biggest offset) match fields. */ 7490 first = table->fields[0].field; 7491 last = table->fields[0].field; 7492 7493 for (i = 0; i < table->n_fields; i++) { 7494 struct field *f = table->fields[i].field; 7495 7496 if (f->offset < first->offset) 7497 first = f; 7498 7499 if (f->offset > last->offset) 7500 last = f; 7501 } 7502 7503 /* Key offset and size. */ 7504 key_offset = first->offset / 8; 7505 key_size = (last->offset + last->n_bits - first->offset) / 8; 7506 7507 /* Memory allocation. */ 7508 key_mask = calloc(1, key_size); 7509 if (!key_mask) { 7510 free(params); 7511 return NULL; 7512 } 7513 7514 /* Key mask. */ 7515 for (i = 0; i < table->n_fields; i++) { 7516 struct field *f = table->fields[i].field; 7517 uint32_t start = (f->offset - first->offset) / 8; 7518 size_t size = f->n_bits / 8; 7519 7520 memset(&key_mask[start], 0xFF, size); 7521 } 7522 7523 /* Action data size. */ 7524 action_data_size = 0; 7525 for (i = 0; i < table->n_actions; i++) { 7526 struct action *action = table->actions[i]; 7527 uint32_t ads = action->st ? action->st->n_bits / 8 : 0; 7528 7529 if (ads > action_data_size) 7530 action_data_size = ads; 7531 } 7532 7533 /* Fill in. */ 7534 params->match_type = table->type->match_type; 7535 params->key_size = key_size; 7536 params->key_offset = key_offset; 7537 params->key_mask0 = key_mask; 7538 params->action_data_size = action_data_size; 7539 params->n_keys_max = table->size; 7540 7541 return params; 7542 } 7543 7544 static void 7545 table_params_free(struct rte_swx_table_params *params) 7546 { 7547 if (!params) 7548 return; 7549 7550 free(params->key_mask0); 7551 free(params); 7552 } 7553 7554 static int 7555 table_stub_lkp(void *table __rte_unused, 7556 void *mailbox __rte_unused, 7557 uint8_t **key __rte_unused, 7558 uint64_t *action_id __rte_unused, 7559 uint8_t **action_data __rte_unused, 7560 int *hit) 7561 { 7562 *hit = 0; 7563 return 1; /* DONE. */ 7564 } 7565 7566 static int 7567 table_build(struct rte_swx_pipeline *p) 7568 { 7569 uint32_t i; 7570 7571 /* Per pipeline: table statistics. */ 7572 p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics)); 7573 CHECK(p->table_stats, ENOMEM); 7574 7575 for (i = 0; i < p->n_tables; i++) { 7576 p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 7577 CHECK(p->table_stats[i].n_pkts_action, ENOMEM); 7578 } 7579 7580 /* Per thread: table runt-time. */ 7581 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7582 struct thread *t = &p->threads[i]; 7583 struct table *table; 7584 7585 t->tables = calloc(p->n_tables, sizeof(struct table_runtime)); 7586 CHECK(t->tables, ENOMEM); 7587 7588 TAILQ_FOREACH(table, &p->tables, node) { 7589 struct table_runtime *r = &t->tables[table->id]; 7590 7591 if (table->type) { 7592 uint64_t size; 7593 7594 size = table->type->ops.mailbox_size_get(); 7595 7596 /* r->func. */ 7597 r->func = table->type->ops.lkp; 7598 7599 /* r->mailbox. */ 7600 if (size) { 7601 r->mailbox = calloc(1, size); 7602 CHECK(r->mailbox, ENOMEM); 7603 } 7604 7605 /* r->key. */ 7606 r->key = table->header ? 7607 &t->structs[table->header->struct_id] : 7608 &t->structs[p->metadata_struct_id]; 7609 } else { 7610 r->func = table_stub_lkp; 7611 } 7612 } 7613 } 7614 7615 return 0; 7616 } 7617 7618 static void 7619 table_build_free(struct rte_swx_pipeline *p) 7620 { 7621 uint32_t i; 7622 7623 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7624 struct thread *t = &p->threads[i]; 7625 uint32_t j; 7626 7627 if (!t->tables) 7628 continue; 7629 7630 for (j = 0; j < p->n_tables; j++) { 7631 struct table_runtime *r = &t->tables[j]; 7632 7633 free(r->mailbox); 7634 } 7635 7636 free(t->tables); 7637 t->tables = NULL; 7638 } 7639 7640 if (p->table_stats) { 7641 for (i = 0; i < p->n_tables; i++) 7642 free(p->table_stats[i].n_pkts_action); 7643 7644 free(p->table_stats); 7645 } 7646 } 7647 7648 static void 7649 table_free(struct rte_swx_pipeline *p) 7650 { 7651 table_build_free(p); 7652 7653 /* Tables. */ 7654 for ( ; ; ) { 7655 struct table *elem; 7656 7657 elem = TAILQ_FIRST(&p->tables); 7658 if (!elem) 7659 break; 7660 7661 TAILQ_REMOVE(&p->tables, elem, node); 7662 free(elem->fields); 7663 free(elem->actions); 7664 free(elem->default_action_data); 7665 free(elem); 7666 } 7667 7668 /* Table types. */ 7669 for ( ; ; ) { 7670 struct table_type *elem; 7671 7672 elem = TAILQ_FIRST(&p->table_types); 7673 if (!elem) 7674 break; 7675 7676 TAILQ_REMOVE(&p->table_types, elem, node); 7677 free(elem); 7678 } 7679 } 7680 7681 /* 7682 * Selector. 7683 */ 7684 static struct selector * 7685 selector_find(struct rte_swx_pipeline *p, const char *name) 7686 { 7687 struct selector *s; 7688 7689 TAILQ_FOREACH(s, &p->selectors, node) 7690 if (strcmp(s->name, name) == 0) 7691 return s; 7692 7693 return NULL; 7694 } 7695 7696 static struct selector * 7697 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 7698 { 7699 struct selector *s = NULL; 7700 7701 TAILQ_FOREACH(s, &p->selectors, node) 7702 if (s->id == id) 7703 return s; 7704 7705 return NULL; 7706 } 7707 7708 static int 7709 selector_fields_check(struct rte_swx_pipeline *p, 7710 struct rte_swx_pipeline_selector_params *params, 7711 struct header **header) 7712 { 7713 struct header *h0 = NULL; 7714 struct field *hf, *mf; 7715 uint32_t i; 7716 7717 /* Return if no selector fields. */ 7718 if (!params->n_selector_fields || !params->selector_field_names) 7719 return -EINVAL; 7720 7721 /* Check that all the selector fields either belong to the same header 7722 * or are all meta-data fields. 7723 */ 7724 hf = header_field_parse(p, params->selector_field_names[0], &h0); 7725 mf = metadata_field_parse(p, params->selector_field_names[0]); 7726 if (!hf && !mf) 7727 return -EINVAL; 7728 7729 for (i = 1; i < params->n_selector_fields; i++) 7730 if (h0) { 7731 struct header *h; 7732 7733 hf = header_field_parse(p, params->selector_field_names[i], &h); 7734 if (!hf || (h->id != h0->id)) 7735 return -EINVAL; 7736 } else { 7737 mf = metadata_field_parse(p, params->selector_field_names[i]); 7738 if (!mf) 7739 return -EINVAL; 7740 } 7741 7742 /* Check that there are no duplicated match fields. */ 7743 for (i = 0; i < params->n_selector_fields; i++) { 7744 const char *field_name = params->selector_field_names[i]; 7745 uint32_t j; 7746 7747 for (j = i + 1; j < params->n_selector_fields; j++) 7748 if (!strcmp(params->selector_field_names[j], field_name)) 7749 return -EINVAL; 7750 } 7751 7752 /* Return. */ 7753 if (header) 7754 *header = h0; 7755 7756 return 0; 7757 } 7758 7759 int 7760 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p, 7761 const char *name, 7762 struct rte_swx_pipeline_selector_params *params) 7763 { 7764 struct selector *s; 7765 struct header *selector_header = NULL; 7766 struct field *group_id_field, *member_id_field; 7767 uint32_t i; 7768 int status = 0; 7769 7770 CHECK(p, EINVAL); 7771 7772 CHECK_NAME(name, EINVAL); 7773 CHECK(!table_find(p, name), EEXIST); 7774 CHECK(!selector_find(p, name), EEXIST); 7775 CHECK(!learner_find(p, name), EEXIST); 7776 7777 CHECK(params, EINVAL); 7778 7779 CHECK_NAME(params->group_id_field_name, EINVAL); 7780 group_id_field = metadata_field_parse(p, params->group_id_field_name); 7781 CHECK(group_id_field, EINVAL); 7782 7783 for (i = 0; i < params->n_selector_fields; i++) { 7784 const char *field_name = params->selector_field_names[i]; 7785 7786 CHECK_NAME(field_name, EINVAL); 7787 } 7788 status = selector_fields_check(p, params, &selector_header); 7789 if (status) 7790 return status; 7791 7792 CHECK_NAME(params->member_id_field_name, EINVAL); 7793 member_id_field = metadata_field_parse(p, params->member_id_field_name); 7794 CHECK(member_id_field, EINVAL); 7795 7796 CHECK(params->n_groups_max, EINVAL); 7797 7798 CHECK(params->n_members_per_group_max, EINVAL); 7799 7800 /* Memory allocation. */ 7801 s = calloc(1, sizeof(struct selector)); 7802 if (!s) { 7803 status = -ENOMEM; 7804 goto error; 7805 } 7806 7807 s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *)); 7808 if (!s->selector_fields) { 7809 status = -ENOMEM; 7810 goto error; 7811 } 7812 7813 /* Node initialization. */ 7814 strcpy(s->name, name); 7815 7816 s->group_id_field = group_id_field; 7817 7818 for (i = 0; i < params->n_selector_fields; i++) { 7819 const char *field_name = params->selector_field_names[i]; 7820 7821 s->selector_fields[i] = selector_header ? 7822 header_field_parse(p, field_name, NULL) : 7823 metadata_field_parse(p, field_name); 7824 } 7825 7826 s->n_selector_fields = params->n_selector_fields; 7827 7828 s->selector_header = selector_header; 7829 7830 s->member_id_field = member_id_field; 7831 7832 s->n_groups_max = params->n_groups_max; 7833 7834 s->n_members_per_group_max = params->n_members_per_group_max; 7835 7836 s->id = p->n_selectors; 7837 7838 /* Node add to tailq. */ 7839 TAILQ_INSERT_TAIL(&p->selectors, s, node); 7840 p->n_selectors++; 7841 7842 return 0; 7843 7844 error: 7845 if (!s) 7846 return status; 7847 7848 free(s->selector_fields); 7849 7850 free(s); 7851 7852 return status; 7853 } 7854 7855 static void 7856 selector_params_free(struct rte_swx_table_selector_params *params) 7857 { 7858 if (!params) 7859 return; 7860 7861 free(params->selector_mask); 7862 7863 free(params); 7864 } 7865 7866 static struct rte_swx_table_selector_params * 7867 selector_table_params_get(struct selector *s) 7868 { 7869 struct rte_swx_table_selector_params *params = NULL; 7870 struct field *first, *last; 7871 uint32_t i; 7872 7873 /* Memory allocation. */ 7874 params = calloc(1, sizeof(struct rte_swx_table_selector_params)); 7875 if (!params) 7876 goto error; 7877 7878 /* Group ID. */ 7879 params->group_id_offset = s->group_id_field->offset / 8; 7880 7881 /* Find first (smallest offset) and last (biggest offset) selector fields. */ 7882 first = s->selector_fields[0]; 7883 last = s->selector_fields[0]; 7884 7885 for (i = 0; i < s->n_selector_fields; i++) { 7886 struct field *f = s->selector_fields[i]; 7887 7888 if (f->offset < first->offset) 7889 first = f; 7890 7891 if (f->offset > last->offset) 7892 last = f; 7893 } 7894 7895 /* Selector offset and size. */ 7896 params->selector_offset = first->offset / 8; 7897 params->selector_size = (last->offset + last->n_bits - first->offset) / 8; 7898 7899 /* Memory allocation. */ 7900 params->selector_mask = calloc(1, params->selector_size); 7901 if (!params->selector_mask) 7902 goto error; 7903 7904 /* Selector mask. */ 7905 for (i = 0; i < s->n_selector_fields; i++) { 7906 struct field *f = s->selector_fields[i]; 7907 uint32_t start = (f->offset - first->offset) / 8; 7908 size_t size = f->n_bits / 8; 7909 7910 memset(¶ms->selector_mask[start], 0xFF, size); 7911 } 7912 7913 /* Member ID. */ 7914 params->member_id_offset = s->member_id_field->offset / 8; 7915 7916 /* Maximum number of groups. */ 7917 params->n_groups_max = s->n_groups_max; 7918 7919 /* Maximum number of members per group. */ 7920 params->n_members_per_group_max = s->n_members_per_group_max; 7921 7922 return params; 7923 7924 error: 7925 selector_params_free(params); 7926 return NULL; 7927 } 7928 7929 static void 7930 selector_build_free(struct rte_swx_pipeline *p) 7931 { 7932 uint32_t i; 7933 7934 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7935 struct thread *t = &p->threads[i]; 7936 uint32_t j; 7937 7938 if (!t->selectors) 7939 continue; 7940 7941 for (j = 0; j < p->n_selectors; j++) { 7942 struct selector_runtime *r = &t->selectors[j]; 7943 7944 free(r->mailbox); 7945 } 7946 7947 free(t->selectors); 7948 t->selectors = NULL; 7949 } 7950 7951 free(p->selector_stats); 7952 p->selector_stats = NULL; 7953 } 7954 7955 static int 7956 selector_build(struct rte_swx_pipeline *p) 7957 { 7958 uint32_t i; 7959 int status = 0; 7960 7961 /* Per pipeline: selector statistics. */ 7962 p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics)); 7963 if (!p->selector_stats) { 7964 status = -ENOMEM; 7965 goto error; 7966 } 7967 7968 /* Per thread: selector run-time. */ 7969 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7970 struct thread *t = &p->threads[i]; 7971 struct selector *s; 7972 7973 t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime)); 7974 if (!t->selectors) { 7975 status = -ENOMEM; 7976 goto error; 7977 } 7978 7979 TAILQ_FOREACH(s, &p->selectors, node) { 7980 struct selector_runtime *r = &t->selectors[s->id]; 7981 uint64_t size; 7982 7983 /* r->mailbox. */ 7984 size = rte_swx_table_selector_mailbox_size_get(); 7985 if (size) { 7986 r->mailbox = calloc(1, size); 7987 if (!r->mailbox) { 7988 status = -ENOMEM; 7989 goto error; 7990 } 7991 } 7992 7993 /* r->group_id_buffer. */ 7994 r->group_id_buffer = &t->structs[p->metadata_struct_id]; 7995 7996 /* r->selector_buffer. */ 7997 r->selector_buffer = s->selector_header ? 7998 &t->structs[s->selector_header->struct_id] : 7999 &t->structs[p->metadata_struct_id]; 8000 8001 /* r->member_id_buffer. */ 8002 r->member_id_buffer = &t->structs[p->metadata_struct_id]; 8003 } 8004 } 8005 8006 return 0; 8007 8008 error: 8009 selector_build_free(p); 8010 return status; 8011 } 8012 8013 static void 8014 selector_free(struct rte_swx_pipeline *p) 8015 { 8016 selector_build_free(p); 8017 8018 /* Selector tables. */ 8019 for ( ; ; ) { 8020 struct selector *elem; 8021 8022 elem = TAILQ_FIRST(&p->selectors); 8023 if (!elem) 8024 break; 8025 8026 TAILQ_REMOVE(&p->selectors, elem, node); 8027 free(elem->selector_fields); 8028 free(elem); 8029 } 8030 } 8031 8032 /* 8033 * Learner table. 8034 */ 8035 static struct learner * 8036 learner_find(struct rte_swx_pipeline *p, const char *name) 8037 { 8038 struct learner *l; 8039 8040 TAILQ_FOREACH(l, &p->learners, node) 8041 if (!strcmp(l->name, name)) 8042 return l; 8043 8044 return NULL; 8045 } 8046 8047 static struct learner * 8048 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8049 { 8050 struct learner *l = NULL; 8051 8052 TAILQ_FOREACH(l, &p->learners, node) 8053 if (l->id == id) 8054 return l; 8055 8056 return NULL; 8057 } 8058 8059 static int 8060 learner_match_fields_check(struct rte_swx_pipeline *p, 8061 struct rte_swx_pipeline_learner_params *params, 8062 struct header **header) 8063 { 8064 struct header *h0 = NULL; 8065 struct field *hf, *mf; 8066 uint32_t i; 8067 8068 /* Return if no match fields. */ 8069 if (!params->n_fields || !params->field_names) 8070 return -EINVAL; 8071 8072 /* Check that all the match fields either belong to the same header 8073 * or are all meta-data fields. 8074 */ 8075 hf = header_field_parse(p, params->field_names[0], &h0); 8076 mf = metadata_field_parse(p, params->field_names[0]); 8077 if (!hf && !mf) 8078 return -EINVAL; 8079 8080 for (i = 1; i < params->n_fields; i++) 8081 if (h0) { 8082 struct header *h; 8083 8084 hf = header_field_parse(p, params->field_names[i], &h); 8085 if (!hf || (h->id != h0->id)) 8086 return -EINVAL; 8087 } else { 8088 mf = metadata_field_parse(p, params->field_names[i]); 8089 if (!mf) 8090 return -EINVAL; 8091 } 8092 8093 /* Check that there are no duplicated match fields. */ 8094 for (i = 0; i < params->n_fields; i++) { 8095 const char *field_name = params->field_names[i]; 8096 uint32_t j; 8097 8098 for (j = i + 1; j < params->n_fields; j++) 8099 if (!strcmp(params->field_names[j], field_name)) 8100 return -EINVAL; 8101 } 8102 8103 /* Return. */ 8104 if (header) 8105 *header = h0; 8106 8107 return 0; 8108 } 8109 8110 static int 8111 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name) 8112 { 8113 struct struct_type *mst = p->metadata_st, *ast = a->st; 8114 struct field *mf, *af; 8115 uint32_t mf_pos, i; 8116 8117 if (!ast) { 8118 if (mf_name) 8119 return -EINVAL; 8120 8121 return 0; 8122 } 8123 8124 /* Check that mf_name is the name of a valid meta-data field. */ 8125 CHECK_NAME(mf_name, EINVAL); 8126 mf = metadata_field_parse(p, mf_name); 8127 CHECK(mf, EINVAL); 8128 8129 /* Check that there are enough meta-data fields, starting with the mf_name field, to cover 8130 * all the action arguments. 8131 */ 8132 mf_pos = mf - mst->fields; 8133 CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL); 8134 8135 /* Check that the size of each of the identified meta-data fields matches exactly the size 8136 * of the corresponding action argument. 8137 */ 8138 for (i = 0; i < ast->n_fields; i++) { 8139 mf = &mst->fields[mf_pos + i]; 8140 af = &ast->fields[i]; 8141 8142 CHECK(mf->n_bits == af->n_bits, EINVAL); 8143 } 8144 8145 return 0; 8146 } 8147 8148 static int 8149 learner_action_learning_check(struct rte_swx_pipeline *p, 8150 struct action *action, 8151 const char **action_names, 8152 uint32_t n_actions) 8153 { 8154 uint32_t i; 8155 8156 /* For each "learn" instruction of the current action, check that the learned action (i.e. 8157 * the action passed as argument to the "learn" instruction) is also enabled for the 8158 * current learner table. 8159 */ 8160 for (i = 0; i < action->n_instructions; i++) { 8161 struct instruction *instr = &action->instructions[i]; 8162 uint32_t found = 0, j; 8163 8164 if (instr->type != INSTR_LEARNER_LEARN) 8165 continue; 8166 8167 for (j = 0; j < n_actions; j++) { 8168 struct action *a; 8169 8170 a = action_find(p, action_names[j]); 8171 if (!a) 8172 return -EINVAL; 8173 8174 if (a->id == instr->learn.action_id) 8175 found = 1; 8176 } 8177 8178 if (!found) 8179 return -EINVAL; 8180 } 8181 8182 return 0; 8183 } 8184 8185 int 8186 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, 8187 const char *name, 8188 struct rte_swx_pipeline_learner_params *params, 8189 uint32_t size, 8190 uint32_t timeout) 8191 { 8192 struct learner *l = NULL; 8193 struct action *default_action; 8194 struct header *header = NULL; 8195 uint32_t action_data_size_max = 0, i; 8196 int status = 0; 8197 8198 CHECK(p, EINVAL); 8199 8200 CHECK_NAME(name, EINVAL); 8201 CHECK(!table_find(p, name), EEXIST); 8202 CHECK(!selector_find(p, name), EEXIST); 8203 CHECK(!learner_find(p, name), EEXIST); 8204 8205 CHECK(params, EINVAL); 8206 8207 /* Match checks. */ 8208 status = learner_match_fields_check(p, params, &header); 8209 if (status) 8210 return status; 8211 8212 /* Action checks. */ 8213 CHECK(params->n_actions, EINVAL); 8214 CHECK(params->action_names, EINVAL); 8215 for (i = 0; i < params->n_actions; i++) { 8216 const char *action_name = params->action_names[i]; 8217 struct action *a; 8218 uint32_t action_data_size; 8219 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8220 8221 CHECK_NAME(action_name, EINVAL); 8222 8223 a = action_find(p, action_name); 8224 CHECK(a, EINVAL); 8225 8226 status = learner_action_learning_check(p, 8227 a, 8228 params->action_names, 8229 params->n_actions); 8230 if (status) 8231 return status; 8232 8233 action_data_size = a->st ? a->st->n_bits / 8 : 0; 8234 if (action_data_size > action_data_size_max) 8235 action_data_size_max = action_data_size; 8236 8237 if (params->action_is_for_table_entries) 8238 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8239 if (params->action_is_for_default_entry) 8240 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8241 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 8242 } 8243 8244 CHECK_NAME(params->default_action_name, EINVAL); 8245 for (i = 0; i < p->n_actions; i++) 8246 if (!strcmp(params->action_names[i], 8247 params->default_action_name)) 8248 break; 8249 CHECK(i < params->n_actions, EINVAL); 8250 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 8251 EINVAL); 8252 8253 default_action = action_find(p, params->default_action_name); 8254 CHECK((default_action->st && params->default_action_data) || 8255 !params->default_action_data, EINVAL); 8256 8257 /* Any other checks. */ 8258 CHECK(size, EINVAL); 8259 CHECK(timeout, EINVAL); 8260 8261 /* Memory allocation. */ 8262 l = calloc(1, sizeof(struct learner)); 8263 if (!l) 8264 goto nomem; 8265 8266 l->fields = calloc(params->n_fields, sizeof(struct field *)); 8267 if (!l->fields) 8268 goto nomem; 8269 8270 l->actions = calloc(params->n_actions, sizeof(struct action *)); 8271 if (!l->actions) 8272 goto nomem; 8273 8274 if (action_data_size_max) { 8275 l->default_action_data = calloc(1, action_data_size_max); 8276 if (!l->default_action_data) 8277 goto nomem; 8278 } 8279 8280 l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 8281 if (!l->action_is_for_table_entries) 8282 goto nomem; 8283 8284 l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 8285 if (!l->action_is_for_default_entry) 8286 goto nomem; 8287 8288 /* Node initialization. */ 8289 strcpy(l->name, name); 8290 8291 for (i = 0; i < params->n_fields; i++) { 8292 const char *field_name = params->field_names[i]; 8293 8294 l->fields[i] = header ? 8295 header_field_parse(p, field_name, NULL) : 8296 metadata_field_parse(p, field_name); 8297 } 8298 8299 l->n_fields = params->n_fields; 8300 8301 l->header = header; 8302 8303 for (i = 0; i < params->n_actions; i++) { 8304 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8305 8306 if (params->action_is_for_table_entries) 8307 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8308 if (params->action_is_for_default_entry) 8309 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8310 8311 l->actions[i] = action_find(p, params->action_names[i]); 8312 l->action_is_for_table_entries[i] = action_is_for_table_entries; 8313 l->action_is_for_default_entry[i] = action_is_for_default_entry; 8314 } 8315 8316 l->default_action = default_action; 8317 8318 if (default_action->st) 8319 memcpy(l->default_action_data, 8320 params->default_action_data, 8321 default_action->st->n_bits / 8); 8322 8323 l->n_actions = params->n_actions; 8324 8325 l->default_action_is_const = params->default_action_is_const; 8326 8327 l->action_data_size_max = action_data_size_max; 8328 8329 l->size = size; 8330 8331 l->timeout = timeout; 8332 8333 l->id = p->n_learners; 8334 8335 /* Node add to tailq. */ 8336 TAILQ_INSERT_TAIL(&p->learners, l, node); 8337 p->n_learners++; 8338 8339 return 0; 8340 8341 nomem: 8342 if (!l) 8343 return -ENOMEM; 8344 8345 free(l->action_is_for_default_entry); 8346 free(l->action_is_for_table_entries); 8347 free(l->default_action_data); 8348 free(l->actions); 8349 free(l->fields); 8350 free(l); 8351 8352 return -ENOMEM; 8353 } 8354 8355 static void 8356 learner_params_free(struct rte_swx_table_learner_params *params) 8357 { 8358 if (!params) 8359 return; 8360 8361 free(params->key_mask0); 8362 8363 free(params); 8364 } 8365 8366 static struct rte_swx_table_learner_params * 8367 learner_params_get(struct learner *l) 8368 { 8369 struct rte_swx_table_learner_params *params = NULL; 8370 struct field *first, *last; 8371 uint32_t i; 8372 8373 /* Memory allocation. */ 8374 params = calloc(1, sizeof(struct rte_swx_table_learner_params)); 8375 if (!params) 8376 goto error; 8377 8378 /* Find first (smallest offset) and last (biggest offset) match fields. */ 8379 first = l->fields[0]; 8380 last = l->fields[0]; 8381 8382 for (i = 0; i < l->n_fields; i++) { 8383 struct field *f = l->fields[i]; 8384 8385 if (f->offset < first->offset) 8386 first = f; 8387 8388 if (f->offset > last->offset) 8389 last = f; 8390 } 8391 8392 /* Key offset and size. */ 8393 params->key_offset = first->offset / 8; 8394 params->key_size = (last->offset + last->n_bits - first->offset) / 8; 8395 8396 /* Memory allocation. */ 8397 params->key_mask0 = calloc(1, params->key_size); 8398 if (!params->key_mask0) 8399 goto error; 8400 8401 /* Key mask. */ 8402 for (i = 0; i < l->n_fields; i++) { 8403 struct field *f = l->fields[i]; 8404 uint32_t start = (f->offset - first->offset) / 8; 8405 size_t size = f->n_bits / 8; 8406 8407 memset(¶ms->key_mask0[start], 0xFF, size); 8408 } 8409 8410 /* Action data size. */ 8411 params->action_data_size = l->action_data_size_max; 8412 8413 /* Maximum number of keys. */ 8414 params->n_keys_max = l->size; 8415 8416 /* Timeout. */ 8417 params->key_timeout = l->timeout; 8418 8419 return params; 8420 8421 error: 8422 learner_params_free(params); 8423 return NULL; 8424 } 8425 8426 static void 8427 learner_build_free(struct rte_swx_pipeline *p) 8428 { 8429 uint32_t i; 8430 8431 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8432 struct thread *t = &p->threads[i]; 8433 uint32_t j; 8434 8435 if (!t->learners) 8436 continue; 8437 8438 for (j = 0; j < p->n_learners; j++) { 8439 struct learner_runtime *r = &t->learners[j]; 8440 8441 free(r->mailbox); 8442 } 8443 8444 free(t->learners); 8445 t->learners = NULL; 8446 } 8447 8448 if (p->learner_stats) { 8449 for (i = 0; i < p->n_learners; i++) 8450 free(p->learner_stats[i].n_pkts_action); 8451 8452 free(p->learner_stats); 8453 } 8454 } 8455 8456 static int 8457 learner_build(struct rte_swx_pipeline *p) 8458 { 8459 uint32_t i; 8460 int status = 0; 8461 8462 /* Per pipeline: learner statistics. */ 8463 p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics)); 8464 CHECK(p->learner_stats, ENOMEM); 8465 8466 for (i = 0; i < p->n_learners; i++) { 8467 p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 8468 CHECK(p->learner_stats[i].n_pkts_action, ENOMEM); 8469 } 8470 8471 /* Per thread: learner run-time. */ 8472 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8473 struct thread *t = &p->threads[i]; 8474 struct learner *l; 8475 8476 t->learners = calloc(p->n_learners, sizeof(struct learner_runtime)); 8477 if (!t->learners) { 8478 status = -ENOMEM; 8479 goto error; 8480 } 8481 8482 TAILQ_FOREACH(l, &p->learners, node) { 8483 struct learner_runtime *r = &t->learners[l->id]; 8484 uint64_t size; 8485 8486 /* r->mailbox. */ 8487 size = rte_swx_table_learner_mailbox_size_get(); 8488 if (size) { 8489 r->mailbox = calloc(1, size); 8490 if (!r->mailbox) { 8491 status = -ENOMEM; 8492 goto error; 8493 } 8494 } 8495 8496 /* r->key. */ 8497 r->key = l->header ? 8498 &t->structs[l->header->struct_id] : 8499 &t->structs[p->metadata_struct_id]; 8500 } 8501 } 8502 8503 return 0; 8504 8505 error: 8506 learner_build_free(p); 8507 return status; 8508 } 8509 8510 static void 8511 learner_free(struct rte_swx_pipeline *p) 8512 { 8513 learner_build_free(p); 8514 8515 /* Learner tables. */ 8516 for ( ; ; ) { 8517 struct learner *l; 8518 8519 l = TAILQ_FIRST(&p->learners); 8520 if (!l) 8521 break; 8522 8523 TAILQ_REMOVE(&p->learners, l, node); 8524 free(l->fields); 8525 free(l->actions); 8526 free(l->default_action_data); 8527 free(l); 8528 } 8529 } 8530 8531 /* 8532 * Table state. 8533 */ 8534 static int 8535 table_state_build(struct rte_swx_pipeline *p) 8536 { 8537 struct table *table; 8538 struct selector *s; 8539 struct learner *l; 8540 8541 p->table_state = calloc(p->n_tables + p->n_selectors, 8542 sizeof(struct rte_swx_table_state)); 8543 CHECK(p->table_state, ENOMEM); 8544 8545 TAILQ_FOREACH(table, &p->tables, node) { 8546 struct rte_swx_table_state *ts = &p->table_state[table->id]; 8547 8548 if (table->type) { 8549 struct rte_swx_table_params *params; 8550 8551 /* ts->obj. */ 8552 params = table_params_get(table); 8553 CHECK(params, ENOMEM); 8554 8555 ts->obj = table->type->ops.create(params, 8556 NULL, 8557 table->args, 8558 p->numa_node); 8559 8560 table_params_free(params); 8561 CHECK(ts->obj, ENODEV); 8562 } 8563 8564 /* ts->default_action_data. */ 8565 if (table->action_data_size_max) { 8566 ts->default_action_data = 8567 malloc(table->action_data_size_max); 8568 CHECK(ts->default_action_data, ENOMEM); 8569 8570 memcpy(ts->default_action_data, 8571 table->default_action_data, 8572 table->action_data_size_max); 8573 } 8574 8575 /* ts->default_action_id. */ 8576 ts->default_action_id = table->default_action->id; 8577 } 8578 8579 TAILQ_FOREACH(s, &p->selectors, node) { 8580 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id]; 8581 struct rte_swx_table_selector_params *params; 8582 8583 /* ts->obj. */ 8584 params = selector_table_params_get(s); 8585 CHECK(params, ENOMEM); 8586 8587 ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node); 8588 8589 selector_params_free(params); 8590 CHECK(ts->obj, ENODEV); 8591 } 8592 8593 TAILQ_FOREACH(l, &p->learners, node) { 8594 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + 8595 p->n_selectors + l->id]; 8596 struct rte_swx_table_learner_params *params; 8597 8598 /* ts->obj. */ 8599 params = learner_params_get(l); 8600 CHECK(params, ENOMEM); 8601 8602 ts->obj = rte_swx_table_learner_create(params, p->numa_node); 8603 learner_params_free(params); 8604 CHECK(ts->obj, ENODEV); 8605 8606 /* ts->default_action_data. */ 8607 if (l->action_data_size_max) { 8608 ts->default_action_data = malloc(l->action_data_size_max); 8609 CHECK(ts->default_action_data, ENOMEM); 8610 8611 memcpy(ts->default_action_data, 8612 l->default_action_data, 8613 l->action_data_size_max); 8614 } 8615 8616 /* ts->default_action_id. */ 8617 ts->default_action_id = l->default_action->id; 8618 } 8619 8620 return 0; 8621 } 8622 8623 static void 8624 table_state_build_free(struct rte_swx_pipeline *p) 8625 { 8626 uint32_t i; 8627 8628 if (!p->table_state) 8629 return; 8630 8631 for (i = 0; i < p->n_tables; i++) { 8632 struct rte_swx_table_state *ts = &p->table_state[i]; 8633 struct table *table = table_find_by_id(p, i); 8634 8635 /* ts->obj. */ 8636 if (table->type && ts->obj) 8637 table->type->ops.free(ts->obj); 8638 8639 /* ts->default_action_data. */ 8640 free(ts->default_action_data); 8641 } 8642 8643 for (i = 0; i < p->n_selectors; i++) { 8644 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i]; 8645 8646 /* ts->obj. */ 8647 if (ts->obj) 8648 rte_swx_table_selector_free(ts->obj); 8649 } 8650 8651 for (i = 0; i < p->n_learners; i++) { 8652 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i]; 8653 8654 /* ts->obj. */ 8655 if (ts->obj) 8656 rte_swx_table_learner_free(ts->obj); 8657 8658 /* ts->default_action_data. */ 8659 free(ts->default_action_data); 8660 } 8661 8662 free(p->table_state); 8663 p->table_state = NULL; 8664 } 8665 8666 static void 8667 table_state_free(struct rte_swx_pipeline *p) 8668 { 8669 table_state_build_free(p); 8670 } 8671 8672 /* 8673 * Register array. 8674 */ 8675 static struct regarray * 8676 regarray_find(struct rte_swx_pipeline *p, const char *name) 8677 { 8678 struct regarray *elem; 8679 8680 TAILQ_FOREACH(elem, &p->regarrays, node) 8681 if (!strcmp(elem->name, name)) 8682 return elem; 8683 8684 return NULL; 8685 } 8686 8687 static struct regarray * 8688 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8689 { 8690 struct regarray *elem = NULL; 8691 8692 TAILQ_FOREACH(elem, &p->regarrays, node) 8693 if (elem->id == id) 8694 return elem; 8695 8696 return NULL; 8697 } 8698 8699 int 8700 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p, 8701 const char *name, 8702 uint32_t size, 8703 uint64_t init_val) 8704 { 8705 struct regarray *r; 8706 8707 CHECK(p, EINVAL); 8708 8709 CHECK_NAME(name, EINVAL); 8710 CHECK(!regarray_find(p, name), EEXIST); 8711 8712 CHECK(size, EINVAL); 8713 size = rte_align32pow2(size); 8714 8715 /* Memory allocation. */ 8716 r = calloc(1, sizeof(struct regarray)); 8717 CHECK(r, ENOMEM); 8718 8719 /* Node initialization. */ 8720 strcpy(r->name, name); 8721 r->init_val = init_val; 8722 r->size = size; 8723 r->id = p->n_regarrays; 8724 8725 /* Node add to tailq. */ 8726 TAILQ_INSERT_TAIL(&p->regarrays, r, node); 8727 p->n_regarrays++; 8728 8729 return 0; 8730 } 8731 8732 static int 8733 regarray_build(struct rte_swx_pipeline *p) 8734 { 8735 struct regarray *regarray; 8736 8737 if (!p->n_regarrays) 8738 return 0; 8739 8740 p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime)); 8741 CHECK(p->regarray_runtime, ENOMEM); 8742 8743 TAILQ_FOREACH(regarray, &p->regarrays, node) { 8744 struct regarray_runtime *r = &p->regarray_runtime[regarray->id]; 8745 uint32_t i; 8746 8747 r->regarray = env_malloc(regarray->size * sizeof(uint64_t), 8748 RTE_CACHE_LINE_SIZE, 8749 p->numa_node); 8750 CHECK(r->regarray, ENOMEM); 8751 8752 if (regarray->init_val) 8753 for (i = 0; i < regarray->size; i++) 8754 r->regarray[i] = regarray->init_val; 8755 8756 r->size_mask = regarray->size - 1; 8757 } 8758 8759 return 0; 8760 } 8761 8762 static void 8763 regarray_build_free(struct rte_swx_pipeline *p) 8764 { 8765 uint32_t i; 8766 8767 if (!p->regarray_runtime) 8768 return; 8769 8770 for (i = 0; i < p->n_regarrays; i++) { 8771 struct regarray *regarray = regarray_find_by_id(p, i); 8772 struct regarray_runtime *r = &p->regarray_runtime[i]; 8773 8774 env_free(r->regarray, regarray->size * sizeof(uint64_t)); 8775 } 8776 8777 free(p->regarray_runtime); 8778 p->regarray_runtime = NULL; 8779 } 8780 8781 static void 8782 regarray_free(struct rte_swx_pipeline *p) 8783 { 8784 regarray_build_free(p); 8785 8786 for ( ; ; ) { 8787 struct regarray *elem; 8788 8789 elem = TAILQ_FIRST(&p->regarrays); 8790 if (!elem) 8791 break; 8792 8793 TAILQ_REMOVE(&p->regarrays, elem, node); 8794 free(elem); 8795 } 8796 } 8797 8798 /* 8799 * Meter array. 8800 */ 8801 static struct meter_profile * 8802 meter_profile_find(struct rte_swx_pipeline *p, const char *name) 8803 { 8804 struct meter_profile *elem; 8805 8806 TAILQ_FOREACH(elem, &p->meter_profiles, node) 8807 if (!strcmp(elem->name, name)) 8808 return elem; 8809 8810 return NULL; 8811 } 8812 8813 static struct metarray * 8814 metarray_find(struct rte_swx_pipeline *p, const char *name) 8815 { 8816 struct metarray *elem; 8817 8818 TAILQ_FOREACH(elem, &p->metarrays, node) 8819 if (!strcmp(elem->name, name)) 8820 return elem; 8821 8822 return NULL; 8823 } 8824 8825 static struct metarray * 8826 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8827 { 8828 struct metarray *elem = NULL; 8829 8830 TAILQ_FOREACH(elem, &p->metarrays, node) 8831 if (elem->id == id) 8832 return elem; 8833 8834 return NULL; 8835 } 8836 8837 int 8838 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p, 8839 const char *name, 8840 uint32_t size) 8841 { 8842 struct metarray *m; 8843 8844 CHECK(p, EINVAL); 8845 8846 CHECK_NAME(name, EINVAL); 8847 CHECK(!metarray_find(p, name), EEXIST); 8848 8849 CHECK(size, EINVAL); 8850 size = rte_align32pow2(size); 8851 8852 /* Memory allocation. */ 8853 m = calloc(1, sizeof(struct metarray)); 8854 CHECK(m, ENOMEM); 8855 8856 /* Node initialization. */ 8857 strcpy(m->name, name); 8858 m->size = size; 8859 m->id = p->n_metarrays; 8860 8861 /* Node add to tailq. */ 8862 TAILQ_INSERT_TAIL(&p->metarrays, m, node); 8863 p->n_metarrays++; 8864 8865 return 0; 8866 } 8867 8868 struct meter_profile meter_profile_default = { 8869 .node = {0}, 8870 .name = "", 8871 .params = {0}, 8872 8873 .profile = { 8874 .cbs = 10000, 8875 .pbs = 10000, 8876 .cir_period = 1, 8877 .cir_bytes_per_period = 1, 8878 .pir_period = 1, 8879 .pir_bytes_per_period = 1, 8880 }, 8881 8882 .n_users = 0, 8883 }; 8884 8885 static void 8886 meter_init(struct meter *m) 8887 { 8888 memset(m, 0, sizeof(struct meter)); 8889 rte_meter_trtcm_config(&m->m, &meter_profile_default.profile); 8890 m->profile = &meter_profile_default; 8891 m->color_mask = RTE_COLOR_GREEN; 8892 8893 meter_profile_default.n_users++; 8894 } 8895 8896 static int 8897 metarray_build(struct rte_swx_pipeline *p) 8898 { 8899 struct metarray *m; 8900 8901 if (!p->n_metarrays) 8902 return 0; 8903 8904 p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime)); 8905 CHECK(p->metarray_runtime, ENOMEM); 8906 8907 TAILQ_FOREACH(m, &p->metarrays, node) { 8908 struct metarray_runtime *r = &p->metarray_runtime[m->id]; 8909 uint32_t i; 8910 8911 r->metarray = env_malloc(m->size * sizeof(struct meter), 8912 RTE_CACHE_LINE_SIZE, 8913 p->numa_node); 8914 CHECK(r->metarray, ENOMEM); 8915 8916 for (i = 0; i < m->size; i++) 8917 meter_init(&r->metarray[i]); 8918 8919 r->size_mask = m->size - 1; 8920 } 8921 8922 return 0; 8923 } 8924 8925 static void 8926 metarray_build_free(struct rte_swx_pipeline *p) 8927 { 8928 uint32_t i; 8929 8930 if (!p->metarray_runtime) 8931 return; 8932 8933 for (i = 0; i < p->n_metarrays; i++) { 8934 struct metarray *m = metarray_find_by_id(p, i); 8935 struct metarray_runtime *r = &p->metarray_runtime[i]; 8936 8937 env_free(r->metarray, m->size * sizeof(struct meter)); 8938 } 8939 8940 free(p->metarray_runtime); 8941 p->metarray_runtime = NULL; 8942 } 8943 8944 static void 8945 metarray_free(struct rte_swx_pipeline *p) 8946 { 8947 metarray_build_free(p); 8948 8949 /* Meter arrays. */ 8950 for ( ; ; ) { 8951 struct metarray *elem; 8952 8953 elem = TAILQ_FIRST(&p->metarrays); 8954 if (!elem) 8955 break; 8956 8957 TAILQ_REMOVE(&p->metarrays, elem, node); 8958 free(elem); 8959 } 8960 8961 /* Meter profiles. */ 8962 for ( ; ; ) { 8963 struct meter_profile *elem; 8964 8965 elem = TAILQ_FIRST(&p->meter_profiles); 8966 if (!elem) 8967 break; 8968 8969 TAILQ_REMOVE(&p->meter_profiles, elem, node); 8970 free(elem); 8971 } 8972 } 8973 8974 /* 8975 * Pipeline. 8976 */ 8977 int 8978 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) 8979 { 8980 struct rte_swx_pipeline *pipeline; 8981 8982 /* Check input parameters. */ 8983 CHECK(p, EINVAL); 8984 8985 /* Memory allocation. */ 8986 pipeline = calloc(1, sizeof(struct rte_swx_pipeline)); 8987 CHECK(pipeline, ENOMEM); 8988 8989 /* Initialization. */ 8990 TAILQ_INIT(&pipeline->struct_types); 8991 TAILQ_INIT(&pipeline->port_in_types); 8992 TAILQ_INIT(&pipeline->ports_in); 8993 TAILQ_INIT(&pipeline->port_out_types); 8994 TAILQ_INIT(&pipeline->ports_out); 8995 TAILQ_INIT(&pipeline->extern_types); 8996 TAILQ_INIT(&pipeline->extern_objs); 8997 TAILQ_INIT(&pipeline->extern_funcs); 8998 TAILQ_INIT(&pipeline->headers); 8999 TAILQ_INIT(&pipeline->actions); 9000 TAILQ_INIT(&pipeline->table_types); 9001 TAILQ_INIT(&pipeline->tables); 9002 TAILQ_INIT(&pipeline->selectors); 9003 TAILQ_INIT(&pipeline->learners); 9004 TAILQ_INIT(&pipeline->regarrays); 9005 TAILQ_INIT(&pipeline->meter_profiles); 9006 TAILQ_INIT(&pipeline->metarrays); 9007 9008 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */ 9009 pipeline->numa_node = numa_node; 9010 9011 *p = pipeline; 9012 return 0; 9013 } 9014 9015 void 9016 rte_swx_pipeline_free(struct rte_swx_pipeline *p) 9017 { 9018 void *lib; 9019 9020 if (!p) 9021 return; 9022 9023 lib = p->lib; 9024 9025 free(p->instruction_data); 9026 free(p->instructions); 9027 9028 metarray_free(p); 9029 regarray_free(p); 9030 table_state_free(p); 9031 learner_free(p); 9032 selector_free(p); 9033 table_free(p); 9034 action_free(p); 9035 instruction_table_free(p); 9036 metadata_free(p); 9037 header_free(p); 9038 extern_func_free(p); 9039 extern_obj_free(p); 9040 port_out_free(p); 9041 port_in_free(p); 9042 struct_free(p); 9043 9044 free(p); 9045 9046 if (lib) 9047 dlclose(lib); 9048 } 9049 9050 int 9051 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p, 9052 const char **instructions, 9053 uint32_t n_instructions) 9054 { 9055 int err; 9056 uint32_t i; 9057 9058 err = instruction_config(p, NULL, instructions, n_instructions); 9059 if (err) 9060 return err; 9061 9062 /* Thread instruction pointer reset. */ 9063 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9064 struct thread *t = &p->threads[i]; 9065 9066 thread_ip_reset(p, t); 9067 } 9068 9069 return 0; 9070 } 9071 9072 static int 9073 pipeline_compile(struct rte_swx_pipeline *p); 9074 9075 int 9076 rte_swx_pipeline_build(struct rte_swx_pipeline *p) 9077 { 9078 int status; 9079 9080 CHECK(p, EINVAL); 9081 CHECK(p->build_done == 0, EEXIST); 9082 9083 status = port_in_build(p); 9084 if (status) 9085 goto error; 9086 9087 status = port_out_build(p); 9088 if (status) 9089 goto error; 9090 9091 status = struct_build(p); 9092 if (status) 9093 goto error; 9094 9095 status = extern_obj_build(p); 9096 if (status) 9097 goto error; 9098 9099 status = extern_func_build(p); 9100 if (status) 9101 goto error; 9102 9103 status = header_build(p); 9104 if (status) 9105 goto error; 9106 9107 status = metadata_build(p); 9108 if (status) 9109 goto error; 9110 9111 status = instruction_table_build(p); 9112 if (status) 9113 goto error; 9114 9115 status = action_build(p); 9116 if (status) 9117 goto error; 9118 9119 status = table_build(p); 9120 if (status) 9121 goto error; 9122 9123 status = selector_build(p); 9124 if (status) 9125 goto error; 9126 9127 status = learner_build(p); 9128 if (status) 9129 goto error; 9130 9131 status = table_state_build(p); 9132 if (status) 9133 goto error; 9134 9135 status = regarray_build(p); 9136 if (status) 9137 goto error; 9138 9139 status = metarray_build(p); 9140 if (status) 9141 goto error; 9142 9143 p->build_done = 1; 9144 9145 pipeline_compile(p); 9146 9147 return 0; 9148 9149 error: 9150 metarray_build_free(p); 9151 regarray_build_free(p); 9152 table_state_build_free(p); 9153 learner_build_free(p); 9154 selector_build_free(p); 9155 table_build_free(p); 9156 action_build_free(p); 9157 instruction_table_build_free(p); 9158 metadata_build_free(p); 9159 header_build_free(p); 9160 extern_func_build_free(p); 9161 extern_obj_build_free(p); 9162 port_out_build_free(p); 9163 port_in_build_free(p); 9164 struct_build_free(p); 9165 9166 return status; 9167 } 9168 9169 void 9170 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions) 9171 { 9172 uint32_t i; 9173 9174 for (i = 0; i < n_instructions; i++) 9175 instr_exec(p); 9176 } 9177 9178 void 9179 rte_swx_pipeline_flush(struct rte_swx_pipeline *p) 9180 { 9181 uint32_t i; 9182 9183 for (i = 0; i < p->n_ports_out; i++) { 9184 struct port_out_runtime *port = &p->out[i]; 9185 9186 if (port->flush) 9187 port->flush(port->obj); 9188 } 9189 } 9190 9191 /* 9192 * Control. 9193 */ 9194 int 9195 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, 9196 struct rte_swx_ctl_pipeline_info *pipeline) 9197 { 9198 struct action *action; 9199 struct table *table; 9200 uint32_t n_actions = 0, n_tables = 0; 9201 9202 if (!p || !pipeline) 9203 return -EINVAL; 9204 9205 TAILQ_FOREACH(action, &p->actions, node) 9206 n_actions++; 9207 9208 TAILQ_FOREACH(table, &p->tables, node) 9209 n_tables++; 9210 9211 pipeline->n_ports_in = p->n_ports_in; 9212 pipeline->n_ports_out = p->n_ports_out; 9213 pipeline->n_actions = n_actions; 9214 pipeline->n_tables = n_tables; 9215 pipeline->n_selectors = p->n_selectors; 9216 pipeline->n_learners = p->n_learners; 9217 pipeline->n_regarrays = p->n_regarrays; 9218 pipeline->n_metarrays = p->n_metarrays; 9219 9220 return 0; 9221 } 9222 9223 int 9224 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node) 9225 { 9226 if (!p || !numa_node) 9227 return -EINVAL; 9228 9229 *numa_node = p->numa_node; 9230 return 0; 9231 } 9232 9233 int 9234 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, 9235 uint32_t action_id, 9236 struct rte_swx_ctl_action_info *action) 9237 { 9238 struct action *a = NULL; 9239 9240 if (!p || (action_id >= p->n_actions) || !action) 9241 return -EINVAL; 9242 9243 a = action_find_by_id(p, action_id); 9244 if (!a) 9245 return -EINVAL; 9246 9247 strcpy(action->name, a->name); 9248 action->n_args = a->st ? a->st->n_fields : 0; 9249 return 0; 9250 } 9251 9252 int 9253 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, 9254 uint32_t action_id, 9255 uint32_t action_arg_id, 9256 struct rte_swx_ctl_action_arg_info *action_arg) 9257 { 9258 struct action *a = NULL; 9259 struct field *arg = NULL; 9260 9261 if (!p || (action_id >= p->n_actions) || !action_arg) 9262 return -EINVAL; 9263 9264 a = action_find_by_id(p, action_id); 9265 if (!a || !a->st || (action_arg_id >= a->st->n_fields)) 9266 return -EINVAL; 9267 9268 arg = &a->st->fields[action_arg_id]; 9269 strcpy(action_arg->name, arg->name); 9270 action_arg->n_bits = arg->n_bits; 9271 action_arg->is_network_byte_order = a->args_endianness[action_arg_id]; 9272 9273 return 0; 9274 } 9275 9276 int 9277 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, 9278 uint32_t table_id, 9279 struct rte_swx_ctl_table_info *table) 9280 { 9281 struct table *t = NULL; 9282 9283 if (!p || !table) 9284 return -EINVAL; 9285 9286 t = table_find_by_id(p, table_id); 9287 if (!t) 9288 return -EINVAL; 9289 9290 strcpy(table->name, t->name); 9291 strcpy(table->args, t->args); 9292 table->n_match_fields = t->n_fields; 9293 table->n_actions = t->n_actions; 9294 table->default_action_is_const = t->default_action_is_const; 9295 table->size = t->size; 9296 return 0; 9297 } 9298 9299 int 9300 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, 9301 uint32_t table_id, 9302 uint32_t match_field_id, 9303 struct rte_swx_ctl_table_match_field_info *match_field) 9304 { 9305 struct table *t; 9306 struct match_field *f; 9307 9308 if (!p || (table_id >= p->n_tables) || !match_field) 9309 return -EINVAL; 9310 9311 t = table_find_by_id(p, table_id); 9312 if (!t || (match_field_id >= t->n_fields)) 9313 return -EINVAL; 9314 9315 f = &t->fields[match_field_id]; 9316 match_field->match_type = f->match_type; 9317 match_field->is_header = t->header ? 1 : 0; 9318 match_field->n_bits = f->field->n_bits; 9319 match_field->offset = f->field->offset; 9320 9321 return 0; 9322 } 9323 9324 int 9325 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, 9326 uint32_t table_id, 9327 uint32_t table_action_id, 9328 struct rte_swx_ctl_table_action_info *table_action) 9329 { 9330 struct table *t; 9331 9332 if (!p || (table_id >= p->n_tables) || !table_action) 9333 return -EINVAL; 9334 9335 t = table_find_by_id(p, table_id); 9336 if (!t || (table_action_id >= t->n_actions)) 9337 return -EINVAL; 9338 9339 table_action->action_id = t->actions[table_action_id]->id; 9340 9341 table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; 9342 table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; 9343 9344 return 0; 9345 } 9346 9347 int 9348 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, 9349 uint32_t table_id, 9350 struct rte_swx_table_ops *table_ops, 9351 int *is_stub) 9352 { 9353 struct table *t; 9354 9355 if (!p || (table_id >= p->n_tables)) 9356 return -EINVAL; 9357 9358 t = table_find_by_id(p, table_id); 9359 if (!t) 9360 return -EINVAL; 9361 9362 if (t->type) { 9363 if (table_ops) 9364 memcpy(table_ops, &t->type->ops, sizeof(*table_ops)); 9365 *is_stub = 0; 9366 } else { 9367 *is_stub = 1; 9368 } 9369 9370 return 0; 9371 } 9372 9373 int 9374 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p, 9375 uint32_t selector_id, 9376 struct rte_swx_ctl_selector_info *selector) 9377 { 9378 struct selector *s = NULL; 9379 9380 if (!p || !selector) 9381 return -EINVAL; 9382 9383 s = selector_find_by_id(p, selector_id); 9384 if (!s) 9385 return -EINVAL; 9386 9387 strcpy(selector->name, s->name); 9388 9389 selector->n_selector_fields = s->n_selector_fields; 9390 selector->n_groups_max = s->n_groups_max; 9391 selector->n_members_per_group_max = s->n_members_per_group_max; 9392 9393 return 0; 9394 } 9395 9396 int 9397 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p, 9398 uint32_t selector_id, 9399 struct rte_swx_ctl_table_match_field_info *field) 9400 { 9401 struct selector *s; 9402 9403 if (!p || (selector_id >= p->n_selectors) || !field) 9404 return -EINVAL; 9405 9406 s = selector_find_by_id(p, selector_id); 9407 if (!s) 9408 return -EINVAL; 9409 9410 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9411 field->is_header = 0; 9412 field->n_bits = s->group_id_field->n_bits; 9413 field->offset = s->group_id_field->offset; 9414 9415 return 0; 9416 } 9417 9418 int 9419 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p, 9420 uint32_t selector_id, 9421 uint32_t selector_field_id, 9422 struct rte_swx_ctl_table_match_field_info *field) 9423 { 9424 struct selector *s; 9425 struct field *f; 9426 9427 if (!p || (selector_id >= p->n_selectors) || !field) 9428 return -EINVAL; 9429 9430 s = selector_find_by_id(p, selector_id); 9431 if (!s || (selector_field_id >= s->n_selector_fields)) 9432 return -EINVAL; 9433 9434 f = s->selector_fields[selector_field_id]; 9435 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9436 field->is_header = s->selector_header ? 1 : 0; 9437 field->n_bits = f->n_bits; 9438 field->offset = f->offset; 9439 9440 return 0; 9441 } 9442 9443 int 9444 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p, 9445 uint32_t selector_id, 9446 struct rte_swx_ctl_table_match_field_info *field) 9447 { 9448 struct selector *s; 9449 9450 if (!p || (selector_id >= p->n_selectors) || !field) 9451 return -EINVAL; 9452 9453 s = selector_find_by_id(p, selector_id); 9454 if (!s) 9455 return -EINVAL; 9456 9457 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9458 field->is_header = 0; 9459 field->n_bits = s->member_id_field->n_bits; 9460 field->offset = s->member_id_field->offset; 9461 9462 return 0; 9463 } 9464 9465 int 9466 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p, 9467 uint32_t learner_id, 9468 struct rte_swx_ctl_learner_info *learner) 9469 { 9470 struct learner *l = NULL; 9471 9472 if (!p || !learner) 9473 return -EINVAL; 9474 9475 l = learner_find_by_id(p, learner_id); 9476 if (!l) 9477 return -EINVAL; 9478 9479 strcpy(learner->name, l->name); 9480 9481 learner->n_match_fields = l->n_fields; 9482 learner->n_actions = l->n_actions; 9483 learner->default_action_is_const = l->default_action_is_const; 9484 learner->size = l->size; 9485 9486 return 0; 9487 } 9488 9489 int 9490 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p, 9491 uint32_t learner_id, 9492 uint32_t match_field_id, 9493 struct rte_swx_ctl_table_match_field_info *match_field) 9494 { 9495 struct learner *l; 9496 struct field *f; 9497 9498 if (!p || (learner_id >= p->n_learners) || !match_field) 9499 return -EINVAL; 9500 9501 l = learner_find_by_id(p, learner_id); 9502 if (!l || (match_field_id >= l->n_fields)) 9503 return -EINVAL; 9504 9505 f = l->fields[match_field_id]; 9506 match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9507 match_field->is_header = l->header ? 1 : 0; 9508 match_field->n_bits = f->n_bits; 9509 match_field->offset = f->offset; 9510 9511 return 0; 9512 } 9513 9514 int 9515 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, 9516 uint32_t learner_id, 9517 uint32_t learner_action_id, 9518 struct rte_swx_ctl_table_action_info *learner_action) 9519 { 9520 struct learner *l; 9521 9522 if (!p || (learner_id >= p->n_learners) || !learner_action) 9523 return -EINVAL; 9524 9525 l = learner_find_by_id(p, learner_id); 9526 if (!l || (learner_action_id >= l->n_actions)) 9527 return -EINVAL; 9528 9529 learner_action->action_id = l->actions[learner_action_id]->id; 9530 9531 learner_action->action_is_for_table_entries = 9532 l->action_is_for_table_entries[learner_action_id]; 9533 9534 learner_action->action_is_for_default_entry = 9535 l->action_is_for_default_entry[learner_action_id]; 9536 9537 return 0; 9538 } 9539 9540 int 9541 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p, 9542 struct rte_swx_table_state **table_state) 9543 { 9544 if (!p || !table_state || !p->build_done) 9545 return -EINVAL; 9546 9547 *table_state = p->table_state; 9548 return 0; 9549 } 9550 9551 int 9552 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p, 9553 struct rte_swx_table_state *table_state) 9554 { 9555 if (!p || !table_state || !p->build_done) 9556 return -EINVAL; 9557 9558 p->table_state = table_state; 9559 return 0; 9560 } 9561 9562 int 9563 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, 9564 uint32_t port_id, 9565 struct rte_swx_port_in_stats *stats) 9566 { 9567 struct port_in *port; 9568 9569 if (!p || !stats) 9570 return -EINVAL; 9571 9572 port = port_in_find(p, port_id); 9573 if (!port) 9574 return -EINVAL; 9575 9576 port->type->ops.stats_read(port->obj, stats); 9577 return 0; 9578 } 9579 9580 int 9581 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, 9582 uint32_t port_id, 9583 struct rte_swx_port_out_stats *stats) 9584 { 9585 struct port_out *port; 9586 9587 if (!p || !stats) 9588 return -EINVAL; 9589 9590 port = port_out_find(p, port_id); 9591 if (!port) 9592 return -EINVAL; 9593 9594 port->type->ops.stats_read(port->obj, stats); 9595 return 0; 9596 } 9597 9598 int 9599 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, 9600 const char *table_name, 9601 struct rte_swx_table_stats *stats) 9602 { 9603 struct table *table; 9604 struct table_statistics *table_stats; 9605 9606 if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action) 9607 return -EINVAL; 9608 9609 table = table_find(p, table_name); 9610 if (!table) 9611 return -EINVAL; 9612 9613 table_stats = &p->table_stats[table->id]; 9614 9615 memcpy(stats->n_pkts_action, 9616 table_stats->n_pkts_action, 9617 p->n_actions * sizeof(uint64_t)); 9618 9619 stats->n_pkts_hit = table_stats->n_pkts_hit[1]; 9620 stats->n_pkts_miss = table_stats->n_pkts_hit[0]; 9621 9622 return 0; 9623 } 9624 9625 int 9626 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p, 9627 const char *selector_name, 9628 struct rte_swx_pipeline_selector_stats *stats) 9629 { 9630 struct selector *s; 9631 9632 if (!p || !selector_name || !selector_name[0] || !stats) 9633 return -EINVAL; 9634 9635 s = selector_find(p, selector_name); 9636 if (!s) 9637 return -EINVAL; 9638 9639 stats->n_pkts = p->selector_stats[s->id].n_pkts; 9640 9641 return 0; 9642 } 9643 9644 int 9645 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, 9646 const char *learner_name, 9647 struct rte_swx_learner_stats *stats) 9648 { 9649 struct learner *l; 9650 struct learner_statistics *learner_stats; 9651 9652 if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action) 9653 return -EINVAL; 9654 9655 l = learner_find(p, learner_name); 9656 if (!l) 9657 return -EINVAL; 9658 9659 learner_stats = &p->learner_stats[l->id]; 9660 9661 memcpy(stats->n_pkts_action, 9662 learner_stats->n_pkts_action, 9663 p->n_actions * sizeof(uint64_t)); 9664 9665 stats->n_pkts_hit = learner_stats->n_pkts_hit[1]; 9666 stats->n_pkts_miss = learner_stats->n_pkts_hit[0]; 9667 9668 stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0]; 9669 stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1]; 9670 9671 stats->n_pkts_forget = learner_stats->n_pkts_forget; 9672 9673 return 0; 9674 } 9675 9676 int 9677 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p, 9678 uint32_t regarray_id, 9679 struct rte_swx_ctl_regarray_info *regarray) 9680 { 9681 struct regarray *r; 9682 9683 if (!p || !regarray) 9684 return -EINVAL; 9685 9686 r = regarray_find_by_id(p, regarray_id); 9687 if (!r) 9688 return -EINVAL; 9689 9690 strcpy(regarray->name, r->name); 9691 regarray->size = r->size; 9692 return 0; 9693 } 9694 9695 int 9696 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p, 9697 const char *regarray_name, 9698 uint32_t regarray_index, 9699 uint64_t *value) 9700 { 9701 struct regarray *regarray; 9702 struct regarray_runtime *r; 9703 9704 if (!p || !regarray_name || !value) 9705 return -EINVAL; 9706 9707 regarray = regarray_find(p, regarray_name); 9708 if (!regarray || (regarray_index >= regarray->size)) 9709 return -EINVAL; 9710 9711 r = &p->regarray_runtime[regarray->id]; 9712 *value = r->regarray[regarray_index]; 9713 return 0; 9714 } 9715 9716 int 9717 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p, 9718 const char *regarray_name, 9719 uint32_t regarray_index, 9720 uint64_t value) 9721 { 9722 struct regarray *regarray; 9723 struct regarray_runtime *r; 9724 9725 if (!p || !regarray_name) 9726 return -EINVAL; 9727 9728 regarray = regarray_find(p, regarray_name); 9729 if (!regarray || (regarray_index >= regarray->size)) 9730 return -EINVAL; 9731 9732 r = &p->regarray_runtime[regarray->id]; 9733 r->regarray[regarray_index] = value; 9734 return 0; 9735 } 9736 9737 int 9738 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p, 9739 uint32_t metarray_id, 9740 struct rte_swx_ctl_metarray_info *metarray) 9741 { 9742 struct metarray *m; 9743 9744 if (!p || !metarray) 9745 return -EINVAL; 9746 9747 m = metarray_find_by_id(p, metarray_id); 9748 if (!m) 9749 return -EINVAL; 9750 9751 strcpy(metarray->name, m->name); 9752 metarray->size = m->size; 9753 return 0; 9754 } 9755 9756 int 9757 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p, 9758 const char *name, 9759 struct rte_meter_trtcm_params *params) 9760 { 9761 struct meter_profile *mp; 9762 int status; 9763 9764 CHECK(p, EINVAL); 9765 CHECK_NAME(name, EINVAL); 9766 CHECK(params, EINVAL); 9767 CHECK(!meter_profile_find(p, name), EEXIST); 9768 9769 /* Node allocation. */ 9770 mp = calloc(1, sizeof(struct meter_profile)); 9771 CHECK(mp, ENOMEM); 9772 9773 /* Node initialization. */ 9774 strcpy(mp->name, name); 9775 memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params)); 9776 status = rte_meter_trtcm_profile_config(&mp->profile, params); 9777 if (status) { 9778 free(mp); 9779 CHECK(0, EINVAL); 9780 } 9781 9782 /* Node add to tailq. */ 9783 TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node); 9784 9785 return 0; 9786 } 9787 9788 int 9789 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p, 9790 const char *name) 9791 { 9792 struct meter_profile *mp; 9793 9794 CHECK(p, EINVAL); 9795 CHECK_NAME(name, EINVAL); 9796 9797 mp = meter_profile_find(p, name); 9798 CHECK(mp, EINVAL); 9799 CHECK(!mp->n_users, EBUSY); 9800 9801 /* Remove node from tailq. */ 9802 TAILQ_REMOVE(&p->meter_profiles, mp, node); 9803 free(mp); 9804 9805 return 0; 9806 } 9807 9808 int 9809 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p, 9810 const char *metarray_name, 9811 uint32_t metarray_index) 9812 { 9813 struct meter_profile *mp_old; 9814 struct metarray *metarray; 9815 struct metarray_runtime *metarray_runtime; 9816 struct meter *m; 9817 9818 CHECK(p, EINVAL); 9819 CHECK_NAME(metarray_name, EINVAL); 9820 9821 metarray = metarray_find(p, metarray_name); 9822 CHECK(metarray, EINVAL); 9823 CHECK(metarray_index < metarray->size, EINVAL); 9824 9825 metarray_runtime = &p->metarray_runtime[metarray->id]; 9826 m = &metarray_runtime->metarray[metarray_index]; 9827 mp_old = m->profile; 9828 9829 meter_init(m); 9830 9831 mp_old->n_users--; 9832 9833 return 0; 9834 } 9835 9836 int 9837 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p, 9838 const char *metarray_name, 9839 uint32_t metarray_index, 9840 const char *profile_name) 9841 { 9842 struct meter_profile *mp, *mp_old; 9843 struct metarray *metarray; 9844 struct metarray_runtime *metarray_runtime; 9845 struct meter *m; 9846 9847 CHECK(p, EINVAL); 9848 CHECK_NAME(metarray_name, EINVAL); 9849 9850 metarray = metarray_find(p, metarray_name); 9851 CHECK(metarray, EINVAL); 9852 CHECK(metarray_index < metarray->size, EINVAL); 9853 9854 mp = meter_profile_find(p, profile_name); 9855 CHECK(mp, EINVAL); 9856 9857 metarray_runtime = &p->metarray_runtime[metarray->id]; 9858 m = &metarray_runtime->metarray[metarray_index]; 9859 mp_old = m->profile; 9860 9861 memset(m, 0, sizeof(struct meter)); 9862 rte_meter_trtcm_config(&m->m, &mp->profile); 9863 m->profile = mp; 9864 m->color_mask = RTE_COLORS; 9865 9866 mp->n_users++; 9867 mp_old->n_users--; 9868 9869 return 0; 9870 } 9871 9872 int 9873 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, 9874 const char *metarray_name, 9875 uint32_t metarray_index, 9876 struct rte_swx_ctl_meter_stats *stats) 9877 { 9878 struct metarray *metarray; 9879 struct metarray_runtime *metarray_runtime; 9880 struct meter *m; 9881 9882 CHECK(p, EINVAL); 9883 CHECK_NAME(metarray_name, EINVAL); 9884 9885 metarray = metarray_find(p, metarray_name); 9886 CHECK(metarray, EINVAL); 9887 CHECK(metarray_index < metarray->size, EINVAL); 9888 9889 CHECK(stats, EINVAL); 9890 9891 metarray_runtime = &p->metarray_runtime[metarray->id]; 9892 m = &metarray_runtime->metarray[metarray_index]; 9893 9894 memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts)); 9895 memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes)); 9896 9897 return 0; 9898 } 9899 9900 /* 9901 * Pipeline compilation. 9902 */ 9903 static const char * 9904 instr_type_to_name(struct instruction *instr) 9905 { 9906 switch (instr->type) { 9907 case INSTR_RX: return "INSTR_RX"; 9908 9909 case INSTR_TX: return "INSTR_TX"; 9910 case INSTR_TX_I: return "INSTR_TX_I"; 9911 9912 case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; 9913 case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; 9914 case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3"; 9915 case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4"; 9916 case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5"; 9917 case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6"; 9918 case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7"; 9919 case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8"; 9920 9921 case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M"; 9922 9923 case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD"; 9924 9925 case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT"; 9926 case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX"; 9927 case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX"; 9928 case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX"; 9929 case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX"; 9930 case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX"; 9931 case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX"; 9932 case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX"; 9933 case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX"; 9934 9935 case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE"; 9936 case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE"; 9937 9938 case INSTR_MOV: return "INSTR_MOV"; 9939 case INSTR_MOV_MH: return "INSTR_MOV_MH"; 9940 case INSTR_MOV_HM: return "INSTR_MOV_HM"; 9941 case INSTR_MOV_HH: return "INSTR_MOV_HH"; 9942 case INSTR_MOV_I: return "INSTR_MOV_I"; 9943 9944 case INSTR_DMA_HT: return "INSTR_DMA_HT"; 9945 case INSTR_DMA_HT2: return "INSTR_DMA_HT2"; 9946 case INSTR_DMA_HT3: return "INSTR_DMA_HT3"; 9947 case INSTR_DMA_HT4: return "INSTR_DMA_HT4"; 9948 case INSTR_DMA_HT5: return "INSTR_DMA_HT5"; 9949 case INSTR_DMA_HT6: return "INSTR_DMA_HT6"; 9950 case INSTR_DMA_HT7: return "INSTR_DMA_HT7"; 9951 case INSTR_DMA_HT8: return "INSTR_DMA_HT8"; 9952 9953 case INSTR_ALU_ADD: return "INSTR_ALU_ADD"; 9954 case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH"; 9955 case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM"; 9956 case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH"; 9957 case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI"; 9958 case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI"; 9959 9960 case INSTR_ALU_SUB: return "INSTR_ALU_SUB"; 9961 case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH"; 9962 case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM"; 9963 case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH"; 9964 case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI"; 9965 case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI"; 9966 9967 case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD"; 9968 case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20"; 9969 case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT"; 9970 case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD"; 9971 9972 case INSTR_ALU_AND: return "INSTR_ALU_AND"; 9973 case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH"; 9974 case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM"; 9975 case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH"; 9976 case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I"; 9977 9978 case INSTR_ALU_OR: return "INSTR_ALU_OR"; 9979 case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH"; 9980 case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM"; 9981 case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH"; 9982 case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I"; 9983 9984 case INSTR_ALU_XOR: return "INSTR_ALU_XOR"; 9985 case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH"; 9986 case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM"; 9987 case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH"; 9988 case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I"; 9989 9990 case INSTR_ALU_SHL: return "INSTR_ALU_SHL"; 9991 case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH"; 9992 case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM"; 9993 case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH"; 9994 case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI"; 9995 case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI"; 9996 9997 case INSTR_ALU_SHR: return "INSTR_ALU_SHR"; 9998 case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH"; 9999 case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM"; 10000 case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH"; 10001 case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI"; 10002 case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI"; 10003 10004 case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH"; 10005 case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM"; 10006 case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI"; 10007 10008 case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH"; 10009 case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM"; 10010 case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI"; 10011 case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH"; 10012 case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM"; 10013 case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI"; 10014 10015 case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH"; 10016 case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM"; 10017 case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI"; 10018 case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH"; 10019 case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM"; 10020 case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI"; 10021 case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH"; 10022 case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM"; 10023 case INSTR_REGWR_RII: return "INSTR_REGWR_RII"; 10024 10025 case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH"; 10026 case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM"; 10027 case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI"; 10028 case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH"; 10029 case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM"; 10030 case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI"; 10031 case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH"; 10032 case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM"; 10033 case INSTR_REGADD_RII: return "INSTR_REGADD_RII"; 10034 10035 case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H"; 10036 case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M"; 10037 case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I"; 10038 10039 case INSTR_METER_HHM: return "INSTR_METER_HHM"; 10040 case INSTR_METER_HHI: return "INSTR_METER_HHI"; 10041 case INSTR_METER_HMM: return "INSTR_METER_HMM"; 10042 case INSTR_METER_HMI: return "INSTR_METER_HMI"; 10043 case INSTR_METER_MHM: return "INSTR_METER_MHM"; 10044 case INSTR_METER_MHI: return "INSTR_METER_MHI"; 10045 case INSTR_METER_MMM: return "INSTR_METER_MMM"; 10046 case INSTR_METER_MMI: return "INSTR_METER_MMI"; 10047 case INSTR_METER_IHM: return "INSTR_METER_IHM"; 10048 case INSTR_METER_IHI: return "INSTR_METER_IHI"; 10049 case INSTR_METER_IMM: return "INSTR_METER_IMM"; 10050 case INSTR_METER_IMI: return "INSTR_METER_IMI"; 10051 10052 case INSTR_TABLE: return "INSTR_TABLE"; 10053 case INSTR_TABLE_AF: return "INSTR_TABLE_AF"; 10054 case INSTR_SELECTOR: return "INSTR_SELECTOR"; 10055 case INSTR_LEARNER: return "INSTR_LEARNER"; 10056 case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; 10057 10058 case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; 10059 case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; 10060 10061 case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; 10062 case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC"; 10063 10064 case INSTR_JMP: return "INSTR_JMP"; 10065 case INSTR_JMP_VALID: return "INSTR_JMP_VALID"; 10066 case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID"; 10067 case INSTR_JMP_HIT: return "INSTR_JMP_HIT"; 10068 case INSTR_JMP_MISS: return "INSTR_JMP_MISS"; 10069 case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT"; 10070 case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS"; 10071 case INSTR_JMP_EQ: return "INSTR_JMP_EQ"; 10072 case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH"; 10073 case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM"; 10074 case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH"; 10075 case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I"; 10076 case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ"; 10077 case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH"; 10078 case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM"; 10079 case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH"; 10080 case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I"; 10081 case INSTR_JMP_LT: return "INSTR_JMP_LT"; 10082 case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH"; 10083 case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM"; 10084 case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH"; 10085 case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI"; 10086 case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI"; 10087 case INSTR_JMP_GT: return "INSTR_JMP_GT"; 10088 case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH"; 10089 case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM"; 10090 case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH"; 10091 case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI"; 10092 case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI"; 10093 10094 case INSTR_RETURN: return "INSTR_RETURN"; 10095 10096 default: return "INSTR_UNKNOWN"; 10097 } 10098 } 10099 10100 typedef void 10101 (*instruction_export_t)(struct instruction *, FILE *); 10102 10103 static void 10104 instr_io_export(struct instruction *instr, FILE *f) 10105 { 10106 uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i; 10107 10108 /* n_io, n_io_imm, n_hdrs. */ 10109 if (instr->type == INSTR_RX || 10110 instr->type == INSTR_TX || 10111 instr->type == INSTR_HDR_EXTRACT_M || 10112 (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)) 10113 n_io = 1; 10114 10115 if (instr->type == INSTR_TX_I) 10116 n_io_imm = 1; 10117 10118 if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8) 10119 n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT); 10120 10121 if (instr->type == INSTR_HDR_EXTRACT_M || 10122 instr->type == INSTR_HDR_LOOKAHEAD || 10123 instr->type == INSTR_HDR_EMIT) 10124 n_hdrs = 1; 10125 10126 if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX) 10127 n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX); 10128 10129 /* instr. */ 10130 fprintf(f, 10131 "\t{\n" 10132 "\t\t.type = %s,\n", 10133 instr_type_to_name(instr)); 10134 10135 /* instr.io. */ 10136 fprintf(f, 10137 "\t\t.io = {\n"); 10138 10139 /* instr.io.io. */ 10140 if (n_io) 10141 fprintf(f, 10142 "\t\t\t.io = {\n" 10143 "\t\t\t\t.offset = %u,\n" 10144 "\t\t\t\t.n_bits = %u,\n" 10145 "\t\t\t},\n", 10146 instr->io.io.offset, 10147 instr->io.io.n_bits); 10148 10149 if (n_io_imm) 10150 fprintf(f, 10151 "\t\t\t.io = {\n" 10152 "\t\t\t\t.val = %u,\n" 10153 "\t\t\t},\n", 10154 instr->io.io.val); 10155 10156 /* instr.io.hdr. */ 10157 if (n_hdrs) { 10158 fprintf(f, 10159 "\t\t.hdr = {\n"); 10160 10161 /* instr.io.hdr.header_id. */ 10162 fprintf(f, 10163 "\t\t\t.header_id = {"); 10164 10165 for (i = 0; i < n_hdrs; i++) 10166 fprintf(f, 10167 "%u, ", 10168 instr->io.hdr.header_id[i]); 10169 10170 fprintf(f, 10171 "},\n"); 10172 10173 /* instr.io.hdr.struct_id. */ 10174 fprintf(f, 10175 "\t\t\t.struct_id = {"); 10176 10177 for (i = 0; i < n_hdrs; i++) 10178 fprintf(f, 10179 "%u, ", 10180 instr->io.hdr.struct_id[i]); 10181 10182 fprintf(f, 10183 "},\n"); 10184 10185 /* instr.io.hdr.n_bytes. */ 10186 fprintf(f, 10187 "\t\t\t.n_bytes = {"); 10188 10189 for (i = 0; i < n_hdrs; i++) 10190 fprintf(f, 10191 "%u, ", 10192 instr->io.hdr.n_bytes[i]); 10193 10194 fprintf(f, 10195 "},\n"); 10196 10197 /* instr.io.hdr - closing curly brace. */ 10198 fprintf(f, 10199 "\t\t\t}\n,"); 10200 } 10201 10202 /* instr.io - closing curly brace. */ 10203 fprintf(f, 10204 "\t\t},\n"); 10205 10206 /* instr - closing curly brace. */ 10207 fprintf(f, 10208 "\t},\n"); 10209 } 10210 10211 static void 10212 instr_hdr_validate_export(struct instruction *instr, FILE *f) 10213 { 10214 fprintf(f, 10215 "\t{\n" 10216 "\t\t.type = %s,\n" 10217 "\t\t.valid = {\n" 10218 "\t\t\t.header_id = %u,\n" 10219 "\t\t},\n" 10220 "\t},\n", 10221 instr_type_to_name(instr), 10222 instr->valid.header_id); 10223 } 10224 10225 static void 10226 instr_mov_export(struct instruction *instr, FILE *f) 10227 { 10228 if (instr->type != INSTR_MOV_I) 10229 fprintf(f, 10230 "\t{\n" 10231 "\t\t.type = %s,\n" 10232 "\t\t.mov = {\n" 10233 "\t\t\t.dst = {\n" 10234 "\t\t\t\t.struct_id = %u,\n" 10235 "\t\t\t\t.n_bits = %u,\n" 10236 "\t\t\t\t.offset = %u,\n" 10237 "\t\t\t},\n" 10238 "\t\t\t.src = {\n" 10239 "\t\t\t\t.struct_id = %u,\n" 10240 "\t\t\t\t.n_bits = %u,\n" 10241 "\t\t\t\t.offset = %u,\n" 10242 "\t\t\t},\n" 10243 "\t\t},\n" 10244 "\t},\n", 10245 instr_type_to_name(instr), 10246 instr->mov.dst.struct_id, 10247 instr->mov.dst.n_bits, 10248 instr->mov.dst.offset, 10249 instr->mov.src.struct_id, 10250 instr->mov.src.n_bits, 10251 instr->mov.src.offset); 10252 else 10253 fprintf(f, 10254 "\t{\n" 10255 "\t\t.type = %s,\n" 10256 "\t\t.mov = {\n" 10257 "\t\t\t.dst = {\n" 10258 "\t\t\t\t.struct_id = %u,\n" 10259 "\t\t\t\t.n_bits = %u,\n" 10260 "\t\t\t\t.offset = %u,\n" 10261 "\t\t\t}\n," 10262 "\t\t\t.src_val = %" PRIu64 ",\n" 10263 "\t\t},\n" 10264 "\t},\n", 10265 instr_type_to_name(instr), 10266 instr->mov.dst.struct_id, 10267 instr->mov.dst.n_bits, 10268 instr->mov.dst.offset, 10269 instr->mov.src_val); 10270 } 10271 10272 static void 10273 instr_dma_ht_export(struct instruction *instr, FILE *f) 10274 { 10275 uint32_t n_dma = 0, i; 10276 10277 /* n_dma. */ 10278 n_dma = 1 + (instr->type - INSTR_DMA_HT); 10279 10280 /* instr. */ 10281 fprintf(f, 10282 "\t{\n" 10283 "\t\t.type = %s,\n", 10284 instr_type_to_name(instr)); 10285 10286 /* instr.dma. */ 10287 fprintf(f, 10288 "\t\t.dma = {\n"); 10289 10290 /* instr.dma.dst. */ 10291 fprintf(f, 10292 "\t\t\t.dst = {\n"); 10293 10294 /* instr.dma.dst.header_id. */ 10295 fprintf(f, 10296 "\t\t\t\t.header_id = {"); 10297 10298 for (i = 0; i < n_dma; i++) 10299 fprintf(f, 10300 "%u, ", 10301 instr->dma.dst.header_id[i]); 10302 10303 fprintf(f, 10304 "},\n"); 10305 10306 /* instr.dma.dst.struct_id. */ 10307 fprintf(f, 10308 "\t\t\t\t.struct_id = {"); 10309 10310 for (i = 0; i < n_dma; i++) 10311 fprintf(f, 10312 "%u, ", 10313 instr->dma.dst.struct_id[i]); 10314 10315 fprintf(f, 10316 "},\n"); 10317 10318 /* instr.dma.dst - closing curly brace. */ 10319 fprintf(f, 10320 "\t\t\t},\n"); 10321 10322 /* instr.dma.src. */ 10323 fprintf(f, 10324 "\t\t\t.src = {\n"); 10325 10326 /* instr.dma.src.offset. */ 10327 fprintf(f, 10328 "\t\t\t\t.offset = {"); 10329 10330 for (i = 0; i < n_dma; i++) 10331 fprintf(f, 10332 "%u, ", 10333 instr->dma.src.offset[i]); 10334 10335 fprintf(f, 10336 "},\n"); 10337 10338 /* instr.dma.src - closing curly brace. */ 10339 fprintf(f, 10340 "\t\t\t},\n"); 10341 10342 /* instr.dma.n_bytes. */ 10343 fprintf(f, 10344 "\t\t\t.n_bytes = {"); 10345 10346 for (i = 0; i < n_dma; i++) 10347 fprintf(f, 10348 "%u, ", 10349 instr->dma.n_bytes[i]); 10350 10351 fprintf(f, 10352 "},\n"); 10353 10354 /* instr.dma - closing curly brace. */ 10355 fprintf(f, 10356 "\t\t},\n"); 10357 10358 /* instr - closing curly brace. */ 10359 fprintf(f, 10360 "\t},\n"); 10361 } 10362 10363 static void 10364 instr_alu_export(struct instruction *instr, FILE *f) 10365 { 10366 int imm = 0; 10367 10368 if (instr->type == INSTR_ALU_ADD_MI || 10369 instr->type == INSTR_ALU_ADD_HI || 10370 instr->type == INSTR_ALU_SUB_MI || 10371 instr->type == INSTR_ALU_SUB_HI || 10372 instr->type == INSTR_ALU_SHL_MI || 10373 instr->type == INSTR_ALU_SHL_HI || 10374 instr->type == INSTR_ALU_SHR_MI || 10375 instr->type == INSTR_ALU_SHR_HI || 10376 instr->type == INSTR_ALU_AND_I || 10377 instr->type == INSTR_ALU_OR_I || 10378 instr->type == INSTR_ALU_XOR_I) 10379 imm = 1; 10380 10381 if (!imm) 10382 fprintf(f, 10383 "\t{\n" 10384 "\t\t.type = %s,\n" 10385 "\t\t.alu = {\n" 10386 "\t\t\t.dst = {\n" 10387 "\t\t\t\t.struct_id = %u,\n" 10388 "\t\t\t\t.n_bits = %u,\n" 10389 "\t\t\t\t.offset = %u,\n" 10390 "\t\t\t},\n" 10391 "\t\t\t.src = {\n" 10392 "\t\t\t\t.struct_id = %u,\n" 10393 "\t\t\t\t.n_bits = %u,\n" 10394 "\t\t\t\t.offset = %u,\n" 10395 "\t\t\t},\n" 10396 "\t\t},\n" 10397 "\t},\n", 10398 instr_type_to_name(instr), 10399 instr->alu.dst.struct_id, 10400 instr->alu.dst.n_bits, 10401 instr->alu.dst.offset, 10402 instr->alu.src.struct_id, 10403 instr->alu.src.n_bits, 10404 instr->alu.src.offset); 10405 else 10406 fprintf(f, 10407 "\t{\n" 10408 "\t\t.type = %s,\n" 10409 "\t\t.alu = {\n" 10410 "\t\t\t.dst = {\n" 10411 "\t\t\t\t.struct_id = %u,\n" 10412 "\t\t\t\t.n_bits = %u,\n" 10413 "\t\t\t\t.offset = %u,\n" 10414 "\t\t\t}\n," 10415 "\t\t\t.src_val = %" PRIu64 ",\n" 10416 "\t\t},\n" 10417 "\t},\n", 10418 instr_type_to_name(instr), 10419 instr->alu.dst.struct_id, 10420 instr->alu.dst.n_bits, 10421 instr->alu.dst.offset, 10422 instr->alu.src_val); 10423 } 10424 10425 static void 10426 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 10427 { 10428 int prefetch = 0, idx_imm = 0, src_imm = 0; 10429 10430 if (instr->type == INSTR_REGPREFETCH_RH || 10431 instr->type == INSTR_REGPREFETCH_RM || 10432 instr->type == INSTR_REGPREFETCH_RI) 10433 prefetch = 1; 10434 10435 /* index is the 3rd operand for the regrd instruction and the 2nd 10436 * operand for the regwr and regadd instructions. 10437 */ 10438 if (instr->type == INSTR_REGPREFETCH_RI || 10439 instr->type == INSTR_REGRD_HRI || 10440 instr->type == INSTR_REGRD_MRI || 10441 instr->type == INSTR_REGWR_RIH || 10442 instr->type == INSTR_REGWR_RIM || 10443 instr->type == INSTR_REGWR_RII || 10444 instr->type == INSTR_REGADD_RIH || 10445 instr->type == INSTR_REGADD_RIM || 10446 instr->type == INSTR_REGADD_RII) 10447 idx_imm = 1; 10448 10449 /* src is the 3rd operand for the regwr and regadd instructions. */ 10450 if (instr->type == INSTR_REGWR_RHI || 10451 instr->type == INSTR_REGWR_RMI || 10452 instr->type == INSTR_REGWR_RII || 10453 instr->type == INSTR_REGADD_RHI || 10454 instr->type == INSTR_REGADD_RMI || 10455 instr->type == INSTR_REGADD_RII) 10456 src_imm = 1; 10457 10458 /* instr.regarray.regarray_id. */ 10459 fprintf(f, 10460 "\t{\n" 10461 "\t\t.type = %s,\n" 10462 "\t\t.regarray = {\n" 10463 "\t\t\t.regarray_id = %u,\n", 10464 instr_type_to_name(instr), 10465 instr->regarray.regarray_id); 10466 10467 /* instr.regarray.idx / instr.regarray.idx_val. */ 10468 if (!idx_imm) 10469 fprintf(f, 10470 "\t\t\t\t.idx = {\n" 10471 "\t\t\t\t\t.struct_id = %u,\n" 10472 "\t\t\t\t\t.n_bits = %u,\n" 10473 "\t\t\t\t\t.offset = %u,\n" 10474 "\t\t\t\t},\n", 10475 instr->regarray.idx.struct_id, 10476 instr->regarray.idx.n_bits, 10477 instr->regarray.idx.offset); 10478 else 10479 fprintf(f, 10480 "\t\t\t\t.idx_val = %u,\n", 10481 instr->regarray.idx_val); 10482 10483 /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */ 10484 if (!prefetch) { 10485 if (!src_imm) 10486 fprintf(f, 10487 "\t\t\t\t.dstsrc = {\n" 10488 "\t\t\t\t\t.struct_id = %u,\n" 10489 "\t\t\t\t\t.n_bits = %u,\n" 10490 "\t\t\t\t\t.offset = %u,\n" 10491 "\t\t\t\t},\n", 10492 instr->regarray.dstsrc.struct_id, 10493 instr->regarray.dstsrc.n_bits, 10494 instr->regarray.dstsrc.offset); 10495 else 10496 fprintf(f, 10497 "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n", 10498 instr->regarray.dstsrc_val); 10499 } 10500 10501 /* instr.regarray and instr - closing curly braces. */ 10502 fprintf(f, 10503 "\t\t},\n" 10504 "\t},\n"); 10505 } 10506 10507 static void 10508 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 10509 { 10510 int prefetch = 0, idx_imm = 0, color_in_imm = 0; 10511 10512 if (instr->type == INSTR_METPREFETCH_H || 10513 instr->type == INSTR_METPREFETCH_M || 10514 instr->type == INSTR_METPREFETCH_I) 10515 prefetch = 1; 10516 10517 /* idx_imm. */ 10518 if (instr->type == INSTR_METPREFETCH_I || 10519 instr->type == INSTR_METER_IHM || 10520 instr->type == INSTR_METER_IHI || 10521 instr->type == INSTR_METER_IMM || 10522 instr->type == INSTR_METER_IMI) 10523 idx_imm = 1; 10524 10525 /* color_in_imm. */ 10526 if (instr->type == INSTR_METER_HHI || 10527 instr->type == INSTR_METER_HMI || 10528 instr->type == INSTR_METER_MHI || 10529 instr->type == INSTR_METER_MMI || 10530 instr->type == INSTR_METER_IHI || 10531 instr->type == INSTR_METER_IMI) 10532 color_in_imm = 1; 10533 10534 /* instr.meter.metarray_id. */ 10535 fprintf(f, 10536 "\t{\n" 10537 "\t\t.type = %s,\n" 10538 "\t\t.meter = {\n" 10539 "\t\t\t.metarray_id = %u,\n", 10540 instr_type_to_name(instr), 10541 instr->meter.metarray_id); 10542 10543 /* instr.meter.idx / instr.meter.idx_val. */ 10544 if (!idx_imm) 10545 fprintf(f, 10546 "\t\t\t.idx = {\n" 10547 "\t\t\t\t.struct_id = %u,\n" 10548 "\t\t\t\t.n_bits = %u,\n" 10549 "\t\t\t\t.offset = %u,\n" 10550 "\t\t\t},\n", 10551 instr->meter.idx.struct_id, 10552 instr->meter.idx.n_bits, 10553 instr->meter.idx.offset); 10554 else 10555 fprintf(f, 10556 "\t\t\t.idx_val = %u,\n", 10557 instr->meter.idx_val); 10558 10559 if (!prefetch) { 10560 /* instr.meter.length. */ 10561 fprintf(f, 10562 "\t\t\t.length = {\n" 10563 "\t\t\t\t.struct_id = %u,\n" 10564 "\t\t\t\t.n_bits = %u,\n" 10565 "\t\t\t\t.offset = %u,\n" 10566 "\t\t\t},\n", 10567 instr->meter.length.struct_id, 10568 instr->meter.length.n_bits, 10569 instr->meter.length.offset); 10570 10571 /* instr.meter.color_in / instr.meter.color_in_val. */ 10572 if (!color_in_imm) 10573 fprintf(f, 10574 "\t\t\t.color_in = {\n" 10575 "\t\t\t\t.struct_id = %u,\n" 10576 "\t\t\t\t.n_bits = %u,\n" 10577 "\t\t\t\t.offset = %u,\n" 10578 "\t\t\t},\n", 10579 instr->meter.color_in.struct_id, 10580 instr->meter.color_in.n_bits, 10581 instr->meter.color_in.offset); 10582 else 10583 fprintf(f, 10584 "\t\t\t.color_in_val = %u,\n", 10585 (uint32_t)instr->meter.color_in_val); 10586 10587 /* instr.meter.color_out. */ 10588 fprintf(f, 10589 "\t\t\t.color_out = {\n" 10590 "\t\t\t\t.struct_id = %u,\n" 10591 "\t\t\t\t.n_bits = %u,\n" 10592 "\t\t\t\t.offset = %u,\n" 10593 "\t\t\t},\n", 10594 instr->meter.color_out.struct_id, 10595 instr->meter.color_out.n_bits, 10596 instr->meter.color_out.offset); 10597 } 10598 10599 /* instr.meter and instr - closing curly braces. */ 10600 fprintf(f, 10601 "\t\t},\n" 10602 "\t},\n"); 10603 } 10604 10605 static void 10606 instr_table_export(struct instruction *instr, 10607 FILE *f) 10608 { 10609 fprintf(f, 10610 "\t{\n" 10611 "\t\t.type = %s,\n" 10612 "\t\t.table = {\n" 10613 "\t\t\t.table_id = %u,\n" 10614 "\t\t},\n" 10615 "\t},\n", 10616 instr_type_to_name(instr), 10617 instr->table.table_id); 10618 } 10619 10620 static void 10621 instr_learn_export(struct instruction *instr, FILE *f) 10622 { 10623 fprintf(f, 10624 "\t{\n" 10625 "\t\t.type = %s,\n" 10626 "\t\t.learn = {\n" 10627 "\t\t\t\t.action_id = %u,\n" 10628 "\t\t},\n" 10629 "\t},\n", 10630 instr_type_to_name(instr), 10631 instr->learn.action_id); 10632 } 10633 10634 static void 10635 instr_forget_export(struct instruction *instr, FILE *f) 10636 { 10637 fprintf(f, 10638 "\t{\n" 10639 "\t\t.type = %s,\n" 10640 "\t},\n", 10641 instr_type_to_name(instr)); 10642 } 10643 10644 static void 10645 instr_extern_export(struct instruction *instr, FILE *f) 10646 { 10647 if (instr->type == INSTR_EXTERN_OBJ) 10648 fprintf(f, 10649 "\t{\n" 10650 "\t\t.type = %s,\n" 10651 "\t\t.ext_obj = {\n" 10652 "\t\t\t.ext_obj_id = %u,\n" 10653 "\t\t\t.func_id = %u,\n" 10654 "\t\t},\n" 10655 "\t},\n", 10656 instr_type_to_name(instr), 10657 instr->ext_obj.ext_obj_id, 10658 instr->ext_obj.func_id); 10659 else 10660 fprintf(f, 10661 "\t{\n" 10662 "\t\t.type = %s,\n" 10663 "\t\t.ext_func = {\n" 10664 "\t\t\t.ext_func_id = %u,\n" 10665 "\t\t},\n" 10666 "\t},\n", 10667 instr_type_to_name(instr), 10668 instr->ext_func.ext_func_id); 10669 } 10670 10671 static void 10672 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused) 10673 { 10674 fprintf(f, 10675 "\t{\n" 10676 "\t\t.type = %s,\n" 10677 "\t\t.jmp = {\n" 10678 "\t\t\t.ip = NULL,\n", 10679 instr_type_to_name(instr)); 10680 10681 switch (instr->type) { 10682 case INSTR_JMP_VALID: 10683 case INSTR_JMP_INVALID: 10684 fprintf(f, 10685 "\t\t\t.header_id = %u,\n", 10686 instr->jmp.header_id); 10687 break; 10688 10689 case INSTR_JMP_ACTION_HIT: 10690 case INSTR_JMP_ACTION_MISS: 10691 fprintf(f, 10692 "\t\t\t.action_id = %u,\n", 10693 instr->jmp.action_id); 10694 break; 10695 10696 case INSTR_JMP_EQ: 10697 case INSTR_JMP_EQ_MH: 10698 case INSTR_JMP_EQ_HM: 10699 case INSTR_JMP_EQ_HH: 10700 case INSTR_JMP_NEQ: 10701 case INSTR_JMP_NEQ_MH: 10702 case INSTR_JMP_NEQ_HM: 10703 case INSTR_JMP_NEQ_HH: 10704 case INSTR_JMP_LT: 10705 case INSTR_JMP_LT_MH: 10706 case INSTR_JMP_LT_HM: 10707 case INSTR_JMP_LT_HH: 10708 case INSTR_JMP_GT: 10709 case INSTR_JMP_GT_MH: 10710 case INSTR_JMP_GT_HM: 10711 case INSTR_JMP_GT_HH: 10712 fprintf(f, 10713 "\t\t\t.a = {\n" 10714 "\t\t\t\t.struct_id = %u,\n" 10715 "\t\t\t\t.n_bits = %u,\n" 10716 "\t\t\t\t.offset = %u,\n" 10717 "\t\t\t},\n" 10718 "\t\t\t.b = {\n" 10719 "\t\t\t\t.struct_id = %u,\n" 10720 "\t\t\t\t.n_bits = %u,\n" 10721 "\t\t\t\t.offset = %u,\n" 10722 "\t\t\t},\n", 10723 instr->jmp.a.struct_id, 10724 instr->jmp.a.n_bits, 10725 instr->jmp.a.offset, 10726 instr->jmp.b.struct_id, 10727 instr->jmp.b.n_bits, 10728 instr->jmp.b.offset); 10729 break; 10730 10731 case INSTR_JMP_EQ_I: 10732 case INSTR_JMP_NEQ_I: 10733 case INSTR_JMP_LT_MI: 10734 case INSTR_JMP_LT_HI: 10735 case INSTR_JMP_GT_MI: 10736 case INSTR_JMP_GT_HI: 10737 fprintf(f, 10738 "\t\t\t.a = {\n" 10739 "\t\t\t\t.struct_id = %u,\n" 10740 "\t\t\t\t.n_bits = %u,\n" 10741 "\t\t\t\t.offset = %u,\n" 10742 "\t\t\t}\n," 10743 "\t\t\t.b_val = %" PRIu64 ",\n", 10744 instr->jmp.a.struct_id, 10745 instr->jmp.a.n_bits, 10746 instr->jmp.a.offset, 10747 instr->jmp.b_val); 10748 break; 10749 10750 default: 10751 break; 10752 } 10753 10754 fprintf(f, 10755 "\t\t},\n" 10756 "\t},\n"); 10757 } 10758 10759 static void 10760 instr_return_export(struct instruction *instr, 10761 FILE *f) 10762 { 10763 fprintf(f, 10764 "\t{\n" 10765 "\t\t.type = %s,\n", 10766 instr_type_to_name(instr)); 10767 10768 fprintf(f, 10769 "\t},\n"); 10770 } 10771 10772 static instruction_export_t export_table[] = { 10773 [INSTR_RX] = instr_io_export, 10774 10775 [INSTR_TX] = instr_io_export, 10776 [INSTR_TX_I] = instr_io_export, 10777 10778 [INSTR_HDR_EXTRACT] = instr_io_export, 10779 [INSTR_HDR_EXTRACT2] = instr_io_export, 10780 [INSTR_HDR_EXTRACT3] = instr_io_export, 10781 [INSTR_HDR_EXTRACT4] = instr_io_export, 10782 [INSTR_HDR_EXTRACT5] = instr_io_export, 10783 [INSTR_HDR_EXTRACT6] = instr_io_export, 10784 [INSTR_HDR_EXTRACT7] = instr_io_export, 10785 [INSTR_HDR_EXTRACT8] = instr_io_export, 10786 10787 [INSTR_HDR_EXTRACT_M] = instr_io_export, 10788 10789 [INSTR_HDR_LOOKAHEAD] = instr_io_export, 10790 10791 [INSTR_HDR_EMIT] = instr_io_export, 10792 [INSTR_HDR_EMIT_TX] = instr_io_export, 10793 [INSTR_HDR_EMIT2_TX] = instr_io_export, 10794 [INSTR_HDR_EMIT3_TX] = instr_io_export, 10795 [INSTR_HDR_EMIT4_TX] = instr_io_export, 10796 [INSTR_HDR_EMIT5_TX] = instr_io_export, 10797 [INSTR_HDR_EMIT6_TX] = instr_io_export, 10798 [INSTR_HDR_EMIT7_TX] = instr_io_export, 10799 [INSTR_HDR_EMIT8_TX] = instr_io_export, 10800 10801 [INSTR_HDR_VALIDATE] = instr_hdr_validate_export, 10802 [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export, 10803 10804 [INSTR_MOV] = instr_mov_export, 10805 [INSTR_MOV_MH] = instr_mov_export, 10806 [INSTR_MOV_HM] = instr_mov_export, 10807 [INSTR_MOV_HH] = instr_mov_export, 10808 [INSTR_MOV_I] = instr_mov_export, 10809 10810 [INSTR_DMA_HT] = instr_dma_ht_export, 10811 [INSTR_DMA_HT2] = instr_dma_ht_export, 10812 [INSTR_DMA_HT3] = instr_dma_ht_export, 10813 [INSTR_DMA_HT4] = instr_dma_ht_export, 10814 [INSTR_DMA_HT5] = instr_dma_ht_export, 10815 [INSTR_DMA_HT6] = instr_dma_ht_export, 10816 [INSTR_DMA_HT7] = instr_dma_ht_export, 10817 [INSTR_DMA_HT8] = instr_dma_ht_export, 10818 10819 [INSTR_ALU_ADD] = instr_alu_export, 10820 [INSTR_ALU_ADD_MH] = instr_alu_export, 10821 [INSTR_ALU_ADD_HM] = instr_alu_export, 10822 [INSTR_ALU_ADD_HH] = instr_alu_export, 10823 [INSTR_ALU_ADD_MI] = instr_alu_export, 10824 [INSTR_ALU_ADD_HI] = instr_alu_export, 10825 10826 [INSTR_ALU_SUB] = instr_alu_export, 10827 [INSTR_ALU_SUB_MH] = instr_alu_export, 10828 [INSTR_ALU_SUB_HM] = instr_alu_export, 10829 [INSTR_ALU_SUB_HH] = instr_alu_export, 10830 [INSTR_ALU_SUB_MI] = instr_alu_export, 10831 [INSTR_ALU_SUB_HI] = instr_alu_export, 10832 10833 [INSTR_ALU_CKADD_FIELD] = instr_alu_export, 10834 [INSTR_ALU_CKADD_STRUCT] = instr_alu_export, 10835 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export, 10836 [INSTR_ALU_CKSUB_FIELD] = instr_alu_export, 10837 10838 [INSTR_ALU_AND] = instr_alu_export, 10839 [INSTR_ALU_AND_MH] = instr_alu_export, 10840 [INSTR_ALU_AND_HM] = instr_alu_export, 10841 [INSTR_ALU_AND_HH] = instr_alu_export, 10842 [INSTR_ALU_AND_I] = instr_alu_export, 10843 10844 [INSTR_ALU_OR] = instr_alu_export, 10845 [INSTR_ALU_OR_MH] = instr_alu_export, 10846 [INSTR_ALU_OR_HM] = instr_alu_export, 10847 [INSTR_ALU_OR_HH] = instr_alu_export, 10848 [INSTR_ALU_OR_I] = instr_alu_export, 10849 10850 [INSTR_ALU_XOR] = instr_alu_export, 10851 [INSTR_ALU_XOR_MH] = instr_alu_export, 10852 [INSTR_ALU_XOR_HM] = instr_alu_export, 10853 [INSTR_ALU_XOR_HH] = instr_alu_export, 10854 [INSTR_ALU_XOR_I] = instr_alu_export, 10855 10856 [INSTR_ALU_SHL] = instr_alu_export, 10857 [INSTR_ALU_SHL_MH] = instr_alu_export, 10858 [INSTR_ALU_SHL_HM] = instr_alu_export, 10859 [INSTR_ALU_SHL_HH] = instr_alu_export, 10860 [INSTR_ALU_SHL_MI] = instr_alu_export, 10861 [INSTR_ALU_SHL_HI] = instr_alu_export, 10862 10863 [INSTR_ALU_SHR] = instr_alu_export, 10864 [INSTR_ALU_SHR_MH] = instr_alu_export, 10865 [INSTR_ALU_SHR_HM] = instr_alu_export, 10866 [INSTR_ALU_SHR_HH] = instr_alu_export, 10867 [INSTR_ALU_SHR_MI] = instr_alu_export, 10868 [INSTR_ALU_SHR_HI] = instr_alu_export, 10869 10870 [INSTR_REGPREFETCH_RH] = instr_reg_export, 10871 [INSTR_REGPREFETCH_RM] = instr_reg_export, 10872 [INSTR_REGPREFETCH_RI] = instr_reg_export, 10873 10874 [INSTR_REGRD_HRH] = instr_reg_export, 10875 [INSTR_REGRD_HRM] = instr_reg_export, 10876 [INSTR_REGRD_MRH] = instr_reg_export, 10877 [INSTR_REGRD_MRM] = instr_reg_export, 10878 [INSTR_REGRD_HRI] = instr_reg_export, 10879 [INSTR_REGRD_MRI] = instr_reg_export, 10880 10881 [INSTR_REGWR_RHH] = instr_reg_export, 10882 [INSTR_REGWR_RHM] = instr_reg_export, 10883 [INSTR_REGWR_RMH] = instr_reg_export, 10884 [INSTR_REGWR_RMM] = instr_reg_export, 10885 [INSTR_REGWR_RHI] = instr_reg_export, 10886 [INSTR_REGWR_RMI] = instr_reg_export, 10887 [INSTR_REGWR_RIH] = instr_reg_export, 10888 [INSTR_REGWR_RIM] = instr_reg_export, 10889 [INSTR_REGWR_RII] = instr_reg_export, 10890 10891 [INSTR_REGADD_RHH] = instr_reg_export, 10892 [INSTR_REGADD_RHM] = instr_reg_export, 10893 [INSTR_REGADD_RMH] = instr_reg_export, 10894 [INSTR_REGADD_RMM] = instr_reg_export, 10895 [INSTR_REGADD_RHI] = instr_reg_export, 10896 [INSTR_REGADD_RMI] = instr_reg_export, 10897 [INSTR_REGADD_RIH] = instr_reg_export, 10898 [INSTR_REGADD_RIM] = instr_reg_export, 10899 [INSTR_REGADD_RII] = instr_reg_export, 10900 10901 [INSTR_METPREFETCH_H] = instr_meter_export, 10902 [INSTR_METPREFETCH_M] = instr_meter_export, 10903 [INSTR_METPREFETCH_I] = instr_meter_export, 10904 10905 [INSTR_METER_HHM] = instr_meter_export, 10906 [INSTR_METER_HHI] = instr_meter_export, 10907 [INSTR_METER_HMM] = instr_meter_export, 10908 [INSTR_METER_HMI] = instr_meter_export, 10909 [INSTR_METER_MHM] = instr_meter_export, 10910 [INSTR_METER_MHI] = instr_meter_export, 10911 [INSTR_METER_MMM] = instr_meter_export, 10912 [INSTR_METER_MMI] = instr_meter_export, 10913 [INSTR_METER_IHM] = instr_meter_export, 10914 [INSTR_METER_IHI] = instr_meter_export, 10915 [INSTR_METER_IMM] = instr_meter_export, 10916 [INSTR_METER_IMI] = instr_meter_export, 10917 10918 [INSTR_TABLE] = instr_table_export, 10919 [INSTR_TABLE_AF] = instr_table_export, 10920 [INSTR_SELECTOR] = instr_table_export, 10921 [INSTR_LEARNER] = instr_table_export, 10922 [INSTR_LEARNER_AF] = instr_table_export, 10923 10924 [INSTR_LEARNER_LEARN] = instr_learn_export, 10925 [INSTR_LEARNER_FORGET] = instr_forget_export, 10926 10927 [INSTR_EXTERN_OBJ] = instr_extern_export, 10928 [INSTR_EXTERN_FUNC] = instr_extern_export, 10929 10930 [INSTR_JMP] = instr_jmp_export, 10931 [INSTR_JMP_VALID] = instr_jmp_export, 10932 [INSTR_JMP_INVALID] = instr_jmp_export, 10933 [INSTR_JMP_HIT] = instr_jmp_export, 10934 [INSTR_JMP_MISS] = instr_jmp_export, 10935 [INSTR_JMP_ACTION_HIT] = instr_jmp_export, 10936 [INSTR_JMP_ACTION_MISS] = instr_jmp_export, 10937 10938 [INSTR_JMP_EQ] = instr_jmp_export, 10939 [INSTR_JMP_EQ_MH] = instr_jmp_export, 10940 [INSTR_JMP_EQ_HM] = instr_jmp_export, 10941 [INSTR_JMP_EQ_HH] = instr_jmp_export, 10942 [INSTR_JMP_EQ_I] = instr_jmp_export, 10943 10944 [INSTR_JMP_NEQ] = instr_jmp_export, 10945 [INSTR_JMP_NEQ_MH] = instr_jmp_export, 10946 [INSTR_JMP_NEQ_HM] = instr_jmp_export, 10947 [INSTR_JMP_NEQ_HH] = instr_jmp_export, 10948 [INSTR_JMP_NEQ_I] = instr_jmp_export, 10949 10950 [INSTR_JMP_LT] = instr_jmp_export, 10951 [INSTR_JMP_LT_MH] = instr_jmp_export, 10952 [INSTR_JMP_LT_HM] = instr_jmp_export, 10953 [INSTR_JMP_LT_HH] = instr_jmp_export, 10954 [INSTR_JMP_LT_MI] = instr_jmp_export, 10955 [INSTR_JMP_LT_HI] = instr_jmp_export, 10956 10957 [INSTR_JMP_GT] = instr_jmp_export, 10958 [INSTR_JMP_GT_MH] = instr_jmp_export, 10959 [INSTR_JMP_GT_HM] = instr_jmp_export, 10960 [INSTR_JMP_GT_HH] = instr_jmp_export, 10961 [INSTR_JMP_GT_MI] = instr_jmp_export, 10962 [INSTR_JMP_GT_HI] = instr_jmp_export, 10963 10964 [INSTR_RETURN] = instr_return_export, 10965 }; 10966 10967 static void 10968 action_data_codegen(struct action *a, FILE *f) 10969 { 10970 uint32_t i; 10971 10972 fprintf(f, 10973 "static const struct instruction action_%s_instructions[] = {\n", 10974 a->name); 10975 10976 for (i = 0; i < a->n_instructions; i++) { 10977 struct instruction *instr = &a->instructions[i]; 10978 instruction_export_t func = export_table[instr->type]; 10979 10980 func(instr, f); 10981 } 10982 10983 fprintf(f, "};\n"); 10984 } 10985 10986 static const char * 10987 instr_type_to_func(struct instruction *instr) 10988 { 10989 switch (instr->type) { 10990 case INSTR_RX: return NULL; 10991 10992 case INSTR_TX: return "__instr_tx_exec"; 10993 case INSTR_TX_I: return "__instr_tx_i_exec"; 10994 10995 case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; 10996 case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; 10997 case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec"; 10998 case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec"; 10999 case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec"; 11000 case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec"; 11001 case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec"; 11002 case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec"; 11003 11004 case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec"; 11005 11006 case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec"; 11007 11008 case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec"; 11009 case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec"; 11010 case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec"; 11011 case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec"; 11012 case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec"; 11013 case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec"; 11014 case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec"; 11015 case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec"; 11016 case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec"; 11017 11018 case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec"; 11019 case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec"; 11020 11021 case INSTR_MOV: return "__instr_mov_exec"; 11022 case INSTR_MOV_MH: return "__instr_mov_mh_exec"; 11023 case INSTR_MOV_HM: return "__instr_mov_hm_exec"; 11024 case INSTR_MOV_HH: return "__instr_mov_hh_exec"; 11025 case INSTR_MOV_I: return "__instr_mov_i_exec"; 11026 11027 case INSTR_DMA_HT: return "__instr_dma_ht_exec"; 11028 case INSTR_DMA_HT2: return "__instr_dma_ht2_exec"; 11029 case INSTR_DMA_HT3: return "__instr_dma_ht3_exec"; 11030 case INSTR_DMA_HT4: return "__instr_dma_ht4_exec"; 11031 case INSTR_DMA_HT5: return "__instr_dma_ht5_exec"; 11032 case INSTR_DMA_HT6: return "__instr_dma_ht6_exec"; 11033 case INSTR_DMA_HT7: return "__instr_dma_ht7_exec"; 11034 case INSTR_DMA_HT8: return "__instr_dma_ht8_exec"; 11035 11036 case INSTR_ALU_ADD: return "__instr_alu_add_exec"; 11037 case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec"; 11038 case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec"; 11039 case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec"; 11040 case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec"; 11041 case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec"; 11042 11043 case INSTR_ALU_SUB: return "__instr_alu_sub_exec"; 11044 case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec"; 11045 case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec"; 11046 case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec"; 11047 case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec"; 11048 case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec"; 11049 11050 case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec"; 11051 case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec"; 11052 case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec"; 11053 case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec"; 11054 11055 case INSTR_ALU_AND: return "__instr_alu_and_exec"; 11056 case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec"; 11057 case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec"; 11058 case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec"; 11059 case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec"; 11060 11061 case INSTR_ALU_OR: return "__instr_alu_or_exec"; 11062 case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec"; 11063 case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec"; 11064 case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec"; 11065 case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec"; 11066 11067 case INSTR_ALU_XOR: return "__instr_alu_xor_exec"; 11068 case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec"; 11069 case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec"; 11070 case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec"; 11071 case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec"; 11072 11073 case INSTR_ALU_SHL: return "__instr_alu_shl_exec"; 11074 case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec"; 11075 case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec"; 11076 case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec"; 11077 case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec"; 11078 case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec"; 11079 11080 case INSTR_ALU_SHR: return "__instr_alu_shr_exec"; 11081 case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec"; 11082 case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec"; 11083 case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec"; 11084 case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec"; 11085 case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec"; 11086 11087 case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec"; 11088 case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec"; 11089 case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec"; 11090 11091 case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec"; 11092 case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec"; 11093 case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec"; 11094 case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec"; 11095 case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec"; 11096 case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec"; 11097 11098 case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec"; 11099 case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec"; 11100 case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec"; 11101 case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec"; 11102 case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec"; 11103 case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec"; 11104 case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec"; 11105 case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec"; 11106 case INSTR_REGWR_RII: return "__instr_regwr_rii_exec"; 11107 11108 case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec"; 11109 case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec"; 11110 case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec"; 11111 case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec"; 11112 case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec"; 11113 case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec"; 11114 case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec"; 11115 case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec"; 11116 case INSTR_REGADD_RII: return "__instr_regadd_rii_exec"; 11117 11118 case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec"; 11119 case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec"; 11120 case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec"; 11121 11122 case INSTR_METER_HHM: return "__instr_meter_hhm_exec"; 11123 case INSTR_METER_HHI: return "__instr_meter_hhi_exec"; 11124 case INSTR_METER_HMM: return "__instr_meter_hmm_exec"; 11125 case INSTR_METER_HMI: return "__instr_meter_hmi_exec"; 11126 case INSTR_METER_MHM: return "__instr_meter_mhm_exec"; 11127 case INSTR_METER_MHI: return "__instr_meter_mhi_exec"; 11128 case INSTR_METER_MMM: return "__instr_meter_mmm_exec"; 11129 case INSTR_METER_MMI: return "__instr_meter_mmi_exec"; 11130 case INSTR_METER_IHM: return "__instr_meter_ihm_exec"; 11131 case INSTR_METER_IHI: return "__instr_meter_ihi_exec"; 11132 case INSTR_METER_IMM: return "__instr_meter_imm_exec"; 11133 case INSTR_METER_IMI: return "__instr_meter_imi_exec"; 11134 11135 case INSTR_TABLE: return NULL; 11136 case INSTR_TABLE_AF: return NULL; 11137 case INSTR_SELECTOR: return NULL; 11138 case INSTR_LEARNER: return NULL; 11139 case INSTR_LEARNER_AF: return NULL; 11140 11141 case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; 11142 case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; 11143 11144 case INSTR_EXTERN_OBJ: return NULL; 11145 case INSTR_EXTERN_FUNC: return NULL; 11146 11147 case INSTR_JMP: return NULL; 11148 case INSTR_JMP_VALID: return NULL; 11149 case INSTR_JMP_INVALID: return NULL; 11150 case INSTR_JMP_HIT: return NULL; 11151 case INSTR_JMP_MISS: return NULL; 11152 case INSTR_JMP_ACTION_HIT: return NULL; 11153 case INSTR_JMP_ACTION_MISS: return NULL; 11154 case INSTR_JMP_EQ: return NULL; 11155 case INSTR_JMP_EQ_MH: return NULL; 11156 case INSTR_JMP_EQ_HM: return NULL; 11157 case INSTR_JMP_EQ_HH: return NULL; 11158 case INSTR_JMP_EQ_I: return NULL; 11159 case INSTR_JMP_NEQ: return NULL; 11160 case INSTR_JMP_NEQ_MH: return NULL; 11161 case INSTR_JMP_NEQ_HM: return NULL; 11162 case INSTR_JMP_NEQ_HH: return NULL; 11163 case INSTR_JMP_NEQ_I: return NULL; 11164 case INSTR_JMP_LT: return NULL; 11165 case INSTR_JMP_LT_MH: return NULL; 11166 case INSTR_JMP_LT_HM: return NULL; 11167 case INSTR_JMP_LT_HH: return NULL; 11168 case INSTR_JMP_LT_MI: return NULL; 11169 case INSTR_JMP_LT_HI: return NULL; 11170 case INSTR_JMP_GT: return NULL; 11171 case INSTR_JMP_GT_MH: return NULL; 11172 case INSTR_JMP_GT_HM: return NULL; 11173 case INSTR_JMP_GT_HH: return NULL; 11174 case INSTR_JMP_GT_MI: return NULL; 11175 case INSTR_JMP_GT_HI: return NULL; 11176 11177 case INSTR_RETURN: return NULL; 11178 11179 default: return NULL; 11180 } 11181 } 11182 11183 static void 11184 action_instr_does_tx_codegen(struct action *a, 11185 uint32_t instr_pos, 11186 struct instruction *instr, 11187 FILE *f) 11188 { 11189 fprintf(f, 11190 "%s(p, t, &action_%s_instructions[%u]);\n" 11191 "\tthread_ip_reset(p, t);\n" 11192 "\tinstr_rx_exec(p);\n" 11193 "\treturn;\n", 11194 instr_type_to_func(instr), 11195 a->name, 11196 instr_pos); 11197 } 11198 11199 static void 11200 action_instr_extern_obj_codegen(struct action *a, 11201 uint32_t instr_pos, 11202 FILE *f) 11203 { 11204 fprintf(f, 11205 "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n", 11206 a->name, 11207 instr_pos); 11208 } 11209 11210 static void 11211 action_instr_extern_func_codegen(struct action *a, 11212 uint32_t instr_pos, 11213 FILE *f) 11214 { 11215 fprintf(f, 11216 "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n", 11217 a->name, 11218 instr_pos); 11219 } 11220 11221 static void 11222 action_instr_jmp_codegen(struct action *a, 11223 uint32_t instr_pos, 11224 struct instruction *instr, 11225 struct instruction_data *data, 11226 FILE *f) 11227 { 11228 switch (instr->type) { 11229 case INSTR_JMP: 11230 fprintf(f, 11231 "goto %s;\n", 11232 data->jmp_label); 11233 return; 11234 11235 case INSTR_JMP_VALID: 11236 fprintf(f, 11237 "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 11238 "\t\tgoto %s;\n", 11239 a->name, 11240 instr_pos, 11241 data->jmp_label); 11242 return; 11243 11244 case INSTR_JMP_INVALID: 11245 fprintf(f, 11246 "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 11247 "\t\tgoto %s;\n", 11248 a->name, 11249 instr_pos, 11250 data->jmp_label); 11251 return; 11252 11253 case INSTR_JMP_HIT: 11254 fprintf(f, 11255 "if (t->hit)\n" 11256 "\t\tgoto %s;\n", 11257 data->jmp_label); 11258 return; 11259 11260 case INSTR_JMP_MISS: 11261 fprintf(f, 11262 "if (!t->hit)\n" 11263 "\t\tgoto %s;\n", 11264 data->jmp_label); 11265 return; 11266 11267 case INSTR_JMP_ACTION_HIT: 11268 fprintf(f, 11269 "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n" 11270 "\t\tgoto %s;\n", 11271 a->name, 11272 instr_pos, 11273 data->jmp_label); 11274 return; 11275 11276 case INSTR_JMP_ACTION_MISS: 11277 fprintf(f, 11278 "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n" 11279 "\t\tgoto %s;\n", 11280 a->name, 11281 instr_pos, 11282 data->jmp_label); 11283 return; 11284 11285 case INSTR_JMP_EQ: 11286 fprintf(f, 11287 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11288 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11289 "\t\tgoto %s;\n", 11290 a->name, 11291 instr_pos, 11292 a->name, 11293 instr_pos, 11294 data->jmp_label); 11295 return; 11296 11297 case INSTR_JMP_EQ_MH: 11298 fprintf(f, 11299 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11300 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11301 "\t\tgoto %s;\n", 11302 a->name, 11303 instr_pos, 11304 a->name, 11305 instr_pos, 11306 data->jmp_label); 11307 return; 11308 11309 case INSTR_JMP_EQ_HM: 11310 fprintf(f, 11311 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 11312 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11313 "\t\tgoto %s;\n", 11314 a->name, 11315 instr_pos, 11316 a->name, 11317 instr_pos, 11318 data->jmp_label); 11319 return; 11320 11321 case INSTR_JMP_EQ_HH: 11322 fprintf(f, 11323 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 11324 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11325 "\t\tgoto %s;\n", 11326 a->name, 11327 instr_pos, 11328 a->name, 11329 instr_pos, 11330 data->jmp_label); 11331 return; 11332 11333 case INSTR_JMP_EQ_I: 11334 fprintf(f, 11335 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11336 "action_%s_instructions[%u].jmp.b_val)\n" 11337 "\t\tgoto %s;\n", 11338 a->name, 11339 instr_pos, 11340 a->name, 11341 instr_pos, 11342 data->jmp_label); 11343 return; 11344 11345 case INSTR_JMP_NEQ: 11346 fprintf(f, 11347 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11348 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11349 "\t\tgoto %s;\n", 11350 a->name, 11351 instr_pos, 11352 a->name, 11353 instr_pos, 11354 data->jmp_label); 11355 return; 11356 11357 case INSTR_JMP_NEQ_MH: 11358 fprintf(f, 11359 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11360 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11361 "\t\tgoto %s;\n", 11362 a->name, 11363 instr_pos, 11364 a->name, 11365 instr_pos, 11366 data->jmp_label); 11367 return; 11368 11369 case INSTR_JMP_NEQ_HM: 11370 fprintf(f, 11371 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 11372 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11373 "\t\tgoto %s;\n", 11374 a->name, 11375 instr_pos, 11376 a->name, 11377 instr_pos, 11378 data->jmp_label); 11379 return; 11380 11381 case INSTR_JMP_NEQ_HH: 11382 fprintf(f, 11383 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 11384 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11385 "\t\tgoto %s;\n", 11386 a->name, 11387 instr_pos, 11388 a->name, 11389 instr_pos, 11390 data->jmp_label); 11391 return; 11392 11393 case INSTR_JMP_NEQ_I: 11394 fprintf(f, 11395 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11396 "action_%s_instructions[%u].jmp.b_val)\n" 11397 "\t\tgoto %s;\n", 11398 a->name, 11399 instr_pos, 11400 a->name, 11401 instr_pos, 11402 data->jmp_label); 11403 return; 11404 11405 case INSTR_JMP_LT: 11406 fprintf(f, 11407 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11408 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11409 "\t\tgoto %s;\n", 11410 a->name, 11411 instr_pos, 11412 a->name, 11413 instr_pos, 11414 data->jmp_label); 11415 return; 11416 11417 case INSTR_JMP_LT_MH: 11418 fprintf(f, 11419 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11420 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11421 "\t\tgoto %s;\n", 11422 a->name, 11423 instr_pos, 11424 a->name, 11425 instr_pos, 11426 data->jmp_label); 11427 return; 11428 11429 case INSTR_JMP_LT_HM: 11430 fprintf(f, 11431 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11432 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11433 "\t\tgoto %s;\n", 11434 a->name, 11435 instr_pos, 11436 a->name, 11437 instr_pos, 11438 data->jmp_label); 11439 return; 11440 11441 case INSTR_JMP_LT_HH: 11442 fprintf(f, 11443 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11444 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11445 "\t\tgoto %s;\n", 11446 a->name, 11447 instr_pos, 11448 a->name, 11449 instr_pos, 11450 data->jmp_label); 11451 return; 11452 11453 case INSTR_JMP_LT_MI: 11454 fprintf(f, 11455 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11456 "action_%s_instructions[%u].jmp.b_val)\n" 11457 "\t\tgoto %s;\n", 11458 a->name, 11459 instr_pos, 11460 a->name, 11461 instr_pos, 11462 data->jmp_label); 11463 return; 11464 11465 case INSTR_JMP_LT_HI: 11466 fprintf(f, 11467 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11468 "action_%s_instructions[%u].jmp.b_val)\n" 11469 "\t\tgoto %s;\n", 11470 a->name, 11471 instr_pos, 11472 a->name, 11473 instr_pos, 11474 data->jmp_label); 11475 return; 11476 11477 case INSTR_JMP_GT: 11478 fprintf(f, 11479 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11480 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11481 "\t\tgoto %s;\n", 11482 a->name, 11483 instr_pos, 11484 a->name, 11485 instr_pos, 11486 data->jmp_label); 11487 return; 11488 11489 case INSTR_JMP_GT_MH: 11490 fprintf(f, 11491 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11492 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11493 "\t\tgoto %s;\n", 11494 a->name, 11495 instr_pos, 11496 a->name, 11497 instr_pos, 11498 data->jmp_label); 11499 return; 11500 11501 case INSTR_JMP_GT_HM: 11502 fprintf(f, 11503 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11504 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11505 "\t\tgoto %s;\n", 11506 a->name, 11507 instr_pos, 11508 a->name, 11509 instr_pos, 11510 data->jmp_label); 11511 return; 11512 11513 case INSTR_JMP_GT_HH: 11514 fprintf(f, 11515 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11516 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11517 "\t\tgoto %s;\n", 11518 a->name, 11519 instr_pos, 11520 a->name, 11521 instr_pos, 11522 data->jmp_label); 11523 return; 11524 11525 case INSTR_JMP_GT_MI: 11526 fprintf(f, 11527 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11528 "action_%s_instructions[%u].jmp.b_val)\n" 11529 "\t\tgoto %s;\n", 11530 a->name, 11531 instr_pos, 11532 a->name, 11533 instr_pos, 11534 data->jmp_label); 11535 return; 11536 11537 case INSTR_JMP_GT_HI: 11538 fprintf(f, 11539 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11540 "action_%s_instructions[%u].jmp.b_val)\n" 11541 "\t\tgoto %s;\n", 11542 a->name, 11543 instr_pos, 11544 a->name, 11545 instr_pos, 11546 data->jmp_label); 11547 return; 11548 11549 default: 11550 return; 11551 } 11552 } 11553 11554 static void 11555 action_instr_return_codegen(FILE *f) 11556 { 11557 fprintf(f, 11558 "return;\n"); 11559 } 11560 11561 static void 11562 action_instr_codegen(struct action *a, FILE *f) 11563 { 11564 uint32_t i; 11565 11566 fprintf(f, 11567 "void\n" 11568 "action_%s_run(struct rte_swx_pipeline *p)\n" 11569 "{\n" 11570 "\tstruct thread *t = &p->threads[p->thread_id];\n" 11571 "\n", 11572 a->name); 11573 11574 for (i = 0; i < a->n_instructions; i++) { 11575 struct instruction *instr = &a->instructions[i]; 11576 struct instruction_data *data = &a->instruction_data[i]; 11577 11578 /* Label, if present. */ 11579 if (data->label[0]) 11580 fprintf(f, "\n%s : ", data->label); 11581 else 11582 fprintf(f, "\n\t"); 11583 11584 /* TX instruction type. */ 11585 if (instruction_does_tx(instr)) { 11586 action_instr_does_tx_codegen(a, i, instr, f); 11587 continue; 11588 } 11589 11590 /* Extern object/function instruction type. */ 11591 if (instr->type == INSTR_EXTERN_OBJ) { 11592 action_instr_extern_obj_codegen(a, i, f); 11593 continue; 11594 } 11595 11596 if (instr->type == INSTR_EXTERN_FUNC) { 11597 action_instr_extern_func_codegen(a, i, f); 11598 continue; 11599 } 11600 11601 /* Jump instruction type. */ 11602 if (instruction_is_jmp(instr)) { 11603 action_instr_jmp_codegen(a, i, instr, data, f); 11604 continue; 11605 } 11606 11607 /* Return instruction type. */ 11608 if (instr->type == INSTR_RETURN) { 11609 action_instr_return_codegen(f); 11610 continue; 11611 } 11612 11613 /* Any other instruction type. */ 11614 fprintf(f, 11615 "%s(p, t, &action_%s_instructions[%u]);\n", 11616 instr_type_to_func(instr), 11617 a->name, 11618 i); 11619 } 11620 11621 fprintf(f, "}\n\n"); 11622 } 11623 11624 struct instruction_group { 11625 TAILQ_ENTRY(instruction_group) node; 11626 11627 uint32_t group_id; 11628 11629 uint32_t first_instr_id; 11630 11631 uint32_t last_instr_id; 11632 11633 instr_exec_t func; 11634 }; 11635 11636 TAILQ_HEAD(instruction_group_list, instruction_group); 11637 11638 static struct instruction_group * 11639 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id) 11640 { 11641 struct instruction_group *g; 11642 11643 TAILQ_FOREACH(g, igl, node) 11644 if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id)) 11645 return g; 11646 11647 return NULL; 11648 } 11649 11650 static void 11651 instruction_group_list_free(struct instruction_group_list *igl) 11652 { 11653 if (!igl) 11654 return; 11655 11656 for ( ; ; ) { 11657 struct instruction_group *g; 11658 11659 g = TAILQ_FIRST(igl); 11660 if (!g) 11661 break; 11662 11663 TAILQ_REMOVE(igl, g, node); 11664 free(g); 11665 } 11666 11667 free(igl); 11668 } 11669 11670 static struct instruction_group_list * 11671 instruction_group_list_create(struct rte_swx_pipeline *p) 11672 { 11673 struct instruction_group_list *igl = NULL; 11674 struct instruction_group *g = NULL; 11675 uint32_t n_groups = 0, i; 11676 11677 if (!p || !p->instructions || !p->instruction_data || !p->n_instructions) 11678 goto error; 11679 11680 /* List init. */ 11681 igl = calloc(1, sizeof(struct instruction_group_list)); 11682 if (!igl) 11683 goto error; 11684 11685 TAILQ_INIT(igl); 11686 11687 /* Allocate the first group. */ 11688 g = calloc(1, sizeof(struct instruction_group)); 11689 if (!g) 11690 goto error; 11691 11692 /* Iteration 1: Separate the instructions into groups based on the thread yield 11693 * instructions. Do not worry about the jump instructions at this point. 11694 */ 11695 for (i = 0; i < p->n_instructions; i++) { 11696 struct instruction *instr = &p->instructions[i]; 11697 11698 /* Check for thread yield instructions. */ 11699 if (!instruction_does_thread_yield(instr)) 11700 continue; 11701 11702 /* If the current group contains at least one instruction, then finalize it (with 11703 * the previous instruction), add it to the list and allocate a new group (that 11704 * starts with the current instruction). 11705 */ 11706 if (i - g->first_instr_id) { 11707 /* Finalize the group. */ 11708 g->last_instr_id = i - 1; 11709 11710 /* Add the group to the list. Advance the number of groups. */ 11711 TAILQ_INSERT_TAIL(igl, g, node); 11712 n_groups++; 11713 11714 /* Allocate a new group. */ 11715 g = calloc(1, sizeof(struct instruction_group)); 11716 if (!g) 11717 goto error; 11718 11719 /* Initialize the new group. */ 11720 g->group_id = n_groups; 11721 g->first_instr_id = i; 11722 } 11723 11724 /* Finalize the current group (with the current instruction, therefore this group 11725 * contains just the current thread yield instruction), add it to the list and 11726 * allocate a new group (that starts with the next instruction). 11727 */ 11728 11729 /* Finalize the group. */ 11730 g->last_instr_id = i; 11731 11732 /* Add the group to the list. Advance the number of groups. */ 11733 TAILQ_INSERT_TAIL(igl, g, node); 11734 n_groups++; 11735 11736 /* Allocate a new group. */ 11737 g = calloc(1, sizeof(struct instruction_group)); 11738 if (!g) 11739 goto error; 11740 11741 /* Initialize the new group. */ 11742 g->group_id = n_groups; 11743 g->first_instr_id = i + 1; 11744 } 11745 11746 /* Handle the last group. */ 11747 if (i - g->first_instr_id) { 11748 /* Finalize the group. */ 11749 g->last_instr_id = i - 1; 11750 11751 /* Add the group to the list. Advance the number of groups. */ 11752 TAILQ_INSERT_TAIL(igl, g, node); 11753 n_groups++; 11754 } else 11755 free(g); 11756 11757 g = NULL; 11758 11759 /* Iteration 2: Handle jumps. If the current group contains an instruction which represents 11760 * the destination of a jump instruction located in a different group ("far jump"), then the 11761 * current group has to be split, so that the instruction representing the far jump 11762 * destination is at the start of its group. 11763 */ 11764 for ( ; ; ) { 11765 int is_modified = 0; 11766 11767 for (i = 0; i < p->n_instructions; i++) { 11768 struct instruction_data *data = &p->instruction_data[i]; 11769 struct instruction_group *g; 11770 uint32_t j; 11771 11772 /* Continue when the current instruction is not a jump destination. */ 11773 if (!data->n_users) 11774 continue; 11775 11776 g = instruction_group_list_group_find(igl, i); 11777 if (!g) 11778 goto error; 11779 11780 /* Find out all the jump instructions with this destination. */ 11781 for (j = 0; j < p->n_instructions; j++) { 11782 struct instruction *jmp_instr = &p->instructions[j]; 11783 struct instruction_data *jmp_data = &p->instruction_data[j]; 11784 struct instruction_group *jmp_g, *new_g; 11785 11786 /* Continue when not a jump instruction. Even when jump instruction, 11787 * continue when the jump destination is not this instruction. 11788 */ 11789 if (!instruction_is_jmp(jmp_instr) || 11790 strcmp(jmp_data->jmp_label, data->label)) 11791 continue; 11792 11793 jmp_g = instruction_group_list_group_find(igl, j); 11794 if (!jmp_g) 11795 goto error; 11796 11797 /* Continue when both the jump instruction and the jump destination 11798 * instruction are in the same group. Even when in different groups, 11799 * still continue if the jump destination instruction is already the 11800 * first instruction of its group. 11801 */ 11802 if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i)) 11803 continue; 11804 11805 /* Split the group of the current jump destination instruction to 11806 * make this instruction the first instruction of a new group. 11807 */ 11808 new_g = calloc(1, sizeof(struct instruction_group)); 11809 if (!new_g) 11810 goto error; 11811 11812 new_g->group_id = n_groups; 11813 new_g->first_instr_id = i; 11814 new_g->last_instr_id = g->last_instr_id; 11815 11816 g->last_instr_id = i - 1; 11817 11818 TAILQ_INSERT_AFTER(igl, g, new_g, node); 11819 n_groups++; 11820 is_modified = 1; 11821 11822 /* The decision to split this group (to make the current instruction 11823 * the first instruction of a new group) is already taken and fully 11824 * implemented, so no need to search for more reasons to do it. 11825 */ 11826 break; 11827 } 11828 } 11829 11830 /* Re-evaluate everything, as at least one group got split, so some jumps that were 11831 * previously considered local (i.e. the jump destination is in the same group as 11832 * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a 11833 * different group than the jump instruction). Wost case scenario: each instruction 11834 * that is a jump destination ends up as the first instruction of its group. 11835 */ 11836 if (!is_modified) 11837 break; 11838 } 11839 11840 /* Re-assign the group IDs to be in incremental order. */ 11841 i = 0; 11842 TAILQ_FOREACH(g, igl, node) { 11843 g->group_id = i; 11844 11845 i++; 11846 } 11847 11848 return igl; 11849 11850 error: 11851 instruction_group_list_free(igl); 11852 11853 free(g); 11854 11855 return NULL; 11856 } 11857 11858 static void 11859 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused, 11860 uint32_t instr_pos, 11861 struct instruction *instr, 11862 FILE *f) 11863 { 11864 fprintf(f, 11865 "%s(p, t, &pipeline_instructions[%u]);\n" 11866 "\tthread_ip_reset(p, t);\n" 11867 "\tinstr_rx_exec(p);\n" 11868 "\treturn;\n", 11869 instr_type_to_func(instr), 11870 instr_pos); 11871 } 11872 11873 static int 11874 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p, 11875 struct instruction_group_list *igl, 11876 uint32_t jmp_instr_id, 11877 struct instruction *jmp_instr, 11878 struct instruction_data *jmp_data, 11879 FILE *f) 11880 { 11881 struct instruction_group *jmp_g, *g; 11882 struct instruction_data *data; 11883 uint32_t instr_id; 11884 11885 switch (jmp_instr->type) { 11886 case INSTR_JMP: 11887 break; 11888 11889 case INSTR_JMP_VALID: 11890 fprintf(f, 11891 "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 11892 jmp_instr_id); 11893 break; 11894 11895 case INSTR_JMP_INVALID: 11896 fprintf(f, 11897 "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 11898 jmp_instr_id); 11899 break; 11900 11901 case INSTR_JMP_HIT: 11902 fprintf(f, 11903 "if (t->hit)\n"); 11904 break; 11905 11906 case INSTR_JMP_MISS: 11907 fprintf(f, 11908 "if (!t->hit)\n"); 11909 break; 11910 11911 case INSTR_JMP_ACTION_HIT: 11912 fprintf(f, 11913 "if (t->action_id == pipeline_instructions[%u].jmp.action_id)", 11914 jmp_instr_id); 11915 break; 11916 11917 case INSTR_JMP_ACTION_MISS: 11918 fprintf(f, 11919 "if (t->action_id != pipeline_instructions[%u].jmp.action_id)", 11920 jmp_instr_id); 11921 break; 11922 11923 case INSTR_JMP_EQ: 11924 fprintf(f, 11925 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11926 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11927 jmp_instr_id, 11928 jmp_instr_id); 11929 break; 11930 11931 case INSTR_JMP_EQ_MH: 11932 fprintf(f, 11933 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11934 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11935 jmp_instr_id, 11936 jmp_instr_id); 11937 break; 11938 11939 case INSTR_JMP_EQ_HM: 11940 fprintf(f, 11941 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 11942 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11943 jmp_instr_id, 11944 jmp_instr_id); 11945 break; 11946 11947 case INSTR_JMP_EQ_HH: 11948 fprintf(f, 11949 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 11950 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11951 jmp_instr_id, 11952 jmp_instr_id); 11953 break; 11954 11955 case INSTR_JMP_EQ_I: 11956 fprintf(f, 11957 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11958 "pipeline_instructions[%u].jmp.b_val)", 11959 jmp_instr_id, 11960 jmp_instr_id); 11961 break; 11962 11963 case INSTR_JMP_NEQ: 11964 fprintf(f, 11965 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11966 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11967 jmp_instr_id, 11968 jmp_instr_id); 11969 break; 11970 11971 case INSTR_JMP_NEQ_MH: 11972 fprintf(f, 11973 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11974 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11975 jmp_instr_id, 11976 jmp_instr_id); 11977 break; 11978 11979 case INSTR_JMP_NEQ_HM: 11980 fprintf(f, 11981 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 11982 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11983 jmp_instr_id, 11984 jmp_instr_id); 11985 break; 11986 11987 case INSTR_JMP_NEQ_HH: 11988 fprintf(f, 11989 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 11990 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11991 jmp_instr_id, 11992 jmp_instr_id); 11993 break; 11994 11995 case INSTR_JMP_NEQ_I: 11996 fprintf(f, 11997 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11998 "pipeline_instructions[%u].jmp.b_val)", 11999 jmp_instr_id, 12000 jmp_instr_id); 12001 break; 12002 12003 case INSTR_JMP_LT: 12004 fprintf(f, 12005 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12006 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12007 jmp_instr_id, 12008 jmp_instr_id); 12009 break; 12010 12011 case INSTR_JMP_LT_MH: 12012 fprintf(f, 12013 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12014 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12015 jmp_instr_id, 12016 jmp_instr_id); 12017 break; 12018 12019 case INSTR_JMP_LT_HM: 12020 fprintf(f, 12021 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12022 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12023 jmp_instr_id, 12024 jmp_instr_id); 12025 break; 12026 12027 case INSTR_JMP_LT_HH: 12028 fprintf(f, 12029 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12030 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12031 jmp_instr_id, 12032 jmp_instr_id); 12033 break; 12034 12035 case INSTR_JMP_LT_MI: 12036 fprintf(f, 12037 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12038 "pipeline_instructions[%u].jmp.b_val)", 12039 jmp_instr_id, 12040 jmp_instr_id); 12041 break; 12042 12043 case INSTR_JMP_LT_HI: 12044 fprintf(f, 12045 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12046 "pipeline_instructions[%u].jmp.b_val)", 12047 jmp_instr_id, 12048 jmp_instr_id); 12049 break; 12050 12051 case INSTR_JMP_GT: 12052 fprintf(f, 12053 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12054 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12055 jmp_instr_id, 12056 jmp_instr_id); 12057 break; 12058 12059 case INSTR_JMP_GT_MH: 12060 fprintf(f, 12061 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12062 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12063 jmp_instr_id, 12064 jmp_instr_id); 12065 break; 12066 12067 case INSTR_JMP_GT_HM: 12068 fprintf(f, 12069 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12070 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12071 jmp_instr_id, 12072 jmp_instr_id); 12073 break; 12074 12075 case INSTR_JMP_GT_HH: 12076 fprintf(f, 12077 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12078 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12079 jmp_instr_id, 12080 jmp_instr_id); 12081 break; 12082 12083 case INSTR_JMP_GT_MI: 12084 fprintf(f, 12085 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12086 "pipeline_instructions[%u].jmp.b_val)", 12087 jmp_instr_id, 12088 jmp_instr_id); 12089 break; 12090 12091 case INSTR_JMP_GT_HI: 12092 fprintf(f, 12093 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12094 "pipeline_instructions[%u].jmp.b_val)", 12095 jmp_instr_id, 12096 jmp_instr_id); 12097 break; 12098 12099 default: 12100 break; 12101 } 12102 12103 /* Find the instruction group of the jump instruction. */ 12104 jmp_g = instruction_group_list_group_find(igl, jmp_instr_id); 12105 if (!jmp_g) 12106 return -EINVAL; 12107 12108 /* Find the instruction group of the jump destination instruction. */ 12109 data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label); 12110 if (!data) 12111 return -EINVAL; 12112 12113 instr_id = data - p->instruction_data; 12114 12115 g = instruction_group_list_group_find(igl, instr_id); 12116 if (!g) 12117 return -EINVAL; 12118 12119 /* Code generation for "near" jump (same instruction group) or "far" jump (different 12120 * instruction group). 12121 */ 12122 if (g->group_id == jmp_g->group_id) 12123 fprintf(f, 12124 "\n\t\tgoto %s;\n", 12125 jmp_data->jmp_label); 12126 else 12127 fprintf(f, 12128 " {\n" 12129 "\t\tthread_ip_set(t, &p->instructions[%u]);\n" 12130 "\t\treturn;\n" 12131 "\t}\n\n", 12132 g->group_id); 12133 12134 return 0; 12135 } 12136 12137 static void 12138 instruction_group_list_codegen(struct instruction_group_list *igl, 12139 struct rte_swx_pipeline *p, 12140 FILE *f) 12141 { 12142 struct instruction_group *g; 12143 uint32_t i; 12144 int is_required = 0; 12145 12146 /* Check if code generation is required. */ 12147 TAILQ_FOREACH(g, igl, node) 12148 if (g->first_instr_id < g->last_instr_id) 12149 is_required = 1; 12150 12151 if (!is_required) 12152 return; 12153 12154 /* Generate the code for the pipeline instruction array. */ 12155 fprintf(f, 12156 "static const struct instruction pipeline_instructions[] = {\n"); 12157 12158 for (i = 0; i < p->n_instructions; i++) { 12159 struct instruction *instr = &p->instructions[i]; 12160 instruction_export_t func = export_table[instr->type]; 12161 12162 func(instr, f); 12163 } 12164 12165 fprintf(f, "};\n\n"); 12166 12167 /* Generate the code for the pipeline functions: one function for each instruction group 12168 * that contains more than one instruction. 12169 */ 12170 TAILQ_FOREACH(g, igl, node) { 12171 struct instruction *last_instr; 12172 uint32_t j; 12173 12174 /* Skip if group contains a single instruction. */ 12175 if (g->last_instr_id == g->first_instr_id) 12176 continue; 12177 12178 /* Generate new pipeline function. */ 12179 fprintf(f, 12180 "void\n" 12181 "pipeline_func_%u(struct rte_swx_pipeline *p)\n" 12182 "{\n" 12183 "\tstruct thread *t = &p->threads[p->thread_id];\n" 12184 "\n", 12185 g->group_id); 12186 12187 /* Generate the code for each pipeline instruction. */ 12188 for (j = g->first_instr_id; j <= g->last_instr_id; j++) { 12189 struct instruction *instr = &p->instructions[j]; 12190 struct instruction_data *data = &p->instruction_data[j]; 12191 12192 /* Label, if present. */ 12193 if (data->label[0]) 12194 fprintf(f, "\n%s : ", data->label); 12195 else 12196 fprintf(f, "\n\t"); 12197 12198 /* TX instruction type. */ 12199 if (instruction_does_tx(instr)) { 12200 pipeline_instr_does_tx_codegen(p, j, instr, f); 12201 continue; 12202 } 12203 12204 /* Jump instruction type. */ 12205 if (instruction_is_jmp(instr)) { 12206 pipeline_instr_jmp_codegen(p, igl, j, instr, data, f); 12207 continue; 12208 } 12209 12210 /* Any other instruction type. */ 12211 fprintf(f, 12212 "%s(p, t, &pipeline_instructions[%u]);\n", 12213 instr_type_to_func(instr), 12214 j); 12215 } 12216 12217 /* Finalize the generated pipeline function. For some instructions such as TX, 12218 * emit-many-and-TX and unconditional jump, the next instruction has been already 12219 * decided unconditionally and the instruction pointer of the current thread set 12220 * accordingly; for all the other instructions, the instruction pointer must be 12221 * incremented now. 12222 */ 12223 last_instr = &p->instructions[g->last_instr_id]; 12224 12225 if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP)) 12226 fprintf(f, 12227 "thread_ip_inc(p);\n"); 12228 12229 fprintf(f, 12230 "}\n" 12231 "\n"); 12232 } 12233 } 12234 12235 static uint32_t 12236 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl) 12237 { 12238 struct instruction_group *g; 12239 uint32_t n_custom_instr = 0; 12240 12241 /* Groups with a single instruction: no function is generated for this group, the group 12242 * keeps its current instruction. Groups with more than two instructions: one function and 12243 * the associated custom instruction get generated for each such group. 12244 */ 12245 TAILQ_FOREACH(g, igl, node) { 12246 if (g->first_instr_id == g->last_instr_id) 12247 continue; 12248 12249 n_custom_instr++; 12250 } 12251 12252 return n_custom_instr; 12253 } 12254 12255 static int 12256 pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12257 { 12258 struct action *a; 12259 FILE *f = NULL; 12260 12261 /* Create the .c file. */ 12262 f = fopen("/tmp/pipeline.c", "w"); 12263 if (!f) 12264 return -EIO; 12265 12266 /* Include the .h file. */ 12267 fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n"); 12268 12269 /* Add the code for each action. */ 12270 TAILQ_FOREACH(a, &p->actions, node) { 12271 fprintf(f, "/**\n * Action %s\n */\n\n", a->name); 12272 12273 action_data_codegen(a, f); 12274 12275 fprintf(f, "\n"); 12276 12277 action_instr_codegen(a, f); 12278 12279 fprintf(f, "\n"); 12280 } 12281 12282 /* Add the pipeline code. */ 12283 instruction_group_list_codegen(igl, p, f); 12284 12285 /* Close the .c file. */ 12286 fclose(f); 12287 12288 return 0; 12289 } 12290 12291 #ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE 12292 #define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096 12293 #endif 12294 12295 static int 12296 pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12297 { 12298 struct action *a; 12299 struct instruction_group *g; 12300 char *dir_in, *buffer = NULL; 12301 const char *dir_out; 12302 int status = 0; 12303 12304 /* Get the environment variables. */ 12305 dir_in = getenv("RTE_INSTALL_DIR"); 12306 if (!dir_in) { 12307 status = -EINVAL; 12308 goto free; 12309 } 12310 12311 dir_out = "/tmp"; 12312 12313 /* Memory allocation for the command buffer. */ 12314 buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE); 12315 if (!buffer) { 12316 status = -ENOMEM; 12317 goto free; 12318 } 12319 12320 snprintf(buffer, 12321 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 12322 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c " 12323 "-I %s/lib/pipeline " 12324 "-I %s/lib/eal/include " 12325 "-I %s/lib/eal/x86/include " 12326 "-I %s/lib/eal/include/generic " 12327 "-I %s/lib/meter " 12328 "-I %s/lib/port " 12329 "-I %s/lib/table " 12330 "-I %s/lib/pipeline " 12331 "-I %s/config " 12332 "-I %s/build " 12333 "-I %s/lib/eal/linux/include " 12334 ">%s/pipeline.log 2>&1 " 12335 "&& " 12336 "gcc -shared %s/pipeline.o -o %s/libpipeline.so " 12337 ">>%s/pipeline.log 2>&1", 12338 dir_out, 12339 dir_out, 12340 dir_in, 12341 dir_in, 12342 dir_in, 12343 dir_in, 12344 dir_in, 12345 dir_in, 12346 dir_in, 12347 dir_in, 12348 dir_in, 12349 dir_in, 12350 dir_in, 12351 dir_out, 12352 dir_out, 12353 dir_out, 12354 dir_out); 12355 12356 /* Build the shared object library. */ 12357 status = system(buffer); 12358 if (status) 12359 goto free; 12360 12361 /* Open library. */ 12362 snprintf(buffer, 12363 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 12364 "%s/libpipeline.so", 12365 dir_out); 12366 12367 p->lib = dlopen(buffer, RTLD_LAZY); 12368 if (!p->lib) { 12369 status = -EIO; 12370 goto free; 12371 } 12372 12373 /* Get the action function symbols. */ 12374 TAILQ_FOREACH(a, &p->actions, node) { 12375 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name); 12376 12377 p->action_funcs[a->id] = dlsym(p->lib, buffer); 12378 if (!p->action_funcs[a->id]) { 12379 status = -EINVAL; 12380 goto free; 12381 } 12382 } 12383 12384 /* Get the pipeline function symbols. */ 12385 TAILQ_FOREACH(g, igl, node) { 12386 if (g->first_instr_id == g->last_instr_id) 12387 continue; 12388 12389 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id); 12390 12391 g->func = dlsym(p->lib, buffer); 12392 if (!g->func) { 12393 status = -EINVAL; 12394 goto free; 12395 } 12396 } 12397 12398 free: 12399 if (status && p->lib) { 12400 dlclose(p->lib); 12401 p->lib = NULL; 12402 } 12403 12404 free(buffer); 12405 12406 return status; 12407 } 12408 12409 static int 12410 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused, 12411 struct instruction_group_list *igl) 12412 { 12413 uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl); 12414 12415 /* Check that enough space is available within the pipeline instruction table to store all 12416 * the custom instructions. 12417 */ 12418 if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX) 12419 return -ENOSPC; 12420 12421 return 0; 12422 } 12423 12424 static void 12425 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12426 { 12427 struct instruction_group *g; 12428 uint32_t i; 12429 12430 /* Pipeline table instructions. */ 12431 for (i = 0; i < p->n_instructions; i++) { 12432 struct instruction *instr = &p->instructions[i]; 12433 12434 if (instr->type == INSTR_TABLE) 12435 instr->type = INSTR_TABLE_AF; 12436 12437 if (instr->type == INSTR_LEARNER) 12438 instr->type = INSTR_LEARNER_AF; 12439 } 12440 12441 /* Pipeline custom instructions. */ 12442 i = 0; 12443 TAILQ_FOREACH(g, igl, node) { 12444 struct instruction *instr = &p->instructions[g->first_instr_id]; 12445 uint32_t j; 12446 12447 if (g->first_instr_id == g->last_instr_id) 12448 continue; 12449 12450 /* Install a new custom instruction. */ 12451 p->instruction_table[INSTR_CUSTOM_0 + i] = g->func; 12452 12453 /* First instruction of the group: change its type to the new custom instruction. */ 12454 instr->type = INSTR_CUSTOM_0 + i; 12455 12456 /* All the subsequent instructions of the group: invalidate. */ 12457 for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) { 12458 struct instruction_data *data = &p->instruction_data[j]; 12459 12460 data->invalid = 1; 12461 } 12462 12463 i++; 12464 } 12465 12466 /* Remove the invalidated instructions. */ 12467 p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions); 12468 12469 /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump 12470 * instructions that are the only instruction within their group, so they were left 12471 * unmodified). 12472 */ 12473 instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions); 12474 } 12475 12476 static int 12477 pipeline_compile(struct rte_swx_pipeline *p) 12478 { 12479 struct instruction_group_list *igl = NULL; 12480 int status = 0; 12481 12482 igl = instruction_group_list_create(p); 12483 if (!igl) { 12484 status = -ENOMEM; 12485 goto free; 12486 } 12487 12488 /* Code generation. */ 12489 status = pipeline_codegen(p, igl); 12490 if (status) 12491 goto free; 12492 12493 /* Build and load the shared object library. */ 12494 status = pipeline_libload(p, igl); 12495 if (status) 12496 goto free; 12497 12498 /* Adjust instructions. */ 12499 status = pipeline_adjust_check(p, igl); 12500 if (status) 12501 goto free; 12502 12503 pipeline_adjust(p, igl); 12504 12505 free: 12506 instruction_group_list_free(igl); 12507 12508 return status; 12509 } 12510