Signed-off-by: Georgios Katsikas <george....@gmail.com>
---
 app/test-pmd/Makefile             |   2 +
 app/test-pmd/cmdline.c            |   4 +
 app/test-pmd/testpmd.h            |  14 -
 lib/librte_cmdline/Makefile       |   3 +
 lib/librte_cmdline/cmdline_flow.c | 555 ++++++--------------------------
 lib/librte_cmdline/cmdline_flow.h | 653 +++++++++++++++++++++++++++++++-------
 lib/librte_ether/rte_flow.c       |   4 +-
 lib/librte_ether/rte_flow.h       |  10 -
 8 files changed, 640 insertions(+), 605 deletions(-)

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index ec48773..26de9f3 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -38,6 +38,8 @@ endif
 
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
 
+LDLIBS += -lrte_cmdline
+
 ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
 LDLIBS += -lrte_pmd_bond
 endif
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 5b2e2ef..d1c6428 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -10921,7 +10921,11 @@ cmdline_parse_inst_t 
cmd_set_flow_director_flex_payload = {
 };
 
 /* Generic flow interface command. */
+#ifdef RTE_BUILD_SHARED_LIB
+cmdline_parse_inst_t cmd_flow;
+#else
 extern cmdline_parse_inst_t cmd_flow;
+#endif
 
 /* *** Classification Filters Control *** */
 /* *** Get symmetric hash enable per port *** */
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 303a9ec..71da7ef 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -498,20 +498,6 @@ void port_reg_bit_field_set(portid_t port_id, uint32_t 
reg_off,
                            uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value);
 void port_reg_display(portid_t port_id, uint32_t reg_off);
 void port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t value);
-int port_flow_validate(portid_t port_id,
-                      const struct rte_flow_attr *attr,
-                      const struct rte_flow_item *pattern,
-                      const struct rte_flow_action *actions);
-int port_flow_create(portid_t port_id,
-                    const struct rte_flow_attr *attr,
-                    const struct rte_flow_item *pattern,
-                    const struct rte_flow_action *actions);
-int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule);
-int port_flow_flush(portid_t port_id);
-int port_flow_query(portid_t port_id, uint32_t rule,
-                   enum rte_flow_action_type action);
-void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);
-int port_flow_isolate(portid_t port_id, int set);
 
 void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
 void tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id);
diff --git a/lib/librte_cmdline/Makefile b/lib/librte_cmdline/Makefile
index cf46b22..475b1f7 100644
--- a/lib/librte_cmdline/Makefile
+++ b/lib/librte_cmdline/Makefile
@@ -28,6 +28,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_parse_portlist.c
 
 CFLAGS += -D_GNU_SOURCE
 LDLIBS += -lrte_eal
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+LDLIBS += -lrte_ethdev
+endif
 
 # install includes
 INCS := cmdline.h cmdline_parse.h cmdline_parse_num.h cmdline_parse_ipaddr.h
diff --git a/lib/librte_cmdline/cmdline_flow.c 
b/lib/librte_cmdline/cmdline_flow.c
index b43c10f..e4a8230 100644
--- a/lib/librte_cmdline/cmdline_flow.c
+++ b/lib/librte_cmdline/cmdline_flow.c
@@ -43,21 +43,6 @@
 
 #include "cmdline_flow.h"
 
-int
-port_id_is_invalid(portid_t port_id, enum print_warning warning)
-{
-       if (port_id == (portid_t)RTE_PORT_ALL)
-               return 0;
-
-       if (rte_eth_dev_is_valid_port(port_id))
-               return 0;
-
-       if (warning == ENABLED_WARN)
-               printf("Invalid port %d\n", port_id);
-
-       return 1;
-}
-
 /** Remove and return last entry from argument stack. */
 const struct arg *
 pop_args(struct context *ctx)
@@ -134,7 +119,7 @@ strcmp_partial(const char *full, const char *partial, 
size_t partial_len)
  * location and whether the result must use network byte ordering.
  */
 int
