dpdk/lib/librte_pipeline/rte_swx_pipeline_spec.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2020 Intel Corporation
   3 */
   4#include <stdint.h>
   5#include <stdlib.h>
   6#include <stdio.h>
   7#include <string.h>
   8#include <errno.h>
   9
  10#include "rte_swx_pipeline.h"
  11#include "rte_swx_ctl.h"
  12
  13#define MAX_LINE_LENGTH RTE_SWX_INSTRUCTION_SIZE
  14#define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX
  15
  16#define STRUCT_BLOCK 0
  17#define ACTION_BLOCK 1
  18#define TABLE_BLOCK 2
  19#define TABLE_KEY_BLOCK 3
  20#define TABLE_ACTIONS_BLOCK 4
  21#define APPLY_BLOCK 5
  22
  23/*
  24 * extobj.
  25 *
  26 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  27 */
  28struct extobj_spec {
  29        char *name;
  30        char *extern_type_name;
  31        char *pragma;
  32};
  33
  34static void
  35extobj_spec_free(struct extobj_spec *s)
  36{
  37        if (!s)
  38                return;
  39
  40        free(s->name);
  41        s->name = NULL;
  42
  43        free(s->extern_type_name);
  44        s->extern_type_name = NULL;
  45
  46        free(s->pragma);
  47        s->pragma = NULL;
  48}
  49
  50static int
  51extobj_statement_parse(struct extobj_spec *s,
  52                       char **tokens,
  53                       uint32_t n_tokens,
  54                       uint32_t n_lines,
  55                       uint32_t *err_line,
  56                       const char **err_msg)
  57{
  58        /* Check format. */
  59        if (((n_tokens != 4) && (n_tokens != 6)) ||
  60            ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
  61            ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
  62                                 strcmp(tokens[4], "pragma")))) {
  63                if (err_line)
  64                        *err_line = n_lines;
  65                if (err_msg)
  66                        *err_msg = "Invalid extobj statement.";
  67                return -EINVAL;
  68        }
  69
  70        /* spec. */
  71        s->name = strdup(tokens[1]);
  72        s->extern_type_name = strdup(tokens[3]);
  73        s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
  74
  75        if (!s->name ||
  76            !s->extern_type_name ||
  77            ((n_tokens == 6) && !s->pragma)) {
  78                free(s->name);
  79                free(s->extern_type_name);
  80                free(s->pragma);
  81
  82                if (err_line)
  83                        *err_line = n_lines;
  84                if (err_msg)
  85                        *err_msg = "Memory allocation failed.";
  86                return -ENOMEM;
  87        }
  88
  89        return 0;
  90}
  91
  92/*
  93 * struct.
  94 *
  95 * struct STRUCT_TYPE_NAME {
  96 *      bit<SIZE> FIELD_NAME
  97 *      ...
  98 * }
  99 */
 100struct struct_spec {
 101        char *name;
 102        struct rte_swx_field_params *fields;
 103        uint32_t n_fields;
 104};
 105
 106static void
 107struct_spec_free(struct struct_spec *s)
 108{
 109        uint32_t i;
 110
 111        if (!s)
 112                return;
 113
 114        free(s->name);
 115        s->name = NULL;
 116
 117        for (i = 0; i < s->n_fields; i++) {
 118                uintptr_t name = (uintptr_t)s->fields[i].name;
 119
 120                free((void *)name);
 121        }
 122
 123        free(s->fields);
 124        s->fields = NULL;
 125
 126        s->n_fields = 0;
 127}
 128
 129static int
 130struct_statement_parse(struct struct_spec *s,
 131                       uint32_t *block_mask,
 132                       char **tokens,
 133                       uint32_t n_tokens,
 134                       uint32_t n_lines,
 135                       uint32_t *err_line,
 136                       const char **err_msg)
 137{
 138        /* Check format. */
 139        if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
 140                if (err_line)
 141                        *err_line = n_lines;
 142                if (err_msg)
 143                        *err_msg = "Invalid struct statement.";
 144                return -EINVAL;
 145        }
 146
 147        /* spec. */
 148        s->name = strdup(tokens[1]);
 149        if (!s->name) {
 150                if (err_line)
 151                        *err_line = n_lines;
 152                if (err_msg)
 153                        *err_msg = "Memory allocation failed.";
 154                return -ENOMEM;
 155        }
 156
 157        /* block_mask. */
 158        *block_mask |= 1 << STRUCT_BLOCK;
 159
 160        return 0;
 161}
 162
 163static int
 164struct_block_parse(struct struct_spec *s,
 165                   uint32_t *block_mask,
 166                   char **tokens,
 167                   uint32_t n_tokens,
 168                   uint32_t n_lines,
 169                   uint32_t *err_line,
 170                   const char **err_msg)
 171{
 172        struct rte_swx_field_params *new_fields;
 173        char *p = tokens[0], *name;
 174        uint32_t n_bits;
 175
 176        /* Handle end of block. */
 177        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
 178                *block_mask &= ~(1 << STRUCT_BLOCK);
 179                return 0;
 180        }
 181
 182        /* Check format. */
 183        if ((n_tokens != 2) ||
 184            (strlen(p) < 6) ||
 185            (p[0] != 'b') ||
 186            (p[1] != 'i') ||
 187            (p[2] != 't') ||
 188            (p[3] != '<') ||
 189            (p[strlen(p) - 1] != '>')) {
 190                if (err_line)
 191                        *err_line = n_lines;
 192                if (err_msg)
 193                        *err_msg = "Invalid struct field statement.";
 194                return -EINVAL;
 195        }
 196
 197        /* Remove the "bit<" and ">". */
 198        p[strlen(p) - 1] = 0;
 199        p += 4;
 200
 201        n_bits = strtoul(p, &p, 0);
 202        if ((p[0]) ||
 203            !n_bits ||
 204            (n_bits % 8) ||
 205            (n_bits > 64)) {
 206                if (err_line)
 207                        *err_line = n_lines;
 208                if (err_msg)
 209                        *err_msg = "Invalid struct field size.";
 210                return -EINVAL;
 211        }
 212
 213        /* spec. */
 214        name = strdup(tokens[1]);
 215        if (!name) {
 216                if (err_line)
 217                        *err_line = n_lines;
 218                if (err_msg)
 219                        *err_msg = "Memory allocation failed.";
 220                return -ENOMEM;
 221        }
 222
 223        new_fields = realloc(s->fields,
 224                             (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
 225        if (!new_fields) {
 226                free(name);
 227
 228                if (err_line)
 229                        *err_line = n_lines;
 230                if (err_msg)
 231                        *err_msg = "Memory allocation failed.";
 232                return -ENOMEM;
 233        }
 234
 235        s->fields = new_fields;
 236        s->fields[s->n_fields].name = name;
 237        s->fields[s->n_fields].n_bits = n_bits;
 238        s->n_fields++;
 239
 240        return 0;
 241}
 242
 243/*
 244 * header.
 245 *
 246 * header HEADER_NAME instanceof STRUCT_TYPE_NAME
 247 */
 248struct header_spec {
 249        char *name;
 250        char *struct_type_name;
 251};
 252
 253static void
 254header_spec_free(struct header_spec *s)
 255{
 256        if (!s)
 257                return;
 258
 259        free(s->name);
 260        s->name = NULL;
 261
 262        free(s->struct_type_name);
 263        s->struct_type_name = NULL;
 264}
 265
 266static int
 267header_statement_parse(struct header_spec *s,
 268                       char **tokens,
 269                       uint32_t n_tokens,
 270                       uint32_t n_lines,
 271                       uint32_t *err_line,
 272                       const char **err_msg)
 273{
 274        /* Check format. */
 275        if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
 276                if (err_line)
 277                        *err_line = n_lines;
 278                if (err_msg)
 279                        *err_msg = "Invalid header statement.";
 280                return -EINVAL;
 281        }
 282
 283        /* spec. */
 284        s->name = strdup(tokens[1]);
 285        s->struct_type_name = strdup(tokens[3]);
 286
 287        if (!s->name || !s->struct_type_name) {
 288                free(s->name);
 289                free(s->struct_type_name);
 290
 291                if (err_line)
 292                        *err_line = n_lines;
 293                if (err_msg)
 294                        *err_msg = "Memory allocation failed.";
 295                return -ENOMEM;
 296        }
 297
 298        return 0;
 299}
 300
 301/*
 302 * metadata.
 303 *
 304 * metadata instanceof STRUCT_TYPE_NAME
 305 */
 306struct metadata_spec {
 307        char *struct_type_name;
 308};
 309
 310static void
 311metadata_spec_free(struct metadata_spec *s)
 312{
 313        if (!s)
 314                return;
 315
 316        free(s->struct_type_name);
 317        s->struct_type_name = NULL;
 318}
 319
 320static int
 321metadata_statement_parse(struct metadata_spec *s,
 322                         char **tokens,
 323                         uint32_t n_tokens,
 324                         uint32_t n_lines,
 325                         uint32_t *err_line,
 326                         const char **err_msg)
 327{
 328        /* Check format. */
 329        if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
 330                if (err_line)
 331                        *err_line = n_lines;
 332                if (err_msg)
 333                        *err_msg = "Invalid metadata statement.";
 334                return -EINVAL;
 335        }
 336
 337        /* spec. */
 338        s->struct_type_name = strdup(tokens[2]);
 339        if (!s->struct_type_name) {
 340                if (err_line)
 341                        *err_line = n_lines;
 342                if (err_msg)
 343                        *err_msg = "Memory allocation failed.";
 344                return -ENOMEM;
 345        }
 346
 347        return 0;
 348}
 349
 350/*
 351 * action.
 352 *
 353 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
 354 *      INSTRUCTION
 355 *      ...
 356 * }
 357 */
 358struct action_spec {
 359        char *name;
 360        char *args_struct_type_name;
 361        const char **instructions;
 362        uint32_t n_instructions;
 363};
 364
 365static void
 366action_spec_free(struct action_spec *s)
 367{
 368        uint32_t i;
 369
 370        if (!s)
 371                return;
 372
 373        free(s->name);
 374        s->name = NULL;
 375
 376        free(s->args_struct_type_name);
 377        s->args_struct_type_name = NULL;
 378
 379        for (i = 0; i < s->n_instructions; i++) {
 380                uintptr_t instr = (uintptr_t)s->instructions[i];
 381
 382                free((void *)instr);
 383        }
 384
 385        free(s->instructions);
 386        s->instructions = NULL;
 387
 388        s->n_instructions = 0;
 389}
 390
 391static int
 392action_statement_parse(struct action_spec *s,
 393                       uint32_t *block_mask,
 394                       char **tokens,
 395                       uint32_t n_tokens,
 396                       uint32_t n_lines,
 397                       uint32_t *err_line,
 398                       const char **err_msg)
 399{
 400        /* Check format. */
 401        if (((n_tokens != 5) && (n_tokens != 6)) ||
 402            ((n_tokens == 5) &&
 403             (strcmp(tokens[2], "args") ||
 404              strcmp(tokens[3], "none") ||
 405              strcmp(tokens[4], "{"))) ||
 406            ((n_tokens == 6) &&
 407             (strcmp(tokens[2], "args") ||
 408              strcmp(tokens[3], "instanceof") ||
 409              strcmp(tokens[5], "{")))) {
 410                if (err_line)
 411                        *err_line = n_lines;
 412                if (err_msg)
 413                        *err_msg = "Invalid action statement.";
 414                return -EINVAL;
 415        }
 416
 417        /* spec. */
 418        s->name = strdup(tokens[1]);
 419        s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
 420
 421        if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
 422                if (err_line)
 423                        *err_line = n_lines;
 424                if (err_msg)
 425                        *err_msg = "Memory allocation failed.";
 426                return -ENOMEM;
 427        }
 428
 429        /* block_mask. */
 430        *block_mask |= 1 << ACTION_BLOCK;
 431
 432        return 0;
 433}
 434
 435static int
 436action_block_parse(struct action_spec *s,
 437                   uint32_t *block_mask,
 438                   char **tokens,
 439                   uint32_t n_tokens,
 440                   uint32_t n_lines,
 441                   uint32_t *err_line,
 442                   const char **err_msg)
 443{
 444        char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
 445        const char **new_instructions;
 446        uint32_t i;
 447
 448        /* Handle end of block. */
 449        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
 450                *block_mask &= ~(1 << ACTION_BLOCK);
 451                return 0;
 452        }
 453
 454        /* spec. */
 455        buffer[0] = 0;
 456        for (i = 0; i < n_tokens; i++) {
 457                if (i)
 458                        strcat(buffer, " ");
 459                strcat(buffer, tokens[i]);
 460        }
 461
 462        instr = strdup(buffer);
 463        if (!instr) {
 464                if (err_line)
 465                        *err_line = n_lines;
 466                if (err_msg)
 467                        *err_msg = "Memory allocation failed.";
 468                return -ENOMEM;
 469        }
 470
 471        new_instructions = realloc(s->instructions,
 472                                   (s->n_instructions + 1) * sizeof(char *));
 473        if (!new_instructions) {
 474                free(instr);
 475
 476                if (err_line)
 477                        *err_line = n_lines;
 478                if (err_msg)
 479                        *err_msg = "Memory allocation failed.";
 480                return -ENOMEM;
 481        }
 482
 483        s->instructions = new_instructions;
 484        s->instructions[s->n_instructions] = instr;
 485        s->n_instructions++;
 486
 487        return 0;
 488}
 489
 490/*
 491 * table.
 492 *
 493 * table {
 494 *      key {
 495 *              MATCH_FIELD_NAME exact | wildcard | lpm
 496 *              ...
 497 *      }
 498 *      actions {
 499 *              ACTION_NAME
 500 *              ...
 501 *      }
 502 *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
 503 *      instanceof TABLE_TYPE_NAME
 504 *      pragma ARGS
 505 *      size SIZE
 506 * }
 507 */
 508struct table_spec {
 509        char *name;
 510        struct rte_swx_pipeline_table_params params;
 511        char *recommended_table_type_name;
 512        char *args;
 513        uint32_t size;
 514};
 515
 516static void
 517table_spec_free(struct table_spec *s)
 518{
 519        uintptr_t default_action_name;
 520        uint32_t i;
 521
 522        if (!s)
 523                return;
 524
 525        free(s->name);
 526        s->name = NULL;
 527
 528        for (i = 0; i < s->params.n_fields; i++) {
 529                uintptr_t name = (uintptr_t)s->params.fields[i].name;
 530
 531                free((void *)name);
 532        }
 533
 534        free(s->params.fields);
 535        s->params.fields = NULL;
 536
 537        s->params.n_fields = 0;
 538
 539        for (i = 0; i < s->params.n_actions; i++) {
 540                uintptr_t name = (uintptr_t)s->params.action_names[i];
 541
 542                free((void *)name);
 543        }
 544
 545        free(s->params.action_names);
 546        s->params.action_names = NULL;
 547
 548        s->params.n_actions = 0;
 549
 550        default_action_name = (uintptr_t)s->params.default_action_name;
 551        free((void *)default_action_name);
 552        s->params.default_action_name = NULL;
 553
 554        free(s->params.default_action_data);
 555        s->params.default_action_data = NULL;
 556
 557        s->params.default_action_is_const = 0;
 558
 559        free(s->recommended_table_type_name);
 560        s->recommended_table_type_name = NULL;
 561
 562        free(s->args);
 563        s->args = NULL;
 564
 565        s->size = 0;
 566}
 567
 568static int
 569table_key_statement_parse(uint32_t *block_mask,
 570                          char **tokens,
 571                          uint32_t n_tokens,
 572                          uint32_t n_lines,
 573                          uint32_t *err_line,
 574                          const char **err_msg)
 575{
 576        /* Check format. */
 577        if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
 578                if (err_line)
 579                        *err_line = n_lines;
 580                if (err_msg)
 581                        *err_msg = "Invalid key statement.";
 582                return -EINVAL;
 583        }
 584
 585        /* block_mask. */
 586        *block_mask |= 1 << TABLE_KEY_BLOCK;
 587
 588        return 0;
 589}
 590
 591static int
 592table_key_block_parse(struct table_spec *s,
 593                      uint32_t *block_mask,
 594                      char **tokens,
 595                      uint32_t n_tokens,
 596                      uint32_t n_lines,
 597                      uint32_t *err_line,
 598                      const char **err_msg)
 599{
 600        struct rte_swx_match_field_params *new_fields;
 601        enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
 602        char *name;
 603
 604        /* Handle end of block. */
 605        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
 606                *block_mask &= ~(1 << TABLE_KEY_BLOCK);
 607                return 0;
 608        }
 609
 610        /* Check input arguments. */
 611        if ((n_tokens != 2) ||
 612            (strcmp(tokens[1], "exact") &&
 613             strcmp(tokens[1], "wildcard") &&
 614             strcmp(tokens[1], "lpm"))) {
 615                if (err_line)
 616                        *err_line = n_lines;
 617                if (err_msg)
 618                        *err_msg = "Invalid match field statement.";
 619                return -EINVAL;
 620        }
 621
 622        if (!strcmp(tokens[1], "wildcard"))
 623                match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
 624        if (!strcmp(tokens[1], "lpm"))
 625                match_type = RTE_SWX_TABLE_MATCH_LPM;
 626        if (!strcmp(tokens[1], "exact"))
 627                match_type = RTE_SWX_TABLE_MATCH_EXACT;
 628
 629        name = strdup(tokens[0]);
 630        if (!name) {
 631                if (err_line)
 632                        *err_line = n_lines;
 633                if (err_msg)
 634                        *err_msg = "Memory allocation failed.";
 635                return -ENOMEM;
 636        }
 637
 638        new_fields = realloc(s->params.fields,
 639                             (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
 640        if (!new_fields) {
 641                free(name);
 642
 643                if (err_line)
 644                        *err_line = n_lines;
 645                if (err_msg)
 646                        *err_msg = "Memory allocation failed.";
 647                return -ENOMEM;
 648        }
 649
 650        s->params.fields = new_fields;
 651        s->params.fields[s->params.n_fields].name = name;
 652        s->params.fields[s->params.n_fields].match_type = match_type;
 653        s->params.n_fields++;
 654
 655        return 0;
 656}
 657
 658static int
 659table_actions_statement_parse(uint32_t *block_mask,
 660                              char **tokens,
 661                              uint32_t n_tokens,
 662                              uint32_t n_lines,
 663                              uint32_t *err_line,
 664                              const char **err_msg)
 665{
 666        /* Check format. */
 667        if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
 668                if (err_line)
 669                        *err_line = n_lines;
 670                if (err_msg)
 671                        *err_msg = "Invalid actions statement.";
 672                return -EINVAL;
 673        }
 674
 675        /* block_mask. */
 676        *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
 677
 678        return 0;
 679}
 680
 681static int
 682table_actions_block_parse(struct table_spec *s,
 683                          uint32_t *block_mask,
 684                          char **tokens,
 685                          uint32_t n_tokens,
 686                          uint32_t n_lines,
 687                          uint32_t *err_line,
 688                          const char **err_msg)
 689{
 690        const char **new_action_names;
 691        char *name;
 692
 693        /* Handle end of block. */
 694        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
 695                *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
 696                return 0;
 697        }
 698
 699        /* Check input arguments. */
 700        if (n_tokens != 1) {
 701                if (err_line)
 702                        *err_line = n_lines;
 703                if (err_msg)
 704                        *err_msg = "Invalid action name statement.";
 705                return -EINVAL;
 706        }
 707
 708        name = strdup(tokens[0]);
 709        if (!name) {
 710                if (err_line)
 711                        *err_line = n_lines;
 712                if (err_msg)
 713                        *err_msg = "Memory allocation failed.";
 714                return -ENOMEM;
 715        }
 716
 717        new_action_names = realloc(s->params.action_names,
 718                                   (s->params.n_actions + 1) * sizeof(char *));
 719        if (!new_action_names) {
 720                free(name);
 721
 722                if (err_line)
 723                        *err_line = n_lines;
 724                if (err_msg)
 725                        *err_msg = "Memory allocation failed.";
 726                return -ENOMEM;
 727        }
 728
 729        s->params.action_names = new_action_names;
 730        s->params.action_names[s->params.n_actions] = name;
 731        s->params.n_actions++;
 732
 733        return 0;
 734}
 735
 736static int
 737table_statement_parse(struct table_spec *s,
 738                      uint32_t *block_mask,
 739                      char **tokens,
 740                      uint32_t n_tokens,
 741                      uint32_t n_lines,
 742                      uint32_t *err_line,
 743                      const char **err_msg)
 744{
 745        /* Check format. */
 746        if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
 747                if (err_line)
 748                        *err_line = n_lines;
 749                if (err_msg)
 750                        *err_msg = "Invalid table statement.";
 751                return -EINVAL;
 752        }
 753
 754        /* spec. */
 755        s->name = strdup(tokens[1]);
 756        if (!s->name) {
 757                if (err_line)
 758                        *err_line = n_lines;
 759                if (err_msg)
 760                        *err_msg = "Memory allocation failed.";
 761                return -ENOMEM;
 762        }
 763
 764        /* block_mask. */
 765        *block_mask |= 1 << TABLE_BLOCK;
 766
 767        return 0;
 768}
 769
 770static int
 771table_block_parse(struct table_spec *s,
 772                  uint32_t *block_mask,
 773                  char **tokens,
 774                  uint32_t n_tokens,
 775                  uint32_t n_lines,
 776                  uint32_t *err_line,
 777                  const char **err_msg)
 778{
 779        if (*block_mask & (1 << TABLE_KEY_BLOCK))
 780                return table_key_block_parse(s,
 781                                             block_mask,
 782                                             tokens,
 783                                             n_tokens,
 784                                             n_lines,
 785                                             err_line,
 786                                             err_msg);
 787
 788        if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
 789                return table_actions_block_parse(s,
 790                                                 block_mask,
 791                                                 tokens,
 792                                                 n_tokens,
 793                                                 n_lines,
 794                                                 err_line,
 795                                                 err_msg);
 796
 797        /* Handle end of block. */
 798        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
 799                *block_mask &= ~(1 << TABLE_BLOCK);
 800                return 0;
 801        }
 802
 803        if (!strcmp(tokens[0], "key"))
 804                return table_key_statement_parse(block_mask,
 805                                                 tokens,
 806                                                 n_tokens,
 807                                                 n_lines,
 808                                                 err_line,
 809                                                 err_msg);
 810
 811        if (!strcmp(tokens[0], "actions"))
 812                return table_actions_statement_parse(block_mask,
 813                                                     tokens,
 814                                                     n_tokens,
 815                                                     n_lines,
 816                                                     err_line,
 817                                                     err_msg);
 818
 819        if (!strcmp(tokens[0], "default_action")) {
 820                if (((n_tokens != 4) && (n_tokens != 5)) ||
 821                    strcmp(tokens[2], "args") ||
 822                    strcmp(tokens[3], "none") ||
 823                    ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
 824                        if (err_line)
 825                                *err_line = n_lines;
 826                        if (err_msg)
 827                                *err_msg = "Invalid default_action statement.";
 828                        return -EINVAL;
 829                }
 830
 831                if (s->params.default_action_name) {
 832                        if (err_line)
 833                                *err_line = n_lines;
 834                        if (err_msg)
 835                                *err_msg = "Duplicate default_action stmt.";
 836                        return -EINVAL;
 837                }
 838
 839                s->params.default_action_name = strdup(tokens[1]);
 840                if (!s->params.default_action_name) {
 841                        if (err_line)
 842                                *err_line = n_lines;
 843                        if (err_msg)
 844                                *err_msg = "Memory allocation failed.";
 845                        return -ENOMEM;
 846                }
 847
 848                if (n_tokens == 5)
 849                        s->params.default_action_is_const = 1;
 850
 851                return 0;
 852        }
 853
 854        if (!strcmp(tokens[0], "instanceof")) {
 855                if (n_tokens != 2) {
 856                        if (err_line)
 857                                *err_line = n_lines;
 858                        if (err_msg)
 859                                *err_msg = "Invalid instanceof statement.";
 860                        return -EINVAL;
 861                }
 862
 863                if (s->recommended_table_type_name) {
 864                        if (err_line)
 865                                *err_line = n_lines;
 866                        if (err_msg)
 867                                *err_msg = "Duplicate instanceof statement.";
 868                        return -EINVAL;
 869                }
 870
 871                s->recommended_table_type_name = strdup(tokens[1]);
 872                if (!s->recommended_table_type_name) {
 873                        if (err_line)
 874                                *err_line = n_lines;
 875                        if (err_msg)
 876                                *err_msg = "Memory allocation failed.";
 877                        return -ENOMEM;
 878                }
 879
 880                return 0;
 881        }
 882
 883        if (!strcmp(tokens[0], "pragma")) {
 884                if (n_tokens != 2) {
 885                        if (err_line)
 886                                *err_line = n_lines;
 887                        if (err_msg)
 888                                *err_msg = "Invalid pragma statement.";
 889                        return -EINVAL;
 890                }
 891
 892                if (s->args) {
 893                        if (err_line)
 894                                *err_line = n_lines;
 895                        if (err_msg)
 896                                *err_msg = "Duplicate pragma statement.";
 897                        return -EINVAL;
 898                }
 899
 900                s->args = strdup(tokens[1]);
 901                if (!s->args) {
 902                        if (err_line)
 903                                *err_line = n_lines;
 904                        if (err_msg)
 905                                *err_msg = "Memory allocation failed.";
 906                        return -ENOMEM;
 907                }
 908
 909                return 0;
 910        }
 911
 912        if (!strcmp(tokens[0], "size")) {
 913                char *p = tokens[1];
 914
 915                if (n_tokens != 2) {
 916                        if (err_line)
 917                                *err_line = n_lines;
 918                        if (err_msg)
 919                                *err_msg = "Invalid pragma statement.";
 920                        return -EINVAL;
 921                }
 922
 923                s->size = strtoul(p, &p, 0);
 924                if (p[0]) {
 925                        if (err_line)
 926                                *err_line = n_lines;
 927                        if (err_msg)
 928                                *err_msg = "Invalid size argument.";
 929                        return -EINVAL;
 930                }
 931
 932                return 0;
 933        }
 934
 935        /* Anything else. */
 936        if (err_line)
 937                *err_line = n_lines;
 938        if (err_msg)
 939                *err_msg = "Invalid statement.";
 940        return -EINVAL;
 941}
 942
 943/*
 944 * apply.
 945 *
 946 * apply {
 947 *      INSTRUCTION
 948 *      ...
 949 * }
 950 */
 951struct apply_spec {
 952        const char **instructions;
 953        uint32_t n_instructions;
 954};
 955
 956static void
 957apply_spec_free(struct apply_spec *s)
 958{
 959        uint32_t i;
 960
 961        if (!s)
 962                return;
 963
 964        for (i = 0; i < s->n_instructions; i++) {
 965                uintptr_t instr = (uintptr_t)s->instructions[i];
 966
 967                free((void *)instr);
 968        }
 969
 970        free(s->instructions);
 971        s->instructions = NULL;
 972
 973        s->n_instructions = 0;
 974}
 975
 976static int
 977apply_statement_parse(uint32_t *block_mask,
 978                      char **tokens,
 979                      uint32_t n_tokens,
 980                      uint32_t n_lines,
 981                      uint32_t *err_line,
 982                      const char **err_msg)
 983{
 984        /* Check format. */
 985        if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
 986                if (err_line)
 987                        *err_line = n_lines;
 988                if (err_msg)
 989                        *err_msg = "Invalid apply statement.";
 990                return -EINVAL;
 991        }
 992
 993        /* block_mask. */
 994        *block_mask |= 1 << APPLY_BLOCK;
 995
 996        return 0;
 997}
 998
 999static int
