From patchwork Thu Oct 14 11:09:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yogesh Jangra X-Patchwork-Id: 101675 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C85F4A0C4B; Thu, 14 Oct 2021 20:21:35 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5D16840041; Thu, 14 Oct 2021 20:21:35 +0200 (CEST) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id ED6994003C for ; Thu, 14 Oct 2021 20:21:32 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10137"; a="291245241" X-IronPort-AV: E=Sophos;i="5.85,373,1624345200"; d="scan'208";a="291245241" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Oct 2021 11:21:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.85,373,1624345200"; d="scan'208";a="492136738" Received: from ena-4.iind.intel.com ([10.190.200.151]) by orsmga008.jf.intel.com with ESMTP; 14 Oct 2021 11:21:25 -0700 From: Yogesh Jangra To: dev@dpdk.org Cc: cristian.dumitrescu@intel.com, venkata.suresh.kumar.p@intel.com, yogesh.jangra@intel.com Date: Thu, 14 Oct 2021 07:09:03 -0400 Message-Id: <1634209743-93477-1-git-send-email-yogesh.jangra@intel.com> X-Mailer: git-send-email 1.8.3.1 Subject: [dpdk-dev] [PATCH] pipeline: add support for action annotations X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- lib/pipeline/rte_swx_ctl.c | 6 ++ lib/pipeline/rte_swx_ctl.h | 6 ++ lib/pipeline/rte_swx_pipeline.c | 105 +++++++++++++++++++++++++------ lib/pipeline/rte_swx_pipeline.h | 28 +++++++++ lib/pipeline/rte_swx_pipeline_internal.h | 4 ++ lib/pipeline/rte_swx_pipeline_spec.c | 101 +++++++++++++++++++++++------ 6 files changed, 212 insertions(+), 38 deletions(-) diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c index 86b58e2..1c908e3 100644 --- a/lib/pipeline/rte_swx_ctl.c +++ b/lib/pipeline/rte_swx_ctl.c @@ -1446,6 +1446,8 @@ struct rte_swx_ctl_pipeline * 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 @@ struct rte_swx_ctl_pipeline * 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 @@ struct rte_swx_ctl_pipeline * 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 8075972..46d0582 100644 --- a/lib/pipeline/rte_swx_ctl.h +++ b/lib/pipeline/rte_swx_ctl.h @@ -301,6 +301,12 @@ struct rte_swx_ctl_table_match_field_info { 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 1cd09a4..f96d6ba 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -7309,7 +7309,7 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(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 @@ struct_field_parse(struct rte_swx_pipeline *p, 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 @@ struct meter_profile meter_profile_default = { 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,9 @@ struct meter_profile meter_profile_default = { 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 490ff60..9c3d081 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 4361c53..1921fdc 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 5c21a7a..8e9aa44 100644 --- a/lib/pipeline/rte_swx_pipeline_spec.c +++ b/lib/pipeline/rte_swx_pipeline_spec.c @@ -539,7 +539,7 @@ struct action_spec { * ... * } * actions { - * ACTION_NAME + * ACTION_NAME [ @tableonly | @defaultonly ] * ... * } * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] @@ -597,6 +597,12 @@ struct table_spec { 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 @@ struct table_spec { 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 @@ struct table_spec { } /* 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 @@ struct table_spec { } 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 @@ struct table_spec { 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 @@ struct selector_spec { * ... * } * actions { - * ACTION_NAME + * ACTION_NAME [ @tableonly | @defaultonly] * ... * } * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] @@ -1349,6 +1378,12 @@ struct learner_spec { 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 @@ struct learner_spec { 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 @@ struct learner_spec { } /* 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 @@ struct learner_spec { 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 @@ struct learner_spec { } 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;