-parse_prefix(struct context *ctx, const struct token *token,
+cmd_parse_prefix(struct context *ctx, const struct token *token,
             const char *str, unsigned int len,
             void *buf, unsigned int size)
 {
@@ -202,7 +187,7 @@ parse_prefix(struct context *ctx, const struct token *token,
 
 /** Default parsing function for token name matching. */
 int
-parse_default(struct context *ctx, const struct token *token,
+cmd_parse_default(struct context *ctx, const struct token *token,
              const char *str, unsigned int len,
              void *buf, unsigned int size)
 {
@@ -216,14 +201,14 @@ parse_default(struct context *ctx, const struct token 
*token,
 
 /** Parse flow command, initialize output buffer for subsequent tokens. */
 int
-parse_init(struct context *ctx, const struct token *token,
+cmd_parse_init(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -242,7 +227,7 @@ parse_init(struct context *ctx, const struct token *token,
 
 /** Parse tokens for validate/create commands. */
 int
-parse_vc(struct context *ctx, const struct token *token,
+cmd_parse_vc(struct context *ctx, const struct token *token,
         const char *str, unsigned int len,
         void *buf, unsigned int size)
 {
@@ -251,7 +236,7 @@ parse_vc(struct context *ctx, const struct token *token,
        uint32_t data_size;
 
        /* Token name must match. */
-       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -345,7 +330,7 @@ parse_vc(struct context *ctx, const struct token *token,
 
 /** Parse pattern item parameter type. */
 int
-parse_vc_spec(struct context *ctx, const struct token *token,
+cmd_parse_vc_spec(struct context *ctx, const struct token *token,
              const char *str, unsigned int len,
              void *buf, unsigned int size)
 {
@@ -357,7 +342,7 @@ parse_vc_spec(struct context *ctx, const struct token 
*token,
 
        (void)size;
        /* Token name must match. */
-       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Parse parameter types. */
        switch (ctx->curr) {
@@ -407,7 +392,7 @@ parse_vc_spec(struct context *ctx, const struct token 
*token,
 
 /** Parse action configuration field. */
 int
-parse_vc_conf(struct context *ctx, const struct token *token,
+cmd_parse_vc_conf(struct context *ctx, const struct token *token,
              const char *str, unsigned int len,
              void *buf, unsigned int size)
 {
@@ -416,7 +401,7 @@ parse_vc_conf(struct context *ctx, const struct token 
*token,
 
        (void)size;
        /* Token name must match. */
-       if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -438,7 +423,7 @@ parse_vc_conf(struct context *ctx, const struct token 
*token,
  * Valid tokens are queue indices and the "end" token.
  */
 int
-parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
+cmd_parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
                          const char *str, unsigned int len,
                          void *buf, unsigned int size)
 {
@@ -460,7 +445,7 @@ parse_vc_action_rss_queue(struct context *ctx, const struct 
token *token,
                return -1;
        if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i])))
                return -1;
-       ret = parse_int(ctx, token, str, len, NULL, 0);
+       ret = cmd_parse_int(ctx, token, str, len, NULL, 0);
        if (ret < 0) {
                pop_args(ctx);
                return -1;
@@ -479,14 +464,14 @@ parse_vc_action_rss_queue(struct context *ctx, const 
struct token *token,
 
 /** Parse tokens for destroy command. */
 int
-parse_destroy(struct context *ctx, const struct token *token,
+cmd_parse_destroy(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -516,14 +501,14 @@ parse_destroy(struct context *ctx, const struct token 
*token,
 
 /** Parse tokens for flush command. */
 int
-parse_flush(struct context *ctx, const struct token *token,
+cmd_parse_flush(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -543,14 +528,14 @@ parse_flush(struct context *ctx, const struct token 
*token,
 
 /** Parse tokens for query command. */
 int
-parse_query(struct context *ctx, const struct token *token,
+cmd_parse_query(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -570,7 +555,7 @@ parse_query(struct context *ctx, const struct token *token,
 
 /** Parse action names. */
 int
-parse_action(struct context *ctx, const struct token *token,
+cmd_parse_action(struct context *ctx, const struct token *token,
             const char *str, unsigned int len,
             void *buf, unsigned int size)
 {
@@ -605,14 +590,14 @@ parse_action(struct context *ctx, const struct token 
*token,
 
 /** Parse tokens for list command. */
 int
-parse_list(struct context *ctx, const struct token *token,
+cmd_parse_list(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -642,14 +627,14 @@ parse_list(struct context *ctx, const struct token *token,
 
 /** Parse tokens for isolate command. */
 int
-parse_isolate(struct context *ctx, const struct token *token,
+cmd_parse_isolate(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)
+       if (cmd_parse_default(ctx, token, str, len, NULL, 0) < 0)
                return -1;
        /* Nothing else to do if there is no buffer. */
        if (!out)
@@ -674,7 +659,7 @@ parse_isolate(struct context *ctx, const struct token 
*token,
  * storage location.
  */
 int
-parse_int(struct context *ctx, const struct token *token,
+cmd_parse_int(struct context *ctx, const struct token *token,
          const char *str, unsigned int len,
          void *buf, unsigned int size)
 {
@@ -750,7 +735,7 @@ parse_int(struct context *ctx, const struct token *token,
  * its length (in that order).
  */
 int
-parse_string(struct context *ctx, const struct token *token,
+cmd_parse_string(struct context *ctx, const struct token *token,
             const char *str, unsigned int len,
             void *buf, unsigned int size)
 {
@@ -772,12 +757,12 @@ parse_string(struct context *ctx, const struct token 
*token,
                goto error;
        if (!ctx->object)
                return len;
-       /* Let parse_int() fill length information first. */
+       /* Let cmd_parse_int() fill length information first. */
        ret = snprintf(tmp, sizeof(tmp), "%u", len);
        if (ret < 0)
                goto error;
        push_args(ctx, arg_len);
-       ret = parse_int(ctx, token, tmp, ret, NULL, 0);
+       ret = cmd_parse_int(ctx, token, tmp, ret, NULL, 0);
        if (ret < 0) {
                pop_args(ctx);
                goto error;
@@ -802,7 +787,7 @@ parse_string(struct context *ctx, const struct token *token,
  * location.
  */
 int
-parse_mac_addr(struct context *ctx, const struct token *token,
+cmd_parse_mac_addr(struct context *ctx, const struct token *token,
               const char *str, unsigned int len,
               void *buf, unsigned int size)
 {
@@ -843,7 +828,7 @@ parse_mac_addr(struct context *ctx, const struct token 
*token,
  * location.
  */
 int
-parse_ipv4_addr(struct context *ctx, const struct token *token,
+cmd_parse_ipv4_addr(struct context *ctx, const struct token *token,
                const char *str, unsigned int len,
                void *buf, unsigned int size)
 {
@@ -868,7 +853,7 @@ parse_ipv4_addr(struct context *ctx, const struct token 
*token,
        if (ret != 1) {
                /* Attempt integer parsing. */
                push_args(ctx, arg);
-               return parse_int(ctx, token, str, len, buf, size);
+               return cmd_parse_int(ctx, token, str, len, buf, size);
        }
        if (!ctx->object)
                return len;
@@ -889,7 +874,7 @@ parse_ipv4_addr(struct context *ctx, const struct token 
*token,
  * location.
  */
 int
-parse_ipv6_addr(struct context *ctx, const struct token *token,
+cmd_parse_ipv6_addr(struct context *ctx, const struct token *token,
                const char *str, unsigned int len,
                void *buf, unsigned int size)
 {
@@ -942,7 +927,7 @@ static const char *const boolean_name[] = {
  * location.
  */
 int
-parse_boolean(struct context *ctx, const struct token *token,
+cmd_parse_boolean(struct context *ctx, const struct token *token,
              const char *str, unsigned int len,
              void *buf, unsigned int size)
 {
@@ -960,13 +945,13 @@ parse_boolean(struct context *ctx, const struct token 
*token,
        if (boolean_name[i])
                str = i & 1 ? "1" : "0";
        push_args(ctx, arg);
-       ret = parse_int(ctx, token, str, strlen(str), buf, size);
+       ret = cmd_parse_int(ctx, token, str, strlen(str), buf, size);
        return ret > 0 ? (int)len : ret;
 }
 
 /** Parse port and update context. */
 int
-parse_port(struct context *ctx, const struct token *token,
+cmd_parse_port(struct context *ctx, const struct token *token,
           const char *str, unsigned int len,
           void *buf, unsigned int size)
 {
@@ -981,7 +966,7 @@ parse_port(struct context *ctx, const struct token *token,
                ctx->objmask = NULL;
                size = sizeof(*out);
        }
-       ret = parse_int(ctx, token, str, len, out, size);
+       ret = cmd_parse_int(ctx, token, str, len, out, size);
        if (ret >= 0)
                ctx->port = out->port;
        if (!buf)
@@ -1102,9 +1087,6 @@ comp_vc_action_rss_queue(struct context *ctx, const 
struct token *token,
 /** Internal context. */
 static struct context cmd_flow_context;
 
-/** Global parser instance (cmdline API). */
-cmdline_parse_inst_t cmd_flow;
-
 /** Initialize context. */
 void
 cmd_flow_context_init(struct context *ctx)
@@ -1173,7 +1155,7 @@ cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char 
*src, void *result,
                if (next->call)
                        tmp = next->call(ctx, next, src, len, result, size);
                else
-                       tmp = parse_default(ctx, next, src, len, result, size);
+                       tmp = cmd_parse_default(ctx, next, src, len, result, 
size);
                if (tmp == -1 || tmp != len)
                        continue;
                token = next;
@@ -1328,6 +1310,64 @@ cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
        *hdr = &cmd_flow_token_hdr;
 }
 
+/* Generic flow management functions. */
+
+/** Compute storage space needed by item specification. */
+void
+flow_item_spec_size(const struct rte_flow_item *item,
+                   size_t *size, size_t *pad)
+{
+       if (!item->spec) {
+               *size = 0;
+               goto empty;
+       }
+       switch (item->type) {
+               union {
+                       const struct rte_flow_item_raw *raw;
+               } spec;
+
+       /* Not a fall-through */
+       case RTE_FLOW_ITEM_TYPE_RAW:
+               spec.raw = item->spec;
+               *size = offsetof(struct rte_flow_item_raw, pattern) +
+                       spec.raw->length * sizeof(*spec.raw->pattern);
+               break;
+       default:
+               *size = flow_item[item->type].size;
+               break;
+       }
+empty:
+       *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
+}
+
+/** Compute storage space needed by action configuration. */
+void
+flow_action_conf_size(const struct rte_flow_action *action,
+                     size_t *size, size_t *pad)
+{
+       if (!action->conf) {
+               *size = 0;
+               goto empty;
+       }
+       switch (action->type) {
+               union {
+                       const struct rte_flow_action_rss *rss;
+               } conf;
+
+       /* Not a fall-through. */
+       case RTE_FLOW_ACTION_TYPE_RSS:
+               conf.rss = action->conf;
+               *size = offsetof(struct rte_flow_action_rss, queue) +
+                       conf.rss->num * sizeof(*conf.rss->queue);
+               break;
+       default:
+               *size = flow_action[action->type].size;
+               break;
+       }
+empty:
+       *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
+}
+
 /** Dispatch parsed buffer to function calls. */
 void
 cmd_flow_parsed(const struct buffer *in)
@@ -1374,7 +1414,7 @@ cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
                cmd_flow_parsed(arg0);
 }
 
-/** Global parser instance (cmdline API). */
+/** Global parser instance (properly initialized). */
 cmdline_parse_inst_t cmd_flow = {
        .f = cmd_flow_cb,
        .data = NULL, /**< Unused. */
@@ -1383,408 +1423,3 @@ cmdline_parse_inst_t cmd_flow = {
                NULL,
        }, /**< Tokens are returned by cmd_flow_tok(). */
 };
-
-/* Generic flow management functions. */
-
-/** Generate a port_flow entry from attributes/pattern/actions. */
-static struct port_flow *
-port_flow_new(const struct rte_flow_attr *attr,
-             const struct rte_flow_item *pattern,
-             const struct rte_flow_action *actions)
-{
-       const struct rte_flow_item *item;
-       const struct rte_flow_action *action;
-       struct port_flow *pf = NULL;
-       size_t tmp;
-       size_t pad;
-       size_t off1 = 0;
-       size_t off2 = 0;
-       int err = ENOTSUP;
-
-store:
-       item = pattern;
-       if (pf)
-               pf->pattern = (void *)&pf->data[off1];
-       do {
-               struct rte_flow_item *dst = NULL;
-
-               if ((unsigned int)item->type >= RTE_DIM(flow_item) ||
-                   !flow_item[item->type].name)
-                       goto notsup;
-               if (pf)
-                       dst = memcpy(pf->data + off1, item, sizeof(*item));
-               off1 += sizeof(*item);
-               flow_item_spec_size(item, &tmp, &pad);
-               if (item->spec) {
-                       if (pf)
-                               dst->spec = memcpy(pf->data + off2,
-                                                  item->spec, tmp);
-                       off2 += tmp + pad;
-               }
-               if (item->last) {
-                       if (pf)
-                               dst->last = memcpy(pf->data + off2,
-                                                  item->last, tmp);
-                       off2 += tmp + pad;
-               }
-               if (item->mask) {
-                       if (pf)
-                               dst->mask = memcpy(pf->data + off2,
-                                                  item->mask, tmp);
-                       off2 += tmp + pad;
-               }
-               off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-       } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
-       off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-       action = actions;
-       if (pf)
-               pf->actions = (void *)&pf->data[off1];
-       do {
-               struct rte_flow_action *dst = NULL;
-
-               if ((unsigned int)action->type >= RTE_DIM(flow_action) ||
-                   !flow_action[action->type].name)
-                       goto notsup;
-               if (pf)
-                       dst = memcpy(pf->data + off1, action, sizeof(*action));
-               off1 += sizeof(*action);
-               flow_action_conf_size(action, &tmp, &pad);
-               if (action->conf) {
-                       if (pf)
-                               dst->conf = memcpy(pf->data + off2,
-                                                  action->conf, tmp);
-                       off2 += tmp + pad;
-               }
-               off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
-       } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
-       if (pf != NULL)
-               return pf;
-       off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
-       tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double));
-       pf = calloc(1, tmp + off1 + off2);
-       if (pf == NULL)
-               err = errno;
-       else {
-               *pf = (const struct port_flow){
-                       .size = tmp + off1 + off2,
-                       .attr = *attr,
-               };
-               tmp -= offsetof(struct port_flow, data);
-               off2 = tmp + off1;
-               off1 = tmp;
-               goto store;
-       }
-notsup:
-       rte_errno = err;
-       return NULL;
-}
-
-/** Print a message out of a flow error. */
-static int
-port_flow_complain(struct rte_flow_error *error)
-{
-       static const char *const errstrlist[] = {
-               [RTE_FLOW_ERROR_TYPE_NONE] = "no error",
-               [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
-               [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
-               [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
-               [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
-               [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
-               [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
-               [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
-               [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
-               [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
-               [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
-               [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
-       };
-       const char *errstr;
-       char buf[32];
-       int err = rte_errno;
-
-       if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
-           !errstrlist[error->type])
-               errstr = "unknown type";
-       else
-               errstr = errstrlist[error->type];
-       printf("Caught error type %d (%s): %s%s\n",
-              error->type, errstr,
-              error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
-                                       error->cause), buf) : "",
-              error->message ? error->message : "(no stated reason)");
-       return -err;
-}
-
-/** Validate flow rule. */
-int
-port_flow_validate(portid_t port_id,
-                  const struct rte_flow_attr *attr,
-                  const struct rte_flow_item *pattern,
-                  const struct rte_flow_action *actions)
-{
-       struct rte_flow_error error;
-
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x11, sizeof(error));
-       if (rte_flow_validate(port_id, attr, pattern, actions, &error))
-               return port_flow_complain(&error);
-       printf("Flow rule validated\n");
-       return 0;
-}
-
-/** Create flow rule. */
-int
-port_flow_create(portid_t port_id,
-                const struct rte_flow_attr *attr,
-                const struct rte_flow_item *pattern,
-                const struct rte_flow_action *actions)
-{
-       struct rte_flow *flow;
-       struct rte_port *port;
-       struct port_flow *pf;
-       uint32_t id;
-       struct rte_flow_error error;
-
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x22, sizeof(error));
-       flow = rte_flow_create(port_id, attr, pattern, actions, &error);
-       if (!flow)
-               return port_flow_complain(&error);
-       port = &ports[port_id];
-       if (port->flow_list) {
-               if (port->flow_list->id == UINT32_MAX) {
-                       printf("Highest rule ID is already assigned, delete"
-                              " it first");
-                       rte_flow_destroy(port_id, flow, NULL);
-                       return -ENOMEM;
-               }
-               id = port->flow_list->id + 1;
-       } else
-               id = 0;
-       pf = port_flow_new(attr, pattern, actions);
-       if (!pf) {
-               int err = rte_errno;
-
-               printf("Cannot allocate flow: %s\n", rte_strerror(err));
-               rte_flow_destroy(port_id, flow, NULL);
-               return -err;
-       }
-       pf->next = port->flow_list;
-       pf->id = id;
-       pf->flow = flow;
-       port->flow_list = pf;
-       printf("Flow rule #%u created\n", pf->id);
-       return 0;
-}
-
-/** Destroy a number of flow rules. */
-int
-port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
-{
-       struct rte_port *port;
-       struct port_flow **tmp;
-       uint32_t c = 0;
-       int ret = 0;
-
-       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
-           port_id == (portid_t)RTE_PORT_ALL)
-               return -EINVAL;
-       port = &ports[port_id];
-       tmp = &port->flow_list;
-       while (*tmp) {
-               uint32_t i;
-
-               for (i = 0; i != n; ++i) {
-                       struct rte_flow_error error;
-                       struct port_flow *pf = *tmp;
-
-                       if (rule[i] != pf->id)
-                               continue;
-                       /*
-                        * Poisoning to make sure PMDs update it in case
-                        * of error.
-                        */
-                       memset(&error, 0x33, sizeof(error));
-                       if (rte_flow_destroy(port_id, pf->flow, &error)) {
-                               ret = port_flow_complain(&error);
-                               continue;
-                       }
-                       printf("Flow rule #%u destroyed\n", pf->id);
-                       *tmp = pf->next;
-                       free(pf);
-                       break;
-               }
-               if (i == n)
-                       tmp = &(*tmp)->next;
-               ++c;
-       }
-       return ret;
-}
-
-/** Remove all flow rules. */
-int
-port_flow_flush(portid_t port_id)
-{
-       struct rte_flow_error error;
-       struct rte_port *port;
-       int ret = 0;
-
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x44, sizeof(error));
-       if (rte_flow_flush(port_id, &error)) {
-               ret = port_flow_complain(&error);
-               if (port_id_is_invalid(port_id, DISABLED_WARN) ||
-                   port_id == (portid_t)RTE_PORT_ALL)
-                       return ret;
-       }
-       port = &ports[port_id];
-       while (port->flow_list) {
-               struct port_flow *pf = port->flow_list->next;
-
-               free(port->flow_list);
-               port->flow_list = pf;
-       }
-       return ret;
-}
-
-/** Query a flow rule. */
-int
-port_flow_query(portid_t port_id, uint32_t rule,
-               enum rte_flow_action_type action)
-{
-       struct rte_flow_error error;
-       struct rte_port *port;
-       struct port_flow *pf;
-       const char *name;
-       union {
-               struct rte_flow_query_count count;
-       } query;
-
-       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
-           port_id == (portid_t)RTE_PORT_ALL)
-               return -EINVAL;
-       port = &ports[port_id];
-       for (pf = port->flow_list; pf; pf = pf->next)
-               if (pf->id == rule)
-                       break;
-       if (!pf) {
-               printf("Flow rule #%u not found\n", rule);
-               return -ENOENT;
-       }
-       if ((unsigned int)action >= RTE_DIM(flow_action) ||
-           !flow_action[action].name)
-               name = "unknown";
-       else
-               name = flow_action[action].name;
-       switch (action) {
-       case RTE_FLOW_ACTION_TYPE_COUNT:
-               break;
-       default:
-               printf("Cannot query action type %d (%s)\n", action, name);
-               return -ENOTSUP;
-       }
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x55, sizeof(error));
-       memset(&query, 0, sizeof(query));
-       if (rte_flow_query(port_id, pf->flow, action, &query, &error))
-               return port_flow_complain(&error);
-       switch (action) {
-       case RTE_FLOW_ACTION_TYPE_COUNT:
-               printf("%s:\n"
-                      " hits_set: %u\n"
-                      " bytes_set: %u\n"
-                      " hits: %" PRIu64 "\n"
-                      " bytes: %" PRIu64 "\n",
-                      name,
-                      query.count.hits_set,
-                      query.count.bytes_set,
-                      query.count.hits,
-                      query.count.bytes);
-               break;
-       default:
-               printf("Cannot display result for action type %d (%s)\n",
-                      action, name);
-               break;
-       }
-       return 0;
-}
-
-/** List flow rules. */
-void
-port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
-{
-       struct rte_port *port;
-       struct port_flow *pf;
-       struct port_flow *list = NULL;
-       uint32_t i;
-
-       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
-           port_id == (portid_t)RTE_PORT_ALL)
-               return;
-       port = &ports[port_id];
-       if (!port->flow_list)
-               return;
-       /* Sort flows by group, priority and ID. */
-       for (pf = port->flow_list; pf != NULL; pf = pf->next) {
-               struct port_flow **tmp;
-
-               if (n) {
-                       /* Filter out unwanted groups. */
-                       for (i = 0; i != n; ++i)
-                               if (pf->attr.group == group[i])
-                                       break;
-                       if (i == n)
-                               continue;
-               }
-               tmp = &list;
-               while (*tmp &&
-                      (pf->attr.group > (*tmp)->attr.group ||
-                       (pf->attr.group == (*tmp)->attr.group &&
-                        pf->attr.priority > (*tmp)->attr.priority) ||
-                       (pf->attr.group == (*tmp)->attr.group &&
-                        pf->attr.priority == (*tmp)->attr.priority &&
-                        pf->id > (*tmp)->id)))
-                       tmp = &(*tmp)->tmp;
-               pf->tmp = *tmp;
-               *tmp = pf;
-       }
-       printf("ID\tGroup\tPrio\tAttr\tRule\n");
-       for (pf = list; pf != NULL; pf = pf->tmp) {
-               const struct rte_flow_item *item = pf->pattern;
-               const struct rte_flow_action *action = pf->actions;
-
-               printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t",
-                      pf->id,
-                      pf->attr.group,
-                      pf->attr.priority,
-                      pf->attr.ingress ? 'i' : '-',
-                      pf->attr.egress ? 'e' : '-');
-               while (item->type != RTE_FLOW_ITEM_TYPE_END) {
-                       if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
-                               printf("%s ", flow_item[item->type].name);
-                       ++item;
-               }
-               printf("=>");
-               while (action->type != RTE_FLOW_ACTION_TYPE_END) {
-                       if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
-                               printf(" %s", flow_action[action->type].name);
-                       ++action;
-               }
-               printf("\n");
-       }
-}
-
-/** Restrict ingress traffic to the defined flow rules. */
-int
-port_flow_isolate(portid_t port_id, int set)
-{
-       struct rte_flow_error error;
-
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x66, sizeof(error));
-       if (rte_flow_isolate(port_id, set, &error))
-               return port_flow_complain(&error);
-       printf("Ingress traffic on port %u is %s to the defined flow rules\n",
-              port_id,
-              set ? "now restricted" : "not restricted anymore");
-       return 0;
-}
diff --git a/lib/librte_cmdline/cmdline_flow.h 
b/lib/librte_cmdline/cmdline_flow.h
index 7066254..9cb8045 100644
--- a/lib/librte_cmdline/cmdline_flow.h
+++ b/lib/librte_cmdline/cmdline_flow.h
@@ -814,8 +814,21 @@ static const struct {
 };
 
 /** Helper functions for parsing. */
-int port_id_is_invalid(portid_t port_id,
-                       enum print_warning warning);
+inline int
+port_id_is_invalid(portid_t port_id, enum print_warning warning)
+{
+       if (port_id == (portid_t)RTE_PORT_ALL)
+               return 0;
+
+       if (rte_eth_dev_is_valid_port(port_id))
+               return 0;
+
+       if (warning == ENABLED_WARN)
+               printf("Invalid port %d\n", port_id);
+
+       return 1;
+}
+
 const struct arg *pop_args(struct context *ctx);
 int push_args(struct context *ctx,
                        const struct arg *arg);
@@ -823,68 +836,75 @@ size_t arg_entry_bf_fill(void *dst, uintmax_t val,
                        const struct arg *arg);
 int strcmp_partial(const char *full,
                        const char *partial, size_t partial_len);
+/** Compute storage space needed by item specification. */
+void flow_item_spec_size(const struct rte_flow_item *item,
+                       size_t *size, size_t *pad);
+
+/** Compute storage space needed by action configuration. */
+void flow_action_conf_size(const struct rte_flow_action *action,
+                       size_t *size, size_t *pad);
 
 /** Parsing functions. */
-int parse_prefix(struct context *, const struct token *,
+int cmd_parse_prefix(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_default(struct context *ctx,
+int cmd_parse_default(struct context *ctx,
                        const struct token *token,
                        const char *str, unsigned int len,
                        void *buf, unsigned int size);
-int parse_init(struct context *, const struct token *,
+int cmd_parse_init(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_vc(struct context *, const struct token *,
+int cmd_parse_vc(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_vc_spec(struct context *, const struct token *,
+int cmd_parse_vc_spec(struct context *, const struct token *,
                        const char *, unsigned int, void *,
                        unsigned int);
-int parse_vc_conf(struct context *, const struct token *,
+int cmd_parse_vc_conf(struct context *, const struct token *,
                        const char *, unsigned int, void *,
                        unsigned int);
-int parse_vc_action_rss_queue(struct context *,
+int cmd_parse_vc_action_rss_queue(struct context *,
                        const struct token *,
                        const char *, unsigned int, void *,
                        unsigned int);
-int parse_destroy(struct context *, const struct token *,
+int cmd_parse_destroy(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_flush(struct context *, const struct token *,
+int cmd_parse_flush(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_query(struct context *, const struct token *,
+int cmd_parse_query(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_action(struct context *, const struct token *,
+int cmd_parse_action(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_list(struct context *, const struct token *,
+int cmd_parse_list(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_isolate(struct context *, const struct token *,
+int cmd_parse_isolate(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_int(struct context *, const struct token *,
+int cmd_parse_int(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_string(struct context *, const struct token *,
+int cmd_parse_string(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_mac_addr(struct context *, const struct token *,
+int cmd_parse_mac_addr(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_ipv4_addr(struct context *, const struct token *,
+int cmd_parse_ipv4_addr(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_ipv6_addr(struct context *, const struct token *,
+int cmd_parse_ipv6_addr(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_boolean(struct context *, const struct token *,
+int cmd_parse_boolean(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
-int parse_port(struct context *, const struct token *,
+int cmd_parse_port(struct context *, const struct token *,
                        const char *, unsigned int,
                        void *, unsigned int);
 
@@ -920,23 +940,418 @@ void cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
 void cmd_flow_parsed(const struct buffer *in);
 void cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2);
 
-/** Generic flow management functions. */
-int port_flow_validate(portid_t port_id,
-                       const struct rte_flow_attr *attr,
-                       const struct rte_flow_item *pattern,
-                       const struct rte_flow_action *actions);
-int port_flow_create(portid_t port_id,
-                       const struct rte_flow_attr *attr,
-                       const struct rte_flow_item *pattern,
-                       const struct rte_flow_action *actions);
-int port_flow_destroy(portid_t port_id, uint32_t n,
-                       const uint32_t *rule);
-int port_flow_flush(portid_t port_id);
-int port_flow_query(portid_t port_id, uint32_t rule,
-                   enum rte_flow_action_type action);
-void port_flow_list(portid_t port_id, uint32_t n,
-                       const uint32_t *group);
-int port_flow_isolate(portid_t port_id, int set);
+/**
+ * Generic flow management functions.
+ *
+ * Allow the creation, validation, insertion, query,
+ * list, and deletion of a NIC's flows.
+ */
+
+/** Generate a port_flow entry from attributes/pattern/actions. */
+static inline struct port_flow *
+port_flow_new(const struct rte_flow_attr *attr,
+             const struct rte_flow_item *pattern,
+             const struct rte_flow_action *actions)
+{
+       const struct rte_flow_item *item;
+       const struct rte_flow_action *action;
+       struct port_flow *pf = NULL;
+       size_t tmp;
+       size_t pad;
+       size_t off1 = 0;
+       size_t off2 = 0;
+       int err = ENOTSUP;
+
+store:
+       item = pattern;
+       if (pf)
+               pf->pattern = (void *)&pf->data[off1];
+       do {
+               struct rte_flow_item *dst = NULL;
+
+               if ((unsigned int)item->type >= RTE_DIM(flow_item) ||
+                   !flow_item[item->type].name)
+                       goto notsup;
+               if (pf)
+                       dst = memcpy(pf->data + off1, item, sizeof(*item));
+               off1 += sizeof(*item);
+               flow_item_spec_size(item, &tmp, &pad);
+               if (item->spec) {
+                       if (pf)
+                               dst->spec = memcpy(pf->data + off2,
+                                                  item->spec, tmp);
+                       off2 += tmp + pad;
+               }
+               if (item->last) {
+                       if (pf)
+                               dst->last = memcpy(pf->data + off2,
+                                                  item->last, tmp);
+                       off2 += tmp + pad;
+               }
+               if (item->mask) {
+                       if (pf)
+                               dst->mask = memcpy(pf->data + off2,
+                                                  item->mask, tmp);
+                       off2 += tmp + pad;
+               }
+               off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
+       } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
+       off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
+       action = actions;
+       if (pf)
+               pf->actions = (void *)&pf->data[off1];
+       do {
+               struct rte_flow_action *dst = NULL;
+
+               if ((unsigned int)action->type >= RTE_DIM(flow_action) ||
+                   !flow_action[action->type].name)
+                       goto notsup;
+               if (pf)
+                       dst = memcpy(pf->data + off1, action, sizeof(*action));
+               off1 += sizeof(*action);
+               flow_action_conf_size(action, &tmp, &pad);
+               if (action->conf) {
+                       if (pf)
+                               dst->conf = memcpy(pf->data + off2,
+                                                  action->conf, tmp);
+                       off2 += tmp + pad;
+               }
+               off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
+       } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
+       if (pf != NULL)
+               return pf;
+       off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
+       tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double));
+       pf = calloc(1, tmp + off1 + off2);
+       if (pf == NULL)
+               err = errno;
+       else {
+               *pf = (const struct port_flow){
+                       .size = tmp + off1 + off2,
+                       .attr = *attr,
+               };
+               tmp -= offsetof(struct port_flow, data);
+               off2 = tmp + off1;
+               off1 = tmp;
+               goto store;
+       }
+notsup:
+       rte_errno = err;
+       return NULL;
+}
+
+/** Print a message out of a flow error. */
+inline int
+port_flow_complain(struct rte_flow_error *error)
+{
+       static const char *const errstrlist[] = {
+               [RTE_FLOW_ERROR_TYPE_NONE] = "no error",
+               [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+               [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
+               [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
+               [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
+               [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
+               [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
+               [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
+               [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
+               [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
+               [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
+               [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
+       };
+       const char *errstr;
+       char buf[32];
+       int err = rte_errno;
+
+       if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+           !errstrlist[error->type])
+               errstr = "unknown type";
+       else
+               errstr = errstrlist[error->type];
+       printf("Caught error type %d (%s): %s%s\n",
+              error->type, errstr,
+              error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
+                                       error->cause), buf) : "",
+              error->message ? error->message : "(no stated reason)");
+       return -err;
+}
+
+/** Validate flow rule. */
+inline int
+port_flow_validate(portid_t port_id,
+                  const struct rte_flow_attr *attr,
+                  const struct rte_flow_item *pattern,
+                  const struct rte_flow_action *actions)
+{
+       struct rte_flow_error error;
+
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x11, sizeof(error));
+       if (rte_flow_validate(port_id, attr, pattern, actions, &error))
+               return port_flow_complain(&error);
+       printf("Flow rule validated\n");
+       return 0;
+}
+
+/** Create flow rule. */
+static inline int
+port_flow_create(portid_t port_id,
+                const struct rte_flow_attr *attr,
+                const struct rte_flow_item *pattern,
+                const struct rte_flow_action *actions)
+{
+       struct rte_flow *flow;
+       struct rte_port *port;
+       struct port_flow *pf;
+       uint32_t id;
+       struct rte_flow_error error;
+
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x22, sizeof(error));
+       flow = rte_flow_create(port_id, attr, pattern, actions, &error);
+       if (!flow)
+               return port_flow_complain(&error);
+       port = &ports[port_id];
+       if (port->flow_list) {
+               if (port->flow_list->id == UINT32_MAX) {
+                       printf("Highest rule ID is already assigned, delete"
+                              " it first");
+                       rte_flow_destroy(port_id, flow, NULL);
+                       return -ENOMEM;
+               }
+               id = port->flow_list->id + 1;
+       } else
+               id = 0;
+       pf = port_flow_new(attr, pattern, actions);
+       if (!pf) {
+               int err = rte_errno;
+
+               printf("Cannot allocate flow: %s\n", rte_strerror(err));
+               rte_flow_destroy(port_id, flow, NULL);
+               return -err;
+       }
+       pf->next = port->flow_list;
+       pf->id = id;
+       pf->flow = flow;
+       port->flow_list = pf;
+       printf("Flow rule #%u created\n", pf->id);
+       return 0;
+}
+
+/** Destroy a number of flow rules. */
+inline int
+port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
+{
+       struct rte_port *port;
+       struct port_flow **tmp;
+       uint32_t c = 0;
+       int ret = 0;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+           port_id == (portid_t)RTE_PORT_ALL)
+               return -EINVAL;
+       port = &ports[port_id];
+       tmp = &port->flow_list;
+       while (*tmp) {
+               uint32_t i;
+
+               for (i = 0; i != n; ++i) {
+                       struct rte_flow_error error;
+                       struct port_flow *pf = *tmp;
+
+                       if (rule[i] != pf->id)
+                               continue;
+                       /*
+                        * Poisoning to make sure PMDs update it in case
+                        * of error.
+                        */
+                       memset(&error, 0x33, sizeof(error));
+                       if (rte_flow_destroy(port_id, pf->flow, &error)) {
+                               ret = port_flow_complain(&error);
+                               continue;
+                       }
+                       printf("Flow rule #%u destroyed\n", pf->id);
+                       *tmp = pf->next;
+                       free(pf);
+                       break;
+               }
+               if (i == n)
+                       tmp = &(*tmp)->next;
+               ++c;
+       }
+       return ret;
+}
+
+/** Remove all flow rules. */
+inline int
+port_flow_flush(portid_t port_id)
+{
+       struct rte_flow_error error;
+       struct rte_port *port;
+       int ret = 0;
+
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x44, sizeof(error));
+       if (rte_flow_flush(port_id, &error)) {
+               ret = port_flow_complain(&error);
+               if (port_id_is_invalid(port_id, DISABLED_WARN) ||
+                   port_id == (portid_t)RTE_PORT_ALL)
+                       return ret;
+       }
+       port = &ports[port_id];
+       while (port->flow_list) {
+               struct port_flow *pf = port->flow_list->next;
+
+               free(port->flow_list);
+               port->flow_list = pf;
+       }
+       return ret;
+}
+
+/** Query a flow rule. */
+static inline int
+port_flow_query(portid_t port_id, uint32_t rule,
+               enum rte_flow_action_type action)
+{
+       struct rte_flow_error error;
+       struct rte_port *port;
+       struct port_flow *pf;
+       const char *name;
+       union {
+               struct rte_flow_query_count count;
+       } query;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+           port_id == (portid_t)RTE_PORT_ALL)
+               return -EINVAL;
+       port = &ports[port_id];
+       for (pf = port->flow_list; pf; pf = pf->next)
+               if (pf->id == rule)
+                       break;
+       if (!pf) {
+               printf("Flow rule #%u not found\n", rule);
+               return -ENOENT;
+       }
+       if ((unsigned int)action >= RTE_DIM(flow_action) ||
+           !flow_action[action].name)
+               name = "unknown";
+       else
+               name = flow_action[action].name;
+       switch (action) {
+       case RTE_FLOW_ACTION_TYPE_COUNT:
+               break;
+       default:
+               printf("Cannot query action type %d (%s)\n", action, name);
+               return -ENOTSUP;
+       }
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x55, sizeof(error));
+       memset(&query, 0, sizeof(query));
+       if (rte_flow_query(port_id, pf->flow, action, &query, &error))
+               return port_flow_complain(&error);
+       switch (action) {
+       case RTE_FLOW_ACTION_TYPE_COUNT:
+               printf("%s:\n"
+                      " hits_set: %u\n"
+                      " bytes_set: %u\n"
+                      " hits: %" PRIu64 "\n"
+                      " bytes: %" PRIu64 "\n",
+                      name,
+                      query.count.hits_set,
+                      query.count.bytes_set,
+                      query.count.hits,
+                      query.count.bytes);
+               break;
+       default:
+               printf("Cannot display result for action type %d (%s)\n",
+                      action, name);
+               break;
+       }
+       return 0;
+}
+
+/** List flow rules. */
+static inline void
+port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
+{
+       struct rte_port *port;
+       struct port_flow *pf;
+       struct port_flow *list = NULL;
+       uint32_t i;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+           port_id == (portid_t)RTE_PORT_ALL)
+               return;
+       port = &ports[port_id];
+       if (!port->flow_list)
+               return;
+       /* Sort flows by group, priority and ID. */
+       for (pf = port->flow_list; pf != NULL; pf = pf->next) {
+               struct port_flow **tmp;
+
+               if (n) {
+                       /* Filter out unwanted groups. */
+                       for (i = 0; i != n; ++i)
+                               if (pf->attr.group == group[i])
+                                       break;
+                       if (i == n)
+                               continue;
+               }
+               tmp = &list;
+               while (*tmp &&
+                      (pf->attr.group > (*tmp)->attr.group ||
+                       (pf->attr.group == (*tmp)->attr.group &&
+                        pf->attr.priority > (*tmp)->attr.priority) ||
+                       (pf->attr.group == (*tmp)->attr.group &&
+                        pf->attr.priority == (*tmp)->attr.priority &&
+                        pf->id > (*tmp)->id)))
+                       tmp = &(*tmp)->tmp;
+               pf->tmp = *tmp;
+               *tmp = pf;
+       }
+       printf("ID\tGroup\tPrio\tAttr\tRule\n");
+       for (pf = list; pf != NULL; pf = pf->tmp) {
+               const struct rte_flow_item *item = pf->pattern;
+               const struct rte_flow_action *action = pf->actions;
+
+               printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t",
+                      pf->id,
+                      pf->attr.group,
+                      pf->attr.priority,
+                      pf->attr.ingress ? 'i' : '-',
+                      pf->attr.egress ? 'e' : '-');
+               while (item->type != RTE_FLOW_ITEM_TYPE_END) {
+                       if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
+                               printf("%s ", flow_item[item->type].name);
+                       ++item;
+               }
+               printf("=>");
+               while (action->type != RTE_FLOW_ACTION_TYPE_END) {
+                       if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
+                               printf(" %s", flow_action[action->type].name);
+                       ++action;
+               }
+               printf("\n");
+       }
+}
+
+/** Restrict ingress traffic to the defined flow rules. */
+inline int
+port_flow_isolate(portid_t port_id, int set)
+{
+       struct rte_flow_error error;
+
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x66, sizeof(error));
+       if (rte_flow_isolate(port_id, set, &error))
+               return port_flow_complain(&error);
+       printf("Ingress traffic on port %u is %s to the defined flow rules\n",
+              port_id,
+              set ? "now restricted" : "not restricted anymore");
+       return 0;
+}
+
+/** Global parser instance (cmdline API). */
+extern cmdline_parse_inst_t cmd_flow;
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -956,84 +1371,84 @@ static const struct token token_list[] = {
                .name = "{int}",
                .type = "INTEGER",
                .help = "integer value",
-               .call = parse_int,
+               .call = cmd_parse_int,
                .comp = comp_none,
        },
        [UNSIGNED] = {
                .name = "{unsigned}",
                .type = "UNSIGNED",
                .help = "unsigned integer value",
-               .call = parse_int,
+               .call = cmd_parse_int,
                .comp = comp_none,
        },
        [PREFIX] = {
                .name = "{prefix}",
                .type = "PREFIX",
                .help = "prefix length for bit-mask",
-               .call = parse_prefix,
+               .call = cmd_parse_prefix,
                .comp = comp_none,
        },
        [BOOLEAN] = {
                .name = "{boolean}",
                .type = "BOOLEAN",
                .help = "any boolean value",
-               .call = parse_boolean,
+               .call = cmd_parse_boolean,
                .comp = comp_boolean,
        },
        [STRING] = {
                .name = "{string}",
                .type = "STRING",
                .help = "fixed string",
-               .call = parse_string,
+               .call = cmd_parse_string,
                .comp = comp_none,
        },
        [MAC_ADDR] = {
                .name = "{MAC address}",
                .type = "MAC-48",
                .help = "standard MAC address notation",
-               .call = parse_mac_addr,
+               .call = cmd_parse_mac_addr,
                .comp = comp_none,
        },
        [IPV4_ADDR] = {
                .name = "{IPv4 address}",
                .type = "IPV4 ADDRESS",
                .help = "standard IPv4 address notation",
-               .call = parse_ipv4_addr,
+               .call = cmd_parse_ipv4_addr,
                .comp = comp_none,
        },
        [IPV6_ADDR] = {
                .name = "{IPv6 address}",
                .type = "IPV6 ADDRESS",
                .help = "standard IPv6 address notation",
-               .call = parse_ipv6_addr,
+               .call = cmd_parse_ipv6_addr,
                .comp = comp_none,
        },
        [RULE_ID] = {
                .name = "{rule id}",
                .type = "RULE ID",
                .help = "rule identifier",
-               .call = parse_int,
+               .call = cmd_parse_int,
                .comp = comp_rule_id,
        },
        [PORT_ID] = {
                .name = "{port_id}",
                .type = "PORT ID",
                .help = "port identifier",
-               .call = parse_port,
+               .call = cmd_parse_port,
                .comp = comp_port,
        },
        [GROUP_ID] = {
                .name = "{group_id}",
                .type = "GROUP ID",
                .help = "group identifier",
-               .call = parse_int,
+               .call = cmd_parse_int,
                .comp = comp_none,
        },
        [PRIORITY_LEVEL] = {
                .name = "{level}",
                .type = "PRIORITY",
                .help = "priority level",
-               .call = parse_int,
+               .call = cmd_parse_int,
                .comp = comp_none,
        },
        /* Top-level command. */
@@ -1049,7 +1464,7 @@ static const struct token token_list[] = {
                                  LIST,
                                  QUERY,
                                  ISOLATE)),
-               .call = parse_init,
+               .call = cmd_parse_init,
        },
        /* Sub-level commands. */
        [VALIDATE] = {
@@ -1057,28 +1472,28 @@ static const struct token token_list[] = {
                .help = "check whether a flow rule can be created",
                .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [CREATE] = {
                .name = "create",
                .help = "create a flow rule",
                .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [DESTROY] = {
                .name = "destroy",
                .help = "destroy specific flow rules",
                .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
-               .call = parse_destroy,
+               .call = cmd_parse_destroy,
        },
        [FLUSH] = {
                .name = "flush",
                .help = "destroy all flow rules",
                .next = NEXT(NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
-               .call = parse_flush,
+               .call = cmd_parse_flush,
        },
        [QUERY] = {
                .name = "query",
@@ -1089,14 +1504,14 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
                                 ARGS_ENTRY(struct buffer, args.query.rule),
                                 ARGS_ENTRY(struct buffer, port)),
-               .call = parse_query,
+               .call = cmd_parse_query,
        },
        [LIST] = {
                .name = "list",
                .help = "list existing flow rules",
                .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
-               .call = parse_list,
+               .call = cmd_parse_list,
        },
        [ISOLATE] = {
                .name = "isolate",
@@ -1105,7 +1520,7 @@ static const struct token token_list[] = {
                                 NEXT_ENTRY(PORT_ID)),
                .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
                                 ARGS_ENTRY(struct buffer, port)),
-               .call = parse_isolate,
+               .call = cmd_parse_isolate,
        },
        /* Destroy arguments. */
        [DESTROY_RULE] = {
@@ -1113,14 +1528,14 @@ static const struct token token_list[] = {
                .help = "specify a rule identifier",
                .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
                .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
-               .call = parse_destroy,
+               .call = cmd_parse_destroy,
        },
        /* Query arguments. */
        [QUERY_ACTION] = {
                .name = "{action}",
                .type = "ACTION",
                .help = "action to query, must be part of the rule",
-               .call = parse_action,
+               .call = cmd_parse_action,
                .comp = comp_action,
        },
        /* List arguments. */
@@ -1129,7 +1544,7 @@ static const struct token token_list[] = {
                .help = "specify a group",
                .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
                .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
-               .call = parse_list,
+               .call = cmd_parse_list,
        },
        /* Validate/create attributes. */
        [GROUP] = {
@@ -1137,58 +1552,58 @@ static const struct token token_list[] = {
                .help = "specify a group",
                .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [PRIORITY] = {
                .name = "priority",
                .help = "specify a priority level",
                .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [INGRESS] = {
                .name = "ingress",
                .help = "affect rule to ingress",
                .next = NEXT(next_vc_attr),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [EGRESS] = {
                .name = "egress",
                .help = "affect rule to egress",
                .next = NEXT(next_vc_attr),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        /* Validate/create pattern. */
        [PATTERN] = {
                .name = "pattern",
                .help = "submit a list of pattern items",
                .next = NEXT(next_item),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_PARAM_IS] = {
                .name = "is",
                .help = "match value perfectly (with full bit-mask)",
-               .call = parse_vc_spec,
+               .call = cmd_parse_vc_spec,
        },
        [ITEM_PARAM_SPEC] = {
                .name = "spec",
                .help = "match value according to configured bit-mask",
-               .call = parse_vc_spec,
+               .call = cmd_parse_vc_spec,
        },
        [ITEM_PARAM_LAST] = {
                .name = "last",
                .help = "specify upper bound to establish a range",
-               .call = parse_vc_spec,
+               .call = cmd_parse_vc_spec,
        },
        [ITEM_PARAM_MASK] = {
                .name = "mask",
                .help = "specify bit-mask with relevant bits set to one",
-               .call = parse_vc_spec,
+               .call = cmd_parse_vc_spec,
        },
        [ITEM_PARAM_PREFIX] = {
                .name = "prefix",
                .help = "generate bit-mask from a prefix length",
-               .call = parse_vc_spec,
+               .call = cmd_parse_vc_spec,
        },
        [ITEM_NEXT] = {
                .name = "/",
@@ -1200,28 +1615,28 @@ static const struct token token_list[] = {
                .help = "end list of pattern items",
                .priv = PRIV_ITEM(END, 0),
                .next = NEXT(NEXT_ENTRY(ACTIONS)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_VOID] = {
                .name = "void",
                .help = "no-op pattern item",
                .priv = PRIV_ITEM(VOID, 0),
                .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_INVERT] = {
                .name = "invert",
                .help = "perform actions when pattern does not match",
                .priv = PRIV_ITEM(INVERT, 0),
                .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_ANY] = {
                .name = "any",
                .help = "match any protocol for the current layer",
                .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
                .next = NEXT(item_any),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_ANY_NUM] = {
                .name = "num",
@@ -1234,14 +1649,14 @@ static const struct token token_list[] = {
                .help = "match packets addressed to the physical function",
                .priv = PRIV_ITEM(PF, 0),
                .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_VF] = {
                .name = "vf",
                .help = "match packets addressed to a virtual function ID",
                .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
                .next = NEXT(item_vf),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_VF_ID] = {
                .name = "id",
@@ -1254,7 +1669,7 @@ static const struct token token_list[] = {
                .help = "device-specific physical port index to use",
                .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)),
                .next = NEXT(item_port),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_PORT_INDEX] = {
                .name = "index",
@@ -1267,7 +1682,7 @@ static const struct token token_list[] = {
                .help = "match an arbitrary byte string",
                .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
                .next = NEXT(item_raw),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_RAW_RELATIVE] = {
                .name = "relative",
@@ -1313,7 +1728,7 @@ static const struct token token_list[] = {
                .help = "match Ethernet header",
                .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
                .next = NEXT(item_eth),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_ETH_DST] = {
                .name = "dst",
@@ -1338,7 +1753,7 @@ static const struct token token_list[] = {
                .help = "match 802.1Q/ad VLAN tag",
                .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
                .next = NEXT(item_vlan),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_VLAN_TPID] = {
                .name = "tpid",
@@ -1378,7 +1793,7 @@ static const struct token token_list[] = {
                .help = "match IPv4 header",
                .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
                .next = NEXT(item_ipv4),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_IPV4_TOS] = {
                .name = "tos",
@@ -1420,7 +1835,7 @@ static const struct token token_list[] = {
                .help = "match IPv6 header",
                .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
                .next = NEXT(item_ipv6),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_IPV6_TC] = {
                .name = "tc",
@@ -1471,7 +1886,7 @@ static const struct token token_list[] = {
                .help = "match ICMP header",
                .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
                .next = NEXT(item_icmp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_ICMP_TYPE] = {
                .name = "type",
@@ -1492,7 +1907,7 @@ static const struct token token_list[] = {
                .help = "match UDP header",
                .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
                .next = NEXT(item_udp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_UDP_SRC] = {
                .name = "src",
@@ -1513,7 +1928,7 @@ static const struct token token_list[] = {
                .help = "match TCP header",
                .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
                .next = NEXT(item_tcp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_TCP_SRC] = {
                .name = "src",
@@ -1541,7 +1956,7 @@ static const struct token token_list[] = {
                .help = "match SCTP header",
                .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
                .next = NEXT(item_sctp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_SCTP_SRC] = {
                .name = "src",
@@ -1576,7 +1991,7 @@ static const struct token token_list[] = {
                .help = "match VXLAN header",
                .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
                .next = NEXT(item_vxlan),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_VXLAN_VNI] = {
                .name = "vni",
@@ -1589,7 +2004,7 @@ static const struct token token_list[] = {
                .help = "match E-Tag header",
                .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
                .next = NEXT(item_e_tag),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_E_TAG_GRP_ECID_B] = {
                .name = "grp_ecid_b",
@@ -1604,7 +2019,7 @@ static const struct token token_list[] = {
                .help = "match NVGRE header",
                .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
                .next = NEXT(item_nvgre),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_NVGRE_TNI] = {
                .name = "tni",
@@ -1617,7 +2032,7 @@ static const struct token token_list[] = {
                .help = "match MPLS header",
                .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
                .next = NEXT(item_mpls),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_MPLS_LABEL] = {
                .name = "label",
@@ -1632,7 +2047,7 @@ static const struct token token_list[] = {
                .help = "match GRE header",
                .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
                .next = NEXT(item_gre),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_GRE_PROTO] = {
                .name = "protocol",
@@ -1647,7 +2062,7 @@ static const struct token token_list[] = {
                .priv = PRIV_ITEM(FUZZY,
                                sizeof(struct rte_flow_item_fuzzy)),
                .next = NEXT(item_fuzzy),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_FUZZY_THRESH] = {
                .name = "thresh",
@@ -1661,7 +2076,7 @@ static const struct token token_list[] = {
                .help = "match GTP header",
                .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
                .next = NEXT(item_gtp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_GTP_TEID] = {
                .name = "teid",
@@ -1674,14 +2089,14 @@ static const struct token token_list[] = {
                .help = "match GTP header",
                .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
                .next = NEXT(item_gtp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ITEM_GTPU] = {
                .name = "gtpu",
                .help = "match GTP header",
                .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
                .next = NEXT(item_gtp),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
 
        /* Validate/create actions. */
@@ -1689,7 +2104,7 @@ static const struct token token_list[] = {
                .name = "actions",
                .help = "submit a list of associated actions",
                .next = NEXT(next_action),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_NEXT] = {
                .name = "/",
@@ -1700,42 +2115,42 @@ static const struct token token_list[] = {
                .name = "end",
                .help = "end list of actions",
                .priv = PRIV_ACTION(END, 0),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_VOID] = {
                .name = "void",
                .help = "no-op action",
                .priv = PRIV_ACTION(VOID, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_PASSTHRU] = {
                .name = "passthru",
                .help = "let subsequent rule process matched packets",
                .priv = PRIV_ACTION(PASSTHRU, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_MARK] = {
                .name = "mark",
                .help = "attach 32 bit value to packets",
                .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
                .next = NEXT(action_mark),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_MARK_ID] = {
                .name = "id",
                .help = "32 bit value to return with packets",
                .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_FLAG] = {
                .name = "flag",
                .help = "flag packets",
                .priv = PRIV_ACTION(FLAG, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_QUEUE] = {
                .name = "queue",
@@ -1743,60 +2158,60 @@ static const struct token token_list[] = {
                .priv = PRIV_ACTION(QUEUE,
                                        sizeof(struct rte_flow_action_queue)),
                .next = NEXT(action_queue),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_QUEUE_INDEX] = {
                .name = "index",
                .help = "queue index to use",
                .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_DROP] = {
                .name = "drop",
                .help = "drop packets (note: passthru has priority)",
                .priv = PRIV_ACTION(DROP, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_COUNT] = {
                .name = "count",
                .help = "enable counters for this rule",
                .priv = PRIV_ACTION(COUNT, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_DUP] = {
                .name = "dup",
                .help = "duplicate packets to a given queue index",
                .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)),
                .next = NEXT(action_dup),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_DUP_INDEX] = {
                .name = "index",
                .help = "queue index to duplicate packets to",
                .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_RSS] = {
                .name = "rss",
                .help = "spread packets among several queues",
                .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE),
                .next = NEXT(action_rss),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_RSS_QUEUES] = {
                .name = "queues",
                .help = "queue indices to use",
                .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_RSS_QUEUE] = {
                .name = "{queue}",
                .help = "queue index",
-               .call = parse_vc_action_rss_queue,
+               .call = cmd_parse_vc_action_rss_queue,
                .comp = comp_vc_action_rss_queue,
        },
        [ACTION_PF] = {
@@ -1804,14 +2219,14 @@ static const struct token token_list[] = {
                .help = "redirect packets to physical device function",
                .priv = PRIV_ACTION(PF, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_VF] = {
                .name = "vf",
                .help = "redirect packets to virtual device function",
                .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
                .next = NEXT(action_vf),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_VF_ORIGINAL] = {
                .name = "original",
@@ -1819,14 +2234,14 @@ static const struct token token_list[] = {
                .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
                .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
                                           original, 1)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_VF_ID] = {
                .name = "id",
                .help = "VF ID to redirect packets to",
                .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
        [ACTION_METER] = {
                .name = "meter",
@@ -1834,14 +2249,14 @@ static const struct token token_list[] = {
                .priv = PRIV_ACTION(METER,
                                        sizeof(struct rte_flow_action_meter)),
                .next = NEXT(action_meter),
-               .call = parse_vc,
+               .call = cmd_parse_vc,
        },
        [ACTION_METER_ID] = {
                .name = "mtr_id",
                .help = "meter id to use",
                .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
-               .call = parse_vc_conf,
+               .call = cmd_parse_vc_conf,
        },
 };
 
diff --git a/lib/librte_ether/rte_flow.c b/lib/librte_ether/rte_flow.c
index 3302208..e437d03 100644
--- a/lib/librte_ether/rte_flow.c
+++ b/lib/librte_ether/rte_flow.c
@@ -249,7 +249,7 @@ rte_flow_error_set(struct rte_flow_error *error,
 }
 
 /** Compute storage space needed by item specification. */
-void
+static void
 flow_item_spec_size(const struct rte_flow_item *item,
                    size_t *size, size_t *pad)
 {
@@ -277,7 +277,7 @@ flow_item_spec_size(const struct rte_flow_item *item,
 }
 
 /** Compute storage space needed by action configuration. */
-void
+static void
 flow_action_conf_size(const struct rte_flow_action *action,
                      size_t *size, size_t *pad)
 {
diff --git a/lib/librte_ether/rte_flow.h b/lib/librte_ether/rte_flow.h
index c2184b6..4178203 100644
--- a/lib/librte_ether/rte_flow.h
+++ b/lib/librte_ether/rte_flow.h
@@ -1180,16 +1180,6 @@ struct rte_flow_action {
  */
 struct rte_flow;
 
-/** Compute storage space needed by item specification. */
-void
-flow_item_spec_size(const struct rte_flow_item *item,
-                   size_t *size, size_t *pad);
-
-/** Compute storage space needed by action configuration. */
-void
-flow_action_conf_size(const struct rte_flow_action *action,
-                   size_t *size, size_t *pad);
-
 /**
  * Verbose error types.
  *
-- 
2.7.4

Reply via email to