1000apply_block_parse(struct apply_spec *s,
1001                  uint32_t *block_mask,
1002                  char **tokens,
1003                  uint32_t n_tokens,
1004                  uint32_t n_lines,
1005                  uint32_t *err_line,
1006                  const char **err_msg)
1007{
1008        char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1009        const char **new_instructions;
1010        uint32_t i;
1011
1012        /* Handle end of block. */
1013        if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1014                *block_mask &= ~(1 << APPLY_BLOCK);
1015                return 0;
1016        }
1017
1018        /* spec. */
1019        buffer[0] = 0;
1020        for (i = 0; i < n_tokens; i++) {
1021                if (i)
1022                        strcat(buffer, " ");
1023                strcat(buffer, tokens[i]);
1024        }
1025
1026        instr = strdup(buffer);
1027        if (!instr) {
1028                if (err_line)
1029                        *err_line = n_lines;
1030                if (err_msg)
1031                        *err_msg = "Memory allocation failed.";
1032                return -ENOMEM;
1033        }
1034
1035        new_instructions = realloc(s->instructions,
1036                                   (s->n_instructions + 1) * sizeof(char *));
1037        if (!new_instructions) {
1038                free(instr);
1039
1040                if (err_line)
1041                        *err_line = n_lines;
1042                if (err_msg)
1043                        *err_msg = "Memory allocation failed.";
1044                return -ENOMEM;
1045        }
1046
1047        s->instructions = new_instructions;
1048        s->instructions[s->n_instructions] = instr;
1049        s->n_instructions++;
1050
1051        return 0;
1052}
1053
1054/*
1055 * Pipeline.
1056 */
1057int
1058rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1059                                 FILE *spec,
1060                                 uint32_t *err_line,
1061                                 const char **err_msg)
1062{
1063        struct extobj_spec extobj_spec = {0};
1064        struct struct_spec struct_spec = {0};
1065        struct header_spec header_spec = {0};
1066        struct metadata_spec metadata_spec = {0};
1067        struct action_spec action_spec = {0};
1068        struct table_spec table_spec = {0};
1069        struct apply_spec apply_spec = {0};
1070        uint32_t n_lines;
1071        uint32_t block_mask = 0;
1072        int status;
1073
1074        /* Check the input arguments. */
1075        if (!p) {
1076                if (err_line)
1077                        *err_line = 0;
1078                if (err_msg)
1079                        *err_msg = "Null pipeline arument.";
1080                status = -EINVAL;
1081                goto error;
1082        }
1083
1084        if (!spec) {
1085                if (err_line)
1086                        *err_line = 0;
1087                if (err_msg)
1088                        *err_msg = "Null specification file argument.";
1089                status = -EINVAL;
1090                goto error;
1091        }
1092
1093        for (n_lines = 1; ; n_lines++) {
1094                char line[MAX_LINE_LENGTH];
1095                char *tokens[MAX_TOKENS], *ptr = line;
1096                uint32_t n_tokens = 0;
1097
1098                /* Read next line. */
1099                if (!fgets(line, sizeof(line), spec))
1100                        break;
1101
1102                /* Parse the line into tokens. */
1103                for ( ; ; ) {
1104                        char *token;
1105
1106                        /* Get token. */
1107                        token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1108                        if (!token)
1109                                break;
1110
1111                        /* Handle comments. */
1112                        if ((token[0] == '#') ||
1113                            (token[0] == ';') ||
1114                            ((token[0] == '/') && (token[1] == '/'))) {
1115                                break;
1116                        }
1117
1118                        /* Handle excessively long lines. */
1119                        if (n_tokens >= MAX_TOKENS) {
1120                                if (err_line)
1121                                        *err_line = n_lines;
1122                                if (err_msg)
1123                                        *err_msg = "Too many tokens.";
1124                                status = -EINVAL;
1125                                goto error;
1126                        }
1127
1128                        /* Handle excessively long tokens. */
1129                        if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1130                            RTE_SWX_NAME_SIZE) {
1131                                if (err_line)
1132                                        *err_line = n_lines;
1133                                if (err_msg)
1134                                        *err_msg = "Token too big.";
1135                                status = -EINVAL;
1136                                goto error;
1137                        }
1138
1139                        /* Save token. */
1140                        tokens[n_tokens] = token;
1141                        n_tokens++;
1142                }
1143
1144                /* Handle empty lines. */
1145                if (!n_tokens)
1146                        continue;
1147
1148                /* struct block. */
1149                if (block_mask & (1 << STRUCT_BLOCK)) {
1150                        status = struct_block_parse(&struct_spec,
1151                                                    &block_mask,
1152                                                    tokens,
1153                                                    n_tokens,
1154                                                    n_lines,
1155                                                    err_line,
1156                                                    err_msg);
1157                        if (status)
1158                                goto error;
1159
1160                        if (block_mask & (1 << STRUCT_BLOCK))
1161                                continue;
1162
1163                        /* End of block. */
1164                        status = rte_swx_pipeline_struct_type_register(p,
1165                                struct_spec.name,
1166                                struct_spec.fields,
1167                                struct_spec.n_fields);
1168                        if (status) {
1169                                if (err_line)
1170                                        *err_line = n_lines;
1171                                if (err_msg)
1172                                        *err_msg = "Struct registration error.";
1173                                goto error;
1174                        }
1175
1176                        struct_spec_free(&struct_spec);
1177
1178                        continue;
1179                }
1180
1181                /* action block. */
1182                if (block_mask & (1 << ACTION_BLOCK)) {
1183                        status = action_block_parse(&action_spec,
1184                                                    &block_mask,
1185                                                    tokens,
1186                                                    n_tokens,
1187                                                    n_lines,
1188                                                    err_line,
1189                                                    err_msg);
1190                        if (status)
1191                                goto error;
1192
1193                        if (block_mask & (1 << ACTION_BLOCK))
1194                                continue;
1195
1196                        /* End of block. */
1197                        status = rte_swx_pipeline_action_config(p,
1198                                action_spec.name,
1199                                action_spec.args_struct_type_name,
1200                                action_spec.instructions,
1201                                action_spec.n_instructions);
1202                        if (status) {
1203                                if (err_line)
1204                                        *err_line = n_lines;
1205                                if (err_msg)
1206                                        *err_msg = "Action config error.";
1207                                goto error;
1208                        }
1209
1210                        action_spec_free(&action_spec);
1211
1212                        continue;
1213                }
1214
1215                /* table block. */
1216                if (block_mask & (1 << TABLE_BLOCK)) {
1217                        status = table_block_parse(&table_spec,
1218                                                   &block_mask,
1219                                                   tokens,
1220                                                   n_tokens,
1221                                                   n_lines,
1222                                                   err_line,
1223                                                   err_msg);
1224                        if (status)
1225                                goto error;
1226
1227                        if (block_mask & (1 << TABLE_BLOCK))
1228                                continue;
1229
1230                        /* End of block. */
1231                        status = rte_swx_pipeline_table_config(p,
1232                                table_spec.name,
1233                                &table_spec.params,
1234                                table_spec.recommended_table_type_name,
1235                                table_spec.args,
1236                                table_spec.size);
1237                        if (status) {
1238                                if (err_line)
1239                                        *err_line = n_lines;
1240                                if (err_msg)
1241                                        *err_msg = "Table configuration error.";
1242                                goto error;
1243                        }
1244
1245                        table_spec_free(&table_spec);
1246
1247                        continue;
1248                }
1249
1250                /* apply block. */
1251                if (block_mask & (1 << APPLY_BLOCK)) {
1252                        status = apply_block_parse(&apply_spec,
1253                                                   &block_mask,
1254                                                   tokens,
1255                                                   n_tokens,
1256                                                   n_lines,
1257                                                   err_line,
1258                                                   err_msg);
1259                        if (status)
1260                                goto error;
1261
1262                        if (block_mask & (1 << APPLY_BLOCK))
1263                                continue;
1264
1265                        /* End of block. */
1266                        status = rte_swx_pipeline_instructions_config(p,
1267                                apply_spec.instructions,
1268                                apply_spec.n_instructions);
1269                        if (status) {
1270                                if (err_line)
1271                                        *err_line = n_lines;
1272                                if (err_msg)
1273                                        *err_msg = "Pipeline instructions err.";
1274                                goto error;
1275                        }
1276
1277                        apply_spec_free(&apply_spec);
1278
1279                        continue;
1280                }
1281
1282                /* extobj. */
1283                if (!strcmp(tokens[0], "extobj")) {
1284                        status = extobj_statement_parse(&extobj_spec,
1285                                                        tokens,
1286                                                        n_tokens,
1287                                                        n_lines,
1288                                                        err_line,
1289                                                        err_msg);
1290                        if (status)
1291                                goto error;
1292
1293                        status = rte_swx_pipeline_extern_object_config(p,
1294                                extobj_spec.name,
1295                                extobj_spec.extern_type_name,
1296                                extobj_spec.pragma);
1297                        if (status) {
1298                                if (err_line)
1299                                        *err_line = n_lines;
1300                                if (err_msg)
1301                                        *err_msg = "Extern object config err.";
1302                                goto error;
1303                        }
1304
1305                        extobj_spec_free(&extobj_spec);
1306
1307                        continue;
1308                }
1309
1310                /* struct. */
1311                if (!strcmp(tokens[0], "struct")) {
1312                        status = struct_statement_parse(&struct_spec,
1313                                                        &block_mask,
1314                                                        tokens,
1315                                                        n_tokens,
1316                                                        n_lines,
1317                                                        err_line,
1318                                                        err_msg);
1319                        if (status)
1320                                goto error;
1321
1322                        continue;
1323                }
1324
1325                /* header. */
1326                if (!strcmp(tokens[0], "header")) {
1327                        status = header_statement_parse(&header_spec,
1328                                                        tokens,
1329                                                        n_tokens,
1330                                                        n_lines,
1331                                                        err_line,
1332                                                        err_msg);
1333                        if (status)
1334                                goto error;
1335
1336                        status = rte_swx_pipeline_packet_header_register(p,
1337                                header_spec.name,
1338                                header_spec.struct_type_name);
1339                        if (status) {
1340                                if (err_line)
1341                                        *err_line = n_lines;
1342                                if (err_msg)
1343                                        *err_msg = "Header registration error.";
1344                                goto error;
1345                        }
1346
1347                        header_spec_free(&header_spec);
1348
1349                        continue;
1350                }
1351
1352                /* metadata. */
1353                if (!strcmp(tokens[0], "metadata")) {
1354                        status = metadata_statement_parse(&metadata_spec,
1355                                                          tokens,
1356                                                          n_tokens,
1357                                                          n_lines,
1358                                                          err_line,
1359                                                          err_msg);
1360                        if (status)
1361                                goto error;
1362
1363                        status = rte_swx_pipeline_packet_metadata_register(p,
1364                                metadata_spec.struct_type_name);
1365                        if (status) {
1366                                if (err_line)
1367                                        *err_line = n_lines;
1368                                if (err_msg)
1369                                        *err_msg = "Meta-data reg err.";
1370                                goto error;
1371                        }
1372
1373                        metadata_spec_free(&metadata_spec);
1374
1375                        continue;
1376                }
1377
1378                /* action. */
1379                if (!strcmp(tokens[0], "action")) {
1380                        status = action_statement_parse(&action_spec,
1381                                                        &block_mask,
1382                                                        tokens,
1383                                                        n_tokens,
1384                                                        n_lines,
1385                                                        err_line,
1386                                                        err_msg);
1387                        if (status)
1388                                goto error;
1389
1390                        continue;
1391                }
1392
1393                /* table. */
1394                if (!strcmp(tokens[0], "table")) {
1395                        status = table_statement_parse(&table_spec,
1396                                                       &block_mask,
1397                                                       tokens,
1398                                                       n_tokens,
1399                                                       n_lines,
1400                                                       err_line,
1401                                                       err_msg);
1402                        if (status)
1403                                goto error;
1404
1405                        continue;
1406                }
1407
1408                /* apply. */
1409                if (!strcmp(tokens[0], "apply")) {
1410                        status = apply_statement_parse(&block_mask,
1411                                                       tokens,
1412                                                       n_tokens,
1413                                                       n_lines,
1414                                                       err_line,
1415                                                       err_msg);
1416                        if (status)
1417                                goto error;
1418
1419                        continue;
1420                }
1421
1422                /* Anything else. */
1423                if (err_line)
1424                        *err_line = n_lines;
1425                if (err_msg)
1426                        *err_msg = "Unknown statement.";
1427                status = -EINVAL;
1428                goto error;
1429        }
1430
1431        /* Handle unfinished block. */
1432        if (block_mask) {
1433                if (err_line)
1434                        *err_line = n_lines;
1435                if (err_msg)
1436                        *err_msg = "Missing }.";
1437                status = -EINVAL;
1438                goto error;
1439        }
1440
1441        /* Pipeline build. */
1442        status = rte_swx_pipeline_build(p);
1443        if (status) {
1444                if (err_line)
1445                        *err_line = n_lines;
1446                if (err_msg)
1447                        *err_msg = "Pipeline build error.";
1448                goto error;
1449        }
1450
1451        return 0;
1452
1453error:
1454        extobj_spec_free(&extobj_spec);
1455        struct_spec_free(&struct_spec);
1456        header_spec_free(&header_spec);
1457        metadata_spec_free(&metadata_spec);
1458        action_spec_free(&action_spec);
1459        table_spec_free(&table_spec);
1460        apply_spec_free(&apply_spec);
1461        return status;
1462}
1463