pipeline: support action annotations
authorYogesh Jangra <yogesh.jangra@intel.com>
Mon, 18 Oct 2021 01:22:53 +0000 (21:22 -0400)
committerThomas Monjalon <thomas@monjalon.net>
Mon, 25 Oct 2021 12:53:28 +0000 (14:53 +0200)
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@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
lib/pipeline/rte_swx_ctl.c
lib/pipeline/rte_swx_ctl.h
lib/pipeline/rte_swx_pipeline.c
lib/pipeline/rte_swx_pipeline.h
lib/pipeline/rte_swx_pipeline_internal.h
lib/pipeline/rte_swx_pipeline_spec.c

index 86b58e2..1c908e3 100644 (file)
@@ -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);
 
index 8075972..46d0582 100644 (file)
@@ -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;
 };
 
 /**
index 0550560..5e089fb 100644 (file)
@@ -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;
 }
 
index 490ff60..9c3d081 100644 (file)
@@ -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;
index 4361c53..1921fdc 100644 (file)
@@ -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;
index 5c21a7a..8e9aa44 100644 (file)
@@ -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;