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