+ * table.
+ *
+ * table {
+ * key {
+ * MATCH_FIELD_NAME exact | wildcard | lpm
+ * ...
+ * }
+ * actions {
+ * ACTION_NAME [ @tableonly | @defaultonly ]
+ * ...
+ * }
+ * 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;
+
+ 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;
+
+ 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 = 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 << TABLE_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
+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.