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_ctl.h"
  14
  15#define CHECK(condition, err_code)                                             \
  16do {                                                                           \
  17        if (!(condition))                                                      \
  18                return -(err_code);                                            \
  19} while (0)
  20
  21#define ntoh64(x) rte_be_to_cpu_64(x)
  22#define hton64(x) rte_cpu_to_be_64(x)
  23
  24#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
  25#define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
  26#define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
  27#else
  28#define field_ntoh(val, n_bits) (val)
  29#define field_hton(val, n_bits) (val)
  30#endif
  31
  32struct action {
  33        struct rte_swx_ctl_action_info info;
  34        struct rte_swx_ctl_action_arg_info *args;
  35        uint32_t data_size;
  36};
  37
  38struct table {
  39        struct rte_swx_ctl_table_info info;
  40        struct rte_swx_ctl_table_match_field_info *mf;
  41
  42        /* Match field with the smallest offset. */
  43        struct rte_swx_ctl_table_match_field_info *mf_first;
  44
  45        /* Match field with the biggest offset. */
  46        struct rte_swx_ctl_table_match_field_info *mf_last;
  47
  48        struct rte_swx_ctl_table_action_info *actions;
  49        struct rte_swx_table_ops ops;
  50        struct rte_swx_table_params params;
  51
  52        /* Set of "stable" keys: these keys are currently part of the table;
  53         * these keys will be preserved with no action data changes after the
  54         * next commit.
  55         */
  56        struct rte_swx_table_entry_list entries;
  57
  58        /* Set of new keys: these keys are currently NOT part of the table;
  59         * these keys will be added to the table on the next commit, if
  60         * the commit operation is successful.
  61         */
  62        struct rte_swx_table_entry_list pending_add;
  63
  64        /* Set of keys to be modified: these keys are currently part of the
  65         * table; these keys are still going to be part of the table after the
  66         * next commit, but their action data will be modified if the commit
  67         * operation is successful. The modify0 list contains the keys with the
  68         * current action data, the modify1 list contains the keys with the
  69         * modified action data.
  70         */
  71        struct rte_swx_table_entry_list pending_modify0;
  72        struct rte_swx_table_entry_list pending_modify1;
  73
  74        /* Set of keys to be deleted: these keys are currently part of the
  75         * table; these keys are to be deleted from the table on the next
  76         * commit, if the commit operation is successful.
  77         */
  78        struct rte_swx_table_entry_list pending_delete;
  79
  80        /* The pending default action: this is NOT the current default action;
  81         * this will be the new default action after the next commit, if the
  82         * next commit operation is successful.
  83         */
  84        struct rte_swx_table_entry *pending_default;
  85
  86        int is_stub;
  87        uint32_t n_add;
  88        uint32_t n_modify;
  89        uint32_t n_delete;
  90};
  91
  92struct rte_swx_ctl_pipeline {
  93        struct rte_swx_ctl_pipeline_info info;
  94        struct rte_swx_pipeline *p;
  95        struct action *actions;
  96        struct table *tables;
  97        struct rte_swx_table_state *ts;
  98        struct rte_swx_table_state *ts_next;
  99        int numa_node;
 100};
 101
 102static struct action *
 103action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
 104{
 105        uint32_t i;
 106
 107        for (i = 0; i < ctl->info.n_actions; i++) {
 108                struct action *a = &ctl->actions[i];
 109
 110                if (!strcmp(action_name, a->info.name))
 111                        return a;
 112        }
 113
 114        return NULL;
 115}
 116
 117static void
 118action_free(struct rte_swx_ctl_pipeline *ctl)
 119{
 120        uint32_t i;
 121
 122        if (!ctl->actions)
 123                return;
 124
 125        for (i = 0; i < ctl->info.n_actions; i++) {
 126                struct action *action = &ctl->actions[i];
 127
 128                free(action->args);
 129        }
 130
 131        free(ctl->actions);
 132        ctl->actions = NULL;
 133}
 134
 135static struct table *
 136table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
 137{
 138        uint32_t i;
 139
 140        for (i = 0; i < ctl->info.n_tables; i++) {
 141                struct table *table = &ctl->tables[i];
 142
 143                if (!strcmp(table_name, table->info.name))
 144                        return table;
 145        }
 146
 147        return NULL;
 148}
 149
 150static int
 151table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
 152{
 153        struct table *table = &ctl->tables[table_id];
 154        struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
 155        uint8_t *key_mask = NULL;
 156        enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
 157        uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
 158
 159        if (table->info.n_match_fields) {
 160                uint32_t n_match_fields_em = 0, i;
 161
 162                /* Find first (smallest offset) and last (biggest offset) match fields. */
 163                first = &table->mf[0];
 164                last = &table->mf[0];
 165
 166                for (i = 1; i < table->info.n_match_fields; i++) {
 167                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 168
 169                        if (f->offset < first->offset)
 170                                first = f;
 171
 172                        if (f->offset > last->offset)
 173                                last = f;
 174                }
 175
 176                /* match_type. */
 177                for (i = 0; i < table->info.n_match_fields; i++) {
 178                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 179
 180                        if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
 181                                n_match_fields_em++;
 182                }
 183
 184                if (n_match_fields_em == table->info.n_match_fields)
 185                        match_type = RTE_SWX_TABLE_MATCH_EXACT;
 186                else if ((n_match_fields_em == table->info.n_match_fields - 1) &&
 187                         (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
 188                        match_type = RTE_SWX_TABLE_MATCH_LPM;
 189
 190                /* key_offset. */
 191                key_offset = first->offset / 8;
 192
 193                /* key_size. */
 194                key_size = (last->offset + last->n_bits - first->offset) / 8;
 195
 196                /* key_mask. */
 197                key_mask = calloc(1, key_size);
 198                CHECK(key_mask, ENOMEM);
 199
 200                for (i = 0; i < table->info.n_match_fields; i++) {
 201                        struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
 202                        uint32_t start;
 203                        size_t size;
 204
 205                        start = (f->offset - first->offset) / 8;
 206                        size = f->n_bits / 8;
 207
 208                        memset(&key_mask[start], 0xFF, size);
 209                }
 210        }
 211
 212        /* action_data_size. */
 213        for (i = 0; i < table->info.n_actions; i++) {
 214                uint32_t action_id = table->actions[i].action_id;
 215                struct action *a = &ctl->actions[action_id];
 216
 217                if (a->data_size > action_data_size)
 218                        action_data_size = a->data_size;
 219        }
 220
 221        /* Fill in. */
 222        table->params.match_type = match_type;
 223        table->params.key_size = key_size;
 224        table->params.key_offset = key_offset;
 225        table->params.key_mask0 = key_mask;
 226        table->params.action_data_size = action_data_size;
 227        table->params.n_keys_max = table->info.size;
 228
 229        table->mf_first = first;
 230        table->mf_last = last;
 231
 232        return 0;
 233}
 234
 235static void
 236table_entry_free(struct rte_swx_table_entry *entry)
 237{
 238        if (!entry)
 239                return;
 240
 241        free(entry->key);
 242        free(entry->key_mask);
 243        free(entry->action_data);
 244        free(entry);
 245}
 246
 247static struct rte_swx_table_entry *
 248table_entry_alloc(struct table *table)
 249{
 250        struct rte_swx_table_entry *entry;
 251
 252        entry = calloc(1, sizeof(struct rte_swx_table_entry));
 253        if (!entry)
 254                goto error;
 255
 256        /* key, key_mask. */
 257        if (!table->is_stub) {
 258                entry->key = calloc(1, table->params.key_size);
 259                if (!entry->key)
 260                        goto error;
 261
 262                if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
 263                        entry->key_mask = calloc(1, table->params.key_size);
 264                        if (!entry->key_mask)
 265                                goto error;
 266                }
 267        }
 268
 269        /* action_data. */
 270        if (table->params.action_data_size) {
 271                entry->action_data = calloc(1, table->params.action_data_size);
 272                if (!entry->action_data)
 273                        goto error;
 274        }
 275
 276        return entry;
 277
 278error:
 279        table_entry_free(entry);
 280        return NULL;
 281}
 282
 283static int
 284table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
 285{
 286        uint8_t *key_mask0 = table->params.key_mask0;
 287        uint32_t key_size = table->params.key_size, i;
 288
 289        if (!entry->key_mask)
 290                return 0;
 291
 292        for (i = 0; i < key_size; i++) {
 293                uint8_t km0 = key_mask0[i];
 294                uint8_t km = entry->key_mask[i];
 295
 296                if ((km & km0) != km0)
 297                        return -EINVAL;
 298        }
 299
 300        return 0;
 301}
 302
 303static int
 304table_entry_check(struct rte_swx_ctl_pipeline *ctl,
 305                  uint32_t table_id,
 306                  struct rte_swx_table_entry *entry,
 307                  int key_check,
 308                  int data_check)
 309{
 310        struct table *table = &ctl->tables[table_id];
 311        int status;
 312
 313        CHECK(entry, EINVAL);
 314
 315        if (key_check) {
 316                if (table->is_stub) {
 317                        /* key. */
 318                        CHECK(!entry->key, EINVAL);
 319
 320                        /* key_mask. */
 321                        CHECK(!entry->key_mask, EINVAL);
 322                } else {
 323                        /* key. */
 324                        CHECK(entry->key, EINVAL);
 325
 326                        /* key_mask. */
 327                        switch (table->params.match_type) {
 328                        case RTE_SWX_TABLE_MATCH_WILDCARD:
 329                                break;
 330
 331                        case RTE_SWX_TABLE_MATCH_LPM:
 332                                /* TBD Check that key mask is prefix. */
 333                                break;
 334
 335                        case RTE_SWX_TABLE_MATCH_EXACT:
 336                                status = table_entry_key_check_em(table, entry);
 337                                if (status)
 338                                        return status;
 339                                break;
 340
 341                        default:
 342                                CHECK(0, EINVAL);
 343                        }
 344                }
 345        }
 346
 347        if (data_check) {
 348                struct action *a;
 349                uint32_t i;
 350
 351                /* action_id. */
 352                for (i = 0; i < table->info.n_actions; i++)
 353                        if (entry->action_id == table->actions[i].action_id)
 354                                break;
 355
 356                CHECK(i < table->info.n_actions, EINVAL);
 357
 358                /* action_data. */
 359                a = &ctl->actions[entry->action_id];
 360                CHECK(!(a->data_size && !entry->action_data), EINVAL);
 361        }
 362
 363        return 0;
 364}
 365
 366static struct rte_swx_table_entry *
 367table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
 368                      uint32_t table_id,
 369                      struct rte_swx_table_entry *entry,
 370                      int key_duplicate,
 371                      int data_duplicate)
 372{
 373        struct table *table = &ctl->tables[table_id];
 374        struct rte_swx_table_entry *new_entry = NULL;
 375
 376        if (!entry)
 377                goto error;
 378
 379        new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
 380        if (!new_entry)
 381                goto error;
 382
 383        if (key_duplicate && !table->is_stub) {
 384                /* key. */
 385                if (!entry->key)
 386                        goto error;
 387
 388                new_entry->key = malloc(table->params.key_size);
 389                if (!new_entry->key)
 390                        goto error;
 391
 392                memcpy(new_entry->key, entry->key, table->params.key_size);
 393
 394                /* key_signature. */
 395                new_entry->key_signature = entry->key_signature;
 396
 397                /* key_mask. */
 398                if (entry->key_mask) {
 399                        new_entry->key_mask = malloc(table->params.key_size);
 400                        if (!new_entry->key_mask)
 401                                goto error;
 402
 403                        memcpy(new_entry->key_mask,
 404                               entry->key_mask,
 405                               table->params.key_size);
 406                }
 407
 408                /* key_priority. */
 409                new_entry->key_priority = entry->key_priority;
 410        }
 411
 412        if (data_duplicate) {
 413                struct action *a;
 414                uint32_t i;
 415
 416                /* action_id. */
 417                for (i = 0; i < table->info.n_actions; i++)
 418                        if (entry->action_id == table->actions[i].action_id)
 419                                break;
 420
 421                if (i >= table->info.n_actions)
 422                        goto error;
 423
 424                new_entry->action_id = entry->action_id;
 425
 426                /* action_data. */
 427                a = &ctl->actions[entry->action_id];
 428                if (a->data_size && !entry->action_data)
 429                        goto error;
 430
 431                /* The table layer provisions a constant action data size per
 432                 * entry, which should be the largest data size for all the
 433                 * actions enabled for the current table, and attempts to copy
 434                 * this many bytes each time a table entry is added, even if the
 435                 * specific action requires less data or even no data at all,
 436                 * hence we always have to allocate the max.
 437                 */
 438                new_entry->action_data = calloc(1, table->params.action_data_size);
 439                if (!new_entry->action_data)
 440                        goto error;
 441
 442                if (a->data_size)
 443                        memcpy(new_entry->action_data,
 444                               entry->action_data,
 445                               a->data_size);
 446        }
 447
 448        return new_entry;
 449
 450error:
 451        table_entry_free(new_entry);
 452        return NULL;
 453}
 454
 455static int
 456table_entry_keycmp(struct table *table,
 457                   struct rte_swx_table_entry *e0,
 458                   struct rte_swx_table_entry *e1)
 459{
 460        uint32_t key_size = table->params.key_size;
 461        uint32_t i;
 462
 463        for (i = 0; i < key_size; i++) {
 464                uint8_t *key_mask0 = table->params.key_mask0;
 465                uint8_t km0, km[2], k[2];
 466
 467                km0 = key_mask0 ? key_mask0[i] : 0xFF;
 468
 469                km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
 470                km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
 471
 472                k[0] = e0->key[i];
 473                k[1] = e1->key[i];
 474
 475                /* Mask comparison. */
 476                if ((km[0] & km0) != (km[1] & km0))
 477                        return 1; /* Not equal. */
 478
 479                /* Value comparison. */
 480                if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
 481                        return 1; /* Not equal. */
 482        }
 483
 484        return 0; /* Equal. */
 485}
 486
 487static struct rte_swx_table_entry *
 488table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
 489{
 490        struct rte_swx_table_entry *e;
 491
 492        TAILQ_FOREACH(e, &table->entries, node)
 493                if (!table_entry_keycmp(table, entry, e))
 494                        return e; /* Found. */
 495
 496        return NULL; /* Not found. */
 497}
 498
 499static void
 500table_entries_free(struct table *table)
 501{
 502        for ( ; ; ) {
 503                struct rte_swx_table_entry *entry;
 504
 505                entry = TAILQ_FIRST(&table->entries);
 506                if (!entry)
 507                        break;
 508
 509                TAILQ_REMOVE(&table->entries, entry, node);
 510                table_entry_free(entry);
 511        }
 512}
 513
 514static struct rte_swx_table_entry *
 515table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
 516{
 517        struct rte_swx_table_entry *e;
 518
 519        TAILQ_FOREACH(e, &table->pending_add, node)
 520                if (!table_entry_keycmp(table, entry, e))
 521                        return e; /* Found. */
 522
 523        return NULL; /* Not found. */
 524}
 525
 526static void
 527table_pending_add_admit(struct table *table)
 528{
 529        TAILQ_CONCAT(&table->entries, &table->pending_add, node);
 530}
 531
 532static void
 533table_pending_add_free(struct table *table)
 534{
 535        for ( ; ; ) {
 536                struct rte_swx_table_entry *entry;
 537
 538                entry = TAILQ_FIRST(&table->pending_add);
 539                if (!entry)
 540                        break;
 541
 542                TAILQ_REMOVE(&table->pending_add, entry, node);
 543                table_entry_free(entry);
 544        }
 545}
 546
 547static struct rte_swx_table_entry *
 548table_pending_modify0_find(struct table *table,
 549                           struct rte_swx_table_entry *entry)
 550{
 551        struct rte_swx_table_entry *e;
 552
 553        TAILQ_FOREACH(e, &table->pending_modify0, node)
 554                if (!table_entry_keycmp(table, entry, e))
 555                        return e; /* Found. */
 556
 557        return NULL; /* Not found. */
 558}
 559
 560static void
 561table_pending_modify0_admit(struct table *table)
 562{
 563        TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
 564}
 565
 566static void
 567table_pending_modify0_free(struct table *table)
 568{
 569        for ( ; ; ) {
 570                struct rte_swx_table_entry *entry;
 571
 572                entry = TAILQ_FIRST(&table->pending_modify0);
 573                if (!entry)
 574                        break;
 575
 576                TAILQ_REMOVE(&table->pending_modify0, entry, node);
 577                table_entry_free(entry);
 578        }
 579}
 580
 581static struct rte_swx_table_entry *
 582table_pending_modify1_find(struct table *table,
 583                           struct rte_swx_table_entry *entry)
 584{
 585        struct rte_swx_table_entry *e;
 586
 587        TAILQ_FOREACH(e, &table->pending_modify1, node)
 588                if (!table_entry_keycmp(table, entry, e))
 589                        return e; /* Found. */
 590
 591        return NULL; /* Not found. */
 592}
 593
 594static void
 595table_pending_modify1_admit(struct table *table)
 596{
 597        TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
 598}
 599
 600static void
 601table_pending_modify1_free(struct table *table)
 602{
 603        for ( ; ; ) {
 604                struct rte_swx_table_entry *entry;
 605
 606                entry = TAILQ_FIRST(&table->pending_modify1);
 607                if (!entry)
 608                        break;
 609
 610                TAILQ_REMOVE(&table->pending_modify1, entry, node);
 611                table_entry_free(entry);
 612        }
 613}
 614
 615static struct rte_swx_table_entry *
 616table_pending_delete_find(struct table *table,
 617                          struct rte_swx_table_entry *entry)
 618{
 619        struct rte_swx_table_entry *e;
 620
 621        TAILQ_FOREACH(e, &table->pending_delete, node)
 622                if (!table_entry_keycmp(table, entry, e))
 623                        return e; /* Found. */
 624
 625        return NULL; /* Not found. */
 626}
 627
 628static void
 629table_pending_delete_admit(struct table *table)
 630{
 631        TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
 632}
 633
 634static void
 635table_pending_delete_free(struct table *table)
 636{
 637        for ( ; ; ) {
 638                struct rte_swx_table_entry *entry;
 639
 640                entry = TAILQ_FIRST(&table->pending_delete);
 641                if (!entry)
 642                        break;
 643
 644                TAILQ_REMOVE(&table->pending_delete, entry, node);
 645                table_entry_free(entry);
 646        }
 647}
 648
 649static void
 650table_pending_default_free(struct table *table)
 651{
 652        if (!table->pending_default)
 653                return;
 654
 655        free(table->pending_default->action_data);
 656        free(table->pending_default);
 657        table->pending_default = NULL;
 658}
 659
 660static int
 661table_is_update_pending(struct table *table, int consider_pending_default)
 662{
 663        struct rte_swx_table_entry *e;
 664        uint32_t n = 0;
 665
 666        /* Pending add. */
 667        TAILQ_FOREACH(e, &table->pending_add, node)
 668                n++;
 669
 670        /* Pending modify. */
 671        TAILQ_FOREACH(e, &table->pending_modify1, node)
 672                n++;
 673
 674        /* Pending delete. */
 675        TAILQ_FOREACH(e, &table->pending_delete, node)
 676                n++;
 677
 678        /* Pending default. */
 679        if (consider_pending_default && table->pending_default)
 680                n++;
 681
 682        return n;
 683}
 684
 685static void
 686table_free(struct rte_swx_ctl_pipeline *ctl)
 687{
 688        uint32_t i;
 689
 690        if (!ctl->tables)
 691                return;
 692
 693        for (i = 0; i < ctl->info.n_tables; i++) {
 694                struct table *table = &ctl->tables[i];
 695
 696                free(table->mf);
 697                free(table->actions);
 698                free(table->params.key_mask0);
 699
 700                table_entries_free(table);
 701                table_pending_add_free(table);
 702                table_pending_modify0_free(table);
 703                table_pending_modify1_free(table);
 704                table_pending_delete_free(table);
 705                table_pending_default_free(table);
 706        }
 707
 708        free(ctl->tables);
 709        ctl->tables = NULL;
 710}
 711
 712static void
 713table_state_free(struct rte_swx_ctl_pipeline *ctl)
 714{
 715        uint32_t i;
 716
 717        if (!ctl->ts_next)
 718                return;
 719
 720        /* For each table, free its table state. */
 721        for (i = 0; i < ctl->info.n_tables; i++) {
 722                struct table *table = &ctl->tables[i];
 723                struct rte_swx_table_state *ts = &ctl->ts_next[i];
 724
 725                /* Default action data. */
 726                free(ts->default_action_data);
 727
 728                /* Table object. */
 729                if (!table->is_stub && table->ops.free && ts->obj)
 730                        table->ops.free(ts->obj);
 731        }
 732
 733        free(ctl->ts_next);
 734        ctl->ts_next = NULL;
 735}
 736
 737static int
 738table_state_create(struct rte_swx_ctl_pipeline *ctl)
 739{
 740        int status = 0;
 741        uint32_t i;
 742
 743        ctl->ts_next = calloc(ctl->info.n_tables,
 744                              sizeof(struct rte_swx_table_state));
 745        if (!ctl->ts_next) {
 746                status = -ENOMEM;
 747                goto error;
 748        }
 749
 750        for (i = 0; i < ctl->info.n_tables; i++) {
 751                struct table *table = &ctl->tables[i];
 752                struct rte_swx_table_state *ts = &ctl->ts[i];
 753                struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
 754
 755                /* Table object. */
 756                if (!table->is_stub && table->ops.add) {
 757                        ts_next->obj = table->ops.create(&table->params,
 758                                                         &table->entries,
 759                                                         table->info.args,
 760                                                         ctl->numa_node);
 761                        if (!ts_next->obj) {
 762                                status = -ENODEV;
 763                                goto error;
 764                        }
 765                }
 766
 767                if (!table->is_stub && !table->ops.add)
 768                        ts_next->obj = ts->obj;
 769
 770                /* Default action data: duplicate from current table state. */
 771                ts_next->default_action_data =
 772                        malloc(table->params.action_data_size);
 773                if (!ts_next->default_action_data) {
 774                        status = -ENOMEM;
 775                        goto error;
 776                }
 777
 778                memcpy(ts_next->default_action_data,
 779                       ts->default_action_data,
 780                       table->params.action_data_size);
 781
 782                ts_next->default_action_id = ts->default_action_id;
 783        }
 784
 785        return 0;
 786
 787error:
 788        table_state_free(ctl);
 789        return status;
 790}
 791
 792void
 793rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
 794{
 795        if (!ctl)
 796                return;
 797
 798        action_free(ctl);
 799
 800        table_state_free(ctl);
 801
 802        table_free(ctl);
 803
 804        free(ctl);
 805}
 806
 807struct rte_swx_ctl_pipeline *
 808rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
 809{
 810        struct rte_swx_ctl_pipeline *ctl = NULL;
 811        uint32_t i;
 812        int status;
 813
 814        if (!p)
 815                goto error;
 816
 817        ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
 818        if (!ctl)
 819                goto error;
 820
 821        /* info. */
 822        status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
 823        if (status)
 824                goto error;
 825
 826        /* numa_node. */
 827        status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
 828        if (status)
 829                goto error;
 830
 831        /* p. */
 832        ctl->p = p;
 833
 834        /* actions. */
 835        ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
 836        if (!ctl->actions)
 837                goto error;
 838
 839        for (i = 0; i < ctl->info.n_actions; i++) {
 840                struct action *a = &ctl->actions[i];
 841                uint32_t j;
 842
 843                /* info. */
 844                status = rte_swx_ctl_action_info_get(p, i, &a->info);
 845                if (status)
 846                        goto error;
 847
 848                /* args. */
 849                a->args = calloc(a->info.n_args,
 850                                 sizeof(struct rte_swx_ctl_action_arg_info));
 851                if (!a->args)
 852                        goto error;
 853
 854                for (j = 0; j < a->info.n_args; j++) {
 855                        status = rte_swx_ctl_action_arg_info_get(p,
 856                                                                 i,
 857                                                                 j,
 858                                                                 &a->args[j]);
 859                        if (status)
 860                                goto error;
 861                }
 862
 863                /* data_size. */
 864                for (j = 0; j < a->info.n_args; j++) {
 865                        struct rte_swx_ctl_action_arg_info *info = &a->args[j];
 866
 867                        a->data_size += info->n_bits;
 868                }
 869
 870                a->data_size = (a->data_size + 7) / 8;
 871        }
 872
 873        /* tables. */
 874        ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
 875        if (!ctl->tables)
 876                goto error;
 877
 878        for (i = 0; i < ctl->info.n_tables; i++) {
 879                struct table *t = &ctl->tables[i];
 880
 881                TAILQ_INIT(&t->entries);
 882                TAILQ_INIT(&t->pending_add);
 883                TAILQ_INIT(&t->pending_modify0);
 884                TAILQ_INIT(&t->pending_modify1);
 885                TAILQ_INIT(&t->pending_delete);
 886        }
 887
 888        for (i = 0; i < ctl->info.n_tables; i++) {
 889                struct table *t = &ctl->tables[i];
 890                uint32_t j;
 891
 892                /* info. */
 893                status = rte_swx_ctl_table_info_get(p, i, &t->info);
 894                if (status)
 895                        goto error;
 896
 897                /* mf. */
 898                t->mf = calloc(t->info.n_match_fields,
 899                        sizeof(struct rte_swx_ctl_table_match_field_info));
 900                if (!t->mf)
 901                        goto error;
 902
 903                for (j = 0; j < t->info.n_match_fields; j++) {
 904                        status = rte_swx_ctl_table_match_field_info_get(p,
 905                                i,
 906                                j,
 907                                &t->mf[j]);
 908                        if (status)
 909                                goto error;
 910                }
 911
 912                /* actions. */
 913                t->actions = calloc(t->info.n_actions,
 914                        sizeof(struct rte_swx_ctl_table_action_info));
 915                if (!t->actions)
 916                        goto error;
 917
 918                for (j = 0; j < t->info.n_actions; j++) {
 919                        status = rte_swx_ctl_table_action_info_get(p,
 920                                i,
 921                                j,
 922                                &t->actions[j]);
 923                        if (status ||
 924                            t->actions[j].action_id >= ctl->info.n_actions)
 925                                goto error;
 926                }
 927
 928                /* ops, is_stub. */
 929                status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
 930                if (status)
 931                        goto error;
 932
 933                if ((t->is_stub && t->info.n_match_fields) ||
 934                    (!t->is_stub && !t->info.n_match_fields))
 935                        goto error;
 936
 937                /* params. */
 938                status = table_params_get(ctl, i);
 939                if (status)
 940                        goto error;
 941        }
 942
 943        /* ts. */
 944        status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
 945        if (status)
 946                goto error;
 947
 948        /* ts_next. */
 949        status = table_state_create(ctl);
 950        if (status)
 951                goto error;
 952
 953        return ctl;
 954
 955error:
 956        rte_swx_ctl_pipeline_free(ctl);
 957        return NULL;
 958}
 959
 960int
 961rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
 962                                     const char *table_name,
 963                                     struct rte_swx_table_entry *entry)
 964{
 965        struct table *table;
 966        struct rte_swx_table_entry *new_entry, *existing_entry;
 967        uint32_t table_id;
 968
 969        CHECK(ctl, EINVAL);
 970        CHECK(table_name && table_name[0], EINVAL);
 971
 972        table = table_find(ctl, table_name);
 973        CHECK(table, EINVAL);
 974        table_id = table - ctl->tables;
 975
 976        CHECK(entry, EINVAL);
 977        CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
 978
 979        new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
 980        CHECK(new_entry, ENOMEM);
 981
 982        /* The new entry is found in the table->entries list:
 983         * - Add the new entry to the table->pending_modify1 list;
 984         * - Move the existing entry from the table->entries list to the
 985         *   table->pending_modify0 list.
 986         */
 987        existing_entry = table_entries_find(table, entry);
 988        if (existing_entry) {
 989                TAILQ_INSERT_TAIL(&table->pending_modify1,
 990                                  new_entry,
 991                                  node);
 992
 993                TAILQ_REMOVE(&table->entries,
 994                             existing_entry,
 995                             node);
 996
 997                TAILQ_INSERT_TAIL(&table->pending_modify0,
 998                                  existing_entry,
 999                                  node);
1000
1001                return 0;
1002        }
1003
1004        /* The new entry is found in the table->pending_add list:
1005         * - Replace the entry in the table->pending_add list with the new entry
1006         *   (and free the replaced entry).
1007         */
1008        existing_entry = table_pending_add_find(table, entry);
1009        if (existing_entry) {
1010                TAILQ_INSERT_AFTER(&table->pending_add,
1011                                   existing_entry,
1012                                   new_entry,
1013                                   node);
1014
1015                TAILQ_REMOVE(&table->pending_add,
1016                             existing_entry,
1017                             node);
1018
1019                table_entry_free(existing_entry);
1020
1021                return 0;
1022        }
1023
1024        /* The new entry is found in the table->pending_modify1 list:
1025         * - Replace the entry in the table->pending_modify1 list with the new
1026         *   entry (and free the replaced entry).
1027         */
1028        existing_entry = table_pending_modify1_find(table, entry);
1029        if (existing_entry) {
1030                TAILQ_INSERT_AFTER(&table->pending_modify1,
1031                                   existing_entry,
1032                                   new_entry,
1033                                   node);
1034
1035                TAILQ_REMOVE(&table->pending_modify1,
1036                             existing_entry,
1037                             node);
1038
1039                table_entry_free(existing_entry);
1040
1041                return 0;
1042        }
1043
1044        /* The new entry is found in the table->pending_delete list:
1045         * - Add the new entry to the table->pending_modify1 list;
1046         * - Move the existing entry from the table->pending_delete list to the
1047         *   table->pending_modify0 list.
1048         */
1049        existing_entry = table_pending_delete_find(table, entry);
1050        if (existing_entry) {
1051                TAILQ_INSERT_TAIL(&table->pending_modify1,
1052                                  new_entry,
1053                                  node);
1054
1055                TAILQ_REMOVE(&table->pending_delete,
1056                             existing_entry,
1057                             node);
1058
1059                TAILQ_INSERT_TAIL(&table->pending_modify0,
1060                                  existing_entry,
1061                                  node);
1062
1063                return 0;
1064        }
1065
1066        /* The new entry is not found in any of the above lists:
1067         * - Add the new entry to the table->pending_add list.
1068         */
1069        TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1070
1071        return 0;
1072}
1073
1074int
1075rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1076                                        const char *table_name,
1077                                        struct rte_swx_table_entry *entry)
1078{
1079        struct table *table;
1080        struct rte_swx_table_entry *existing_entry;
1081        uint32_t table_id;
1082
1083        CHECK(ctl, EINVAL);
1084
1085        CHECK(table_name && table_name[0], EINVAL);
1086        table = table_find(ctl, table_name);
1087        CHECK(table, EINVAL);
1088        table_id = table - ctl->tables;
1089
1090        CHECK(entry, EINVAL);
1091        CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1092
1093        /* The entry is found in the table->entries list:
1094         * - Move the existing entry from the table->entries list to to the
1095         *   table->pending_delete list.
1096         */
1097        existing_entry = table_entries_find(table, entry);
1098        if (existing_entry) {
1099                TAILQ_REMOVE(&table->entries,
1100                             existing_entry,
1101                             node);
1102
1103                TAILQ_INSERT_TAIL(&table->pending_delete,
1104                                  existing_entry,
1105                                  node);
1106
1107                return 0;
1108        }
1109
1110        /* The entry is found in the table->pending_add list:
1111         * - Remove the entry from the table->pending_add list and free it.
1112         */
1113        existing_entry = table_pending_add_find(table, entry);
1114        if (existing_entry) {
1115                TAILQ_REMOVE(&table->pending_add,
1116                             existing_entry,
1117                             node);
1118
1119                table_entry_free(existing_entry);
1120        }
1121
1122        /* The entry is found in the table->pending_modify1 list:
1123         * - Free the entry in the table->pending_modify1 list;
1124         * - Move the existing entry from the table->pending_modify0 list to the
1125         *   table->pending_delete list.
1126         */
1127        existing_entry = table_pending_modify1_find(table, entry);
1128        if (existing_entry) {
1129                struct rte_swx_table_entry *real_existing_entry;
1130
1131                TAILQ_REMOVE(&table->pending_modify1,
1132                             existing_entry,
1133                             node);
1134
1135                table_entry_free(existing_entry);
1136
1137                real_existing_entry = table_pending_modify0_find(table, entry);
1138                CHECK(real_existing_entry, EINVAL); /* Coverity. */
1139
1140                TAILQ_REMOVE(&table->pending_modify0,
1141                             real_existing_entry,
1142                             node);
1143
1144                TAILQ_INSERT_TAIL(&table->pending_delete,
1145                                  real_existing_entry,
1146                                  node);
1147
1148                return 0;
1149        }
1150
1151        /* The entry is found in the table->pending_delete list:
1152         * - Do nothing: the existing entry is already in the
1153         *   table->pending_delete list, i.e. already marked for delete, so
1154         *   simply keep it there as it is.
1155         */
1156
1157        /* The entry is not found in any of the above lists:
1158         * - Do nothing: no existing entry to delete.
1159         */
1160
1161        return 0;
1162}
1163
1164int
1165rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1166                                             const char *table_name,
1167                                             struct rte_swx_table_entry *entry)
1168{
1169        struct table *table;
1170        struct rte_swx_table_entry *new_entry;
1171        uint32_t table_id;
1172
1173        CHECK(ctl, EINVAL);
1174
1175        CHECK(table_name && table_name[0], EINVAL);
1176        table = table_find(ctl, table_name);
1177        CHECK(table, EINVAL);
1178        table_id = table - ctl->tables;
1179        CHECK(!table->info.default_action_is_const, EINVAL);
1180
1181        CHECK(entry, EINVAL);
1182        CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1183
1184        new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1185        CHECK(new_entry, ENOMEM);
1186
1187        table_pending_default_free(table);
1188
1189        table->pending_default = new_entry;
1190        return 0;
1191}
1192
1193
1194static void
1195table_entry_list_free(struct rte_swx_table_entry_list *list)
1196{
1197        for ( ; ; ) {
1198                struct rte_swx_table_entry *entry;
1199
1200                entry = TAILQ_FIRST(list);
1201                if (!entry)
1202                        break;
1203
1204                TAILQ_REMOVE(list, entry, node);
1205                table_entry_free(entry);
1206        }
1207}
1208
1209static int
1210table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1211                           uint32_t table_id,
1212                           struct rte_swx_table_entry_list *dst,
1213                           struct rte_swx_table_entry_list *src)
1214{
1215        struct rte_swx_table_entry *src_entry;
1216
1217        TAILQ_FOREACH(src_entry, src, node) {
1218                struct rte_swx_table_entry *dst_entry;
1219
1220                dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1221                if (!dst_entry)
1222                        goto error;
1223
1224                TAILQ_INSERT_TAIL(dst, dst_entry, node);
1225        }
1226
1227        return 0;
1228
1229error:
1230        table_entry_list_free(dst);
1231        return -ENOMEM;
1232}
1233
1234/* This commit stage contains all the operations that can fail; in case ANY of
1235 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1236 */
1237static int
1238table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1239               uint32_t table_id,
1240               uint32_t after_swap)
1241{
1242        struct table *table = &ctl->tables[table_id];
1243        struct rte_swx_table_state *ts = &ctl->ts[table_id];
1244        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1245
1246        if (table->is_stub || !table_is_update_pending(table, 0))
1247                return 0;
1248
1249        /*
1250         * Current table supports incremental update.
1251         */
1252        if (table->ops.add) {
1253                /* Reset counters. */
1254                table->n_add = 0;
1255                table->n_modify = 0;
1256                table->n_delete = 0;
1257
1258                /* Add pending rules. */
1259                struct rte_swx_table_entry *entry;
1260
1261                TAILQ_FOREACH(entry, &table->pending_add, node) {
1262                        int status;
1263
1264                        status = table->ops.add(ts_next->obj, entry);
1265                        if (status)
1266                                return status;
1267
1268                        table->n_add++;
1269                }
1270
1271                /* Modify pending rules. */
1272                TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1273                        int status;
1274
1275                        status = table->ops.add(ts_next->obj, entry);
1276                        if (status)
1277                                return status;
1278
1279                        table->n_modify++;
1280                }
1281
1282                /* Delete pending rules. */
1283                TAILQ_FOREACH(entry, &table->pending_delete, node) {
1284                        int status;
1285
1286                        status = table->ops.del(ts_next->obj, entry);
1287                        if (status)
1288                                return status;
1289
1290                        table->n_delete++;
1291                }
1292
1293                return 0;
1294        }
1295
1296        /*
1297         * Current table does NOT support incremental update.
1298         */
1299        if (!after_swap) {
1300                struct rte_swx_table_entry_list list;
1301                int status;
1302
1303                /* Create updated list of entries included. */
1304                TAILQ_INIT(&list);
1305
1306                status = table_entry_list_duplicate(ctl,
1307                                                    table_id,
1308                                                    &list,
1309                                                    &table->entries);
1310                if (status)
1311                        goto error;
1312
1313                status = table_entry_list_duplicate(ctl,
1314                                                    table_id,
1315                                                    &list,
1316                                                    &table->pending_add);
1317                if (status)
1318                        goto error;
1319
1320                status = table_entry_list_duplicate(ctl,
1321                                                    table_id,
1322                                                    &list,
1323                                                    &table->pending_modify1);
1324                if (status)
1325                        goto error;
1326
1327                /* Create new table object with the updates included. */
1328                ts_next->obj = table->ops.create(&table->params,
1329                                                 &list,
1330                                                 table->info.args,
1331                                                 ctl->numa_node);
1332                if (!ts_next->obj) {
1333                        status = -ENODEV;
1334                        goto error;
1335                }
1336
1337                table_entry_list_free(&list);
1338
1339                return 0;
1340
1341error:
1342                table_entry_list_free(&list);
1343                return status;
1344        }
1345
1346        /* Free the old table object. */
1347        if (ts_next->obj && table->ops.free)
1348                table->ops.free(ts_next->obj);
1349
1350        /* Copy over the new table object. */
1351        ts_next->obj = ts->obj;
1352
1353        return 0;
1354}
1355
1356/* This commit stage contains all the operations that cannot fail. They are
1357 * executed only if the previous stage was successful for ALL the tables. Hence,
1358 * none of these operations has to be rolled back for ANY table.
1359 */
1360static void
1361table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1362{
1363        struct table *table = &ctl->tables[table_id];
1364        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1365        struct action *a;
1366        uint8_t *action_data;
1367        uint64_t action_id;
1368
1369        /* Copy the pending default entry. */
1370        if (!table->pending_default)
1371                return;
1372
1373        action_id = table->pending_default->action_id;
1374        action_data = table->pending_default->action_data;
1375        a = &ctl->actions[action_id];
1376
1377        memcpy(ts_next->default_action_data,
1378               action_data,
1379               a->data_size);
1380
1381        ts_next->default_action_id = action_id;
1382}
1383
1384/* This last commit stage is simply finalizing a successful commit operation.
1385 * This stage is only executed if all the previous stages were successful. This
1386 * stage cannot fail.
1387 */
1388static void
1389table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1390{
1391        struct table *table = &ctl->tables[table_id];
1392
1393        /* Move all the pending add entries to the table, as they are now part
1394         * of the table.
1395         */
1396        table_pending_add_admit(table);
1397
1398        /* Move all the pending modify1 entries to table, are they are now part
1399         * of the table. Free up all the pending modify0 entries, as they are no
1400         * longer part of the table.
1401         */
1402        table_pending_modify1_admit(table);
1403        table_pending_modify0_free(table);
1404
1405        /* Free up all the pending delete entries, as they are no longer part of
1406         * the table.
1407         */
1408        table_pending_delete_free(table);
1409
1410        /* Free up the pending default entry, as it is now part of the table. */
1411        table_pending_default_free(table);
1412}
1413
1414/* The rollback stage is only executed when the commit failed, i.e. ANY of the
1415 * commit operations that can fail did fail for ANY table. It reverts ALL the
1416 * tables to their state before the commit started, as if the commit never
1417 * happened.
1418 */
1419static void
1420table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1421{
1422        struct table *table = &ctl->tables[table_id];
1423        struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1424
1425        if (table->is_stub || !table_is_update_pending(table, 0))
1426                return;
1427
1428        if (table->ops.add) {
1429                struct rte_swx_table_entry *entry;
1430
1431                /* Add back all the entries that were just deleted. */
1432                TAILQ_FOREACH(entry, &table->pending_delete, node) {
1433                        if (!table->n_delete)
1434                                break;
1435
1436                        table->ops.add(ts_next->obj, entry);
1437                        table->n_delete--;
1438                }
1439
1440                /* Add back the old copy for all the entries that were just
1441                 * modified.
1442                 */
1443                TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1444                        if (!table->n_modify)
1445                                break;
1446
1447                        table->ops.add(ts_next->obj, entry);
1448                        table->n_modify--;
1449                }
1450
1451                /* Delete all the entries that were just added. */
1452                TAILQ_FOREACH(entry, &table->pending_add, node) {
1453                        if (!table->n_add)
1454                                break;
1455
1456                        table->ops.del(ts_next->obj, entry);
1457                        table->n_add--;
1458                }
1459        } else {
1460                struct rte_swx_table_state *ts = &ctl->ts[table_id];
1461
1462                /* Free the new table object, as update was cancelled. */
1463                if (ts_next->obj && table->ops.free)
1464                        table->ops.free(ts_next->obj);
1465
1466                /* Reinstate the old table object. */
1467                ts_next->obj = ts->obj;
1468        }
1469}
1470
1471/* This stage is conditionally executed (as instructed by the user) after a
1472 * failed commit operation to remove ALL the pending work for ALL the tables.
1473 */
1474static void
1475table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1476{
1477        struct table *table = &ctl->tables[table_id];
1478
1479        /* Free up all the pending add entries, as none of them is part of the
1480         * table.
1481         */
1482        table_pending_add_free(table);
1483
1484        /* Free up all the pending modify1 entries, as none of them made it to
1485         * the table. Add back all the pending modify0 entries, as none of them
1486         * was deleted from the table.
1487         */
1488        table_pending_modify1_free(table);
1489        table_pending_modify0_admit(table);
1490
1491        /* Add back all the pending delete entries, as none of them was deleted
1492         * from the table.
1493         */
1494        table_pending_delete_admit(table);
1495
1496        /* Free up the pending default entry, as it is no longer going to be
1497         * added to the table.
1498         */
1499        table_pending_default_free(table);
1500}
1501
1502int
1503rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1504{
1505        struct rte_swx_table_state *ts;
1506        int status = 0;
1507        uint32_t i;
1508
1509        CHECK(ctl, EINVAL);
1510
1511        /* Operate the changes on the current ts_next before it becomes the new
1512         * ts.
1513         */
1514        for (i = 0; i < ctl->info.n_tables; i++) {
1515                status = table_rollfwd0(ctl, i, 0);
1516                if (status)
1517                        goto rollback;
1518        }
1519
1520        for (i = 0; i < ctl->info.n_tables; i++)
1521                table_rollfwd1(ctl, i);
1522
1523        /* Swap the table state for the data plane. The current ts and ts_next
1524         * become the new ts_next and ts, respectively.
1525         */
1526        rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1527        usleep(100);
1528        ts = ctl->ts;
1529        ctl->ts = ctl->ts_next;
1530        ctl->ts_next = ts;
1531
1532        /* Operate the changes on the current ts_next, which is the previous ts.
1533         */
1534        for (i = 0; i < ctl->info.n_tables; i++) {
1535                table_rollfwd0(ctl, i, 1);
1536                table_rollfwd1(ctl, i);
1537                table_rollfwd2(ctl, i);
1538        }
1539
1540        return 0;
1541
1542rollback:
1543        for (i = 0; i < ctl->info.n_tables; i++) {
1544                table_rollback(ctl, i);
1545                if (abort_on_fail)
1546                        table_abort(ctl, i);
1547        }
1548
1549        return status;
1550}
1551
1552void
1553rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1554{
1555        uint32_t i;
1556
1557        if (!ctl)
1558                return;
1559
1560        for (i = 0; i < ctl->info.n_tables; i++)
1561                table_abort(ctl, i);
1562}
1563
1564static int
1565token_is_comment(const char *token)
1566{
1567        if ((token[0] == '#') ||
1568            (token[0] == ';') ||
1569            ((token[0] == '/') && (token[1] == '/')))
1570                return 1; /* TRUE. */
1571
1572        return 0; /* FALSE. */
1573}
1574
1575#define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1576
1577struct rte_swx_table_entry *
1578rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1579                                      const char *table_name,
1580                                      const char *string,
1581                                      int *is_blank_or_comment)
1582{
1583        char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1584        struct table *table;
1585        struct action *action;
1586        struct rte_swx_table_entry *entry = NULL;
1587        char *s0 = NULL, *s;
1588        uint32_t n_tokens = 0, arg_offset = 0, i;
1589        int blank_or_comment = 0;
1590
1591        /* Check input arguments. */
1592        if (!ctl)
1593                goto error;
1594
1595        if (!table_name || !table_name[0])
1596                goto error;
1597
1598        table = table_find(ctl, table_name);
1599        if (!table)
1600                goto error;
1601
1602        if (!string || !string[0])
1603                goto error;
1604
1605        /* Memory allocation. */
1606        s0 = strdup(string);
1607        if (!s0)
1608                goto error;
1609
1610        entry = table_entry_alloc(table);
1611        if (!entry)
1612                goto error;
1613
1614        /* Parse the string into tokens. */
1615        for (s = s0; ; ) {
1616                char *token;
1617
1618                token = strtok_r(s, " \f\n\r\t\v", &s);
1619                if (!token || token_is_comment(token))
1620                        break;
1621
1622                if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1623                        goto error;
1624
1625                token_array[n_tokens] = token;
1626                n_tokens++;
1627        }
1628
1629        if (!n_tokens) {
1630                blank_or_comment = 1;
1631                goto error;
1632        }
1633
1634        tokens = token_array;
1635
1636        /*
1637         * Match.
1638         */
1639        if (n_tokens && strcmp(tokens[0], "match"))
1640                goto action;
1641
1642        if (n_tokens < 1 + table->info.n_match_fields)
1643                goto error;
1644
1645        for (i = 0; i < table->info.n_match_fields; i++) {
1646                struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1647                char *mf_val = tokens[1 + i], *mf_mask = NULL;
1648                uint64_t val, mask = UINT64_MAX;
1649                uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
1650
1651                /*
1652                 * Mask.
1653                 */
1654                mf_mask = strchr(mf_val, '/');
1655                if (mf_mask) {
1656                        *mf_mask = 0;
1657                        mf_mask++;
1658
1659                        /* Parse. */
1660                        mask = strtoull(mf_mask, &mf_mask, 0);
1661                        if (mf_mask[0])
1662                                goto error;
1663
1664                        /* Endianness conversion. */
1665                        if (mf->is_header)
1666                                mask = field_hton(mask, mf->n_bits);
1667                }
1668
1669                /* Copy to entry. */
1670                if (entry->key_mask)
1671                        memcpy(&entry->key_mask[offset],
1672                               (uint8_t *)&mask,
1673                               mf->n_bits / 8);
1674
1675                /*
1676                 * Value.
1677                 */
1678                /* Parse. */
1679                val = strtoull(mf_val, &mf_val, 0);
1680                if (mf_val[0])
1681                        goto error;
1682
1683                /* Endianness conversion. */
1684                if (mf->is_header)
1685                        val = field_hton(val, mf->n_bits);
1686
1687                /* Copy to entry. */
1688                memcpy(&entry->key[offset],
1689                       (uint8_t *)&val,
1690                       mf->n_bits / 8);
1691        }
1692
1693        tokens += 1 + table->info.n_match_fields;
1694        n_tokens -= 1 + table->info.n_match_fields;
1695
1696        /*
1697         * Match priority.
1698         */
1699        if (n_tokens && !strcmp(tokens[0], "priority")) {
1700                char *priority = tokens[1];
1701                uint32_t val;
1702
1703                if (n_tokens < 2)
1704                        goto error;
1705
1706                /* Parse. */
1707                val = strtoul(priority, &priority, 0);
1708                if (priority[0])
1709                        goto error;
1710
1711                /* Copy to entry. */
1712                entry->key_priority = val;
1713
1714                tokens += 2;
1715                n_tokens -= 2;
1716        }
1717
1718        /*
1719         * Action.
1720         */
1721action:
1722        if (n_tokens && strcmp(tokens[0], "action"))
1723                goto other;
1724
1725        if (n_tokens < 2)
1726                goto error;
1727
1728        action = action_find(ctl, tokens[1]);
1729        if (!action)
1730                goto error;
1731
1732        if (n_tokens < 2 + action->info.n_args * 2)
1733                goto error;
1734
1735        /* action_id. */
1736        entry->action_id = action - ctl->actions;
1737
1738        /* action_data. */
1739        for (i = 0; i < action->info.n_args; i++) {
1740                struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1741                char *arg_name, *arg_val;
1742                uint64_t val;
1743
1744                arg_name = tokens[2 + i * 2];
1745                arg_val = tokens[2 + i * 2 + 1];
1746
1747                if (strcmp(arg_name, arg->name))
1748                        goto error;
1749
1750                val = strtoull(arg_val, &arg_val, 0);
1751                if (arg_val[0])
1752                        goto error;
1753
1754                /* Endianness conversion. */
1755                if (arg->is_network_byte_order)
1756                        val = field_hton(val, arg->n_bits);
1757
1758                /* Copy to entry. */
1759                memcpy(&entry->action_data[arg_offset],
1760                       (uint8_t *)&val,
1761                       arg->n_bits / 8);
1762
1763                arg_offset += arg->n_bits / 8;
1764        }
1765
1766        tokens += 2 + action->info.n_args * 2;
1767        n_tokens -= 2 + action->info.n_args * 2;
1768
1769other:
1770        if (n_tokens)
1771                goto error;
1772
1773        free(s0);
1774        return entry;
1775
1776error:
1777        table_entry_free(entry);
1778        free(s0);
1779        if (is_blank_or_comment)
1780                *is_blank_or_comment = blank_or_comment;
1781        return NULL;
1782}
1783
1784static void
1785table_entry_printf(FILE *f,
1786                   struct rte_swx_ctl_pipeline *ctl,
1787                   struct table *table,
1788                   struct rte_swx_table_entry *entry)
1789{
1790        struct action *action = &ctl->actions[entry->action_id];
1791        uint32_t i;
1792
1793        fprintf(f, "match ");
1794        for (i = 0; i < table->params.key_size; i++)
1795                fprintf(f, "%02x", entry->key[i]);
1796
1797        if (entry->key_mask) {
1798                fprintf(f, "/");
1799                for (i = 0; i < table->params.key_size; i++)
1800                        fprintf(f, "%02x", entry->key_mask[i]);
1801        }
1802
1803        fprintf(f, " priority %u", entry->key_priority);
1804
1805        fprintf(f, " action %s ", action->info.name);
1806        for (i = 0; i < action->data_size; i++)
1807                fprintf(f, "%02x", entry->action_data[i]);
1808
1809        fprintf(f, "\n");
1810}
1811
1812int
1813rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1814                                   struct rte_swx_ctl_pipeline *ctl,
1815                                   const char *table_name)
1816{
1817        struct table *table;
1818        struct rte_swx_table_entry *entry;
1819        uint32_t n_entries = 0, i;
1820
1821        if (!f || !ctl || !table_name || !table_name[0])
1822                return -EINVAL;
1823
1824        table = table_find(ctl, table_name);
1825        if (!table)
1826                return -EINVAL;
1827
1828        /* Table. */
1829        fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1830                table->info.name,
1831                table->params.key_size,
1832                table->params.key_offset);
1833
1834        for (i = 0; i < table->params.key_size; i++)
1835                fprintf(f, "%02x", table->params.key_mask0[i]);
1836
1837        fprintf(f, "], action data size %u bytes\n",
1838                table->params.action_data_size);
1839
1840        /* Table entries. */
1841        TAILQ_FOREACH(entry, &table->entries, node) {
1842                table_entry_printf(f, ctl, table, entry);
1843                n_entries++;
1844        }
1845
1846        TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1847                table_entry_printf(f, ctl, table, entry);
1848                n_entries++;
1849        }
1850
1851        TAILQ_FOREACH(entry, &table->pending_delete, node) {
1852                table_entry_printf(f, ctl, table, entry);
1853                n_entries++;
1854        }
1855
1856        fprintf(f, "# Table %s currently has %u entries.\n",
1857                table_name,
1858                n_entries);
1859        return 0;
1860}
1861