#include <string.h>
#include <errno.h>
+#include <rte_common.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
+#ifndef MAX_LINE_LENGTH
+#define MAX_LINE_LENGTH 2048
+#endif
+
+#ifndef MAX_TOKENS
+#define MAX_TOKENS 256
+#endif
#define STRUCT_BLOCK 0
#define ACTION_BLOCK 1
#define TABLE_BLOCK 2
#define TABLE_KEY_BLOCK 3
#define TABLE_ACTIONS_BLOCK 4
-#define APPLY_BLOCK 5
+#define SELECTOR_BLOCK 5
+#define SELECTOR_SELECTOR_BLOCK 6
+#define LEARNER_BLOCK 7
+#define LEARNER_KEY_BLOCK 8
+#define LEARNER_ACTIONS_BLOCK 9
+#define LEARNER_TIMEOUT_BLOCK 10
+#define APPLY_BLOCK 11
/*
* extobj.
* struct.
*
* struct STRUCT_TYPE_NAME {
- * bit<SIZE> FIELD_NAME
+ * bit<SIZE> | varbit<SIZE> FIELD_NAME
* ...
* }
*/
char *name;
struct rte_swx_field_params *fields;
uint32_t n_fields;
+ int varbit;
};
static void
s->fields = NULL;
s->n_fields = 0;
+
+ s->varbit = 0;
}
static int
const char **err_msg)
{
struct rte_swx_field_params *new_fields;
- char *p = tokens[0], *name;
+ 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], "}")) {
}
/* Check format. */
- if ((n_tokens != 2) ||
- (strlen(p) < 6) ||
- (p[0] != 'b') ||
- (p[1] != 'i') ||
- (p[2] != 't') ||
- (p[3] != '<') ||
- (p[strlen(p) - 1] != '>')) {
- if (err_line)
- *err_line = n_lines;
- if (err_msg)
- *err_msg = "Invalid struct field statement.";
- return -EINVAL;
+ if (n_tokens != 2) {
+ error = -EINVAL;
+ goto error;
+ }
+
+ if (s->varbit) {
+ error = -EINVAL;
+ error_varbit_not_last = 1;
+ goto error;
}
- /* Remove the "bit<" and ">". */
- p[strlen(p) - 1] = 0;
- p += 4;
+ 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)) {
- if (err_line)
- *err_line = n_lines;
- if (err_msg)
- *err_msg = "Invalid struct field size.";
- return -EINVAL;
+ ((n_bits > 64) && !varbit)) {
+ error = -EINVAL;
+ error_size_invalid = 1;
+ goto error;
}
/* spec. */
name = strdup(tokens[1]);
if (!name) {
- if (err_line)
- *err_line = n_lines;
- if (err_msg)
- *err_msg = "Memory allocation failed.";
- return -ENOMEM;
+ error = -ENOMEM;
+ goto error;
}
- new_fields = realloc(s->fields,
- (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
+ new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
if (!new_fields) {
- free(name);
-
- if (err_line)
- *err_line = n_lines;
- if (err_msg)
- *err_msg = "Memory allocation failed.";
- return -ENOMEM;
+ 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;
}
/*
/*
* table.
*
- * table {
+ * table TABLE_NAME {
* key {
* MATCH_FIELD_NAME exact | wildcard | lpm
* ...
* }
* actions {
- * ACTION_NAME
+ * ACTION_NAME [ @tableonly | @defaultonly ]
* ...
* }
- * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
+ * default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
* instanceof TABLE_TYPE_NAME
* pragma ARGS
* size SIZE
static void
table_spec_free(struct table_spec *s)
{
- uintptr_t default_action_name;
+ uintptr_t default_action_name, default_action_args;
uint32_t i;
if (!s)
free((void *)default_action_name);
s->params.default_action_name = NULL;
- free(s->params.default_action_data);
- s->params.default_action_data = NULL;
+ default_action_args = (uintptr_t)s->params.default_action_args;
+ free((void *)default_action_args);
+ s->params.default_action_args = NULL;
+
+ free(s->params.action_is_for_table_entries);
+ s->params.action_is_for_table_entries = NULL;
+
+ free(s->params.action_is_for_default_entry);
+ s->params.action_is_for_default_entry = NULL;
s->params.default_action_is_const = 0;
uint32_t *err_line,
const char **err_msg)
{
- const char **new_action_names;
- char *name;
+ const char **new_action_names = NULL;
+ int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
+ char *name = NULL;
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
/* Handle end of block. */
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
}
/* Check input arguments. */
- if (n_tokens != 1) {
+ if ((n_tokens > 2) ||
+ ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
+ strcmp(tokens[1], "@defaultonly"))) {
if (err_line)
*err_line = n_lines;
if (err_msg)
}
name = strdup(tokens[0]);
- if (!name) {
- if (err_line)
- *err_line = n_lines;
- if (err_msg)
- *err_msg = "Memory allocation failed.";
- return -ENOMEM;
+
+ if (n_tokens == 2) {
+ if (!strcmp(tokens[1], "@tableonly"))
+ action_is_for_default_entry = 0;
+
+ if (!strcmp(tokens[1], "@defaultonly"))
+ action_is_for_table_entries = 0;
}
new_action_names = realloc(s->params.action_names,
(s->params.n_actions + 1) * sizeof(char *));
- if (!new_action_names) {
+ new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
+ (s->params.n_actions + 1) * sizeof(int));
+ new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
+ (s->params.n_actions + 1) * sizeof(int));
+
+ if (!name ||
+ !new_action_names ||
+ !new_action_is_for_table_entries ||
+ !new_action_is_for_default_entry) {
free(name);
+ free(new_action_names);
+ free(new_action_is_for_table_entries);
+ free(new_action_is_for_default_entry);
if (err_line)
*err_line = n_lines;
s->params.action_names = new_action_names;
s->params.action_names[s->params.n_actions] = name;
+
+ s->params.action_is_for_table_entries = new_action_is_for_table_entries;
+ s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
+
+ s->params.action_is_for_default_entry = new_action_is_for_default_entry;
+ s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
+
s->params.n_actions++;
return 0;
}
+static int
+table_default_action_statement_parse(struct table_spec *s,
+ char **tokens,
+ uint32_t n_tokens,
+ uint32_t n_lines,
+ uint32_t *err_line,
+ const char **err_msg)
+{
+ uint32_t i;
+ int status = 0, duplicate = 0;
+
+ /* Check format. */
+ if ((n_tokens < 4) ||
+ strcmp(tokens[2], "args")) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ if (s->params.default_action_name) {
+ duplicate = 1;
+ status = -EINVAL;
+ goto error;
+ }
+
+ s->params.default_action_name = strdup(tokens[1]);
+ if (!s->params.default_action_name) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ if (strcmp(tokens[3], "none")) {
+ char buffer[MAX_LINE_LENGTH];
+ uint32_t n_tokens_args = n_tokens - 3;
+
+ if (!strcmp(tokens[n_tokens - 1], "const"))
+ n_tokens_args--;
+
+ if (!n_tokens_args) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ buffer[0] = 0;
+ for (i = 0; i < n_tokens_args; i++) {
+ if (i)
+ strcat(buffer, " ");
+
+ strcat(buffer, tokens[3 + i]);
+ }
+
+ s->params.default_action_args = strdup(buffer);
+ if (!s->params.default_action_args) {
+ status = -ENOMEM;
+ goto error;
+ }
+ } else {
+ if (((n_tokens != 4) && (n_tokens != 5)) ||
+ ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
+ status = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (!strcmp(tokens[n_tokens - 1], "const"))
+ s->params.default_action_is_const = 1;
+
+ return 0;
+
+error:
+ if (err_line)
+ *err_line = n_lines;
+
+ if (err_msg)
+ switch (status) {
+ case -ENOMEM:
+ *err_msg = "Memory allocation failed.";
+ break;
+
+ default:
+ if (duplicate)
+ *err_msg = "Duplicate default_action statement.";
+
+ *err_msg = "Invalid default_action statement.";
+ }
+
+ return status;
+}
+
static int
table_statement_parse(struct table_spec *s,
uint32_t *block_mask,
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], "default_action"))
+ return table_default_action_statement_parse(s,
+ tokens,
+ n_tokens,
+ n_lines,
+ err_line,
+ err_msg);
if (!strcmp(tokens[0], "instanceof")) {
if (n_tokens != 2) {
}
/*
- * regarray.
+ * selector.
*
- * regarray NAME size SIZE initval INITVAL
+ * 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 regarray_spec {
+struct selector_spec {
char *name;
- uint64_t init_val;
- uint32_t size;
+ struct rte_swx_pipeline_selector_params params;
};
static void
-regarray_spec_free(struct regarray_spec *s)
+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
-regarray_statement_parse(struct regarray_spec *s,
+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)
{
- char *p;
-
/* Check format. */
- if ((n_tokens != 6) ||
- strcmp(tokens[2], "size") ||
- strcmp(tokens[4], "initval")) {
+ if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
if (err_line)
*err_line = n_lines;
if (err_msg)
- *err_msg = "Invalid regarray statement.";
+ *err_msg = "Invalid selector statement.";
return -EINVAL;
}
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;
- }
+ /* block_mask. */
+ *block_mask |= 1 << SELECTOR_BLOCK;
- p = tokens[5];
- s->init_val = strtoull(p, &p, 0);
- if (p[0]) {
+ 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 initval argument.";
+ *err_msg = "Invalid selector statement.";
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;
+ /* block_mask. */
+ *block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
- free(s->name);
- s->name = NULL;
+ return 0;
}
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)
+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)
{
- char *p;
+ const char **new_fields;
+ char *name;
- /* Check format. */
- if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
+ /* 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 metarray statement.";
+ *err_msg = "Invalid selector field statement.";
return -EINVAL;
}
- /* spec. */
- s->name = strdup(tokens[1]);
- if (!s->name) {
+ name = strdup(tokens[0]);
+ if (!name) {
if (err_line)
*err_line = n_lines;
if (err_msg)
return -ENOMEM;
}
- p = tokens[3];
- s->size = strtoul(p, &p, 0);
- if (p[0] || !s->size) {
+ 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 = "Invalid size argument.";
- return -EINVAL;
+ *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;
}
-/*
- * apply.
- *
- * apply {
- * INSTRUCTION
- * ...
- * }
- */
-struct apply_spec {
+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 LEARNER_NAME {
+ * key {
+ * MATCH_FIELD_NAME
+ * ...
+ * }
+ * actions {
+ * ACTION_NAME [ @tableonly | @defaultonly]
+ * ...
+ * }
+ * default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ 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;
+ uint32_t n_timeouts;
+};
+
+static void
+learner_spec_free(struct learner_spec *s)
+{
+ uintptr_t default_action_name, default_action_args;
+ 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;
+
+ default_action_args = (uintptr_t)s->params.default_action_args;
+ free((void *)default_action_args);
+ s->params.default_action_args = NULL;
+
+ free(s->params.action_is_for_table_entries);
+ s->params.action_is_for_table_entries = NULL;
+
+ free(s->params.action_is_for_default_entry);
+ s->params.action_is_for_default_entry = NULL;
+
+ s->params.default_action_is_const = 0;
+
+ s->size = 0;
+
+ free(s->timeout);
+ s->timeout = NULL;
+
+ s->n_timeouts = 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;
+ int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
+ char *name = NULL;
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
+
+ /* 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 > 2) ||
+ ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
+ strcmp(tokens[1], "@defaultonly"))) {
+ if (err_line)
+ *err_line = n_lines;
+ if (err_msg)
+ *err_msg = "Invalid action name statement.";
+ return -EINVAL;
+ }
+
+ name = strdup(tokens[0]);
+
+ if (n_tokens == 2) {
+ if (!strcmp(tokens[1], "@tableonly"))
+ action_is_for_default_entry = 0;
+
+ if (!strcmp(tokens[1], "@defaultonly"))
+ action_is_for_table_entries = 0;
+ }
+
+ new_action_names = realloc(s->params.action_names,
+ (s->params.n_actions + 1) * sizeof(char *));
+ new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
+ (s->params.n_actions + 1) * sizeof(int));
+ new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
+ (s->params.n_actions + 1) * sizeof(int));
+
+ if (!name ||
+ !new_action_names ||
+ !new_action_is_for_table_entries ||
+ !new_action_is_for_default_entry) {
+ free(name);
+ free(new_action_names);
+ free(new_action_is_for_table_entries);
+ free(new_action_is_for_default_entry);
+
+ 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.action_is_for_table_entries = new_action_is_for_table_entries;
+ s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
+
+ s->params.action_is_for_default_entry = new_action_is_for_default_entry;
+ s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
+
+ s->params.n_actions++;
+
+ return 0;
+}
+
+static int
+learner_default_action_statement_parse(struct learner_spec *s,
+ char **tokens,
+ uint32_t n_tokens,
+ uint32_t n_lines,
+ uint32_t *err_line,
+ const char **err_msg)
+{
+ uint32_t i;
+ int status = 0, duplicate = 0;
+
+ /* Check format. */
+ if ((n_tokens < 4) ||
+ strcmp(tokens[2], "args")) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ if (s->params.default_action_name) {
+ duplicate = 1;
+ status = -EINVAL;
+ goto error;
+ }
+
+ s->params.default_action_name = strdup(tokens[1]);
+ if (!s->params.default_action_name) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ if (strcmp(tokens[3], "none")) {
+ char buffer[MAX_LINE_LENGTH];
+ uint32_t n_tokens_args = n_tokens - 3;
+
+ if (!strcmp(tokens[n_tokens - 1], "const"))
+ n_tokens_args--;
+
+ if (!n_tokens_args) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ buffer[0] = 0;
+ for (i = 0; i < n_tokens_args; i++) {
+ if (i)
+ strcat(buffer, " ");
+
+ strcat(buffer, tokens[3 + i]);
+ }
+
+ s->params.default_action_args = strdup(buffer);
+ if (!s->params.default_action_args) {
+ status = -ENOMEM;
+ goto error;
+ }
+ } else {
+ if (((n_tokens != 4) && (n_tokens != 5)) ||
+ ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
+ status = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (!strcmp(tokens[n_tokens - 1], "const"))
+ s->params.default_action_is_const = 1;
+
+ return 0;
+
+error:
+ if (err_line)
+ *err_line = n_lines;
+
+ if (err_msg)
+ switch (status) {
+ case -ENOMEM:
+ *err_msg = "Memory allocation failed.";
+ break;
+
+ default:
+ if (duplicate)
+ *err_msg = "Duplicate default_action statement.";
+
+ *err_msg = "Invalid default_action statement.";
+ }
+
+ return status;
+}
+
+static int
+learner_timeout_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 timeout statement.";
+ return -EINVAL;
+ }
+
+ /* block_mask. */
+ *block_mask |= 1 << LEARNER_TIMEOUT_BLOCK;
+
+ return 0;
+}
+
+static int
+learner_timeout_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)
+{
+ uint32_t *new_timeout = NULL;
+ char *str;
+ uint32_t val;
+ int status = 0;
+
+ /* Handle end of block. */
+ if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
+ *block_mask &= ~(1 << LEARNER_TIMEOUT_BLOCK);
+ return 0;
+ }
+
+ /* Check input arguments. */
+ if (n_tokens != 1) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ str = tokens[0];
+ val = strtoul(str, &str, 0);
+ if (str[0]) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ new_timeout = realloc(s->timeout, (s->n_timeouts + 1) * sizeof(uint32_t));
+ if (!new_timeout) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ s->timeout = new_timeout;
+ s->timeout[s->n_timeouts] = val;
+ s->n_timeouts++;
+
+ return 0;
+
+error:
+ free(new_timeout);
+
+ if (err_line)
+ *err_line = n_lines;
+
+ if (err_msg)
+ switch (status) {
+ case -ENOMEM:
+ *err_msg = "Memory allocation failed.";
+ break;
+
+ default:
+ *err_msg = "Invalid timeout value statement.";
+ break;
+ }
+
+ return status;
+}
+
+
+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);
+
+ if (*block_mask & (1 << LEARNER_TIMEOUT_BLOCK))
+ return learner_timeout_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"))
+ return learner_default_action_statement_parse(s,
+ tokens,
+ n_tokens,
+ n_lines,
+ err_line,
+ err_msg);
+
+ 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"))
+ return learner_timeout_statement_parse(block_mask,
+ tokens,
+ n_tokens,
+ n_lines,
+ err_line,
+ err_msg);
+
+ /* 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;
};
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};
if (err_line)
*err_line = 0;
if (err_msg)
- *err_msg = "Null pipeline arument.";
+ *err_msg = "Null pipeline argument.";
status = -EINVAL;
goto error;
}
}
/* Handle excessively long lines. */
- if (n_tokens >= MAX_TOKENS) {
+ if (n_tokens >= RTE_DIM(tokens)) {
if (err_line)
*err_line = n_lines;
if (err_msg)
status = rte_swx_pipeline_struct_type_register(p,
struct_spec.name,
struct_spec.fields,
- struct_spec.n_fields);
+ struct_spec.n_fields,
+ struct_spec.varbit);
if (status) {
if (err_line)
*err_line = n_lines;
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,
+ learner_spec.n_timeouts);
+ 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,
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,
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);