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 4544 /* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */ 4545 if (fidx && !fcin) { 4546 uint32_t color_in_val; 4547 4548 CHECK(!fidx->var_size, EINVAL); 4549 4550 color_in_val = strtoul(color_in, &color_in, 0); 4551 CHECK(!color_in[0], EINVAL); 4552 4553 instr->type = INSTR_METER_MMI; 4554 if (idx[0] == 'h' && length[0] == 'h') 4555 instr->type = INSTR_METER_HHI; 4556 if (idx[0] == 'h' && length[0] != 'h') 4557 instr->type = INSTR_METER_HMI; 4558 if (idx[0] != 'h' && length[0] == 'h') 4559 instr->type = INSTR_METER_MHI; 4560 4561 instr->meter.metarray_id = m->id; 4562 4563 instr->meter.idx.struct_id = (uint8_t)idx_struct_id; 4564 instr->meter.idx.n_bits = fidx->n_bits; 4565 instr->meter.idx.offset = fidx->offset / 8; 4566 4567 instr->meter.length.struct_id = (uint8_t)length_struct_id; 4568 instr->meter.length.n_bits = flength->n_bits; 4569 instr->meter.length.offset = flength->offset / 8; 4570 4571 instr->meter.color_in_val = color_in_val; 4572 4573 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 4574 instr->meter.color_out.n_bits = fcout->n_bits; 4575 instr->meter.color_out.offset = fcout->offset / 8; 4576 } 4577 4578 /* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */ 4579 if (!fidx && fcin) { 4580 uint32_t idx_val; 4581 4582 idx_val = strtoul(idx, &idx, 0); 4583 CHECK(!idx[0], EINVAL); 4584 4585 CHECK(!fcin->var_size, EINVAL); 4586 4587 instr->type = INSTR_METER_IMM; 4588 if (length[0] == 'h') 4589 instr->type = INSTR_METER_IHM; 4590 4591 instr->meter.metarray_id = m->id; 4592 4593 instr->meter.idx_val = idx_val; 4594 4595 instr->meter.length.struct_id = (uint8_t)length_struct_id; 4596 instr->meter.length.n_bits = flength->n_bits; 4597 instr->meter.length.offset = flength->offset / 8; 4598 4599 instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id; 4600 instr->meter.color_in.n_bits = fcin->n_bits; 4601 instr->meter.color_in.offset = fcin->offset / 8; 4602 4603 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 4604 instr->meter.color_out.n_bits = fcout->n_bits; 4605 instr->meter.color_out.offset = fcout->offset / 8; 4606 } 4607 4608 /* index = I, length = HMEFT, color_in = I, color_out = MEF. */ 4609 if (!fidx && !fcin) { 4610 uint32_t idx_val, color_in_val; 4611 4612 idx_val = strtoul(idx, &idx, 0); 4613 CHECK(!idx[0], EINVAL); 4614 4615 color_in_val = strtoul(color_in, &color_in, 0); 4616 CHECK(!color_in[0], EINVAL); 4617 4618 instr->type = INSTR_METER_IMI; 4619 if (length[0] == 'h') 4620 instr->type = INSTR_METER_IHI; 4621 4622 instr->meter.metarray_id = m->id; 4623 4624 instr->meter.idx_val = idx_val; 4625 4626 instr->meter.length.struct_id = (uint8_t)length_struct_id; 4627 instr->meter.length.n_bits = flength->n_bits; 4628 instr->meter.length.offset = flength->offset / 8; 4629 4630 instr->meter.color_in_val = color_in_val; 4631 4632 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; 4633 instr->meter.color_out.n_bits = fcout->n_bits; 4634 instr->meter.color_out.offset = fcout->offset / 8; 4635 } 4636 4637 return 0; 4638 } 4639 4640 static inline void 4641 instr_metprefetch_h_exec(struct rte_swx_pipeline *p) 4642 { 4643 struct thread *t = &p->threads[p->thread_id]; 4644 struct instruction *ip = t->ip; 4645 4646 /* Structs. */ 4647 __instr_metprefetch_h_exec(p, t, ip); 4648 4649 /* Thread. */ 4650 thread_ip_inc(p); 4651 } 4652 4653 static inline void 4654 instr_metprefetch_m_exec(struct rte_swx_pipeline *p) 4655 { 4656 struct thread *t = &p->threads[p->thread_id]; 4657 struct instruction *ip = t->ip; 4658 4659 /* Structs. */ 4660 __instr_metprefetch_m_exec(p, t, ip); 4661 4662 /* Thread. */ 4663 thread_ip_inc(p); 4664 } 4665 4666 static inline void 4667 instr_metprefetch_i_exec(struct rte_swx_pipeline *p) 4668 { 4669 struct thread *t = &p->threads[p->thread_id]; 4670 struct instruction *ip = t->ip; 4671 4672 /* Structs. */ 4673 __instr_metprefetch_i_exec(p, t, ip); 4674 4675 /* Thread. */ 4676 thread_ip_inc(p); 4677 } 4678 4679 static inline void 4680 instr_meter_hhm_exec(struct rte_swx_pipeline *p) 4681 { 4682 struct thread *t = &p->threads[p->thread_id]; 4683 struct instruction *ip = t->ip; 4684 4685 /* Structs. */ 4686 __instr_meter_hhm_exec(p, t, ip); 4687 4688 /* Thread. */ 4689 thread_ip_inc(p); 4690 } 4691 4692 static inline void 4693 instr_meter_hhi_exec(struct rte_swx_pipeline *p) 4694 { 4695 struct thread *t = &p->threads[p->thread_id]; 4696 struct instruction *ip = t->ip; 4697 4698 /* Structs. */ 4699 __instr_meter_hhi_exec(p, t, ip); 4700 4701 /* Thread. */ 4702 thread_ip_inc(p); 4703 } 4704 4705 static inline void 4706 instr_meter_hmm_exec(struct rte_swx_pipeline *p) 4707 { 4708 struct thread *t = &p->threads[p->thread_id]; 4709 struct instruction *ip = t->ip; 4710 4711 /* Structs. */ 4712 __instr_meter_hmm_exec(p, t, ip); 4713 4714 /* Thread. */ 4715 thread_ip_inc(p); 4716 } 4717 4718 static inline void 4719 instr_meter_hmi_exec(struct rte_swx_pipeline *p) 4720 { 4721 struct thread *t = &p->threads[p->thread_id]; 4722 struct instruction *ip = t->ip; 4723 4724 /* Structs. */ 4725 __instr_meter_hmi_exec(p, t, ip); 4726 4727 /* Thread. */ 4728 thread_ip_inc(p); 4729 } 4730 4731 static inline void 4732 instr_meter_mhm_exec(struct rte_swx_pipeline *p) 4733 { 4734 struct thread *t = &p->threads[p->thread_id]; 4735 struct instruction *ip = t->ip; 4736 4737 /* Structs. */ 4738 __instr_meter_mhm_exec(p, t, ip); 4739 4740 /* Thread. */ 4741 thread_ip_inc(p); 4742 } 4743 4744 static inline void 4745 instr_meter_mhi_exec(struct rte_swx_pipeline *p) 4746 { 4747 struct thread *t = &p->threads[p->thread_id]; 4748 struct instruction *ip = t->ip; 4749 4750 /* Structs. */ 4751 __instr_meter_mhi_exec(p, t, ip); 4752 4753 /* Thread. */ 4754 thread_ip_inc(p); 4755 } 4756 4757 static inline void 4758 instr_meter_mmm_exec(struct rte_swx_pipeline *p) 4759 { 4760 struct thread *t = &p->threads[p->thread_id]; 4761 struct instruction *ip = t->ip; 4762 4763 /* Structs. */ 4764 __instr_meter_mmm_exec(p, t, ip); 4765 4766 /* Thread. */ 4767 thread_ip_inc(p); 4768 } 4769 4770 static inline void 4771 instr_meter_mmi_exec(struct rte_swx_pipeline *p) 4772 { 4773 struct thread *t = &p->threads[p->thread_id]; 4774 struct instruction *ip = t->ip; 4775 4776 /* Structs. */ 4777 __instr_meter_mmi_exec(p, t, ip); 4778 4779 /* Thread. */ 4780 thread_ip_inc(p); 4781 } 4782 4783 static inline void 4784 instr_meter_ihm_exec(struct rte_swx_pipeline *p) 4785 { 4786 struct thread *t = &p->threads[p->thread_id]; 4787 struct instruction *ip = t->ip; 4788 4789 /* Structs. */ 4790 __instr_meter_ihm_exec(p, t, ip); 4791 4792 /* Thread. */ 4793 thread_ip_inc(p); 4794 } 4795 4796 static inline void 4797 instr_meter_ihi_exec(struct rte_swx_pipeline *p) 4798 { 4799 struct thread *t = &p->threads[p->thread_id]; 4800 struct instruction *ip = t->ip; 4801 4802 /* Structs. */ 4803 __instr_meter_ihi_exec(p, t, ip); 4804 4805 /* Thread. */ 4806 thread_ip_inc(p); 4807 } 4808 4809 static inline void 4810 instr_meter_imm_exec(struct rte_swx_pipeline *p) 4811 { 4812 struct thread *t = &p->threads[p->thread_id]; 4813 struct instruction *ip = t->ip; 4814 4815 /* Structs. */ 4816 __instr_meter_imm_exec(p, t, ip); 4817 4818 /* Thread. */ 4819 thread_ip_inc(p); 4820 } 4821 4822 static inline void 4823 instr_meter_imi_exec(struct rte_swx_pipeline *p) 4824 { 4825 struct thread *t = &p->threads[p->thread_id]; 4826 struct instruction *ip = t->ip; 4827 4828 /* Structs. */ 4829 __instr_meter_imi_exec(p, t, ip); 4830 4831 /* Thread. */ 4832 thread_ip_inc(p); 4833 } 4834 4835 /* 4836 * jmp. 4837 */ 4838 static int 4839 instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused, 4840 struct action *action __rte_unused, 4841 char **tokens, 4842 int n_tokens, 4843 struct instruction *instr, 4844 struct instruction_data *data) 4845 { 4846 CHECK(n_tokens == 2, EINVAL); 4847 4848 strcpy(data->jmp_label, tokens[1]); 4849 4850 instr->type = INSTR_JMP; 4851 instr->jmp.ip = NULL; /* Resolved later. */ 4852 return 0; 4853 } 4854 4855 static int 4856 instr_jmp_valid_translate(struct rte_swx_pipeline *p, 4857 struct action *action __rte_unused, 4858 char **tokens, 4859 int n_tokens, 4860 struct instruction *instr, 4861 struct instruction_data *data) 4862 { 4863 struct header *h; 4864 4865 CHECK(n_tokens == 3, EINVAL); 4866 4867 strcpy(data->jmp_label, tokens[1]); 4868 4869 h = header_parse(p, tokens[2]); 4870 CHECK(h, EINVAL); 4871 4872 instr->type = INSTR_JMP_VALID; 4873 instr->jmp.ip = NULL; /* Resolved later. */ 4874 instr->jmp.header_id = h->id; 4875 return 0; 4876 } 4877 4878 static int 4879 instr_jmp_invalid_translate(struct rte_swx_pipeline *p, 4880 struct action *action __rte_unused, 4881 char **tokens, 4882 int n_tokens, 4883 struct instruction *instr, 4884 struct instruction_data *data) 4885 { 4886 struct header *h; 4887 4888 CHECK(n_tokens == 3, EINVAL); 4889 4890 strcpy(data->jmp_label, tokens[1]); 4891 4892 h = header_parse(p, tokens[2]); 4893 CHECK(h, EINVAL); 4894 4895 instr->type = INSTR_JMP_INVALID; 4896 instr->jmp.ip = NULL; /* Resolved later. */ 4897 instr->jmp.header_id = h->id; 4898 return 0; 4899 } 4900 4901 static int 4902 instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused, 4903 struct action *action, 4904 char **tokens, 4905 int n_tokens, 4906 struct instruction *instr, 4907 struct instruction_data *data) 4908 { 4909 CHECK(!action, EINVAL); 4910 CHECK(n_tokens == 2, EINVAL); 4911 4912 strcpy(data->jmp_label, tokens[1]); 4913 4914 instr->type = INSTR_JMP_HIT; 4915 instr->jmp.ip = NULL; /* Resolved later. */ 4916 return 0; 4917 } 4918 4919 static int 4920 instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused, 4921 struct action *action, 4922 char **tokens, 4923 int n_tokens, 4924 struct instruction *instr, 4925 struct instruction_data *data) 4926 { 4927 CHECK(!action, EINVAL); 4928 CHECK(n_tokens == 2, EINVAL); 4929 4930 strcpy(data->jmp_label, tokens[1]); 4931 4932 instr->type = INSTR_JMP_MISS; 4933 instr->jmp.ip = NULL; /* Resolved later. */ 4934 return 0; 4935 } 4936 4937 static int 4938 instr_jmp_action_hit_translate(struct rte_swx_pipeline *p, 4939 struct action *action, 4940 char **tokens, 4941 int n_tokens, 4942 struct instruction *instr, 4943 struct instruction_data *data) 4944 { 4945 struct action *a; 4946 4947 CHECK(!action, EINVAL); 4948 CHECK(n_tokens == 3, EINVAL); 4949 4950 strcpy(data->jmp_label, tokens[1]); 4951 4952 a = action_find(p, tokens[2]); 4953 CHECK(a, EINVAL); 4954 4955 instr->type = INSTR_JMP_ACTION_HIT; 4956 instr->jmp.ip = NULL; /* Resolved later. */ 4957 instr->jmp.action_id = a->id; 4958 return 0; 4959 } 4960 4961 static int 4962 instr_jmp_action_miss_translate(struct rte_swx_pipeline *p, 4963 struct action *action, 4964 char **tokens, 4965 int n_tokens, 4966 struct instruction *instr, 4967 struct instruction_data *data) 4968 { 4969 struct action *a; 4970 4971 CHECK(!action, EINVAL); 4972 CHECK(n_tokens == 3, EINVAL); 4973 4974 strcpy(data->jmp_label, tokens[1]); 4975 4976 a = action_find(p, tokens[2]); 4977 CHECK(a, EINVAL); 4978 4979 instr->type = INSTR_JMP_ACTION_MISS; 4980 instr->jmp.ip = NULL; /* Resolved later. */ 4981 instr->jmp.action_id = a->id; 4982 return 0; 4983 } 4984 4985 static int 4986 instr_jmp_eq_translate(struct rte_swx_pipeline *p, 4987 struct action *action, 4988 char **tokens, 4989 int n_tokens, 4990 struct instruction *instr, 4991 struct instruction_data *data) 4992 { 4993 char *a = tokens[2], *b = tokens[3]; 4994 struct field *fa, *fb; 4995 uint64_t b_val; 4996 uint32_t a_struct_id, b_struct_id; 4997 4998 CHECK(n_tokens == 4, EINVAL); 4999 5000 strcpy(data->jmp_label, tokens[1]); 5001 5002 fa = struct_field_parse(p, action, a, &a_struct_id); 5003 CHECK(fa, EINVAL); 5004 CHECK(!fa->var_size, EINVAL); 5005 5006 /* JMP_EQ, JMP_EQ_MH, JMP_EQ_HM, JMP_EQ_HH. */ 5007 fb = struct_field_parse(p, action, b, &b_struct_id); 5008 if (fb) { 5009 CHECK(!fb->var_size, EINVAL); 5010 5011 instr->type = INSTR_JMP_EQ; 5012 if (a[0] != 'h' && b[0] == 'h') 5013 instr->type = INSTR_JMP_EQ_MH; 5014 if (a[0] == 'h' && b[0] != 'h') 5015 instr->type = INSTR_JMP_EQ_HM; 5016 if (a[0] == 'h' && b[0] == 'h') 5017 instr->type = INSTR_JMP_EQ_HH; 5018 instr->jmp.ip = NULL; /* Resolved later. */ 5019 5020 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5021 instr->jmp.a.n_bits = fa->n_bits; 5022 instr->jmp.a.offset = fa->offset / 8; 5023 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5024 instr->jmp.b.n_bits = fb->n_bits; 5025 instr->jmp.b.offset = fb->offset / 8; 5026 return 0; 5027 } 5028 5029 /* JMP_EQ_I. */ 5030 b_val = strtoull(b, &b, 0); 5031 CHECK(!b[0], EINVAL); 5032 5033 if (a[0] == 'h') 5034 b_val = hton64(b_val) >> (64 - fa->n_bits); 5035 5036 instr->type = INSTR_JMP_EQ_I; 5037 instr->jmp.ip = NULL; /* Resolved later. */ 5038 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5039 instr->jmp.a.n_bits = fa->n_bits; 5040 instr->jmp.a.offset = fa->offset / 8; 5041 instr->jmp.b_val = b_val; 5042 return 0; 5043 } 5044 5045 static int 5046 instr_jmp_neq_translate(struct rte_swx_pipeline *p, 5047 struct action *action, 5048 char **tokens, 5049 int n_tokens, 5050 struct instruction *instr, 5051 struct instruction_data *data) 5052 { 5053 char *a = tokens[2], *b = tokens[3]; 5054 struct field *fa, *fb; 5055 uint64_t b_val; 5056 uint32_t a_struct_id, b_struct_id; 5057 5058 CHECK(n_tokens == 4, EINVAL); 5059 5060 strcpy(data->jmp_label, tokens[1]); 5061 5062 fa = struct_field_parse(p, action, a, &a_struct_id); 5063 CHECK(fa, EINVAL); 5064 CHECK(!fa->var_size, EINVAL); 5065 5066 /* JMP_NEQ, JMP_NEQ_MH, JMP_NEQ_HM, JMP_NEQ_HH. */ 5067 fb = struct_field_parse(p, action, b, &b_struct_id); 5068 if (fb) { 5069 CHECK(!fb->var_size, EINVAL); 5070 5071 instr->type = INSTR_JMP_NEQ; 5072 if (a[0] != 'h' && b[0] == 'h') 5073 instr->type = INSTR_JMP_NEQ_MH; 5074 if (a[0] == 'h' && b[0] != 'h') 5075 instr->type = INSTR_JMP_NEQ_HM; 5076 if (a[0] == 'h' && b[0] == 'h') 5077 instr->type = INSTR_JMP_NEQ_HH; 5078 instr->jmp.ip = NULL; /* Resolved later. */ 5079 5080 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5081 instr->jmp.a.n_bits = fa->n_bits; 5082 instr->jmp.a.offset = fa->offset / 8; 5083 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5084 instr->jmp.b.n_bits = fb->n_bits; 5085 instr->jmp.b.offset = fb->offset / 8; 5086 return 0; 5087 } 5088 5089 /* JMP_NEQ_I. */ 5090 b_val = strtoull(b, &b, 0); 5091 CHECK(!b[0], EINVAL); 5092 5093 if (a[0] == 'h') 5094 b_val = hton64(b_val) >> (64 - fa->n_bits); 5095 5096 instr->type = INSTR_JMP_NEQ_I; 5097 instr->jmp.ip = NULL; /* Resolved later. */ 5098 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5099 instr->jmp.a.n_bits = fa->n_bits; 5100 instr->jmp.a.offset = fa->offset / 8; 5101 instr->jmp.b_val = b_val; 5102 return 0; 5103 } 5104 5105 static int 5106 instr_jmp_lt_translate(struct rte_swx_pipeline *p, 5107 struct action *action, 5108 char **tokens, 5109 int n_tokens, 5110 struct instruction *instr, 5111 struct instruction_data *data) 5112 { 5113 char *a = tokens[2], *b = tokens[3]; 5114 struct field *fa, *fb; 5115 uint64_t b_val; 5116 uint32_t a_struct_id, b_struct_id; 5117 5118 CHECK(n_tokens == 4, EINVAL); 5119 5120 strcpy(data->jmp_label, tokens[1]); 5121 5122 fa = struct_field_parse(p, action, a, &a_struct_id); 5123 CHECK(fa, EINVAL); 5124 CHECK(!fa->var_size, EINVAL); 5125 5126 /* JMP_LT, JMP_LT_MH, JMP_LT_HM, JMP_LT_HH. */ 5127 fb = struct_field_parse(p, action, b, &b_struct_id); 5128 if (fb) { 5129 CHECK(!fb->var_size, EINVAL); 5130 5131 instr->type = INSTR_JMP_LT; 5132 if (a[0] == 'h' && b[0] != 'h') 5133 instr->type = INSTR_JMP_LT_HM; 5134 if (a[0] != 'h' && b[0] == 'h') 5135 instr->type = INSTR_JMP_LT_MH; 5136 if (a[0] == 'h' && b[0] == 'h') 5137 instr->type = INSTR_JMP_LT_HH; 5138 instr->jmp.ip = NULL; /* Resolved later. */ 5139 5140 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5141 instr->jmp.a.n_bits = fa->n_bits; 5142 instr->jmp.a.offset = fa->offset / 8; 5143 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5144 instr->jmp.b.n_bits = fb->n_bits; 5145 instr->jmp.b.offset = fb->offset / 8; 5146 return 0; 5147 } 5148 5149 /* JMP_LT_MI, JMP_LT_HI. */ 5150 b_val = strtoull(b, &b, 0); 5151 CHECK(!b[0], EINVAL); 5152 5153 instr->type = INSTR_JMP_LT_MI; 5154 if (a[0] == 'h') 5155 instr->type = INSTR_JMP_LT_HI; 5156 instr->jmp.ip = NULL; /* Resolved later. */ 5157 5158 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5159 instr->jmp.a.n_bits = fa->n_bits; 5160 instr->jmp.a.offset = fa->offset / 8; 5161 instr->jmp.b_val = b_val; 5162 return 0; 5163 } 5164 5165 static int 5166 instr_jmp_gt_translate(struct rte_swx_pipeline *p, 5167 struct action *action, 5168 char **tokens, 5169 int n_tokens, 5170 struct instruction *instr, 5171 struct instruction_data *data) 5172 { 5173 char *a = tokens[2], *b = tokens[3]; 5174 struct field *fa, *fb; 5175 uint64_t b_val; 5176 uint32_t a_struct_id, b_struct_id; 5177 5178 CHECK(n_tokens == 4, EINVAL); 5179 5180 strcpy(data->jmp_label, tokens[1]); 5181 5182 fa = struct_field_parse(p, action, a, &a_struct_id); 5183 CHECK(fa, EINVAL); 5184 CHECK(!fa->var_size, EINVAL); 5185 5186 /* JMP_GT, JMP_GT_MH, JMP_GT_HM, JMP_GT_HH. */ 5187 fb = struct_field_parse(p, action, b, &b_struct_id); 5188 if (fb) { 5189 CHECK(!fb->var_size, EINVAL); 5190 5191 instr->type = INSTR_JMP_GT; 5192 if (a[0] == 'h' && b[0] != 'h') 5193 instr->type = INSTR_JMP_GT_HM; 5194 if (a[0] != 'h' && b[0] == 'h') 5195 instr->type = INSTR_JMP_GT_MH; 5196 if (a[0] == 'h' && b[0] == 'h') 5197 instr->type = INSTR_JMP_GT_HH; 5198 instr->jmp.ip = NULL; /* Resolved later. */ 5199 5200 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5201 instr->jmp.a.n_bits = fa->n_bits; 5202 instr->jmp.a.offset = fa->offset / 8; 5203 instr->jmp.b.struct_id = (uint8_t)b_struct_id; 5204 instr->jmp.b.n_bits = fb->n_bits; 5205 instr->jmp.b.offset = fb->offset / 8; 5206 return 0; 5207 } 5208 5209 /* JMP_GT_MI, JMP_GT_HI. */ 5210 b_val = strtoull(b, &b, 0); 5211 CHECK(!b[0], EINVAL); 5212 5213 instr->type = INSTR_JMP_GT_MI; 5214 if (a[0] == 'h') 5215 instr->type = INSTR_JMP_GT_HI; 5216 instr->jmp.ip = NULL; /* Resolved later. */ 5217 5218 instr->jmp.a.struct_id = (uint8_t)a_struct_id; 5219 instr->jmp.a.n_bits = fa->n_bits; 5220 instr->jmp.a.offset = fa->offset / 8; 5221 instr->jmp.b_val = b_val; 5222 return 0; 5223 } 5224 5225 static inline void 5226 instr_jmp_exec(struct rte_swx_pipeline *p) 5227 { 5228 struct thread *t = &p->threads[p->thread_id]; 5229 struct instruction *ip = t->ip; 5230 5231 TRACE("[Thread %2u] jmp\n", p->thread_id); 5232 5233 thread_ip_set(t, ip->jmp.ip); 5234 } 5235 5236 static inline void 5237 instr_jmp_valid_exec(struct rte_swx_pipeline *p) 5238 { 5239 struct thread *t = &p->threads[p->thread_id]; 5240 struct instruction *ip = t->ip; 5241 uint32_t header_id = ip->jmp.header_id; 5242 5243 TRACE("[Thread %2u] jmpv\n", p->thread_id); 5244 5245 t->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1); 5246 } 5247 5248 static inline void 5249 instr_jmp_invalid_exec(struct rte_swx_pipeline *p) 5250 { 5251 struct thread *t = &p->threads[p->thread_id]; 5252 struct instruction *ip = t->ip; 5253 uint32_t header_id = ip->jmp.header_id; 5254 5255 TRACE("[Thread %2u] jmpnv\n", p->thread_id); 5256 5257 t->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip; 5258 } 5259 5260 static inline void 5261 instr_jmp_hit_exec(struct rte_swx_pipeline *p) 5262 { 5263 struct thread *t = &p->threads[p->thread_id]; 5264 struct instruction *ip = t->ip; 5265 struct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip}; 5266 5267 TRACE("[Thread %2u] jmph\n", p->thread_id); 5268 5269 t->ip = ip_next[t->hit]; 5270 } 5271 5272 static inline void 5273 instr_jmp_miss_exec(struct rte_swx_pipeline *p) 5274 { 5275 struct thread *t = &p->threads[p->thread_id]; 5276 struct instruction *ip = t->ip; 5277 struct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1}; 5278 5279 TRACE("[Thread %2u] jmpnh\n", p->thread_id); 5280 5281 t->ip = ip_next[t->hit]; 5282 } 5283 5284 static inline void 5285 instr_jmp_action_hit_exec(struct rte_swx_pipeline *p) 5286 { 5287 struct thread *t = &p->threads[p->thread_id]; 5288 struct instruction *ip = t->ip; 5289 5290 TRACE("[Thread %2u] jmpa\n", p->thread_id); 5291 5292 t->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1); 5293 } 5294 5295 static inline void 5296 instr_jmp_action_miss_exec(struct rte_swx_pipeline *p) 5297 { 5298 struct thread *t = &p->threads[p->thread_id]; 5299 struct instruction *ip = t->ip; 5300 5301 TRACE("[Thread %2u] jmpna\n", p->thread_id); 5302 5303 t->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip; 5304 } 5305 5306 static inline void 5307 instr_jmp_eq_exec(struct rte_swx_pipeline *p) 5308 { 5309 struct thread *t = &p->threads[p->thread_id]; 5310 struct instruction *ip = t->ip; 5311 5312 TRACE("[Thread %2u] jmpeq\n", p->thread_id); 5313 5314 JMP_CMP(t, ip, ==); 5315 } 5316 5317 static inline void 5318 instr_jmp_eq_mh_exec(struct rte_swx_pipeline *p) 5319 { 5320 struct thread *t = &p->threads[p->thread_id]; 5321 struct instruction *ip = t->ip; 5322 5323 TRACE("[Thread %2u] jmpeq (mh)\n", p->thread_id); 5324 5325 JMP_CMP_MH(t, ip, ==); 5326 } 5327 5328 static inline void 5329 instr_jmp_eq_hm_exec(struct rte_swx_pipeline *p) 5330 { 5331 struct thread *t = &p->threads[p->thread_id]; 5332 struct instruction *ip = t->ip; 5333 5334 TRACE("[Thread %2u] jmpeq (hm)\n", p->thread_id); 5335 5336 JMP_CMP_HM(t, ip, ==); 5337 } 5338 5339 static inline void 5340 instr_jmp_eq_hh_exec(struct rte_swx_pipeline *p) 5341 { 5342 struct thread *t = &p->threads[p->thread_id]; 5343 struct instruction *ip = t->ip; 5344 5345 TRACE("[Thread %2u] jmpeq (hh)\n", p->thread_id); 5346 5347 JMP_CMP_HH_FAST(t, ip, ==); 5348 } 5349 5350 static inline void 5351 instr_jmp_eq_i_exec(struct rte_swx_pipeline *p) 5352 { 5353 struct thread *t = &p->threads[p->thread_id]; 5354 struct instruction *ip = t->ip; 5355 5356 TRACE("[Thread %2u] jmpeq (i)\n", p->thread_id); 5357 5358 JMP_CMP_I(t, ip, ==); 5359 } 5360 5361 static inline void 5362 instr_jmp_neq_exec(struct rte_swx_pipeline *p) 5363 { 5364 struct thread *t = &p->threads[p->thread_id]; 5365 struct instruction *ip = t->ip; 5366 5367 TRACE("[Thread %2u] jmpneq\n", p->thread_id); 5368 5369 JMP_CMP(t, ip, !=); 5370 } 5371 5372 static inline void 5373 instr_jmp_neq_mh_exec(struct rte_swx_pipeline *p) 5374 { 5375 struct thread *t = &p->threads[p->thread_id]; 5376 struct instruction *ip = t->ip; 5377 5378 TRACE("[Thread %2u] jmpneq (mh)\n", p->thread_id); 5379 5380 JMP_CMP_MH(t, ip, !=); 5381 } 5382 5383 static inline void 5384 instr_jmp_neq_hm_exec(struct rte_swx_pipeline *p) 5385 { 5386 struct thread *t = &p->threads[p->thread_id]; 5387 struct instruction *ip = t->ip; 5388 5389 TRACE("[Thread %2u] jmpneq (hm)\n", p->thread_id); 5390 5391 JMP_CMP_HM(t, ip, !=); 5392 } 5393 5394 static inline void 5395 instr_jmp_neq_hh_exec(struct rte_swx_pipeline *p) 5396 { 5397 struct thread *t = &p->threads[p->thread_id]; 5398 struct instruction *ip = t->ip; 5399 5400 TRACE("[Thread %2u] jmpneq (hh)\n", p->thread_id); 5401 5402 JMP_CMP_HH_FAST(t, ip, !=); 5403 } 5404 5405 static inline void 5406 instr_jmp_neq_i_exec(struct rte_swx_pipeline *p) 5407 { 5408 struct thread *t = &p->threads[p->thread_id]; 5409 struct instruction *ip = t->ip; 5410 5411 TRACE("[Thread %2u] jmpneq (i)\n", p->thread_id); 5412 5413 JMP_CMP_I(t, ip, !=); 5414 } 5415 5416 static inline void 5417 instr_jmp_lt_exec(struct rte_swx_pipeline *p) 5418 { 5419 struct thread *t = &p->threads[p->thread_id]; 5420 struct instruction *ip = t->ip; 5421 5422 TRACE("[Thread %2u] jmplt\n", p->thread_id); 5423 5424 JMP_CMP(t, ip, <); 5425 } 5426 5427 static inline void 5428 instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p) 5429 { 5430 struct thread *t = &p->threads[p->thread_id]; 5431 struct instruction *ip = t->ip; 5432 5433 TRACE("[Thread %2u] jmplt (mh)\n", p->thread_id); 5434 5435 JMP_CMP_MH(t, ip, <); 5436 } 5437 5438 static inline void 5439 instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p) 5440 { 5441 struct thread *t = &p->threads[p->thread_id]; 5442 struct instruction *ip = t->ip; 5443 5444 TRACE("[Thread %2u] jmplt (hm)\n", p->thread_id); 5445 5446 JMP_CMP_HM(t, ip, <); 5447 } 5448 5449 static inline void 5450 instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p) 5451 { 5452 struct thread *t = &p->threads[p->thread_id]; 5453 struct instruction *ip = t->ip; 5454 5455 TRACE("[Thread %2u] jmplt (hh)\n", p->thread_id); 5456 5457 JMP_CMP_HH(t, ip, <); 5458 } 5459 5460 static inline void 5461 instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p) 5462 { 5463 struct thread *t = &p->threads[p->thread_id]; 5464 struct instruction *ip = t->ip; 5465 5466 TRACE("[Thread %2u] jmplt (mi)\n", p->thread_id); 5467 5468 JMP_CMP_MI(t, ip, <); 5469 } 5470 5471 static inline void 5472 instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p) 5473 { 5474 struct thread *t = &p->threads[p->thread_id]; 5475 struct instruction *ip = t->ip; 5476 5477 TRACE("[Thread %2u] jmplt (hi)\n", p->thread_id); 5478 5479 JMP_CMP_HI(t, ip, <); 5480 } 5481 5482 static inline void 5483 instr_jmp_gt_exec(struct rte_swx_pipeline *p) 5484 { 5485 struct thread *t = &p->threads[p->thread_id]; 5486 struct instruction *ip = t->ip; 5487 5488 TRACE("[Thread %2u] jmpgt\n", p->thread_id); 5489 5490 JMP_CMP(t, ip, >); 5491 } 5492 5493 static inline void 5494 instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p) 5495 { 5496 struct thread *t = &p->threads[p->thread_id]; 5497 struct instruction *ip = t->ip; 5498 5499 TRACE("[Thread %2u] jmpgt (mh)\n", p->thread_id); 5500 5501 JMP_CMP_MH(t, ip, >); 5502 } 5503 5504 static inline void 5505 instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p) 5506 { 5507 struct thread *t = &p->threads[p->thread_id]; 5508 struct instruction *ip = t->ip; 5509 5510 TRACE("[Thread %2u] jmpgt (hm)\n", p->thread_id); 5511 5512 JMP_CMP_HM(t, ip, >); 5513 } 5514 5515 static inline void 5516 instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p) 5517 { 5518 struct thread *t = &p->threads[p->thread_id]; 5519 struct instruction *ip = t->ip; 5520 5521 TRACE("[Thread %2u] jmpgt (hh)\n", p->thread_id); 5522 5523 JMP_CMP_HH(t, ip, >); 5524 } 5525 5526 static inline void 5527 instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p) 5528 { 5529 struct thread *t = &p->threads[p->thread_id]; 5530 struct instruction *ip = t->ip; 5531 5532 TRACE("[Thread %2u] jmpgt (mi)\n", p->thread_id); 5533 5534 JMP_CMP_MI(t, ip, >); 5535 } 5536 5537 static inline void 5538 instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p) 5539 { 5540 struct thread *t = &p->threads[p->thread_id]; 5541 struct instruction *ip = t->ip; 5542 5543 TRACE("[Thread %2u] jmpgt (hi)\n", p->thread_id); 5544 5545 JMP_CMP_HI(t, ip, >); 5546 } 5547 5548 /* 5549 * return. 5550 */ 5551 static int 5552 instr_return_translate(struct rte_swx_pipeline *p __rte_unused, 5553 struct action *action, 5554 char **tokens __rte_unused, 5555 int n_tokens, 5556 struct instruction *instr, 5557 struct instruction_data *data __rte_unused) 5558 { 5559 CHECK(action, EINVAL); 5560 CHECK(n_tokens == 1, EINVAL); 5561 5562 instr->type = INSTR_RETURN; 5563 return 0; 5564 } 5565 5566 static inline void 5567 instr_return_exec(struct rte_swx_pipeline *p) 5568 { 5569 struct thread *t = &p->threads[p->thread_id]; 5570 5571 TRACE("[Thread %2u] return\n", p->thread_id); 5572 5573 t->ip = t->ret; 5574 } 5575 5576 static int 5577 instr_translate(struct rte_swx_pipeline *p, 5578 struct action *action, 5579 char *string, 5580 struct instruction *instr, 5581 struct instruction_data *data) 5582 { 5583 char *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX]; 5584 int n_tokens = 0, tpos = 0; 5585 5586 /* Parse the instruction string into tokens. */ 5587 for ( ; ; ) { 5588 char *token; 5589 5590 token = strtok_r(string, " \t\v", &string); 5591 if (!token) 5592 break; 5593 5594 CHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL); 5595 CHECK_NAME(token, EINVAL); 5596 5597 tokens[n_tokens] = token; 5598 n_tokens++; 5599 } 5600 5601 CHECK(n_tokens, EINVAL); 5602 5603 /* Handle the optional instruction label. */ 5604 if ((n_tokens >= 2) && !strcmp(tokens[1], ":")) { 5605 strcpy(data->label, tokens[0]); 5606 5607 tpos += 2; 5608 CHECK(n_tokens - tpos, EINVAL); 5609 } 5610 5611 /* Identify the instruction type. */ 5612 if (!strcmp(tokens[tpos], "rx")) 5613 return instr_rx_translate(p, 5614 action, 5615 &tokens[tpos], 5616 n_tokens - tpos, 5617 instr, 5618 data); 5619 5620 if (!strcmp(tokens[tpos], "tx")) 5621 return instr_tx_translate(p, 5622 action, 5623 &tokens[tpos], 5624 n_tokens - tpos, 5625 instr, 5626 data); 5627 5628 if (!strcmp(tokens[tpos], "drop")) 5629 return instr_drop_translate(p, 5630 action, 5631 &tokens[tpos], 5632 n_tokens - tpos, 5633 instr, 5634 data); 5635 5636 if (!strcmp(tokens[tpos], "extract")) 5637 return instr_hdr_extract_translate(p, 5638 action, 5639 &tokens[tpos], 5640 n_tokens - tpos, 5641 instr, 5642 data); 5643 5644 if (!strcmp(tokens[tpos], "lookahead")) 5645 return instr_hdr_lookahead_translate(p, 5646 action, 5647 &tokens[tpos], 5648 n_tokens - tpos, 5649 instr, 5650 data); 5651 5652 if (!strcmp(tokens[tpos], "emit")) 5653 return instr_hdr_emit_translate(p, 5654 action, 5655 &tokens[tpos], 5656 n_tokens - tpos, 5657 instr, 5658 data); 5659 5660 if (!strcmp(tokens[tpos], "validate")) 5661 return instr_hdr_validate_translate(p, 5662 action, 5663 &tokens[tpos], 5664 n_tokens - tpos, 5665 instr, 5666 data); 5667 5668 if (!strcmp(tokens[tpos], "invalidate")) 5669 return instr_hdr_invalidate_translate(p, 5670 action, 5671 &tokens[tpos], 5672 n_tokens - tpos, 5673 instr, 5674 data); 5675 5676 if (!strcmp(tokens[tpos], "mov")) 5677 return instr_mov_translate(p, 5678 action, 5679 &tokens[tpos], 5680 n_tokens - tpos, 5681 instr, 5682 data); 5683 5684 if (!strcmp(tokens[tpos], "add")) 5685 return instr_alu_add_translate(p, 5686 action, 5687 &tokens[tpos], 5688 n_tokens - tpos, 5689 instr, 5690 data); 5691 5692 if (!strcmp(tokens[tpos], "sub")) 5693 return instr_alu_sub_translate(p, 5694 action, 5695 &tokens[tpos], 5696 n_tokens - tpos, 5697 instr, 5698 data); 5699 5700 if (!strcmp(tokens[tpos], "ckadd")) 5701 return instr_alu_ckadd_translate(p, 5702 action, 5703 &tokens[tpos], 5704 n_tokens - tpos, 5705 instr, 5706 data); 5707 5708 if (!strcmp(tokens[tpos], "cksub")) 5709 return instr_alu_cksub_translate(p, 5710 action, 5711 &tokens[tpos], 5712 n_tokens - tpos, 5713 instr, 5714 data); 5715 5716 if (!strcmp(tokens[tpos], "and")) 5717 return instr_alu_and_translate(p, 5718 action, 5719 &tokens[tpos], 5720 n_tokens - tpos, 5721 instr, 5722 data); 5723 5724 if (!strcmp(tokens[tpos], "or")) 5725 return instr_alu_or_translate(p, 5726 action, 5727 &tokens[tpos], 5728 n_tokens - tpos, 5729 instr, 5730 data); 5731 5732 if (!strcmp(tokens[tpos], "xor")) 5733 return instr_alu_xor_translate(p, 5734 action, 5735 &tokens[tpos], 5736 n_tokens - tpos, 5737 instr, 5738 data); 5739 5740 if (!strcmp(tokens[tpos], "shl")) 5741 return instr_alu_shl_translate(p, 5742 action, 5743 &tokens[tpos], 5744 n_tokens - tpos, 5745 instr, 5746 data); 5747 5748 if (!strcmp(tokens[tpos], "shr")) 5749 return instr_alu_shr_translate(p, 5750 action, 5751 &tokens[tpos], 5752 n_tokens - tpos, 5753 instr, 5754 data); 5755 5756 if (!strcmp(tokens[tpos], "regprefetch")) 5757 return instr_regprefetch_translate(p, 5758 action, 5759 &tokens[tpos], 5760 n_tokens - tpos, 5761 instr, 5762 data); 5763 5764 if (!strcmp(tokens[tpos], "regrd")) 5765 return instr_regrd_translate(p, 5766 action, 5767 &tokens[tpos], 5768 n_tokens - tpos, 5769 instr, 5770 data); 5771 5772 if (!strcmp(tokens[tpos], "regwr")) 5773 return instr_regwr_translate(p, 5774 action, 5775 &tokens[tpos], 5776 n_tokens - tpos, 5777 instr, 5778 data); 5779 5780 if (!strcmp(tokens[tpos], "regadd")) 5781 return instr_regadd_translate(p, 5782 action, 5783 &tokens[tpos], 5784 n_tokens - tpos, 5785 instr, 5786 data); 5787 5788 if (!strcmp(tokens[tpos], "metprefetch")) 5789 return instr_metprefetch_translate(p, 5790 action, 5791 &tokens[tpos], 5792 n_tokens - tpos, 5793 instr, 5794 data); 5795 5796 if (!strcmp(tokens[tpos], "meter")) 5797 return instr_meter_translate(p, 5798 action, 5799 &tokens[tpos], 5800 n_tokens - tpos, 5801 instr, 5802 data); 5803 5804 if (!strcmp(tokens[tpos], "table")) 5805 return instr_table_translate(p, 5806 action, 5807 &tokens[tpos], 5808 n_tokens - tpos, 5809 instr, 5810 data); 5811 5812 if (!strcmp(tokens[tpos], "learn")) 5813 return instr_learn_translate(p, 5814 action, 5815 &tokens[tpos], 5816 n_tokens - tpos, 5817 instr, 5818 data); 5819 5820 if (!strcmp(tokens[tpos], "forget")) 5821 return instr_forget_translate(p, 5822 action, 5823 &tokens[tpos], 5824 n_tokens - tpos, 5825 instr, 5826 data); 5827 5828 if (!strcmp(tokens[tpos], "extern")) 5829 return instr_extern_translate(p, 5830 action, 5831 &tokens[tpos], 5832 n_tokens - tpos, 5833 instr, 5834 data); 5835 5836 if (!strcmp(tokens[tpos], "jmp")) 5837 return instr_jmp_translate(p, 5838 action, 5839 &tokens[tpos], 5840 n_tokens - tpos, 5841 instr, 5842 data); 5843 5844 if (!strcmp(tokens[tpos], "jmpv")) 5845 return instr_jmp_valid_translate(p, 5846 action, 5847 &tokens[tpos], 5848 n_tokens - tpos, 5849 instr, 5850 data); 5851 5852 if (!strcmp(tokens[tpos], "jmpnv")) 5853 return instr_jmp_invalid_translate(p, 5854 action, 5855 &tokens[tpos], 5856 n_tokens - tpos, 5857 instr, 5858 data); 5859 5860 if (!strcmp(tokens[tpos], "jmph")) 5861 return instr_jmp_hit_translate(p, 5862 action, 5863 &tokens[tpos], 5864 n_tokens - tpos, 5865 instr, 5866 data); 5867 5868 if (!strcmp(tokens[tpos], "jmpnh")) 5869 return instr_jmp_miss_translate(p, 5870 action, 5871 &tokens[tpos], 5872 n_tokens - tpos, 5873 instr, 5874 data); 5875 5876 if (!strcmp(tokens[tpos], "jmpa")) 5877 return instr_jmp_action_hit_translate(p, 5878 action, 5879 &tokens[tpos], 5880 n_tokens - tpos, 5881 instr, 5882 data); 5883 5884 if (!strcmp(tokens[tpos], "jmpna")) 5885 return instr_jmp_action_miss_translate(p, 5886 action, 5887 &tokens[tpos], 5888 n_tokens - tpos, 5889 instr, 5890 data); 5891 5892 if (!strcmp(tokens[tpos], "jmpeq")) 5893 return instr_jmp_eq_translate(p, 5894 action, 5895 &tokens[tpos], 5896 n_tokens - tpos, 5897 instr, 5898 data); 5899 5900 if (!strcmp(tokens[tpos], "jmpneq")) 5901 return instr_jmp_neq_translate(p, 5902 action, 5903 &tokens[tpos], 5904 n_tokens - tpos, 5905 instr, 5906 data); 5907 5908 if (!strcmp(tokens[tpos], "jmplt")) 5909 return instr_jmp_lt_translate(p, 5910 action, 5911 &tokens[tpos], 5912 n_tokens - tpos, 5913 instr, 5914 data); 5915 5916 if (!strcmp(tokens[tpos], "jmpgt")) 5917 return instr_jmp_gt_translate(p, 5918 action, 5919 &tokens[tpos], 5920 n_tokens - tpos, 5921 instr, 5922 data); 5923 5924 if (!strcmp(tokens[tpos], "return")) 5925 return instr_return_translate(p, 5926 action, 5927 &tokens[tpos], 5928 n_tokens - tpos, 5929 instr, 5930 data); 5931 5932 return -EINVAL; 5933 } 5934 5935 static struct instruction_data * 5936 label_find(struct instruction_data *data, uint32_t n, const char *label) 5937 { 5938 uint32_t i; 5939 5940 for (i = 0; i < n; i++) 5941 if (!strcmp(label, data[i].label)) 5942 return &data[i]; 5943 5944 return NULL; 5945 } 5946 5947 static uint32_t 5948 label_is_used(struct instruction_data *data, uint32_t n, const char *label) 5949 { 5950 uint32_t count = 0, i; 5951 5952 if (!label[0]) 5953 return 0; 5954 5955 for (i = 0; i < n; i++) 5956 if (!strcmp(label, data[i].jmp_label)) 5957 count++; 5958 5959 return count; 5960 } 5961 5962 static int 5963 instr_label_check(struct instruction_data *instruction_data, 5964 uint32_t n_instructions) 5965 { 5966 uint32_t i; 5967 5968 /* Check that all instruction labels are unique. */ 5969 for (i = 0; i < n_instructions; i++) { 5970 struct instruction_data *data = &instruction_data[i]; 5971 char *label = data->label; 5972 uint32_t j; 5973 5974 if (!label[0]) 5975 continue; 5976 5977 for (j = i + 1; j < n_instructions; j++) 5978 CHECK(strcmp(label, instruction_data[j].label), EINVAL); 5979 } 5980 5981 /* Get users for each instruction label. */ 5982 for (i = 0; i < n_instructions; i++) { 5983 struct instruction_data *data = &instruction_data[i]; 5984 char *label = data->label; 5985 5986 data->n_users = label_is_used(instruction_data, 5987 n_instructions, 5988 label); 5989 } 5990 5991 return 0; 5992 } 5993 5994 static int 5995 instr_jmp_resolve(struct instruction *instructions, 5996 struct instruction_data *instruction_data, 5997 uint32_t n_instructions) 5998 { 5999 uint32_t i; 6000 6001 for (i = 0; i < n_instructions; i++) { 6002 struct instruction *instr = &instructions[i]; 6003 struct instruction_data *data = &instruction_data[i]; 6004 struct instruction_data *found; 6005 6006 if (!instruction_is_jmp(instr)) 6007 continue; 6008 6009 found = label_find(instruction_data, 6010 n_instructions, 6011 data->jmp_label); 6012 CHECK(found, EINVAL); 6013 6014 instr->jmp.ip = &instructions[found - instruction_data]; 6015 } 6016 6017 return 0; 6018 } 6019 6020 static int 6021 instr_verify(struct rte_swx_pipeline *p __rte_unused, 6022 struct action *a, 6023 struct instruction *instr, 6024 struct instruction_data *data __rte_unused, 6025 uint32_t n_instructions) 6026 { 6027 if (!a) { 6028 enum instruction_type type; 6029 uint32_t i; 6030 6031 /* Check that the first instruction is rx. */ 6032 CHECK(instr[0].type == INSTR_RX, EINVAL); 6033 6034 /* Check that there is at least one tx instruction. */ 6035 for (i = 0; i < n_instructions; i++) { 6036 type = instr[i].type; 6037 6038 if (instruction_is_tx(type)) 6039 break; 6040 } 6041 CHECK(i < n_instructions, EINVAL); 6042 6043 /* Check that the last instruction is either tx or unconditional 6044 * jump. 6045 */ 6046 type = instr[n_instructions - 1].type; 6047 CHECK(instruction_is_tx(type) || (type == INSTR_JMP), EINVAL); 6048 } 6049 6050 if (a) { 6051 enum instruction_type type; 6052 uint32_t i; 6053 6054 /* Check that there is at least one return or tx instruction. */ 6055 for (i = 0; i < n_instructions; i++) { 6056 type = instr[i].type; 6057 6058 if ((type == INSTR_RETURN) || instruction_is_tx(type)) 6059 break; 6060 } 6061 CHECK(i < n_instructions, EINVAL); 6062 } 6063 6064 return 0; 6065 } 6066 6067 static uint32_t 6068 instr_compact(struct instruction *instructions, 6069 struct instruction_data *instruction_data, 6070 uint32_t n_instructions) 6071 { 6072 uint32_t i, pos = 0; 6073 6074 /* Eliminate the invalid instructions that have been optimized out. */ 6075 for (i = 0; i < n_instructions; i++) { 6076 struct instruction *instr = &instructions[i]; 6077 struct instruction_data *data = &instruction_data[i]; 6078 6079 if (data->invalid) 6080 continue; 6081 6082 if (i != pos) { 6083 memcpy(&instructions[pos], instr, sizeof(*instr)); 6084 memcpy(&instruction_data[pos], data, sizeof(*data)); 6085 } 6086 6087 pos++; 6088 } 6089 6090 return pos; 6091 } 6092 6093 static int 6094 instr_pattern_extract_many_search(struct instruction *instr, 6095 struct instruction_data *data, 6096 uint32_t n_instr, 6097 uint32_t *n_pattern_instr) 6098 { 6099 uint32_t i; 6100 6101 for (i = 0; i < n_instr; i++) { 6102 if (data[i].invalid) 6103 break; 6104 6105 if (instr[i].type != INSTR_HDR_EXTRACT) 6106 break; 6107 6108 if (i == RTE_DIM(instr->io.hdr.header_id)) 6109 break; 6110 6111 if (i && data[i].n_users) 6112 break; 6113 } 6114 6115 if (i < 2) 6116 return 0; 6117 6118 *n_pattern_instr = i; 6119 return 1; 6120 } 6121 6122 static void 6123 instr_pattern_extract_many_replace(struct instruction *instr, 6124 struct instruction_data *data, 6125 uint32_t n_instr) 6126 { 6127 uint32_t i; 6128 6129 for (i = 1; i < n_instr; i++) { 6130 instr[0].type++; 6131 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0]; 6132 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0]; 6133 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0]; 6134 6135 data[i].invalid = 1; 6136 } 6137 } 6138 6139 static uint32_t 6140 instr_pattern_extract_many_optimize(struct instruction *instructions, 6141 struct instruction_data *instruction_data, 6142 uint32_t n_instructions) 6143 { 6144 uint32_t i; 6145 6146 for (i = 0; i < n_instructions; ) { 6147 struct instruction *instr = &instructions[i]; 6148 struct instruction_data *data = &instruction_data[i]; 6149 uint32_t n_instr = 0; 6150 int detected; 6151 6152 /* Extract many. */ 6153 detected = instr_pattern_extract_many_search(instr, 6154 data, 6155 n_instructions - i, 6156 &n_instr); 6157 if (detected) { 6158 instr_pattern_extract_many_replace(instr, 6159 data, 6160 n_instr); 6161 i += n_instr; 6162 continue; 6163 } 6164 6165 /* No pattern starting at the current instruction. */ 6166 i++; 6167 } 6168 6169 /* Eliminate the invalid instructions that have been optimized out. */ 6170 n_instructions = instr_compact(instructions, 6171 instruction_data, 6172 n_instructions); 6173 6174 return n_instructions; 6175 } 6176 6177 static int 6178 instr_pattern_emit_many_tx_search(struct instruction *instr, 6179 struct instruction_data *data, 6180 uint32_t n_instr, 6181 uint32_t *n_pattern_instr) 6182 { 6183 uint32_t i; 6184 6185 for (i = 0; i < n_instr; i++) { 6186 if (data[i].invalid) 6187 break; 6188 6189 if (instr[i].type != INSTR_HDR_EMIT) 6190 break; 6191 6192 if (i == RTE_DIM(instr->io.hdr.header_id)) 6193 break; 6194 6195 if (i && data[i].n_users) 6196 break; 6197 } 6198 6199 if (!i) 6200 return 0; 6201 6202 if (!instruction_is_tx(instr[i].type)) 6203 return 0; 6204 6205 if (data[i].n_users) 6206 return 0; 6207 6208 i++; 6209 6210 *n_pattern_instr = i; 6211 return 1; 6212 } 6213 6214 static void 6215 instr_pattern_emit_many_tx_replace(struct instruction *instr, 6216 struct instruction_data *data, 6217 uint32_t n_instr) 6218 { 6219 uint32_t i; 6220 6221 /* Any emit instruction in addition to the first one. */ 6222 for (i = 1; i < n_instr - 1; i++) { 6223 instr[0].type++; 6224 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0]; 6225 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0]; 6226 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0]; 6227 6228 data[i].invalid = 1; 6229 } 6230 6231 /* The TX instruction is the last one in the pattern. */ 6232 instr[0].type++; 6233 instr[0].io.io.offset = instr[i].io.io.offset; 6234 instr[0].io.io.n_bits = instr[i].io.io.n_bits; 6235 data[i].invalid = 1; 6236 } 6237 6238 static uint32_t 6239 instr_pattern_emit_many_tx_optimize(struct instruction *instructions, 6240 struct instruction_data *instruction_data, 6241 uint32_t n_instructions) 6242 { 6243 uint32_t i; 6244 6245 for (i = 0; i < n_instructions; ) { 6246 struct instruction *instr = &instructions[i]; 6247 struct instruction_data *data = &instruction_data[i]; 6248 uint32_t n_instr = 0; 6249 int detected; 6250 6251 /* Emit many + TX. */ 6252 detected = instr_pattern_emit_many_tx_search(instr, 6253 data, 6254 n_instructions - i, 6255 &n_instr); 6256 if (detected) { 6257 instr_pattern_emit_many_tx_replace(instr, 6258 data, 6259 n_instr); 6260 i += n_instr; 6261 continue; 6262 } 6263 6264 /* No pattern starting at the current instruction. */ 6265 i++; 6266 } 6267 6268 /* Eliminate the invalid instructions that have been optimized out. */ 6269 n_instructions = instr_compact(instructions, 6270 instruction_data, 6271 n_instructions); 6272 6273 return n_instructions; 6274 } 6275 6276 static uint32_t 6277 action_arg_src_mov_count(struct action *a, 6278 uint32_t arg_id, 6279 struct instruction *instructions, 6280 struct instruction_data *instruction_data, 6281 uint32_t n_instructions); 6282 6283 static int 6284 instr_pattern_mov_all_validate_search(struct rte_swx_pipeline *p, 6285 struct action *a, 6286 struct instruction *instr, 6287 struct instruction_data *data, 6288 uint32_t n_instr, 6289 struct instruction *instructions, 6290 struct instruction_data *instruction_data, 6291 uint32_t n_instructions, 6292 uint32_t *n_pattern_instr) 6293 { 6294 struct header *h; 6295 uint32_t src_field_id, i, j; 6296 6297 /* Prerequisites. */ 6298 if (!a || !a->st) 6299 return 0; 6300 6301 /* First instruction: MOV_HM. */ 6302 if (data[0].invalid || (instr[0].type != INSTR_MOV_HM)) 6303 return 0; 6304 6305 h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id); 6306 if (!h || h->st->var_size) 6307 return 0; 6308 6309 for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++) 6310 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8) 6311 break; 6312 6313 if (src_field_id == a->st->n_fields) 6314 return 0; 6315 6316 if (instr[0].mov.dst.offset || 6317 (instr[0].mov.dst.n_bits != h->st->fields[0].n_bits) || 6318 instr[0].mov.src.struct_id || 6319 (instr[0].mov.src.n_bits != a->st->fields[src_field_id].n_bits) || 6320 (instr[0].mov.dst.n_bits != instr[0].mov.src.n_bits)) 6321 return 0; 6322 6323 if ((n_instr < h->st->n_fields + 1) || 6324 (a->st->n_fields < src_field_id + h->st->n_fields + 1)) 6325 return 0; 6326 6327 /* Subsequent instructions: MOV_HM. */ 6328 for (i = 1; i < h->st->n_fields; i++) 6329 if (data[i].invalid || 6330 data[i].n_users || 6331 (instr[i].type != INSTR_MOV_HM) || 6332 (instr[i].mov.dst.struct_id != h->struct_id) || 6333 (instr[i].mov.dst.offset != h->st->fields[i].offset / 8) || 6334 (instr[i].mov.dst.n_bits != h->st->fields[i].n_bits) || 6335 instr[i].mov.src.struct_id || 6336 (instr[i].mov.src.offset != a->st->fields[src_field_id + i].offset / 8) || 6337 (instr[i].mov.src.n_bits != a->st->fields[src_field_id + i].n_bits) || 6338 (instr[i].mov.dst.n_bits != instr[i].mov.src.n_bits)) 6339 return 0; 6340 6341 /* Last instruction: HDR_VALIDATE. */ 6342 if ((instr[i].type != INSTR_HDR_VALIDATE) || 6343 (instr[i].valid.header_id != h->id)) 6344 return 0; 6345 6346 /* Check that none of the action args that are used as source for this 6347 * DMA transfer are not used as source in any other mov instruction. 6348 */ 6349 for (j = src_field_id; j < src_field_id + h->st->n_fields; j++) { 6350 uint32_t n_users; 6351 6352 n_users = action_arg_src_mov_count(a, 6353 j, 6354 instructions, 6355 instruction_data, 6356 n_instructions); 6357 if (n_users > 1) 6358 return 0; 6359 } 6360 6361 *n_pattern_instr = 1 + i; 6362 return 1; 6363 } 6364 6365 static void 6366 instr_pattern_mov_all_validate_replace(struct rte_swx_pipeline *p, 6367 struct action *a, 6368 struct instruction *instr, 6369 struct instruction_data *data, 6370 uint32_t n_instr) 6371 { 6372 struct header *h; 6373 uint32_t src_field_id, src_offset, i; 6374 6375 /* Read from the instructions before they are modified. */ 6376 h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id); 6377 if (!h) 6378 return; 6379 6380 for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++) 6381 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8) 6382 break; 6383 6384 if (src_field_id == a->st->n_fields) 6385 return; 6386 6387 src_offset = instr[0].mov.src.offset; 6388 6389 /* Modify the instructions. */ 6390 instr[0].type = INSTR_DMA_HT; 6391 instr[0].dma.dst.header_id[0] = h->id; 6392 instr[0].dma.dst.struct_id[0] = h->struct_id; 6393 instr[0].dma.src.offset[0] = (uint8_t)src_offset; 6394 instr[0].dma.n_bytes[0] = h->st->n_bits / 8; 6395 6396 for (i = 1; i < n_instr; i++) 6397 data[i].invalid = 1; 6398 6399 /* Update the endianness of the action arguments to header endianness. */ 6400 for (i = 0; i < h->st->n_fields; i++) 6401 a->args_endianness[src_field_id + i] = 1; 6402 } 6403 6404 static uint32_t 6405 instr_pattern_mov_all_validate_optimize(struct rte_swx_pipeline *p, 6406 struct action *a, 6407 struct instruction *instructions, 6408 struct instruction_data *instruction_data, 6409 uint32_t n_instructions) 6410 { 6411 uint32_t i; 6412 6413 if (!a || !a->st) 6414 return n_instructions; 6415 6416 for (i = 0; i < n_instructions; ) { 6417 struct instruction *instr = &instructions[i]; 6418 struct instruction_data *data = &instruction_data[i]; 6419 uint32_t n_instr = 0; 6420 int detected; 6421 6422 /* Mov all + validate. */ 6423 detected = instr_pattern_mov_all_validate_search(p, 6424 a, 6425 instr, 6426 data, 6427 n_instructions - i, 6428 instructions, 6429 instruction_data, 6430 n_instructions, 6431 &n_instr); 6432 if (detected) { 6433 instr_pattern_mov_all_validate_replace(p, a, instr, data, n_instr); 6434 i += n_instr; 6435 continue; 6436 } 6437 6438 /* No pattern starting at the current instruction. */ 6439 i++; 6440 } 6441 6442 /* Eliminate the invalid instructions that have been optimized out. */ 6443 n_instructions = instr_compact(instructions, 6444 instruction_data, 6445 n_instructions); 6446 6447 return n_instructions; 6448 } 6449 6450 static int 6451 instr_pattern_dma_many_search(struct instruction *instr, 6452 struct instruction_data *data, 6453 uint32_t n_instr, 6454 uint32_t *n_pattern_instr) 6455 { 6456 uint32_t i; 6457 6458 for (i = 0; i < n_instr; i++) { 6459 if (data[i].invalid) 6460 break; 6461 6462 if (instr[i].type != INSTR_DMA_HT) 6463 break; 6464 6465 if (i == RTE_DIM(instr->dma.dst.header_id)) 6466 break; 6467 6468 if (i && data[i].n_users) 6469 break; 6470 } 6471 6472 if (i < 2) 6473 return 0; 6474 6475 *n_pattern_instr = i; 6476 return 1; 6477 } 6478 6479 static void 6480 instr_pattern_dma_many_replace(struct instruction *instr, 6481 struct instruction_data *data, 6482 uint32_t n_instr) 6483 { 6484 uint32_t i; 6485 6486 for (i = 1; i < n_instr; i++) { 6487 instr[0].type++; 6488 instr[0].dma.dst.header_id[i] = instr[i].dma.dst.header_id[0]; 6489 instr[0].dma.dst.struct_id[i] = instr[i].dma.dst.struct_id[0]; 6490 instr[0].dma.src.offset[i] = instr[i].dma.src.offset[0]; 6491 instr[0].dma.n_bytes[i] = instr[i].dma.n_bytes[0]; 6492 6493 data[i].invalid = 1; 6494 } 6495 } 6496 6497 static uint32_t 6498 instr_pattern_dma_many_optimize(struct instruction *instructions, 6499 struct instruction_data *instruction_data, 6500 uint32_t n_instructions) 6501 { 6502 uint32_t i; 6503 6504 for (i = 0; i < n_instructions; ) { 6505 struct instruction *instr = &instructions[i]; 6506 struct instruction_data *data = &instruction_data[i]; 6507 uint32_t n_instr = 0; 6508 int detected; 6509 6510 /* DMA many. */ 6511 detected = instr_pattern_dma_many_search(instr, 6512 data, 6513 n_instructions - i, 6514 &n_instr); 6515 if (detected) { 6516 instr_pattern_dma_many_replace(instr, data, n_instr); 6517 i += n_instr; 6518 continue; 6519 } 6520 6521 /* No pattern starting at the current instruction. */ 6522 i++; 6523 } 6524 6525 /* Eliminate the invalid instructions that have been optimized out. */ 6526 n_instructions = instr_compact(instructions, 6527 instruction_data, 6528 n_instructions); 6529 6530 return n_instructions; 6531 } 6532 6533 static uint32_t 6534 instr_optimize(struct rte_swx_pipeline *p, 6535 struct action *a, 6536 struct instruction *instructions, 6537 struct instruction_data *instruction_data, 6538 uint32_t n_instructions) 6539 { 6540 /* Extract many. */ 6541 n_instructions = instr_pattern_extract_many_optimize(instructions, 6542 instruction_data, 6543 n_instructions); 6544 6545 /* Emit many + TX. */ 6546 n_instructions = instr_pattern_emit_many_tx_optimize(instructions, 6547 instruction_data, 6548 n_instructions); 6549 6550 /* Mov all + validate. */ 6551 n_instructions = instr_pattern_mov_all_validate_optimize(p, 6552 a, 6553 instructions, 6554 instruction_data, 6555 n_instructions); 6556 6557 /* DMA many. */ 6558 n_instructions = instr_pattern_dma_many_optimize(instructions, 6559 instruction_data, 6560 n_instructions); 6561 6562 return n_instructions; 6563 } 6564 6565 static int 6566 instruction_config(struct rte_swx_pipeline *p, 6567 struct action *a, 6568 const char **instructions, 6569 uint32_t n_instructions) 6570 { 6571 struct instruction *instr = NULL; 6572 struct instruction_data *data = NULL; 6573 int err = 0; 6574 uint32_t i; 6575 6576 CHECK(n_instructions, EINVAL); 6577 CHECK(instructions, EINVAL); 6578 for (i = 0; i < n_instructions; i++) 6579 CHECK_INSTRUCTION(instructions[i], EINVAL); 6580 6581 /* Memory allocation. */ 6582 instr = calloc(n_instructions, sizeof(struct instruction)); 6583 if (!instr) { 6584 err = -ENOMEM; 6585 goto error; 6586 } 6587 6588 data = calloc(n_instructions, sizeof(struct instruction_data)); 6589 if (!data) { 6590 err = -ENOMEM; 6591 goto error; 6592 } 6593 6594 for (i = 0; i < n_instructions; i++) { 6595 char *string = strdup(instructions[i]); 6596 if (!string) { 6597 err = -ENOMEM; 6598 goto error; 6599 } 6600 6601 err = instr_translate(p, a, string, &instr[i], &data[i]); 6602 if (err) { 6603 free(string); 6604 goto error; 6605 } 6606 6607 free(string); 6608 } 6609 6610 err = instr_label_check(data, n_instructions); 6611 if (err) 6612 goto error; 6613 6614 err = instr_verify(p, a, instr, data, n_instructions); 6615 if (err) 6616 goto error; 6617 6618 n_instructions = instr_optimize(p, a, instr, data, n_instructions); 6619 6620 err = instr_jmp_resolve(instr, data, n_instructions); 6621 if (err) 6622 goto error; 6623 6624 if (a) { 6625 a->instructions = instr; 6626 a->instruction_data = data; 6627 a->n_instructions = n_instructions; 6628 } else { 6629 p->instructions = instr; 6630 p->instruction_data = data; 6631 p->n_instructions = n_instructions; 6632 } 6633 6634 return 0; 6635 6636 error: 6637 free(data); 6638 free(instr); 6639 return err; 6640 } 6641 6642 static instr_exec_t instruction_table[] = { 6643 [INSTR_RX] = instr_rx_exec, 6644 [INSTR_TX] = instr_tx_exec, 6645 [INSTR_TX_I] = instr_tx_i_exec, 6646 6647 [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec, 6648 [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec, 6649 [INSTR_HDR_EXTRACT3] = instr_hdr_extract3_exec, 6650 [INSTR_HDR_EXTRACT4] = instr_hdr_extract4_exec, 6651 [INSTR_HDR_EXTRACT5] = instr_hdr_extract5_exec, 6652 [INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec, 6653 [INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec, 6654 [INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec, 6655 [INSTR_HDR_EXTRACT_M] = instr_hdr_extract_m_exec, 6656 [INSTR_HDR_LOOKAHEAD] = instr_hdr_lookahead_exec, 6657 6658 [INSTR_HDR_EMIT] = instr_hdr_emit_exec, 6659 [INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec, 6660 [INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec, 6661 [INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec, 6662 [INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec, 6663 [INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec, 6664 [INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec, 6665 [INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec, 6666 [INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec, 6667 6668 [INSTR_HDR_VALIDATE] = instr_hdr_validate_exec, 6669 [INSTR_HDR_INVALIDATE] = instr_hdr_invalidate_exec, 6670 6671 [INSTR_MOV] = instr_mov_exec, 6672 [INSTR_MOV_MH] = instr_mov_mh_exec, 6673 [INSTR_MOV_HM] = instr_mov_hm_exec, 6674 [INSTR_MOV_HH] = instr_mov_hh_exec, 6675 [INSTR_MOV_I] = instr_mov_i_exec, 6676 6677 [INSTR_DMA_HT] = instr_dma_ht_exec, 6678 [INSTR_DMA_HT2] = instr_dma_ht2_exec, 6679 [INSTR_DMA_HT3] = instr_dma_ht3_exec, 6680 [INSTR_DMA_HT4] = instr_dma_ht4_exec, 6681 [INSTR_DMA_HT5] = instr_dma_ht5_exec, 6682 [INSTR_DMA_HT6] = instr_dma_ht6_exec, 6683 [INSTR_DMA_HT7] = instr_dma_ht7_exec, 6684 [INSTR_DMA_HT8] = instr_dma_ht8_exec, 6685 6686 [INSTR_ALU_ADD] = instr_alu_add_exec, 6687 [INSTR_ALU_ADD_MH] = instr_alu_add_mh_exec, 6688 [INSTR_ALU_ADD_HM] = instr_alu_add_hm_exec, 6689 [INSTR_ALU_ADD_HH] = instr_alu_add_hh_exec, 6690 [INSTR_ALU_ADD_MI] = instr_alu_add_mi_exec, 6691 [INSTR_ALU_ADD_HI] = instr_alu_add_hi_exec, 6692 6693 [INSTR_ALU_SUB] = instr_alu_sub_exec, 6694 [INSTR_ALU_SUB_MH] = instr_alu_sub_mh_exec, 6695 [INSTR_ALU_SUB_HM] = instr_alu_sub_hm_exec, 6696 [INSTR_ALU_SUB_HH] = instr_alu_sub_hh_exec, 6697 [INSTR_ALU_SUB_MI] = instr_alu_sub_mi_exec, 6698 [INSTR_ALU_SUB_HI] = instr_alu_sub_hi_exec, 6699 6700 [INSTR_ALU_CKADD_FIELD] = instr_alu_ckadd_field_exec, 6701 [INSTR_ALU_CKADD_STRUCT] = instr_alu_ckadd_struct_exec, 6702 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_ckadd_struct20_exec, 6703 [INSTR_ALU_CKSUB_FIELD] = instr_alu_cksub_field_exec, 6704 6705 [INSTR_ALU_AND] = instr_alu_and_exec, 6706 [INSTR_ALU_AND_MH] = instr_alu_and_mh_exec, 6707 [INSTR_ALU_AND_HM] = instr_alu_and_hm_exec, 6708 [INSTR_ALU_AND_HH] = instr_alu_and_hh_exec, 6709 [INSTR_ALU_AND_I] = instr_alu_and_i_exec, 6710 6711 [INSTR_ALU_OR] = instr_alu_or_exec, 6712 [INSTR_ALU_OR_MH] = instr_alu_or_mh_exec, 6713 [INSTR_ALU_OR_HM] = instr_alu_or_hm_exec, 6714 [INSTR_ALU_OR_HH] = instr_alu_or_hh_exec, 6715 [INSTR_ALU_OR_I] = instr_alu_or_i_exec, 6716 6717 [INSTR_ALU_XOR] = instr_alu_xor_exec, 6718 [INSTR_ALU_XOR_MH] = instr_alu_xor_mh_exec, 6719 [INSTR_ALU_XOR_HM] = instr_alu_xor_hm_exec, 6720 [INSTR_ALU_XOR_HH] = instr_alu_xor_hh_exec, 6721 [INSTR_ALU_XOR_I] = instr_alu_xor_i_exec, 6722 6723 [INSTR_ALU_SHL] = instr_alu_shl_exec, 6724 [INSTR_ALU_SHL_MH] = instr_alu_shl_mh_exec, 6725 [INSTR_ALU_SHL_HM] = instr_alu_shl_hm_exec, 6726 [INSTR_ALU_SHL_HH] = instr_alu_shl_hh_exec, 6727 [INSTR_ALU_SHL_MI] = instr_alu_shl_mi_exec, 6728 [INSTR_ALU_SHL_HI] = instr_alu_shl_hi_exec, 6729 6730 [INSTR_ALU_SHR] = instr_alu_shr_exec, 6731 [INSTR_ALU_SHR_MH] = instr_alu_shr_mh_exec, 6732 [INSTR_ALU_SHR_HM] = instr_alu_shr_hm_exec, 6733 [INSTR_ALU_SHR_HH] = instr_alu_shr_hh_exec, 6734 [INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec, 6735 [INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec, 6736 6737 [INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec, 6738 [INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec, 6739 [INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec, 6740 6741 [INSTR_REGRD_HRH] = instr_regrd_hrh_exec, 6742 [INSTR_REGRD_HRM] = instr_regrd_hrm_exec, 6743 [INSTR_REGRD_MRH] = instr_regrd_mrh_exec, 6744 [INSTR_REGRD_MRM] = instr_regrd_mrm_exec, 6745 [INSTR_REGRD_HRI] = instr_regrd_hri_exec, 6746 [INSTR_REGRD_MRI] = instr_regrd_mri_exec, 6747 6748 [INSTR_REGWR_RHH] = instr_regwr_rhh_exec, 6749 [INSTR_REGWR_RHM] = instr_regwr_rhm_exec, 6750 [INSTR_REGWR_RMH] = instr_regwr_rmh_exec, 6751 [INSTR_REGWR_RMM] = instr_regwr_rmm_exec, 6752 [INSTR_REGWR_RHI] = instr_regwr_rhi_exec, 6753 [INSTR_REGWR_RMI] = instr_regwr_rmi_exec, 6754 [INSTR_REGWR_RIH] = instr_regwr_rih_exec, 6755 [INSTR_REGWR_RIM] = instr_regwr_rim_exec, 6756 [INSTR_REGWR_RII] = instr_regwr_rii_exec, 6757 6758 [INSTR_REGADD_RHH] = instr_regadd_rhh_exec, 6759 [INSTR_REGADD_RHM] = instr_regadd_rhm_exec, 6760 [INSTR_REGADD_RMH] = instr_regadd_rmh_exec, 6761 [INSTR_REGADD_RMM] = instr_regadd_rmm_exec, 6762 [INSTR_REGADD_RHI] = instr_regadd_rhi_exec, 6763 [INSTR_REGADD_RMI] = instr_regadd_rmi_exec, 6764 [INSTR_REGADD_RIH] = instr_regadd_rih_exec, 6765 [INSTR_REGADD_RIM] = instr_regadd_rim_exec, 6766 [INSTR_REGADD_RII] = instr_regadd_rii_exec, 6767 6768 [INSTR_METPREFETCH_H] = instr_metprefetch_h_exec, 6769 [INSTR_METPREFETCH_M] = instr_metprefetch_m_exec, 6770 [INSTR_METPREFETCH_I] = instr_metprefetch_i_exec, 6771 6772 [INSTR_METER_HHM] = instr_meter_hhm_exec, 6773 [INSTR_METER_HHI] = instr_meter_hhi_exec, 6774 [INSTR_METER_HMM] = instr_meter_hmm_exec, 6775 [INSTR_METER_HMI] = instr_meter_hmi_exec, 6776 [INSTR_METER_MHM] = instr_meter_mhm_exec, 6777 [INSTR_METER_MHI] = instr_meter_mhi_exec, 6778 [INSTR_METER_MMM] = instr_meter_mmm_exec, 6779 [INSTR_METER_MMI] = instr_meter_mmi_exec, 6780 [INSTR_METER_IHM] = instr_meter_ihm_exec, 6781 [INSTR_METER_IHI] = instr_meter_ihi_exec, 6782 [INSTR_METER_IMM] = instr_meter_imm_exec, 6783 [INSTR_METER_IMI] = instr_meter_imi_exec, 6784 6785 [INSTR_TABLE] = instr_table_exec, 6786 [INSTR_TABLE_AF] = instr_table_af_exec, 6787 [INSTR_SELECTOR] = instr_selector_exec, 6788 [INSTR_LEARNER] = instr_learner_exec, 6789 [INSTR_LEARNER_AF] = instr_learner_af_exec, 6790 [INSTR_LEARNER_LEARN] = instr_learn_exec, 6791 [INSTR_LEARNER_FORGET] = instr_forget_exec, 6792 [INSTR_EXTERN_OBJ] = instr_extern_obj_exec, 6793 [INSTR_EXTERN_FUNC] = instr_extern_func_exec, 6794 6795 [INSTR_JMP] = instr_jmp_exec, 6796 [INSTR_JMP_VALID] = instr_jmp_valid_exec, 6797 [INSTR_JMP_INVALID] = instr_jmp_invalid_exec, 6798 [INSTR_JMP_HIT] = instr_jmp_hit_exec, 6799 [INSTR_JMP_MISS] = instr_jmp_miss_exec, 6800 [INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec, 6801 [INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec, 6802 6803 [INSTR_JMP_EQ] = instr_jmp_eq_exec, 6804 [INSTR_JMP_EQ_MH] = instr_jmp_eq_mh_exec, 6805 [INSTR_JMP_EQ_HM] = instr_jmp_eq_hm_exec, 6806 [INSTR_JMP_EQ_HH] = instr_jmp_eq_hh_exec, 6807 [INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec, 6808 6809 [INSTR_JMP_NEQ] = instr_jmp_neq_exec, 6810 [INSTR_JMP_NEQ_MH] = instr_jmp_neq_mh_exec, 6811 [INSTR_JMP_NEQ_HM] = instr_jmp_neq_hm_exec, 6812 [INSTR_JMP_NEQ_HH] = instr_jmp_neq_hh_exec, 6813 [INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec, 6814 6815 [INSTR_JMP_LT] = instr_jmp_lt_exec, 6816 [INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec, 6817 [INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec, 6818 [INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec, 6819 [INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec, 6820 [INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec, 6821 6822 [INSTR_JMP_GT] = instr_jmp_gt_exec, 6823 [INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec, 6824 [INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec, 6825 [INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec, 6826 [INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec, 6827 [INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec, 6828 6829 [INSTR_RETURN] = instr_return_exec, 6830 }; 6831 6832 static int 6833 instruction_table_build(struct rte_swx_pipeline *p) 6834 { 6835 p->instruction_table = calloc(RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX, 6836 sizeof(struct instr_exec_t *)); 6837 if (!p->instruction_table) 6838 return -EINVAL; 6839 6840 memcpy(p->instruction_table, instruction_table, sizeof(instruction_table)); 6841 6842 return 0; 6843 } 6844 6845 static void 6846 instruction_table_build_free(struct rte_swx_pipeline *p) 6847 { 6848 if (!p->instruction_table) 6849 return; 6850 6851 free(p->instruction_table); 6852 p->instruction_table = NULL; 6853 } 6854 6855 static void 6856 instruction_table_free(struct rte_swx_pipeline *p) 6857 { 6858 instruction_table_build_free(p); 6859 } 6860 6861 static inline void 6862 instr_exec(struct rte_swx_pipeline *p) 6863 { 6864 struct thread *t = &p->threads[p->thread_id]; 6865 struct instruction *ip = t->ip; 6866 instr_exec_t instr = p->instruction_table[ip->type]; 6867 6868 instr(p); 6869 } 6870 6871 /* 6872 * Action. 6873 */ 6874 static struct action * 6875 action_find(struct rte_swx_pipeline *p, const char *name) 6876 { 6877 struct action *elem; 6878 6879 if (!name) 6880 return NULL; 6881 6882 TAILQ_FOREACH(elem, &p->actions, node) 6883 if (strcmp(elem->name, name) == 0) 6884 return elem; 6885 6886 return NULL; 6887 } 6888 6889 static struct action * 6890 action_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 6891 { 6892 struct action *action = NULL; 6893 6894 TAILQ_FOREACH(action, &p->actions, node) 6895 if (action->id == id) 6896 return action; 6897 6898 return NULL; 6899 } 6900 6901 static struct field * 6902 action_field_find(struct action *a, const char *name) 6903 { 6904 return a->st ? struct_type_field_find(a->st, name) : NULL; 6905 } 6906 6907 static struct field * 6908 action_field_parse(struct action *action, const char *name) 6909 { 6910 if (name[0] != 't' || name[1] != '.') 6911 return NULL; 6912 6913 return action_field_find(action, &name[2]); 6914 } 6915 6916 static int 6917 action_has_nbo_args(struct action *a) 6918 { 6919 uint32_t i; 6920 6921 /* Return if the action does not have any args. */ 6922 if (!a->st) 6923 return 0; /* FALSE */ 6924 6925 for (i = 0; i < a->st->n_fields; i++) 6926 if (a->args_endianness[i]) 6927 return 1; /* TRUE */ 6928 6929 return 0; /* FALSE */ 6930 } 6931 6932 static int 6933 action_does_learning(struct action *a) 6934 { 6935 uint32_t i; 6936 6937 for (i = 0; i < a->n_instructions; i++) 6938 switch (a->instructions[i].type) { 6939 case INSTR_LEARNER_LEARN: 6940 return 1; /* TRUE */ 6941 6942 case INSTR_LEARNER_FORGET: 6943 return 1; /* TRUE */ 6944 6945 default: 6946 continue; 6947 } 6948 6949 return 0; /* FALSE */ 6950 } 6951 6952 int 6953 rte_swx_pipeline_action_config(struct rte_swx_pipeline *p, 6954 const char *name, 6955 const char *args_struct_type_name, 6956 const char **instructions, 6957 uint32_t n_instructions) 6958 { 6959 struct struct_type *args_struct_type = NULL; 6960 struct action *a; 6961 int err; 6962 6963 CHECK(p, EINVAL); 6964 6965 CHECK_NAME(name, EINVAL); 6966 CHECK(!action_find(p, name), EEXIST); 6967 6968 if (args_struct_type_name) { 6969 CHECK_NAME(args_struct_type_name, EINVAL); 6970 args_struct_type = struct_type_find(p, args_struct_type_name); 6971 CHECK(args_struct_type, EINVAL); 6972 CHECK(!args_struct_type->var_size, EINVAL); 6973 } 6974 6975 /* Node allocation. */ 6976 a = calloc(1, sizeof(struct action)); 6977 CHECK(a, ENOMEM); 6978 if (args_struct_type) { 6979 a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int)); 6980 if (!a->args_endianness) { 6981 free(a); 6982 CHECK(0, ENOMEM); 6983 } 6984 } 6985 6986 /* Node initialization. */ 6987 strcpy(a->name, name); 6988 a->st = args_struct_type; 6989 a->id = p->n_actions; 6990 6991 /* Instruction translation. */ 6992 err = instruction_config(p, a, instructions, n_instructions); 6993 if (err) { 6994 free(a->args_endianness); 6995 free(a); 6996 return err; 6997 } 6998 6999 /* Node add to tailq. */ 7000 TAILQ_INSERT_TAIL(&p->actions, a, node); 7001 p->n_actions++; 7002 7003 return 0; 7004 } 7005 7006 static int 7007 action_build(struct rte_swx_pipeline *p) 7008 { 7009 struct action *action; 7010 7011 /* p->action_instructions. */ 7012 p->action_instructions = calloc(p->n_actions, sizeof(struct instruction *)); 7013 CHECK(p->action_instructions, ENOMEM); 7014 7015 TAILQ_FOREACH(action, &p->actions, node) 7016 p->action_instructions[action->id] = action->instructions; 7017 7018 /* p->action_funcs. */ 7019 p->action_funcs = calloc(p->n_actions, sizeof(action_func_t)); 7020 CHECK(p->action_funcs, ENOMEM); 7021 7022 return 0; 7023 } 7024 7025 static void 7026 action_build_free(struct rte_swx_pipeline *p) 7027 { 7028 free(p->action_funcs); 7029 p->action_funcs = NULL; 7030 7031 free(p->action_instructions); 7032 p->action_instructions = NULL; 7033 } 7034 7035 static void 7036 action_free(struct rte_swx_pipeline *p) 7037 { 7038 action_build_free(p); 7039 7040 for ( ; ; ) { 7041 struct action *action; 7042 7043 action = TAILQ_FIRST(&p->actions); 7044 if (!action) 7045 break; 7046 7047 TAILQ_REMOVE(&p->actions, action, node); 7048 free(action->instruction_data); 7049 free(action->instructions); 7050 free(action); 7051 } 7052 } 7053 7054 static uint32_t 7055 action_arg_src_mov_count(struct action *a, 7056 uint32_t arg_id, 7057 struct instruction *instructions, 7058 struct instruction_data *instruction_data, 7059 uint32_t n_instructions) 7060 { 7061 uint32_t offset, n_users = 0, i; 7062 7063 if (!a->st || 7064 (arg_id >= a->st->n_fields) || 7065 !instructions || 7066 !instruction_data || 7067 !n_instructions) 7068 return 0; 7069 7070 offset = a->st->fields[arg_id].offset / 8; 7071 7072 for (i = 0; i < n_instructions; i++) { 7073 struct instruction *instr = &instructions[i]; 7074 struct instruction_data *data = &instruction_data[i]; 7075 7076 if (data->invalid || 7077 ((instr->type != INSTR_MOV) && (instr->type != INSTR_MOV_HM)) || 7078 instr->mov.src.struct_id || 7079 (instr->mov.src.offset != offset)) 7080 continue; 7081 7082 n_users++; 7083 } 7084 7085 return n_users; 7086 } 7087 7088 /* 7089 * Table. 7090 */ 7091 static struct table_type * 7092 table_type_find(struct rte_swx_pipeline *p, const char *name) 7093 { 7094 struct table_type *elem; 7095 7096 TAILQ_FOREACH(elem, &p->table_types, node) 7097 if (strcmp(elem->name, name) == 0) 7098 return elem; 7099 7100 return NULL; 7101 } 7102 7103 static struct table_type * 7104 table_type_resolve(struct rte_swx_pipeline *p, 7105 const char *recommended_type_name, 7106 enum rte_swx_table_match_type match_type) 7107 { 7108 struct table_type *elem; 7109 7110 /* Only consider the recommended type if the match type is correct. */ 7111 if (recommended_type_name) 7112 TAILQ_FOREACH(elem, &p->table_types, node) 7113 if (!strcmp(elem->name, recommended_type_name) && 7114 (elem->match_type == match_type)) 7115 return elem; 7116 7117 /* Ignore the recommended type and get the first element with this match 7118 * type. 7119 */ 7120 TAILQ_FOREACH(elem, &p->table_types, node) 7121 if (elem->match_type == match_type) 7122 return elem; 7123 7124 return NULL; 7125 } 7126 7127 static struct table * 7128 table_find(struct rte_swx_pipeline *p, const char *name) 7129 { 7130 struct table *elem; 7131 7132 TAILQ_FOREACH(elem, &p->tables, node) 7133 if (strcmp(elem->name, name) == 0) 7134 return elem; 7135 7136 return NULL; 7137 } 7138 7139 static struct table * 7140 table_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 7141 { 7142 struct table *table = NULL; 7143 7144 TAILQ_FOREACH(table, &p->tables, node) 7145 if (table->id == id) 7146 return table; 7147 7148 return NULL; 7149 } 7150 7151 int 7152 rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p, 7153 const char *name, 7154 enum rte_swx_table_match_type match_type, 7155 struct rte_swx_table_ops *ops) 7156 { 7157 struct table_type *elem; 7158 7159 CHECK(p, EINVAL); 7160 7161 CHECK_NAME(name, EINVAL); 7162 CHECK(!table_type_find(p, name), EEXIST); 7163 7164 CHECK(ops, EINVAL); 7165 CHECK(ops->create, EINVAL); 7166 CHECK(ops->lkp, EINVAL); 7167 CHECK(ops->free, EINVAL); 7168 7169 /* Node allocation. */ 7170 elem = calloc(1, sizeof(struct table_type)); 7171 CHECK(elem, ENOMEM); 7172 7173 /* Node initialization. */ 7174 strcpy(elem->name, name); 7175 elem->match_type = match_type; 7176 memcpy(&elem->ops, ops, sizeof(*ops)); 7177 7178 /* Node add to tailq. */ 7179 TAILQ_INSERT_TAIL(&p->table_types, elem, node); 7180 7181 return 0; 7182 } 7183 7184 static int 7185 table_match_type_resolve(struct rte_swx_match_field_params *fields, 7186 uint32_t n_fields, 7187 enum rte_swx_table_match_type *match_type) 7188 { 7189 uint32_t n_fields_em = 0, n_fields_lpm = 0, i; 7190 7191 for (i = 0; i < n_fields; i++) { 7192 struct rte_swx_match_field_params *f = &fields[i]; 7193 7194 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT) 7195 n_fields_em++; 7196 7197 if (f->match_type == RTE_SWX_TABLE_MATCH_LPM) 7198 n_fields_lpm++; 7199 } 7200 7201 if ((n_fields_lpm > 1) || 7202 (n_fields_lpm && (n_fields_em != n_fields - 1))) 7203 return -EINVAL; 7204 7205 *match_type = (n_fields_em == n_fields) ? 7206 RTE_SWX_TABLE_MATCH_EXACT : 7207 RTE_SWX_TABLE_MATCH_WILDCARD; 7208 7209 return 0; 7210 } 7211 7212 static int 7213 table_match_fields_check(struct rte_swx_pipeline *p, 7214 struct rte_swx_pipeline_table_params *params, 7215 struct header **header) 7216 { 7217 struct header *h0 = NULL; 7218 struct field *hf, *mf; 7219 uint32_t *offset = NULL, i; 7220 int status = 0; 7221 7222 /* Return if no match fields. */ 7223 if (!params->n_fields) { 7224 if (params->fields) { 7225 status = -EINVAL; 7226 goto end; 7227 } 7228 7229 if (header) 7230 *header = NULL; 7231 7232 return 0; 7233 } 7234 7235 /* Memory allocation. */ 7236 offset = calloc(params->n_fields, sizeof(uint32_t)); 7237 if (!offset) { 7238 status = -ENOMEM; 7239 goto end; 7240 } 7241 7242 /* Check that all the match fields belong to either the same header or 7243 * to the meta-data. 7244 */ 7245 hf = header_field_parse(p, params->fields[0].name, &h0); 7246 mf = metadata_field_parse(p, params->fields[0].name); 7247 if ((!hf && !mf) || (hf && hf->var_size)) { 7248 status = -EINVAL; 7249 goto end; 7250 } 7251 7252 offset[0] = h0 ? hf->offset : mf->offset; 7253 7254 for (i = 1; i < params->n_fields; i++) 7255 if (h0) { 7256 struct header *h; 7257 7258 hf = header_field_parse(p, params->fields[i].name, &h); 7259 if (!hf || (h->id != h0->id) || hf->var_size) { 7260 status = -EINVAL; 7261 goto end; 7262 } 7263 7264 offset[i] = hf->offset; 7265 } else { 7266 mf = metadata_field_parse(p, params->fields[i].name); 7267 if (!mf) { 7268 status = -EINVAL; 7269 goto end; 7270 } 7271 7272 offset[i] = mf->offset; 7273 } 7274 7275 /* Check that there are no duplicated match fields. */ 7276 for (i = 0; i < params->n_fields; i++) { 7277 uint32_t j; 7278 7279 for (j = 0; j < i; j++) 7280 if (offset[j] == offset[i]) { 7281 status = -EINVAL; 7282 goto end; 7283 } 7284 } 7285 7286 /* Return. */ 7287 if (header) 7288 *header = h0; 7289 7290 end: 7291 free(offset); 7292 return status; 7293 } 7294 7295 int 7296 rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, 7297 const char *name, 7298 struct rte_swx_pipeline_table_params *params, 7299 const char *recommended_table_type_name, 7300 const char *args, 7301 uint32_t size) 7302 { 7303 struct table_type *type; 7304 struct table *t = NULL; 7305 struct action *default_action; 7306 struct header *header = NULL; 7307 uint32_t action_data_size_max = 0, i; 7308 int status = 0; 7309 7310 CHECK(p, EINVAL); 7311 7312 CHECK_NAME(name, EINVAL); 7313 CHECK(!table_find(p, name), EEXIST); 7314 CHECK(!selector_find(p, name), EEXIST); 7315 CHECK(!learner_find(p, name), EEXIST); 7316 7317 CHECK(params, EINVAL); 7318 7319 /* Match checks. */ 7320 status = table_match_fields_check(p, params, &header); 7321 if (status) 7322 return status; 7323 7324 /* Action checks. */ 7325 CHECK(params->n_actions, EINVAL); 7326 CHECK(params->action_names, EINVAL); 7327 for (i = 0; i < params->n_actions; i++) { 7328 const char *action_name = params->action_names[i]; 7329 struct action *a; 7330 uint32_t action_data_size; 7331 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 7332 7333 CHECK_NAME(action_name, EINVAL); 7334 7335 a = action_find(p, action_name); 7336 CHECK(a, EINVAL); 7337 CHECK(!action_does_learning(a), EINVAL); 7338 7339 action_data_size = a->st ? a->st->n_bits / 8 : 0; 7340 if (action_data_size > action_data_size_max) 7341 action_data_size_max = action_data_size; 7342 7343 if (params->action_is_for_table_entries) 7344 action_is_for_table_entries = params->action_is_for_table_entries[i]; 7345 if (params->action_is_for_default_entry) 7346 action_is_for_default_entry = params->action_is_for_default_entry[i]; 7347 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 7348 } 7349 7350 CHECK_NAME(params->default_action_name, EINVAL); 7351 for (i = 0; i < p->n_actions; i++) 7352 if (!strcmp(params->action_names[i], 7353 params->default_action_name)) 7354 break; 7355 CHECK(i < params->n_actions, EINVAL); 7356 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 7357 EINVAL); 7358 7359 default_action = action_find(p, params->default_action_name); 7360 CHECK((default_action->st && params->default_action_data) || 7361 !params->default_action_data, EINVAL); 7362 7363 /* Table type checks. */ 7364 if (recommended_table_type_name) 7365 CHECK_NAME(recommended_table_type_name, EINVAL); 7366 7367 if (params->n_fields) { 7368 enum rte_swx_table_match_type match_type; 7369 7370 status = table_match_type_resolve(params->fields, params->n_fields, &match_type); 7371 if (status) 7372 return status; 7373 7374 type = table_type_resolve(p, recommended_table_type_name, match_type); 7375 CHECK(type, EINVAL); 7376 } else { 7377 type = NULL; 7378 } 7379 7380 /* Memory allocation. */ 7381 t = calloc(1, sizeof(struct table)); 7382 if (!t) 7383 goto nomem; 7384 7385 t->fields = calloc(params->n_fields, sizeof(struct match_field)); 7386 if (!t->fields) 7387 goto nomem; 7388 7389 t->actions = calloc(params->n_actions, sizeof(struct action *)); 7390 if (!t->actions) 7391 goto nomem; 7392 7393 if (action_data_size_max) { 7394 t->default_action_data = calloc(1, action_data_size_max); 7395 if (!t->default_action_data) 7396 goto nomem; 7397 } 7398 7399 t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 7400 if (!t->action_is_for_table_entries) 7401 goto nomem; 7402 7403 t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 7404 if (!t->action_is_for_default_entry) 7405 goto nomem; 7406 7407 /* Node initialization. */ 7408 strcpy(t->name, name); 7409 if (args && args[0]) 7410 strcpy(t->args, args); 7411 t->type = type; 7412 7413 for (i = 0; i < params->n_fields; i++) { 7414 struct rte_swx_match_field_params *field = ¶ms->fields[i]; 7415 struct match_field *f = &t->fields[i]; 7416 7417 f->match_type = field->match_type; 7418 f->field = header ? 7419 header_field_parse(p, field->name, NULL) : 7420 metadata_field_parse(p, field->name); 7421 } 7422 t->n_fields = params->n_fields; 7423 t->header = header; 7424 7425 for (i = 0; i < params->n_actions; i++) { 7426 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 7427 7428 if (params->action_is_for_table_entries) 7429 action_is_for_table_entries = params->action_is_for_table_entries[i]; 7430 if (params->action_is_for_default_entry) 7431 action_is_for_default_entry = params->action_is_for_default_entry[i]; 7432 7433 t->actions[i] = action_find(p, params->action_names[i]); 7434 t->action_is_for_table_entries[i] = action_is_for_table_entries; 7435 t->action_is_for_default_entry[i] = action_is_for_default_entry; 7436 } 7437 t->default_action = default_action; 7438 if (default_action->st) 7439 memcpy(t->default_action_data, 7440 params->default_action_data, 7441 default_action->st->n_bits / 8); 7442 t->n_actions = params->n_actions; 7443 t->default_action_is_const = params->default_action_is_const; 7444 t->action_data_size_max = action_data_size_max; 7445 7446 t->size = size; 7447 t->id = p->n_tables; 7448 7449 /* Node add to tailq. */ 7450 TAILQ_INSERT_TAIL(&p->tables, t, node); 7451 p->n_tables++; 7452 7453 return 0; 7454 7455 nomem: 7456 if (!t) 7457 return -ENOMEM; 7458 7459 free(t->action_is_for_default_entry); 7460 free(t->action_is_for_table_entries); 7461 free(t->default_action_data); 7462 free(t->actions); 7463 free(t->fields); 7464 free(t); 7465 7466 return -ENOMEM; 7467 } 7468 7469 static struct rte_swx_table_params * 7470 table_params_get(struct table *table) 7471 { 7472 struct rte_swx_table_params *params; 7473 struct field *first, *last; 7474 uint8_t *key_mask; 7475 uint32_t key_size, key_offset, action_data_size, i; 7476 7477 /* Memory allocation. */ 7478 params = calloc(1, sizeof(struct rte_swx_table_params)); 7479 if (!params) 7480 return NULL; 7481 7482 /* Find first (smallest offset) and last (biggest offset) match fields. */ 7483 first = table->fields[0].field; 7484 last = table->fields[0].field; 7485 7486 for (i = 0; i < table->n_fields; i++) { 7487 struct field *f = table->fields[i].field; 7488 7489 if (f->offset < first->offset) 7490 first = f; 7491 7492 if (f->offset > last->offset) 7493 last = f; 7494 } 7495 7496 /* Key offset and size. */ 7497 key_offset = first->offset / 8; 7498 key_size = (last->offset + last->n_bits - first->offset) / 8; 7499 7500 /* Memory allocation. */ 7501 key_mask = calloc(1, key_size); 7502 if (!key_mask) { 7503 free(params); 7504 return NULL; 7505 } 7506 7507 /* Key mask. */ 7508 for (i = 0; i < table->n_fields; i++) { 7509 struct field *f = table->fields[i].field; 7510 uint32_t start = (f->offset - first->offset) / 8; 7511 size_t size = f->n_bits / 8; 7512 7513 memset(&key_mask[start], 0xFF, size); 7514 } 7515 7516 /* Action data size. */ 7517 action_data_size = 0; 7518 for (i = 0; i < table->n_actions; i++) { 7519 struct action *action = table->actions[i]; 7520 uint32_t ads = action->st ? action->st->n_bits / 8 : 0; 7521 7522 if (ads > action_data_size) 7523 action_data_size = ads; 7524 } 7525 7526 /* Fill in. */ 7527 params->match_type = table->type->match_type; 7528 params->key_size = key_size; 7529 params->key_offset = key_offset; 7530 params->key_mask0 = key_mask; 7531 params->action_data_size = action_data_size; 7532 params->n_keys_max = table->size; 7533 7534 return params; 7535 } 7536 7537 static void 7538 table_params_free(struct rte_swx_table_params *params) 7539 { 7540 if (!params) 7541 return; 7542 7543 free(params->key_mask0); 7544 free(params); 7545 } 7546 7547 static int 7548 table_stub_lkp(void *table __rte_unused, 7549 void *mailbox __rte_unused, 7550 uint8_t **key __rte_unused, 7551 uint64_t *action_id __rte_unused, 7552 uint8_t **action_data __rte_unused, 7553 int *hit) 7554 { 7555 *hit = 0; 7556 return 1; /* DONE. */ 7557 } 7558 7559 static int 7560 table_build(struct rte_swx_pipeline *p) 7561 { 7562 uint32_t i; 7563 7564 /* Per pipeline: table statistics. */ 7565 p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics)); 7566 CHECK(p->table_stats, ENOMEM); 7567 7568 for (i = 0; i < p->n_tables; i++) { 7569 p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 7570 CHECK(p->table_stats[i].n_pkts_action, ENOMEM); 7571 } 7572 7573 /* Per thread: table runt-time. */ 7574 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7575 struct thread *t = &p->threads[i]; 7576 struct table *table; 7577 7578 t->tables = calloc(p->n_tables, sizeof(struct table_runtime)); 7579 CHECK(t->tables, ENOMEM); 7580 7581 TAILQ_FOREACH(table, &p->tables, node) { 7582 struct table_runtime *r = &t->tables[table->id]; 7583 7584 if (table->type) { 7585 uint64_t size; 7586 7587 size = table->type->ops.mailbox_size_get(); 7588 7589 /* r->func. */ 7590 r->func = table->type->ops.lkp; 7591 7592 /* r->mailbox. */ 7593 if (size) { 7594 r->mailbox = calloc(1, size); 7595 CHECK(r->mailbox, ENOMEM); 7596 } 7597 7598 /* r->key. */ 7599 r->key = table->header ? 7600 &t->structs[table->header->struct_id] : 7601 &t->structs[p->metadata_struct_id]; 7602 } else { 7603 r->func = table_stub_lkp; 7604 } 7605 } 7606 } 7607 7608 return 0; 7609 } 7610 7611 static void 7612 table_build_free(struct rte_swx_pipeline *p) 7613 { 7614 uint32_t i; 7615 7616 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7617 struct thread *t = &p->threads[i]; 7618 uint32_t j; 7619 7620 if (!t->tables) 7621 continue; 7622 7623 for (j = 0; j < p->n_tables; j++) { 7624 struct table_runtime *r = &t->tables[j]; 7625 7626 free(r->mailbox); 7627 } 7628 7629 free(t->tables); 7630 t->tables = NULL; 7631 } 7632 7633 if (p->table_stats) { 7634 for (i = 0; i < p->n_tables; i++) 7635 free(p->table_stats[i].n_pkts_action); 7636 7637 free(p->table_stats); 7638 } 7639 } 7640 7641 static void 7642 table_free(struct rte_swx_pipeline *p) 7643 { 7644 table_build_free(p); 7645 7646 /* Tables. */ 7647 for ( ; ; ) { 7648 struct table *elem; 7649 7650 elem = TAILQ_FIRST(&p->tables); 7651 if (!elem) 7652 break; 7653 7654 TAILQ_REMOVE(&p->tables, elem, node); 7655 free(elem->fields); 7656 free(elem->actions); 7657 free(elem->default_action_data); 7658 free(elem); 7659 } 7660 7661 /* Table types. */ 7662 for ( ; ; ) { 7663 struct table_type *elem; 7664 7665 elem = TAILQ_FIRST(&p->table_types); 7666 if (!elem) 7667 break; 7668 7669 TAILQ_REMOVE(&p->table_types, elem, node); 7670 free(elem); 7671 } 7672 } 7673 7674 /* 7675 * Selector. 7676 */ 7677 static struct selector * 7678 selector_find(struct rte_swx_pipeline *p, const char *name) 7679 { 7680 struct selector *s; 7681 7682 TAILQ_FOREACH(s, &p->selectors, node) 7683 if (strcmp(s->name, name) == 0) 7684 return s; 7685 7686 return NULL; 7687 } 7688 7689 static struct selector * 7690 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 7691 { 7692 struct selector *s = NULL; 7693 7694 TAILQ_FOREACH(s, &p->selectors, node) 7695 if (s->id == id) 7696 return s; 7697 7698 return NULL; 7699 } 7700 7701 static int 7702 selector_fields_check(struct rte_swx_pipeline *p, 7703 struct rte_swx_pipeline_selector_params *params, 7704 struct header **header) 7705 { 7706 struct header *h0 = NULL; 7707 struct field *hf, *mf; 7708 uint32_t i; 7709 7710 /* Return if no selector fields. */ 7711 if (!params->n_selector_fields || !params->selector_field_names) 7712 return -EINVAL; 7713 7714 /* Check that all the selector fields either belong to the same header 7715 * or are all meta-data fields. 7716 */ 7717 hf = header_field_parse(p, params->selector_field_names[0], &h0); 7718 mf = metadata_field_parse(p, params->selector_field_names[0]); 7719 if (!hf && !mf) 7720 return -EINVAL; 7721 7722 for (i = 1; i < params->n_selector_fields; i++) 7723 if (h0) { 7724 struct header *h; 7725 7726 hf = header_field_parse(p, params->selector_field_names[i], &h); 7727 if (!hf || (h->id != h0->id)) 7728 return -EINVAL; 7729 } else { 7730 mf = metadata_field_parse(p, params->selector_field_names[i]); 7731 if (!mf) 7732 return -EINVAL; 7733 } 7734 7735 /* Check that there are no duplicated match fields. */ 7736 for (i = 0; i < params->n_selector_fields; i++) { 7737 const char *field_name = params->selector_field_names[i]; 7738 uint32_t j; 7739 7740 for (j = i + 1; j < params->n_selector_fields; j++) 7741 if (!strcmp(params->selector_field_names[j], field_name)) 7742 return -EINVAL; 7743 } 7744 7745 /* Return. */ 7746 if (header) 7747 *header = h0; 7748 7749 return 0; 7750 } 7751 7752 int 7753 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p, 7754 const char *name, 7755 struct rte_swx_pipeline_selector_params *params) 7756 { 7757 struct selector *s; 7758 struct header *selector_header = NULL; 7759 struct field *group_id_field, *member_id_field; 7760 uint32_t i; 7761 int status = 0; 7762 7763 CHECK(p, EINVAL); 7764 7765 CHECK_NAME(name, EINVAL); 7766 CHECK(!table_find(p, name), EEXIST); 7767 CHECK(!selector_find(p, name), EEXIST); 7768 CHECK(!learner_find(p, name), EEXIST); 7769 7770 CHECK(params, EINVAL); 7771 7772 CHECK_NAME(params->group_id_field_name, EINVAL); 7773 group_id_field = metadata_field_parse(p, params->group_id_field_name); 7774 CHECK(group_id_field, EINVAL); 7775 7776 for (i = 0; i < params->n_selector_fields; i++) { 7777 const char *field_name = params->selector_field_names[i]; 7778 7779 CHECK_NAME(field_name, EINVAL); 7780 } 7781 status = selector_fields_check(p, params, &selector_header); 7782 if (status) 7783 return status; 7784 7785 CHECK_NAME(params->member_id_field_name, EINVAL); 7786 member_id_field = metadata_field_parse(p, params->member_id_field_name); 7787 CHECK(member_id_field, EINVAL); 7788 7789 CHECK(params->n_groups_max, EINVAL); 7790 7791 CHECK(params->n_members_per_group_max, EINVAL); 7792 7793 /* Memory allocation. */ 7794 s = calloc(1, sizeof(struct selector)); 7795 if (!s) { 7796 status = -ENOMEM; 7797 goto error; 7798 } 7799 7800 s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *)); 7801 if (!s->selector_fields) { 7802 status = -ENOMEM; 7803 goto error; 7804 } 7805 7806 /* Node initialization. */ 7807 strcpy(s->name, name); 7808 7809 s->group_id_field = group_id_field; 7810 7811 for (i = 0; i < params->n_selector_fields; i++) { 7812 const char *field_name = params->selector_field_names[i]; 7813 7814 s->selector_fields[i] = selector_header ? 7815 header_field_parse(p, field_name, NULL) : 7816 metadata_field_parse(p, field_name); 7817 } 7818 7819 s->n_selector_fields = params->n_selector_fields; 7820 7821 s->selector_header = selector_header; 7822 7823 s->member_id_field = member_id_field; 7824 7825 s->n_groups_max = params->n_groups_max; 7826 7827 s->n_members_per_group_max = params->n_members_per_group_max; 7828 7829 s->id = p->n_selectors; 7830 7831 /* Node add to tailq. */ 7832 TAILQ_INSERT_TAIL(&p->selectors, s, node); 7833 p->n_selectors++; 7834 7835 return 0; 7836 7837 error: 7838 if (!s) 7839 return status; 7840 7841 free(s->selector_fields); 7842 7843 free(s); 7844 7845 return status; 7846 } 7847 7848 static void 7849 selector_params_free(struct rte_swx_table_selector_params *params) 7850 { 7851 if (!params) 7852 return; 7853 7854 free(params->selector_mask); 7855 7856 free(params); 7857 } 7858 7859 static struct rte_swx_table_selector_params * 7860 selector_table_params_get(struct selector *s) 7861 { 7862 struct rte_swx_table_selector_params *params = NULL; 7863 struct field *first, *last; 7864 uint32_t i; 7865 7866 /* Memory allocation. */ 7867 params = calloc(1, sizeof(struct rte_swx_table_selector_params)); 7868 if (!params) 7869 goto error; 7870 7871 /* Group ID. */ 7872 params->group_id_offset = s->group_id_field->offset / 8; 7873 7874 /* Find first (smallest offset) and last (biggest offset) selector fields. */ 7875 first = s->selector_fields[0]; 7876 last = s->selector_fields[0]; 7877 7878 for (i = 0; i < s->n_selector_fields; i++) { 7879 struct field *f = s->selector_fields[i]; 7880 7881 if (f->offset < first->offset) 7882 first = f; 7883 7884 if (f->offset > last->offset) 7885 last = f; 7886 } 7887 7888 /* Selector offset and size. */ 7889 params->selector_offset = first->offset / 8; 7890 params->selector_size = (last->offset + last->n_bits - first->offset) / 8; 7891 7892 /* Memory allocation. */ 7893 params->selector_mask = calloc(1, params->selector_size); 7894 if (!params->selector_mask) 7895 goto error; 7896 7897 /* Selector mask. */ 7898 for (i = 0; i < s->n_selector_fields; i++) { 7899 struct field *f = s->selector_fields[i]; 7900 uint32_t start = (f->offset - first->offset) / 8; 7901 size_t size = f->n_bits / 8; 7902 7903 memset(¶ms->selector_mask[start], 0xFF, size); 7904 } 7905 7906 /* Member ID. */ 7907 params->member_id_offset = s->member_id_field->offset / 8; 7908 7909 /* Maximum number of groups. */ 7910 params->n_groups_max = s->n_groups_max; 7911 7912 /* Maximum number of members per group. */ 7913 params->n_members_per_group_max = s->n_members_per_group_max; 7914 7915 return params; 7916 7917 error: 7918 selector_params_free(params); 7919 return NULL; 7920 } 7921 7922 static void 7923 selector_build_free(struct rte_swx_pipeline *p) 7924 { 7925 uint32_t i; 7926 7927 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7928 struct thread *t = &p->threads[i]; 7929 uint32_t j; 7930 7931 if (!t->selectors) 7932 continue; 7933 7934 for (j = 0; j < p->n_selectors; j++) { 7935 struct selector_runtime *r = &t->selectors[j]; 7936 7937 free(r->mailbox); 7938 } 7939 7940 free(t->selectors); 7941 t->selectors = NULL; 7942 } 7943 7944 free(p->selector_stats); 7945 p->selector_stats = NULL; 7946 } 7947 7948 static int 7949 selector_build(struct rte_swx_pipeline *p) 7950 { 7951 uint32_t i; 7952 int status = 0; 7953 7954 /* Per pipeline: selector statistics. */ 7955 p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics)); 7956 if (!p->selector_stats) { 7957 status = -ENOMEM; 7958 goto error; 7959 } 7960 7961 /* Per thread: selector run-time. */ 7962 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 7963 struct thread *t = &p->threads[i]; 7964 struct selector *s; 7965 7966 t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime)); 7967 if (!t->selectors) { 7968 status = -ENOMEM; 7969 goto error; 7970 } 7971 7972 TAILQ_FOREACH(s, &p->selectors, node) { 7973 struct selector_runtime *r = &t->selectors[s->id]; 7974 uint64_t size; 7975 7976 /* r->mailbox. */ 7977 size = rte_swx_table_selector_mailbox_size_get(); 7978 if (size) { 7979 r->mailbox = calloc(1, size); 7980 if (!r->mailbox) { 7981 status = -ENOMEM; 7982 goto error; 7983 } 7984 } 7985 7986 /* r->group_id_buffer. */ 7987 r->group_id_buffer = &t->structs[p->metadata_struct_id]; 7988 7989 /* r->selector_buffer. */ 7990 r->selector_buffer = s->selector_header ? 7991 &t->structs[s->selector_header->struct_id] : 7992 &t->structs[p->metadata_struct_id]; 7993 7994 /* r->member_id_buffer. */ 7995 r->member_id_buffer = &t->structs[p->metadata_struct_id]; 7996 } 7997 } 7998 7999 return 0; 8000 8001 error: 8002 selector_build_free(p); 8003 return status; 8004 } 8005 8006 static void 8007 selector_free(struct rte_swx_pipeline *p) 8008 { 8009 selector_build_free(p); 8010 8011 /* Selector tables. */ 8012 for ( ; ; ) { 8013 struct selector *elem; 8014 8015 elem = TAILQ_FIRST(&p->selectors); 8016 if (!elem) 8017 break; 8018 8019 TAILQ_REMOVE(&p->selectors, elem, node); 8020 free(elem->selector_fields); 8021 free(elem); 8022 } 8023 } 8024 8025 /* 8026 * Learner table. 8027 */ 8028 static struct learner * 8029 learner_find(struct rte_swx_pipeline *p, const char *name) 8030 { 8031 struct learner *l; 8032 8033 TAILQ_FOREACH(l, &p->learners, node) 8034 if (!strcmp(l->name, name)) 8035 return l; 8036 8037 return NULL; 8038 } 8039 8040 static struct learner * 8041 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8042 { 8043 struct learner *l = NULL; 8044 8045 TAILQ_FOREACH(l, &p->learners, node) 8046 if (l->id == id) 8047 return l; 8048 8049 return NULL; 8050 } 8051 8052 static int 8053 learner_match_fields_check(struct rte_swx_pipeline *p, 8054 struct rte_swx_pipeline_learner_params *params, 8055 struct header **header) 8056 { 8057 struct header *h0 = NULL; 8058 struct field *hf, *mf; 8059 uint32_t i; 8060 8061 /* Return if no match fields. */ 8062 if (!params->n_fields || !params->field_names) 8063 return -EINVAL; 8064 8065 /* Check that all the match fields either belong to the same header 8066 * or are all meta-data fields. 8067 */ 8068 hf = header_field_parse(p, params->field_names[0], &h0); 8069 mf = metadata_field_parse(p, params->field_names[0]); 8070 if (!hf && !mf) 8071 return -EINVAL; 8072 8073 for (i = 1; i < params->n_fields; i++) 8074 if (h0) { 8075 struct header *h; 8076 8077 hf = header_field_parse(p, params->field_names[i], &h); 8078 if (!hf || (h->id != h0->id)) 8079 return -EINVAL; 8080 } else { 8081 mf = metadata_field_parse(p, params->field_names[i]); 8082 if (!mf) 8083 return -EINVAL; 8084 } 8085 8086 /* Check that there are no duplicated match fields. */ 8087 for (i = 0; i < params->n_fields; i++) { 8088 const char *field_name = params->field_names[i]; 8089 uint32_t j; 8090 8091 for (j = i + 1; j < params->n_fields; j++) 8092 if (!strcmp(params->field_names[j], field_name)) 8093 return -EINVAL; 8094 } 8095 8096 /* Return. */ 8097 if (header) 8098 *header = h0; 8099 8100 return 0; 8101 } 8102 8103 static int 8104 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name) 8105 { 8106 struct struct_type *mst = p->metadata_st, *ast = a->st; 8107 struct field *mf, *af; 8108 uint32_t mf_pos, i; 8109 8110 if (!ast) { 8111 if (mf_name) 8112 return -EINVAL; 8113 8114 return 0; 8115 } 8116 8117 /* Check that mf_name is the name of a valid meta-data field. */ 8118 CHECK_NAME(mf_name, EINVAL); 8119 mf = metadata_field_parse(p, mf_name); 8120 CHECK(mf, EINVAL); 8121 8122 /* Check that there are enough meta-data fields, starting with the mf_name field, to cover 8123 * all the action arguments. 8124 */ 8125 mf_pos = mf - mst->fields; 8126 CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL); 8127 8128 /* Check that the size of each of the identified meta-data fields matches exactly the size 8129 * of the corresponding action argument. 8130 */ 8131 for (i = 0; i < ast->n_fields; i++) { 8132 mf = &mst->fields[mf_pos + i]; 8133 af = &ast->fields[i]; 8134 8135 CHECK(mf->n_bits == af->n_bits, EINVAL); 8136 } 8137 8138 return 0; 8139 } 8140 8141 static int 8142 learner_action_learning_check(struct rte_swx_pipeline *p, 8143 struct action *action, 8144 const char **action_names, 8145 uint32_t n_actions) 8146 { 8147 uint32_t i; 8148 8149 /* For each "learn" instruction of the current action, check that the learned action (i.e. 8150 * the action passed as argument to the "learn" instruction) is also enabled for the 8151 * current learner table. 8152 */ 8153 for (i = 0; i < action->n_instructions; i++) { 8154 struct instruction *instr = &action->instructions[i]; 8155 uint32_t found = 0, j; 8156 8157 if (instr->type != INSTR_LEARNER_LEARN) 8158 continue; 8159 8160 for (j = 0; j < n_actions; j++) { 8161 struct action *a; 8162 8163 a = action_find(p, action_names[j]); 8164 if (!a) 8165 return -EINVAL; 8166 8167 if (a->id == instr->learn.action_id) 8168 found = 1; 8169 } 8170 8171 if (!found) 8172 return -EINVAL; 8173 } 8174 8175 return 0; 8176 } 8177 8178 int 8179 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, 8180 const char *name, 8181 struct rte_swx_pipeline_learner_params *params, 8182 uint32_t size, 8183 uint32_t timeout) 8184 { 8185 struct learner *l = NULL; 8186 struct action *default_action; 8187 struct header *header = NULL; 8188 uint32_t action_data_size_max = 0, i; 8189 int status = 0; 8190 8191 CHECK(p, EINVAL); 8192 8193 CHECK_NAME(name, EINVAL); 8194 CHECK(!table_find(p, name), EEXIST); 8195 CHECK(!selector_find(p, name), EEXIST); 8196 CHECK(!learner_find(p, name), EEXIST); 8197 8198 CHECK(params, EINVAL); 8199 8200 /* Match checks. */ 8201 status = learner_match_fields_check(p, params, &header); 8202 if (status) 8203 return status; 8204 8205 /* Action checks. */ 8206 CHECK(params->n_actions, EINVAL); 8207 CHECK(params->action_names, EINVAL); 8208 for (i = 0; i < params->n_actions; i++) { 8209 const char *action_name = params->action_names[i]; 8210 struct action *a; 8211 uint32_t action_data_size; 8212 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8213 8214 CHECK_NAME(action_name, EINVAL); 8215 8216 a = action_find(p, action_name); 8217 CHECK(a, EINVAL); 8218 8219 status = learner_action_learning_check(p, 8220 a, 8221 params->action_names, 8222 params->n_actions); 8223 if (status) 8224 return status; 8225 8226 action_data_size = a->st ? a->st->n_bits / 8 : 0; 8227 if (action_data_size > action_data_size_max) 8228 action_data_size_max = action_data_size; 8229 8230 if (params->action_is_for_table_entries) 8231 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8232 if (params->action_is_for_default_entry) 8233 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8234 CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); 8235 } 8236 8237 CHECK_NAME(params->default_action_name, EINVAL); 8238 for (i = 0; i < p->n_actions; i++) 8239 if (!strcmp(params->action_names[i], 8240 params->default_action_name)) 8241 break; 8242 CHECK(i < params->n_actions, EINVAL); 8243 CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], 8244 EINVAL); 8245 8246 default_action = action_find(p, params->default_action_name); 8247 CHECK((default_action->st && params->default_action_data) || 8248 !params->default_action_data, EINVAL); 8249 8250 /* Any other checks. */ 8251 CHECK(size, EINVAL); 8252 CHECK(timeout, EINVAL); 8253 8254 /* Memory allocation. */ 8255 l = calloc(1, sizeof(struct learner)); 8256 if (!l) 8257 goto nomem; 8258 8259 l->fields = calloc(params->n_fields, sizeof(struct field *)); 8260 if (!l->fields) 8261 goto nomem; 8262 8263 l->actions = calloc(params->n_actions, sizeof(struct action *)); 8264 if (!l->actions) 8265 goto nomem; 8266 8267 if (action_data_size_max) { 8268 l->default_action_data = calloc(1, action_data_size_max); 8269 if (!l->default_action_data) 8270 goto nomem; 8271 } 8272 8273 l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); 8274 if (!l->action_is_for_table_entries) 8275 goto nomem; 8276 8277 l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); 8278 if (!l->action_is_for_default_entry) 8279 goto nomem; 8280 8281 /* Node initialization. */ 8282 strcpy(l->name, name); 8283 8284 for (i = 0; i < params->n_fields; i++) { 8285 const char *field_name = params->field_names[i]; 8286 8287 l->fields[i] = header ? 8288 header_field_parse(p, field_name, NULL) : 8289 metadata_field_parse(p, field_name); 8290 } 8291 8292 l->n_fields = params->n_fields; 8293 8294 l->header = header; 8295 8296 for (i = 0; i < params->n_actions; i++) { 8297 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 8298 8299 if (params->action_is_for_table_entries) 8300 action_is_for_table_entries = params->action_is_for_table_entries[i]; 8301 if (params->action_is_for_default_entry) 8302 action_is_for_default_entry = params->action_is_for_default_entry[i]; 8303 8304 l->actions[i] = action_find(p, params->action_names[i]); 8305 l->action_is_for_table_entries[i] = action_is_for_table_entries; 8306 l->action_is_for_default_entry[i] = action_is_for_default_entry; 8307 } 8308 8309 l->default_action = default_action; 8310 8311 if (default_action->st) 8312 memcpy(l->default_action_data, 8313 params->default_action_data, 8314 default_action->st->n_bits / 8); 8315 8316 l->n_actions = params->n_actions; 8317 8318 l->default_action_is_const = params->default_action_is_const; 8319 8320 l->action_data_size_max = action_data_size_max; 8321 8322 l->size = size; 8323 8324 l->timeout = timeout; 8325 8326 l->id = p->n_learners; 8327 8328 /* Node add to tailq. */ 8329 TAILQ_INSERT_TAIL(&p->learners, l, node); 8330 p->n_learners++; 8331 8332 return 0; 8333 8334 nomem: 8335 if (!l) 8336 return -ENOMEM; 8337 8338 free(l->action_is_for_default_entry); 8339 free(l->action_is_for_table_entries); 8340 free(l->default_action_data); 8341 free(l->actions); 8342 free(l->fields); 8343 free(l); 8344 8345 return -ENOMEM; 8346 } 8347 8348 static void 8349 learner_params_free(struct rte_swx_table_learner_params *params) 8350 { 8351 if (!params) 8352 return; 8353 8354 free(params->key_mask0); 8355 8356 free(params); 8357 } 8358 8359 static struct rte_swx_table_learner_params * 8360 learner_params_get(struct learner *l) 8361 { 8362 struct rte_swx_table_learner_params *params = NULL; 8363 struct field *first, *last; 8364 uint32_t i; 8365 8366 /* Memory allocation. */ 8367 params = calloc(1, sizeof(struct rte_swx_table_learner_params)); 8368 if (!params) 8369 goto error; 8370 8371 /* Find first (smallest offset) and last (biggest offset) match fields. */ 8372 first = l->fields[0]; 8373 last = l->fields[0]; 8374 8375 for (i = 0; i < l->n_fields; i++) { 8376 struct field *f = l->fields[i]; 8377 8378 if (f->offset < first->offset) 8379 first = f; 8380 8381 if (f->offset > last->offset) 8382 last = f; 8383 } 8384 8385 /* Key offset and size. */ 8386 params->key_offset = first->offset / 8; 8387 params->key_size = (last->offset + last->n_bits - first->offset) / 8; 8388 8389 /* Memory allocation. */ 8390 params->key_mask0 = calloc(1, params->key_size); 8391 if (!params->key_mask0) 8392 goto error; 8393 8394 /* Key mask. */ 8395 for (i = 0; i < l->n_fields; i++) { 8396 struct field *f = l->fields[i]; 8397 uint32_t start = (f->offset - first->offset) / 8; 8398 size_t size = f->n_bits / 8; 8399 8400 memset(¶ms->key_mask0[start], 0xFF, size); 8401 } 8402 8403 /* Action data size. */ 8404 params->action_data_size = l->action_data_size_max; 8405 8406 /* Maximum number of keys. */ 8407 params->n_keys_max = l->size; 8408 8409 /* Timeout. */ 8410 params->key_timeout = l->timeout; 8411 8412 return params; 8413 8414 error: 8415 learner_params_free(params); 8416 return NULL; 8417 } 8418 8419 static void 8420 learner_build_free(struct rte_swx_pipeline *p) 8421 { 8422 uint32_t i; 8423 8424 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8425 struct thread *t = &p->threads[i]; 8426 uint32_t j; 8427 8428 if (!t->learners) 8429 continue; 8430 8431 for (j = 0; j < p->n_learners; j++) { 8432 struct learner_runtime *r = &t->learners[j]; 8433 8434 free(r->mailbox); 8435 } 8436 8437 free(t->learners); 8438 t->learners = NULL; 8439 } 8440 8441 if (p->learner_stats) { 8442 for (i = 0; i < p->n_learners; i++) 8443 free(p->learner_stats[i].n_pkts_action); 8444 8445 free(p->learner_stats); 8446 } 8447 } 8448 8449 static int 8450 learner_build(struct rte_swx_pipeline *p) 8451 { 8452 uint32_t i; 8453 int status = 0; 8454 8455 /* Per pipeline: learner statistics. */ 8456 p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics)); 8457 CHECK(p->learner_stats, ENOMEM); 8458 8459 for (i = 0; i < p->n_learners; i++) { 8460 p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t)); 8461 CHECK(p->learner_stats[i].n_pkts_action, ENOMEM); 8462 } 8463 8464 /* Per thread: learner run-time. */ 8465 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 8466 struct thread *t = &p->threads[i]; 8467 struct learner *l; 8468 8469 t->learners = calloc(p->n_learners, sizeof(struct learner_runtime)); 8470 if (!t->learners) { 8471 status = -ENOMEM; 8472 goto error; 8473 } 8474 8475 TAILQ_FOREACH(l, &p->learners, node) { 8476 struct learner_runtime *r = &t->learners[l->id]; 8477 uint64_t size; 8478 8479 /* r->mailbox. */ 8480 size = rte_swx_table_learner_mailbox_size_get(); 8481 if (size) { 8482 r->mailbox = calloc(1, size); 8483 if (!r->mailbox) { 8484 status = -ENOMEM; 8485 goto error; 8486 } 8487 } 8488 8489 /* r->key. */ 8490 r->key = l->header ? 8491 &t->structs[l->header->struct_id] : 8492 &t->structs[p->metadata_struct_id]; 8493 } 8494 } 8495 8496 return 0; 8497 8498 error: 8499 learner_build_free(p); 8500 return status; 8501 } 8502 8503 static void 8504 learner_free(struct rte_swx_pipeline *p) 8505 { 8506 learner_build_free(p); 8507 8508 /* Learner tables. */ 8509 for ( ; ; ) { 8510 struct learner *l; 8511 8512 l = TAILQ_FIRST(&p->learners); 8513 if (!l) 8514 break; 8515 8516 TAILQ_REMOVE(&p->learners, l, node); 8517 free(l->fields); 8518 free(l->actions); 8519 free(l->default_action_data); 8520 free(l); 8521 } 8522 } 8523 8524 /* 8525 * Table state. 8526 */ 8527 static int 8528 table_state_build(struct rte_swx_pipeline *p) 8529 { 8530 struct table *table; 8531 struct selector *s; 8532 struct learner *l; 8533 8534 p->table_state = calloc(p->n_tables + p->n_selectors, 8535 sizeof(struct rte_swx_table_state)); 8536 CHECK(p->table_state, ENOMEM); 8537 8538 TAILQ_FOREACH(table, &p->tables, node) { 8539 struct rte_swx_table_state *ts = &p->table_state[table->id]; 8540 8541 if (table->type) { 8542 struct rte_swx_table_params *params; 8543 8544 /* ts->obj. */ 8545 params = table_params_get(table); 8546 CHECK(params, ENOMEM); 8547 8548 ts->obj = table->type->ops.create(params, 8549 NULL, 8550 table->args, 8551 p->numa_node); 8552 8553 table_params_free(params); 8554 CHECK(ts->obj, ENODEV); 8555 } 8556 8557 /* ts->default_action_data. */ 8558 if (table->action_data_size_max) { 8559 ts->default_action_data = 8560 malloc(table->action_data_size_max); 8561 CHECK(ts->default_action_data, ENOMEM); 8562 8563 memcpy(ts->default_action_data, 8564 table->default_action_data, 8565 table->action_data_size_max); 8566 } 8567 8568 /* ts->default_action_id. */ 8569 ts->default_action_id = table->default_action->id; 8570 } 8571 8572 TAILQ_FOREACH(s, &p->selectors, node) { 8573 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id]; 8574 struct rte_swx_table_selector_params *params; 8575 8576 /* ts->obj. */ 8577 params = selector_table_params_get(s); 8578 CHECK(params, ENOMEM); 8579 8580 ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node); 8581 8582 selector_params_free(params); 8583 CHECK(ts->obj, ENODEV); 8584 } 8585 8586 TAILQ_FOREACH(l, &p->learners, node) { 8587 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + 8588 p->n_selectors + l->id]; 8589 struct rte_swx_table_learner_params *params; 8590 8591 /* ts->obj. */ 8592 params = learner_params_get(l); 8593 CHECK(params, ENOMEM); 8594 8595 ts->obj = rte_swx_table_learner_create(params, p->numa_node); 8596 learner_params_free(params); 8597 CHECK(ts->obj, ENODEV); 8598 8599 /* ts->default_action_data. */ 8600 if (l->action_data_size_max) { 8601 ts->default_action_data = malloc(l->action_data_size_max); 8602 CHECK(ts->default_action_data, ENOMEM); 8603 8604 memcpy(ts->default_action_data, 8605 l->default_action_data, 8606 l->action_data_size_max); 8607 } 8608 8609 /* ts->default_action_id. */ 8610 ts->default_action_id = l->default_action->id; 8611 } 8612 8613 return 0; 8614 } 8615 8616 static void 8617 table_state_build_free(struct rte_swx_pipeline *p) 8618 { 8619 uint32_t i; 8620 8621 if (!p->table_state) 8622 return; 8623 8624 for (i = 0; i < p->n_tables; i++) { 8625 struct rte_swx_table_state *ts = &p->table_state[i]; 8626 struct table *table = table_find_by_id(p, i); 8627 8628 /* ts->obj. */ 8629 if (table->type && ts->obj) 8630 table->type->ops.free(ts->obj); 8631 8632 /* ts->default_action_data. */ 8633 free(ts->default_action_data); 8634 } 8635 8636 for (i = 0; i < p->n_selectors; i++) { 8637 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i]; 8638 8639 /* ts->obj. */ 8640 if (ts->obj) 8641 rte_swx_table_selector_free(ts->obj); 8642 } 8643 8644 for (i = 0; i < p->n_learners; i++) { 8645 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i]; 8646 8647 /* ts->obj. */ 8648 if (ts->obj) 8649 rte_swx_table_learner_free(ts->obj); 8650 8651 /* ts->default_action_data. */ 8652 free(ts->default_action_data); 8653 } 8654 8655 free(p->table_state); 8656 p->table_state = NULL; 8657 } 8658 8659 static void 8660 table_state_free(struct rte_swx_pipeline *p) 8661 { 8662 table_state_build_free(p); 8663 } 8664 8665 /* 8666 * Register array. 8667 */ 8668 static struct regarray * 8669 regarray_find(struct rte_swx_pipeline *p, const char *name) 8670 { 8671 struct regarray *elem; 8672 8673 TAILQ_FOREACH(elem, &p->regarrays, node) 8674 if (!strcmp(elem->name, name)) 8675 return elem; 8676 8677 return NULL; 8678 } 8679 8680 static struct regarray * 8681 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8682 { 8683 struct regarray *elem = NULL; 8684 8685 TAILQ_FOREACH(elem, &p->regarrays, node) 8686 if (elem->id == id) 8687 return elem; 8688 8689 return NULL; 8690 } 8691 8692 int 8693 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p, 8694 const char *name, 8695 uint32_t size, 8696 uint64_t init_val) 8697 { 8698 struct regarray *r; 8699 8700 CHECK(p, EINVAL); 8701 8702 CHECK_NAME(name, EINVAL); 8703 CHECK(!regarray_find(p, name), EEXIST); 8704 8705 CHECK(size, EINVAL); 8706 size = rte_align32pow2(size); 8707 8708 /* Memory allocation. */ 8709 r = calloc(1, sizeof(struct regarray)); 8710 CHECK(r, ENOMEM); 8711 8712 /* Node initialization. */ 8713 strcpy(r->name, name); 8714 r->init_val = init_val; 8715 r->size = size; 8716 r->id = p->n_regarrays; 8717 8718 /* Node add to tailq. */ 8719 TAILQ_INSERT_TAIL(&p->regarrays, r, node); 8720 p->n_regarrays++; 8721 8722 return 0; 8723 } 8724 8725 static int 8726 regarray_build(struct rte_swx_pipeline *p) 8727 { 8728 struct regarray *regarray; 8729 8730 if (!p->n_regarrays) 8731 return 0; 8732 8733 p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime)); 8734 CHECK(p->regarray_runtime, ENOMEM); 8735 8736 TAILQ_FOREACH(regarray, &p->regarrays, node) { 8737 struct regarray_runtime *r = &p->regarray_runtime[regarray->id]; 8738 uint32_t i; 8739 8740 r->regarray = env_malloc(regarray->size * sizeof(uint64_t), 8741 RTE_CACHE_LINE_SIZE, 8742 p->numa_node); 8743 CHECK(r->regarray, ENOMEM); 8744 8745 if (regarray->init_val) 8746 for (i = 0; i < regarray->size; i++) 8747 r->regarray[i] = regarray->init_val; 8748 8749 r->size_mask = regarray->size - 1; 8750 } 8751 8752 return 0; 8753 } 8754 8755 static void 8756 regarray_build_free(struct rte_swx_pipeline *p) 8757 { 8758 uint32_t i; 8759 8760 if (!p->regarray_runtime) 8761 return; 8762 8763 for (i = 0; i < p->n_regarrays; i++) { 8764 struct regarray *regarray = regarray_find_by_id(p, i); 8765 struct regarray_runtime *r = &p->regarray_runtime[i]; 8766 8767 env_free(r->regarray, regarray->size * sizeof(uint64_t)); 8768 } 8769 8770 free(p->regarray_runtime); 8771 p->regarray_runtime = NULL; 8772 } 8773 8774 static void 8775 regarray_free(struct rte_swx_pipeline *p) 8776 { 8777 regarray_build_free(p); 8778 8779 for ( ; ; ) { 8780 struct regarray *elem; 8781 8782 elem = TAILQ_FIRST(&p->regarrays); 8783 if (!elem) 8784 break; 8785 8786 TAILQ_REMOVE(&p->regarrays, elem, node); 8787 free(elem); 8788 } 8789 } 8790 8791 /* 8792 * Meter array. 8793 */ 8794 static struct meter_profile * 8795 meter_profile_find(struct rte_swx_pipeline *p, const char *name) 8796 { 8797 struct meter_profile *elem; 8798 8799 TAILQ_FOREACH(elem, &p->meter_profiles, node) 8800 if (!strcmp(elem->name, name)) 8801 return elem; 8802 8803 return NULL; 8804 } 8805 8806 static struct metarray * 8807 metarray_find(struct rte_swx_pipeline *p, const char *name) 8808 { 8809 struct metarray *elem; 8810 8811 TAILQ_FOREACH(elem, &p->metarrays, node) 8812 if (!strcmp(elem->name, name)) 8813 return elem; 8814 8815 return NULL; 8816 } 8817 8818 static struct metarray * 8819 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id) 8820 { 8821 struct metarray *elem = NULL; 8822 8823 TAILQ_FOREACH(elem, &p->metarrays, node) 8824 if (elem->id == id) 8825 return elem; 8826 8827 return NULL; 8828 } 8829 8830 int 8831 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p, 8832 const char *name, 8833 uint32_t size) 8834 { 8835 struct metarray *m; 8836 8837 CHECK(p, EINVAL); 8838 8839 CHECK_NAME(name, EINVAL); 8840 CHECK(!metarray_find(p, name), EEXIST); 8841 8842 CHECK(size, EINVAL); 8843 size = rte_align32pow2(size); 8844 8845 /* Memory allocation. */ 8846 m = calloc(1, sizeof(struct metarray)); 8847 CHECK(m, ENOMEM); 8848 8849 /* Node initialization. */ 8850 strcpy(m->name, name); 8851 m->size = size; 8852 m->id = p->n_metarrays; 8853 8854 /* Node add to tailq. */ 8855 TAILQ_INSERT_TAIL(&p->metarrays, m, node); 8856 p->n_metarrays++; 8857 8858 return 0; 8859 } 8860 8861 struct meter_profile meter_profile_default = { 8862 .node = {0}, 8863 .name = "", 8864 .params = {0}, 8865 8866 .profile = { 8867 .cbs = 10000, 8868 .pbs = 10000, 8869 .cir_period = 1, 8870 .cir_bytes_per_period = 1, 8871 .pir_period = 1, 8872 .pir_bytes_per_period = 1, 8873 }, 8874 8875 .n_users = 0, 8876 }; 8877 8878 static void 8879 meter_init(struct meter *m) 8880 { 8881 memset(m, 0, sizeof(struct meter)); 8882 rte_meter_trtcm_config(&m->m, &meter_profile_default.profile); 8883 m->profile = &meter_profile_default; 8884 m->color_mask = RTE_COLOR_GREEN; 8885 8886 meter_profile_default.n_users++; 8887 } 8888 8889 static int 8890 metarray_build(struct rte_swx_pipeline *p) 8891 { 8892 struct metarray *m; 8893 8894 if (!p->n_metarrays) 8895 return 0; 8896 8897 p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime)); 8898 CHECK(p->metarray_runtime, ENOMEM); 8899 8900 TAILQ_FOREACH(m, &p->metarrays, node) { 8901 struct metarray_runtime *r = &p->metarray_runtime[m->id]; 8902 uint32_t i; 8903 8904 r->metarray = env_malloc(m->size * sizeof(struct meter), 8905 RTE_CACHE_LINE_SIZE, 8906 p->numa_node); 8907 CHECK(r->metarray, ENOMEM); 8908 8909 for (i = 0; i < m->size; i++) 8910 meter_init(&r->metarray[i]); 8911 8912 r->size_mask = m->size - 1; 8913 } 8914 8915 return 0; 8916 } 8917 8918 static void 8919 metarray_build_free(struct rte_swx_pipeline *p) 8920 { 8921 uint32_t i; 8922 8923 if (!p->metarray_runtime) 8924 return; 8925 8926 for (i = 0; i < p->n_metarrays; i++) { 8927 struct metarray *m = metarray_find_by_id(p, i); 8928 struct metarray_runtime *r = &p->metarray_runtime[i]; 8929 8930 env_free(r->metarray, m->size * sizeof(struct meter)); 8931 } 8932 8933 free(p->metarray_runtime); 8934 p->metarray_runtime = NULL; 8935 } 8936 8937 static void 8938 metarray_free(struct rte_swx_pipeline *p) 8939 { 8940 metarray_build_free(p); 8941 8942 /* Meter arrays. */ 8943 for ( ; ; ) { 8944 struct metarray *elem; 8945 8946 elem = TAILQ_FIRST(&p->metarrays); 8947 if (!elem) 8948 break; 8949 8950 TAILQ_REMOVE(&p->metarrays, elem, node); 8951 free(elem); 8952 } 8953 8954 /* Meter profiles. */ 8955 for ( ; ; ) { 8956 struct meter_profile *elem; 8957 8958 elem = TAILQ_FIRST(&p->meter_profiles); 8959 if (!elem) 8960 break; 8961 8962 TAILQ_REMOVE(&p->meter_profiles, elem, node); 8963 free(elem); 8964 } 8965 } 8966 8967 /* 8968 * Pipeline. 8969 */ 8970 int 8971 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) 8972 { 8973 struct rte_swx_pipeline *pipeline; 8974 8975 /* Check input parameters. */ 8976 CHECK(p, EINVAL); 8977 8978 /* Memory allocation. */ 8979 pipeline = calloc(1, sizeof(struct rte_swx_pipeline)); 8980 CHECK(pipeline, ENOMEM); 8981 8982 /* Initialization. */ 8983 TAILQ_INIT(&pipeline->struct_types); 8984 TAILQ_INIT(&pipeline->port_in_types); 8985 TAILQ_INIT(&pipeline->ports_in); 8986 TAILQ_INIT(&pipeline->port_out_types); 8987 TAILQ_INIT(&pipeline->ports_out); 8988 TAILQ_INIT(&pipeline->extern_types); 8989 TAILQ_INIT(&pipeline->extern_objs); 8990 TAILQ_INIT(&pipeline->extern_funcs); 8991 TAILQ_INIT(&pipeline->headers); 8992 TAILQ_INIT(&pipeline->actions); 8993 TAILQ_INIT(&pipeline->table_types); 8994 TAILQ_INIT(&pipeline->tables); 8995 TAILQ_INIT(&pipeline->selectors); 8996 TAILQ_INIT(&pipeline->learners); 8997 TAILQ_INIT(&pipeline->regarrays); 8998 TAILQ_INIT(&pipeline->meter_profiles); 8999 TAILQ_INIT(&pipeline->metarrays); 9000 9001 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */ 9002 pipeline->numa_node = numa_node; 9003 9004 *p = pipeline; 9005 return 0; 9006 } 9007 9008 void 9009 rte_swx_pipeline_free(struct rte_swx_pipeline *p) 9010 { 9011 void *lib; 9012 9013 if (!p) 9014 return; 9015 9016 lib = p->lib; 9017 9018 free(p->instruction_data); 9019 free(p->instructions); 9020 9021 metarray_free(p); 9022 regarray_free(p); 9023 table_state_free(p); 9024 learner_free(p); 9025 selector_free(p); 9026 table_free(p); 9027 action_free(p); 9028 instruction_table_free(p); 9029 metadata_free(p); 9030 header_free(p); 9031 extern_func_free(p); 9032 extern_obj_free(p); 9033 port_out_free(p); 9034 port_in_free(p); 9035 struct_free(p); 9036 9037 free(p); 9038 9039 if (lib) 9040 dlclose(lib); 9041 } 9042 9043 int 9044 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p, 9045 const char **instructions, 9046 uint32_t n_instructions) 9047 { 9048 int err; 9049 uint32_t i; 9050 9051 err = instruction_config(p, NULL, instructions, n_instructions); 9052 if (err) 9053 return err; 9054 9055 /* Thread instruction pointer reset. */ 9056 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { 9057 struct thread *t = &p->threads[i]; 9058 9059 thread_ip_reset(p, t); 9060 } 9061 9062 return 0; 9063 } 9064 9065 static int 9066 pipeline_compile(struct rte_swx_pipeline *p); 9067 9068 int 9069 rte_swx_pipeline_build(struct rte_swx_pipeline *p) 9070 { 9071 int status; 9072 9073 CHECK(p, EINVAL); 9074 CHECK(p->build_done == 0, EEXIST); 9075 9076 status = port_in_build(p); 9077 if (status) 9078 goto error; 9079 9080 status = port_out_build(p); 9081 if (status) 9082 goto error; 9083 9084 status = struct_build(p); 9085 if (status) 9086 goto error; 9087 9088 status = extern_obj_build(p); 9089 if (status) 9090 goto error; 9091 9092 status = extern_func_build(p); 9093 if (status) 9094 goto error; 9095 9096 status = header_build(p); 9097 if (status) 9098 goto error; 9099 9100 status = metadata_build(p); 9101 if (status) 9102 goto error; 9103 9104 status = instruction_table_build(p); 9105 if (status) 9106 goto error; 9107 9108 status = action_build(p); 9109 if (status) 9110 goto error; 9111 9112 status = table_build(p); 9113 if (status) 9114 goto error; 9115 9116 status = selector_build(p); 9117 if (status) 9118 goto error; 9119 9120 status = learner_build(p); 9121 if (status) 9122 goto error; 9123 9124 status = table_state_build(p); 9125 if (status) 9126 goto error; 9127 9128 status = regarray_build(p); 9129 if (status) 9130 goto error; 9131 9132 status = metarray_build(p); 9133 if (status) 9134 goto error; 9135 9136 p->build_done = 1; 9137 9138 pipeline_compile(p); 9139 9140 return 0; 9141 9142 error: 9143 metarray_build_free(p); 9144 regarray_build_free(p); 9145 table_state_build_free(p); 9146 learner_build_free(p); 9147 selector_build_free(p); 9148 table_build_free(p); 9149 action_build_free(p); 9150 instruction_table_build_free(p); 9151 metadata_build_free(p); 9152 header_build_free(p); 9153 extern_func_build_free(p); 9154 extern_obj_build_free(p); 9155 port_out_build_free(p); 9156 port_in_build_free(p); 9157 struct_build_free(p); 9158 9159 return status; 9160 } 9161 9162 void 9163 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions) 9164 { 9165 uint32_t i; 9166 9167 for (i = 0; i < n_instructions; i++) 9168 instr_exec(p); 9169 } 9170 9171 void 9172 rte_swx_pipeline_flush(struct rte_swx_pipeline *p) 9173 { 9174 uint32_t i; 9175 9176 for (i = 0; i < p->n_ports_out; i++) { 9177 struct port_out_runtime *port = &p->out[i]; 9178 9179 if (port->flush) 9180 port->flush(port->obj); 9181 } 9182 } 9183 9184 /* 9185 * Control. 9186 */ 9187 int 9188 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, 9189 struct rte_swx_ctl_pipeline_info *pipeline) 9190 { 9191 struct action *action; 9192 struct table *table; 9193 uint32_t n_actions = 0, n_tables = 0; 9194 9195 if (!p || !pipeline) 9196 return -EINVAL; 9197 9198 TAILQ_FOREACH(action, &p->actions, node) 9199 n_actions++; 9200 9201 TAILQ_FOREACH(table, &p->tables, node) 9202 n_tables++; 9203 9204 pipeline->n_ports_in = p->n_ports_in; 9205 pipeline->n_ports_out = p->n_ports_out; 9206 pipeline->n_actions = n_actions; 9207 pipeline->n_tables = n_tables; 9208 pipeline->n_selectors = p->n_selectors; 9209 pipeline->n_learners = p->n_learners; 9210 pipeline->n_regarrays = p->n_regarrays; 9211 pipeline->n_metarrays = p->n_metarrays; 9212 9213 return 0; 9214 } 9215 9216 int 9217 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node) 9218 { 9219 if (!p || !numa_node) 9220 return -EINVAL; 9221 9222 *numa_node = p->numa_node; 9223 return 0; 9224 } 9225 9226 int 9227 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, 9228 uint32_t action_id, 9229 struct rte_swx_ctl_action_info *action) 9230 { 9231 struct action *a = NULL; 9232 9233 if (!p || (action_id >= p->n_actions) || !action) 9234 return -EINVAL; 9235 9236 a = action_find_by_id(p, action_id); 9237 if (!a) 9238 return -EINVAL; 9239 9240 strcpy(action->name, a->name); 9241 action->n_args = a->st ? a->st->n_fields : 0; 9242 return 0; 9243 } 9244 9245 int 9246 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, 9247 uint32_t action_id, 9248 uint32_t action_arg_id, 9249 struct rte_swx_ctl_action_arg_info *action_arg) 9250 { 9251 struct action *a = NULL; 9252 struct field *arg = NULL; 9253 9254 if (!p || (action_id >= p->n_actions) || !action_arg) 9255 return -EINVAL; 9256 9257 a = action_find_by_id(p, action_id); 9258 if (!a || !a->st || (action_arg_id >= a->st->n_fields)) 9259 return -EINVAL; 9260 9261 arg = &a->st->fields[action_arg_id]; 9262 strcpy(action_arg->name, arg->name); 9263 action_arg->n_bits = arg->n_bits; 9264 action_arg->is_network_byte_order = a->args_endianness[action_arg_id]; 9265 9266 return 0; 9267 } 9268 9269 int 9270 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, 9271 uint32_t table_id, 9272 struct rte_swx_ctl_table_info *table) 9273 { 9274 struct table *t = NULL; 9275 9276 if (!p || !table) 9277 return -EINVAL; 9278 9279 t = table_find_by_id(p, table_id); 9280 if (!t) 9281 return -EINVAL; 9282 9283 strcpy(table->name, t->name); 9284 strcpy(table->args, t->args); 9285 table->n_match_fields = t->n_fields; 9286 table->n_actions = t->n_actions; 9287 table->default_action_is_const = t->default_action_is_const; 9288 table->size = t->size; 9289 return 0; 9290 } 9291 9292 int 9293 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, 9294 uint32_t table_id, 9295 uint32_t match_field_id, 9296 struct rte_swx_ctl_table_match_field_info *match_field) 9297 { 9298 struct table *t; 9299 struct match_field *f; 9300 9301 if (!p || (table_id >= p->n_tables) || !match_field) 9302 return -EINVAL; 9303 9304 t = table_find_by_id(p, table_id); 9305 if (!t || (match_field_id >= t->n_fields)) 9306 return -EINVAL; 9307 9308 f = &t->fields[match_field_id]; 9309 match_field->match_type = f->match_type; 9310 match_field->is_header = t->header ? 1 : 0; 9311 match_field->n_bits = f->field->n_bits; 9312 match_field->offset = f->field->offset; 9313 9314 return 0; 9315 } 9316 9317 int 9318 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, 9319 uint32_t table_id, 9320 uint32_t table_action_id, 9321 struct rte_swx_ctl_table_action_info *table_action) 9322 { 9323 struct table *t; 9324 9325 if (!p || (table_id >= p->n_tables) || !table_action) 9326 return -EINVAL; 9327 9328 t = table_find_by_id(p, table_id); 9329 if (!t || (table_action_id >= t->n_actions)) 9330 return -EINVAL; 9331 9332 table_action->action_id = t->actions[table_action_id]->id; 9333 9334 table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; 9335 table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; 9336 9337 return 0; 9338 } 9339 9340 int 9341 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, 9342 uint32_t table_id, 9343 struct rte_swx_table_ops *table_ops, 9344 int *is_stub) 9345 { 9346 struct table *t; 9347 9348 if (!p || (table_id >= p->n_tables)) 9349 return -EINVAL; 9350 9351 t = table_find_by_id(p, table_id); 9352 if (!t) 9353 return -EINVAL; 9354 9355 if (t->type) { 9356 if (table_ops) 9357 memcpy(table_ops, &t->type->ops, sizeof(*table_ops)); 9358 *is_stub = 0; 9359 } else { 9360 *is_stub = 1; 9361 } 9362 9363 return 0; 9364 } 9365 9366 int 9367 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p, 9368 uint32_t selector_id, 9369 struct rte_swx_ctl_selector_info *selector) 9370 { 9371 struct selector *s = NULL; 9372 9373 if (!p || !selector) 9374 return -EINVAL; 9375 9376 s = selector_find_by_id(p, selector_id); 9377 if (!s) 9378 return -EINVAL; 9379 9380 strcpy(selector->name, s->name); 9381 9382 selector->n_selector_fields = s->n_selector_fields; 9383 selector->n_groups_max = s->n_groups_max; 9384 selector->n_members_per_group_max = s->n_members_per_group_max; 9385 9386 return 0; 9387 } 9388 9389 int 9390 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p, 9391 uint32_t selector_id, 9392 struct rte_swx_ctl_table_match_field_info *field) 9393 { 9394 struct selector *s; 9395 9396 if (!p || (selector_id >= p->n_selectors) || !field) 9397 return -EINVAL; 9398 9399 s = selector_find_by_id(p, selector_id); 9400 if (!s) 9401 return -EINVAL; 9402 9403 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9404 field->is_header = 0; 9405 field->n_bits = s->group_id_field->n_bits; 9406 field->offset = s->group_id_field->offset; 9407 9408 return 0; 9409 } 9410 9411 int 9412 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p, 9413 uint32_t selector_id, 9414 uint32_t selector_field_id, 9415 struct rte_swx_ctl_table_match_field_info *field) 9416 { 9417 struct selector *s; 9418 struct field *f; 9419 9420 if (!p || (selector_id >= p->n_selectors) || !field) 9421 return -EINVAL; 9422 9423 s = selector_find_by_id(p, selector_id); 9424 if (!s || (selector_field_id >= s->n_selector_fields)) 9425 return -EINVAL; 9426 9427 f = s->selector_fields[selector_field_id]; 9428 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9429 field->is_header = s->selector_header ? 1 : 0; 9430 field->n_bits = f->n_bits; 9431 field->offset = f->offset; 9432 9433 return 0; 9434 } 9435 9436 int 9437 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p, 9438 uint32_t selector_id, 9439 struct rte_swx_ctl_table_match_field_info *field) 9440 { 9441 struct selector *s; 9442 9443 if (!p || (selector_id >= p->n_selectors) || !field) 9444 return -EINVAL; 9445 9446 s = selector_find_by_id(p, selector_id); 9447 if (!s) 9448 return -EINVAL; 9449 9450 field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9451 field->is_header = 0; 9452 field->n_bits = s->member_id_field->n_bits; 9453 field->offset = s->member_id_field->offset; 9454 9455 return 0; 9456 } 9457 9458 int 9459 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p, 9460 uint32_t learner_id, 9461 struct rte_swx_ctl_learner_info *learner) 9462 { 9463 struct learner *l = NULL; 9464 9465 if (!p || !learner) 9466 return -EINVAL; 9467 9468 l = learner_find_by_id(p, learner_id); 9469 if (!l) 9470 return -EINVAL; 9471 9472 strcpy(learner->name, l->name); 9473 9474 learner->n_match_fields = l->n_fields; 9475 learner->n_actions = l->n_actions; 9476 learner->default_action_is_const = l->default_action_is_const; 9477 learner->size = l->size; 9478 9479 return 0; 9480 } 9481 9482 int 9483 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p, 9484 uint32_t learner_id, 9485 uint32_t match_field_id, 9486 struct rte_swx_ctl_table_match_field_info *match_field) 9487 { 9488 struct learner *l; 9489 struct field *f; 9490 9491 if (!p || (learner_id >= p->n_learners) || !match_field) 9492 return -EINVAL; 9493 9494 l = learner_find_by_id(p, learner_id); 9495 if (!l || (match_field_id >= l->n_fields)) 9496 return -EINVAL; 9497 9498 f = l->fields[match_field_id]; 9499 match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT; 9500 match_field->is_header = l->header ? 1 : 0; 9501 match_field->n_bits = f->n_bits; 9502 match_field->offset = f->offset; 9503 9504 return 0; 9505 } 9506 9507 int 9508 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, 9509 uint32_t learner_id, 9510 uint32_t learner_action_id, 9511 struct rte_swx_ctl_table_action_info *learner_action) 9512 { 9513 struct learner *l; 9514 9515 if (!p || (learner_id >= p->n_learners) || !learner_action) 9516 return -EINVAL; 9517 9518 l = learner_find_by_id(p, learner_id); 9519 if (!l || (learner_action_id >= l->n_actions)) 9520 return -EINVAL; 9521 9522 learner_action->action_id = l->actions[learner_action_id]->id; 9523 9524 learner_action->action_is_for_table_entries = 9525 l->action_is_for_table_entries[learner_action_id]; 9526 9527 learner_action->action_is_for_default_entry = 9528 l->action_is_for_default_entry[learner_action_id]; 9529 9530 return 0; 9531 } 9532 9533 int 9534 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p, 9535 struct rte_swx_table_state **table_state) 9536 { 9537 if (!p || !table_state || !p->build_done) 9538 return -EINVAL; 9539 9540 *table_state = p->table_state; 9541 return 0; 9542 } 9543 9544 int 9545 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p, 9546 struct rte_swx_table_state *table_state) 9547 { 9548 if (!p || !table_state || !p->build_done) 9549 return -EINVAL; 9550 9551 p->table_state = table_state; 9552 return 0; 9553 } 9554 9555 int 9556 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, 9557 uint32_t port_id, 9558 struct rte_swx_port_in_stats *stats) 9559 { 9560 struct port_in *port; 9561 9562 if (!p || !stats) 9563 return -EINVAL; 9564 9565 port = port_in_find(p, port_id); 9566 if (!port) 9567 return -EINVAL; 9568 9569 port->type->ops.stats_read(port->obj, stats); 9570 return 0; 9571 } 9572 9573 int 9574 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, 9575 uint32_t port_id, 9576 struct rte_swx_port_out_stats *stats) 9577 { 9578 struct port_out *port; 9579 9580 if (!p || !stats) 9581 return -EINVAL; 9582 9583 port = port_out_find(p, port_id); 9584 if (!port) 9585 return -EINVAL; 9586 9587 port->type->ops.stats_read(port->obj, stats); 9588 return 0; 9589 } 9590 9591 int 9592 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p, 9593 const char *table_name, 9594 struct rte_swx_table_stats *stats) 9595 { 9596 struct table *table; 9597 struct table_statistics *table_stats; 9598 9599 if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action) 9600 return -EINVAL; 9601 9602 table = table_find(p, table_name); 9603 if (!table) 9604 return -EINVAL; 9605 9606 table_stats = &p->table_stats[table->id]; 9607 9608 memcpy(stats->n_pkts_action, 9609 table_stats->n_pkts_action, 9610 p->n_actions * sizeof(uint64_t)); 9611 9612 stats->n_pkts_hit = table_stats->n_pkts_hit[1]; 9613 stats->n_pkts_miss = table_stats->n_pkts_hit[0]; 9614 9615 return 0; 9616 } 9617 9618 int 9619 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p, 9620 const char *selector_name, 9621 struct rte_swx_pipeline_selector_stats *stats) 9622 { 9623 struct selector *s; 9624 9625 if (!p || !selector_name || !selector_name[0] || !stats) 9626 return -EINVAL; 9627 9628 s = selector_find(p, selector_name); 9629 if (!s) 9630 return -EINVAL; 9631 9632 stats->n_pkts = p->selector_stats[s->id].n_pkts; 9633 9634 return 0; 9635 } 9636 9637 int 9638 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, 9639 const char *learner_name, 9640 struct rte_swx_learner_stats *stats) 9641 { 9642 struct learner *l; 9643 struct learner_statistics *learner_stats; 9644 9645 if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action) 9646 return -EINVAL; 9647 9648 l = learner_find(p, learner_name); 9649 if (!l) 9650 return -EINVAL; 9651 9652 learner_stats = &p->learner_stats[l->id]; 9653 9654 memcpy(stats->n_pkts_action, 9655 learner_stats->n_pkts_action, 9656 p->n_actions * sizeof(uint64_t)); 9657 9658 stats->n_pkts_hit = learner_stats->n_pkts_hit[1]; 9659 stats->n_pkts_miss = learner_stats->n_pkts_hit[0]; 9660 9661 stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0]; 9662 stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1]; 9663 9664 stats->n_pkts_forget = learner_stats->n_pkts_forget; 9665 9666 return 0; 9667 } 9668 9669 int 9670 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p, 9671 uint32_t regarray_id, 9672 struct rte_swx_ctl_regarray_info *regarray) 9673 { 9674 struct regarray *r; 9675 9676 if (!p || !regarray) 9677 return -EINVAL; 9678 9679 r = regarray_find_by_id(p, regarray_id); 9680 if (!r) 9681 return -EINVAL; 9682 9683 strcpy(regarray->name, r->name); 9684 regarray->size = r->size; 9685 return 0; 9686 } 9687 9688 int 9689 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p, 9690 const char *regarray_name, 9691 uint32_t regarray_index, 9692 uint64_t *value) 9693 { 9694 struct regarray *regarray; 9695 struct regarray_runtime *r; 9696 9697 if (!p || !regarray_name || !value) 9698 return -EINVAL; 9699 9700 regarray = regarray_find(p, regarray_name); 9701 if (!regarray || (regarray_index >= regarray->size)) 9702 return -EINVAL; 9703 9704 r = &p->regarray_runtime[regarray->id]; 9705 *value = r->regarray[regarray_index]; 9706 return 0; 9707 } 9708 9709 int 9710 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p, 9711 const char *regarray_name, 9712 uint32_t regarray_index, 9713 uint64_t value) 9714 { 9715 struct regarray *regarray; 9716 struct regarray_runtime *r; 9717 9718 if (!p || !regarray_name) 9719 return -EINVAL; 9720 9721 regarray = regarray_find(p, regarray_name); 9722 if (!regarray || (regarray_index >= regarray->size)) 9723 return -EINVAL; 9724 9725 r = &p->regarray_runtime[regarray->id]; 9726 r->regarray[regarray_index] = value; 9727 return 0; 9728 } 9729 9730 int 9731 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p, 9732 uint32_t metarray_id, 9733 struct rte_swx_ctl_metarray_info *metarray) 9734 { 9735 struct metarray *m; 9736 9737 if (!p || !metarray) 9738 return -EINVAL; 9739 9740 m = metarray_find_by_id(p, metarray_id); 9741 if (!m) 9742 return -EINVAL; 9743 9744 strcpy(metarray->name, m->name); 9745 metarray->size = m->size; 9746 return 0; 9747 } 9748 9749 int 9750 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p, 9751 const char *name, 9752 struct rte_meter_trtcm_params *params) 9753 { 9754 struct meter_profile *mp; 9755 int status; 9756 9757 CHECK(p, EINVAL); 9758 CHECK_NAME(name, EINVAL); 9759 CHECK(params, EINVAL); 9760 CHECK(!meter_profile_find(p, name), EEXIST); 9761 9762 /* Node allocation. */ 9763 mp = calloc(1, sizeof(struct meter_profile)); 9764 CHECK(mp, ENOMEM); 9765 9766 /* Node initialization. */ 9767 strcpy(mp->name, name); 9768 memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params)); 9769 status = rte_meter_trtcm_profile_config(&mp->profile, params); 9770 if (status) { 9771 free(mp); 9772 CHECK(0, EINVAL); 9773 } 9774 9775 /* Node add to tailq. */ 9776 TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node); 9777 9778 return 0; 9779 } 9780 9781 int 9782 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p, 9783 const char *name) 9784 { 9785 struct meter_profile *mp; 9786 9787 CHECK(p, EINVAL); 9788 CHECK_NAME(name, EINVAL); 9789 9790 mp = meter_profile_find(p, name); 9791 CHECK(mp, EINVAL); 9792 CHECK(!mp->n_users, EBUSY); 9793 9794 /* Remove node from tailq. */ 9795 TAILQ_REMOVE(&p->meter_profiles, mp, node); 9796 free(mp); 9797 9798 return 0; 9799 } 9800 9801 int 9802 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p, 9803 const char *metarray_name, 9804 uint32_t metarray_index) 9805 { 9806 struct meter_profile *mp_old; 9807 struct metarray *metarray; 9808 struct metarray_runtime *metarray_runtime; 9809 struct meter *m; 9810 9811 CHECK(p, EINVAL); 9812 CHECK_NAME(metarray_name, EINVAL); 9813 9814 metarray = metarray_find(p, metarray_name); 9815 CHECK(metarray, EINVAL); 9816 CHECK(metarray_index < metarray->size, EINVAL); 9817 9818 metarray_runtime = &p->metarray_runtime[metarray->id]; 9819 m = &metarray_runtime->metarray[metarray_index]; 9820 mp_old = m->profile; 9821 9822 meter_init(m); 9823 9824 mp_old->n_users--; 9825 9826 return 0; 9827 } 9828 9829 int 9830 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p, 9831 const char *metarray_name, 9832 uint32_t metarray_index, 9833 const char *profile_name) 9834 { 9835 struct meter_profile *mp, *mp_old; 9836 struct metarray *metarray; 9837 struct metarray_runtime *metarray_runtime; 9838 struct meter *m; 9839 9840 CHECK(p, EINVAL); 9841 CHECK_NAME(metarray_name, EINVAL); 9842 9843 metarray = metarray_find(p, metarray_name); 9844 CHECK(metarray, EINVAL); 9845 CHECK(metarray_index < metarray->size, EINVAL); 9846 9847 mp = meter_profile_find(p, profile_name); 9848 CHECK(mp, EINVAL); 9849 9850 metarray_runtime = &p->metarray_runtime[metarray->id]; 9851 m = &metarray_runtime->metarray[metarray_index]; 9852 mp_old = m->profile; 9853 9854 memset(m, 0, sizeof(struct meter)); 9855 rte_meter_trtcm_config(&m->m, &mp->profile); 9856 m->profile = mp; 9857 m->color_mask = RTE_COLORS; 9858 9859 mp->n_users++; 9860 mp_old->n_users--; 9861 9862 return 0; 9863 } 9864 9865 int 9866 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, 9867 const char *metarray_name, 9868 uint32_t metarray_index, 9869 struct rte_swx_ctl_meter_stats *stats) 9870 { 9871 struct metarray *metarray; 9872 struct metarray_runtime *metarray_runtime; 9873 struct meter *m; 9874 9875 CHECK(p, EINVAL); 9876 CHECK_NAME(metarray_name, EINVAL); 9877 9878 metarray = metarray_find(p, metarray_name); 9879 CHECK(metarray, EINVAL); 9880 CHECK(metarray_index < metarray->size, EINVAL); 9881 9882 CHECK(stats, EINVAL); 9883 9884 metarray_runtime = &p->metarray_runtime[metarray->id]; 9885 m = &metarray_runtime->metarray[metarray_index]; 9886 9887 memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts)); 9888 memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes)); 9889 9890 return 0; 9891 } 9892 9893 /* 9894 * Pipeline compilation. 9895 */ 9896 static const char * 9897 instr_type_to_name(struct instruction *instr) 9898 { 9899 switch (instr->type) { 9900 case INSTR_RX: return "INSTR_RX"; 9901 9902 case INSTR_TX: return "INSTR_TX"; 9903 case INSTR_TX_I: return "INSTR_TX_I"; 9904 9905 case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; 9906 case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; 9907 case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3"; 9908 case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4"; 9909 case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5"; 9910 case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6"; 9911 case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7"; 9912 case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8"; 9913 9914 case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M"; 9915 9916 case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD"; 9917 9918 case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT"; 9919 case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX"; 9920 case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX"; 9921 case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX"; 9922 case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX"; 9923 case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX"; 9924 case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX"; 9925 case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX"; 9926 case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX"; 9927 9928 case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE"; 9929 case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE"; 9930 9931 case INSTR_MOV: return "INSTR_MOV"; 9932 case INSTR_MOV_MH: return "INSTR_MOV_MH"; 9933 case INSTR_MOV_HM: return "INSTR_MOV_HM"; 9934 case INSTR_MOV_HH: return "INSTR_MOV_HH"; 9935 case INSTR_MOV_I: return "INSTR_MOV_I"; 9936 9937 case INSTR_DMA_HT: return "INSTR_DMA_HT"; 9938 case INSTR_DMA_HT2: return "INSTR_DMA_HT2"; 9939 case INSTR_DMA_HT3: return "INSTR_DMA_HT3"; 9940 case INSTR_DMA_HT4: return "INSTR_DMA_HT4"; 9941 case INSTR_DMA_HT5: return "INSTR_DMA_HT5"; 9942 case INSTR_DMA_HT6: return "INSTR_DMA_HT6"; 9943 case INSTR_DMA_HT7: return "INSTR_DMA_HT7"; 9944 case INSTR_DMA_HT8: return "INSTR_DMA_HT8"; 9945 9946 case INSTR_ALU_ADD: return "INSTR_ALU_ADD"; 9947 case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH"; 9948 case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM"; 9949 case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH"; 9950 case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI"; 9951 case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI"; 9952 9953 case INSTR_ALU_SUB: return "INSTR_ALU_SUB"; 9954 case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH"; 9955 case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM"; 9956 case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH"; 9957 case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI"; 9958 case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI"; 9959 9960 case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD"; 9961 case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20"; 9962 case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT"; 9963 case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD"; 9964 9965 case INSTR_ALU_AND: return "INSTR_ALU_AND"; 9966 case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH"; 9967 case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM"; 9968 case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH"; 9969 case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I"; 9970 9971 case INSTR_ALU_OR: return "INSTR_ALU_OR"; 9972 case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH"; 9973 case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM"; 9974 case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH"; 9975 case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I"; 9976 9977 case INSTR_ALU_XOR: return "INSTR_ALU_XOR"; 9978 case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH"; 9979 case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM"; 9980 case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH"; 9981 case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I"; 9982 9983 case INSTR_ALU_SHL: return "INSTR_ALU_SHL"; 9984 case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH"; 9985 case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM"; 9986 case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH"; 9987 case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI"; 9988 case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI"; 9989 9990 case INSTR_ALU_SHR: return "INSTR_ALU_SHR"; 9991 case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH"; 9992 case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM"; 9993 case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH"; 9994 case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI"; 9995 case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI"; 9996 9997 case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH"; 9998 case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM"; 9999 case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI"; 10000 10001 case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH"; 10002 case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM"; 10003 case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI"; 10004 case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH"; 10005 case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM"; 10006 case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI"; 10007 10008 case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH"; 10009 case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM"; 10010 case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI"; 10011 case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH"; 10012 case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM"; 10013 case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI"; 10014 case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH"; 10015 case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM"; 10016 case INSTR_REGWR_RII: return "INSTR_REGWR_RII"; 10017 10018 case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH"; 10019 case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM"; 10020 case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI"; 10021 case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH"; 10022 case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM"; 10023 case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI"; 10024 case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH"; 10025 case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM"; 10026 case INSTR_REGADD_RII: return "INSTR_REGADD_RII"; 10027 10028 case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H"; 10029 case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M"; 10030 case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I"; 10031 10032 case INSTR_METER_HHM: return "INSTR_METER_HHM"; 10033 case INSTR_METER_HHI: return "INSTR_METER_HHI"; 10034 case INSTR_METER_HMM: return "INSTR_METER_HMM"; 10035 case INSTR_METER_HMI: return "INSTR_METER_HMI"; 10036 case INSTR_METER_MHM: return "INSTR_METER_MHM"; 10037 case INSTR_METER_MHI: return "INSTR_METER_MHI"; 10038 case INSTR_METER_MMM: return "INSTR_METER_MMM"; 10039 case INSTR_METER_MMI: return "INSTR_METER_MMI"; 10040 case INSTR_METER_IHM: return "INSTR_METER_IHM"; 10041 case INSTR_METER_IHI: return "INSTR_METER_IHI"; 10042 case INSTR_METER_IMM: return "INSTR_METER_IMM"; 10043 case INSTR_METER_IMI: return "INSTR_METER_IMI"; 10044 10045 case INSTR_TABLE: return "INSTR_TABLE"; 10046 case INSTR_TABLE_AF: return "INSTR_TABLE_AF"; 10047 case INSTR_SELECTOR: return "INSTR_SELECTOR"; 10048 case INSTR_LEARNER: return "INSTR_LEARNER"; 10049 case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; 10050 10051 case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; 10052 case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; 10053 10054 case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; 10055 case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC"; 10056 10057 case INSTR_JMP: return "INSTR_JMP"; 10058 case INSTR_JMP_VALID: return "INSTR_JMP_VALID"; 10059 case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID"; 10060 case INSTR_JMP_HIT: return "INSTR_JMP_HIT"; 10061 case INSTR_JMP_MISS: return "INSTR_JMP_MISS"; 10062 case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT"; 10063 case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS"; 10064 case INSTR_JMP_EQ: return "INSTR_JMP_EQ"; 10065 case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH"; 10066 case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM"; 10067 case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH"; 10068 case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I"; 10069 case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ"; 10070 case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH"; 10071 case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM"; 10072 case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH"; 10073 case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I"; 10074 case INSTR_JMP_LT: return "INSTR_JMP_LT"; 10075 case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH"; 10076 case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM"; 10077 case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH"; 10078 case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI"; 10079 case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI"; 10080 case INSTR_JMP_GT: return "INSTR_JMP_GT"; 10081 case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH"; 10082 case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM"; 10083 case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH"; 10084 case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI"; 10085 case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI"; 10086 10087 case INSTR_RETURN: return "INSTR_RETURN"; 10088 10089 default: return "INSTR_UNKNOWN"; 10090 } 10091 } 10092 10093 typedef void 10094 (*instruction_export_t)(struct instruction *, FILE *); 10095 10096 static void 10097 instr_io_export(struct instruction *instr, FILE *f) 10098 { 10099 uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i; 10100 10101 /* n_io, n_io_imm, n_hdrs. */ 10102 if (instr->type == INSTR_RX || 10103 instr->type == INSTR_TX || 10104 instr->type == INSTR_HDR_EXTRACT_M || 10105 (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)) 10106 n_io = 1; 10107 10108 if (instr->type == INSTR_TX_I) 10109 n_io_imm = 1; 10110 10111 if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8) 10112 n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT); 10113 10114 if (instr->type == INSTR_HDR_EXTRACT_M || 10115 instr->type == INSTR_HDR_LOOKAHEAD || 10116 instr->type == INSTR_HDR_EMIT) 10117 n_hdrs = 1; 10118 10119 if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX) 10120 n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX); 10121 10122 /* instr. */ 10123 fprintf(f, 10124 "\t{\n" 10125 "\t\t.type = %s,\n", 10126 instr_type_to_name(instr)); 10127 10128 /* instr.io. */ 10129 fprintf(f, 10130 "\t\t.io = {\n"); 10131 10132 /* instr.io.io. */ 10133 if (n_io) 10134 fprintf(f, 10135 "\t\t\t.io = {\n" 10136 "\t\t\t\t.offset = %u,\n" 10137 "\t\t\t\t.n_bits = %u,\n" 10138 "\t\t\t},\n", 10139 instr->io.io.offset, 10140 instr->io.io.n_bits); 10141 10142 if (n_io_imm) 10143 fprintf(f, 10144 "\t\t\t.io = {\n" 10145 "\t\t\t\t.val = %u,\n" 10146 "\t\t\t},\n", 10147 instr->io.io.val); 10148 10149 /* instr.io.hdr. */ 10150 if (n_hdrs) { 10151 fprintf(f, 10152 "\t\t.hdr = {\n"); 10153 10154 /* instr.io.hdr.header_id. */ 10155 fprintf(f, 10156 "\t\t\t.header_id = {"); 10157 10158 for (i = 0; i < n_hdrs; i++) 10159 fprintf(f, 10160 "%u, ", 10161 instr->io.hdr.header_id[i]); 10162 10163 fprintf(f, 10164 "},\n"); 10165 10166 /* instr.io.hdr.struct_id. */ 10167 fprintf(f, 10168 "\t\t\t.struct_id = {"); 10169 10170 for (i = 0; i < n_hdrs; i++) 10171 fprintf(f, 10172 "%u, ", 10173 instr->io.hdr.struct_id[i]); 10174 10175 fprintf(f, 10176 "},\n"); 10177 10178 /* instr.io.hdr.n_bytes. */ 10179 fprintf(f, 10180 "\t\t\t.n_bytes = {"); 10181 10182 for (i = 0; i < n_hdrs; i++) 10183 fprintf(f, 10184 "%u, ", 10185 instr->io.hdr.n_bytes[i]); 10186 10187 fprintf(f, 10188 "},\n"); 10189 10190 /* instr.io.hdr - closing curly brace. */ 10191 fprintf(f, 10192 "\t\t\t}\n,"); 10193 } 10194 10195 /* instr.io - closing curly brace. */ 10196 fprintf(f, 10197 "\t\t},\n"); 10198 10199 /* instr - closing curly brace. */ 10200 fprintf(f, 10201 "\t},\n"); 10202 } 10203 10204 static void 10205 instr_hdr_validate_export(struct instruction *instr, FILE *f) 10206 { 10207 fprintf(f, 10208 "\t{\n" 10209 "\t\t.type = %s,\n" 10210 "\t\t.valid = {\n" 10211 "\t\t\t.header_id = %u,\n" 10212 "\t\t},\n" 10213 "\t},\n", 10214 instr_type_to_name(instr), 10215 instr->valid.header_id); 10216 } 10217 10218 static void 10219 instr_mov_export(struct instruction *instr, FILE *f) 10220 { 10221 if (instr->type != INSTR_MOV_I) 10222 fprintf(f, 10223 "\t{\n" 10224 "\t\t.type = %s,\n" 10225 "\t\t.mov = {\n" 10226 "\t\t\t.dst = {\n" 10227 "\t\t\t\t.struct_id = %u,\n" 10228 "\t\t\t\t.n_bits = %u,\n" 10229 "\t\t\t\t.offset = %u,\n" 10230 "\t\t\t},\n" 10231 "\t\t\t.src = {\n" 10232 "\t\t\t\t.struct_id = %u,\n" 10233 "\t\t\t\t.n_bits = %u,\n" 10234 "\t\t\t\t.offset = %u,\n" 10235 "\t\t\t},\n" 10236 "\t\t},\n" 10237 "\t},\n", 10238 instr_type_to_name(instr), 10239 instr->mov.dst.struct_id, 10240 instr->mov.dst.n_bits, 10241 instr->mov.dst.offset, 10242 instr->mov.src.struct_id, 10243 instr->mov.src.n_bits, 10244 instr->mov.src.offset); 10245 else 10246 fprintf(f, 10247 "\t{\n" 10248 "\t\t.type = %s,\n" 10249 "\t\t.mov = {\n" 10250 "\t\t\t.dst = {\n" 10251 "\t\t\t\t.struct_id = %u,\n" 10252 "\t\t\t\t.n_bits = %u,\n" 10253 "\t\t\t\t.offset = %u,\n" 10254 "\t\t\t}\n," 10255 "\t\t\t.src_val = %" PRIu64 ",\n" 10256 "\t\t},\n" 10257 "\t},\n", 10258 instr_type_to_name(instr), 10259 instr->mov.dst.struct_id, 10260 instr->mov.dst.n_bits, 10261 instr->mov.dst.offset, 10262 instr->mov.src_val); 10263 } 10264 10265 static void 10266 instr_dma_ht_export(struct instruction *instr, FILE *f) 10267 { 10268 uint32_t n_dma = 0, i; 10269 10270 /* n_dma. */ 10271 n_dma = 1 + (instr->type - INSTR_DMA_HT); 10272 10273 /* instr. */ 10274 fprintf(f, 10275 "\t{\n" 10276 "\t\t.type = %s,\n", 10277 instr_type_to_name(instr)); 10278 10279 /* instr.dma. */ 10280 fprintf(f, 10281 "\t\t.dma = {\n"); 10282 10283 /* instr.dma.dst. */ 10284 fprintf(f, 10285 "\t\t\t.dst = {\n"); 10286 10287 /* instr.dma.dst.header_id. */ 10288 fprintf(f, 10289 "\t\t\t\t.header_id = {"); 10290 10291 for (i = 0; i < n_dma; i++) 10292 fprintf(f, 10293 "%u, ", 10294 instr->dma.dst.header_id[i]); 10295 10296 fprintf(f, 10297 "},\n"); 10298 10299 /* instr.dma.dst.struct_id. */ 10300 fprintf(f, 10301 "\t\t\t\t.struct_id = {"); 10302 10303 for (i = 0; i < n_dma; i++) 10304 fprintf(f, 10305 "%u, ", 10306 instr->dma.dst.struct_id[i]); 10307 10308 fprintf(f, 10309 "},\n"); 10310 10311 /* instr.dma.dst - closing curly brace. */ 10312 fprintf(f, 10313 "\t\t\t},\n"); 10314 10315 /* instr.dma.src. */ 10316 fprintf(f, 10317 "\t\t\t.src = {\n"); 10318 10319 /* instr.dma.src.offset. */ 10320 fprintf(f, 10321 "\t\t\t\t.offset = {"); 10322 10323 for (i = 0; i < n_dma; i++) 10324 fprintf(f, 10325 "%u, ", 10326 instr->dma.src.offset[i]); 10327 10328 fprintf(f, 10329 "},\n"); 10330 10331 /* instr.dma.src - closing curly brace. */ 10332 fprintf(f, 10333 "\t\t\t},\n"); 10334 10335 /* instr.dma.n_bytes. */ 10336 fprintf(f, 10337 "\t\t\t.n_bytes = {"); 10338 10339 for (i = 0; i < n_dma; i++) 10340 fprintf(f, 10341 "%u, ", 10342 instr->dma.n_bytes[i]); 10343 10344 fprintf(f, 10345 "},\n"); 10346 10347 /* instr.dma - closing curly brace. */ 10348 fprintf(f, 10349 "\t\t},\n"); 10350 10351 /* instr - closing curly brace. */ 10352 fprintf(f, 10353 "\t},\n"); 10354 } 10355 10356 static void 10357 instr_alu_export(struct instruction *instr, FILE *f) 10358 { 10359 int imm = 0; 10360 10361 if (instr->type == INSTR_ALU_ADD_MI || 10362 instr->type == INSTR_ALU_ADD_HI || 10363 instr->type == INSTR_ALU_SUB_MI || 10364 instr->type == INSTR_ALU_SUB_HI || 10365 instr->type == INSTR_ALU_SHL_MI || 10366 instr->type == INSTR_ALU_SHL_HI || 10367 instr->type == INSTR_ALU_SHR_MI || 10368 instr->type == INSTR_ALU_SHR_HI || 10369 instr->type == INSTR_ALU_AND_I || 10370 instr->type == INSTR_ALU_OR_I || 10371 instr->type == INSTR_ALU_XOR_I) 10372 imm = 1; 10373 10374 if (!imm) 10375 fprintf(f, 10376 "\t{\n" 10377 "\t\t.type = %s,\n" 10378 "\t\t.alu = {\n" 10379 "\t\t\t.dst = {\n" 10380 "\t\t\t\t.struct_id = %u,\n" 10381 "\t\t\t\t.n_bits = %u,\n" 10382 "\t\t\t\t.offset = %u,\n" 10383 "\t\t\t},\n" 10384 "\t\t\t.src = {\n" 10385 "\t\t\t\t.struct_id = %u,\n" 10386 "\t\t\t\t.n_bits = %u,\n" 10387 "\t\t\t\t.offset = %u,\n" 10388 "\t\t\t},\n" 10389 "\t\t},\n" 10390 "\t},\n", 10391 instr_type_to_name(instr), 10392 instr->alu.dst.struct_id, 10393 instr->alu.dst.n_bits, 10394 instr->alu.dst.offset, 10395 instr->alu.src.struct_id, 10396 instr->alu.src.n_bits, 10397 instr->alu.src.offset); 10398 else 10399 fprintf(f, 10400 "\t{\n" 10401 "\t\t.type = %s,\n" 10402 "\t\t.alu = {\n" 10403 "\t\t\t.dst = {\n" 10404 "\t\t\t\t.struct_id = %u,\n" 10405 "\t\t\t\t.n_bits = %u,\n" 10406 "\t\t\t\t.offset = %u,\n" 10407 "\t\t\t}\n," 10408 "\t\t\t.src_val = %" PRIu64 ",\n" 10409 "\t\t},\n" 10410 "\t},\n", 10411 instr_type_to_name(instr), 10412 instr->alu.dst.struct_id, 10413 instr->alu.dst.n_bits, 10414 instr->alu.dst.offset, 10415 instr->alu.src_val); 10416 } 10417 10418 static void 10419 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 10420 { 10421 int prefetch = 0, idx_imm = 0, src_imm = 0; 10422 10423 if (instr->type == INSTR_REGPREFETCH_RH || 10424 instr->type == INSTR_REGPREFETCH_RM || 10425 instr->type == INSTR_REGPREFETCH_RI) 10426 prefetch = 1; 10427 10428 /* index is the 3rd operand for the regrd instruction and the 2nd 10429 * operand for the regwr and regadd instructions. 10430 */ 10431 if (instr->type == INSTR_REGPREFETCH_RI || 10432 instr->type == INSTR_REGRD_HRI || 10433 instr->type == INSTR_REGRD_MRI || 10434 instr->type == INSTR_REGWR_RIH || 10435 instr->type == INSTR_REGWR_RIM || 10436 instr->type == INSTR_REGWR_RII || 10437 instr->type == INSTR_REGADD_RIH || 10438 instr->type == INSTR_REGADD_RIM || 10439 instr->type == INSTR_REGADD_RII) 10440 idx_imm = 1; 10441 10442 /* src is the 3rd operand for the regwr and regadd instructions. */ 10443 if (instr->type == INSTR_REGWR_RHI || 10444 instr->type == INSTR_REGWR_RMI || 10445 instr->type == INSTR_REGWR_RII || 10446 instr->type == INSTR_REGADD_RHI || 10447 instr->type == INSTR_REGADD_RMI || 10448 instr->type == INSTR_REGADD_RII) 10449 src_imm = 1; 10450 10451 /* instr.regarray.regarray_id. */ 10452 fprintf(f, 10453 "\t{\n" 10454 "\t\t.type = %s,\n" 10455 "\t\t.regarray = {\n" 10456 "\t\t\t.regarray_id = %u,\n", 10457 instr_type_to_name(instr), 10458 instr->regarray.regarray_id); 10459 10460 /* instr.regarray.idx / instr.regarray.idx_val. */ 10461 if (!idx_imm) 10462 fprintf(f, 10463 "\t\t\t\t.idx = {\n" 10464 "\t\t\t\t\t.struct_id = %u,\n" 10465 "\t\t\t\t\t.n_bits = %u,\n" 10466 "\t\t\t\t\t.offset = %u,\n" 10467 "\t\t\t\t},\n", 10468 instr->regarray.idx.struct_id, 10469 instr->regarray.idx.n_bits, 10470 instr->regarray.idx.offset); 10471 else 10472 fprintf(f, 10473 "\t\t\t\t.idx_val = %u,\n", 10474 instr->regarray.idx_val); 10475 10476 /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */ 10477 if (!prefetch) { 10478 if (!src_imm) 10479 fprintf(f, 10480 "\t\t\t\t.dstsrc = {\n" 10481 "\t\t\t\t\t.struct_id = %u,\n" 10482 "\t\t\t\t\t.n_bits = %u,\n" 10483 "\t\t\t\t\t.offset = %u,\n" 10484 "\t\t\t\t},\n", 10485 instr->regarray.dstsrc.struct_id, 10486 instr->regarray.dstsrc.n_bits, 10487 instr->regarray.dstsrc.offset); 10488 else 10489 fprintf(f, 10490 "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n", 10491 instr->regarray.dstsrc_val); 10492 } 10493 10494 /* instr.regarray and instr - closing curly braces. */ 10495 fprintf(f, 10496 "\t\t},\n" 10497 "\t},\n"); 10498 } 10499 10500 static void 10501 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) 10502 { 10503 int prefetch = 0, idx_imm = 0, color_in_imm = 0; 10504 10505 if (instr->type == INSTR_METPREFETCH_H || 10506 instr->type == INSTR_METPREFETCH_M || 10507 instr->type == INSTR_METPREFETCH_I) 10508 prefetch = 1; 10509 10510 /* idx_imm. */ 10511 if (instr->type == INSTR_METPREFETCH_I || 10512 instr->type == INSTR_METER_IHM || 10513 instr->type == INSTR_METER_IHI || 10514 instr->type == INSTR_METER_IMM || 10515 instr->type == INSTR_METER_IMI) 10516 idx_imm = 1; 10517 10518 /* color_in_imm. */ 10519 if (instr->type == INSTR_METER_HHI || 10520 instr->type == INSTR_METER_HMI || 10521 instr->type == INSTR_METER_MHI || 10522 instr->type == INSTR_METER_MMI || 10523 instr->type == INSTR_METER_IHI || 10524 instr->type == INSTR_METER_IMI) 10525 color_in_imm = 1; 10526 10527 /* instr.meter.metarray_id. */ 10528 fprintf(f, 10529 "\t{\n" 10530 "\t\t.type = %s,\n" 10531 "\t\t.meter = {\n" 10532 "\t\t\t.metarray_id = %u,\n", 10533 instr_type_to_name(instr), 10534 instr->meter.metarray_id); 10535 10536 /* instr.meter.idx / instr.meter.idx_val. */ 10537 if (!idx_imm) 10538 fprintf(f, 10539 "\t\t\t.idx = {\n" 10540 "\t\t\t\t.struct_id = %u,\n" 10541 "\t\t\t\t.n_bits = %u,\n" 10542 "\t\t\t\t.offset = %u,\n" 10543 "\t\t\t},\n", 10544 instr->meter.idx.struct_id, 10545 instr->meter.idx.n_bits, 10546 instr->meter.idx.offset); 10547 else 10548 fprintf(f, 10549 "\t\t\t.idx_val = %u,\n", 10550 instr->meter.idx_val); 10551 10552 if (!prefetch) { 10553 /* instr.meter.length. */ 10554 fprintf(f, 10555 "\t\t\t.length = {\n" 10556 "\t\t\t\t.struct_id = %u,\n" 10557 "\t\t\t\t.n_bits = %u,\n" 10558 "\t\t\t\t.offset = %u,\n" 10559 "\t\t\t},\n", 10560 instr->meter.length.struct_id, 10561 instr->meter.length.n_bits, 10562 instr->meter.length.offset); 10563 10564 /* instr.meter.color_in / instr.meter.color_in_val. */ 10565 if (!color_in_imm) 10566 fprintf(f, 10567 "\t\t\t.color_in = {\n" 10568 "\t\t\t\t.struct_id = %u,\n" 10569 "\t\t\t\t.n_bits = %u,\n" 10570 "\t\t\t\t.offset = %u,\n" 10571 "\t\t\t},\n", 10572 instr->meter.color_in.struct_id, 10573 instr->meter.color_in.n_bits, 10574 instr->meter.color_in.offset); 10575 else 10576 fprintf(f, 10577 "\t\t\t.color_in_val = %u,\n", 10578 (uint32_t)instr->meter.color_in_val); 10579 10580 /* instr.meter.color_out. */ 10581 fprintf(f, 10582 "\t\t\t.color_out = {\n" 10583 "\t\t\t\t.struct_id = %u,\n" 10584 "\t\t\t\t.n_bits = %u,\n" 10585 "\t\t\t\t.offset = %u,\n" 10586 "\t\t\t},\n", 10587 instr->meter.color_out.struct_id, 10588 instr->meter.color_out.n_bits, 10589 instr->meter.color_out.offset); 10590 } 10591 10592 /* instr.meter and instr - closing curly braces. */ 10593 fprintf(f, 10594 "\t\t},\n" 10595 "\t},\n"); 10596 } 10597 10598 static void 10599 instr_table_export(struct instruction *instr, 10600 FILE *f) 10601 { 10602 fprintf(f, 10603 "\t{\n" 10604 "\t\t.type = %s,\n" 10605 "\t\t.table = {\n" 10606 "\t\t\t.table_id = %u,\n" 10607 "\t\t},\n" 10608 "\t},\n", 10609 instr_type_to_name(instr), 10610 instr->table.table_id); 10611 } 10612 10613 static void 10614 instr_learn_export(struct instruction *instr, FILE *f) 10615 { 10616 fprintf(f, 10617 "\t{\n" 10618 "\t\t.type = %s,\n" 10619 "\t\t.learn = {\n" 10620 "\t\t\t\t.action_id = %u,\n" 10621 "\t\t},\n" 10622 "\t},\n", 10623 instr_type_to_name(instr), 10624 instr->learn.action_id); 10625 } 10626 10627 static void 10628 instr_forget_export(struct instruction *instr, FILE *f) 10629 { 10630 fprintf(f, 10631 "\t{\n" 10632 "\t\t.type = %s,\n" 10633 "\t},\n", 10634 instr_type_to_name(instr)); 10635 } 10636 10637 static void 10638 instr_extern_export(struct instruction *instr, FILE *f) 10639 { 10640 if (instr->type == INSTR_EXTERN_OBJ) 10641 fprintf(f, 10642 "\t{\n" 10643 "\t\t.type = %s,\n" 10644 "\t\t.ext_obj = {\n" 10645 "\t\t\t.ext_obj_id = %u,\n" 10646 "\t\t\t.func_id = %u,\n" 10647 "\t\t},\n" 10648 "\t},\n", 10649 instr_type_to_name(instr), 10650 instr->ext_obj.ext_obj_id, 10651 instr->ext_obj.func_id); 10652 else 10653 fprintf(f, 10654 "\t{\n" 10655 "\t\t.type = %s,\n" 10656 "\t\t.ext_func = {\n" 10657 "\t\t\t.ext_func_id = %u,\n" 10658 "\t\t},\n" 10659 "\t},\n", 10660 instr_type_to_name(instr), 10661 instr->ext_func.ext_func_id); 10662 } 10663 10664 static void 10665 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused) 10666 { 10667 fprintf(f, 10668 "\t{\n" 10669 "\t\t.type = %s,\n" 10670 "\t\t.jmp = {\n" 10671 "\t\t\t.ip = NULL,\n", 10672 instr_type_to_name(instr)); 10673 10674 switch (instr->type) { 10675 case INSTR_JMP_VALID: 10676 case INSTR_JMP_INVALID: 10677 fprintf(f, 10678 "\t\t\t.header_id = %u,\n", 10679 instr->jmp.header_id); 10680 break; 10681 10682 case INSTR_JMP_ACTION_HIT: 10683 case INSTR_JMP_ACTION_MISS: 10684 fprintf(f, 10685 "\t\t\t.action_id = %u,\n", 10686 instr->jmp.action_id); 10687 break; 10688 10689 case INSTR_JMP_EQ: 10690 case INSTR_JMP_EQ_MH: 10691 case INSTR_JMP_EQ_HM: 10692 case INSTR_JMP_EQ_HH: 10693 case INSTR_JMP_NEQ: 10694 case INSTR_JMP_NEQ_MH: 10695 case INSTR_JMP_NEQ_HM: 10696 case INSTR_JMP_NEQ_HH: 10697 case INSTR_JMP_LT: 10698 case INSTR_JMP_LT_MH: 10699 case INSTR_JMP_LT_HM: 10700 case INSTR_JMP_LT_HH: 10701 case INSTR_JMP_GT: 10702 case INSTR_JMP_GT_MH: 10703 case INSTR_JMP_GT_HM: 10704 case INSTR_JMP_GT_HH: 10705 fprintf(f, 10706 "\t\t\t.a = {\n" 10707 "\t\t\t\t.struct_id = %u,\n" 10708 "\t\t\t\t.n_bits = %u,\n" 10709 "\t\t\t\t.offset = %u,\n" 10710 "\t\t\t},\n" 10711 "\t\t\t.b = {\n" 10712 "\t\t\t\t.struct_id = %u,\n" 10713 "\t\t\t\t.n_bits = %u,\n" 10714 "\t\t\t\t.offset = %u,\n" 10715 "\t\t\t},\n", 10716 instr->jmp.a.struct_id, 10717 instr->jmp.a.n_bits, 10718 instr->jmp.a.offset, 10719 instr->jmp.b.struct_id, 10720 instr->jmp.b.n_bits, 10721 instr->jmp.b.offset); 10722 break; 10723 10724 case INSTR_JMP_EQ_I: 10725 case INSTR_JMP_NEQ_I: 10726 case INSTR_JMP_LT_MI: 10727 case INSTR_JMP_LT_HI: 10728 case INSTR_JMP_GT_MI: 10729 case INSTR_JMP_GT_HI: 10730 fprintf(f, 10731 "\t\t\t.a = {\n" 10732 "\t\t\t\t.struct_id = %u,\n" 10733 "\t\t\t\t.n_bits = %u,\n" 10734 "\t\t\t\t.offset = %u,\n" 10735 "\t\t\t}\n," 10736 "\t\t\t.b_val = %" PRIu64 ",\n", 10737 instr->jmp.a.struct_id, 10738 instr->jmp.a.n_bits, 10739 instr->jmp.a.offset, 10740 instr->jmp.b_val); 10741 break; 10742 10743 default: 10744 break; 10745 } 10746 10747 fprintf(f, 10748 "\t\t},\n" 10749 "\t},\n"); 10750 } 10751 10752 static void 10753 instr_return_export(struct instruction *instr, 10754 FILE *f) 10755 { 10756 fprintf(f, 10757 "\t{\n" 10758 "\t\t.type = %s,\n", 10759 instr_type_to_name(instr)); 10760 10761 fprintf(f, 10762 "\t},\n"); 10763 } 10764 10765 static instruction_export_t export_table[] = { 10766 [INSTR_RX] = instr_io_export, 10767 10768 [INSTR_TX] = instr_io_export, 10769 [INSTR_TX_I] = instr_io_export, 10770 10771 [INSTR_HDR_EXTRACT] = instr_io_export, 10772 [INSTR_HDR_EXTRACT2] = instr_io_export, 10773 [INSTR_HDR_EXTRACT3] = instr_io_export, 10774 [INSTR_HDR_EXTRACT4] = instr_io_export, 10775 [INSTR_HDR_EXTRACT5] = instr_io_export, 10776 [INSTR_HDR_EXTRACT6] = instr_io_export, 10777 [INSTR_HDR_EXTRACT7] = instr_io_export, 10778 [INSTR_HDR_EXTRACT8] = instr_io_export, 10779 10780 [INSTR_HDR_EXTRACT_M] = instr_io_export, 10781 10782 [INSTR_HDR_LOOKAHEAD] = instr_io_export, 10783 10784 [INSTR_HDR_EMIT] = instr_io_export, 10785 [INSTR_HDR_EMIT_TX] = instr_io_export, 10786 [INSTR_HDR_EMIT2_TX] = instr_io_export, 10787 [INSTR_HDR_EMIT3_TX] = instr_io_export, 10788 [INSTR_HDR_EMIT4_TX] = instr_io_export, 10789 [INSTR_HDR_EMIT5_TX] = instr_io_export, 10790 [INSTR_HDR_EMIT6_TX] = instr_io_export, 10791 [INSTR_HDR_EMIT7_TX] = instr_io_export, 10792 [INSTR_HDR_EMIT8_TX] = instr_io_export, 10793 10794 [INSTR_HDR_VALIDATE] = instr_hdr_validate_export, 10795 [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export, 10796 10797 [INSTR_MOV] = instr_mov_export, 10798 [INSTR_MOV_MH] = instr_mov_export, 10799 [INSTR_MOV_HM] = instr_mov_export, 10800 [INSTR_MOV_HH] = instr_mov_export, 10801 [INSTR_MOV_I] = instr_mov_export, 10802 10803 [INSTR_DMA_HT] = instr_dma_ht_export, 10804 [INSTR_DMA_HT2] = instr_dma_ht_export, 10805 [INSTR_DMA_HT3] = instr_dma_ht_export, 10806 [INSTR_DMA_HT4] = instr_dma_ht_export, 10807 [INSTR_DMA_HT5] = instr_dma_ht_export, 10808 [INSTR_DMA_HT6] = instr_dma_ht_export, 10809 [INSTR_DMA_HT7] = instr_dma_ht_export, 10810 [INSTR_DMA_HT8] = instr_dma_ht_export, 10811 10812 [INSTR_ALU_ADD] = instr_alu_export, 10813 [INSTR_ALU_ADD_MH] = instr_alu_export, 10814 [INSTR_ALU_ADD_HM] = instr_alu_export, 10815 [INSTR_ALU_ADD_HH] = instr_alu_export, 10816 [INSTR_ALU_ADD_MI] = instr_alu_export, 10817 [INSTR_ALU_ADD_HI] = instr_alu_export, 10818 10819 [INSTR_ALU_SUB] = instr_alu_export, 10820 [INSTR_ALU_SUB_MH] = instr_alu_export, 10821 [INSTR_ALU_SUB_HM] = instr_alu_export, 10822 [INSTR_ALU_SUB_HH] = instr_alu_export, 10823 [INSTR_ALU_SUB_MI] = instr_alu_export, 10824 [INSTR_ALU_SUB_HI] = instr_alu_export, 10825 10826 [INSTR_ALU_CKADD_FIELD] = instr_alu_export, 10827 [INSTR_ALU_CKADD_STRUCT] = instr_alu_export, 10828 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export, 10829 [INSTR_ALU_CKSUB_FIELD] = instr_alu_export, 10830 10831 [INSTR_ALU_AND] = instr_alu_export, 10832 [INSTR_ALU_AND_MH] = instr_alu_export, 10833 [INSTR_ALU_AND_HM] = instr_alu_export, 10834 [INSTR_ALU_AND_HH] = instr_alu_export, 10835 [INSTR_ALU_AND_I] = instr_alu_export, 10836 10837 [INSTR_ALU_OR] = instr_alu_export, 10838 [INSTR_ALU_OR_MH] = instr_alu_export, 10839 [INSTR_ALU_OR_HM] = instr_alu_export, 10840 [INSTR_ALU_OR_HH] = instr_alu_export, 10841 [INSTR_ALU_OR_I] = instr_alu_export, 10842 10843 [INSTR_ALU_XOR] = instr_alu_export, 10844 [INSTR_ALU_XOR_MH] = instr_alu_export, 10845 [INSTR_ALU_XOR_HM] = instr_alu_export, 10846 [INSTR_ALU_XOR_HH] = instr_alu_export, 10847 [INSTR_ALU_XOR_I] = instr_alu_export, 10848 10849 [INSTR_ALU_SHL] = instr_alu_export, 10850 [INSTR_ALU_SHL_MH] = instr_alu_export, 10851 [INSTR_ALU_SHL_HM] = instr_alu_export, 10852 [INSTR_ALU_SHL_HH] = instr_alu_export, 10853 [INSTR_ALU_SHL_MI] = instr_alu_export, 10854 [INSTR_ALU_SHL_HI] = instr_alu_export, 10855 10856 [INSTR_ALU_SHR] = instr_alu_export, 10857 [INSTR_ALU_SHR_MH] = instr_alu_export, 10858 [INSTR_ALU_SHR_HM] = instr_alu_export, 10859 [INSTR_ALU_SHR_HH] = instr_alu_export, 10860 [INSTR_ALU_SHR_MI] = instr_alu_export, 10861 [INSTR_ALU_SHR_HI] = instr_alu_export, 10862 10863 [INSTR_REGPREFETCH_RH] = instr_reg_export, 10864 [INSTR_REGPREFETCH_RM] = instr_reg_export, 10865 [INSTR_REGPREFETCH_RI] = instr_reg_export, 10866 10867 [INSTR_REGRD_HRH] = instr_reg_export, 10868 [INSTR_REGRD_HRM] = instr_reg_export, 10869 [INSTR_REGRD_MRH] = instr_reg_export, 10870 [INSTR_REGRD_MRM] = instr_reg_export, 10871 [INSTR_REGRD_HRI] = instr_reg_export, 10872 [INSTR_REGRD_MRI] = instr_reg_export, 10873 10874 [INSTR_REGWR_RHH] = instr_reg_export, 10875 [INSTR_REGWR_RHM] = instr_reg_export, 10876 [INSTR_REGWR_RMH] = instr_reg_export, 10877 [INSTR_REGWR_RMM] = instr_reg_export, 10878 [INSTR_REGWR_RHI] = instr_reg_export, 10879 [INSTR_REGWR_RMI] = instr_reg_export, 10880 [INSTR_REGWR_RIH] = instr_reg_export, 10881 [INSTR_REGWR_RIM] = instr_reg_export, 10882 [INSTR_REGWR_RII] = instr_reg_export, 10883 10884 [INSTR_REGADD_RHH] = instr_reg_export, 10885 [INSTR_REGADD_RHM] = instr_reg_export, 10886 [INSTR_REGADD_RMH] = instr_reg_export, 10887 [INSTR_REGADD_RMM] = instr_reg_export, 10888 [INSTR_REGADD_RHI] = instr_reg_export, 10889 [INSTR_REGADD_RMI] = instr_reg_export, 10890 [INSTR_REGADD_RIH] = instr_reg_export, 10891 [INSTR_REGADD_RIM] = instr_reg_export, 10892 [INSTR_REGADD_RII] = instr_reg_export, 10893 10894 [INSTR_METPREFETCH_H] = instr_meter_export, 10895 [INSTR_METPREFETCH_M] = instr_meter_export, 10896 [INSTR_METPREFETCH_I] = instr_meter_export, 10897 10898 [INSTR_METER_HHM] = instr_meter_export, 10899 [INSTR_METER_HHI] = instr_meter_export, 10900 [INSTR_METER_HMM] = instr_meter_export, 10901 [INSTR_METER_HMI] = instr_meter_export, 10902 [INSTR_METER_MHM] = instr_meter_export, 10903 [INSTR_METER_MHI] = instr_meter_export, 10904 [INSTR_METER_MMM] = instr_meter_export, 10905 [INSTR_METER_MMI] = instr_meter_export, 10906 [INSTR_METER_IHM] = instr_meter_export, 10907 [INSTR_METER_IHI] = instr_meter_export, 10908 [INSTR_METER_IMM] = instr_meter_export, 10909 [INSTR_METER_IMI] = instr_meter_export, 10910 10911 [INSTR_TABLE] = instr_table_export, 10912 [INSTR_TABLE_AF] = instr_table_export, 10913 [INSTR_SELECTOR] = instr_table_export, 10914 [INSTR_LEARNER] = instr_table_export, 10915 [INSTR_LEARNER_AF] = instr_table_export, 10916 10917 [INSTR_LEARNER_LEARN] = instr_learn_export, 10918 [INSTR_LEARNER_FORGET] = instr_forget_export, 10919 10920 [INSTR_EXTERN_OBJ] = instr_extern_export, 10921 [INSTR_EXTERN_FUNC] = instr_extern_export, 10922 10923 [INSTR_JMP] = instr_jmp_export, 10924 [INSTR_JMP_VALID] = instr_jmp_export, 10925 [INSTR_JMP_INVALID] = instr_jmp_export, 10926 [INSTR_JMP_HIT] = instr_jmp_export, 10927 [INSTR_JMP_MISS] = instr_jmp_export, 10928 [INSTR_JMP_ACTION_HIT] = instr_jmp_export, 10929 [INSTR_JMP_ACTION_MISS] = instr_jmp_export, 10930 10931 [INSTR_JMP_EQ] = instr_jmp_export, 10932 [INSTR_JMP_EQ_MH] = instr_jmp_export, 10933 [INSTR_JMP_EQ_HM] = instr_jmp_export, 10934 [INSTR_JMP_EQ_HH] = instr_jmp_export, 10935 [INSTR_JMP_EQ_I] = instr_jmp_export, 10936 10937 [INSTR_JMP_NEQ] = instr_jmp_export, 10938 [INSTR_JMP_NEQ_MH] = instr_jmp_export, 10939 [INSTR_JMP_NEQ_HM] = instr_jmp_export, 10940 [INSTR_JMP_NEQ_HH] = instr_jmp_export, 10941 [INSTR_JMP_NEQ_I] = instr_jmp_export, 10942 10943 [INSTR_JMP_LT] = instr_jmp_export, 10944 [INSTR_JMP_LT_MH] = instr_jmp_export, 10945 [INSTR_JMP_LT_HM] = instr_jmp_export, 10946 [INSTR_JMP_LT_HH] = instr_jmp_export, 10947 [INSTR_JMP_LT_MI] = instr_jmp_export, 10948 [INSTR_JMP_LT_HI] = instr_jmp_export, 10949 10950 [INSTR_JMP_GT] = instr_jmp_export, 10951 [INSTR_JMP_GT_MH] = instr_jmp_export, 10952 [INSTR_JMP_GT_HM] = instr_jmp_export, 10953 [INSTR_JMP_GT_HH] = instr_jmp_export, 10954 [INSTR_JMP_GT_MI] = instr_jmp_export, 10955 [INSTR_JMP_GT_HI] = instr_jmp_export, 10956 10957 [INSTR_RETURN] = instr_return_export, 10958 }; 10959 10960 static void 10961 action_data_codegen(struct action *a, FILE *f) 10962 { 10963 uint32_t i; 10964 10965 fprintf(f, 10966 "static const struct instruction action_%s_instructions[] = {\n", 10967 a->name); 10968 10969 for (i = 0; i < a->n_instructions; i++) { 10970 struct instruction *instr = &a->instructions[i]; 10971 instruction_export_t func = export_table[instr->type]; 10972 10973 func(instr, f); 10974 } 10975 10976 fprintf(f, "};\n"); 10977 } 10978 10979 static const char * 10980 instr_type_to_func(struct instruction *instr) 10981 { 10982 switch (instr->type) { 10983 case INSTR_RX: return NULL; 10984 10985 case INSTR_TX: return "__instr_tx_exec"; 10986 case INSTR_TX_I: return "__instr_tx_i_exec"; 10987 10988 case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; 10989 case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; 10990 case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec"; 10991 case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec"; 10992 case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec"; 10993 case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec"; 10994 case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec"; 10995 case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec"; 10996 10997 case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec"; 10998 10999 case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec"; 11000 11001 case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec"; 11002 case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec"; 11003 case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec"; 11004 case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec"; 11005 case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec"; 11006 case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec"; 11007 case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec"; 11008 case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec"; 11009 case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec"; 11010 11011 case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec"; 11012 case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec"; 11013 11014 case INSTR_MOV: return "__instr_mov_exec"; 11015 case INSTR_MOV_MH: return "__instr_mov_mh_exec"; 11016 case INSTR_MOV_HM: return "__instr_mov_hm_exec"; 11017 case INSTR_MOV_HH: return "__instr_mov_hh_exec"; 11018 case INSTR_MOV_I: return "__instr_mov_i_exec"; 11019 11020 case INSTR_DMA_HT: return "__instr_dma_ht_exec"; 11021 case INSTR_DMA_HT2: return "__instr_dma_ht2_exec"; 11022 case INSTR_DMA_HT3: return "__instr_dma_ht3_exec"; 11023 case INSTR_DMA_HT4: return "__instr_dma_ht4_exec"; 11024 case INSTR_DMA_HT5: return "__instr_dma_ht5_exec"; 11025 case INSTR_DMA_HT6: return "__instr_dma_ht6_exec"; 11026 case INSTR_DMA_HT7: return "__instr_dma_ht7_exec"; 11027 case INSTR_DMA_HT8: return "__instr_dma_ht8_exec"; 11028 11029 case INSTR_ALU_ADD: return "__instr_alu_add_exec"; 11030 case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec"; 11031 case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec"; 11032 case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec"; 11033 case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec"; 11034 case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec"; 11035 11036 case INSTR_ALU_SUB: return "__instr_alu_sub_exec"; 11037 case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec"; 11038 case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec"; 11039 case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec"; 11040 case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec"; 11041 case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec"; 11042 11043 case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec"; 11044 case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec"; 11045 case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec"; 11046 case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec"; 11047 11048 case INSTR_ALU_AND: return "__instr_alu_and_exec"; 11049 case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec"; 11050 case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec"; 11051 case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec"; 11052 case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec"; 11053 11054 case INSTR_ALU_OR: return "__instr_alu_or_exec"; 11055 case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec"; 11056 case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec"; 11057 case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec"; 11058 case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec"; 11059 11060 case INSTR_ALU_XOR: return "__instr_alu_xor_exec"; 11061 case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec"; 11062 case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec"; 11063 case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec"; 11064 case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec"; 11065 11066 case INSTR_ALU_SHL: return "__instr_alu_shl_exec"; 11067 case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec"; 11068 case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec"; 11069 case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec"; 11070 case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec"; 11071 case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec"; 11072 11073 case INSTR_ALU_SHR: return "__instr_alu_shr_exec"; 11074 case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec"; 11075 case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec"; 11076 case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec"; 11077 case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec"; 11078 case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec"; 11079 11080 case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec"; 11081 case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec"; 11082 case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec"; 11083 11084 case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec"; 11085 case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec"; 11086 case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec"; 11087 case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec"; 11088 case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec"; 11089 case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec"; 11090 11091 case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec"; 11092 case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec"; 11093 case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec"; 11094 case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec"; 11095 case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec"; 11096 case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec"; 11097 case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec"; 11098 case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec"; 11099 case INSTR_REGWR_RII: return "__instr_regwr_rii_exec"; 11100 11101 case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec"; 11102 case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec"; 11103 case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec"; 11104 case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec"; 11105 case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec"; 11106 case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec"; 11107 case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec"; 11108 case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec"; 11109 case INSTR_REGADD_RII: return "__instr_regadd_rii_exec"; 11110 11111 case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec"; 11112 case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec"; 11113 case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec"; 11114 11115 case INSTR_METER_HHM: return "__instr_meter_hhm_exec"; 11116 case INSTR_METER_HHI: return "__instr_meter_hhi_exec"; 11117 case INSTR_METER_HMM: return "__instr_meter_hmm_exec"; 11118 case INSTR_METER_HMI: return "__instr_meter_hmi_exec"; 11119 case INSTR_METER_MHM: return "__instr_meter_mhm_exec"; 11120 case INSTR_METER_MHI: return "__instr_meter_mhi_exec"; 11121 case INSTR_METER_MMM: return "__instr_meter_mmm_exec"; 11122 case INSTR_METER_MMI: return "__instr_meter_mmi_exec"; 11123 case INSTR_METER_IHM: return "__instr_meter_ihm_exec"; 11124 case INSTR_METER_IHI: return "__instr_meter_ihi_exec"; 11125 case INSTR_METER_IMM: return "__instr_meter_imm_exec"; 11126 case INSTR_METER_IMI: return "__instr_meter_imi_exec"; 11127 11128 case INSTR_TABLE: return NULL; 11129 case INSTR_TABLE_AF: return NULL; 11130 case INSTR_SELECTOR: return NULL; 11131 case INSTR_LEARNER: return NULL; 11132 case INSTR_LEARNER_AF: return NULL; 11133 11134 case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; 11135 case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; 11136 11137 case INSTR_EXTERN_OBJ: return NULL; 11138 case INSTR_EXTERN_FUNC: return NULL; 11139 11140 case INSTR_JMP: return NULL; 11141 case INSTR_JMP_VALID: return NULL; 11142 case INSTR_JMP_INVALID: return NULL; 11143 case INSTR_JMP_HIT: return NULL; 11144 case INSTR_JMP_MISS: return NULL; 11145 case INSTR_JMP_ACTION_HIT: return NULL; 11146 case INSTR_JMP_ACTION_MISS: return NULL; 11147 case INSTR_JMP_EQ: return NULL; 11148 case INSTR_JMP_EQ_MH: return NULL; 11149 case INSTR_JMP_EQ_HM: return NULL; 11150 case INSTR_JMP_EQ_HH: return NULL; 11151 case INSTR_JMP_EQ_I: return NULL; 11152 case INSTR_JMP_NEQ: return NULL; 11153 case INSTR_JMP_NEQ_MH: return NULL; 11154 case INSTR_JMP_NEQ_HM: return NULL; 11155 case INSTR_JMP_NEQ_HH: return NULL; 11156 case INSTR_JMP_NEQ_I: return NULL; 11157 case INSTR_JMP_LT: return NULL; 11158 case INSTR_JMP_LT_MH: return NULL; 11159 case INSTR_JMP_LT_HM: return NULL; 11160 case INSTR_JMP_LT_HH: return NULL; 11161 case INSTR_JMP_LT_MI: return NULL; 11162 case INSTR_JMP_LT_HI: return NULL; 11163 case INSTR_JMP_GT: return NULL; 11164 case INSTR_JMP_GT_MH: return NULL; 11165 case INSTR_JMP_GT_HM: return NULL; 11166 case INSTR_JMP_GT_HH: return NULL; 11167 case INSTR_JMP_GT_MI: return NULL; 11168 case INSTR_JMP_GT_HI: return NULL; 11169 11170 case INSTR_RETURN: return NULL; 11171 11172 default: return NULL; 11173 } 11174 } 11175 11176 static void 11177 action_instr_does_tx_codegen(struct action *a, 11178 uint32_t instr_pos, 11179 struct instruction *instr, 11180 FILE *f) 11181 { 11182 fprintf(f, 11183 "%s(p, t, &action_%s_instructions[%u]);\n" 11184 "\tthread_ip_reset(p, t);\n" 11185 "\tinstr_rx_exec(p);\n" 11186 "\treturn;\n", 11187 instr_type_to_func(instr), 11188 a->name, 11189 instr_pos); 11190 } 11191 11192 static void 11193 action_instr_extern_obj_codegen(struct action *a, 11194 uint32_t instr_pos, 11195 FILE *f) 11196 { 11197 fprintf(f, 11198 "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n", 11199 a->name, 11200 instr_pos); 11201 } 11202 11203 static void 11204 action_instr_extern_func_codegen(struct action *a, 11205 uint32_t instr_pos, 11206 FILE *f) 11207 { 11208 fprintf(f, 11209 "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n", 11210 a->name, 11211 instr_pos); 11212 } 11213 11214 static void 11215 action_instr_jmp_codegen(struct action *a, 11216 uint32_t instr_pos, 11217 struct instruction *instr, 11218 struct instruction_data *data, 11219 FILE *f) 11220 { 11221 switch (instr->type) { 11222 case INSTR_JMP: 11223 fprintf(f, 11224 "goto %s;\n", 11225 data->jmp_label); 11226 return; 11227 11228 case INSTR_JMP_VALID: 11229 fprintf(f, 11230 "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 11231 "\t\tgoto %s;\n", 11232 a->name, 11233 instr_pos, 11234 data->jmp_label); 11235 return; 11236 11237 case INSTR_JMP_INVALID: 11238 fprintf(f, 11239 "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" 11240 "\t\tgoto %s;\n", 11241 a->name, 11242 instr_pos, 11243 data->jmp_label); 11244 return; 11245 11246 case INSTR_JMP_HIT: 11247 fprintf(f, 11248 "if (t->hit)\n" 11249 "\t\tgoto %s;\n", 11250 data->jmp_label); 11251 return; 11252 11253 case INSTR_JMP_MISS: 11254 fprintf(f, 11255 "if (!t->hit)\n" 11256 "\t\tgoto %s;\n", 11257 data->jmp_label); 11258 return; 11259 11260 case INSTR_JMP_ACTION_HIT: 11261 fprintf(f, 11262 "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n" 11263 "\t\tgoto %s;\n", 11264 a->name, 11265 instr_pos, 11266 data->jmp_label); 11267 return; 11268 11269 case INSTR_JMP_ACTION_MISS: 11270 fprintf(f, 11271 "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n" 11272 "\t\tgoto %s;\n", 11273 a->name, 11274 instr_pos, 11275 data->jmp_label); 11276 return; 11277 11278 case INSTR_JMP_EQ: 11279 fprintf(f, 11280 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11281 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11282 "\t\tgoto %s;\n", 11283 a->name, 11284 instr_pos, 11285 a->name, 11286 instr_pos, 11287 data->jmp_label); 11288 return; 11289 11290 case INSTR_JMP_EQ_MH: 11291 fprintf(f, 11292 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11293 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11294 "\t\tgoto %s;\n", 11295 a->name, 11296 instr_pos, 11297 a->name, 11298 instr_pos, 11299 data->jmp_label); 11300 return; 11301 11302 case INSTR_JMP_EQ_HM: 11303 fprintf(f, 11304 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 11305 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11306 "\t\tgoto %s;\n", 11307 a->name, 11308 instr_pos, 11309 a->name, 11310 instr_pos, 11311 data->jmp_label); 11312 return; 11313 11314 case INSTR_JMP_EQ_HH: 11315 fprintf(f, 11316 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " 11317 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11318 "\t\tgoto %s;\n", 11319 a->name, 11320 instr_pos, 11321 a->name, 11322 instr_pos, 11323 data->jmp_label); 11324 return; 11325 11326 case INSTR_JMP_EQ_I: 11327 fprintf(f, 11328 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " 11329 "action_%s_instructions[%u].jmp.b_val)\n" 11330 "\t\tgoto %s;\n", 11331 a->name, 11332 instr_pos, 11333 a->name, 11334 instr_pos, 11335 data->jmp_label); 11336 return; 11337 11338 case INSTR_JMP_NEQ: 11339 fprintf(f, 11340 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11341 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11342 "\t\tgoto %s;\n", 11343 a->name, 11344 instr_pos, 11345 a->name, 11346 instr_pos, 11347 data->jmp_label); 11348 return; 11349 11350 case INSTR_JMP_NEQ_MH: 11351 fprintf(f, 11352 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11353 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11354 "\t\tgoto %s;\n", 11355 a->name, 11356 instr_pos, 11357 a->name, 11358 instr_pos, 11359 data->jmp_label); 11360 return; 11361 11362 case INSTR_JMP_NEQ_HM: 11363 fprintf(f, 11364 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 11365 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11366 "\t\tgoto %s;\n", 11367 a->name, 11368 instr_pos, 11369 a->name, 11370 instr_pos, 11371 data->jmp_label); 11372 return; 11373 11374 case INSTR_JMP_NEQ_HH: 11375 fprintf(f, 11376 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " 11377 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11378 "\t\tgoto %s;\n", 11379 a->name, 11380 instr_pos, 11381 a->name, 11382 instr_pos, 11383 data->jmp_label); 11384 return; 11385 11386 case INSTR_JMP_NEQ_I: 11387 fprintf(f, 11388 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " 11389 "action_%s_instructions[%u].jmp.b_val)\n" 11390 "\t\tgoto %s;\n", 11391 a->name, 11392 instr_pos, 11393 a->name, 11394 instr_pos, 11395 data->jmp_label); 11396 return; 11397 11398 case INSTR_JMP_LT: 11399 fprintf(f, 11400 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11401 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11402 "\t\tgoto %s;\n", 11403 a->name, 11404 instr_pos, 11405 a->name, 11406 instr_pos, 11407 data->jmp_label); 11408 return; 11409 11410 case INSTR_JMP_LT_MH: 11411 fprintf(f, 11412 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11413 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11414 "\t\tgoto %s;\n", 11415 a->name, 11416 instr_pos, 11417 a->name, 11418 instr_pos, 11419 data->jmp_label); 11420 return; 11421 11422 case INSTR_JMP_LT_HM: 11423 fprintf(f, 11424 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11425 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11426 "\t\tgoto %s;\n", 11427 a->name, 11428 instr_pos, 11429 a->name, 11430 instr_pos, 11431 data->jmp_label); 11432 return; 11433 11434 case INSTR_JMP_LT_HH: 11435 fprintf(f, 11436 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11437 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11438 "\t\tgoto %s;\n", 11439 a->name, 11440 instr_pos, 11441 a->name, 11442 instr_pos, 11443 data->jmp_label); 11444 return; 11445 11446 case INSTR_JMP_LT_MI: 11447 fprintf(f, 11448 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " 11449 "action_%s_instructions[%u].jmp.b_val)\n" 11450 "\t\tgoto %s;\n", 11451 a->name, 11452 instr_pos, 11453 a->name, 11454 instr_pos, 11455 data->jmp_label); 11456 return; 11457 11458 case INSTR_JMP_LT_HI: 11459 fprintf(f, 11460 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " 11461 "action_%s_instructions[%u].jmp.b_val)\n" 11462 "\t\tgoto %s;\n", 11463 a->name, 11464 instr_pos, 11465 a->name, 11466 instr_pos, 11467 data->jmp_label); 11468 return; 11469 11470 case INSTR_JMP_GT: 11471 fprintf(f, 11472 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11473 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11474 "\t\tgoto %s;\n", 11475 a->name, 11476 instr_pos, 11477 a->name, 11478 instr_pos, 11479 data->jmp_label); 11480 return; 11481 11482 case INSTR_JMP_GT_MH: 11483 fprintf(f, 11484 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11485 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11486 "\t\tgoto %s;\n", 11487 a->name, 11488 instr_pos, 11489 a->name, 11490 instr_pos, 11491 data->jmp_label); 11492 return; 11493 11494 case INSTR_JMP_GT_HM: 11495 fprintf(f, 11496 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11497 "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" 11498 "\t\tgoto %s;\n", 11499 a->name, 11500 instr_pos, 11501 a->name, 11502 instr_pos, 11503 data->jmp_label); 11504 return; 11505 11506 case INSTR_JMP_GT_HH: 11507 fprintf(f, 11508 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11509 "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" 11510 "\t\tgoto %s;\n", 11511 a->name, 11512 instr_pos, 11513 a->name, 11514 instr_pos, 11515 data->jmp_label); 11516 return; 11517 11518 case INSTR_JMP_GT_MI: 11519 fprintf(f, 11520 "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " 11521 "action_%s_instructions[%u].jmp.b_val)\n" 11522 "\t\tgoto %s;\n", 11523 a->name, 11524 instr_pos, 11525 a->name, 11526 instr_pos, 11527 data->jmp_label); 11528 return; 11529 11530 case INSTR_JMP_GT_HI: 11531 fprintf(f, 11532 "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " 11533 "action_%s_instructions[%u].jmp.b_val)\n" 11534 "\t\tgoto %s;\n", 11535 a->name, 11536 instr_pos, 11537 a->name, 11538 instr_pos, 11539 data->jmp_label); 11540 return; 11541 11542 default: 11543 return; 11544 } 11545 } 11546 11547 static void 11548 action_instr_return_codegen(FILE *f) 11549 { 11550 fprintf(f, 11551 "return;\n"); 11552 } 11553 11554 static void 11555 action_instr_codegen(struct action *a, FILE *f) 11556 { 11557 uint32_t i; 11558 11559 fprintf(f, 11560 "void\n" 11561 "action_%s_run(struct rte_swx_pipeline *p)\n" 11562 "{\n" 11563 "\tstruct thread *t = &p->threads[p->thread_id];\n" 11564 "\n", 11565 a->name); 11566 11567 for (i = 0; i < a->n_instructions; i++) { 11568 struct instruction *instr = &a->instructions[i]; 11569 struct instruction_data *data = &a->instruction_data[i]; 11570 11571 /* Label, if present. */ 11572 if (data->label[0]) 11573 fprintf(f, "\n%s : ", data->label); 11574 else 11575 fprintf(f, "\n\t"); 11576 11577 /* TX instruction type. */ 11578 if (instruction_does_tx(instr)) { 11579 action_instr_does_tx_codegen(a, i, instr, f); 11580 continue; 11581 } 11582 11583 /* Extern object/function instruction type. */ 11584 if (instr->type == INSTR_EXTERN_OBJ) { 11585 action_instr_extern_obj_codegen(a, i, f); 11586 continue; 11587 } 11588 11589 if (instr->type == INSTR_EXTERN_FUNC) { 11590 action_instr_extern_func_codegen(a, i, f); 11591 continue; 11592 } 11593 11594 /* Jump instruction type. */ 11595 if (instruction_is_jmp(instr)) { 11596 action_instr_jmp_codegen(a, i, instr, data, f); 11597 continue; 11598 } 11599 11600 /* Return instruction type. */ 11601 if (instr->type == INSTR_RETURN) { 11602 action_instr_return_codegen(f); 11603 continue; 11604 } 11605 11606 /* Any other instruction type. */ 11607 fprintf(f, 11608 "%s(p, t, &action_%s_instructions[%u]);\n", 11609 instr_type_to_func(instr), 11610 a->name, 11611 i); 11612 } 11613 11614 fprintf(f, "}\n\n"); 11615 } 11616 11617 struct instruction_group { 11618 TAILQ_ENTRY(instruction_group) node; 11619 11620 uint32_t group_id; 11621 11622 uint32_t first_instr_id; 11623 11624 uint32_t last_instr_id; 11625 11626 instr_exec_t func; 11627 }; 11628 11629 TAILQ_HEAD(instruction_group_list, instruction_group); 11630 11631 static struct instruction_group * 11632 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id) 11633 { 11634 struct instruction_group *g; 11635 11636 TAILQ_FOREACH(g, igl, node) 11637 if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id)) 11638 return g; 11639 11640 return NULL; 11641 } 11642 11643 static void 11644 instruction_group_list_free(struct instruction_group_list *igl) 11645 { 11646 if (!igl) 11647 return; 11648 11649 for ( ; ; ) { 11650 struct instruction_group *g; 11651 11652 g = TAILQ_FIRST(igl); 11653 if (!g) 11654 break; 11655 11656 TAILQ_REMOVE(igl, g, node); 11657 free(g); 11658 } 11659 11660 free(igl); 11661 } 11662 11663 static struct instruction_group_list * 11664 instruction_group_list_create(struct rte_swx_pipeline *p) 11665 { 11666 struct instruction_group_list *igl = NULL; 11667 struct instruction_group *g = NULL; 11668 uint32_t n_groups = 0, i; 11669 11670 if (!p || !p->instructions || !p->instruction_data || !p->n_instructions) 11671 goto error; 11672 11673 /* List init. */ 11674 igl = calloc(1, sizeof(struct instruction_group_list)); 11675 if (!igl) 11676 goto error; 11677 11678 TAILQ_INIT(igl); 11679 11680 /* Allocate the first group. */ 11681 g = calloc(1, sizeof(struct instruction_group)); 11682 if (!g) 11683 goto error; 11684 11685 /* Iteration 1: Separate the instructions into groups based on the thread yield 11686 * instructions. Do not worry about the jump instructions at this point. 11687 */ 11688 for (i = 0; i < p->n_instructions; i++) { 11689 struct instruction *instr = &p->instructions[i]; 11690 11691 /* Check for thread yield instructions. */ 11692 if (!instruction_does_thread_yield(instr)) 11693 continue; 11694 11695 /* If the current group contains at least one instruction, then finalize it (with 11696 * the previous instruction), add it to the list and allocate a new group (that 11697 * starts with the current instruction). 11698 */ 11699 if (i - g->first_instr_id) { 11700 /* Finalize the group. */ 11701 g->last_instr_id = i - 1; 11702 11703 /* Add the group to the list. Advance the number of groups. */ 11704 TAILQ_INSERT_TAIL(igl, g, node); 11705 n_groups++; 11706 11707 /* Allocate a new group. */ 11708 g = calloc(1, sizeof(struct instruction_group)); 11709 if (!g) 11710 goto error; 11711 11712 /* Initialize the new group. */ 11713 g->group_id = n_groups; 11714 g->first_instr_id = i; 11715 } 11716 11717 /* Finalize the current group (with the current instruction, therefore this group 11718 * contains just the current thread yield instruction), add it to the list and 11719 * allocate a new group (that starts with the next instruction). 11720 */ 11721 11722 /* Finalize the group. */ 11723 g->last_instr_id = i; 11724 11725 /* Add the group to the list. Advance the number of groups. */ 11726 TAILQ_INSERT_TAIL(igl, g, node); 11727 n_groups++; 11728 11729 /* Allocate a new group. */ 11730 g = calloc(1, sizeof(struct instruction_group)); 11731 if (!g) 11732 goto error; 11733 11734 /* Initialize the new group. */ 11735 g->group_id = n_groups; 11736 g->first_instr_id = i + 1; 11737 } 11738 11739 /* Handle the last group. */ 11740 if (i - g->first_instr_id) { 11741 /* Finalize the group. */ 11742 g->last_instr_id = i - 1; 11743 11744 /* Add the group to the list. Advance the number of groups. */ 11745 TAILQ_INSERT_TAIL(igl, g, node); 11746 n_groups++; 11747 } else 11748 free(g); 11749 11750 g = NULL; 11751 11752 /* Iteration 2: Handle jumps. If the current group contains an instruction which represents 11753 * the destination of a jump instruction located in a different group ("far jump"), then the 11754 * current group has to be split, so that the instruction representing the far jump 11755 * destination is at the start of its group. 11756 */ 11757 for ( ; ; ) { 11758 int is_modified = 0; 11759 11760 for (i = 0; i < p->n_instructions; i++) { 11761 struct instruction_data *data = &p->instruction_data[i]; 11762 struct instruction_group *g; 11763 uint32_t j; 11764 11765 /* Continue when the current instruction is not a jump destination. */ 11766 if (!data->n_users) 11767 continue; 11768 11769 g = instruction_group_list_group_find(igl, i); 11770 if (!g) 11771 goto error; 11772 11773 /* Find out all the jump instructions with this destination. */ 11774 for (j = 0; j < p->n_instructions; j++) { 11775 struct instruction *jmp_instr = &p->instructions[j]; 11776 struct instruction_data *jmp_data = &p->instruction_data[j]; 11777 struct instruction_group *jmp_g, *new_g; 11778 11779 /* Continue when not a jump instruction. Even when jump instruction, 11780 * continue when the jump destination is not this instruction. 11781 */ 11782 if (!instruction_is_jmp(jmp_instr) || 11783 strcmp(jmp_data->jmp_label, data->label)) 11784 continue; 11785 11786 jmp_g = instruction_group_list_group_find(igl, j); 11787 if (!jmp_g) 11788 goto error; 11789 11790 /* Continue when both the jump instruction and the jump destination 11791 * instruction are in the same group. Even when in different groups, 11792 * still continue if the jump destination instruction is already the 11793 * first instruction of its group. 11794 */ 11795 if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i)) 11796 continue; 11797 11798 /* Split the group of the current jump destination instruction to 11799 * make this instruction the first instruction of a new group. 11800 */ 11801 new_g = calloc(1, sizeof(struct instruction_group)); 11802 if (!new_g) 11803 goto error; 11804 11805 new_g->group_id = n_groups; 11806 new_g->first_instr_id = i; 11807 new_g->last_instr_id = g->last_instr_id; 11808 11809 g->last_instr_id = i - 1; 11810 11811 TAILQ_INSERT_AFTER(igl, g, new_g, node); 11812 n_groups++; 11813 is_modified = 1; 11814 11815 /* The decision to split this group (to make the current instruction 11816 * the first instruction of a new group) is already taken and fully 11817 * implemented, so no need to search for more reasons to do it. 11818 */ 11819 break; 11820 } 11821 } 11822 11823 /* Re-evaluate everything, as at least one group got split, so some jumps that were 11824 * previously considered local (i.e. the jump destination is in the same group as 11825 * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a 11826 * different group than the jump instruction). Wost case scenario: each instruction 11827 * that is a jump destination ends up as the first instruction of its group. 11828 */ 11829 if (!is_modified) 11830 break; 11831 } 11832 11833 /* Re-assign the group IDs to be in incremental order. */ 11834 i = 0; 11835 TAILQ_FOREACH(g, igl, node) { 11836 g->group_id = i; 11837 11838 i++; 11839 } 11840 11841 return igl; 11842 11843 error: 11844 instruction_group_list_free(igl); 11845 11846 free(g); 11847 11848 return NULL; 11849 } 11850 11851 static void 11852 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused, 11853 uint32_t instr_pos, 11854 struct instruction *instr, 11855 FILE *f) 11856 { 11857 fprintf(f, 11858 "%s(p, t, &pipeline_instructions[%u]);\n" 11859 "\tthread_ip_reset(p, t);\n" 11860 "\tinstr_rx_exec(p);\n" 11861 "\treturn;\n", 11862 instr_type_to_func(instr), 11863 instr_pos); 11864 } 11865 11866 static int 11867 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p, 11868 struct instruction_group_list *igl, 11869 uint32_t jmp_instr_id, 11870 struct instruction *jmp_instr, 11871 struct instruction_data *jmp_data, 11872 FILE *f) 11873 { 11874 struct instruction_group *jmp_g, *g; 11875 struct instruction_data *data; 11876 uint32_t instr_id; 11877 11878 switch (jmp_instr->type) { 11879 case INSTR_JMP: 11880 break; 11881 11882 case INSTR_JMP_VALID: 11883 fprintf(f, 11884 "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 11885 jmp_instr_id); 11886 break; 11887 11888 case INSTR_JMP_INVALID: 11889 fprintf(f, 11890 "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", 11891 jmp_instr_id); 11892 break; 11893 11894 case INSTR_JMP_HIT: 11895 fprintf(f, 11896 "if (t->hit)\n"); 11897 break; 11898 11899 case INSTR_JMP_MISS: 11900 fprintf(f, 11901 "if (!t->hit)\n"); 11902 break; 11903 11904 case INSTR_JMP_ACTION_HIT: 11905 fprintf(f, 11906 "if (t->action_id == pipeline_instructions[%u].jmp.action_id)", 11907 jmp_instr_id); 11908 break; 11909 11910 case INSTR_JMP_ACTION_MISS: 11911 fprintf(f, 11912 "if (t->action_id != pipeline_instructions[%u].jmp.action_id)", 11913 jmp_instr_id); 11914 break; 11915 11916 case INSTR_JMP_EQ: 11917 fprintf(f, 11918 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11919 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11920 jmp_instr_id, 11921 jmp_instr_id); 11922 break; 11923 11924 case INSTR_JMP_EQ_MH: 11925 fprintf(f, 11926 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11927 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11928 jmp_instr_id, 11929 jmp_instr_id); 11930 break; 11931 11932 case INSTR_JMP_EQ_HM: 11933 fprintf(f, 11934 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 11935 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11936 jmp_instr_id, 11937 jmp_instr_id); 11938 break; 11939 11940 case INSTR_JMP_EQ_HH: 11941 fprintf(f, 11942 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " 11943 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11944 jmp_instr_id, 11945 jmp_instr_id); 11946 break; 11947 11948 case INSTR_JMP_EQ_I: 11949 fprintf(f, 11950 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " 11951 "pipeline_instructions[%u].jmp.b_val)", 11952 jmp_instr_id, 11953 jmp_instr_id); 11954 break; 11955 11956 case INSTR_JMP_NEQ: 11957 fprintf(f, 11958 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11959 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11960 jmp_instr_id, 11961 jmp_instr_id); 11962 break; 11963 11964 case INSTR_JMP_NEQ_MH: 11965 fprintf(f, 11966 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11967 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11968 jmp_instr_id, 11969 jmp_instr_id); 11970 break; 11971 11972 case INSTR_JMP_NEQ_HM: 11973 fprintf(f, 11974 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 11975 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 11976 jmp_instr_id, 11977 jmp_instr_id); 11978 break; 11979 11980 case INSTR_JMP_NEQ_HH: 11981 fprintf(f, 11982 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " 11983 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 11984 jmp_instr_id, 11985 jmp_instr_id); 11986 break; 11987 11988 case INSTR_JMP_NEQ_I: 11989 fprintf(f, 11990 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " 11991 "pipeline_instructions[%u].jmp.b_val)", 11992 jmp_instr_id, 11993 jmp_instr_id); 11994 break; 11995 11996 case INSTR_JMP_LT: 11997 fprintf(f, 11998 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 11999 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12000 jmp_instr_id, 12001 jmp_instr_id); 12002 break; 12003 12004 case INSTR_JMP_LT_MH: 12005 fprintf(f, 12006 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12007 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12008 jmp_instr_id, 12009 jmp_instr_id); 12010 break; 12011 12012 case INSTR_JMP_LT_HM: 12013 fprintf(f, 12014 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12015 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12016 jmp_instr_id, 12017 jmp_instr_id); 12018 break; 12019 12020 case INSTR_JMP_LT_HH: 12021 fprintf(f, 12022 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12023 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12024 jmp_instr_id, 12025 jmp_instr_id); 12026 break; 12027 12028 case INSTR_JMP_LT_MI: 12029 fprintf(f, 12030 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " 12031 "pipeline_instructions[%u].jmp.b_val)", 12032 jmp_instr_id, 12033 jmp_instr_id); 12034 break; 12035 12036 case INSTR_JMP_LT_HI: 12037 fprintf(f, 12038 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " 12039 "pipeline_instructions[%u].jmp.b_val)", 12040 jmp_instr_id, 12041 jmp_instr_id); 12042 break; 12043 12044 case INSTR_JMP_GT: 12045 fprintf(f, 12046 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12047 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12048 jmp_instr_id, 12049 jmp_instr_id); 12050 break; 12051 12052 case INSTR_JMP_GT_MH: 12053 fprintf(f, 12054 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12055 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12056 jmp_instr_id, 12057 jmp_instr_id); 12058 break; 12059 12060 case INSTR_JMP_GT_HM: 12061 fprintf(f, 12062 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12063 "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", 12064 jmp_instr_id, 12065 jmp_instr_id); 12066 break; 12067 12068 case INSTR_JMP_GT_HH: 12069 fprintf(f, 12070 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12071 "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", 12072 jmp_instr_id, 12073 jmp_instr_id); 12074 break; 12075 12076 case INSTR_JMP_GT_MI: 12077 fprintf(f, 12078 "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " 12079 "pipeline_instructions[%u].jmp.b_val)", 12080 jmp_instr_id, 12081 jmp_instr_id); 12082 break; 12083 12084 case INSTR_JMP_GT_HI: 12085 fprintf(f, 12086 "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " 12087 "pipeline_instructions[%u].jmp.b_val)", 12088 jmp_instr_id, 12089 jmp_instr_id); 12090 break; 12091 12092 default: 12093 break; 12094 } 12095 12096 /* Find the instruction group of the jump instruction. */ 12097 jmp_g = instruction_group_list_group_find(igl, jmp_instr_id); 12098 if (!jmp_g) 12099 return -EINVAL; 12100 12101 /* Find the instruction group of the jump destination instruction. */ 12102 data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label); 12103 if (!data) 12104 return -EINVAL; 12105 12106 instr_id = data - p->instruction_data; 12107 12108 g = instruction_group_list_group_find(igl, instr_id); 12109 if (!g) 12110 return -EINVAL; 12111 12112 /* Code generation for "near" jump (same instruction group) or "far" jump (different 12113 * instruction group). 12114 */ 12115 if (g->group_id == jmp_g->group_id) 12116 fprintf(f, 12117 "\n\t\tgoto %s;\n", 12118 jmp_data->jmp_label); 12119 else 12120 fprintf(f, 12121 " {\n" 12122 "\t\tthread_ip_set(t, &p->instructions[%u]);\n" 12123 "\t\treturn;\n" 12124 "\t}\n\n", 12125 g->group_id); 12126 12127 return 0; 12128 } 12129 12130 static void 12131 instruction_group_list_codegen(struct instruction_group_list *igl, 12132 struct rte_swx_pipeline *p, 12133 FILE *f) 12134 { 12135 struct instruction_group *g; 12136 uint32_t i; 12137 int is_required = 0; 12138 12139 /* Check if code generation is required. */ 12140 TAILQ_FOREACH(g, igl, node) 12141 if (g->first_instr_id < g->last_instr_id) 12142 is_required = 1; 12143 12144 if (!is_required) 12145 return; 12146 12147 /* Generate the code for the pipeline instruction array. */ 12148 fprintf(f, 12149 "static const struct instruction pipeline_instructions[] = {\n"); 12150 12151 for (i = 0; i < p->n_instructions; i++) { 12152 struct instruction *instr = &p->instructions[i]; 12153 instruction_export_t func = export_table[instr->type]; 12154 12155 func(instr, f); 12156 } 12157 12158 fprintf(f, "};\n\n"); 12159 12160 /* Generate the code for the pipeline functions: one function for each instruction group 12161 * that contains more than one instruction. 12162 */ 12163 TAILQ_FOREACH(g, igl, node) { 12164 struct instruction *last_instr; 12165 uint32_t j; 12166 12167 /* Skip if group contains a single instruction. */ 12168 if (g->last_instr_id == g->first_instr_id) 12169 continue; 12170 12171 /* Generate new pipeline function. */ 12172 fprintf(f, 12173 "void\n" 12174 "pipeline_func_%u(struct rte_swx_pipeline *p)\n" 12175 "{\n" 12176 "\tstruct thread *t = &p->threads[p->thread_id];\n" 12177 "\n", 12178 g->group_id); 12179 12180 /* Generate the code for each pipeline instruction. */ 12181 for (j = g->first_instr_id; j <= g->last_instr_id; j++) { 12182 struct instruction *instr = &p->instructions[j]; 12183 struct instruction_data *data = &p->instruction_data[j]; 12184 12185 /* Label, if present. */ 12186 if (data->label[0]) 12187 fprintf(f, "\n%s : ", data->label); 12188 else 12189 fprintf(f, "\n\t"); 12190 12191 /* TX instruction type. */ 12192 if (instruction_does_tx(instr)) { 12193 pipeline_instr_does_tx_codegen(p, j, instr, f); 12194 continue; 12195 } 12196 12197 /* Jump instruction type. */ 12198 if (instruction_is_jmp(instr)) { 12199 pipeline_instr_jmp_codegen(p, igl, j, instr, data, f); 12200 continue; 12201 } 12202 12203 /* Any other instruction type. */ 12204 fprintf(f, 12205 "%s(p, t, &pipeline_instructions[%u]);\n", 12206 instr_type_to_func(instr), 12207 j); 12208 } 12209 12210 /* Finalize the generated pipeline function. For some instructions such as TX, 12211 * emit-many-and-TX and unconditional jump, the next instruction has been already 12212 * decided unconditionally and the instruction pointer of the current thread set 12213 * accordingly; for all the other instructions, the instruction pointer must be 12214 * incremented now. 12215 */ 12216 last_instr = &p->instructions[g->last_instr_id]; 12217 12218 if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP)) 12219 fprintf(f, 12220 "thread_ip_inc(p);\n"); 12221 12222 fprintf(f, 12223 "}\n" 12224 "\n"); 12225 } 12226 } 12227 12228 static uint32_t 12229 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl) 12230 { 12231 struct instruction_group *g; 12232 uint32_t n_custom_instr = 0; 12233 12234 /* Groups with a single instruction: no function is generated for this group, the group 12235 * keeps its current instruction. Groups with more than two instructions: one function and 12236 * the associated custom instruction get generated for each such group. 12237 */ 12238 TAILQ_FOREACH(g, igl, node) { 12239 if (g->first_instr_id == g->last_instr_id) 12240 continue; 12241 12242 n_custom_instr++; 12243 } 12244 12245 return n_custom_instr; 12246 } 12247 12248 static int 12249 pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12250 { 12251 struct action *a; 12252 FILE *f = NULL; 12253 12254 /* Create the .c file. */ 12255 f = fopen("/tmp/pipeline.c", "w"); 12256 if (!f) 12257 return -EIO; 12258 12259 /* Include the .h file. */ 12260 fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n"); 12261 12262 /* Add the code for each action. */ 12263 TAILQ_FOREACH(a, &p->actions, node) { 12264 fprintf(f, "/**\n * Action %s\n */\n\n", a->name); 12265 12266 action_data_codegen(a, f); 12267 12268 fprintf(f, "\n"); 12269 12270 action_instr_codegen(a, f); 12271 12272 fprintf(f, "\n"); 12273 } 12274 12275 /* Add the pipeline code. */ 12276 instruction_group_list_codegen(igl, p, f); 12277 12278 /* Close the .c file. */ 12279 fclose(f); 12280 12281 return 0; 12282 } 12283 12284 #ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE 12285 #define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096 12286 #endif 12287 12288 static int 12289 pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12290 { 12291 struct action *a; 12292 struct instruction_group *g; 12293 char *dir_in, *buffer = NULL; 12294 const char *dir_out; 12295 int status = 0; 12296 12297 /* Get the environment variables. */ 12298 dir_in = getenv("RTE_INSTALL_DIR"); 12299 if (!dir_in) { 12300 status = -EINVAL; 12301 goto free; 12302 } 12303 12304 dir_out = "/tmp"; 12305 12306 /* Memory allocation for the command buffer. */ 12307 buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE); 12308 if (!buffer) { 12309 status = -ENOMEM; 12310 goto free; 12311 } 12312 12313 snprintf(buffer, 12314 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 12315 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c " 12316 "-I %s/lib/pipeline " 12317 "-I %s/lib/eal/include " 12318 "-I %s/lib/eal/x86/include " 12319 "-I %s/lib/eal/include/generic " 12320 "-I %s/lib/meter " 12321 "-I %s/lib/port " 12322 "-I %s/lib/table " 12323 "-I %s/lib/pipeline " 12324 "-I %s/config " 12325 "-I %s/build " 12326 "-I %s/lib/eal/linux/include " 12327 ">%s/pipeline.log 2>&1 " 12328 "&& " 12329 "gcc -shared %s/pipeline.o -o %s/libpipeline.so " 12330 ">>%s/pipeline.log 2>&1", 12331 dir_out, 12332 dir_out, 12333 dir_in, 12334 dir_in, 12335 dir_in, 12336 dir_in, 12337 dir_in, 12338 dir_in, 12339 dir_in, 12340 dir_in, 12341 dir_in, 12342 dir_in, 12343 dir_in, 12344 dir_out, 12345 dir_out, 12346 dir_out, 12347 dir_out); 12348 12349 /* Build the shared object library. */ 12350 status = system(buffer); 12351 if (status) 12352 goto free; 12353 12354 /* Open library. */ 12355 snprintf(buffer, 12356 RTE_SWX_PIPELINE_CMD_MAX_SIZE, 12357 "%s/libpipeline.so", 12358 dir_out); 12359 12360 p->lib = dlopen(buffer, RTLD_LAZY); 12361 if (!p->lib) { 12362 status = -EIO; 12363 goto free; 12364 } 12365 12366 /* Get the action function symbols. */ 12367 TAILQ_FOREACH(a, &p->actions, node) { 12368 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name); 12369 12370 p->action_funcs[a->id] = dlsym(p->lib, buffer); 12371 if (!p->action_funcs[a->id]) { 12372 status = -EINVAL; 12373 goto free; 12374 } 12375 } 12376 12377 /* Get the pipeline function symbols. */ 12378 TAILQ_FOREACH(g, igl, node) { 12379 if (g->first_instr_id == g->last_instr_id) 12380 continue; 12381 12382 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id); 12383 12384 g->func = dlsym(p->lib, buffer); 12385 if (!g->func) { 12386 status = -EINVAL; 12387 goto free; 12388 } 12389 } 12390 12391 free: 12392 if (status && p->lib) { 12393 dlclose(p->lib); 12394 p->lib = NULL; 12395 } 12396 12397 free(buffer); 12398 12399 return status; 12400 } 12401 12402 static int 12403 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused, 12404 struct instruction_group_list *igl) 12405 { 12406 uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl); 12407 12408 /* Check that enough space is available within the pipeline instruction table to store all 12409 * the custom instructions. 12410 */ 12411 if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX) 12412 return -ENOSPC; 12413 12414 return 0; 12415 } 12416 12417 static void 12418 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl) 12419 { 12420 struct instruction_group *g; 12421 uint32_t i; 12422 12423 /* Pipeline table instructions. */ 12424 for (i = 0; i < p->n_instructions; i++) { 12425 struct instruction *instr = &p->instructions[i]; 12426 12427 if (instr->type == INSTR_TABLE) 12428 instr->type = INSTR_TABLE_AF; 12429 12430 if (instr->type == INSTR_LEARNER) 12431 instr->type = INSTR_LEARNER_AF; 12432 } 12433 12434 /* Pipeline custom instructions. */ 12435 i = 0; 12436 TAILQ_FOREACH(g, igl, node) { 12437 struct instruction *instr = &p->instructions[g->first_instr_id]; 12438 uint32_t j; 12439 12440 if (g->first_instr_id == g->last_instr_id) 12441 continue; 12442 12443 /* Install a new custom instruction. */ 12444 p->instruction_table[INSTR_CUSTOM_0 + i] = g->func; 12445 12446 /* First instruction of the group: change its type to the new custom instruction. */ 12447 instr->type = INSTR_CUSTOM_0 + i; 12448 12449 /* All the subsequent instructions of the group: invalidate. */ 12450 for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) { 12451 struct instruction_data *data = &p->instruction_data[j]; 12452 12453 data->invalid = 1; 12454 } 12455 12456 i++; 12457 } 12458 12459 /* Remove the invalidated instructions. */ 12460 p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions); 12461 12462 /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump 12463 * instructions that are the only instruction within their group, so they were left 12464 * unmodified). 12465 */ 12466 instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions); 12467 } 12468 12469 static int 12470 pipeline_compile(struct rte_swx_pipeline *p) 12471 { 12472 struct instruction_group_list *igl = NULL; 12473 int status = 0; 12474 12475 igl = instruction_group_list_create(p); 12476 if (!igl) { 12477 status = -ENOMEM; 12478 goto free; 12479 } 12480 12481 /* Code generation. */ 12482 status = pipeline_codegen(p, igl); 12483 if (status) 12484 goto free; 12485 12486 /* Build and load the shared object library. */ 12487 status = pipeline_libload(p, igl); 12488 if (status) 12489 goto free; 12490 12491 /* Adjust instructions. */ 12492 status = pipeline_adjust_check(p, igl); 12493 if (status) 12494 goto free; 12495 12496 pipeline_adjust(p, igl); 12497 12498 free: 12499 instruction_group_list_free(igl); 12500 12501 return status; 12502 } 12503