dpdk/lib/pipeline/rte_swx_ctl.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2020 Intel Corporation
   3 */
   4#include <stdlib.h>
   5#include <string.h>
   6#include <stdio.h>
   7#include <sys/queue.h>
   8#include <unistd.h>
   9
  10#include <rte_common.h>
  11#include <rte_byteorder.h>
  12
  13#include <rte_swx_table_selector.h>
  14
  15#include "rte_swx_ctl.h"
  16
  17#define CHECK(condition, err_code)                                             \
  18do {                                                                           \
  19        if (!(condition))                                                      \
  20                return -(err_code);                                            \
  21} while (0)
  22
  23#define ntoh64(x) rte_be_to_cpu_64(x)
  24#define hton64(x) rte_cpu_to_be_64(x)
  25
  26#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
  27#define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
  28#define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
  29#else
  30#define field_ntoh(val, n_bits) (val)
  31#define field_hton(val, n_bits) (val)
  32#endif
  33
  34struct action {
  35        struct rte_swx_ctl_action_info info;
  36        struct rte_swx_ctl_action_arg_info *args;
  37        uint32_t data_size;
  38};
  39
  40struct table {
  41        struct rte_swx_ctl_table_info info;
  42        struct rte_swx_ctl_table_match_field_info *mf;
  43
  44        /* Match field with the smallest offset. */
  45        struct rte_swx_ctl_table_match_field_info *mf_first;
  46
  47        /* Match field with the biggest offset. */
  48        struct rte_swx_ctl_table_match_field_info *mf_last;
  49
  50        struct rte_swx_ctl_table_action_info *actions;
  51        struct rte_swx_table_ops ops;
  52        struct rte_swx_table_params params;
  53
  54        /* Set of "stable" keys: these keys are currently part of the table;
  55         * these keys will be preserved with no action data changes after the
  56         * next commit.
  57         */
  58        struct rte_swx_table_entry_list entries;
  59
  60        /* Set of new keys: these keys are currently NOT part of the table;
  61         * these keys will be added to the table on the next commit, if
  62         * the commit operation is successful.
  63         */
  64        struct rte_swx_table_entry_list pending_add;
  65
  66        /* Set of keys to be modified: these keys are currently part of the
  67         * table; these keys are still going to be part of the table after the
  68         * next commit, but their action data will be modified if the commit
  69         * operation is successful. The modify0 list contains the keys with the
  70         * current action data, the modify1 list contains the keys with the
  71         * modified action data.
  72         */
  73        struct rte_swx_table_entry_list pending_modify0;
  74        struct rte_swx_table_entry_list pending_modify1;
  75
  76        /* Set of keys to be deleted: these keys are currently part of the
  77         * table; these keys are to be deleted from the table on the next
  78         * commit, if the commit operation is successful.
  79         */
  80        struct rte_swx_table_entry_list pending_delete;
  81
  82        /* The pending default action: this is NOT the current default action;
  83         * this will be the new default action after the next commit, if the
  84         * next commit operation is successful.
  85         */
  86        struct rte_swx_table_entry *pending_default;
  87
  88        int is_stub;
  89        uint32_t n_add;
  90        uint32_t n_modify;
  91        uint32_t n_delete;
  92};
  93
  94struct selector {
  95        /* Selector table info. */
  96        struct rte_swx_ctl_selector_info info;
  97
  98        /* group_id field. */
  99        struct rte_swx_ctl_table_match_field_info group_id_field;
 100
 101        /* selector fields. */
 102        struct rte_swx_ctl_table_match_field_info *selector_fields;
 103
 104        /* member_id field. */
 105        struct rte_swx_ctl_table_match_field_info member_id_field;
 106
 107        /* Current selector table. Array of info.n_groups_max elements.*/
 108        struct rte_swx_table_selector_group **groups;
 109
 110        /* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
 111         */
 112        struct rte_swx_table_selector_group **pending_groups;
 113
 114        /* Valid flag per group. Array of n_groups_max elements. */
 115        int *groups_added;
 116
 117        /* Pending delete flag per group. Group deletion is subject to the next commit. Array of
 118         * info.n_groups_max elements.
 119         */
 120        int *groups_pending_delete;
 121
 122        /* Params. */
 123        struct rte_swx_table_selector_params params;
 124};
 125
 126struct learner {
 127        struct rte_swx_ctl_learner_info info;
 128        struct rte_swx_ctl_table_match_field_info *mf;
 129        struct rte_swx_ctl_table_action_info *actions;
 130        uint32_t action_data_size;
 131
 132        /* The pending default action: this is NOT the current default action;
 133         * this will be the new default action after the next commit, if the
 134         * next commit operation is successful.
 135         */
 136        struct rte_swx_table_entry *pending_default;
 137};
 138
 139struct rte_swx_ctl_pipeline {
 140        struct rte_swx_ctl_pipeline_info info;
 141        struct rte_swx_pipeline *p;
 142        struct action *actions;
 143        struct table *tables;
 144        struct selector *selectors;
 145        struct learner *learners;
 146        struct rte_swx_table_state *ts;
 147        struct rte_swx_table_state *ts_next;
 148        int numa_node;
 149};
 150
 151static struct action *
 152action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
 153{
 154        uint32_t i;
 155
 156        for (i = 0; i < ctl->info.n_actions; i++) {
 157                struct action *a = &ctl->actions[i];
 158
 159                if (!strcmp(action_name, a->info.name))
 160                        return a;
 161        }
 162
 163        return NULL;
 164}
 165
 166static void
 167action_free(struct rte_swx_ctl_pipeline *ctl)
 168{
 169        uint32_t i;
 170
 171        if (!ctl->actions)
 172                return;
 173
 174        for (i = 0; i < ctl->info.n_actions; i++) {
 175                struct action *action = &ctl->actions[i];
 176
 177                free(action->args);
 178        }
 179
 180        free(ctl->actions);
 181        ctl->actions = NULL;
 182}
 183
 184static struct table *
 185table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
 186{
 187        uint32_t i;
 188
 189        for (i = 0; i < ctl->info.n_tables; i++) {
 190                struct table *table = &ctl->tables[i];
 191
 192                if (!strcmp(table_name, table->info.name))
 193                        return table;
 194        }
 195
 196        return NULL;
 197}
 198
 199static int
 200table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
 201{
 202        struct table *table = &ctl->tables[table_id];
 203        struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
 204        uint8_t *key_mask = NULL;
 205        enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
 206        uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
 207
 208        if (table->info.n_match_fields) {
 209                uint32_t n_match_fields_em = 0, i;
 210
 211                /* Find first (smallest offset) and last (biggest offset) match fields. */
 212                first = &table->mf[0];
 213                last = &table->mf[0];
 214
 215                for (i = 1; i < table->info.n_match_fields; i++) {
 216                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 217
 218                        if (f->offset < first->offset)
 219                                first = f;
 220
 221                        if (f->offset > last->offset)
 222                                last = f;
 223                }
 224
 225                /* match_type. */
 226                for (i = 0; i < table->info.n_match_fields; i++) {
 227                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 228
 229                        if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
 230                                n_match_fields_em++;
 231                }
 232
 233                if (n_match_fields_em == table->info.n_match_fields)
 234                        match_type = RTE_SWX_TABLE_MATCH_EXACT;
 235
 236                /* key_offset. */
 237                key_offset = first->offset / 8;
 238
 239                /* key_size. */
 240                key_size = (last->offset + last->n_bits - first->offset) / 8;
 241
 242                /* key_mask. */
 243                key_mask = calloc(1, key_size);
 244                CHECK(key_mask, ENOMEM);
 245
 246                for (i = 0; i < table->info.n_match_fields; i++) {
 247                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 248                        uint32_t start;
 249                        size_t size;
 250
 251                        start = (f->offset - first->offset) / 8;
 252                        size = f->n_bits / 8;
 253
 254                        memset(&key_mask[start], 0xFF, size);
 255                }
 256        }
 257
 258        /* action_data_size. */
 259        for (i = 0; i < table->info.n_actions; i++) {
 260                uint32_t action_id = table->actions[i].action_id;
 261                struct action *a = &ctl->actions[action_id];
 262
 263                if (a->data_size > action_data_size)
 264                        action_data_size = a->data_size;
 265        }
 266
 267        /* Fill in. */
 268        table->params.match_type = match_type;
 269        table->params.key_size = key_size;
 270        table->params.key_offset = key_offset;
 271        table->params.key_mask0 = key_mask;
 272        table->params.action_data_size = action_data_size;
 273        table->params.n_keys_max = table->info.size;
 274
 275        table->mf_first = first;
 276        table->mf_last = last;
 277
 278        return 0;
 279}
 280
 281static void
 282table_entry_free(struct rte_swx_table_entry *entry)
 283{
 284        if (!entry)
 285                return;
 286
 287        free(entry->key);
 288        free(entry->key_mask);
 289        free(entry->action_data);
 290        free(entry);
 291}
 292
 293static struct rte_swx_table_entry *
 294table_entry_alloc(struct table *table)
 295{
 296        struct rte_swx_table_entry *entry;
 297
 298        entry = calloc(1, sizeof(struct rte_swx_table_entry));
 299        if (!entry)
 300                goto error;
 301
 302        /* key, key_mask. */
 303        if (!table->is_stub) {
 304                entry->key = calloc(1, table->params.key_size);
 305                if (!entry->key)
 306                        goto error;
 307
 308                if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
 309                        entry->key_mask = calloc(1, table->params.key_size);
 310                        if (!entry->key_mask)
 311                                goto error;
 312                }
 313        }
 314
 315        /* action_data. */
 316        if (table->params.action_data_size) {
 317                entry->action_data = calloc(1, table->params.action_data_size);
 318                if (!entry->action_data)
 319                        goto error;
 320        }
 321
 322        return entry;
 323
 324error:
 325        table_entry_free(entry);
 326        return NULL;
 327}
 328
 329static int
 330table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
 331{
 332        uint8_t *key_mask0 = table->params.key_mask0;
 333        uint32_t key_size = table->params.key_size, i;
 334
 335        if (!entry->key_mask)
 336                return 0;
 337
 338        for (i = 0; i < key_size; i++) {
 339                uint8_t km0 = key_mask0[i];
 340                uint8_t km = entry->key_mask[i];
 341
 342                if ((km & km0) != km0)
 343                        return -EINVAL;
 344        }
 345
 346        return 0;
 347}
 348
 349static int
 350table_entry_check(struct rte_swx_ctl_pipeline *ctl,
 351                  uint32_t table_id,
 352                  struct rte_swx_table_entry *entry,
 353                  int key_check,
 354                  int data_check)
 355{
 356        struct table *table = &ctl->tables[table_id];
 357        int status;
 358
 359        CHECK(entry, EINVAL);
 360
 361        if (key_check && !table->is_stub) {
 362                /* key. */
 363                CHECK(entry->key, EINVAL);
 364
 365                /* key_mask. */
 366                if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
 367                        status = table_entry_key_check_em(table, entry);
 368                        if (status)
 369                                return status;
 370                }
 371        }
 372
 373        if (data_check) {
 374                struct action *a;
 375                struct rte_swx_ctl_table_action_info *tai;
 376                uint32_t i;
 377
 378                /* action_id. */
 379                for (i = 0; i < table->info.n_actions; i++) {
 380                        tai = &table->actions[i];
 381
 382                        if (entry->action_id == tai->action_id)
 383                                break;
 384                }
 385
 386                CHECK(i < table->info.n_actions, EINVAL);
 387
 388                /* action_data. */
 389                a = &ctl->actions[entry->action_id];
 390                CHECK(!(a->data_size && !entry->action_data), EINVAL);
 391
 392                /* When both key_check and data_check are true, we are interested in both the entry
 393                 * key and data, which means the operation is _regular_ table entry add.
 394                 */
 395                if (key_check && !tai->action_is_for_table_entries)
 396                        return -EINVAL;
 397
 398                /* When key_check is false while data_check is true, we are only interested in the
 399                 * entry data, which means the operation is _default_ table entry add.
 400                 */
 401                if (!key_check && !tai->action_is_for_default_entry)
 402                        return -EINVAL;
 403        }
 404
 405        return 0;
 406}
 407
 408static struct rte_swx_table_entry *
 409table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
 410                      uint32_t table_id,
 411                      struct rte_swx_table_entry *entry,
 412                      int key_duplicate,
 413                      int data_duplicate)
 414{
 415        struct table *table = &ctl->tables[table_id];
 416        struct rte_swx_table_entry *new_entry = NULL;
 417
 418        if (!entry)
 419                goto error;
 420
 421        new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
 422        if (!new_entry)
 423                goto error;
 424
 425        if (key_duplicate && !table->is_stub) {
 426                /* key. */
 427                if (!entry->key)
 428                        goto error;
 429
 430                new_entry->key = malloc(table->params.key_size);
 431                if (!new_entry->key)
 432                        goto error;
 433
 434                memcpy(new_entry->key, entry->key, table->params.key_size);
 435
 436                /* key_signature. */
 437                new_entry->key_signature = entry->key_signature;
 438
 439                /* key_mask. */
 440                if (entry->key_mask) {
 441                        new_entry->key_mask = malloc(table->params.key_size);
 442                        if (!new_entry->key_mask)
 443                                goto error;
 444
 445                        memcpy(new_entry->key_mask,
 446                               entry->key_mask,
 447                               table->params.key_size);
 448                }
 449
 450                /* key_priority. */
 451                new_entry->key_priority = entry->key_priority;
 452        }
 453
 454        if (data_duplicate) {
 455                struct action *a;
 456                uint32_t i;
 457
 458                /* action_id. */
 459                for (i = 0; i < table->info.n_actions; i++)
 460                        if (entry->action_id == table->actions[i].action_id)
 461                                break;
 462
 463                if (i >= table->info.n_actions)
 464                        goto error;
 465
 466                new_entry->action_id = entry->action_id;
 467
 468                /* action_data. */
 469                a = &ctl->actions[entry->action_id];
 470                if (a->data_size && !entry->action_data)
 471                        goto error;
 472
 473                /* The table layer provisions a constant action data size per
 474                 * entry, which should be the largest data size for all the
 475                 * actions enabled for the current table, and attempts to copy
 476                 * this many bytes each time a table entry is added, even if the
 477                 * specific action requires less data or even no data at all,
 478                 * hence we always have to allocate the max.
 479                 */
 480                new_entry->action_data = calloc(1, table->params.action_data_size);
 481                if (!new_entry->action_data)
 482                        goto error;
 483
 484                if (a->data_size)
 485                        memcpy(new_entry->action_data,
 486                               entry->action_data,
 487                               a->data_size);
 488        }
 489
 490        return new_entry;
 491
 492error:
 493        table_entry_free(new_entry);
 494        return NULL;
 495}
 496
 497static int
 498table_entry_keycmp(struct table *table,
 499                   struct rte_swx_table_entry *e0,
 500                   struct rte_swx_table_entry *e1)
 501{
 502        uint32_t key_size = table->params.key_size;
 503        uint32_t i;
 504
 505        for (i = 0; i < key_size; i++) {
 506                uint8_t *key_mask0 = table->params.key_mask0;
 507                uint8_t km0, km[2], k[2];
 508
 509                km0 = key_mask0 ? key_mask0[i] : 0xFF;
 510
 511                km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
 512                km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
 513
 514                k[0] = e0->key[i];
 515                k[1] = e1->key[i];
 516
 517                /* Mask comparison. */
 518                if ((km[0] & km0) != (km[1] & km0))
 519                        return 1; /* Not equal. */
 520
 521                /* Value comparison. */
 522                if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
 523                        return 1; /* Not equal. */
 524        }
 525
 526        return 0; /* Equal. */
 527}
 528
 529static struct rte_swx_table_entry *
 530table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
 531{
 532        struct rte_swx_table_entry *e;
 533
 534        TAILQ_FOREACH(e, &table->entries, node)
 535                if (!table_entry_keycmp(table, entry, e))
 536                        return e; /* Found. */
 537
 538        return NULL; /* Not found. */
 539}
 540
 541static void
 542table_entries_free(struct table *table)
 543{
 544        for ( ; ; ) {
 545                struct rte_swx_table_entry *entry;
 546
 547                entry = TAILQ_FIRST(&table->entries);
 548                if (!entry)
 549                        break;
 550
 551                TAILQ_REMOVE(&table->entries, entry, node);
 552                table_entry_free(entry);
 553        }
 554}
 555
 556static struct rte_swx_table_entry *
 557table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
 558{
 559        struct rte_swx_table_entry *e;
 560
 561        TAILQ_FOREACH(e, &table->pending_add, node)
 562                if (!table_entry_keycmp(table, entry, e))
 563                        return e; /* Found. */
 564
 565        return NULL; /* Not found. */
 566}
 567
 568static void
 569table_pending_add_admit(struct table *table)
 570{
 571        TAILQ_CONCAT(&table->entries, &table->pending_add, node);
 572}
 573
 574static void
 575table_pending_add_free(struct table *table)
 576{
 577        for ( ; ; ) {
 578                struct rte_swx_table_entry *entry;
 579
 580                entry = TAILQ_FIRST(&table->pending_add);
 581                if (!entry)
 582                        break;
 583
 584                TAILQ_REMOVE(&table->pending_add, entry, node);
 585                table_entry_free(entry);
 586        }
 587}
 588
 589static struct rte_swx_table_entry *
 590table_pending_modify0_find(struct table *table,
 591                           struct rte_swx_table_entry *entry)
 592{
 593        struct rte_swx_table_entry *e;
 594
 595        TAILQ_FOREACH(e, &table->pending_modify0, node)
 596                if (!table_entry_keycmp(table, entry, e))
 597                        return e; /* Found. */
 598
 599        return NULL; /* Not found. */
 600}
 601
 602static void
 603table_pending_modify0_admit(struct table *table)
 604{
 605        TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
 606}
 607
 608static void
 609table_pending_modify0_free(struct table *table)
 610{
 611        for ( ; ; ) {
 612                struct rte_swx_table_entry *entry;
 613
 614                entry = TAILQ_FIRST(&table->pending_modify0);
 615                if (!entry)
 616                        break;
 617
 618                TAILQ_REMOVE(&table->pending_modify0, entry, node);
 619                table_entry_free(entry);
 620        }
 621}
 622
 623static struct rte_swx_table_entry *
 624table_pending_modify1_find(struct table *table,
 625                           struct rte_swx_table_entry *entry)
 626{
 627        struct rte_swx_table_entry *e;
 628
 629        TAILQ_FOREACH(e, &table->pending_modify1, node)
 630                if (!table_entry_keycmp(table, entry, e))
 631                        return e; /* Found. */
 632
 633        return NULL; /* Not found. */
 634}
 635
 636static void
 637table_pending_modify1_admit(struct table *table)
 638{
 639        TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
 640}
 641
 642static void
 643table_pending_modify1_free(struct table *table)
 644{
 645        for ( ; ; ) {
 646                struct rte_swx_table_entry *entry;
 647
 648                entry = TAILQ_FIRST(&table->pending_modify1);
 649                if (!entry)
 650                        break;
 651
 652                TAILQ_REMOVE(&table->pending_modify1, entry, node);
 653                table_entry_free(entry);
 654        }
 655}
 656
 657static struct rte_swx_table_entry *
 658table_pending_delete_find(struct table *table,
 659                          struct rte_swx_table_entry *entry)
 660{
 661        struct rte_swx_table_entry *e;
 662
 663        TAILQ_FOREACH(e, &table->pending_delete, node)
 664                if (!table_entry_keycmp(table, entry, e))
 665                        return e; /* Found. */
 666
 667        return NULL; /* Not found. */
 668}
 669
 670static void
 671table_pending_delete_admit(struct table *table)
 672{
 673        TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
 674}
 675
 676static void
 677table_pending_delete_free(struct table *table)
 678{
 679        for ( ; ; ) {
 680                struct rte_swx_table_entry *entry;
 681
 682                entry = TAILQ_FIRST(&table->pending_delete);
 683                if (!entry)
 684                        break;
 685
 686                TAILQ_REMOVE(&table->pending_delete, entry, node);
 687                table_entry_free(entry);
 688        }
 689}
 690
 691static void
 692table_pending_default_free(struct table *table)
 693{
 694        if (!table->pending_default)
 695                return;
 696
 697        free(table->pending_default->action_data);
 698        free(table->pending_default);
 699        table->pending_default = NULL;
 700}
 701
 702static int
 703table_is_update_pending(struct table *table, int consider_pending_default)
 704{
 705        struct rte_swx_table_entry *e;
 706        uint32_t n = 0;
 707
 708        /* Pending add. */
 709        TAILQ_FOREACH(e, &table->pending_add, node)
 710                n++;
 711
 712        /* Pending modify. */
 713        TAILQ_FOREACH(e, &table->pending_modify1, node)
 714                n++;
 715
 716        /* Pending delete. */
 717        TAILQ_FOREACH(e, &table->pending_delete, node)
 718                n++;
 719
 720        /* Pending default. */
 721        if (consider_pending_default && table->pending_default)
 722                n++;
 723
 724        return n;
 725}
 726
 727static void
 728table_free(struct rte_swx_ctl_pipeline *ctl)
 729{
 730        uint32_t i;
 731
 732        if (!ctl->tables)
 733                return;
 734
 735        for (i = 0; i < ctl->info.n_tables; i++) {
 736                struct table *table = &ctl->tables[i];
 737
 738                free(table->mf);
 739                free(table->actions);
 740                free(table->params.key_mask0);
 741
 742                table_entries_free(table);
 743                table_pending_add_free(table);
 744                table_pending_modify0_free(table);
 745                table_pending_modify1_free(table);
 746                table_pending_delete_free(table);
 747                table_pending_default_free(table);
 748        }
 749
 750        free(ctl->tables);
 751        ctl->tables = NULL;
 752}
 753
 754static void
 755selector_group_members_free(struct selector *s, uint32_t group_id)
 756{
 757        struct rte_swx_table_selector_group *group = s->groups[group_id];
 758
 759        if (!group)
 760                return;
 761
 762        for ( ; ; ) {
 763                struct rte_swx_table_selector_member *m;
 764
 765                m = TAILQ_FIRST(&group->members);
 766                if (!m)
 767                        break;
 768
 769                TAILQ_REMOVE(&group->members, m, node);
 770                free(m);
 771        }
 772
 773        free(group);
 774        s->groups[group_id] = NULL;
 775}
 776
 777static void
 778selector_pending_group_members_free(struct selector *s, uint32_t group_id)
 779{
 780        struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
 781
 782        if (!group)
 783                return;
 784
 785        for ( ; ; ) {
 786                struct rte_swx_table_selector_member *m;
 787
 788                m = TAILQ_FIRST(&group->members);
 789                if (!m)
 790                        break;
 791
 792                TAILQ_REMOVE(&group->members, m, node);
 793                free(m);
 794        }
 795
 796        free(group);
 797        s->pending_groups[group_id] = NULL;
 798}
 799
 800static int
 801selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
 802{
 803        struct rte_swx_table_selector_group *g, *gp;
 804        struct rte_swx_table_selector_member *m;
 805
 806        selector_pending_group_members_free(s, group_id);
 807
 808        g = s->groups[group_id];
 809        gp = s->pending_groups[group_id];
 810
 811        if (!gp) {
 812                gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
 813                if (!gp)
 814                        goto error;
 815
 816                TAILQ_INIT(&gp->members);
 817
 818                s->pending_groups[group_id] = gp;
 819        }
 820
 821        if (!g)
 822                return 0;
 823
 824        TAILQ_FOREACH(m, &g->members, node) {
 825                struct rte_swx_table_selector_member *mp;
 826
 827                mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
 828                if (!mp)
 829                        goto error;
 830
 831                memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
 832
 833                TAILQ_INSERT_TAIL(&gp->members, mp, node);
 834        }
 835
 836        return 0;
 837
 838error:
 839        selector_pending_group_members_free(s, group_id);
 840        return -ENOMEM;
 841}
 842
 843static void
 844selector_free(struct rte_swx_ctl_pipeline *ctl)
 845{
 846        uint32_t i;
 847
 848        if (!ctl->selectors)
 849                return;
 850
 851        for (i = 0; i < ctl->info.n_selectors; i++) {
 852                struct selector *s = &ctl->selectors[i];
 853                uint32_t i;
 854
 855                /* selector_fields. */
 856                free(s->selector_fields);
 857
 858                /* groups. */
 859                if (s->groups)
 860                        for (i = 0; i < s->info.n_groups_max; i++)
 861                                selector_group_members_free(s, i);
 862
 863                free(s->groups);
 864
 865                /* pending_groups. */
 866                if (s->pending_groups)
 867                        for (i = 0; i < s->info.n_groups_max; i++)
 868                                selector_pending_group_members_free(s, i);
 869
 870                free(s->pending_groups);
 871
 872                /* groups_added. */
 873                free(s->groups_added);
 874
 875                /* groups_pending_delete. */
 876                free(s->groups_pending_delete);
 877
 878                /* params. */
 879                free(s->params.selector_mask);
 880        }
 881
 882        free(ctl->selectors);
 883        ctl->selectors = NULL;
 884}
 885
 886static struct selector *
 887selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
 888{
 889        uint32_t i;
 890
 891        for (i = 0; i < ctl->info.n_selectors; i++) {
 892                struct selector *s = &ctl->selectors[i];
 893
 894                if (!strcmp(selector_name, s->info.name))
 895                        return s;
 896        }
 897
 898        return NULL;
 899}
 900
 901static int
 902selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
 903{
 904        struct selector *s = &ctl->selectors[selector_id];
 905        struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
 906        uint8_t *selector_mask = NULL;
 907        uint32_t selector_size = 0, selector_offset = 0, i;
 908
 909        /* Find first (smallest offset) and last (biggest offset) match fields. */
 910        first = &s->selector_fields[0];
 911        last = &s->selector_fields[0];
 912
 913        for (i = 1; i < s->info.n_selector_fields; i++) {
 914                struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
 915
 916                if (f->offset < first->offset)
 917                        first = f;
 918
 919                if (f->offset > last->offset)
 920                        last = f;
 921        }
 922
 923        /* selector_offset. */
 924        selector_offset = first->offset / 8;
 925
 926        /* selector_size. */
 927        selector_size = (last->offset + last->n_bits - first->offset) / 8;
 928
 929        /* selector_mask. */
 930        selector_mask = calloc(1, selector_size);
 931        if (!selector_mask)
 932                return -ENOMEM;
 933
 934        for (i = 0; i < s->info.n_selector_fields; i++) {
 935                struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
 936                uint32_t start;
 937                size_t size;
 938
 939                start = (f->offset - first->offset) / 8;
 940                size = f->n_bits / 8;
 941
 942                memset(&selector_mask[start], 0xFF, size);
 943        }
 944
 945        /* Fill in. */
 946        s->params.group_id_offset = s->group_id_field.offset / 8;
 947        s->params.selector_size = selector_size;
 948        s->params.selector_offset = selector_offset;
 949        s->params.selector_mask = selector_mask;
 950        s->params.member_id_offset = s->member_id_field.offset / 8;
 951        s->params.n_groups_max = s->info.n_groups_max;
 952        s->params.n_members_per_group_max = s->info.n_members_per_group_max;
 953
 954        return 0;
 955}
 956
 957static void
 958learner_pending_default_free(struct learner *l)
 959{
 960        if (!l->pending_default)
 961                return;
 962
 963        free(l->pending_default->action_data);
 964        free(l->pending_default);
 965        l->pending_default = NULL;
 966}
 967
 968
 969static void
 970learner_free(struct rte_swx_ctl_pipeline *ctl)
 971{
 972        uint32_t i;
 973
 974        if (!ctl->learners)
 975                return;
 976
 977        for (i = 0; i < ctl->info.n_learners; i++) {
 978                struct learner *l = &ctl->learners[i];
 979
 980                free(l->mf);
 981                free(l->actions);
 982
 983                learner_pending_default_free(l);
 984        }
 985
 986        free(ctl->learners);
 987        ctl->learners = NULL;
 988}
 989
 990static struct learner *
 991learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
 992{
 993        uint32_t i;
 994
 995        for (i = 0; i < ctl->info.n_learners; i++) {
 996                struct learner *l = &ctl->learners[i];
 997
 998                if (!strcmp(learner_name, l->info.name))
 999                        return l;
1000        }
1001
1002        return NULL;
1003}
1004
1005static uint32_t
1006learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1007{
1008        uint32_t action_data_size = 0, i;
1009
1010        for (i = 0; i < l->info.n_actions; i++) {
1011                uint32_t action_id = l->actions[i].action_id;
1012                struct action *a = &ctl->actions[action_id];
1013
1014                if (a->data_size > action_data_size)
1015                        action_data_size = a->data_size;
1016        }
1017
1018        return action_data_size;
1019}
1020
1021static void
1022table_state_free(struct rte_swx_ctl_pipeline *ctl)
1023{
1024        uint32_t table_base_index, selector_base_index, learner_base_index, i;
1025
1026        if (!ctl->ts_next)
1027                return;
1028
1029        /* For each table, free its table state. */
1030        table_base_index = 0;
1031        for (i = 0; i < ctl->info.n_tables; i++) {
1032                struct table *table = &ctl->tables[i];
1033                struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
1034
1035                /* Default action data. */
1036                free(ts->default_action_data);
1037
1038                /* Table object. */
1039                if (!table->is_stub && table->ops.free && ts->obj)
1040                        table->ops.free(ts->obj);
1041        }
1042
1043        /* For each selector table, free its table state. */
1044        selector_base_index = ctl->info.n_tables;
1045        for (i = 0; i < ctl->info.n_selectors; i++) {
1046                struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1047
1048                /* Table object. */
1049                rte_swx_table_selector_free(ts->obj);
1050        }
1051
1052        /* For each learner table, free its table state. */
1053        learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1054        for (i = 0; i < ctl->info.n_learners; i++) {
1055                struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1056
1057                /* Default action data. */
1058                free(ts->default_action_data);
1059        }
1060
1061        free(ctl->ts_next);
1062        ctl->ts_next = NULL;
1063}
1064
1065static int
1066table_state_create(struct rte_swx_ctl_pipeline *ctl)
1067{
1068        uint32_t table_base_index, selector_base_index, learner_base_index, i;
1069        int status = 0;
1070
1071        ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1072                              sizeof(struct rte_swx_table_state));
1073        if (!ctl->ts_next) {
1074                status = -ENOMEM;
1075                goto error;
1076        }
1077
1078        /* Tables. */
1079        table_base_index = 0;
1080        for (i = 0; i < ctl->info.n_tables; i++) {
1081                struct table *table = &ctl->tables[i];
1082                struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1083                struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1084
1085                /* Table object. */
1086                if (!table->is_stub && table->ops.add) {
1087                        ts_next->obj = table->ops.create(&table->params,
1088                                                         &table->entries,
1089                                                         table->info.args,
1090                                                         ctl->numa_node);
1091                        if (!ts_next->obj) {
1092                                status = -ENODEV;
1093                                goto error;
1094                        }
1095                }
1096
1097                if (!table->is_stub && !table->ops.add)
1098                        ts_next->obj = ts->obj;
1099
1100                /* Default action data: duplicate from current table state. */
1101                ts_next->default_action_data =
1102                        malloc(table->params.action_data_size);
1103                if (!ts_next->default_action_data) {
1104                        status = -ENOMEM;
1105                        goto error;
1106                }
1107
1108                memcpy(ts_next->default_action_data,
1109                       ts->default_action_data,
1110                       table->params.action_data_size);
1111
1112                ts_next->default_action_id = ts->default_action_id;
1113        }
1114
1115        /* Selector tables. */
1116        selector_base_index = ctl->info.n_tables;
1117        for (i = 0; i < ctl->info.n_selectors; i++) {
1118                struct selector *s = &ctl->selectors[i];
1119                struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1120
1121                /* Table object. */
1122                ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1123                if (!ts_next->obj) {
1124                        status = -ENODEV;
1125                        goto error;
1126                }
1127        }
1128
1129        /* Learner tables. */
1130        learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1131        for (i = 0; i < ctl->info.n_learners; i++) {
1132                struct learner *l = &ctl->learners[i];
1133                struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1134                struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1135
1136                /* Table object: duplicate from the current table state. */
1137                ts_next->obj = ts->obj;
1138
1139                /* Default action data: duplicate from the current table state. */
1140                ts_next->default_action_data = malloc(l->action_data_size);
1141                if (!ts_next->default_action_data) {
1142                        status = -ENOMEM;
1143                        goto error;
1144                }
1145
1146                memcpy(ts_next->default_action_data,
1147                       ts->default_action_data,
1148                       l->action_data_size);
1149
1150                ts_next->default_action_id = ts->default_action_id;
1151        }
1152
1153        return 0;
1154
1155error:
1156        table_state_free(ctl);
1157        return status;
1158}
1159
1160void
1161rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1162{
1163        if (!ctl)
1164                return;
1165
1166        action_free(ctl);
1167
1168        table_state_free(ctl);
1169
1170        learner_free(ctl);
1171
1172        selector_free(ctl);
1173
1174        table_free(ctl);
1175
1176        free(ctl);
1177}
1178
1179struct rte_swx_ctl_pipeline *
1180rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1181{
1182        struct rte_swx_ctl_pipeline *ctl = NULL;
1183        uint32_t i;
1184        int status;
1185
1186        if (!p)
1187                goto error;
1188
1189        ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1190        if (!ctl)
1191                goto error;
1192
1193        /* info. */
1194        status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1195        if (status)
1196                goto error;
1197
1198        /* numa_node. */
1199        status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1200        if (status)
1201                goto error;
1202
1203        /* p. */
1204        ctl->p = p;
1205
1206        /* actions. */
1207        ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1208        if (!ctl->actions)
1209                goto error;
1210
1211        for (i = 0; i < ctl->info.n_actions; i++) {
1212                struct action *a = &ctl->actions[i];
1213                uint32_t j;
1214
1215                /* info. */
1216                status = rte_swx_ctl_action_info_get(p, i, &a->info);
1217                if (status)
1218                        goto error;
1219
1220                /* args. */
1221                a->args = calloc(a->info.n_args,
1222                                 sizeof(struct rte_swx_ctl_action_arg_info));
1223                if (!a->args)
1224                        goto error;
1225
1226                for (j = 0; j < a->info.n_args; j++) {
1227                        status = rte_swx_ctl_action_arg_info_get(p,
1228                                                                 i,
1229                                                                 j,
1230                                                                 &a->args[j]);
1231                        if (status)
1232                                goto error;
1233                }
1234
1235                /* data_size. */
1236                for (j = 0; j < a->info.n_args; j++) {
1237                        struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1238
1239                        a->data_size += info->n_bits;
1240                }
1241
1242                a->data_size = (a->data_size + 7) / 8;
1243        }
1244
1245        /* tables. */
1246        ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1247        if (!ctl->tables)
1248                goto error;
1249
1250        for (i = 0; i < ctl->info.n_tables; i++) {
1251                struct table *t = &ctl->tables[i];
1252
1253                TAILQ_INIT(&t->entries);
1254                TAILQ_INIT(&t->pending_add);
1255                TAILQ_INIT(&t->pending_modify0);
1256                TAILQ_INIT(&t->pending_modify1);
1257                TAILQ_INIT(&t->pending_delete);
1258        }
1259
1260        for (i = 0; i < ctl->info.n_tables; i++) {
1261                struct table *t = &ctl->tables[i];
1262                uint32_t j;
1263
1264                /* info. */
1265                status = rte_swx_ctl_table_info_get(p, i, &t->info);
1266                if (status)
1267                        goto error;
1268
1269                /* mf. */
1270                t->mf = calloc(t->info.n_match_fields,
1271                        sizeof(struct rte_swx_ctl_table_match_field_info));
1272                if (!t->mf)
1273                        goto error;
1274
1275                for (j = 0; j < t->info.n_match_fields; j++) {
1276                        status = rte_swx_ctl_table_match_field_info_get(p,
1277                                i,
1278                                j,
1279                                &t->mf[j]);
1280                        if (status)
1281                                goto error;
1282                }
1283
1284                /* actions. */
1285                t->actions = calloc(t->info.n_actions,
1286                        sizeof(struct rte_swx_ctl_table_action_info));
1287                if (!t->actions)
1288                        goto error;
1289
1290                for (j = 0; j < t->info.n_actions; j++) {
1291                        status = rte_swx_ctl_table_action_info_get(p,
1292                                i,
1293                                j,
1294                                &t->actions[j]);
1295                        if (status ||
1296                            t->actions[j].action_id >= ctl->info.n_actions)
1297                                goto error;
1298                }
1299
1300                /* ops, is_stub. */
1301                status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1302                if (status)
1303                        goto error;
1304
1305                if ((t->is_stub && t->info.n_match_fields) ||
1306                    (!t->is_stub && !t->info.n_match_fields))
1307                        goto error;
1308
1309                /* params. */
1310                status = table_params_get(ctl, i);
1311                if (status)
1312                        goto error;
1313        }
1314
1315        /* selector tables. */
1316        ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1317        if (!ctl->selectors)
1318                goto error;
1319
1320        for (i = 0; i < ctl->info.n_selectors; i++) {
1321                struct selector *s = &ctl->selectors[i];
1322                uint32_t j;
1323
1324                /* info. */
1325                status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1326                if (status)
1327                        goto error;
1328
1329                /* group_id field. */
1330                status = rte_swx_ctl_selector_group_id_field_info_get(p,
1331                        i,
1332                        &s->group_id_field);
1333                if (status)
1334                        goto error;
1335
1336                /* selector fields. */
1337                s->selector_fields = calloc(s->info.n_selector_fields,
1338                        sizeof(struct rte_swx_ctl_table_match_field_info));
1339                if (!s->selector_fields)
1340                        goto error;
1341
1342                for (j = 0; j < s->info.n_selector_fields; j++) {
1343                        status = rte_swx_ctl_selector_field_info_get(p,
1344                                i,
1345                                j,
1346                                &s->selector_fields[j]);
1347                        if (status)
1348                                goto error;
1349                }
1350
1351                /* member_id field. */
1352                status = rte_swx_ctl_selector_member_id_field_info_get(p,
1353                        i,
1354                        &s->member_id_field);
1355                if (status)
1356                        goto error;
1357
1358                /* groups. */
1359                s->groups = calloc(s->info.n_groups_max,
1360                        sizeof(struct rte_swx_table_selector_group *));
1361                if (!s->groups)
1362                        goto error;
1363
1364                /* pending_groups. */
1365                s->pending_groups = calloc(s->info.n_groups_max,
1366                        sizeof(struct rte_swx_table_selector_group *));
1367                if (!s->pending_groups)
1368                        goto error;
1369
1370                /* groups_added. */
1371                s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1372                if (!s->groups_added)
1373                        goto error;
1374
1375                /* groups_pending_delete. */
1376                s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1377                if (!s->groups_pending_delete)
1378                        goto error;
1379
1380                /* params. */
1381                status = selector_params_get(ctl, i);
1382                if (status)
1383                        goto error;
1384        }
1385
1386        /* learner tables. */
1387        ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1388        if (!ctl->learners)
1389                goto error;
1390
1391        for (i = 0; i < ctl->info.n_learners; i++) {
1392                struct learner *l = &ctl->learners[i];
1393                uint32_t j;
1394
1395                /* info. */
1396                status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1397                if (status)
1398                        goto error;
1399
1400                /* mf. */
1401                l->mf = calloc(l->info.n_match_fields,
1402                               sizeof(struct rte_swx_ctl_table_match_field_info));
1403                if (!l->mf)
1404                        goto error;
1405
1406                for (j = 0; j < l->info.n_match_fields; j++) {
1407                        status = rte_swx_ctl_learner_match_field_info_get(p,
1408                                i,
1409                                j,
1410                                &l->mf[j]);
1411                        if (status)
1412                                goto error;
1413                }
1414
1415                /* actions. */
1416                l->actions = calloc(l->info.n_actions,
1417                        sizeof(struct rte_swx_ctl_table_action_info));
1418                if (!l->actions)
1419                        goto error;
1420
1421                for (j = 0; j < l->info.n_actions; j++) {
1422                        status = rte_swx_ctl_learner_action_info_get(p,
1423                                i,
1424                                j,
1425                                &l->actions[j]);
1426                        if (status || l->actions[j].action_id >= ctl->info.n_actions)
1427                                goto error;
1428                }
1429
1430                /* action_data_size. */
1431                l->action_data_size = learner_action_data_size_get(ctl, l);
1432        }
1433
1434        /* ts. */
1435        status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1436        if (status)
1437                goto error;
1438
1439        /* ts_next. */
1440        status = table_state_create(ctl);
1441        if (status)
1442                goto error;
1443
1444        return ctl;
1445
1446error:
1447        rte_swx_ctl_pipeline_free(ctl);
1448        return NULL;
1449}
1450
1451int
1452rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1453                                     const char *table_name,
1454                                     struct rte_swx_table_entry *entry)
1455{
1456        struct table *table;
1457        struct rte_swx_table_entry *new_entry, *existing_entry;
1458        uint32_t table_id;
1459
1460        CHECK(ctl, EINVAL);
1461        CHECK(table_name && table_name[0], EINVAL);
1462
1463        table = table_find(ctl, table_name);
1464        CHECK(table, EINVAL);
1465        table_id = table - ctl->tables;
1466
1467        CHECK(entry, EINVAL);
1468        CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1469
1470        new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1471        CHECK(new_entry, ENOMEM);
1472
1473        /* The new entry is found in the table->entries list:
1474         * - Add the new entry to the table->pending_modify1 list;
1475         * - Move the existing entry from the table->entries list to the
1476         *   table->pending_modify0 list.
1477         */
1478        existing_entry = table_entries_find(table, entry);
1479        if (existing_entry) {
1480                TAILQ_INSERT_TAIL(&table->pending_modify1,
1481                                  new_entry,
1482                                  node);
1483
1484                TAILQ_REMOVE(&table->entries,
1485                             existing_entry,
1486                             node);
1487
1488                TAILQ_INSERT_TAIL(&table->pending_modify0,
1489                                  existing_entry,
1490                                  node);
1491
1492                return 0;
1493        }
1494
1495        /* The new entry is found in the table->pending_add list:
1496         * - Replace the entry in the table->pending_add list with the new entry
1497         *   (and free the replaced entry).
1498         */
1499        existing_entry = table_pending_add_find(table, entry);
1500        if (existing_entry) {
1501                TAILQ_INSERT_AFTER(&table->pending_add,
1502                                   existing_entry,
1503                                   new_entry,
1504                                   node);
1505
1506                TAILQ_REMOVE(&table->pending_add,
1507                             existing_entry,
1508                             node);
1509
1510                table_entry_free(existing_entry);
1511
1512                return 0;
1513        }
1514
1515        /* The new entry is found in the table->pending_modify1 list:
1516         * - Replace the entry in the table->pending_modify1 list with the new
1517         *   entry (and free the replaced entry).
1518         */
1519        existing_entry = table_pending_modify1_find(table, entry);
1520        if (existing_entry) {
1521                TAILQ_INSERT_AFTER(&table->pending_modify1,
1522                                   existing_entry,
1523                                   new_entry,
1524                                   node);
1525
1526                TAILQ_REMOVE(&table->pending_modify1,
1527                             existing_entry,
1528                             node);
1529
1530                table_entry_free(existing_entry);
1531
1532                return 0;
1533        }
1534
1535        /* The new entry is found in the table->pending_delete list:
1536         * - Add the new entry to the table->pending_modify1 list;
1537         * - Move the existing entry from the table->pending_delete list to the
1538         *   table->pending_modify0 list.
1539         */
1540        existing_entry = table_pending_delete_find(table, entry);
1541        if (existing_entry) {
1542                TAILQ_INSERT_TAIL(&table->pending_modify1,
1543                                  new_entry,
1544                                  node);
1545
1546                TAILQ_REMOVE(&table->pending_delete,
1547                             existing_entry,
1548                             node);
1549
1550                TAILQ_INSERT_TAIL(&table->pending_modify0,
1551                                  existing_entry,
1552                                  node);
1553
1554                return 0;
1555        }
1556
1557        /* The new entry is not found in any of the above lists:
1558         * - Add the new entry to the table->pending_add list.
1559         */
1560        TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1561
1562        return 0;
1563}
1564
1565int
1566rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1567                                        const char *table_name,
1568                                        struct rte_swx_table_entry *entry)
1569{
1570        struct table *table;
1571        struct rte_swx_table_entry *existing_entry;
1572        uint32_t table_id;
1573
1574        CHECK(ctl, EINVAL);
1575
1576        CHECK(table_name && table_name[0], EINVAL);
1577        table = table_find(ctl, table_name);
1578        CHECK(table, EINVAL);
1579        table_id = table - ctl->tables;
1580
1581        CHECK(entry, EINVAL);
1582        CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1583
1584        /* The entry is found in the table->entries list:
1585         * - Move the existing entry from the table->entries list to to the
1586         *   table->pending_delete list.
1587         */
1588        existing_entry = table_entries_find(table, entry);
1589        if (existing_entry) {
1590                TAILQ_REMOVE(&table->entries,
1591                             existing_entry,
1592                             node);
1593
1594                TAILQ_INSERT_TAIL(&table->pending_delete,
1595                                  existing_entry,
1596                                  node);
1597
1598                return 0;
1599        }
1600
1601        /* The entry is found in the table->pending_add list:
1602         * - Remove the entry from the table->pending_add list and free it.
1603         */
1604        existing_entry = table_pending_add_find(table, entry);
1605        if (existing_entry) {
1606                TAILQ_REMOVE(&table->pending_add,
1607                             existing_entry,
1608                             node);
1609
1610                table_entry_free(existing_entry);
1611        }
1612
1613        /* The entry is found in the table->pending_modify1 list:
1614         * - Free the entry in the table->pending_modify1 list;
1615         * - Move the existing entry from the table->pending_modify0 list to the
1616         *   table->pending_delete list.
1617         */
1618        existing_entry = table_pending_modify1_find(table, entry);
1619        if (existing_entry) {
1620                struct rte_swx_table_entry *real_existing_entry;
1621
1622                TAILQ_REMOVE(&table->pending_modify1,
1623                             existing_entry,
1624                             node);
1625
1626                table_entry_free(existing_entry);
1627
1628                real_existing_entry = table_pending_modify0_find(table, entry);
1629                CHECK(real_existing_entry, EINVAL); /* Coverity. */
1630
1631                TAILQ_REMOVE(&table->pending_modify0,
1632                             real_existing_entry,
1633                             node);
1634
1635                TAILQ_INSERT_TAIL(&table->pending_delete,
1636                                  real_existing_entry,
1637                                  node);
1638
1639                return 0;
1640        }
1641
1642        /* The entry is found in the table->pending_delete list:
1643         * - Do nothing: the existing entry is already in the
1644         *   table->pending_delete list, i.e. already marked for delete, so
1645         *   simply keep it there as it is.
1646         */
1647
1648        /* The entry is not found in any of the above lists:
1649         * - Do nothing: no existing entry to delete.
1650         */
1651
1652        return 0;
1653}
1654
1655int
1656rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1657                                             const char *table_name,
1658                                             struct rte_swx_table_entry *entry)
1659{
1660        struct table *table;
1661        struct rte_swx_table_entry *new_entry;
1662        uint32_t table_id;
1663
1664        CHECK(ctl, EINVAL);
1665
1666        CHECK(table_name && table_name[0], EINVAL);
1667        table = table_find(ctl, table_name);
1668        CHECK(table, EINVAL);
1669        table_id = table - ctl->tables;
1670        CHECK(!table->info.default_action_is_const, EINVAL);
1671
1672        CHECK(entry, EINVAL);
1673        CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1674
1675        new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1676        CHECK(new_entry, ENOMEM);
1677
1678        table_pending_default_free(table);
1679
1680        table->pending_default = new_entry;
1681        return 0;
1682}
1683
1684
1685static void
1686table_entry_list_free(struct rte_swx_table_entry_list *list)
1687{
1688        for ( ; ; ) {
1689                struct rte_swx_table_entry *entry;
1690
1691                entry = TAILQ_FIRST(list);
1692                if (!entry)
1693                        break;
1694
1695                TAILQ_REMOVE(list, entry, node);
1696                table_entry_free(entry);
1697        }
1698}
1699
1700static int
1701table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1702                           uint32_t table_id,
1703                           struct rte_swx_table_entry_list *dst,
1704                           struct rte_swx_table_entry_list *src)
1705{
1706        struct rte_swx_table_entry *src_entry;
1707
1708        TAILQ_FOREACH(src_entry, src, node) {
1709                struct rte_swx_table_entry *dst_entry;
1710
1711                dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1712                if (!dst_entry)
1713                        goto error;
1714
1715                TAILQ_INSERT_TAIL(dst, dst_entry, node);
1716        }
1717
1718        return 0;
1719
1720error:
1721        table_entry_list_free(dst);
1722        return -ENOMEM;
1723}
1724
1725/* This commit stage contains all the operations that can fail; in case ANY of
1726 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1727 */
1728static int
1729table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1730               uint32_t table_id,
1731               uint32_t after_swap)
1732{
1733        struct table *table = &ctl->tables[table_id];
1734        struct rte_swx_table_state *ts = &ctl->ts[table_id];
1735        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1736
1737        if (table->is_stub || !table_is_update_pending(table, 0))
1738                return 0;
1739
1740        /*
1741         * Current table supports incremental update.
1742         */
1743        if (table->ops.add) {
1744                /* Reset counters. */
1745                table->n_add = 0;
1746                table->n_modify = 0;
1747                table->n_delete = 0;
1748
1749                /* Add pending rules. */
1750                struct rte_swx_table_entry *entry;
1751
1752                TAILQ_FOREACH(entry, &table->pending_add, node) {
1753                        int status;
1754
1755                        status = table->ops.add(ts_next->obj, entry);
1756                        if (status)
1757                                return status;
1758
1759                        table->n_add++;
1760                }
1761
1762                /* Modify pending rules. */
1763                TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1764                        int status;
1765
1766                        status = table->ops.add(ts_next->obj, entry);
1767                        if (status)
1768                                return status;
1769
1770                        table->n_modify++;
1771                }
1772
1773                /* Delete pending rules. */
1774                TAILQ_FOREACH(entry, &table->pending_delete, node) {
1775                        int status;
1776
1777                        status = table->ops.del(ts_next->obj, entry);
1778                        if (status)
1779                                return status;
1780
1781                        table->n_delete++;
1782                }
1783
1784                return 0;
1785        }
1786
1787        /*
1788         * Current table does NOT support incremental update.
1789         */
1790        if (!after_swap) {
1791                struct rte_swx_table_entry_list list;
1792                int status;
1793
1794                /* Create updated list of entries included. */
1795                TAILQ_INIT(&list);
1796
1797                status = table_entry_list_duplicate(ctl,
1798                                                    table_id,
1799                                                    &list,
1800                                                    &table->entries);
1801                if (status)
1802                        goto error;
1803
1804                status = table_entry_list_duplicate(ctl,
1805                                                    table_id,
1806                                                    &list,
1807                                                    &table->pending_add);
1808                if (status)
1809                        goto error;
1810
1811                status = table_entry_list_duplicate(ctl,
1812                                                    table_id,
1813                                                    &list,
1814                                                    &table->pending_modify1);
1815                if (status)
1816                        goto error;
1817
1818                /* Create new table object with the updates included. */
1819                ts_next->obj = table->ops.create(&table->params,
1820                                                 &list,
1821                                                 table->info.args,
1822                                                 ctl->numa_node);
1823                if (!ts_next->obj) {
1824                        status = -ENODEV;
1825                        goto error;
1826                }
1827
1828                table_entry_list_free(&list);
1829
1830                return 0;
1831
1832error:
1833                table_entry_list_free(&list);
1834                return status;
1835        }
1836
1837        /* Free the old table object. */
1838        if (ts_next->obj && table->ops.free)
1839                table->ops.free(ts_next->obj);
1840
1841        /* Copy over the new table object. */
1842        ts_next->obj = ts->obj;
1843
1844        return 0;
1845}
1846
1847/* This commit stage contains all the operations that cannot fail. They are
1848 * executed only if the previous stage was successful for ALL the tables. Hence,
1849 * none of these operations has to be rolled back for ANY table.
1850 */
1851static void
1852table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1853{
1854        struct table *table = &ctl->tables[table_id];
1855        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1856        struct action *a;
1857        uint8_t *action_data;
1858        uint64_t action_id;
1859
1860        /* Copy the pending default entry. */
1861        if (!table->pending_default)
1862                return;
1863
1864        action_id = table->pending_default->action_id;
1865        action_data = table->pending_default->action_data;
1866        a = &ctl->actions[action_id];
1867
1868        if (a->data_size)
1869                memcpy(ts_next->default_action_data, action_data, a->data_size);
1870
1871        ts_next->default_action_id = action_id;
1872}
1873
1874/* This last commit stage is simply finalizing a successful commit operation.
1875 * This stage is only executed if all the previous stages were successful. This
1876 * stage cannot fail.
1877 */
1878static void
1879table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1880{
1881        struct table *table = &ctl->tables[table_id];
1882
1883        /* Move all the pending add entries to the table, as they are now part
1884         * of the table.
1885         */
1886        table_pending_add_admit(table);
1887
1888        /* Move all the pending modify1 entries to table, are they are now part
1889         * of the table. Free up all the pending modify0 entries, as they are no
1890         * longer part of the table.
1891         */
1892        table_pending_modify1_admit(table);
1893        table_pending_modify0_free(table);
1894
1895        /* Free up all the pending delete entries, as they are no longer part of
1896         * the table.
1897         */
1898        table_pending_delete_free(table);
1899
1900        /* Free up the pending default entry, as it is now part of the table. */
1901        table_pending_default_free(table);
1902}
1903
1904/* The rollback stage is only executed when the commit failed, i.e. ANY of the
1905 * commit operations that can fail did fail for ANY table. It reverts ALL the
1906 * tables to their state before the commit started, as if the commit never
1907 * happened.
1908 */
1909static void
1910table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1911{
1912        struct table *table = &ctl->tables[table_id];
1913        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1914
1915        if (table->is_stub || !table_is_update_pending(table, 0))
1916                return;
1917
1918        if (table->ops.add) {
1919                struct rte_swx_table_entry *entry;
1920
1921                /* Add back all the entries that were just deleted. */
1922                TAILQ_FOREACH(entry, &table->pending_delete, node) {
1923                        if (!table->n_delete)
1924                                break;
1925
1926                        table->ops.add(ts_next->obj, entry);
1927                        table->n_delete--;
1928                }
1929
1930                /* Add back the old copy for all the entries that were just
1931                 * modified.
1932                 */
1933                TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1934                        if (!table->n_modify)
1935                                break;
1936
1937                        table->ops.add(ts_next->obj, entry);
1938                        table->n_modify--;
1939                }
1940
1941                /* Delete all the entries that were just added. */
1942                TAILQ_FOREACH(entry, &table->pending_add, node) {
1943                        if (!table->n_add)
1944                                break;
1945
1946                        table->ops.del(ts_next->obj, entry);
1947                        table->n_add--;
1948                }
1949        } else {
1950                struct rte_swx_table_state *ts = &ctl->ts[table_id];
1951
1952                /* Free the new table object, as update was cancelled. */
1953                if (ts_next->obj && table->ops.free)
1954                        table->ops.free(ts_next->obj);
1955
1956                /* Reinstate the old table object. */
1957                ts_next->obj = ts->obj;
1958        }
1959}
1960
1961/* This stage is conditionally executed (as instructed by the user) after a
1962 * failed commit operation to remove ALL the pending work for ALL the tables.
1963 */
1964static void
1965table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1966{
1967        struct table *table = &ctl->tables[table_id];
1968
1969        /* Free up all the pending add entries, as none of them is part of the
1970         * table.
1971         */
1972        table_pending_add_free(table);
1973
1974        /* Free up all the pending modify1 entries, as none of them made it to
1975         * the table. Add back all the pending modify0 entries, as none of them
1976         * was deleted from the table.
1977         */
1978        table_pending_modify1_free(table);
1979        table_pending_modify0_admit(table);
1980
1981        /* Add back all the pending delete entries, as none of them was deleted
1982         * from the table.
1983         */
1984        table_pending_delete_admit(table);
1985
1986        /* Free up the pending default entry, as it is no longer going to be
1987         * added to the table.
1988         */
1989        table_pending_default_free(table);
1990}
1991
1992int
1993rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1994                                        const char *selector_name,
1995                                        uint32_t *group_id)
1996{
1997        struct selector *s;
1998        uint32_t i;
1999
2000        /* Check input arguments. */
2001        if (!ctl || !selector_name || !selector_name[0] || !group_id)
2002                return -EINVAL;
2003
2004        s = selector_find(ctl, selector_name);
2005        if (!s)
2006                return -EINVAL;
2007
2008        /* Find an unused group. */
2009        for (i = 0; i < s->info.n_groups_max; i++)
2010                if (!s->groups_added[i]) {
2011                        *group_id = i;
2012                        s->groups_added[i] = 1;
2013                        return 0;
2014                }
2015
2016        return -ENOSPC;
2017}
2018
2019int
2020rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2021                                           const char *selector_name,
2022                                           uint32_t group_id)
2023{
2024        struct selector *s;
2025        struct rte_swx_table_selector_group *group;
2026
2027        /* Check input arguments. */
2028        if (!ctl || !selector_name || !selector_name[0])
2029                return -EINVAL;
2030
2031        s = selector_find(ctl, selector_name);
2032        if (!s ||
2033           (group_id >= s->info.n_groups_max) ||
2034           !s->groups_added[group_id])
2035                return -EINVAL;
2036
2037        /* Check if this group is already scheduled for deletion. */
2038        if (s->groups_pending_delete[group_id])
2039                return 0;
2040
2041        /* Initialize the pending group, if needed. */
2042        if (!s->pending_groups[group_id]) {
2043                int status;
2044
2045                status = selector_group_duplicate_to_pending(s, group_id);
2046                if (status)
2047                        return status;
2048        }
2049
2050        group = s->pending_groups[group_id];
2051
2052        /* Schedule removal of all the members from the current group. */
2053        for ( ; ; ) {
2054                struct rte_swx_table_selector_member *m;
2055
2056                m = TAILQ_FIRST(&group->members);
2057                if (!m)
2058                        break;
2059
2060                TAILQ_REMOVE(&group->members, m, node);
2061                free(m);
2062        }
2063
2064        /* Schedule the group for deletion. */
2065        s->groups_pending_delete[group_id] = 1;
2066
2067        return 0;
2068}
2069
2070int
2071rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2072                                               const char *selector_name,
2073                                               uint32_t group_id,
2074                                               uint32_t member_id,
2075                                               uint32_t member_weight)
2076{
2077        struct selector *s;
2078        struct rte_swx_table_selector_group *group;
2079        struct rte_swx_table_selector_member *m;
2080
2081        if (!member_weight)
2082                return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2083                                                                         selector_name,
2084                                                                         group_id,
2085                                                                         member_id);
2086
2087        /* Check input arguments. */
2088        if (!ctl || !selector_name || !selector_name[0])
2089                return -EINVAL;
2090
2091        s = selector_find(ctl, selector_name);
2092        if (!s ||
2093           (group_id >= s->info.n_groups_max) ||
2094           !s->groups_added[group_id] ||
2095           s->groups_pending_delete[group_id])
2096                return -EINVAL;
2097
2098        /* Initialize the pending group, if needed. */
2099        if (!s->pending_groups[group_id]) {
2100                int status;
2101
2102                status = selector_group_duplicate_to_pending(s, group_id);
2103                if (status)
2104                        return status;
2105        }
2106
2107        group = s->pending_groups[group_id];
2108
2109        /* If this member is already in this group, then simply update its weight and return. */
2110        TAILQ_FOREACH(m, &group->members, node)
2111                if (m->member_id == member_id) {
2112                        m->member_weight = member_weight;
2113                        return 0;
2114                }
2115
2116        /* Add new member to this group. */
2117        m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2118        if (!m)
2119                return -ENOMEM;
2120
2121        m->member_id = member_id;
2122        m->member_weight = member_weight;
2123
2124        TAILQ_INSERT_TAIL(&group->members, m, node);
2125
2126        return 0;
2127}
2128
2129int
2130rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2131                                                  const char *selector_name,
2132                                                  uint32_t group_id __rte_unused,
2133                                                  uint32_t member_id __rte_unused)
2134{
2135        struct selector *s;
2136        struct rte_swx_table_selector_group *group;
2137        struct rte_swx_table_selector_member *m;
2138
2139        /* Check input arguments. */
2140        if (!ctl || !selector_name || !selector_name[0])
2141                return -EINVAL;
2142
2143        s = selector_find(ctl, selector_name);
2144        if (!s ||
2145            (group_id >= s->info.n_groups_max) ||
2146            !s->groups_added[group_id] ||
2147            s->groups_pending_delete[group_id])
2148                return -EINVAL;
2149
2150        /* Initialize the pending group, if needed. */
2151        if (!s->pending_groups[group_id]) {
2152                int status;
2153
2154                status = selector_group_duplicate_to_pending(s, group_id);
2155                if (status)
2156                        return status;
2157        }
2158
2159        group = s->pending_groups[group_id];
2160
2161        /* Look for this member in the group and remove it, if found. */
2162        TAILQ_FOREACH(m, &group->members, node)
2163                if (m->member_id == member_id) {
2164                        TAILQ_REMOVE(&group->members, m, node);
2165                        free(m);
2166                        return 0;
2167                }
2168
2169        return 0;
2170}
2171
2172static int
2173selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2174{
2175        struct selector *s = &ctl->selectors[selector_id];
2176        struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2177        uint32_t group_id;
2178
2179        /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2180         * mirror copy (ts_next->obj).
2181         */
2182        for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2183                struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2184                int status;
2185
2186                /* Skip this group if no change needed. */
2187                if (!group)
2188                        continue;
2189
2190                /* Apply the pending changes for the current group. */
2191                status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2192                if (status)
2193                        return status;
2194        }
2195
2196        return 0;
2197}
2198
2199static void
2200selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2201{
2202        struct selector *s = &ctl->selectors[selector_id];
2203        uint32_t group_id;
2204
2205        /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2206         * records (s->groups[group_id).
2207         */
2208        for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2209                struct rte_swx_table_selector_group *g = s->groups[group_id];
2210                struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2211
2212                /* Skip this group if no change needed. */
2213                if (!gp)
2214                        continue;
2215
2216                /* Transition the pending changes to stable. */
2217                s->groups[group_id] = gp;
2218                s->pending_groups[group_id] = NULL;
2219
2220                /* Free the old group member list. */
2221                if (!g)
2222                        continue;
2223
2224                for ( ; ; ) {
2225                        struct rte_swx_table_selector_member *m;
2226
2227                        m = TAILQ_FIRST(&g->members);
2228                        if (!m)
2229                                break;
2230
2231                        TAILQ_REMOVE(&g->members, m, node);
2232                        free(m);
2233                }
2234
2235                free(g);
2236        }
2237
2238        /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2239         * s->groups_added[group_id].
2240         */
2241        for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2242                if (s->groups_pending_delete[group_id]) {
2243                        s->groups_added[group_id] = 0;
2244                        s->groups_pending_delete[group_id] = 0;
2245                }
2246}
2247
2248static void
2249selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2250{
2251        struct selector *s = &ctl->selectors[selector_id];
2252        struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2253        struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2254        uint32_t group_id;
2255
2256        /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2257        for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2258                struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2259
2260                if (gp) {
2261                        ts_next->obj = ts->obj;
2262                        break;
2263                }
2264        }
2265}
2266
2267static void
2268selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2269{
2270        struct selector *s = &ctl->selectors[selector_id];
2271        uint32_t group_id;
2272
2273        /* Discard any pending group member changes (s->pending_groups[group_id]). */
2274        for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2275                selector_pending_group_members_free(s, group_id);
2276
2277        /* Discard any pending group deletions. */
2278        memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2279}
2280
2281static struct rte_swx_table_entry *
2282learner_default_entry_alloc(struct learner *l)
2283{
2284        struct rte_swx_table_entry *entry;
2285
2286        entry = calloc(1, sizeof(struct rte_swx_table_entry));
2287        if (!entry)
2288                goto error;
2289
2290        /* action_data. */
2291        if (l->action_data_size) {
2292                entry->action_data = calloc(1, l->action_data_size);
2293                if (!entry->action_data)
2294                        goto error;
2295        }
2296
2297        return entry;
2298
2299error:
2300        table_entry_free(entry);
2301        return NULL;
2302}
2303
2304static int
2305learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2306                            uint32_t learner_id,
2307                            struct rte_swx_table_entry *entry)
2308{
2309        struct learner *l = &ctl->learners[learner_id];
2310        struct action *a;
2311        uint32_t i;
2312
2313        CHECK(entry, EINVAL);
2314
2315        /* action_id. */
2316        for (i = 0; i < l->info.n_actions; i++)
2317                if (entry->action_id == l->actions[i].action_id)
2318                        break;
2319
2320        CHECK(i < l->info.n_actions, EINVAL);
2321
2322        /* action_data. */
2323        a = &ctl->actions[entry->action_id];
2324        CHECK(!(a->data_size && !entry->action_data), EINVAL);
2325
2326        return 0;
2327}
2328
2329static struct rte_swx_table_entry *
2330learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2331                                uint32_t learner_id,
2332                                struct rte_swx_table_entry *entry)
2333{
2334        struct learner *l = &ctl->learners[learner_id];
2335        struct rte_swx_table_entry *new_entry = NULL;
2336        struct action *a;
2337        uint32_t i;
2338
2339        if (!entry)
2340                goto error;
2341
2342        new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2343        if (!new_entry)
2344                goto error;
2345
2346        /* action_id. */
2347        for (i = 0; i < l->info.n_actions; i++)
2348                if (entry->action_id == l->actions[i].action_id)
2349                        break;
2350
2351        if (i >= l->info.n_actions)
2352                goto error;
2353
2354        new_entry->action_id = entry->action_id;
2355
2356        /* action_data. */
2357        a = &ctl->actions[entry->action_id];
2358        if (a->data_size && !entry->action_data)
2359                goto error;
2360
2361        /* The table layer provisions a constant action data size per
2362         * entry, which should be the largest data size for all the
2363         * actions enabled for the current table, and attempts to copy
2364         * this many bytes each time a table entry is added, even if the
2365         * specific action requires less data or even no data at all,
2366         * hence we always have to allocate the max.
2367         */
2368        new_entry->action_data = calloc(1, l->action_data_size);
2369        if (!new_entry->action_data)
2370                goto error;
2371
2372        if (a->data_size)
2373                memcpy(new_entry->action_data, entry->action_data, a->data_size);
2374
2375        return new_entry;
2376
2377error:
2378        table_entry_free(new_entry);
2379        return NULL;
2380}
2381
2382int
2383rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2384                                               const char *learner_name,
2385                                               struct rte_swx_table_entry *entry)
2386{
2387        struct learner *l;
2388        struct rte_swx_table_entry *new_entry;
2389        uint32_t learner_id;
2390
2391        CHECK(ctl, EINVAL);
2392
2393        CHECK(learner_name && learner_name[0], EINVAL);
2394        l = learner_find(ctl, learner_name);
2395        CHECK(l, EINVAL);
2396        learner_id = l - ctl->learners;
2397        CHECK(!l->info.default_action_is_const, EINVAL);
2398
2399        CHECK(entry, EINVAL);
2400        CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2401
2402        CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2403
2404        new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2405        CHECK(new_entry, ENOMEM);
2406
2407        learner_pending_default_free(l);
2408
2409        l->pending_default = new_entry;
2410        return 0;
2411}
2412
2413static void
2414learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2415{
2416        struct learner *l = &ctl->learners[learner_id];
2417        struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2418                ctl->info.n_selectors + learner_id];
2419        struct action *a;
2420        uint8_t *action_data;
2421        uint64_t action_id;
2422
2423        /* Copy the pending default entry. */
2424        if (!l->pending_default)
2425                return;
2426
2427        action_id = l->pending_default->action_id;
2428        action_data = l->pending_default->action_data;
2429        a = &ctl->actions[action_id];
2430
2431        if (a->data_size)
2432                memcpy(ts_next->default_action_data, action_data, a->data_size);
2433
2434        ts_next->default_action_id = action_id;
2435}
2436
2437static void
2438learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2439{
2440        struct learner *l = &ctl->learners[learner_id];
2441
2442        /* Free up the pending default entry, as it is now part of the table. */
2443        learner_pending_default_free(l);
2444}
2445
2446static void
2447learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2448{
2449        struct learner *l = &ctl->learners[learner_id];
2450
2451        /* Free up the pending default entry, as it is no longer going to be added to the table. */
2452        learner_pending_default_free(l);
2453}
2454
2455int
2456rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2457{
2458        struct rte_swx_table_state *ts;
2459        int status = 0;
2460        uint32_t i;
2461
2462        CHECK(ctl, EINVAL);
2463
2464        /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2465         * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2466         * We must be able to fully revert all the changes that can fail as if they never happened.
2467         */
2468        for (i = 0; i < ctl->info.n_tables; i++) {
2469                status = table_rollfwd0(ctl, i, 0);
2470                if (status)
2471                        goto rollback;
2472        }
2473
2474        for (i = 0; i < ctl->info.n_selectors; i++) {
2475                status = selector_rollfwd(ctl, i);
2476                if (status)
2477                        goto rollback;
2478        }
2479
2480        /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2481         * onwards, the transaction is guaranteed to be successful.
2482         */
2483        for (i = 0; i < ctl->info.n_tables; i++)
2484                table_rollfwd1(ctl, i);
2485
2486        for (i = 0; i < ctl->info.n_learners; i++)
2487                learner_rollfwd(ctl, i);
2488
2489        /* Swap the table state for the data plane. The current ts and ts_next
2490         * become the new ts_next and ts, respectively.
2491         */
2492        rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2493        usleep(100);
2494        ts = ctl->ts;
2495        ctl->ts = ctl->ts_next;
2496        ctl->ts_next = ts;
2497
2498        /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2499         * the current ts_next in sync with the current ts. Since the changes that can fail did
2500         * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2501         * current ts_next, hence no error checking is needed.
2502         */
2503        for (i = 0; i < ctl->info.n_tables; i++) {
2504                table_rollfwd0(ctl, i, 1);
2505                table_rollfwd1(ctl, i);
2506                table_rollfwd2(ctl, i);
2507        }
2508
2509        for (i = 0; i < ctl->info.n_selectors; i++) {
2510                selector_rollfwd(ctl, i);
2511                selector_rollfwd_finalize(ctl, i);
2512        }
2513
2514        for (i = 0; i < ctl->info.n_learners; i++) {
2515                learner_rollfwd(ctl, i);
2516                learner_rollfwd_finalize(ctl, i);
2517        }
2518
2519        return 0;
2520
2521rollback:
2522        for (i = 0; i < ctl->info.n_tables; i++) {
2523                table_rollback(ctl, i);
2524                if (abort_on_fail)
2525                        table_abort(ctl, i);
2526        }
2527
2528        for (i = 0; i < ctl->info.n_selectors; i++) {
2529                selector_rollback(ctl, i);
2530                if (abort_on_fail)
2531                        selector_abort(ctl, i);
2532        }
2533
2534        if (abort_on_fail)
2535                for (i = 0; i < ctl->info.n_learners; i++)
2536                        learner_abort(ctl, i);
2537
2538        return status;
2539}
2540
2541void
2542rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2543{
2544        uint32_t i;
2545
2546        if (!ctl)
2547                return;
2548
2549        for (i = 0; i < ctl->info.n_tables; i++)
2550                table_abort(ctl, i);
2551
2552        for (i = 0; i < ctl->info.n_selectors; i++)
2553                selector_abort(ctl, i);
2554
2555        for (i = 0; i < ctl->info.n_learners; i++)
2556                learner_abort(ctl, i);
2557}
2558
2559static int
2560mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2561{
2562        uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2563
2564        if (!mask) {
2565                *prefix_length = 0;
2566                return 0;
2567        }
2568
2569        /* Count trailing zero bits. */
2570        for (i = 0; i < 64; i++) {
2571                if (mask & (1LLU << i))
2572                        break;
2573
2574                n_trailing_zeros++;
2575        }
2576
2577        /* Count the one bits that follow. */
2578        for ( ; i < 64; i++) {
2579                if (!(mask & (1LLU << i)))
2580                        break;
2581
2582                n_ones++;
2583        }
2584
2585        /* Check that no more one bits are present */
2586        for ( ; i < 64; i++)
2587                if (mask & (1LLU << i))
2588                        return -EINVAL;
2589
2590        /* Check that the input mask is a prefix or the right length. */
2591        if (n_ones + n_trailing_zeros != mask_length)
2592                return -EINVAL;
2593
2594        *prefix_length = n_ones;
2595        return 0;
2596}
2597
2598static int
2599token_is_comment(const char *token)
2600{
2601        if ((token[0] == '#') ||
2602            (token[0] == ';') ||
2603            ((token[0] == '/') && (token[1] == '/')))
2604                return 1; /* TRUE. */
2605
2606        return 0; /* FALSE. */
2607}
2608
2609#define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2610
2611struct rte_swx_table_entry *
2612rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2613                                      const char *table_name,
2614                                      const char *string,
2615                                      int *is_blank_or_comment)
2616{
2617        char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2618        struct table *table;
2619        struct action *action;
2620        struct rte_swx_table_entry *entry = NULL;
2621        char *s0 = NULL, *s;
2622        uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2623        int lpm = 0, blank_or_comment = 0;
2624
2625        /* Check input arguments. */
2626        if (!ctl)
2627                goto error;
2628
2629        if (!table_name || !table_name[0])
2630                goto error;
2631
2632        table = table_find(ctl, table_name);
2633        if (!table)
2634                goto error;
2635
2636        if (!string || !string[0])
2637                goto error;
2638
2639        /* Memory allocation. */
2640        s0 = strdup(string);
2641        if (!s0)
2642                goto error;
2643
2644        entry = table_entry_alloc(table);
2645        if (!entry)
2646                goto error;
2647
2648        /* Parse the string into tokens. */
2649        for (s = s0; ; ) {
2650                char *token;
2651
2652                token = strtok_r(s, " \f\n\r\t\v", &s);
2653                if (!token || token_is_comment(token))
2654                        break;
2655
2656                if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2657                        goto error;
2658
2659                token_array[n_tokens] = token;
2660                n_tokens++;
2661        }
2662
2663        if (!n_tokens) {
2664                blank_or_comment = 1;
2665                goto error;
2666        }
2667
2668        tokens = token_array;
2669
2670        /*
2671         * Match.
2672         */
2673        if (!(n_tokens && !strcmp(tokens[0], "match")))
2674                goto action;
2675
2676        if (n_tokens < 1 + table->info.n_match_fields)
2677                goto error;
2678
2679        for (i = 0; i < table->info.n_match_fields; i++) {
2680                struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2681                char *mf_val = tokens[1 + i], *mf_mask = NULL;
2682                uint64_t val, mask = UINT64_MAX;
2683                uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2684
2685                /*
2686                 * Mask.
2687                 */
2688                mf_mask = strchr(mf_val, '/');
2689                if (mf_mask) {
2690                        *mf_mask = 0;
2691                        mf_mask++;
2692
2693                        /* Parse. */
2694                        mask = strtoull(mf_mask, &mf_mask, 0);
2695                        if (mf_mask[0])
2696                                goto error;
2697
2698                        /* LPM. */
2699                        if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2700                                int status;
2701
2702                                lpm = 1;
2703
2704                                lpm_prefix_length_max = mf->n_bits;
2705
2706                                status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2707                                if (status)
2708                                        goto error;
2709                        }
2710
2711                        /* Endianness conversion. */
2712                        if (mf->is_header)
2713                                mask = field_hton(mask, mf->n_bits);
2714                }
2715
2716                /* Copy to entry. */
2717                if (entry->key_mask)
2718                        memcpy(&entry->key_mask[offset],
2719                               (uint8_t *)&mask,
2720                               mf->n_bits / 8);
2721
2722                /*
2723                 * Value.
2724                 */
2725                /* Parse. */
2726                val = strtoull(mf_val, &mf_val, 0);
2727                if (mf_val[0])
2728                        goto error;
2729
2730                /* Endianness conversion. */
2731                if (mf->is_header)
2732                        val = field_hton(val, mf->n_bits);
2733
2734                /* Copy to entry. */
2735                memcpy(&entry->key[offset],
2736                       (uint8_t *)&val,
2737                       mf->n_bits / 8);
2738        }
2739
2740        tokens += 1 + table->info.n_match_fields;
2741        n_tokens -= 1 + table->info.n_match_fields;
2742
2743        /*
2744         * Match priority.
2745         */
2746        if (n_tokens && !strcmp(tokens[0], "priority")) {
2747                char *priority = tokens[1];
2748                uint32_t val;
2749
2750                if (n_tokens < 2)
2751                        goto error;
2752
2753                /* Parse. */
2754                val = strtoul(priority, &priority, 0);
2755                if (priority[0])
2756                        goto error;
2757
2758                /* Copy to entry. */
2759                entry->key_priority = val;
2760
2761                tokens += 2;
2762                n_tokens -= 2;
2763        }
2764
2765        /* LPM. */
2766        if (lpm)
2767                entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2768
2769        /*
2770         * Action.
2771         */
2772action:
2773        if (!(n_tokens && !strcmp(tokens[0], "action")))
2774                goto other;
2775
2776        if (n_tokens < 2)
2777                goto error;
2778
2779        action = action_find(ctl, tokens[1]);
2780        if (!action)
2781                goto error;
2782
2783        if (n_tokens < 2 + action->info.n_args * 2)
2784                goto error;
2785
2786        /* action_id. */
2787        entry->action_id = action - ctl->actions;
2788
2789        /* action_data. */
2790        for (i = 0; i < action->info.n_args; i++) {
2791                struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2792                char *arg_name, *arg_val;
2793                uint64_t val;
2794
2795                arg_name = tokens[2 + i * 2];
2796                arg_val = tokens[2 + i * 2 + 1];
2797
2798                if (strcmp(arg_name, arg->name))
2799                        goto error;
2800
2801                val = strtoull(arg_val, &arg_val, 0);
2802                if (arg_val[0])
2803                        goto error;
2804
2805                /* Endianness conversion. */
2806                if (arg->is_network_byte_order)
2807                        val = field_hton(val, arg->n_bits);
2808
2809                /* Copy to entry. */
2810                memcpy(&entry->action_data[arg_offset],
2811                       (uint8_t *)&val,
2812                       arg->n_bits / 8);
2813
2814                arg_offset += arg->n_bits / 8;
2815        }
2816
2817        tokens += 2 + action->info.n_args * 2;
2818        n_tokens -= 2 + action->info.n_args * 2;
2819
2820other:
2821        if (n_tokens)
2822                goto error;
2823
2824        free(s0);
2825        return entry;
2826
2827error:
2828        table_entry_free(entry);
2829        free(s0);
2830        if (is_blank_or_comment)
2831                *is_blank_or_comment = blank_or_comment;
2832        return NULL;
2833}
2834
2835struct rte_swx_table_entry *
2836rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2837                                                const char *learner_name,
2838                                                const char *string,
2839                                                int *is_blank_or_comment)
2840{
2841        char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2842        struct learner *l;
2843        struct action *action;
2844        struct rte_swx_table_entry *entry = NULL;
2845        char *s0 = NULL, *s;
2846        uint32_t n_tokens = 0, arg_offset = 0, i;
2847        int blank_or_comment = 0;
2848
2849        /* Check input arguments. */
2850        if (!ctl)
2851                goto error;
2852
2853        if (!learner_name || !learner_name[0])
2854                goto error;
2855
2856        l = learner_find(ctl, learner_name);
2857        if (!l)
2858                goto error;
2859
2860        if (!string || !string[0])
2861                goto error;
2862
2863        /* Memory allocation. */
2864        s0 = strdup(string);
2865        if (!s0)
2866                goto error;
2867
2868        entry = learner_default_entry_alloc(l);
2869        if (!entry)
2870                goto error;
2871
2872        /* Parse the string into tokens. */
2873        for (s = s0; ; ) {
2874                char *token;
2875
2876                token = strtok_r(s, " \f\n\r\t\v", &s);
2877                if (!token || token_is_comment(token))
2878                        break;
2879
2880                if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2881                        goto error;
2882
2883                token_array[n_tokens] = token;
2884                n_tokens++;
2885        }
2886
2887        if (!n_tokens) {
2888                blank_or_comment = 1;
2889                goto error;
2890        }
2891
2892        tokens = token_array;
2893
2894        /*
2895         * Action.
2896         */
2897        if (!(n_tokens && !strcmp(tokens[0], "action")))
2898                goto other;
2899
2900        if (n_tokens < 2)
2901                goto error;
2902
2903        action = action_find(ctl, tokens[1]);
2904        if (!action)
2905                goto error;
2906
2907        if (n_tokens < 2 + action->info.n_args * 2)
2908                goto error;
2909
2910        /* action_id. */
2911        entry->action_id = action - ctl->actions;
2912
2913        /* action_data. */
2914        for (i = 0; i < action->info.n_args; i++) {
2915                struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2916                char *arg_name, *arg_val;
2917                uint64_t val;
2918
2919                arg_name = tokens[2 + i * 2];
2920                arg_val = tokens[2 + i * 2 + 1];
2921
2922                if (strcmp(arg_name, arg->name))
2923                        goto error;
2924
2925                val = strtoull(arg_val, &arg_val, 0);
2926                if (arg_val[0])
2927                        goto error;
2928
2929                /* Endianness conversion. */
2930                if (arg->is_network_byte_order)
2931                        val = field_hton(val, arg->n_bits);
2932
2933                /* Copy to entry. */
2934                memcpy(&entry->action_data[arg_offset],
2935                       (uint8_t *)&val,
2936                       arg->n_bits / 8);
2937
2938                arg_offset += arg->n_bits / 8;
2939        }
2940
2941        tokens += 2 + action->info.n_args * 2;
2942        n_tokens -= 2 + action->info.n_args * 2;
2943
2944other:
2945        if (n_tokens)
2946                goto error;
2947
2948        free(s0);
2949        return entry;
2950
2951error:
2952        table_entry_free(entry);
2953        free(s0);
2954        if (is_blank_or_comment)
2955                *is_blank_or_comment = blank_or_comment;
2956        return NULL;
2957}
2958
2959static void
2960table_entry_printf(FILE *f,
2961                   struct rte_swx_ctl_pipeline *ctl,
2962                   struct table *table,
2963                   struct rte_swx_table_entry *entry)
2964{
2965        struct action *action = &ctl->actions[entry->action_id];
2966        uint32_t i;
2967
2968        fprintf(f, "match ");
2969        for (i = 0; i < table->params.key_size; i++)
2970                fprintf(f, "%02x", entry->key[i]);
2971
2972        if (entry->key_mask) {
2973                fprintf(f, "/");
2974                for (i = 0; i < table->params.key_size; i++)
2975                        fprintf(f, "%02x", entry->key_mask[i]);
2976        }
2977
2978        fprintf(f, " priority %u", entry->key_priority);
2979
2980        fprintf(f, " action %s ", action->info.name);
2981        for (i = 0; i < action->data_size; i++)
2982                fprintf(f, "%02x", entry->action_data[i]);
2983
2984        fprintf(f, "\n");
2985}
2986
2987int
2988rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2989                                   struct rte_swx_ctl_pipeline *ctl,
2990                                   const char *table_name)
2991{
2992        struct table *table;
2993        struct rte_swx_table_entry *entry;
2994        uint32_t n_entries = 0, i;
2995
2996        if (!f || !ctl || !table_name || !table_name[0])
2997                return -EINVAL;
2998
2999        table = table_find(ctl, table_name);
3000        if (!table)
3001                return -EINVAL;
3002
3003        /* Table. */
3004        fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3005                table->info.name,
3006                table->params.key_size,
3007                table->params.key_offset);
3008
3009        for (i = 0; i < table->params.key_size; i++)
3010                fprintf(f, "%02x", table->params.key_mask0[i]);
3011
3012        fprintf(f, "], action data size %u bytes\n",
3013                table->params.action_data_size);
3014
3015        /* Table entries. */
3016        TAILQ_FOREACH(entry, &table->entries, node) {
3017                table_entry_printf(f, ctl, table, entry);
3018                n_entries++;
3019        }
3020
3021        TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3022                table_entry_printf(f, ctl, table, entry);
3023                n_entries++;
3024        }
3025
3026        TAILQ_FOREACH(entry, &table->pending_delete, node) {
3027                table_entry_printf(f, ctl, table, entry);
3028                n_entries++;
3029        }
3030
3031        fprintf(f, "# Table %s currently has %u entries.\n",
3032                table_name,
3033                n_entries);
3034        return 0;
3035}
3036
3037int
3038rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3039                                      struct rte_swx_ctl_pipeline *ctl,
3040                                      const char *selector_name)
3041{
3042        struct selector *s;
3043        uint32_t group_id;
3044
3045        if (!f || !ctl || !selector_name || !selector_name[0])
3046                return -EINVAL;
3047
3048        s = selector_find(ctl, selector_name);
3049        if (!s)
3050                return -EINVAL;
3051
3052        /* Selector. */
3053        fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3054                s->info.name,
3055                s->info.n_groups_max,
3056                s->info.n_members_per_group_max);
3057
3058        /* Groups. */
3059        for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3060                struct rte_swx_table_selector_group *group = s->groups[group_id];
3061                struct rte_swx_table_selector_member *m;
3062                uint32_t n_members = 0;
3063
3064                fprintf(f, "Group %u = [", group_id);
3065
3066                /* Non-empty group. */
3067                if (group)
3068                        TAILQ_FOREACH(m, &group->members, node) {
3069                                fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3070                                n_members++;
3071                        }
3072
3073                /* Empty group. */
3074                if (!n_members)
3075                        fprintf(f, "0:1 ");
3076
3077                fprintf(f, "]\n");
3078        }
3079
3080        return 0;
3081}
3082