175d213bf8
The arguments of actions that are learned are now specified as part of the learn instruction as opposed to being statically specified as part of the learner table configuration. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
2491 lines
48 KiB
C
2491 lines
48 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2020 Intel Corporation
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "rte_swx_pipeline.h"
|
|
#include "rte_swx_ctl.h"
|
|
|
|
#define MAX_LINE_LENGTH RTE_SWX_INSTRUCTION_SIZE
|
|
#define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX
|
|
|
|
#define STRUCT_BLOCK 0
|
|
#define ACTION_BLOCK 1
|
|
#define TABLE_BLOCK 2
|
|
#define TABLE_KEY_BLOCK 3
|
|
#define TABLE_ACTIONS_BLOCK 4
|
|
#define SELECTOR_BLOCK 5
|
|
#define SELECTOR_SELECTOR_BLOCK 6
|
|
#define LEARNER_BLOCK 7
|
|
#define LEARNER_KEY_BLOCK 8
|
|
#define LEARNER_ACTIONS_BLOCK 9
|
|
#define APPLY_BLOCK 10
|
|
|
|
/*
|
|
* extobj.
|
|
*
|
|
* extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
|
|
*/
|
|
struct extobj_spec {
|
|
char *name;
|
|
char *extern_type_name;
|
|
char *pragma;
|
|
};
|
|
|
|
static void
|
|
extobj_spec_free(struct extobj_spec *s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
free(s->extern_type_name);
|
|
s->extern_type_name = NULL;
|
|
|
|
free(s->pragma);
|
|
s->pragma = NULL;
|
|
}
|
|
|
|
static int
|
|
extobj_statement_parse(struct extobj_spec *s,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if (((n_tokens != 4) && (n_tokens != 6)) ||
|
|
((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
|
|
((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
|
|
strcmp(tokens[4], "pragma")))) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid extobj statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
s->extern_type_name = strdup(tokens[3]);
|
|
s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
|
|
|
|
if (!s->name ||
|
|
!s->extern_type_name ||
|
|
((n_tokens == 6) && !s->pragma)) {
|
|
free(s->name);
|
|
free(s->extern_type_name);
|
|
free(s->pragma);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* struct.
|
|
*
|
|
* struct STRUCT_TYPE_NAME {
|
|
* bit<SIZE> | varbit<SIZE> FIELD_NAME
|
|
* ...
|
|
* }
|
|
*/
|
|
struct struct_spec {
|
|
char *name;
|
|
struct rte_swx_field_params *fields;
|
|
uint32_t n_fields;
|
|
int varbit;
|
|
};
|
|
|
|
static void
|
|
struct_spec_free(struct struct_spec *s)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
for (i = 0; i < s->n_fields; i++) {
|
|
uintptr_t name = (uintptr_t)s->fields[i].name;
|
|
|
|
free((void *)name);
|
|
}
|
|
|
|
free(s->fields);
|
|
s->fields = NULL;
|
|
|
|
s->n_fields = 0;
|
|
|
|
s->varbit = 0;
|
|
}
|
|
|
|
static int
|
|
struct_statement_parse(struct struct_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid struct statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << STRUCT_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
struct_block_parse(struct struct_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
struct rte_swx_field_params *new_fields;
|
|
char *p = tokens[0], *name = NULL;
|
|
uint32_t n_bits;
|
|
int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << STRUCT_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check format. */
|
|
if (n_tokens != 2) {
|
|
error = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
if (s->varbit) {
|
|
error = -EINVAL;
|
|
error_varbit_not_last = 1;
|
|
goto error;
|
|
}
|
|
|
|
if (!strncmp(p, "bit<", strlen("bit<"))) {
|
|
size_t len = strlen(p);
|
|
|
|
if ((len < strlen("bit< >")) || (p[len - 1] != '>')) {
|
|
error = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Remove the "bit<" and ">". */
|
|
p[strlen(p) - 1] = 0;
|
|
p += strlen("bit<");
|
|
} else if (!strncmp(p, "varbit<", strlen("varbit<"))) {
|
|
size_t len = strlen(p);
|
|
|
|
if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) {
|
|
error = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Remove the "varbit<" and ">". */
|
|
p[strlen(p) - 1] = 0;
|
|
p += strlen("varbit<");
|
|
|
|
/* Set the varbit flag. */
|
|
varbit = 1;
|
|
} else {
|
|
error = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
n_bits = strtoul(p, &p, 0);
|
|
if ((p[0]) ||
|
|
!n_bits ||
|
|
(n_bits % 8) ||
|
|
((n_bits > 64) && !varbit)) {
|
|
error = -EINVAL;
|
|
error_size_invalid = 1;
|
|
goto error;
|
|
}
|
|
|
|
/* spec. */
|
|
name = strdup(tokens[1]);
|
|
if (!name) {
|
|
error = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
|
|
if (!new_fields) {
|
|
error = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
s->fields = new_fields;
|
|
s->fields[s->n_fields].name = name;
|
|
s->fields[s->n_fields].n_bits = n_bits;
|
|
s->n_fields++;
|
|
s->varbit = varbit;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
free(name);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
|
|
if (err_msg) {
|
|
*err_msg = "Invalid struct field statement.";
|
|
|
|
if ((error == -EINVAL) && error_varbit_not_last)
|
|
*err_msg = "Varbit field is not the last struct field.";
|
|
|
|
if ((error == -EINVAL) && error_size_invalid)
|
|
*err_msg = "Invalid struct field size.";
|
|
|
|
if (error == -ENOMEM)
|
|
*err_msg = "Memory allocation failed.";
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
/*
|
|
* header.
|
|
*
|
|
* header HEADER_NAME instanceof STRUCT_TYPE_NAME
|
|
*/
|
|
struct header_spec {
|
|
char *name;
|
|
char *struct_type_name;
|
|
};
|
|
|
|
static void
|
|
header_spec_free(struct header_spec *s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
free(s->struct_type_name);
|
|
s->struct_type_name = NULL;
|
|
}
|
|
|
|
static int
|
|
header_statement_parse(struct header_spec *s,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid header statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
s->struct_type_name = strdup(tokens[3]);
|
|
|
|
if (!s->name || !s->struct_type_name) {
|
|
free(s->name);
|
|
free(s->struct_type_name);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* metadata.
|
|
*
|
|
* metadata instanceof STRUCT_TYPE_NAME
|
|
*/
|
|
struct metadata_spec {
|
|
char *struct_type_name;
|
|
};
|
|
|
|
static void
|
|
metadata_spec_free(struct metadata_spec *s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->struct_type_name);
|
|
s->struct_type_name = NULL;
|
|
}
|
|
|
|
static int
|
|
metadata_statement_parse(struct metadata_spec *s,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid metadata statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->struct_type_name = strdup(tokens[2]);
|
|
if (!s->struct_type_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* action.
|
|
*
|
|
* action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
|
|
* INSTRUCTION
|
|
* ...
|
|
* }
|
|
*/
|
|
struct action_spec {
|
|
char *name;
|
|
char *args_struct_type_name;
|
|
const char **instructions;
|
|
uint32_t n_instructions;
|
|
};
|
|
|
|
static void
|
|
action_spec_free(struct action_spec *s)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
free(s->args_struct_type_name);
|
|
s->args_struct_type_name = NULL;
|
|
|
|
for (i = 0; i < s->n_instructions; i++) {
|
|
uintptr_t instr = (uintptr_t)s->instructions[i];
|
|
|
|
free((void *)instr);
|
|
}
|
|
|
|
free(s->instructions);
|
|
s->instructions = NULL;
|
|
|
|
s->n_instructions = 0;
|
|
}
|
|
|
|
static int
|
|
action_statement_parse(struct action_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if (((n_tokens != 5) && (n_tokens != 6)) ||
|
|
((n_tokens == 5) &&
|
|
(strcmp(tokens[2], "args") ||
|
|
strcmp(tokens[3], "none") ||
|
|
strcmp(tokens[4], "{"))) ||
|
|
((n_tokens == 6) &&
|
|
(strcmp(tokens[2], "args") ||
|
|
strcmp(tokens[3], "instanceof") ||
|
|
strcmp(tokens[5], "{")))) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid action statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
|
|
|
|
if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << ACTION_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
action_block_parse(struct action_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
|
|
const char **new_instructions;
|
|
uint32_t i;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << ACTION_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* spec. */
|
|
buffer[0] = 0;
|
|
for (i = 0; i < n_tokens; i++) {
|
|
if (i)
|
|
strcat(buffer, " ");
|
|
strcat(buffer, tokens[i]);
|
|
}
|
|
|
|
instr = strdup(buffer);
|
|
if (!instr) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_instructions = realloc(s->instructions,
|
|
(s->n_instructions + 1) * sizeof(char *));
|
|
if (!new_instructions) {
|
|
free(instr);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->instructions = new_instructions;
|
|
s->instructions[s->n_instructions] = instr;
|
|
s->n_instructions++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* table.
|
|
*
|
|
* table {
|
|
* key {
|
|
* MATCH_FIELD_NAME exact | wildcard | lpm
|
|
* ...
|
|
* }
|
|
* actions {
|
|
* ACTION_NAME
|
|
* ...
|
|
* }
|
|
* default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
|
|
* instanceof TABLE_TYPE_NAME
|
|
* pragma ARGS
|
|
* size SIZE
|
|
* }
|
|
*/
|
|
struct table_spec {
|
|
char *name;
|
|
struct rte_swx_pipeline_table_params params;
|
|
char *recommended_table_type_name;
|
|
char *args;
|
|
uint32_t size;
|
|
};
|
|
|
|
static void
|
|
table_spec_free(struct table_spec *s)
|
|
{
|
|
uintptr_t default_action_name;
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
for (i = 0; i < s->params.n_fields; i++) {
|
|
uintptr_t name = (uintptr_t)s->params.fields[i].name;
|
|
|
|
free((void *)name);
|
|
}
|
|
|
|
free(s->params.fields);
|
|
s->params.fields = NULL;
|
|
|
|
s->params.n_fields = 0;
|
|
|
|
for (i = 0; i < s->params.n_actions; i++) {
|
|
uintptr_t name = (uintptr_t)s->params.action_names[i];
|
|
|
|
free((void *)name);
|
|
}
|
|
|
|
free(s->params.action_names);
|
|
s->params.action_names = NULL;
|
|
|
|
s->params.n_actions = 0;
|
|
|
|
default_action_name = (uintptr_t)s->params.default_action_name;
|
|
free((void *)default_action_name);
|
|
s->params.default_action_name = NULL;
|
|
|
|
free(s->params.default_action_data);
|
|
s->params.default_action_data = NULL;
|
|
|
|
s->params.default_action_is_const = 0;
|
|
|
|
free(s->recommended_table_type_name);
|
|
s->recommended_table_type_name = NULL;
|
|
|
|
free(s->args);
|
|
s->args = NULL;
|
|
|
|
s->size = 0;
|
|
}
|
|
|
|
static int
|
|
table_key_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid key statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << TABLE_KEY_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
table_key_block_parse(struct table_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
struct rte_swx_match_field_params *new_fields;
|
|
enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
|
|
char *name;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << TABLE_KEY_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check input arguments. */
|
|
if ((n_tokens != 2) ||
|
|
(strcmp(tokens[1], "exact") &&
|
|
strcmp(tokens[1], "wildcard") &&
|
|
strcmp(tokens[1], "lpm"))) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid match field statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!strcmp(tokens[1], "wildcard"))
|
|
match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
|
|
if (!strcmp(tokens[1], "lpm"))
|
|
match_type = RTE_SWX_TABLE_MATCH_LPM;
|
|
if (!strcmp(tokens[1], "exact"))
|
|
match_type = RTE_SWX_TABLE_MATCH_EXACT;
|
|
|
|
name = strdup(tokens[0]);
|
|
if (!name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_fields = realloc(s->params.fields,
|
|
(s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
|
|
if (!new_fields) {
|
|
free(name);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->params.fields = new_fields;
|
|
s->params.fields[s->params.n_fields].name = name;
|
|
s->params.fields[s->params.n_fields].match_type = match_type;
|
|
s->params.n_fields++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
table_actions_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid actions statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << TABLE_ACTIONS_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
table_actions_block_parse(struct table_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
const char **new_action_names;
|
|
char *name;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check input arguments. */
|
|
if (n_tokens != 1) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid action name statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
name = strdup(tokens[0]);
|
|
if (!name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_action_names = realloc(s->params.action_names,
|
|
(s->params.n_actions + 1) * sizeof(char *));
|
|
if (!new_action_names) {
|
|
free(name);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->params.action_names = new_action_names;
|
|
s->params.action_names[s->params.n_actions] = name;
|
|
s->params.n_actions++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
table_statement_parse(struct table_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid table statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << TABLE_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
table_block_parse(struct table_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
if (*block_mask & (1 << TABLE_KEY_BLOCK))
|
|
return table_key_block_parse(s,
|
|
block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
|
|
return table_actions_block_parse(s,
|
|
block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << TABLE_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "key"))
|
|
return table_key_statement_parse(block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (!strcmp(tokens[0], "actions"))
|
|
return table_actions_statement_parse(block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (!strcmp(tokens[0], "default_action")) {
|
|
if (((n_tokens != 4) && (n_tokens != 5)) ||
|
|
strcmp(tokens[2], "args") ||
|
|
strcmp(tokens[3], "none") ||
|
|
((n_tokens == 5) && strcmp(tokens[4], "const"))) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid default_action statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (s->params.default_action_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Duplicate default_action stmt.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.default_action_name = strdup(tokens[1]);
|
|
if (!s->params.default_action_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (n_tokens == 5)
|
|
s->params.default_action_is_const = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "instanceof")) {
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid instanceof statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (s->recommended_table_type_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Duplicate instanceof statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->recommended_table_type_name = strdup(tokens[1]);
|
|
if (!s->recommended_table_type_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "pragma")) {
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid pragma statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (s->args) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Duplicate pragma statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->args = strdup(tokens[1]);
|
|
if (!s->args) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "size")) {
|
|
char *p = tokens[1];
|
|
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid pragma statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->size = strtoul(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid size argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Anything else. */
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* selector.
|
|
*
|
|
* selector SELECTOR_NAME {
|
|
* group_id FIELD_NAME
|
|
* selector {
|
|
* FIELD_NAME
|
|
* ...
|
|
* }
|
|
* member_id FIELD_NAME
|
|
* n_groups N_GROUPS
|
|
* n_members_per_group N_MEMBERS_PER_GROUP
|
|
* }
|
|
*/
|
|
struct selector_spec {
|
|
char *name;
|
|
struct rte_swx_pipeline_selector_params params;
|
|
};
|
|
|
|
static void
|
|
selector_spec_free(struct selector_spec *s)
|
|
{
|
|
uintptr_t field_name;
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
/* name. */
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
/* params->group_id_field_name. */
|
|
field_name = (uintptr_t)s->params.group_id_field_name;
|
|
free((void *)field_name);
|
|
s->params.group_id_field_name = NULL;
|
|
|
|
/* params->selector_field_names. */
|
|
for (i = 0; i < s->params.n_selector_fields; i++) {
|
|
field_name = (uintptr_t)s->params.selector_field_names[i];
|
|
|
|
free((void *)field_name);
|
|
}
|
|
|
|
free(s->params.selector_field_names);
|
|
s->params.selector_field_names = NULL;
|
|
|
|
s->params.n_selector_fields = 0;
|
|
|
|
/* params->member_id_field_name. */
|
|
field_name = (uintptr_t)s->params.member_id_field_name;
|
|
free((void *)field_name);
|
|
s->params.member_id_field_name = NULL;
|
|
|
|
/* params->n_groups_max. */
|
|
s->params.n_groups_max = 0;
|
|
|
|
/* params->n_members_per_group_max. */
|
|
s->params.n_members_per_group_max = 0;
|
|
}
|
|
|
|
static int
|
|
selector_statement_parse(struct selector_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid selector statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << SELECTOR_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
selector_selector_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid selector statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
selector_selector_block_parse(struct selector_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
const char **new_fields;
|
|
char *name;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check input arguments. */
|
|
if (n_tokens != 1) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid selector field statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
name = strdup(tokens[0]);
|
|
if (!name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_fields = realloc(s->params.selector_field_names,
|
|
(s->params.n_selector_fields + 1) * sizeof(char *));
|
|
if (!new_fields) {
|
|
free(name);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->params.selector_field_names = new_fields;
|
|
s->params.selector_field_names[s->params.n_selector_fields] = name;
|
|
s->params.n_selector_fields++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
selector_block_parse(struct selector_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
|
|
return selector_selector_block_parse(s,
|
|
block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << SELECTOR_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "group_id")) {
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid group_id statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.group_id_field_name = strdup(tokens[1]);
|
|
if (!s->params.group_id_field_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "selector"))
|
|
return selector_selector_statement_parse(block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (!strcmp(tokens[0], "member_id")) {
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid member_id statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.member_id_field_name = strdup(tokens[1]);
|
|
if (!s->params.member_id_field_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "n_groups_max")) {
|
|
char *p = tokens[1];
|
|
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid n_groups statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.n_groups_max = strtoul(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid n_groups argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "n_members_per_group_max")) {
|
|
char *p = tokens[1];
|
|
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid n_members_per_group statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.n_members_per_group_max = strtoul(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid n_members_per_group argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Anything else. */
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* learner.
|
|
*
|
|
* learner {
|
|
* key {
|
|
* MATCH_FIELD_NAME
|
|
* ...
|
|
* }
|
|
* actions {
|
|
* ACTION_NAME
|
|
* ...
|
|
* }
|
|
* default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
|
|
* size SIZE
|
|
* timeout TIMEOUT_IN_SECONDS
|
|
* }
|
|
*/
|
|
struct learner_spec {
|
|
char *name;
|
|
struct rte_swx_pipeline_learner_params params;
|
|
uint32_t size;
|
|
uint32_t timeout;
|
|
};
|
|
|
|
static void
|
|
learner_spec_free(struct learner_spec *s)
|
|
{
|
|
uintptr_t default_action_name;
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
|
|
for (i = 0; i < s->params.n_fields; i++) {
|
|
uintptr_t name = (uintptr_t)s->params.field_names[i];
|
|
|
|
free((void *)name);
|
|
}
|
|
|
|
free(s->params.field_names);
|
|
s->params.field_names = NULL;
|
|
|
|
s->params.n_fields = 0;
|
|
|
|
for (i = 0; i < s->params.n_actions; i++) {
|
|
uintptr_t name = (uintptr_t)s->params.action_names[i];
|
|
|
|
free((void *)name);
|
|
}
|
|
|
|
free(s->params.action_names);
|
|
s->params.action_names = NULL;
|
|
|
|
s->params.n_actions = 0;
|
|
|
|
default_action_name = (uintptr_t)s->params.default_action_name;
|
|
free((void *)default_action_name);
|
|
s->params.default_action_name = NULL;
|
|
|
|
free(s->params.default_action_data);
|
|
s->params.default_action_data = NULL;
|
|
|
|
s->params.default_action_is_const = 0;
|
|
|
|
s->size = 0;
|
|
|
|
s->timeout = 0;
|
|
}
|
|
|
|
static int
|
|
learner_key_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid key statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << LEARNER_KEY_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
learner_key_block_parse(struct learner_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
const char **new_field_names = NULL;
|
|
char *field_name = NULL;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << LEARNER_KEY_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check input arguments. */
|
|
if (n_tokens != 1) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid match field statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
field_name = strdup(tokens[0]);
|
|
new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
|
|
if (!field_name || !new_field_names) {
|
|
free(field_name);
|
|
free(new_field_names);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->params.field_names = new_field_names;
|
|
s->params.field_names[s->params.n_fields] = field_name;
|
|
s->params.n_fields++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
learner_actions_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid actions statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
learner_actions_block_parse(struct learner_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
const char **new_action_names = NULL;
|
|
char *action_name = NULL;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* Check input arguments. */
|
|
if (n_tokens != 1) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid action name statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
action_name = strdup(tokens[0]);
|
|
|
|
new_action_names = realloc(s->params.action_names,
|
|
(s->params.n_actions + 1) * sizeof(char *));
|
|
|
|
if (!action_name || !new_action_names) {
|
|
free(action_name);
|
|
free(new_action_names);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->params.action_names = new_action_names;
|
|
s->params.action_names[s->params.n_actions] = action_name;
|
|
s->params.n_actions++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
learner_statement_parse(struct learner_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid learner statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << LEARNER_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
learner_block_parse(struct learner_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
if (*block_mask & (1 << LEARNER_KEY_BLOCK))
|
|
return learner_key_block_parse(s,
|
|
block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
|
|
return learner_actions_block_parse(s,
|
|
block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << LEARNER_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "key"))
|
|
return learner_key_statement_parse(block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (!strcmp(tokens[0], "actions"))
|
|
return learner_actions_statement_parse(block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
|
|
if (!strcmp(tokens[0], "default_action")) {
|
|
if (((n_tokens != 4) && (n_tokens != 5)) ||
|
|
strcmp(tokens[2], "args") ||
|
|
strcmp(tokens[3], "none") ||
|
|
((n_tokens == 5) && strcmp(tokens[4], "const"))) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid default_action statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (s->params.default_action_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Duplicate default_action stmt.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->params.default_action_name = strdup(tokens[1]);
|
|
if (!s->params.default_action_name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (n_tokens == 5)
|
|
s->params.default_action_is_const = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "size")) {
|
|
char *p = tokens[1];
|
|
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid size statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->size = strtoul(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid size argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(tokens[0], "timeout")) {
|
|
char *p = tokens[1];
|
|
|
|
if (n_tokens != 2) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid timeout statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
s->timeout = strtoul(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid timeout argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Anything else. */
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* regarray.
|
|
*
|
|
* regarray NAME size SIZE initval INITVAL
|
|
*/
|
|
struct regarray_spec {
|
|
char *name;
|
|
uint64_t init_val;
|
|
uint32_t size;
|
|
};
|
|
|
|
static void
|
|
regarray_spec_free(struct regarray_spec *s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
}
|
|
|
|
static int
|
|
regarray_statement_parse(struct regarray_spec *s,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
char *p;
|
|
|
|
/* Check format. */
|
|
if ((n_tokens != 6) ||
|
|
strcmp(tokens[2], "size") ||
|
|
strcmp(tokens[4], "initval")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid regarray statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
p = tokens[3];
|
|
s->size = strtoul(p, &p, 0);
|
|
if (p[0] || !s->size) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid size argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
p = tokens[5];
|
|
s->init_val = strtoull(p, &p, 0);
|
|
if (p[0]) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid initval argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* metarray.
|
|
*
|
|
* metarray NAME size SIZE
|
|
*/
|
|
struct metarray_spec {
|
|
char *name;
|
|
uint32_t size;
|
|
};
|
|
|
|
static void
|
|
metarray_spec_free(struct metarray_spec *s)
|
|
{
|
|
if (!s)
|
|
return;
|
|
|
|
free(s->name);
|
|
s->name = NULL;
|
|
}
|
|
|
|
static int
|
|
metarray_statement_parse(struct metarray_spec *s,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
char *p;
|
|
|
|
/* Check format. */
|
|
if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid metarray statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* spec. */
|
|
s->name = strdup(tokens[1]);
|
|
if (!s->name) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
p = tokens[3];
|
|
s->size = strtoul(p, &p, 0);
|
|
if (p[0] || !s->size) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid size argument.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* apply.
|
|
*
|
|
* apply {
|
|
* INSTRUCTION
|
|
* ...
|
|
* }
|
|
*/
|
|
struct apply_spec {
|
|
const char **instructions;
|
|
uint32_t n_instructions;
|
|
};
|
|
|
|
static void
|
|
apply_spec_free(struct apply_spec *s)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
for (i = 0; i < s->n_instructions; i++) {
|
|
uintptr_t instr = (uintptr_t)s->instructions[i];
|
|
|
|
free((void *)instr);
|
|
}
|
|
|
|
free(s->instructions);
|
|
s->instructions = NULL;
|
|
|
|
s->n_instructions = 0;
|
|
}
|
|
|
|
static int
|
|
apply_statement_parse(uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
/* Check format. */
|
|
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Invalid apply statement.";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* block_mask. */
|
|
*block_mask |= 1 << APPLY_BLOCK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
apply_block_parse(struct apply_spec *s,
|
|
uint32_t *block_mask,
|
|
char **tokens,
|
|
uint32_t n_tokens,
|
|
uint32_t n_lines,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
|
|
const char **new_instructions;
|
|
uint32_t i;
|
|
|
|
/* Handle end of block. */
|
|
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
|
*block_mask &= ~(1 << APPLY_BLOCK);
|
|
return 0;
|
|
}
|
|
|
|
/* spec. */
|
|
buffer[0] = 0;
|
|
for (i = 0; i < n_tokens; i++) {
|
|
if (i)
|
|
strcat(buffer, " ");
|
|
strcat(buffer, tokens[i]);
|
|
}
|
|
|
|
instr = strdup(buffer);
|
|
if (!instr) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
new_instructions = realloc(s->instructions,
|
|
(s->n_instructions + 1) * sizeof(char *));
|
|
if (!new_instructions) {
|
|
free(instr);
|
|
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Memory allocation failed.";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
s->instructions = new_instructions;
|
|
s->instructions[s->n_instructions] = instr;
|
|
s->n_instructions++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Pipeline.
|
|
*/
|
|
int
|
|
rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
|
FILE *spec,
|
|
uint32_t *err_line,
|
|
const char **err_msg)
|
|
{
|
|
struct extobj_spec extobj_spec = {0};
|
|
struct struct_spec struct_spec = {0};
|
|
struct header_spec header_spec = {0};
|
|
struct metadata_spec metadata_spec = {0};
|
|
struct action_spec action_spec = {0};
|
|
struct table_spec table_spec = {0};
|
|
struct selector_spec selector_spec = {0};
|
|
struct learner_spec learner_spec = {0};
|
|
struct regarray_spec regarray_spec = {0};
|
|
struct metarray_spec metarray_spec = {0};
|
|
struct apply_spec apply_spec = {0};
|
|
uint32_t n_lines;
|
|
uint32_t block_mask = 0;
|
|
int status;
|
|
|
|
/* Check the input arguments. */
|
|
if (!p) {
|
|
if (err_line)
|
|
*err_line = 0;
|
|
if (err_msg)
|
|
*err_msg = "Null pipeline arument.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
if (!spec) {
|
|
if (err_line)
|
|
*err_line = 0;
|
|
if (err_msg)
|
|
*err_msg = "Null specification file argument.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
for (n_lines = 1; ; n_lines++) {
|
|
char line[MAX_LINE_LENGTH];
|
|
char *tokens[MAX_TOKENS], *ptr = line;
|
|
uint32_t n_tokens = 0;
|
|
|
|
/* Read next line. */
|
|
if (!fgets(line, sizeof(line), spec))
|
|
break;
|
|
|
|
/* Parse the line into tokens. */
|
|
for ( ; ; ) {
|
|
char *token;
|
|
|
|
/* Get token. */
|
|
token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
|
|
if (!token)
|
|
break;
|
|
|
|
/* Handle comments. */
|
|
if ((token[0] == '#') ||
|
|
(token[0] == ';') ||
|
|
((token[0] == '/') && (token[1] == '/'))) {
|
|
break;
|
|
}
|
|
|
|
/* Handle excessively long lines. */
|
|
if (n_tokens >= MAX_TOKENS) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Too many tokens.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Handle excessively long tokens. */
|
|
if (strnlen(token, RTE_SWX_NAME_SIZE) >=
|
|
RTE_SWX_NAME_SIZE) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Token too big.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Save token. */
|
|
tokens[n_tokens] = token;
|
|
n_tokens++;
|
|
}
|
|
|
|
/* Handle empty lines. */
|
|
if (!n_tokens)
|
|
continue;
|
|
|
|
/* struct block. */
|
|
if (block_mask & (1 << STRUCT_BLOCK)) {
|
|
status = struct_block_parse(&struct_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << STRUCT_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_struct_type_register(p,
|
|
struct_spec.name,
|
|
struct_spec.fields,
|
|
struct_spec.n_fields,
|
|
struct_spec.varbit);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Struct registration error.";
|
|
goto error;
|
|
}
|
|
|
|
struct_spec_free(&struct_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* action block. */
|
|
if (block_mask & (1 << ACTION_BLOCK)) {
|
|
status = action_block_parse(&action_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << ACTION_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_action_config(p,
|
|
action_spec.name,
|
|
action_spec.args_struct_type_name,
|
|
action_spec.instructions,
|
|
action_spec.n_instructions);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Action config error.";
|
|
goto error;
|
|
}
|
|
|
|
action_spec_free(&action_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* table block. */
|
|
if (block_mask & (1 << TABLE_BLOCK)) {
|
|
status = table_block_parse(&table_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << TABLE_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_table_config(p,
|
|
table_spec.name,
|
|
&table_spec.params,
|
|
table_spec.recommended_table_type_name,
|
|
table_spec.args,
|
|
table_spec.size);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Table configuration error.";
|
|
goto error;
|
|
}
|
|
|
|
table_spec_free(&table_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* selector block. */
|
|
if (block_mask & (1 << SELECTOR_BLOCK)) {
|
|
status = selector_block_parse(&selector_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << SELECTOR_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_selector_config(p,
|
|
selector_spec.name,
|
|
&selector_spec.params);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Selector configuration error.";
|
|
goto error;
|
|
}
|
|
|
|
selector_spec_free(&selector_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* learner block. */
|
|
if (block_mask & (1 << LEARNER_BLOCK)) {
|
|
status = learner_block_parse(&learner_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << LEARNER_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_learner_config(p,
|
|
learner_spec.name,
|
|
&learner_spec.params,
|
|
learner_spec.size,
|
|
learner_spec.timeout);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Learner table configuration error.";
|
|
goto error;
|
|
}
|
|
|
|
learner_spec_free(&learner_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* apply block. */
|
|
if (block_mask & (1 << APPLY_BLOCK)) {
|
|
status = apply_block_parse(&apply_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
if (block_mask & (1 << APPLY_BLOCK))
|
|
continue;
|
|
|
|
/* End of block. */
|
|
status = rte_swx_pipeline_instructions_config(p,
|
|
apply_spec.instructions,
|
|
apply_spec.n_instructions);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Pipeline instructions err.";
|
|
goto error;
|
|
}
|
|
|
|
apply_spec_free(&apply_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* extobj. */
|
|
if (!strcmp(tokens[0], "extobj")) {
|
|
status = extobj_statement_parse(&extobj_spec,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
status = rte_swx_pipeline_extern_object_config(p,
|
|
extobj_spec.name,
|
|
extobj_spec.extern_type_name,
|
|
extobj_spec.pragma);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Extern object config err.";
|
|
goto error;
|
|
}
|
|
|
|
extobj_spec_free(&extobj_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* struct. */
|
|
if (!strcmp(tokens[0], "struct")) {
|
|
status = struct_statement_parse(&struct_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* header. */
|
|
if (!strcmp(tokens[0], "header")) {
|
|
status = header_statement_parse(&header_spec,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
status = rte_swx_pipeline_packet_header_register(p,
|
|
header_spec.name,
|
|
header_spec.struct_type_name);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Header registration error.";
|
|
goto error;
|
|
}
|
|
|
|
header_spec_free(&header_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* metadata. */
|
|
if (!strcmp(tokens[0], "metadata")) {
|
|
status = metadata_statement_parse(&metadata_spec,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
status = rte_swx_pipeline_packet_metadata_register(p,
|
|
metadata_spec.struct_type_name);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Meta-data reg err.";
|
|
goto error;
|
|
}
|
|
|
|
metadata_spec_free(&metadata_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* action. */
|
|
if (!strcmp(tokens[0], "action")) {
|
|
status = action_statement_parse(&action_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* table. */
|
|
if (!strcmp(tokens[0], "table")) {
|
|
status = table_statement_parse(&table_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* selector. */
|
|
if (!strcmp(tokens[0], "selector")) {
|
|
status = selector_statement_parse(&selector_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* learner. */
|
|
if (!strcmp(tokens[0], "learner")) {
|
|
status = learner_statement_parse(&learner_spec,
|
|
&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* regarray. */
|
|
if (!strcmp(tokens[0], "regarray")) {
|
|
status = regarray_statement_parse(®array_spec,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
status = rte_swx_pipeline_regarray_config(p,
|
|
regarray_spec.name,
|
|
regarray_spec.size,
|
|
regarray_spec.init_val);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Register array configuration error.";
|
|
goto error;
|
|
}
|
|
|
|
regarray_spec_free(®array_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* metarray. */
|
|
if (!strcmp(tokens[0], "metarray")) {
|
|
status = metarray_statement_parse(&metarray_spec,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
status = rte_swx_pipeline_metarray_config(p,
|
|
metarray_spec.name,
|
|
metarray_spec.size);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Meter array configuration error.";
|
|
goto error;
|
|
}
|
|
|
|
metarray_spec_free(&metarray_spec);
|
|
|
|
continue;
|
|
}
|
|
|
|
/* apply. */
|
|
if (!strcmp(tokens[0], "apply")) {
|
|
status = apply_statement_parse(&block_mask,
|
|
tokens,
|
|
n_tokens,
|
|
n_lines,
|
|
err_line,
|
|
err_msg);
|
|
if (status)
|
|
goto error;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* Anything else. */
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Unknown statement.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Handle unfinished block. */
|
|
if (block_mask) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Missing }.";
|
|
status = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
/* Pipeline build. */
|
|
status = rte_swx_pipeline_build(p);
|
|
if (status) {
|
|
if (err_line)
|
|
*err_line = n_lines;
|
|
if (err_msg)
|
|
*err_msg = "Pipeline build error.";
|
|
goto error;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
extobj_spec_free(&extobj_spec);
|
|
struct_spec_free(&struct_spec);
|
|
header_spec_free(&header_spec);
|
|
metadata_spec_free(&metadata_spec);
|
|
action_spec_free(&action_spec);
|
|
table_spec_free(&table_spec);
|
|
selector_spec_free(&selector_spec);
|
|
learner_spec_free(&learner_spec);
|
|
regarray_spec_free(®array_spec);
|
|
metarray_spec_free(&metarray_spec);
|
|
apply_spec_free(&apply_spec);
|
|
return status;
|
|
}
|