From: Yogesh Jangra Date: Mon, 18 Oct 2021 01:22:53 +0000 (-0400) Subject: pipeline: support action annotations X-Git-Url: http://git.droids-corp.org/?p=dpdk.git;a=commitdiff_plain;h=cd79e0205824cad872e7332976ee773522c3f475 pipeline: support action annotations Enable restricting the scope of an action to regular table entries or to the table default entry in order to support the P4 language tableonly or defaultonly annotations. Signed-off-by: Yogesh Jangra Acked-by: Cristian Dumitrescu --- diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c index 86b58e21dc..1c908e3e3f 100644 --- a/lib/pipeline/rte_swx_ctl.c +++ b/lib/pipeline/rte_swx_ctl.c @@ -1446,6 +1446,8 @@ rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl, CHECK(entry, EINVAL); CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL); + CHECK(table->actions[entry->action_id].action_is_for_table_entries, EINVAL); + new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1); CHECK(new_entry, ENOMEM); @@ -1651,6 +1653,8 @@ rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl, CHECK(entry, EINVAL); CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL); + CHECK(table->actions[entry->action_id].action_is_for_default_entry, EINVAL); + new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1); CHECK(new_entry, ENOMEM); @@ -2378,6 +2382,8 @@ rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl, CHECK(entry, EINVAL); CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL); + CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL); + new_entry = learner_default_entry_duplicate(ctl, learner_id, entry); CHECK(new_entry, ENOMEM); diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h index 807597229d..46d05823e1 100644 --- a/lib/pipeline/rte_swx_ctl.h +++ b/lib/pipeline/rte_swx_ctl.h @@ -301,6 +301,12 @@ rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, struct rte_swx_ctl_table_action_info { /** Action ID. */ uint32_t action_id; + + /** When non-zero (true), the action can be assigned to regular table entries. */ + int action_is_for_table_entries; + + /** When non-zero (true), the action can be assigned to the table default entry. */ + int action_is_for_default_entry; }; /** diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index 055056098d..5e089fb72b 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -7309,7 +7309,7 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, uint32_t size) { struct table_type *type; - struct table *t; + struct table *t = NULL; struct action *default_action; struct header *header = NULL; uint32_t action_data_size_max = 0, i; @@ -7336,6 +7336,7 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, const char *action_name = params->action_names[i]; struct action *a; uint32_t action_data_size; + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; CHECK_NAME(action_name, EINVAL); @@ -7346,6 +7347,12 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, action_data_size = a->st ? a->st->n_bits / 8 : 0; if (action_data_size > action_data_size_max) action_data_size_max = action_data_size; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); } CHECK_NAME(params->default_action_name, EINVAL); @@ -7354,6 +7361,9 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, params->default_action_name)) break; CHECK(i < params->n_actions, EINVAL); + CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], + EINVAL); + default_action = action_find(p, params->default_action_name); CHECK((default_action->st && params->default_action_data) || !params->default_action_data, EINVAL); @@ -7380,28 +7390,27 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, CHECK(t, ENOMEM); t->fields = calloc(params->n_fields, sizeof(struct match_field)); - if (!t->fields) { - free(t); - CHECK(0, ENOMEM); - } + if (!t->fields) + goto nomem; t->actions = calloc(params->n_actions, sizeof(struct action *)); - if (!t->actions) { - free(t->fields); - free(t); - CHECK(0, ENOMEM); - } + if (!t->actions) + goto nomem; if (action_data_size_max) { t->default_action_data = calloc(1, action_data_size_max); - if (!t->default_action_data) { - free(t->actions); - free(t->fields); - free(t); - CHECK(0, ENOMEM); - } + if (!t->default_action_data) + goto nomem; } + t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); + if (!t->action_is_for_table_entries) + goto nomem; + + t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); + if (!t->action_is_for_default_entry) + goto nomem; + /* Node initialization. */ strcpy(t->name, name); if (args && args[0]) @@ -7420,8 +7429,18 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, t->n_fields = params->n_fields; t->header = header; - for (i = 0; i < params->n_actions; i++) + for (i = 0; i < params->n_actions; i++) { + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + t->actions[i] = action_find(p, params->action_names[i]); + t->action_is_for_table_entries[i] = action_is_for_table_entries; + t->action_is_for_default_entry[i] = action_is_for_default_entry; + } t->default_action = default_action; if (default_action->st) memcpy(t->default_action_data, @@ -7439,6 +7458,19 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, p->n_tables++; return 0; + +nomem: + if (!t) + return -ENOMEM; + + free(t->action_is_for_default_entry); + free(t->action_is_for_table_entries); + free(t->default_action_data); + free(t->actions); + free(t->fields); + free(t); + + return -ENOMEM; } static struct rte_swx_table_params * @@ -8179,12 +8211,12 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, /* Action checks. */ CHECK(params->n_actions, EINVAL); - CHECK(params->action_names, EINVAL); for (i = 0; i < params->n_actions; i++) { const char *action_name = params->action_names[i]; struct action *a; uint32_t action_data_size; + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; CHECK_NAME(action_name, EINVAL); @@ -8201,6 +8233,12 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, action_data_size = a->st ? a->st->n_bits / 8 : 0; if (action_data_size > action_data_size_max) action_data_size_max = action_data_size; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); } CHECK_NAME(params->default_action_name, EINVAL); @@ -8209,6 +8247,8 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, params->default_action_name)) break; CHECK(i < params->n_actions, EINVAL); + CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], + EINVAL); default_action = action_find(p, params->default_action_name); CHECK((default_action->st && params->default_action_data) || @@ -8237,6 +8277,14 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, goto nomem; } + l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); + if (!l->action_is_for_table_entries) + goto nomem; + + l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); + if (!l->action_is_for_default_entry) + goto nomem; + /* Node initialization. */ strcpy(l->name, name); @@ -8252,8 +8300,18 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, l->header = header; - for (i = 0; i < params->n_actions; i++) + for (i = 0; i < params->n_actions; i++) { + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + l->actions[i] = action_find(p, params->action_names[i]); + l->action_is_for_table_entries[i] = action_is_for_table_entries; + l->action_is_for_default_entry[i] = action_is_for_default_entry; + } l->default_action = default_action; @@ -8284,6 +8342,9 @@ nomem: if (!l) return -ENOMEM; + free(l->action_is_for_default_entry); + free(l->action_is_for_table_entries); + free(l->default_action_data); free(l->actions); free(l->fields); free(l); @@ -9277,6 +9338,9 @@ rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, table_action->action_id = t->actions[table_action_id]->id; + table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; + table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; + return 0; } @@ -9464,6 +9528,12 @@ rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, learner_action->action_id = l->actions[learner_action_id]->id; + learner_action->action_is_for_table_entries = + l->action_is_for_table_entries[learner_action_id]; + + learner_action->action_is_for_default_entry = + l->action_is_for_default_entry[learner_action_id]; + return 0; } diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h index 490ff60c0d..9c3d08199c 100644 --- a/lib/pipeline/rte_swx_pipeline.h +++ b/lib/pipeline/rte_swx_pipeline.h @@ -567,6 +567,20 @@ struct rte_swx_pipeline_table_params { /** The set of actions for the current table. */ const char **action_names; + /** Array of *n_actions* flags. For each action, the associated flag + * indicates whether the action can be assigned to regular table entries + * (when non-zero, i.e. true) or not (when zero, i.e. false). When set + * to NULL, it defaults to true for all actions. + */ + int *action_is_for_table_entries; + + /** Array of *n_actions* flags. For each action, the associated flag + * indicates whether the action can be assigned to the default table + * entry (when non-zero, i.e. true) or not (when zero, i.e. false). + * When set to NULL, it defaults to true for all actions. + */ + int *action_is_for_default_entry; + /** The number of actions for the current table. Must be at least one. */ uint32_t n_actions; @@ -692,6 +706,20 @@ struct rte_swx_pipeline_learner_params { /** The set of actions for the current table. */ const char **action_names; + /** Array of *n_actions* flags. For each action, the associated flag + * indicates whether the action can be assigned to regular table entries + * (when non-zero, i.e. true) or not (when zero, i.e. false). When set + * to NULL, it defaults to true for all actions. + */ + int *action_is_for_table_entries; + + /** Array of *n_actions* flags. For each action, the associated flag + * indicates whether the action can be assigned to the default table + * entry (when non-zero, i.e. true) or not (when zero, i.e. false). + * When set to NULL, it defaults to true for all actions. + */ + int *action_is_for_default_entry; + /** The number of actions for the current table. Must be at least one. */ uint32_t n_actions; diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h index 4361c535a0..1921fdcd78 100644 --- a/lib/pipeline/rte_swx_pipeline_internal.h +++ b/lib/pipeline/rte_swx_pipeline_internal.h @@ -746,6 +746,8 @@ struct table { uint32_t n_actions; int default_action_is_const; uint32_t action_data_size_max; + int *action_is_for_table_entries; + int *action_is_for_default_entry; uint32_t size; uint32_t id; @@ -815,6 +817,8 @@ struct learner { uint32_t n_actions; int default_action_is_const; uint32_t action_data_size_max; + int *action_is_for_table_entries; + int *action_is_for_default_entry; uint32_t size; uint32_t timeout; diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c index 5c21a7ae4d..8e9aa44e30 100644 --- a/lib/pipeline/rte_swx_pipeline_spec.c +++ b/lib/pipeline/rte_swx_pipeline_spec.c @@ -539,7 +539,7 @@ action_block_parse(struct action_spec *s, * ... * } * actions { - * ACTION_NAME + * ACTION_NAME [ @tableonly | @defaultonly ] * ... * } * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] @@ -597,6 +597,12 @@ table_spec_free(struct table_spec *s) 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); @@ -730,8 +736,10 @@ table_actions_block_parse(struct table_spec *s, 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], "}")) { @@ -740,7 +748,9 @@ table_actions_block_parse(struct table_spec *s, } /* 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) @@ -749,18 +759,30 @@ table_actions_block_parse(struct table_spec *s, } 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; @@ -771,6 +793,13 @@ table_actions_block_parse(struct table_spec *s, 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; @@ -1293,7 +1322,7 @@ selector_block_parse(struct selector_spec *s, * ... * } * actions { - * ACTION_NAME + * ACTION_NAME [ @tableonly | @defaultonly] * ... * } * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] @@ -1349,6 +1378,12 @@ learner_spec_free(struct learner_spec *s) 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; s->size = 0; @@ -1459,7 +1494,9 @@ learner_actions_block_parse(struct learner_spec *s, const char **err_msg) { const char **new_action_names = NULL; - char *action_name = 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], "}")) { @@ -1468,7 +1505,9 @@ learner_actions_block_parse(struct learner_spec *s, } /* 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) @@ -1476,14 +1515,31 @@ learner_actions_block_parse(struct learner_spec *s, return -EINVAL; } - action_name = strdup(tokens[0]); + 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 *)); - - if (!action_name || !new_action_names) { - free(action_name); + 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; @@ -1493,7 +1549,14 @@ learner_actions_block_parse(struct learner_spec *s, } s->params.action_names = new_action_names; - s->params.action_names[s->params.n_actions] = action_name; + 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;