All of lore.kernel.org
 help / color / mirror / Atom feed
From: Georgios Katsikas <george.dit@gmail.com>
To: olivier.matz@6wind.com
Cc: dev@dpdk.org, Georgios Katsikas <george.dit@gmail.com>
Subject: [PATCH 3/3] lib/cmdline: Cross platform fixes for cmdline_flow
Date: Fri, 12 Jan 2018 22:01:27 +0100	[thread overview]
Message-ID: <1515790887-64502-3-git-send-email-george.dit@gmail.com> (raw)
In-Reply-To: <1515790887-64502-1-git-send-email-george.dit@gmail.com>

Signed-off-by: Georgios Katsikas <george.dit@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

  parent reply	other threads:[~2018-01-12 21:02 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-12 21:01 [PATCH 1/3] app/testpmd: Moved cmdline_flow to librte_cmdline Georgios Katsikas
2018-01-12 21:01 ` [PATCH 2/3] app/testpmd: Added new line and parenthesized macros Georgios Katsikas
2018-01-12 21:01 ` Georgios Katsikas [this message]
2018-01-15  1:30 ` [PATCH 1/3] app/testpmd: Moved cmdline_flow to librte_cmdline Lu, Wenzhuo
2018-01-16  8:39   ` Olivier Matz
2018-01-16  8:45     ` george.dit
2018-01-16  9:24       ` Olivier Matz
2018-01-16  9:49         ` Gaëtan Rivet
2018-01-16 14:31         ` Adrien Mazarguil
2018-01-16 14:54           ` george.dit
2018-01-16 17:54             ` Adrien Mazarguil
2018-01-24 11:57               ` george.dit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1515790887-64502-3-git-send-email-george.dit@gmail.com \
    --to=george.dit@gmail.com \
    --cc=dev@dpdk.org \
    --cc=olivier.matz@6wind.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.