test/bonding: fix RSS test when disable RSS
[dpdk.git] / app / test-pmd / cmdline_flow.c
index 1aa32ea..cfd55c5 100644 (file)
@@ -58,6 +58,8 @@ enum index {
        COMMON_FLEX_TOKEN,
        COMMON_PATTERN_TEMPLATE_ID,
        COMMON_ACTIONS_TEMPLATE_ID,
+       COMMON_TABLE_ID,
+       COMMON_QUEUE_ID,
 
        /* TOP-level command. */
        ADD,
@@ -78,6 +80,7 @@ enum index {
        CONFIGURE,
        PATTERN_TEMPLATE,
        ACTIONS_TEMPLATE,
+       TABLE,
        INDIRECT_ACTION,
        VALIDATE,
        CREATE,
@@ -90,6 +93,9 @@ enum index {
        ISOLATE,
        TUNNEL,
        FLEX,
+       QUEUE,
+       PUSH,
+       PULL,
 
        /* Flex arguments */
        FLEX_ITEM_INIT,
@@ -118,6 +124,63 @@ enum index {
        ACTIONS_TEMPLATE_SPEC,
        ACTIONS_TEMPLATE_MASK,
 
+       /* Queue arguments. */
+       QUEUE_CREATE,
+       QUEUE_DESTROY,
+       QUEUE_INDIRECT_ACTION,
+
+       /* Queue create arguments. */
+       QUEUE_CREATE_ID,
+       QUEUE_CREATE_POSTPONE,
+       QUEUE_TEMPLATE_TABLE,
+       QUEUE_PATTERN_TEMPLATE,
+       QUEUE_ACTIONS_TEMPLATE,
+       QUEUE_SPEC,
+
+       /* Queue destroy arguments. */
+       QUEUE_DESTROY_ID,
+       QUEUE_DESTROY_POSTPONE,
+
+       /* Queue indirect action arguments */
+       QUEUE_INDIRECT_ACTION_CREATE,
+       QUEUE_INDIRECT_ACTION_UPDATE,
+       QUEUE_INDIRECT_ACTION_DESTROY,
+
+       /* Queue indirect action create arguments */
+       QUEUE_INDIRECT_ACTION_CREATE_ID,
+       QUEUE_INDIRECT_ACTION_INGRESS,
+       QUEUE_INDIRECT_ACTION_EGRESS,
+       QUEUE_INDIRECT_ACTION_TRANSFER,
+       QUEUE_INDIRECT_ACTION_CREATE_POSTPONE,
+       QUEUE_INDIRECT_ACTION_SPEC,
+
+       /* Queue indirect action update arguments */
+       QUEUE_INDIRECT_ACTION_UPDATE_POSTPONE,
+
+       /* Queue indirect action destroy arguments */
+       QUEUE_INDIRECT_ACTION_DESTROY_ID,
+       QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE,
+
+       /* Push arguments. */
+       PUSH_QUEUE,
+
+       /* Pull arguments. */
+       PULL_QUEUE,
+
+       /* Table arguments. */
+       TABLE_CREATE,
+       TABLE_DESTROY,
+       TABLE_CREATE_ID,
+       TABLE_DESTROY_ID,
+       TABLE_GROUP,
+       TABLE_PRIORITY,
+       TABLE_INGRESS,
+       TABLE_EGRESS,
+       TABLE_TRANSFER,
+       TABLE_RULES_NUMBER,
+       TABLE_PATTERN_TEMPLATE,
+       TABLE_ACTIONS_TEMPLATE,
+
        /* Tunnel arguments. */
        TUNNEL_CREATE,
        TUNNEL_CREATE_TYPE,
@@ -732,7 +795,8 @@ static const char *const modify_field_ids[] = {
        "tcp_seq_num", "tcp_ack_num", "tcp_flags",
        "udp_port_src", "udp_port_dst",
        "vxlan_vni", "geneve_vni", "gtp_teid",
-       "tag", "mark", "meta", "pointer", "value", NULL
+       "tag", "mark", "meta", "pointer", "value",
+       "ipv4_ecn", "ipv6_ecn", NULL
 };
 
 /** Maximum number of subsequent tokens and arguments on the stack. */
@@ -902,6 +966,8 @@ struct token {
 struct buffer {
        enum index command; /**< Flow command. */
        portid_t port; /**< Affected port ID. */
+       queueid_t queue; /** Async queue ID. */
+       bool postpone; /** Postpone async operation */
        union {
                struct {
                        struct rte_flow_port_attr port_attr;
@@ -912,6 +978,18 @@ struct buffer {
                        uint32_t *template_id;
                        uint32_t template_id_n;
                } templ_destroy; /**< Template destroy arguments. */
+               struct {
+                       uint32_t id;
+                       struct rte_flow_template_table_attr attr;
+                       uint32_t *pat_templ_id;
+                       uint32_t pat_templ_id_n;
+                       uint32_t *act_templ_id;
+                       uint32_t act_templ_id_n;
+               } table; /**< Table arguments. */
+               struct {
+                       uint32_t *table_id;
+                       uint32_t table_id_n;
+               } table_destroy; /**< Template destroy arguments. */
                struct {
                        uint32_t *action_id;
                        uint32_t action_id_n;
@@ -920,6 +998,7 @@ struct buffer {
                        uint32_t action_id;
                } ia; /* Indirect action query arguments */
                struct {
+                       uint32_t table_id;
                        uint32_t pat_templ_id;
                        uint32_t act_templ_id;
                        struct rte_flow_attr attr;
@@ -1049,6 +1128,75 @@ static const enum index next_at_destroy_attr[] = {
        ZERO,
 };
 
+static const enum index next_table_subcmd[] = {
+       TABLE_CREATE,
+       TABLE_DESTROY,
+       ZERO,
+};
+
+static const enum index next_table_attr[] = {
+       TABLE_CREATE_ID,
+       TABLE_GROUP,
+       TABLE_PRIORITY,
+       TABLE_INGRESS,
+       TABLE_EGRESS,
+       TABLE_TRANSFER,
+       TABLE_RULES_NUMBER,
+       TABLE_PATTERN_TEMPLATE,
+       TABLE_ACTIONS_TEMPLATE,
+       END,
+       ZERO,
+};
+
+static const enum index next_table_destroy_attr[] = {
+       TABLE_DESTROY_ID,
+       END,
+       ZERO,
+};
+
+static const enum index next_queue_subcmd[] = {
+       QUEUE_CREATE,
+       QUEUE_DESTROY,
+       QUEUE_INDIRECT_ACTION,
+       ZERO,
+};
+
+static const enum index next_queue_destroy_attr[] = {
+       QUEUE_DESTROY_ID,
+       END,
+       ZERO,
+};
+
+static const enum index next_qia_subcmd[] = {
+       QUEUE_INDIRECT_ACTION_CREATE,
+       QUEUE_INDIRECT_ACTION_UPDATE,
+       QUEUE_INDIRECT_ACTION_DESTROY,
+       ZERO,
+};
+
+static const enum index next_qia_create_attr[] = {
+       QUEUE_INDIRECT_ACTION_CREATE_ID,
+       QUEUE_INDIRECT_ACTION_INGRESS,
+       QUEUE_INDIRECT_ACTION_EGRESS,
+       QUEUE_INDIRECT_ACTION_TRANSFER,
+       QUEUE_INDIRECT_ACTION_CREATE_POSTPONE,
+       QUEUE_INDIRECT_ACTION_SPEC,
+       ZERO,
+};
+
+static const enum index next_qia_update_attr[] = {
+       QUEUE_INDIRECT_ACTION_UPDATE_POSTPONE,
+       QUEUE_INDIRECT_ACTION_SPEC,
+       ZERO,
+};
+
+static const enum index next_qia_destroy_attr[] = {
+       QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE,
+       QUEUE_INDIRECT_ACTION_DESTROY_ID,
+       END,
+       ZERO,
+};
+
 static const enum index next_ia_create_attr[] = {
        INDIRECT_ACTION_CREATE_ID,
        INDIRECT_ACTION_INGRESS,
@@ -2154,6 +2302,29 @@ static int parse_template(struct context *, const struct token *,
 static int parse_template_destroy(struct context *, const struct token *,
                                  const char *, unsigned int,
                                  void *, unsigned int);
+static int parse_table(struct context *, const struct token *,
+                      const char *, unsigned int, void *, unsigned int);
+static int parse_table_destroy(struct context *, const struct token *,
+                              const char *, unsigned int,
+                              void *, unsigned int);
+static int parse_qo(struct context *, const struct token *,
+                   const char *, unsigned int,
+                   void *, unsigned int);
+static int parse_qo_destroy(struct context *, const struct token *,
+                           const char *, unsigned int,
+                           void *, unsigned int);
+static int parse_qia(struct context *, const struct token *,
+                    const char *, unsigned int,
+                    void *, unsigned int);
+static int parse_qia_destroy(struct context *, const struct token *,
+                            const char *, unsigned int,
+                            void *, unsigned int);
+static int parse_push(struct context *, const struct token *,
+                     const char *, unsigned int,
+                     void *, unsigned int);
+static int parse_pull(struct context *, const struct token *,
+                     const char *, unsigned int,
+                     void *, unsigned int);
 static int parse_tunnel(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
@@ -2227,6 +2398,10 @@ static int comp_pattern_template_id(struct context *, const struct token *,
                                    unsigned int, char *, unsigned int);
 static int comp_actions_template_id(struct context *, const struct token *,
                                    unsigned int, char *, unsigned int);
+static int comp_table_id(struct context *, const struct token *,
+                        unsigned int, char *, unsigned int);
+static int comp_queue_id(struct context *, const struct token *,
+                        unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -2391,6 +2566,20 @@ static const struct token token_list[] = {
                .call = parse_int,
                .comp = comp_actions_template_id,
        },
+       [COMMON_TABLE_ID] = {
+               .name = "{table_id}",
+               .type = "TABLE_ID",
+               .help = "table id",
+               .call = parse_int,
+               .comp = comp_table_id,
+       },
+       [COMMON_QUEUE_ID] = {
+               .name = "{queue_id}",
+               .type = "QUEUE_ID",
+               .help = "queue id",
+               .call = parse_int,
+               .comp = comp_queue_id,
+       },
        /* Top-level command. */
        [FLOW] = {
                .name = "flow",
@@ -2401,6 +2590,7 @@ static const struct token token_list[] = {
                              CONFIGURE,
                              PATTERN_TEMPLATE,
                              ACTIONS_TEMPLATE,
+                             TABLE,
                              INDIRECT_ACTION,
                              VALIDATE,
                              CREATE,
@@ -2412,7 +2602,10 @@ static const struct token token_list[] = {
                              QUERY,
                              ISOLATE,
                              TUNNEL,
-                             FLEX)),
+                             FLEX,
+                             QUEUE,
+                             PUSH,
+                             PULL)),
                .call = parse_init,
        },
        /* Top-level command. */
@@ -2617,6 +2810,303 @@ static const struct token token_list[] = {
                .call = parse_template,
        },
        /* Top-level command. */
+       [TABLE] = {
+               .name = "template_table",
+               .type = "{command} {port_id} [{arg} [...]]",
+               .help = "manage template tables",
+               .next = NEXT(next_table_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_table,
+       },
+       /* Sub-level commands. */
+       [TABLE_CREATE] = {
+               .name = "create",
+               .help = "create template table",
+               .next = NEXT(next_table_attr),
+               .call = parse_table,
+       },
+       [TABLE_DESTROY] = {
+               .name = "destroy",
+               .help = "destroy template table",
+               .next = NEXT(NEXT_ENTRY(TABLE_DESTROY_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_table_destroy,
+       },
+       /* Table  arguments. */
+       [TABLE_CREATE_ID] = {
+               .name = "table_id",
+               .help = "specify table id to create",
+               .next = NEXT(next_table_attr,
+                            NEXT_ENTRY(COMMON_TABLE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.table.id)),
+       },
+       [TABLE_DESTROY_ID] = {
+               .name = "table",
+               .help = "specify table id to destroy",
+               .next = NEXT(next_table_destroy_attr,
+                            NEXT_ENTRY(COMMON_TABLE_ID)),
+               .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+                                           args.table_destroy.table_id)),
+               .call = parse_table_destroy,
+       },
+       [TABLE_GROUP] = {
+               .name = "group",
+               .help = "specify a group",
+               .next = NEXT(next_table_attr, NEXT_ENTRY(COMMON_GROUP_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.table.attr.flow_attr.group)),
+       },
+       [TABLE_PRIORITY] = {
+               .name = "priority",
+               .help = "specify a priority level",
+               .next = NEXT(next_table_attr, NEXT_ENTRY(COMMON_PRIORITY_LEVEL)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.table.attr.flow_attr.priority)),
+       },
+       [TABLE_EGRESS] = {
+               .name = "egress",
+               .help = "affect rule to egress",
+               .next = NEXT(next_table_attr),
+               .call = parse_table,
+       },
+       [TABLE_INGRESS] = {
+               .name = "ingress",
+               .help = "affect rule to ingress",
+               .next = NEXT(next_table_attr),
+               .call = parse_table,
+       },
+       [TABLE_TRANSFER] = {
+               .name = "transfer",
+               .help = "affect rule to transfer",
+               .next = NEXT(next_table_attr),
+               .call = parse_table,
+       },
+       [TABLE_RULES_NUMBER] = {
+               .name = "rules_number",
+               .help = "number of rules in table",
+               .next = NEXT(next_table_attr,
+                            NEXT_ENTRY(COMMON_UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.table.attr.nb_flows)),
+       },
+       [TABLE_PATTERN_TEMPLATE] = {
+               .name = "pattern_template",
+               .help = "specify pattern template id",
+               .next = NEXT(next_table_attr,
+                            NEXT_ENTRY(COMMON_PATTERN_TEMPLATE_ID)),
+               .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+                                           args.table.pat_templ_id)),
+               .call = parse_table,
+       },
+       [TABLE_ACTIONS_TEMPLATE] = {
+               .name = "actions_template",
+               .help = "specify actions template id",
+               .next = NEXT(next_table_attr,
+                            NEXT_ENTRY(COMMON_ACTIONS_TEMPLATE_ID)),
+               .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+                                           args.table.act_templ_id)),
+               .call = parse_table,
+       },
+       /* Top-level command. */
+       [QUEUE] = {
+               .name = "queue",
+               .help = "queue a flow rule operation",
+               .next = NEXT(next_queue_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_qo,
+       },
+       /* Sub-level commands. */
+       [QUEUE_CREATE] = {
+               .name = "create",
+               .help = "create a flow rule",
+               .next = NEXT(NEXT_ENTRY(QUEUE_TEMPLATE_TABLE),
+                            NEXT_ENTRY(COMMON_QUEUE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+               .call = parse_qo,
+       },
+       [QUEUE_DESTROY] = {
+               .name = "destroy",
+               .help = "destroy a flow rule",
+               .next = NEXT(NEXT_ENTRY(QUEUE_DESTROY_ID),
+                            NEXT_ENTRY(COMMON_QUEUE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+               .call = parse_qo_destroy,
+       },
+       [QUEUE_INDIRECT_ACTION] = {
+               .name = "indirect_action",
+               .help = "queue indirect actions",
+               .next = NEXT(next_qia_subcmd, NEXT_ENTRY(COMMON_QUEUE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+               .call = parse_qia,
+       },
+       /* Queue  arguments. */
+       [QUEUE_TEMPLATE_TABLE] = {
+               .name = "template table",
+               .help = "specify table id",
+               .next = NEXT(NEXT_ENTRY(QUEUE_PATTERN_TEMPLATE),
+                            NEXT_ENTRY(COMMON_TABLE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.vc.table_id)),
+               .call = parse_qo,
+       },
+       [QUEUE_PATTERN_TEMPLATE] = {
+               .name = "pattern_template",
+               .help = "specify pattern template index",
+               .next = NEXT(NEXT_ENTRY(QUEUE_ACTIONS_TEMPLATE),
+                            NEXT_ENTRY(COMMON_UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.vc.pat_templ_id)),
+               .call = parse_qo,
+       },
+       [QUEUE_ACTIONS_TEMPLATE] = {
+               .name = "actions_template",
+               .help = "specify actions template index",
+               .next = NEXT(NEXT_ENTRY(QUEUE_CREATE_POSTPONE),
+                            NEXT_ENTRY(COMMON_UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct buffer,
+                                       args.vc.act_templ_id)),
+               .call = parse_qo,
+       },
+       [QUEUE_CREATE_POSTPONE] = {
+               .name = "postpone",
+               .help = "postpone create operation",
+               .next = NEXT(NEXT_ENTRY(ITEM_PATTERN),
+                            NEXT_ENTRY(COMMON_BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
+               .call = parse_qo,
+       },
+       [QUEUE_DESTROY_POSTPONE] = {
+               .name = "postpone",
+               .help = "postpone destroy operation",
+               .next = NEXT(NEXT_ENTRY(QUEUE_DESTROY_ID),
+                            NEXT_ENTRY(COMMON_BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
+               .call = parse_qo_destroy,
+       },
+       [QUEUE_DESTROY_ID] = {
+               .name = "rule",
+               .help = "specify rule id to destroy",
+               .next = NEXT(next_queue_destroy_attr,
+                       NEXT_ENTRY(COMMON_UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+                                           args.destroy.rule)),
+               .call = parse_qo_destroy,
+       },
+       /* Queue indirect action arguments */
+       [QUEUE_INDIRECT_ACTION_CREATE] = {
+               .name = "create",
+               .help = "create indirect action",
+               .next = NEXT(next_qia_create_attr),
+               .call = parse_qia,
+       },
+       [QUEUE_INDIRECT_ACTION_UPDATE] = {
+               .name = "update",
+               .help = "update indirect action",
+               .next = NEXT(next_qia_update_attr,
+                            NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.vc.attr.group)),
+               .call = parse_qia,
+       },
+       [QUEUE_INDIRECT_ACTION_DESTROY] = {
+               .name = "destroy",
+               .help = "destroy indirect action",
+               .next = NEXT(next_qia_destroy_attr),
+               .call = parse_qia_destroy,
+       },
+       /* Indirect action destroy arguments. */
+       [QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE] = {
+               .name = "postpone",
+               .help = "postpone destroy operation",
+               .next = NEXT(next_qia_destroy_attr,
+                            NEXT_ENTRY(COMMON_BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
+       },
+       [QUEUE_INDIRECT_ACTION_DESTROY_ID] = {
+               .name = "action_id",
+               .help = "specify a indirect action id to destroy",
+               .next = NEXT(next_qia_destroy_attr,
+                            NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
+               .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+                                           args.ia_destroy.action_id)),
+               .call = parse_qia_destroy,
+       },
+       /* Indirect action update arguments. */
+       [QUEUE_INDIRECT_ACTION_UPDATE_POSTPONE] = {
+               .name = "postpone",
+               .help = "postpone update operation",
+               .next = NEXT(next_qia_update_attr,
+                            NEXT_ENTRY(COMMON_BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
+       },
+       /* Indirect action create arguments. */
+       [QUEUE_INDIRECT_ACTION_CREATE_ID] = {
+               .name = "action_id",
+               .help = "specify a indirect action id to create",
+               .next = NEXT(next_qia_create_attr,
+                            NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.vc.attr.group)),
+       },
+       [QUEUE_INDIRECT_ACTION_INGRESS] = {
+               .name = "ingress",
+               .help = "affect rule to ingress",
+               .next = NEXT(next_qia_create_attr),
+               .call = parse_qia,
+       },
+       [QUEUE_INDIRECT_ACTION_EGRESS] = {
+               .name = "egress",
+               .help = "affect rule to egress",
+               .next = NEXT(next_qia_create_attr),
+               .call = parse_qia,
+       },
+       [QUEUE_INDIRECT_ACTION_TRANSFER] = {
+               .name = "transfer",
+               .help = "affect rule to transfer",
+               .next = NEXT(next_qia_create_attr),
+               .call = parse_qia,
+       },
+       [QUEUE_INDIRECT_ACTION_CREATE_POSTPONE] = {
+               .name = "postpone",
+               .help = "postpone create operation",
+               .next = NEXT(next_qia_create_attr,
+                            NEXT_ENTRY(COMMON_BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
+       },
+       [QUEUE_INDIRECT_ACTION_SPEC] = {
+               .name = "action",
+               .help = "specify action to create indirect handle",
+               .next = NEXT(next_action),
+       },
+       /* Top-level command. */
+       [PUSH] = {
+               .name = "push",
+               .help = "push enqueued operations",
+               .next = NEXT(NEXT_ENTRY(PUSH_QUEUE), NEXT_ENTRY(COMMON_PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_push,
+       },
+       /* Sub-level commands. */
+       [PUSH_QUEUE] = {
+               .name = "queue",
+               .help = "specify queue id",
+               .next = NEXT(NEXT_ENTRY(END), NEXT_ENTRY(COMMON_QUEUE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+       },
+       /* Top-level command. */
+       [PULL] = {
+               .name = "pull",
+               .help = "pull flow operations results",
+               .next = NEXT(NEXT_ENTRY(PULL_QUEUE), NEXT_ENTRY(COMMON_PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_pull,
+       },
+       /* Sub-level commands. */
+       [PULL_QUEUE] = {
+               .name = "queue",
+               .help = "specify queue id",
+               .next = NEXT(NEXT_ENTRY(END), NEXT_ENTRY(COMMON_QUEUE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+       },
+       /* Top-level command. */
        [INDIRECT_ACTION] = {
                .name = "indirect_action",
                .type = "{command} {port_id} [{arg} [...]]",
@@ -6161,6 +6651,110 @@ parse_ia_destroy(struct context *ctx, const struct token *token,
        return len;
 }
 
+/** Parse tokens for indirect action commands. */
+static int
+parse_qia(struct context *ctx, const struct token *token,
+         const char *str, unsigned int len,
+         void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command) {
+               if (ctx->curr != QUEUE)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->args.vc.data = (uint8_t *)out + size;
+               return len;
+       }
+       switch (ctx->curr) {
+       case QUEUE_INDIRECT_ACTION:
+               return len;
+       case QUEUE_INDIRECT_ACTION_CREATE:
+       case QUEUE_INDIRECT_ACTION_UPDATE:
+               out->args.vc.actions =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               out->args.vc.attr.group = UINT32_MAX;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               return len;
+       case QUEUE_INDIRECT_ACTION_EGRESS:
+               out->args.vc.attr.egress = 1;
+               return len;
+       case QUEUE_INDIRECT_ACTION_INGRESS:
+               out->args.vc.attr.ingress = 1;
+               return len;
+       case QUEUE_INDIRECT_ACTION_TRANSFER:
+               out->args.vc.attr.transfer = 1;
+               return len;
+       case QUEUE_INDIRECT_ACTION_CREATE_POSTPONE:
+               return len;
+       default:
+               return -1;
+       }
+}
+
+/** Parse tokens for indirect action destroy command. */
+static int
+parse_qia_destroy(struct context *ctx, const struct token *token,
+                 const char *str, unsigned int len,
+                 void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+       uint32_t *action_id;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command || out->command == QUEUE) {
+               if (ctx->curr != QUEUE_INDIRECT_ACTION_DESTROY)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.ia_destroy.action_id =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               return len;
+       }
+       switch (ctx->curr) {
+       case QUEUE_INDIRECT_ACTION:
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               return len;
+       case QUEUE_INDIRECT_ACTION_DESTROY_ID:
+               action_id = out->args.ia_destroy.action_id
+                               + out->args.ia_destroy.action_id_n++;
+               if ((uint8_t *)action_id > (uint8_t *)out + size)
+                       return -1;
+               ctx->objdata = 0;
+               ctx->object = action_id;
+               ctx->objmask = NULL;
+               return len;
+       case QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE:
+               return len;
+       default:
+               return -1;
+       }
+}
+
 /** Parse tokens for meter policy action commands. */
 static int
 parse_mp(struct context *ctx, const struct token *token,
@@ -6271,8 +6865,16 @@ parse_vc(struct context *ctx, const struct token *token,
                ctx->object = out->args.vc.pattern;
                ctx->objmask = NULL;
                return len;
-       case ACTIONS:
-               out->args.vc.actions =
+       case ITEM_END:
+               if ((out->command == VALIDATE || out->command == CREATE) &&
+                   ctx->last)
+                       return -1;
+               if (out->command == PATTERN_TEMPLATE_CREATE &&
+                   !ctx->last)
+                       return -1;
+               break;
+       case ACTIONS:
+               out->args.vc.actions =
                        (void *)RTE_ALIGN_CEIL((uintptr_t)
                                               (out->args.vc.pattern +
                                                out->args.vc.pattern_n),
@@ -8223,6 +8825,280 @@ parse_template_destroy(struct context *ctx, const struct token *token,
        return len;
 }
 
+/** Parse tokens for table create command. */
+static int
+parse_table(struct context *ctx, const struct token *token,
+           const char *str, unsigned int len,
+           void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+       uint32_t *template_id;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command) {
+               if (ctx->curr != TABLE)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               return len;
+       }
+       switch (ctx->curr) {
+       case TABLE_CREATE:
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.table.id = UINT32_MAX;
+               return len;
+       case TABLE_PATTERN_TEMPLATE:
+               out->args.table.pat_templ_id =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               template_id = out->args.table.pat_templ_id
+                               + out->args.table.pat_templ_id_n++;
+               if ((uint8_t *)template_id > (uint8_t *)out + size)
+                       return -1;
+               ctx->objdata = 0;
+               ctx->object = template_id;
+               ctx->objmask = NULL;
+               return len;
+       case TABLE_ACTIONS_TEMPLATE:
+               out->args.table.act_templ_id =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)
+                                              (out->args.table.pat_templ_id +
+                                               out->args.table.pat_templ_id_n),
+                                              sizeof(double));
+               template_id = out->args.table.act_templ_id
+                               + out->args.table.act_templ_id_n++;
+               if ((uint8_t *)template_id > (uint8_t *)out + size)
+                       return -1;
+               ctx->objdata = 0;
+               ctx->object = template_id;
+               ctx->objmask = NULL;
+               return len;
+       case TABLE_INGRESS:
+               out->args.table.attr.flow_attr.ingress = 1;
+               return len;
+       case TABLE_EGRESS:
+               out->args.table.attr.flow_attr.egress = 1;
+               return len;
+       case TABLE_TRANSFER:
+               out->args.table.attr.flow_attr.transfer = 1;
+               return len;
+       default:
+               return -1;
+       }
+}
+
+/** Parse tokens for table destroy command. */
+static int
+parse_table_destroy(struct context *ctx, const struct token *token,
+                   const char *str, unsigned int len,
+                   void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+       uint32_t *table_id;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command || out->command == TABLE) {
+               if (ctx->curr != TABLE_DESTROY)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.table_destroy.table_id =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               return len;
+       }
+       table_id = out->args.table_destroy.table_id
+                   + out->args.table_destroy.table_id_n++;
+       if ((uint8_t *)table_id > (uint8_t *)out + size)
+               return -1;
+       ctx->objdata = 0;
+       ctx->object = table_id;
+       ctx->objmask = NULL;
+       return len;
+}
+
+/** Parse tokens for queue create commands. */
+static int
+parse_qo(struct context *ctx, const struct token *token,
+        const char *str, unsigned int len,
+        void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command) {
+               if (ctx->curr != QUEUE)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.vc.data = (uint8_t *)out + size;
+               return len;
+       }
+       switch (ctx->curr) {
+       case QUEUE_CREATE:
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               return len;
+       case QUEUE_TEMPLATE_TABLE:
+       case QUEUE_PATTERN_TEMPLATE:
+       case QUEUE_ACTIONS_TEMPLATE:
+       case QUEUE_CREATE_POSTPONE:
+               return len;
+       case ITEM_PATTERN:
+               out->args.vc.pattern =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               ctx->object = out->args.vc.pattern;
+               ctx->objmask = NULL;
+               return len;
+       case ACTIONS:
+               out->args.vc.actions =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)
+                                              (out->args.vc.pattern +
+                                               out->args.vc.pattern_n),
+                                              sizeof(double));
+               ctx->object = out->args.vc.actions;
+               ctx->objmask = NULL;
+               return len;
+       default:
+               return -1;
+       }
+}
+
+/** Parse tokens for queue destroy command. */
+static int
+parse_qo_destroy(struct context *ctx, const struct token *token,
+                const char *str, unsigned int len,
+                void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+       uint32_t *flow_id;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command || out->command == QUEUE) {
+               if (ctx->curr != QUEUE_DESTROY)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.destroy.rule =
+                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+                                              sizeof(double));
+               return len;
+       }
+       switch (ctx->curr) {
+       case QUEUE_DESTROY_ID:
+               flow_id = out->args.destroy.rule
+                               + out->args.destroy.rule_n++;
+               if ((uint8_t *)flow_id > (uint8_t *)out + size)
+                       return -1;
+               ctx->objdata = 0;
+               ctx->object = flow_id;
+               ctx->objmask = NULL;
+               return len;
+       case QUEUE_DESTROY_POSTPONE:
+               return len;
+       default:
+               return -1;
+       }
+}
+
+/** Parse tokens for push queue command. */
+static int
+parse_push(struct context *ctx, const struct token *token,
+          const char *str, unsigned int len,
+          void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command) {
+               if (ctx->curr != PUSH)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.vc.data = (uint8_t *)out + size;
+       }
+       return len;
+}
+
+/** Parse tokens for pull command. */
+static int
+parse_pull(struct context *ctx, const struct token *token,
+          const char *str, unsigned int len,
+          void *buf, unsigned int size)
+{
+       struct buffer *out = buf;
+
+       /* Token name must match. */
+       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+               return -1;
+       /* Nothing else to do if there is no buffer. */
+       if (!out)
+               return len;
+       if (!out->command) {
+               if (ctx->curr != PULL)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               out->args.vc.data = (uint8_t *)out + size;
+       }
+       return len;
+}
+
 static int
 parse_flex(struct context *ctx, const struct token *token,
             const char *str, unsigned int len,
@@ -8463,11 +9339,7 @@ parse_hex_string(const char *src, uint8_t *dst, uint32_t *size)
        const uint8_t *head = dst;
        uint32_t left;
 
-       /* Check input parameters */
-       if ((src == NULL) ||
-               (dst == NULL) ||
-               (size == NULL) ||
-               (*size == 0))
+       if (*size == 0)
                return -1;
 
        left = *size;
@@ -9240,6 +10112,52 @@ comp_actions_template_id(struct context *ctx, const struct token *token,
        return i;
 }
 
+/** Complete available table IDs. */
+static int
+comp_table_id(struct context *ctx, const struct token *token,
+             unsigned int ent, char *buf, unsigned int size)
+{
+       unsigned int i = 0;
+       struct rte_port *port;
+       struct port_table *pt;
+
+       (void)token;
+       if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
+           ctx->port == (portid_t)RTE_PORT_ALL)
+               return -1;
+       port = &ports[ctx->port];
+       for (pt = port->table_list; pt != NULL; pt = pt->next) {
+               if (buf && i == ent)
+                       return snprintf(buf, size, "%u", pt->id);
+               ++i;
+       }
+       if (buf)
+               return -1;
+       return i;
+}
+
+/** Complete available queue IDs. */
+static int
+comp_queue_id(struct context *ctx, const struct token *token,
+             unsigned int ent, char *buf, unsigned int size)
+{
+       unsigned int i = 0;
+       struct rte_port *port;
+
+       (void)token;
+       if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
+           ctx->port == (portid_t)RTE_PORT_ALL)
+               return -1;
+       port = &ports[ctx->port];
+       for (i = 0; i < port->queue_nb; i++) {
+               if (buf && i == ent)
+                       return snprintf(buf, size, "%u", i);
+       }
+       if (buf)
+               return -1;
+       return i;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
@@ -9540,6 +10458,57 @@ cmd_flow_parsed(const struct buffer *in)
                                in->args.templ_destroy.template_id_n,
                                in->args.templ_destroy.template_id);
                break;
+       case TABLE_CREATE:
+               port_flow_template_table_create(in->port, in->args.table.id,
+                       &in->args.table.attr, in->args.table.pat_templ_id_n,
+                       in->args.table.pat_templ_id, in->args.table.act_templ_id_n,
+                       in->args.table.act_templ_id);
+               break;
+       case TABLE_DESTROY:
+               port_flow_template_table_destroy(in->port,
+                                       in->args.table_destroy.table_id_n,
+                                       in->args.table_destroy.table_id);
+               break;
+       case QUEUE_CREATE:
+               port_queue_flow_create(in->port, in->queue, in->postpone,
+                                      in->args.vc.table_id, in->args.vc.pat_templ_id,
+                                      in->args.vc.act_templ_id, in->args.vc.pattern,
+                                      in->args.vc.actions);
+               break;
+       case QUEUE_DESTROY:
+               port_queue_flow_destroy(in->port, in->queue, in->postpone,
+                                       in->args.destroy.rule_n,
+                                       in->args.destroy.rule);
+               break;
+       case PUSH:
+               port_queue_flow_push(in->port, in->queue);
+               break;
+       case PULL:
+               port_queue_flow_pull(in->port, in->queue);
+               break;
+       case QUEUE_INDIRECT_ACTION_CREATE:
+               port_queue_action_handle_create(
+                               in->port, in->queue, in->postpone,
+                               in->args.vc.attr.group,
+                               &((const struct rte_flow_indir_action_conf) {
+                                       .ingress = in->args.vc.attr.ingress,
+                                       .egress = in->args.vc.attr.egress,
+                                       .transfer = in->args.vc.attr.transfer,
+                               }),
+                               in->args.vc.actions);
+               break;
+       case QUEUE_INDIRECT_ACTION_DESTROY:
+               port_queue_action_handle_destroy(in->port,
+                                          in->queue, in->postpone,
+                                          in->args.ia_destroy.action_id_n,
+                                          in->args.ia_destroy.action_id);
+               break;
+       case QUEUE_INDIRECT_ACTION_UPDATE:
+               port_queue_action_handle_update(in->port,
+                                               in->queue, in->postpone,
+                                               in->args.vc.attr.group,
+                                               in->args.vc.actions);
+               break;
        case INDIRECT_ACTION_CREATE:
                port_action_handle_create(
                                in->port, in->args.vc.attr.group,
@@ -10002,7 +10971,8 @@ cmd_set_raw_parsed(const struct buffer *in)
                case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
                        opt = (const struct rte_flow_item_geneve_opt *)
                                                                item->spec;
-                       size = offsetof(struct rte_flow_item_geneve_opt, data);
+                       size = offsetof(struct rte_flow_item_geneve_opt,
+                                       option_len) + sizeof(uint8_t);
                        if (opt->option_len && opt->data) {
                                *total_size += opt->option_len *
                                               sizeof(uint32_t);
@@ -10259,16 +11229,16 @@ cmd_show_set_raw_parsed(void *parsed_result, struct cmdline *cl, void *data)
        } while (all && ++index < RAW_ENCAP_CONFS_MAX_NUM);
 }
 
-cmdline_parse_token_string_t cmd_show_set_raw_cmd_show =
+static cmdline_parse_token_string_t cmd_show_set_raw_cmd_show =
        TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
                        cmd_show, "show");
-cmdline_parse_token_string_t cmd_show_set_raw_cmd_what =
+static cmdline_parse_token_string_t cmd_show_set_raw_cmd_what =
        TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
                        cmd_what, "raw_encap#raw_decap");
-cmdline_parse_token_num_t cmd_show_set_raw_cmd_index =
+static cmdline_parse_token_num_t cmd_show_set_raw_cmd_index =
        TOKEN_NUM_INITIALIZER(struct cmd_show_set_raw_result,
                        cmd_index, RTE_UINT16);
-cmdline_parse_token_string_t cmd_show_set_raw_cmd_all =
+static cmdline_parse_token_string_t cmd_show_set_raw_cmd_all =
        TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
                        cmd_all, "all");
 cmdline_parse_inst_t cmd_show_set_raw = {