[dpdk-dev] [PATCH v2] pipeline: add support for action annotations
Yogesh Jangra
yogesh.jangra at intel.com
Mon Oct 18 03:22:53 CEST 2021
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 <yogesh.jangra at intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu at intel.com>
---
lib/pipeline/rte_swx_ctl.c | 6 ++
lib/pipeline/rte_swx_ctl.h | 6 ++
lib/pipeline/rte_swx_pipeline.c | 108 +++++++++++++++++++++++++------
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, 215 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..ff3dfd1 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,12 @@ 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;
--
1.8.3.1
More information about the dev
mailing list