All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] ip_pipeline: CLI rework and improvements
@ 2016-05-06 15:57 Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 1/6] examples/ip_pipeline: add helper functions for parsing string Michal Jastrzebski
                   ` (6 more replies)
  0 siblings, 7 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev

Using the latest librte_cmdline improvements, the CLI implementation
of the ip_pipeline application is streamlined and improved, which
results in eliminating thousands of lines of code from the application,
thus leading to code that is easier to maintain and extend.

Michal Jastrzebski (6):
  examples/ip_pipeline: add helper functions for parsing string
  examples/ip_pipeline: modifies common pipeline CLI
  examples/ip_pipeline: modifies routing commands
  examples/ip_pipeline: modifies firewall pipeline CLI
  examples/ip_pipeline: modifies flow classifications      pipeline CLI
  examples/ip_pipeline: modifies flow action pipeline CLI

 examples/ip_pipeline/Makefile                      |    1 +
 examples/ip_pipeline/config_parse.c                |  242 +--
 examples/ip_pipeline/parser.c                      |  684 +++++++
 examples/ip_pipeline/parser.h                      |   26 +-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  309 ++-
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1336 ++++++-------
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1826 ++++++++---------
 .../pipeline/pipeline_flow_classification.c        | 2066 ++++++++------------
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1774 +++++------------
 9 files changed, 3523 insertions(+), 4741 deletions(-)
 create mode 100644 examples/ip_pipeline/parser.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 1/6] examples/ip_pipeline: add helper functions for parsing string
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 2/6] examples/ip_pipeline: modifies common pipeline CLI Michal Jastrzebski
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Add a couple of additional functions that will allow to parse many types
of input parameters, i.e.: bool, 16, 32, 64 bits, hex, etc.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
---
 examples/ip_pipeline/Makefile       |   1 +
 examples/ip_pipeline/config_parse.c | 242 +------------
 examples/ip_pipeline/parser.c       | 684 ++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/parser.h       |  26 +-
 4 files changed, 713 insertions(+), 240 deletions(-)
 create mode 100644 examples/ip_pipeline/parser.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 10fe1ba..5827117 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -50,6 +50,7 @@ INC += $(wildcard *.h) $(wildcard pipeline/*.h)
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += parser.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index e5efd03..f70e051 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -30,6 +30,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -49,6 +50,8 @@
 #include "app.h"
 #include "parser.h"
 
+#define PARSE_DELIMITER		" \f\n\r\t\v"
+
 /**
  * Default config values
  **/
@@ -248,44 +251,6 @@ do {									\
 		"Parse error in section \"%s\"", section_name);		\
 } while (0)
 
-int
-parser_read_arg_bool(const char *p)
-{
-	p = skip_white_spaces(p);
-	int result = -EINVAL;
-
-	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
-		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
-		p += 3;
-		result = 1;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'n')) ||
-		((p[0] == 'O') && (p[1] == 'N'))) {
-		p += 2;
-		result = 1;
-	}
-
-	if (((p[0] == 'n') && (p[1] == 'o')) ||
-		((p[0] == 'N') && (p[1] == 'O'))) {
-		p += 2;
-		result = 0;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
-		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
-		p += 3;
-		result = 0;
-	}
-
-	p = skip_white_spaces(p);
-
-	if (p[0] != '\0')
-		return -EINVAL;
-
-	return result;
-}
-
 #define PARSE_ERROR(exp, section, entry)				\
 APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"\n", section, entry)
 
@@ -318,207 +283,6 @@ APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"\n",\
 APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"\n",\
 	section, entry)
 
-int
-parser_read_uint64(uint64_t *value, const char *p)
-{
-	char *next;
-	uint64_t val;
-
-	p = skip_white_spaces(p);
-	if (!isdigit(*p))
-		return -EINVAL;
-
-	val = strtoul(p, &next, 10);
-	if (p == next)
-		return -EINVAL;
-
-	p = next;
-	switch (*p) {
-	case 'T':
-		val *= 1024ULL;
-		/* fall through */
-	case 'G':
-		val *= 1024ULL;
-		/* fall through */
-	case 'M':
-		val *= 1024ULL;
-		/* fall through */
-	case 'k':
-	case 'K':
-		val *= 1024ULL;
-		p++;
-		break;
-	}
-
-	p = skip_white_spaces(p);
-	if (*p != '\0')
-		return -EINVAL;
-
-	*value = val;
-	return 0;
-}
-
-int
-parser_read_uint32(uint32_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT32_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
-{
-	size_t num_len;
-	char num[8];
-
-	uint32_t s = 0, c = 0, h = 0, val;
-	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
-	const char *next = skip_white_spaces(entry);
-	char type;
-
-	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
-	while (*next != '\0') {
-		/* If everything parsed nothing should left */
-		if (s_parsed && c_parsed && h_parsed)
-			return -EINVAL;
-
-		type = *next;
-		switch (type) {
-		case 's':
-		case 'S':
-			if (s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-			s_parsed = 1;
-			next++;
-			break;
-		case 'c':
-		case 'C':
-			if (c_parsed || h_parsed)
-				return -EINVAL;
-			c_parsed = 1;
-			next++;
-			break;
-		case 'h':
-		case 'H':
-			if (h_parsed)
-				return -EINVAL;
-			h_parsed = 1;
-			next++;
-			break;
-		default:
-			/* If it start from digit it must be only core id. */
-			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-
-			type = 'C';
-		}
-
-		for (num_len = 0; *next != '\0'; next++, num_len++) {
-			if (num_len == RTE_DIM(num))
-				return -EINVAL;
-
-			if (!isdigit(*next))
-				break;
-
-			num[num_len] = *next;
-		}
-
-		if (num_len == 0 && type != 'h' && type != 'H')
-			return -EINVAL;
-
-		if (num_len != 0 && (type == 'h' || type == 'H'))
-			return -EINVAL;
-
-		num[num_len] = '\0';
-		val = strtol(num, NULL, 10);
-
-		h = 0;
-		switch (type) {
-		case 's':
-		case 'S':
-			s = val;
-			break;
-		case 'c':
-		case 'C':
-			c = val;
-			break;
-		case 'h':
-		case 'H':
-			h = 1;
-			break;
-		}
-	}
-
-	*socket = s;
-	*core = c;
-	*ht = h;
-	return 0;
-}
-
-static uint32_t
-get_hex_val(char c)
-{
-	switch (c) {
-	case '0': case '1': case '2': case '3': case '4': case '5':
-	case '6': case '7': case '8': case '9':
-		return c - '0';
-	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-		return c - 'A' + 10;
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-		return c - 'a' + 10;
-	default:
-		return 0;
-	}
-}
-
-int
-parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
-{
-	char *c;
-	uint32_t len, i;
-
-	/* Check input parameters */
-	if ((src == NULL) ||
-		(dst == NULL) ||
-		(size == NULL) ||
-		(*size == 0))
-		return -1;
-
-	len = strlen(src);
-	if (((len & 3) != 0) ||
-		(len > (*size) * 2))
-		return -1;
-	*size = len / 2;
-
-	for (c = src; *c != 0; c++) {
-		if ((((*c) >= '0') && ((*c) <= '9')) ||
-			(((*c) >= 'A') && ((*c) <= 'F')) ||
-			(((*c) >= 'a') && ((*c) <= 'f')))
-			continue;
-
-		return -1;
-	}
-
-	/* Convert chars to bytes */
-	for (i = 0; i < *size; i++)
-		dst[i] = get_hex_val(src[2 * i]) * 16 +
-			get_hex_val(src[2 * i + 1]);
-
-	return 0;
-}
-
 static size_t
 skip_digits(const char *src)
 {
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
new file mode 100644
index 0000000..4e15178
--- /dev/null
+++ b/examples/ip_pipeline/parser.c
@@ -0,0 +1,684 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For my_ether_aton() function:
+ *
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For inet_pton4() and inet_pton6() functions:
+ *
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+#include "parser.h"
+
+#define PARSE_DELIMITER		" \f\n\r\t\v"
+
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++);		\
+	_p;					\
+})
+
+static uint32_t
+get_hex_val(char c)
+{
+	switch (c) {
+	case '0': case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+		return c - '0';
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+		return c - 'A' + 10;
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+		return c - 'a' + 10;
+	default:
+		return 0;
+	}
+}
+
+int
+parser_read_arg_bool(const char *p)
+{
+	p = skip_white_spaces(p);
+	int result = -EINVAL;
+
+	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+		p += 3;
+		result = 1;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'n')) ||
+		((p[0] == 'O') && (p[1] == 'N'))) {
+		p += 2;
+		result = 1;
+	}
+
+	if (((p[0] == 'n') && (p[1] == 'o')) ||
+		((p[0] == 'N') && (p[1] == 'O'))) {
+		p += 2;
+		result = 0;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+		p += 3;
+		result = 0;
+	}
+
+	p = skip_white_spaces(p);
+
+	if (p[0] != '\0')
+		return -EINVAL;
+
+	return result;
+}
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
+{
+	uint32_t i;
+
+	if ((string == NULL) ||
+		(tokens == NULL) ||
+		(*n_tokens < 1))
+		return -EINVAL;
+
+	for (i = 0; i < *n_tokens; i++) {
+		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
+		if (tokens[i] == NULL)
+			break;
+	}
+
+	if ((i == *n_tokens) &&
+		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
+		return -E2BIG;
+
+	*n_tokens = i;
+	return 0;
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+	char *c;
+	uint32_t len, i;
+
+	/* Check input parameters */
+	if ((src == NULL) ||
+		(dst == NULL) ||
+		(size == NULL) ||
+		(*size == 0))
+		return -1;
+
+	len = strlen(src);
+	if (((len & 3) != 0) ||
+		(len > (*size) * 2))
+		return -1;
+	*size = len / 2;
+
+	for (c = src; *c != 0; c++) {
+		if ((((*c) >= '0') && ((*c) <= '9')) ||
+			(((*c) >= 'A') && ((*c) <= 'F')) ||
+			(((*c) >= 'a') && ((*c) <= 'f')))
+			continue;
+
+		return -1;
+	}
+
+	/* Convert chars to bytes */
+	for (i = 0; i < *size; i++)
+		dst[i] = get_hex_val(src[2 * i]) * 16 +
+			get_hex_val(src[2 * i + 1]);
+
+	return 0;
+}
+
+int
+parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels)
+{
+	uint32_t n_max_labels = *n_labels, count = 0;
+
+	/* Check for void list of labels */
+	if (strcmp(string, "<void>") == 0) {
+		*n_labels = 0;
+		return 0;
+	}
+
+	/* At least one label should be present */
+	for ( ; (*string != '\0'); ) {
+		char *next;
+		int value;
+
+		if (count >= n_max_labels)
+			return -1;
+
+		if (count > 0) {
+			if (string[0] != ':')
+				return -1;
+
+			string++;
+		}
+
+		value = strtol(string, &next, 10);
+		if (next == string)
+			return -1;
+		string = next;
+
+		labels[count++] = (uint32_t) value;
+	}
+
+	*n_labels = count;
+	return 0;
+}
+
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+	static const char digits[] = "0123456789";
+	int saw_digit, octets, ch;
+	unsigned char tmp[INADDRSZ], *tp;
+
+	saw_digit = 0;
+	octets = 0;
+	*(tp = tmp) = 0;
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		if ((pch = strchr(digits, ch)) != NULL) {
+			unsigned int new = *tp * 10 + (pch - digits);
+
+			if (new > 255)
+				return 0;
+			if (! saw_digit) {
+				if (++octets > 4)
+					return 0;
+				saw_digit = 1;
+			}
+			*tp = (unsigned char)new;
+		} else if (ch == '.' && saw_digit) {
+			if (octets == 4)
+				return 0;
+			*++tp = 0;
+			saw_digit = 0;
+		} else
+			return 0;
+	}
+	if (octets < 4)
+		return 0;
+
+	memcpy(dst, tmp, INADDRSZ);
+	return 1;
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+	static const char xdigits_l[] = "0123456789abcdef",
+		xdigits_u[] = "0123456789ABCDEF";
+	unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
+	const char *xdigits = 0, *curtok = 0;
+	int ch = 0, saw_xdigit = 0, count_xdigit = 0;
+	unsigned int val = 0;
+	unsigned dbloct_count = 0;
+
+	memset((tp = tmp), '\0', IN6ADDRSZ);
+	endp = tp + IN6ADDRSZ;
+	colonp = NULL;
+	/* Leading :: requires some special handling. */
+	if (*src == ':')
+		if (*++src != ':')
+			return 0;
+	curtok = src;
+	saw_xdigit = count_xdigit = 0;
+	val = 0;
+
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+			pch = strchr((xdigits = xdigits_u), ch);
+		if (pch != NULL) {
+			if (count_xdigit >= 4)
+				return 0;
+			val <<= 4;
+			val |= (pch - xdigits);
+			if (val > 0xffff)
+				return 0;
+			saw_xdigit = 1;
+			count_xdigit++;
+			continue;
+		}
+		if (ch == ':') {
+			curtok = src;
+			if (!saw_xdigit) {
+				if (colonp)
+					return 0;
+				colonp = tp;
+				continue;
+			} else if (*src == '\0') {
+				return 0;
+			}
+			if (tp + sizeof(int16_t) > endp)
+				return 0;
+			*tp++ = (unsigned char) ((val >> 8) & 0xff);
+			*tp++ = (unsigned char) (val & 0xff);
+			saw_xdigit = 0;
+			count_xdigit = 0;
+			val = 0;
+			dbloct_count++;
+			continue;
+		}
+		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+		    inet_pton4(curtok, tp) > 0) {
+			tp += INADDRSZ;
+			saw_xdigit = 0;
+			dbloct_count += 2;
+			break;  /* '\0' was seen by inet_pton4(). */
+		}
+		return 0;
+	}
+	if (saw_xdigit) {
+		if (tp + sizeof(int16_t) > endp)
+			return 0;
+		*tp++ = (unsigned char) ((val >> 8) & 0xff);
+		*tp++ = (unsigned char) (val & 0xff);
+		dbloct_count++;
+	}
+	if (colonp != NULL) {
+		/* if we already have 8 double octets, having a colon means error */
+		if (dbloct_count == 8)
+			return 0;
+
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		const int n = tp - colonp;
+		int i;
+
+		for (i = 1; i <= n; i++) {
+			endp[- i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+	if (tp != endp)
+		return 0;
+	memcpy(dst, tmp, IN6ADDRSZ);
+	return 1;
+}
+
+static struct ether_addr *
+my_ether_aton(const char *a)
+{
+	int i;
+	char *end;
+	unsigned long o[ETHER_ADDR_LEN];
+	static struct ether_addr ether_addr;
+
+	i = 0;
+	do {
+		errno = 0;
+		o[i] = strtoul(a, &end, 16);
+		if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
+			return NULL;
+		a = end + 1;
+	} while (++i != sizeof (o) / sizeof (o[0]) && end[0] != 0);
+
+	/* Junk at the end of line */
+	if (end[0] != 0)
+		return NULL;
+
+	/* Support the format XX:XX:XX:XX:XX:XX */
+	if (i == ETHER_ADDR_LEN) {
+		while (i-- != 0) {
+			if (o[i] > UINT8_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i] = (uint8_t)o[i];
+		}
+	/* Support the format XXXX:XXXX:XXXX */
+	} else if (i == ETHER_ADDR_LEN / 2) {
+		while (i-- != 0) {
+			if (o[i] > UINT16_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
+			ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
+		}
+	/* unknown format */
+	} else
+		return NULL;
+
+	return (struct ether_addr *)&ether_addr;
+}
+
+int
+parse_ipv4_addr(const char *token, struct in_addr *ipv4)
+{
+	if (strlen(token) >= INET_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton4(token, (unsigned char *)ipv4) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_ipv6_addr(const char *token, struct in6_addr *ipv6)
+{
+	if (strlen(token) >= INET6_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton6(token, (unsigned char *)ipv6) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_mac_addr(const char *token, struct ether_addr *addr)
+{
+	struct ether_addr *tmp;
+
+	tmp = my_ether_aton(token);
+	if (tmp == NULL)
+		return -1;
+
+	memcpy(addr, tmp, sizeof(struct ether_addr));
+	return 0;
+}
+
+int
+parse_pipeline_core(uint32_t *socket,
+	uint32_t *core,
+	uint32_t *ht,
+	const char *entry)
+{
+	size_t num_len;
+	char num[8];
+
+	uint32_t s = 0, c = 0, h = 0, val;
+	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+	const char *next = skip_white_spaces(entry);
+	char type;
+
+	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+	while (*next != '\0') {
+		/* If everything parsed nothing should left */
+		if (s_parsed && c_parsed && h_parsed)
+			return -EINVAL;
+
+		type = *next;
+		switch (type) {
+		case 's':
+		case 'S':
+			if (s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+			s_parsed = 1;
+			next++;
+			break;
+		case 'c':
+		case 'C':
+			if (c_parsed || h_parsed)
+				return -EINVAL;
+			c_parsed = 1;
+			next++;
+			break;
+		case 'h':
+		case 'H':
+			if (h_parsed)
+				return -EINVAL;
+			h_parsed = 1;
+			next++;
+			break;
+		default:
+			/* If it start from digit it must be only core id. */
+			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+
+			type = 'C';
+		}
+
+		for (num_len = 0; *next != '\0'; next++, num_len++) {
+			if (num_len == RTE_DIM(num))
+				return -EINVAL;
+
+			if (!isdigit(*next))
+				break;
+
+			num[num_len] = *next;
+		}
+
+		if (num_len == 0 && type != 'h' && type != 'H')
+			return -EINVAL;
+
+		if (num_len != 0 && (type == 'h' || type == 'H'))
+			return -EINVAL;
+
+		num[num_len] = '\0';
+		val = strtol(num, NULL, 10);
+
+		h = 0;
+		switch (type) {
+		case 's':
+		case 'S':
+			s = val;
+			break;
+		case 'c':
+		case 'C':
+			c = val;
+			break;
+		case 'h':
+		case 'H':
+			h = 1;
+			break;
+		}
+	}
+
+	*socket = s;
+	*core = c;
+	*ht = h;
+	return 0;
+}
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 58b59da..4b33573 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,9 @@
 #ifndef __INCLUDE_PARSER_H__
 #define __INCLUDE_PARSER_H__
 
+#include <rte_ip.h>
+#include <rte_ether.h>
+
 int
 parser_read_arg_bool(const char *p);
 
@@ -44,7 +47,28 @@ int
 parser_read_uint32(uint32_t *value, const char *p);
 
 int
+parser_read_uint16(uint16_t *value, const char *p);
+
+int
+parser_read_uint8(uint8_t *value, const char *p);
+
+int
+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
+
+int
 parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
 
+int
+parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
+
+int
+parse_ipv4_addr(const char *token, struct in_addr *ipv4);
+
+int
+parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
+
+int
+parse_mac_addr(const char *token, struct ether_addr *addr);
+
 #endif
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 2/6] examples/ip_pipeline: modifies common pipeline CLI
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 1/6] examples/ip_pipeline: add helper functions for parsing string Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 3/6] examples/ip_pipeline: modifies routing commands Michal Jastrzebski
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Tomasz Kulasek

All commands are merged into one command:
cmd_link_parsed.

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 309 ++++++++-------------
 1 file changed, 111 insertions(+), 198 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index a691d42..3be48a1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 #include <cmdline.h>
 
 #include "pipeline_common_fe.h"
+#include "parser.h"
 
 int
 app_pipeline_ping(struct app_params *app,
@@ -963,219 +964,136 @@ print_link_info(struct app_link_params *p)
 	printf("\n");
 }
 
-struct cmd_link_config_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t config_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-};
-
-static void
-cmd_link_config_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_config_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	uint32_t link_id = params->link_id;
-	uint32_t ip  = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	uint32_t depth = params->depth;
-
-	status = app_link_config(app, link_id, ip, depth);
-	if (status)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
-
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
-	}
-}
-
-cmdline_parse_token_string_t cmd_link_config_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, link_string,
-		"link");
-
-cmdline_parse_token_num_t cmd_link_config_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, link_id, UINT32);
-
-cmdline_parse_token_string_t cmd_link_config_config_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, config_string,
-		"config");
-
-cmdline_parse_token_ipaddr_t cmd_link_config_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_link_config_result, ip);
-
-cmdline_parse_token_num_t cmd_link_config_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, depth, UINT32);
-
-cmdline_parse_inst_t cmd_link_config = {
-	.f = cmd_link_config_parsed,
-	.data = NULL,
-	.help_str = "Link configuration",
-	.tokens = {
-		(void *)&cmd_link_config_link_string,
-		(void *)&cmd_link_config_link_id,
-		(void *)&cmd_link_config_config_string,
-		(void *)&cmd_link_config_ip,
-		(void *)&cmd_link_config_depth,
-		NULL,
-	},
-};
-
-/*
- * link up
- */
-
-struct cmd_link_up_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t up_string;
-};
-
-static void
-cmd_link_up_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_link_up_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_link_up(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
-
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
-	}
-}
-
-cmdline_parse_token_string_t cmd_link_up_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, link_string,
-		"link");
-
-cmdline_parse_token_num_t cmd_link_up_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_up_result, link_id, UINT32);
-
-cmdline_parse_token_string_t cmd_link_up_up_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, up_string, "up");
-
-cmdline_parse_inst_t cmd_link_up = {
-	.f = cmd_link_up_parsed,
-	.data = NULL,
-	.help_str = "Link UP",
-	.tokens = {
-		(void *)&cmd_link_up_link_string,
-		(void *)&cmd_link_up_link_id,
-		(void *)&cmd_link_up_up_string,
-		NULL,
-	},
-};
-
-/*
- * link down
- */
-
-struct cmd_link_down_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t down_string;
-};
-
-static void
-cmd_link_down_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_link_down_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_link_down(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
-
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
-	}
-}
-
-cmdline_parse_token_string_t cmd_link_down_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, link_string,
-		"link");
-
-cmdline_parse_token_num_t cmd_link_down_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_down_result, link_id, UINT32);
-
-cmdline_parse_token_string_t cmd_link_down_down_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, down_string,
-		"down");
-
-cmdline_parse_inst_t cmd_link_down = {
-	.f = cmd_link_down_parsed,
-	.data = NULL,
-	.help_str = "Link DOWN",
-	.tokens = {
-		(void *) &cmd_link_down_link_string,
-		(void *) &cmd_link_down_link_id,
-		(void *) &cmd_link_down_down_string,
-		NULL,
-	},
-};
-
 /*
- * link ls
+ * link command
  */
 
-struct cmd_link_ls_result {
+struct cmd_link_parsed_result {
 	cmdline_fixed_string_t link_string;
-	cmdline_fixed_string_t ls_string;
+	cmdline_fixed_string_t command_string;
 };
 
 static void
-cmd_link_ls_parsed(
+cmd_link_parsed(
 	__attribute__((unused)) void *parsed_result,
 	__attribute__((unused)) struct cmdline *cl,
 	 void *data)
 {
-	struct app_params *app = data;
+	int status;
+	uint32_t n_tokens;
+	char *tokens[256];
 	uint32_t link_id;
+	uint32_t depth;
 
-	for (link_id = 0; link_id < app->n_links; link_id++) {
-		struct app_link_params *p;
+	struct in_addr ipaddr_ipv4;
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
+	struct app_params *app = data;
+	struct cmd_link_parsed_result *results =
+			(struct cmd_link_parsed_result *)parsed_result;
+
+	n_tokens = RTE_DIM(tokens);
+	status = parse_tokenize_string(results->command_string, tokens, &n_tokens);
+
+	if (status == -E2BIG)
+		printf("Number of parameters exceeds tokenizer limit\n");
+	else
+		printf("Command tokenizer error\n");
+
+	if (n_tokens < 1) {
+		printf("Not enough arguments for link command\n");
+		return;
 	}
+
+	/* handle link id, if provided */
+	if (parser_read_uint32(&link_id, tokens[0]) == 0) {
+		/* link <link ID> config <ipaddr> <depth>
+		 * link <link ID> up
+		 * link <link ID> down
+		 */
+
+		if (n_tokens < 2) {
+			printf("Not enough arguments for \"link <id> [config|up|down] ...\" command\n");
+			return;
+		}
+
+		if (strcmp(tokens[1], "config") == 0) {
+			/* link config */
+
+			if (n_tokens < 4) {
+				printf("Not enough arguments for \"link config ...\" command\n");
+				return;
+			}
+
+			if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4) != 0) {
+				printf("Incorrect format of IPv4 source address\n");
+				return;
+			}
+
+			if (parser_read_uint32(&depth, tokens[3]) != 0) {
+				printf("Incorrect format for depth\n");
+				return;
+			}
+
+			status = app_link_config(app, link_id,
+					rte_bswap32((uint32_t) ipaddr_ipv4.s_addr), depth);
+		}
+		else if (strcmp(tokens[1], "up") == 0)
+			/* link up */
+			status = app_link_up(app, link_id);
+		else if (strcmp(tokens[1], "down") == 0)
+			/* link down */
+			status = app_link_down(app, link_id);
+		else {
+			printf("Incorrect link command: acceptable is link <id> [config|up|down]\n");
+			return;
+		}
+
+		if (status != 0)
+			printf("Command failed\n");
+		else {
+			struct app_link_params *p;
+
+			APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+			print_link_info(p);
+		}
+		return;
+
+	} else if (strcmp(tokens[0], "ls") == 0) {
+		/* link ls */
+
+		if (n_tokens > 1) {
+			printf("Too many arguments for \"link ls\"\n");
+			return;
+		}
+
+		for (link_id = 0; link_id < app->n_links; link_id++) {
+			struct app_link_params *p;
+
+			APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+			print_link_info(p);
+		}
+		return;
+
+	}
+
+	printf("Incorrect link command: should be \"link ls\" or \"link <id> [config|up|down] ...\"\n");
 }
 
-cmdline_parse_token_string_t cmd_link_ls_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, link_string,
+cmdline_parse_token_string_t cmd_link_parsed_link_string =
+		TOKEN_STRING_INITIALIZER(struct cmd_link_parsed_result, link_string,
 		"link");
 
-cmdline_parse_token_string_t cmd_link_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, ls_string, "ls");
+cmdline_parse_token_string_t cmd_link_parsed_command_string =
+		TOKEN_STRING_INITIALIZER(struct cmd_link_parsed_result, command_string,
+		TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_link_ls = {
-	.f = cmd_link_ls_parsed,
+cmdline_parse_inst_t cmd_link_parsed_all = {
+	.f = cmd_link_parsed,
 	.data = NULL,
-	.help_str = "Link list",
+	.help_str = "Link",
 	.tokens = {
-		(void *)&cmd_link_ls_link_string,
-		(void *)&cmd_link_ls_ls_string,
+		(void *)&cmd_link_parsed_link_string,
+		(void *)&cmd_link_parsed_command_string,
 		NULL,
 	},
 };
@@ -1270,12 +1188,7 @@ cmdline_parse_inst_t cmd_run = {
 static cmdline_parse_ctx_t pipeline_common_cmds[] = {
 	(cmdline_parse_inst_t *) &cmd_quit,
 	(cmdline_parse_inst_t *) &cmd_run,
-
-	(cmdline_parse_inst_t *) &cmd_link_config,
-	(cmdline_parse_inst_t *) &cmd_link_up,
-	(cmdline_parse_inst_t *) &cmd_link_down,
-	(cmdline_parse_inst_t *) &cmd_link_ls,
-
+	(cmdline_parse_inst_t *) &cmd_link_parsed_all,
 	(cmdline_parse_inst_t *) &cmd_ping,
 	(cmdline_parse_inst_t *) &cmd_stats_port_in,
 	(cmdline_parse_inst_t *) &cmd_stats_port_out,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 3/6] examples/ip_pipeline: modifies routing commands
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 1/6] examples/ip_pipeline: add helper functions for parsing string Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 2/6] examples/ip_pipeline: modifies common pipeline CLI Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 4/6] examples/ip_pipeline: modifies firewall pipeline CLI Michal Jastrzebski
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

several routing commands are merged into two commands:
route and arp - these two commands are handled by cli library.
Rest of the commands are handled internaly by the pipeline code.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
---
 examples/ip_pipeline/pipeline/pipeline_routing.c | 1774 ++++++----------------
 1 file changed, 493 insertions(+), 1281 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index eab89f2..5726e02 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_routing.h"
+#include "parser.h"
 
 struct app_pipeline_routing_route {
 	struct pipeline_routing_route_key key;
@@ -853,1376 +854,587 @@ app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
 	return 0;
 }
 
-static int
-parse_labels(char *string, uint32_t *labels, uint32_t *n_labels)
-{
-	uint32_t n_max_labels = *n_labels, count = 0;
-
-	/* Check for void list of labels */
-	if (strcmp(string, "<void>") == 0) {
-		*n_labels = 0;
-		return 0;
-	}
-
-	/* At least one label should be present */
-	for ( ; (*string != '\0'); ) {
-		char *next;
-		int value;
-
-		if (count >= n_max_labels)
-			return -1;
-
-		if (count > 0) {
-			if (string[0] != ':')
-				return -1;
-
-			string++;
-		}
-
-		value = strtol(string, &next, 10);
-		if (next == string)
-			return -1;
-		string = next;
-
-		labels[count++] = (uint32_t) value;
-	}
-
-	*n_labels = count;
-	return 0;
-}
-
-/*
- * route add (mpls = no, qinq = no, arp = no)
- */
-
-struct cmd_route_add1_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-};
-
-static void
-cmd_route_add1_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add1_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = 0;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add1_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add1_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add1_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add1_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add1_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add1_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add1_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add1_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add1_result, macaddr);
-
-static cmdline_parse_inst_t cmd_route_add1 = {
-	.f = cmd_route_add1_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add1_p_string,
-		(void *)&cmd_route_add1_p,
-		(void *)&cmd_route_add1_route_string,
-		(void *)&cmd_route_add1_add_string,
-		(void *)&cmd_route_add1_ip,
-		(void *)&cmd_route_add1_depth,
-		(void *)&cmd_route_add1_port_string,
-		(void *)&cmd_route_add1_port,
-		(void *)&cmd_route_add1_ether_string,
-		(void *)&cmd_route_add1_macaddr,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = no, arp = yes)
- */
-
-struct cmd_route_add2_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-};
-
-static void
-cmd_route_add2_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add2_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add2_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add2_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add2_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add2_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add2_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, nh_ip);
-
-static cmdline_parse_inst_t cmd_route_add2 = {
-	.f = cmd_route_add2_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add2_p_string,
-		(void *)&cmd_route_add2_p,
-		(void *)&cmd_route_add2_route_string,
-		(void *)&cmd_route_add2_add_string,
-		(void *)&cmd_route_add2_ip,
-		(void *)&cmd_route_add2_depth,
-		(void *)&cmd_route_add2_port_string,
-		(void *)&cmd_route_add2_port,
-		(void *)&cmd_route_add2_ether_string,
-		(void *)&cmd_route_add2_nh_ip,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = no)
- */
-
-struct cmd_route_add3_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add3_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add3_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add3_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add3_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add3_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add3_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add3_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add3_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add3_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add3_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add3_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add3_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, qinq_string,
-	"qinq");
-
-static cmdline_parse_token_num_t cmd_route_add3_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, svlan, UINT32);
-
-static cmdline_parse_token_num_t cmd_route_add3_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, cvlan, UINT32);
-
-static cmdline_parse_inst_t cmd_route_add3 = {
-	.f = cmd_route_add3_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add3_p_string,
-		(void *)&cmd_route_add3_p,
-		(void *)&cmd_route_add3_route_string,
-		(void *)&cmd_route_add3_add_string,
-		(void *)&cmd_route_add3_ip,
-		(void *)&cmd_route_add3_depth,
-		(void *)&cmd_route_add3_port_string,
-		(void *)&cmd_route_add3_port,
-		(void *)&cmd_route_add3_ether_string,
-		(void *)&cmd_route_add3_macaddr,
-		(void *)&cmd_route_add3_qinq_string,
-		(void *)&cmd_route_add3_svlan,
-		(void *)&cmd_route_add3_cvlan,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = yes)
- */
-
-struct cmd_route_add4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add4_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add4_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add4_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add4_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add4_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add4_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add4_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add4_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add4_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, nh_ip);
-
-static cmdline_parse_token_string_t cmd_route_add4_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, qinq_string,
-	"qinq");
-
-static cmdline_parse_token_num_t cmd_route_add4_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, svlan, UINT32);
-
-static cmdline_parse_token_num_t cmd_route_add4_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, cvlan, UINT32);
-
-static cmdline_parse_inst_t cmd_route_add4 = {
-	.f = cmd_route_add4_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add4_p_string,
-		(void *)&cmd_route_add4_p,
-		(void *)&cmd_route_add4_route_string,
-		(void *)&cmd_route_add4_add_string,
-		(void *)&cmd_route_add4_ip,
-		(void *)&cmd_route_add4_depth,
-		(void *)&cmd_route_add4_port_string,
-		(void *)&cmd_route_add4_port,
-		(void *)&cmd_route_add4_ether_string,
-		(void *)&cmd_route_add4_nh_ip,
-		(void *)&cmd_route_add4_qinq_string,
-		(void *)&cmd_route_add4_svlan,
-		(void *)&cmd_route_add4_cvlan,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = yes, qinq = no, arp = no)
- */
-
-struct cmd_route_add5_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
-
-static void
-cmd_route_add5_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add5_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
-
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add5_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add5_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add5_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add5_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add5_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add5_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add5_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add5_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add5_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add5 = {
-	.f = cmd_route_add5_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add5_p_string,
-		(void *)&cmd_route_add5_p,
-		(void *)&cmd_route_add5_route_string,
-		(void *)&cmd_route_add5_add_string,
-		(void *)&cmd_route_add5_ip,
-		(void *)&cmd_route_add5_depth,
-		(void *)&cmd_route_add5_port_string,
-		(void *)&cmd_route_add5_port,
-		(void *)&cmd_route_add5_ether_string,
-		(void *)&cmd_route_add5_macaddr,
-		(void *)&cmd_route_add5_mpls_string,
-		(void *)&cmd_route_add5_mpls_labels,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = yes, qinq = no, arp = yes)
- */
-
-struct cmd_route_add6_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
-
-static void
-cmd_route_add6_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add6_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
-
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add6_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add6_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add6_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add6_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add6_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add6_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add6_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, nh_ip);
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add6 = {
-	.f = cmd_route_add6_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add6_p_string,
-		(void *)&cmd_route_add6_p,
-		(void *)&cmd_route_add6_route_string,
-		(void *)&cmd_route_add6_add_string,
-		(void *)&cmd_route_add6_ip,
-		(void *)&cmd_route_add6_depth,
-		(void *)&cmd_route_add6_port_string,
-		(void *)&cmd_route_add6_port,
-		(void *)&cmd_route_add6_ether_string,
-		(void *)&cmd_route_add6_nh_ip,
-		(void *)&cmd_route_add6_mpls_string,
-		(void *)&cmd_route_add6_mpls_labels,
-		NULL,
-	},
-};
-
 /*
- * route del
+ * route cmd
  */
 
-struct cmd_route_del_result {
+struct cmd_route_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_route_del_parsed(
+cmd_route_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_route_del_result *params = parsed_result;
+	struct cmd_route_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
 
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	status = app_pipeline_routing_delete_route(app, params->p, &key);
+	struct in_addr ipv4;
+	struct in_addr nh_ipv4;
+	struct ether_addr mac_addr;
+	uint32_t depth;
+	uint32_t port_id;
+	uint32_t svlan;
+	uint32_t cvlan;
+	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
+	uint32_t n_labels = RTE_DIM(mpls_labels);
 
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf("Command \"route\": Too many parameters.\n");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,
-	"del");
-
-static cmdline_parse_token_ipaddr_t cmd_route_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_del_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_del_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT32);
-
-static cmdline_parse_inst_t cmd_route_del = {
-	.f = cmd_route_del_parsed,
-	.data = NULL,
-	.help_str = "Route delete",
-	.tokens = {
-		(void *)&cmd_route_del_p_string,
-		(void *)&cmd_route_del_p,
-		(void *)&cmd_route_del_route_string,
-		(void *)&cmd_route_del_del_string,
-		(void *)&cmd_route_del_ip,
-		(void *)&cmd_route_del_depth,
-		NULL,
-	},
-};
-
-/*
- * route add default
- */
-
-struct cmd_route_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_route_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
 
-	status = app_pipeline_routing_add_default_route(app, params->p,
-			params->port);
+	/* "route add" or "route add default" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "add"))) {
+		if (n_tokens < 3) {
+			printf("Not enough parameters for \"route add\" or"
+					"\"route add default\".\n");
+			return;
+		}
 
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
+		/* route add */
+		if (0 == parse_ipv4_addr(tokens[1], &ipv4)) {
+			struct pipeline_routing_route_key key;
+			struct pipeline_routing_route_data route_data;
+
+			if (n_tokens < 7) {
+				printf("Not enough parameters for \"route add\".\n");
+				return;
+			}
+			if (parser_read_uint32(&depth, tokens[2])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is depth.\n",
+					tokens[2]);
+				return;
+			}
+			if (strcmp(tokens[3], "port")) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is word \"port\".\n",
+					tokens[3]);
+				return;
+			}
+			if (parser_read_uint32(&port_id, tokens[4])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is port id.\n",
+					tokens[4]);
+				return;
+			}
+			if (strcmp(tokens[5], "ether")) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is word \"ether\".\n",
+					tokens[5]);
+				return;
+			}
+
+			if (0 == parse_mac_addr(tokens[6], &mac_addr)) {
+				route_data.flags = 0;
+			}
+			else if (0 == parse_ipv4_addr(tokens[6], &nh_ipv4)) {
+				route_data.flags = PIPELINE_ROUTING_ROUTE_ARP;
+			}
+			else {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is MAC address or next hop IPv4"
+					" address.\n",
+					tokens[6]);
+				return;
+			}
+
+			if (n_tokens > 7) {
+				if (0 == strcmp(tokens[7], "mpls")) {
+					if (n_tokens != 9) {
+						printf(
+						"Incorrect number of parameters for route add mpls.\n");
+						return;
+					}
+					if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
+						printf("Incorrect parameter: \"%s\"."
+							" Expected parameter is mpls labels.\n",
+							tokens[8]);
+						return;
+					}
+					route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
+				}
+				else if (0 == strcmp(tokens[7], "qinq")) {
+					if (n_tokens != 10) {
+						printf(
+						"Incorrect number of parameters for route add qinq.\n");
+						return;
+					}
+					if (parser_read_uint32(&svlan, tokens[8])) {
+						printf("Incorrect parameter: \"%s\"."
+							" Expected parameter is svlan.\n",
+							tokens[8]);
+						return;
+					}
+					if (parser_read_uint32(&cvlan, tokens[9])) {
+						printf("Incorrect parameter: \"%s\"."
+							" Expected parameter is cvlan.\n",
+							tokens[9]);
+						return;
+					}
+					route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
+				}
+				else {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is word \"mpls\" or \"qinq\".\n",
+						tokens[7]);
+					return;
+				}
+			}
+
+			switch (route_data.flags) {
+			case 0:
+				/* route add (mpls = no, qinq = no, arp = no) */
+				/* route add <ipaddr> <depth> port <port ID> ether <macaddr> */
+				route_data.port_id = port_id;
+				route_data.ethernet.macaddr = mac_addr;
+				break;
+			case PIPELINE_ROUTING_ROUTE_ARP:
+				/* route add (mpls = no, qinq = no, arp = yes) */
+				/* route add <ipaddr> <depth> port <port ID> ether <ipaddr> */
+				route_data.port_id = port_id;
+				route_data.ethernet.ip = rte_bswap32((uint32_t) nh_ipv4.s_addr);
+				break;
+			case PIPELINE_ROUTING_ROUTE_MPLS:
+				/* route add (mpls = yes, qinq = no, arp = no) */
+				/* route add <ipaddr> <depth> port <port ID> ether <macaddr>
+				 * mpls <mpls labels> */
+			{
+				uint32_t i;
+
+				route_data.port_id = port_id;
+				route_data.ethernet.macaddr = mac_addr;
+				for (i = 0; i < n_labels; i++)
+					route_data.l2.mpls.labels[i] = mpls_labels[i];
+				route_data.l2.mpls.n_labels = n_labels;
+			}
+				break;
+			case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
+				/* route add (mpls = yes, qinq = no, arp = yes) */
+				/* route add <ipaddr> <depth> port <port ID> ether <ipaddr>
+				 * mpls <mpls labels> */
+			{
+				uint32_t i;
+
+				route_data.port_id = port_id;
+				route_data.ethernet.ip = rte_bswap32((uint32_t) nh_ipv4.s_addr);
+				for (i = 0; i < n_labels; i++)
+					route_data.l2.mpls.labels[i] = mpls_labels[i];
+				route_data.l2.mpls.n_labels = n_labels;
+			}
+				break;
+			case PIPELINE_ROUTING_ROUTE_QINQ:
+				/* route add (mpls = no, qinq = yes, arp = no) */
+				/* route add <ipaddr> <depth> port <port ID> ether <macaddr>
+				 * qinq <svlan> <cvlan> */
+				route_data.port_id = port_id;
+				route_data.ethernet.macaddr = mac_addr;
+				route_data.l2.qinq.svlan = svlan;
+				route_data.l2.qinq.cvlan = cvlan;
+				break;
+			case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
+				/* route add (mpls = no, qinq = yes, arp = yes) */
+				/* route add <ipaddr> <depth> port <port ID> ether <ipaddr>
+				 * qinq <svlan> <cvlan> */
+				route_data.port_id = port_id;
+				route_data.ethernet.ip = rte_bswap32((uint32_t) nh_ipv4.s_addr);
+				route_data.l2.qinq.svlan = svlan;
+				route_data.l2.qinq.cvlan = cvlan;
+				break;
+			default:
+				break;
+			}
+
+			key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+			key.key.ipv4.ip = rte_bswap32((uint32_t) ipv4.s_addr);
+			key.key.ipv4.depth = depth;
+
+			status = app_pipeline_routing_add_route(app,
+				params->p,
+				&key,
+				&route_data);
+			if (status != 0)
+				printf("Command \"route add\" failed.\n");
+
+			return;
+		}
+		/* route add default */
+		else if (0 == strcmp(tokens[1], "default")) {
+			if (n_tokens != 3) {
+				printf(
+				"Incorrect number of parameters for route add default.\n");
+				return;
+			}
+			if (parser_read_uint32(&port_id, tokens[2])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is port id.\n",
+					tokens[2]);
+				return;
+			}
+
+			status = app_pipeline_routing_add_default_route(app,
+				params->p,
+				port_id);
+			if (status != 0)
+				printf("Command \"route add default\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is IPv4 address or word \"default\".\n",
+				tokens[1]);
+			return;
+		}
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, p, UINT32);
-
-cmdline_parse_token_string_t cmd_route_add_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		route_string, "route");
-
-cmdline_parse_token_string_t cmd_route_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_route_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-	default_string, "default");
-
-cmdline_parse_token_num_t cmd_route_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result,
-		port, UINT32);
-
-cmdline_parse_inst_t cmd_route_add_default = {
-	.f = cmd_route_add_default_parsed,
-	.data = NULL,
-	.help_str = "Route default set",
-	.tokens = {
-		(void *)&cmd_route_add_default_p_string,
-		(void *)&cmd_route_add_default_p,
-		(void *)&cmd_route_add_default_route_string,
-		(void *)&cmd_route_add_default_add_string,
-		(void *)&cmd_route_add_default_default_string,
-		(void *)&cmd_route_add_default_port,
-		NULL,
-	},
-};
 
-/*
- * route del default
- */
-
-struct cmd_route_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_route_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_route_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_routing_delete_default_route(app, params->p);
+	/* "route del" or "route del default" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "del"))) {
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"route del\" or"
+					"\"route del default\".\n");
+			return;
+		}
 
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
+		/* route del <ipaddr> <depth> */
+		if (0 == parse_ipv4_addr(tokens[1], &ipv4)) {
+			struct pipeline_routing_route_key key;
+
+			if (n_tokens != 3) {
+				printf(
+				"Incorrect number of parameters for route del.\n");
+				return;
+			}
+			if (parser_read_uint32(&depth, tokens[2])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is depth.\n",
+					tokens[2]);
+				return;
+			}
+
+			key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+			key.key.ipv4.ip = rte_bswap32((uint32_t) ipv4.s_addr);
+			key.key.ipv4.depth = depth;
+
+			status = app_pipeline_routing_delete_route(app, params->p, &key);
+			if (status != 0)
+				printf("Command \"route del\" failed.\n");
+
+			return;
+		}
+		/* route del default */
+		else if (0 == strcmp(tokens[1], "default")) {
+			if (n_tokens != 2) {
+				printf(
+				"Incorrect number of parameters for route del default.\n");
+				return;
+			}
+
+			status = app_pipeline_routing_delete_default_route(app, params->p);
+			if (status != 0)
+				printf("Command \"route del default\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is IPv4 or word \"default\".\n",
+				tokens[1]);
+			return;
+		}
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		del_string, "del");
-
-static cmdline_parse_token_string_t cmd_route_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-	default_string, "default");
-
-
-static cmdline_parse_inst_t cmd_route_del_default = {
-	.f = cmd_route_del_default_parsed,
-	.data = NULL,
-	.help_str = "Route default clear",
-	.tokens = {
-		(void *)&cmd_route_del_default_p_string,
-		(void *)&cmd_route_del_default_p,
-		(void *)&cmd_route_del_default_route_string,
-		(void *)&cmd_route_del_default_del_string,
-		(void *)&cmd_route_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * route ls
- */
-
-struct cmd_route_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t ls_string;
-};
 
-static void
-cmd_route_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	/* route ls */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "ls"))) {
+		if (n_tokens > 1) {
+			printf("Incorrect number of parameters for route ls.\n");
+			return;
+		}
 
-	status = app_pipeline_routing_route_ls(app, params->p);
+		status = app_pipeline_routing_route_ls(app, params->p);
+		if (status != 0)
+			printf("Command \"route ls\" failed.\n");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_route_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_ls_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_ls_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result,
-	route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, ls_string,
-	"ls");
-
-static cmdline_parse_inst_t cmd_route_ls = {
-	.f = cmd_route_ls_parsed,
-	.data = NULL,
-	.help_str = "Route list",
-	.tokens = {
-		(void *)&cmd_route_ls_p_string,
-		(void *)&cmd_route_ls_p,
-		(void *)&cmd_route_ls_route_string,
-		(void *)&cmd_route_ls_ls_string,
-		NULL,
-	},
-};
-
-/*
- * arp add
- */
-
-struct cmd_arp_add_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
-	struct ether_addr macaddr;
-
-};
-
-static void
-cmd_arp_add_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_add_result *params = parsed_result;
-	struct app_params *app = data;
-
-	struct pipeline_routing_arp_key key;
-	int status;
-
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.port_id = params->port_id;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
 
-	status = app_pipeline_routing_add_arp_entry(app,
-		params->p,
-		&key,
-		&params->macaddr);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
+	printf("Command \"route\" failed."
+		" Expected parameter is \"add\" or \"del\" or \"ls\".\n");
+	return;
 }
 
-static cmdline_parse_token_string_t cmd_arp_add_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_add_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, "arp");
+static cmdline_parse_token_string_t cmd_route_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
 
-static cmdline_parse_token_string_t cmd_arp_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, "add");
+static cmdline_parse_token_num_t cmd_route_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
 
-static cmdline_parse_token_num_t cmd_arp_add_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, port_id, UINT32);
+static cmdline_parse_token_string_t cmd_route_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
 
-static cmdline_parse_token_ipaddr_t cmd_arp_add_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_add_result, ip);
+static cmdline_parse_token_string_t cmd_route_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_token_etheraddr_t cmd_arp_add_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, macaddr);
-
-static cmdline_parse_inst_t cmd_arp_add = {
-	.f = cmd_arp_add_parsed,
+static cmdline_parse_inst_t cmd_route = {
+	.f = cmd_route_parsed,
 	.data = NULL,
-	.help_str = "ARP add",
+	.help_str =
+		"\n add <ipaddr> <depth> port <port ID> ether <macaddr> : Route add"
+		" (mpls = no, qinq = no, arp = no)"
+		"\n add <ipaddr> <depth> port <port ID> ether <ipaddr> : Route add"
+		" (mpls = no, qinq = no, arp = yes)"
+		"\n add <ipaddr> <depth> port <port ID> ether <macaddr> qinq <svlan>"
+		" <cvlan> : Route add (qinq = yes, arp = no)"
+		"\n add <ipaddr> <depth> port <port ID> ether <ipaddr> qinq <svlan>"
+		" <cvlan> : Route add (qinq = yes, arp = yes)"
+		"\n add <ipaddr> <depth> port <port ID> ether <macaddr> mpls"
+		" <mpls labels> : Route add (mpls = yes, arp = no)"
+		"\n add <ipaddr> <depth> port <port ID> ether <ipaddr> mpls"
+		" <mpls labels> : Route add (mpls = yes, arp = yes)"
+		"\n add default <port ID> : Route default set"
+		"\n del <ipaddr> <depth> : Route delete"
+		"\n del default : Route default clear"
+		"\n ls : Route list",
 	.tokens = {
-		(void *)&cmd_arp_add_p_string,
-		(void *)&cmd_arp_add_p,
-		(void *)&cmd_arp_add_arp_string,
-		(void *)&cmd_arp_add_add_string,
-		(void *)&cmd_arp_add_port_id,
-		(void *)&cmd_arp_add_ip,
-		(void *)&cmd_arp_add_macaddr,
+		(void *)&cmd_route_p_string,
+		(void *)&cmd_route_p,
+		(void *)&cmd_route_route_string,
+		(void *)&cmd_route_multi_string,
 		NULL,
 	},
 };
 
 /*
- * arp del
+ * arp cmd
  */
 
-struct cmd_arp_del_result {
+struct cmd_arp_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_arp_del_parsed(
+cmd_arp_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_arp_del_result *params = parsed_result;
+	struct cmd_arp_result *params = parsed_result;
 	struct app_params *app = data;
 
-	struct pipeline_routing_arp_key key;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.port_id = params->port_id;
-
-	status = app_pipeline_routing_delete_arp_entry(app, params->p, &key);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arp");
-
-static cmdline_parse_token_string_t cmd_arp_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, "del");
-
-static cmdline_parse_token_num_t cmd_arp_del_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, port_id, UINT32);
-
-static cmdline_parse_token_ipaddr_t cmd_arp_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_del_result, ip);
-
-static cmdline_parse_inst_t cmd_arp_del = {
-	.f = cmd_arp_del_parsed,
-	.data = NULL,
-	.help_str = "ARP delete",
-	.tokens = {
-		(void *)&cmd_arp_del_p_string,
-		(void *)&cmd_arp_del_p,
-		(void *)&cmd_arp_del_arp_string,
-		(void *)&cmd_arp_del_del_string,
-		(void *)&cmd_arp_del_port_id,
-		(void *)&cmd_arp_del_ip,
-		NULL,
-	},
-};
-
-/*
- * arp add default
- */
-
-struct cmd_arp_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
+	struct in_addr ipv4;
+	struct ether_addr mac_addr;
 	uint32_t port_id;
-};
-
-static void
-cmd_arp_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-
-	int status;
-
-	status = app_pipeline_routing_add_default_arp_entry(app,
-		params->p,
-		params->port_id);
 
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf("Command \"arp\": Too many parameters.\n");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, p_string,
-	"p");
 
-static cmdline_parse_token_num_t cmd_arp_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, arp_string,
-	"arp");
-
-static cmdline_parse_token_string_t cmd_arp_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, add_string,
-	"add");
-
-static cmdline_parse_token_string_t cmd_arp_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result,
-		default_string, "default");
-
-static cmdline_parse_token_num_t cmd_arp_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, port_id,
-	UINT32);
-
-static cmdline_parse_inst_t cmd_arp_add_default = {
-	.f = cmd_arp_add_default_parsed,
-	.data = NULL,
-	.help_str = "ARP add default",
-	.tokens = {
-		(void *)&cmd_arp_add_default_p_string,
-		(void *)&cmd_arp_add_default_p,
-		(void *)&cmd_arp_add_default_arp_string,
-		(void *)&cmd_arp_add_default_add_string,
-		(void *)&cmd_arp_add_default_default_string,
-		(void *)&cmd_arp_add_default_port_id,
-		NULL,
-	},
-};
-
-/*
- * arp del default
- */
-
-struct cmd_arp_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_arp_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-
-	int status;
-
-	status = app_pipeline_routing_delete_default_arp_entry(app, params->p);
+	/* "arp add" or "arp add default" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "add"))) {
+		if (n_tokens < 3) {
+			printf("Not enough parameters for \"arp add\" or"
+					"\"arp add default\".\n");
+			return;
+		}
 
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
+		/* arp add <port ID> <ipaddr> <macaddr> */
+		if (0 == parser_read_uint32(&port_id, tokens[1])) {
+			struct pipeline_routing_arp_key key;
+
+			if (n_tokens != 4) {
+				printf(
+				"Incorrect number of parameters for arp add.\n");
+				return;
+			}
+			if(parse_ipv4_addr(tokens[2], &ipv4)) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is IPv4.\n",
+					tokens[2]);
+				return;
+			}
+			if(parse_mac_addr(tokens[3], &mac_addr)) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is MAC address.\n",
+					tokens[3]);
+				return;
+			}
+
+			key.type = PIPELINE_ROUTING_ARP_IPV4;
+			key.key.ipv4.port_id = port_id;
+			key.key.ipv4.ip = rte_cpu_to_be_32(ipv4.s_addr);
+
+			status = app_pipeline_routing_add_arp_entry(app,
+				params->p,
+				&key,
+				&mac_addr);
+			if (status != 0)
+				printf("Command \"arp add\" failed.\n");
+
+			return;
+		}
+		/* arp add default <port ID> */
+		else if (0 == strcmp(tokens[1], "default")) {
+			if (n_tokens != 3) {
+				printf(
+				"Incorrect number of parameters for arp add default.\n");
+				return;
+			}
+			if (parser_read_uint32(&port_id, tokens[2])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is port id.\n",
+					tokens[2]);
+				return;
+			}
+
+			status = app_pipeline_routing_add_default_arp_entry(app,
+				params->p,
+				port_id);
+			if (status != 0)
+				printf("Command \"arp add default\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is port id or word \"default\".\n",
+				tokens[1]);
+			return;
+		}
 	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, arp_string,
-	"arp");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, del_string,
-	"del");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result,
-		default_string, "default");
 
-static cmdline_parse_inst_t cmd_arp_del_default = {
-	.f = cmd_arp_del_default_parsed,
-	.data = NULL,
-	.help_str = "ARP delete default",
-	.tokens = {
-		(void *)&cmd_arp_del_default_p_string,
-		(void *)&cmd_arp_del_default_p,
-		(void *)&cmd_arp_del_default_arp_string,
-		(void *)&cmd_arp_del_default_del_string,
-		(void *)&cmd_arp_del_default_default_string,
-		NULL,
-	},
-};
+	/* "arp del" or "arp del default" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "del"))) {
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"arp del\" or"
+					"\"arp del default\".\n");
+			return;
+		}
 
-/*
- * arp ls
- */
+		/* arp del <port ID> <ipaddr> */
+		if (0 == parser_read_uint32(&port_id, tokens[1])) {
+			struct pipeline_routing_arp_key key;
+
+			if (n_tokens != 3) {
+				printf(
+				"Incorrect number of parameters for \"arp del\".\n");
+				return;
+			}
+			if (parse_ipv4_addr(tokens[2], &ipv4)) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is IPv4.\n",
+					tokens[2]);
+				return;
+			}
+
+			key.type = PIPELINE_ROUTING_ARP_IPV4;
+			key.key.ipv4.ip = rte_cpu_to_be_32(ipv4.s_addr);
+			key.key.ipv4.port_id = port_id;
+
+			status = app_pipeline_routing_delete_arp_entry(app,
+				params->p,
+				&key);
+			if (status != 0)
+				printf("Command \"arp del\" failed.\n");
+
+			return;
+		}
+		/* arp del default */
+		else if (0 == strcmp(tokens[1], "default")) {
+			if (n_tokens != 2) {
+				printf(
+				"Incorrect number of parameters for \"arp del default\".\n");
+				return;
+			}
+
+			status = app_pipeline_routing_delete_default_arp_entry(app,
+				params->p);
+			if (status != 0)
+				printf("Command \"arp del default\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is port id or word \"default\".\n",
+				tokens[1]);
+			return;
+		}
+	}
 
-struct cmd_arp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t ls_string;
-};
+	/* arp ls */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "ls"))) {
+		if (n_tokens > 1) {
+			printf("Incorrect number of parameters for arp ls.\n");
+			return;
+		}
 
-static void
-cmd_arp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing *p;
+		status = app_pipeline_routing_arp_ls(app, params->p);
+		if (status != 0)
+			printf("Command \"arp ls\" failed.\n");
 
-	p = app_pipeline_data_fe(app, params->p, &pipeline_routing);
-	if (p == NULL)
 		return;
+	}
 
-	app_pipeline_routing_arp_ls(app, params->p);
+	printf("Command \"arp\" failed."
+		" Expected parameter is \"add\" or \"del\" or \"ls\".\n");
+	return;
 }
 
-static cmdline_parse_token_string_t cmd_arp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
-	"p");
+static cmdline_parse_token_string_t cmd_arp_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
 
-static cmdline_parse_token_num_t cmd_arp_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+static cmdline_parse_token_num_t cmd_arp_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
 
-static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
-	"arp");
+static cmdline_parse_token_string_t cmd_arp_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
 
-static cmdline_parse_token_string_t cmd_arp_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_arp_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_inst_t cmd_arp_ls = {
-	.f = cmd_arp_ls_parsed,
+static cmdline_parse_inst_t cmd_arp = {
+	.f = cmd_arp_parsed,
 	.data = NULL,
-	.help_str = "ARP list",
+	.help_str =
+		"\n add <port ID> <ipaddr> <macaddr> : ARP add"
+		"\n add default <port ID> : ARP add default"
+		"\n del <port ID> <ipaddr> : ARP delete"
+		"\n del default : ARP delete default"
+		"\n ls : ARP list",
 	.tokens = {
-		(void *)&cmd_arp_ls_p_string,
-		(void *)&cmd_arp_ls_p,
-		(void *)&cmd_arp_ls_arp_string,
-		(void *)&cmd_arp_ls_ls_string,
+		(void *)&cmd_arp_p_string,
+		(void *)&cmd_arp_p,
+		(void *)&cmd_arp_arp_string,
+		(void *)&cmd_arp_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route_add1,
-	(cmdline_parse_inst_t *)&cmd_route_add2,
-	(cmdline_parse_inst_t *)&cmd_route_add3,
-	(cmdline_parse_inst_t *)&cmd_route_add4,
-	(cmdline_parse_inst_t *)&cmd_route_add5,
-	(cmdline_parse_inst_t *)&cmd_route_add6,
-	(cmdline_parse_inst_t *)&cmd_route_del,
-	(cmdline_parse_inst_t *)&cmd_route_add_default,
-	(cmdline_parse_inst_t *)&cmd_route_del_default,
-	(cmdline_parse_inst_t *)&cmd_route_ls,
-	(cmdline_parse_inst_t *)&cmd_arp_add,
-	(cmdline_parse_inst_t *)&cmd_arp_del,
-	(cmdline_parse_inst_t *)&cmd_arp_add_default,
-	(cmdline_parse_inst_t *)&cmd_arp_del_default,
-	(cmdline_parse_inst_t *)&cmd_arp_ls,
+	(cmdline_parse_inst_t *)&cmd_route,
+	(cmdline_parse_inst_t *)&cmd_arp,
 	NULL,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 4/6] examples/ip_pipeline: modifies firewall pipeline CLI
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
                   ` (2 preceding siblings ...)
  2016-05-06 15:57 ` [PATCH 3/6] examples/ip_pipeline: modifies routing commands Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 5/6] examples/ip_pipeline: modifies flow classifications " Michal Jastrzebski
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Daniel Mrzyglod

Each command are merged into one: cmd_firewall_parsed.
ADD command format is changed:
p <pipeline ID> firewall add priority <priority> ipv4 <sipaddr>
<sipdepth> <dipaddr> <dipdepth> <sport0> <sport1> <dport0> <dport1>
<proto> <protomask> port <port ID>

and bulk command was modified:
1. firewall add bulk
File line format:
priority <priority> ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
<sport0> <sport1> <dport0> <dport1> <proto> <protomask> port <port ID>
(protomask is a hex value)
File line example:
priority 0 ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF port 3

2. firewall del bulk
File line format:
ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth> <sport0> <sport1>
<dport0> <dport1> <proto> <protomask>
File line example:
ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 examples/ip_pipeline/pipeline/pipeline_firewall.c | 1336 +++++++++------------
 1 file changed, 593 insertions(+), 743 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
index fd897d5..fb7a44a 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -30,9 +30,11 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
 
@@ -50,6 +52,8 @@
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_firewall.h"
+#include "parser.h"
+
 
 #define BUF_SIZE		1024
 
@@ -276,26 +280,32 @@ static int
 app_pipeline_add_bulk_parse_file(char *filename,
 		struct app_pipeline_add_bulk_params *params)
 {
-	FILE *f;
+	FILE *f = NULL;
 	char file_buf[BUF_SIZE];
-	uint32_t i;
+	uint32_t i, line = 0;
 	int status = 0;
 
 	f = fopen(filename, "r");
-	if (f == NULL)
+	if (f == NULL) {
+		if (getcwd(file_buf, sizeof(file_buf)) != NULL)
+			printf("not found file %s in the current working dir %s\n",
+					filename, file_buf);
 		return -1;
+	}
 
 	params->n_keys = 0;
 	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
+		if (file_buf[0] != '\0' && file_buf[0] != '\n' && file_buf[0] != '#')
+			params->n_keys++;
 	rewind(f);
 
 	if (params->n_keys == 0) {
+		printf("not found any keys in the file %s\n", filename);
 		status = -1;
 		goto end;
 	}
 
-	params->keys = rte_malloc(NULL,
+	params->keys = rte_zmalloc(NULL,
 			params->n_keys * sizeof(struct pipeline_firewall_key),
 			RTE_CACHE_LINE_SIZE);
 	if (params->keys == NULL) {
@@ -321,137 +331,152 @@ app_pipeline_add_bulk_parse_file(char *filename,
 
 	i = 0;
 	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
+		char *tokens[17];
+		uint32_t n_tokens = RTE_DIM(tokens);
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		uint32_t priority = 0;
+		struct in_addr sipaddr;
+		uint32_t sipdepth = 0;
+		struct in_addr dipaddr;
+		uint32_t dipdepth = 0;
+		uint16_t sport0 = 0;
+		uint16_t sport1 = 0;
+		uint16_t dport0 = 0;
+		uint16_t dport1 = 0;
+		uint8_t proto = 0;
+		uint8_t protomask = 0;
+		uint32_t port_id = 0;
 
-		str = strtok(file_buf, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
+		if (n_tokens == 0 || tokens[0][0] == '#') {
+			line++;
+			continue;
 		}
-		params->priorities[i] = atoi(str);
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (status != 0) {
+			printf("Too many tokens\n");
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (n_tokens != 15) {
+			printf("Bad number of tokens at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (strcmp(tokens[0], "priority") != 0) {
+			printf("Incorrect string for priority at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parser_read_uint32(&priority, tokens[1])) {
+			printf("Incorrect format for priority at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (strcmp(tokens[2], "ipv4")) {
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parse_ipv4_addr(tokens[3], &sipaddr)) {
+			printf("Incorrect format for sipaddr at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parser_read_uint32(&sipdepth, tokens[4])) {
+			printf("Incorrect format for sipdepth at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parse_ipv4_addr(tokens[5], &dipaddr)) {
+			printf("Incorrect format for dipaddr at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parser_read_uint32(&dipdepth, tokens[6])) {
+			printf("Incorrect format for dipdepth at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&sport0, tokens[7])) {
+			printf("Incorrect format for sport0 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&sport1, tokens[8])) {
+			printf("Incorrect format for sport1 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&dport0, tokens[9])) {
+			printf("Incorrect format for dport0 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&dport1, tokens[10])) {
+			printf("Incorrect format for dport1 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint8(&proto, tokens[11])) {
+			printf("Incorrect format for proto at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		char *e;
+		protomask = strtoul(tokens[12], &e, 16);
+		if (*e || errno == EINVAL || errno == ERANGE) {
+			printf("Incorrect format for protomask - should be in hex  at line"
+					" %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (strcmp(tokens[13], "port")) {
+			printf("string supported port at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint32(&port_id, tokens[14])) {
+			printf("Incorrect format for port ID at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->port_ids[i] = atoi(str);
+
 		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		params->keys[i].key.ipv4_5tuple.src_ip = rte_bswap32(
+			(uint32_t) sipaddr.s_addr);
+		params->keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
+		params->keys[i].key.ipv4_5tuple.dst_ip = rte_bswap32(
+			(uint32_t) dipaddr.s_addr);
+		params->keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		params->keys[i].key.ipv4_5tuple.src_port_from = sport0;
+		params->keys[i].key.ipv4_5tuple.src_port_to = sport1;
+		params->keys[i].key.ipv4_5tuple.dst_port_from = dport0;
+		params->keys[i].key.ipv4_5tuple.dst_port_to = dport1;
+		params->keys[i].key.ipv4_5tuple.proto = proto;
+		params->keys[i].key.ipv4_5tuple.proto_mask = protomask;
 
+		params->port_ids[i] = port_id;
+		params->priorities[i] = priority;
+
+		line++;
 		i++;
+
+
 	}
 
 end:
@@ -463,26 +488,32 @@ static int
 app_pipeline_del_bulk_parse_file(char *filename,
 		struct app_pipeline_del_bulk_params *params)
 {
-	FILE *f;
+	FILE *f = NULL;
 	char file_buf[BUF_SIZE];
-	uint32_t i;
+	uint32_t i, line = 0;
 	int status = 0;
 
 	f = fopen(filename, "r");
-	if (f == NULL)
+	if (f == NULL) {
+		if (getcwd(file_buf, sizeof(file_buf)) != NULL)
+			printf("not found file %s in the current working dir %s\n",
+					filename, file_buf);
 		return -1;
+	}
 
 	params->n_keys = 0;
 	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
+		if (file_buf[0] != '\0' && file_buf[0] != '\n' && file_buf[0] != '#')
+			params->n_keys++;
 	rewind(f);
 
 	if (params->n_keys == 0) {
+		printf("not found any keys in the file %s\n", filename);
 		status = -1;
 		goto end;
 	}
 
-	params->keys = rte_malloc(NULL,
+	params->keys = rte_zmalloc(NULL,
 			params->n_keys * sizeof(struct pipeline_firewall_key),
 			RTE_CACHE_LINE_SIZE);
 	if (params->keys == NULL) {
@@ -492,124 +523,123 @@ app_pipeline_del_bulk_parse_file(char *filename,
 
 	i = 0;
 	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
+		char *tokens[17];
+		uint32_t n_tokens = RTE_DIM(tokens);
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		struct in_addr sipaddr;
+		uint32_t sipdepth = 0;
+		struct in_addr dipaddr;
+		uint32_t dipdepth;
+		uint16_t sport0 = 0;
+		uint16_t sport1 = 0;
+		uint16_t dport0 = 0;
+		uint16_t dport1 = 0;
+		uint8_t proto = 0;
+		uint8_t protomask = 0;
 
-		str = strtok(file_buf, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
+		if (n_tokens == 0 || tokens[0][0] == '#') {
+					line++;
+					continue;
+				}
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (status != 0) {
+			printf("Too many tokens\n");
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (n_tokens != 11) {
 			status = -1;
+			printf("\nToo many tokens in bulk file at line %d\n", line + 1);
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (strcmp(tokens[0], "ipv4")) {
+			printf("\nThe line should begin with string 'ipv4' %d\n", line + 1);
 			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
+			goto end;		}
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parse_ipv4_addr(tokens[1], &sipaddr)) {
+			printf("\nIncorrect format for sipaddr at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parser_read_uint32(&sipdepth, tokens[2])) {
+			printf("\nIncorrect format for sipdepth at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parse_ipv4_addr(tokens[3], &dipaddr)) {
+			printf("\nIncorrect format for dipaddr at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
 
-		str = strtok(NULL, " .");
-		if (str == NULL) {
+		if (parser_read_uint32(&dipdepth, tokens[4])) {
+			printf("\nIncorrect format for dipdepth at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&sport0, tokens[5])) {
+			printf("\nIncorrect format for sport0 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&sport1, tokens[6])) {
+			printf("\nIncorrect format for sport1 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&dport0, tokens[7])) {
+			printf("\nIncorrect format for dport0 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint16(&dport1, tokens[8])) {
+			printf("\nIncorrect format for dport1 at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		if (parser_read_uint8(&proto, tokens[9])) {
+			printf("\nIncorrect format for proto at line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
+		char *e;
+		protomask = strtoul(tokens[10], &e, 16);
+		if (*e || errno == EINVAL || errno == ERANGE) {
+			printf("\nIncorrect format for protomask - should be in hex  at "
+					"line %d\n", line + 1);
 			status = -1;
 			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
 
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
 
 		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		params->keys[i].key.ipv4_5tuple.src_ip = rte_bswap32(
+			(uint32_t) sipaddr.s_addr);
+		params->keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
+		params->keys[i].key.ipv4_5tuple.dst_ip = rte_bswap32(
+			(uint32_t) dipaddr.s_addr);
+		params->keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		params->keys[i].key.ipv4_5tuple.src_port_from = sport0;
+		params->keys[i].key.ipv4_5tuple.src_port_to = sport1;
+		params->keys[i].key.ipv4_5tuple.dst_port_from = dport0;
+		params->keys[i].key.ipv4_5tuple.dst_port_to = dport1;
+		params->keys[i].key.ipv4_5tuple.proto = proto;
+		params->keys[i].key.ipv4_5tuple.proto_mask = protomask;
 
+		line++;
 		i++;
+
 	}
 
 	for (i = 0; i < params->n_keys; i++) {
@@ -1196,663 +1226,483 @@ app_pipeline_firewall_delete_default_rule(struct app_params *app,
 	return 0;
 }
 
-/*
- * p firewall add ipv4
- */
-
-struct cmd_firewall_add_ipv4_result {
+struct cmd_firewall_parsed_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_string;
-	int32_t priority;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-	uint8_t port_id;
+	cmdline_multi_string_t multi_string;
 };
 
-static void
-cmd_firewall_add_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_ipv4_result *params = parsed_result;
+static void cmd_firewall_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl, void *data) {
+	struct cmd_firewall_parsed_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_firewall_key key;
 	int status;
+	struct pipeline_firewall_key key;
 
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_add_rule(app,
-		params->pipeline_id,
-		&key,
-		params->priority,
-		params->port_id);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_priority =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, priority,
-		INT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip_mask,
-		UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto_mask, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		port_id, UINT8);
-
-cmdline_parse_inst_t cmd_firewall_add_ipv4 = {
-	.f = cmd_firewall_add_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_ipv4_p_string,
-		(void *) &cmd_firewall_add_ipv4_pipeline_id,
-		(void *) &cmd_firewall_add_ipv4_firewall_string,
-		(void *) &cmd_firewall_add_ipv4_add_string,
-		(void *) &cmd_firewall_add_ipv4_ipv4_string,
-		(void *) &cmd_firewall_add_ipv4_priority,
-		(void *) &cmd_firewall_add_ipv4_src_ip,
-		(void *) &cmd_firewall_add_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_dst_ip,
-		(void *) &cmd_firewall_add_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_src_port_from,
-		(void *) &cmd_firewall_add_ipv4_src_port_to,
-		(void *) &cmd_firewall_add_ipv4_dst_port_from,
-		(void *) &cmd_firewall_add_ipv4_dst_port_to,
-		(void *) &cmd_firewall_add_ipv4_proto,
-		(void *) &cmd_firewall_add_ipv4_proto_mask,
-		(void *) &cmd_firewall_add_ipv4_port_id,
-		NULL,
-	},
-};
-
-/*
- * p firewall del ipv4
- */
-
-struct cmd_firewall_del_ipv4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_string;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
+	uint32_t priority;
+	struct in_addr sipaddr;
+	uint32_t sipdepth;
+	struct in_addr dipaddr;
+	uint32_t dipdepth;
+	uint16_t sport0;
+	uint16_t sport1;
+	uint16_t dport0;
+	uint16_t dport1;
 	uint8_t proto;
-	uint8_t proto_mask;
-};
+	uint8_t protomask;
+	uint32_t port_id;
+	char *filepath;
 
-static void
-cmd_firewall_del_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_ipv4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_firewall_key key;
-	int status;
-
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_delete_rule(app,
-		params->pipeline_id,
-		&key);
+	char *tokens[17];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 
 	if (status != 0) {
-		printf("Command failed\n");
+		printf("Too many tokens\n");
 		return;
 	}
-}
 
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip_mask,
-		UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		src_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_port_to,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		proto, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, proto_mask,
-		UINT8);
-
-cmdline_parse_inst_t cmd_firewall_del_ipv4 = {
-	.f = cmd_firewall_del_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_ipv4_p_string,
-		(void *) &cmd_firewall_del_ipv4_pipeline_id,
-		(void *) &cmd_firewall_del_ipv4_firewall_string,
-		(void *) &cmd_firewall_del_ipv4_del_string,
-		(void *) &cmd_firewall_del_ipv4_ipv4_string,
-		(void *) &cmd_firewall_del_ipv4_src_ip,
-		(void *) &cmd_firewall_del_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_dst_ip,
-		(void *) &cmd_firewall_del_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_src_port_from,
-		(void *) &cmd_firewall_del_ipv4_src_port_to,
-		(void *) &cmd_firewall_del_ipv4_dst_port_from,
-		(void *) &cmd_firewall_del_ipv4_dst_port_to,
-		(void *) &cmd_firewall_del_ipv4_proto,
-		(void *) &cmd_firewall_del_ipv4_proto_mask,
-		NULL,
-	},
-};
-
-/*
- * p firewall add bulk
- */
-
-struct cmd_firewall_add_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
-
-static void
-cmd_firewall_add_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	struct app_pipeline_add_bulk_params add_bulk_params;
-
-	status = app_pipeline_add_bulk_parse_file(params->file_path, &add_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
+	if ((n_tokens > 0) && (0 != strcmp(tokens[0], "add")) && (0 != strcmp(tokens[0], "del"))
+			&& (0 != strcmp(tokens[0], "ls"))) {
+		printf("Usage: \n p <id> firewall add ... \n p <id> firewall del... \n p <id> firewall ls\n");
+		return;
 	}
 
-	status = app_pipeline_firewall_add_bulk(app, params->pipeline_id, add_bulk_params.keys,
-			add_bulk_params.n_keys, add_bulk_params.priorities, add_bulk_params.port_ids);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
+	/* Parsing add command*/
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "add"))) {
+		if (n_tokens > 18) {
+			printf("Command failed firewall add too many arguments\n");
+			return;
+		}
+		if (n_tokens < 2) {
+			printf(
+					"Usage: \n p <id> firewall add priority ... \n p <id> "
+					"firewall add bulk ... \n p <id> firewall default ..\n");
+			return;
+		}
+
+		/* Parsing add priority */
+		if (0 == strcmp(tokens[1], "priority")) {
+
+			if (n_tokens > 16) {
+				printf(
+						"Usage\n too many arguments\n p <pipeline ID> firewall "
+						"add priority <priority> ipv4 <sipaddr> <sipdepth> "
+						"<dipaddr> <dipdepth> <sport0> <sport1> <dport0> "
+						"<dport1> <proto> <protomask> port <port ID>\n");
+				return;
+			}
+
+			if (n_tokens < 16) {
+				printf(
+						"Usage\nnot enough arguments\n p <pipeline ID> firewall"
+						" add priority <priority> ipv4 <sipaddr> <sipdepth>"
+						" <dipaddr> <dipdepth> <sport0> <sport1> <dport0> "
+						"<dport1> <proto> <protomask> port <port ID>\n");
+				return;
+			}
+
+			if (parser_read_uint32(&priority, tokens[2])) {
+				printf("Incorrect format for priority\n");
+				return;
+			}
+
+			if (strcmp(tokens[3], "ipv4")) {
+				printf("string  supported ipv4\n");
+				return;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &sipaddr)) {
+				printf("Incorrect format for sipaddr\n");
+				return;
+			}
+
+			if (parser_read_uint32(&sipdepth, tokens[5])) {
+				printf("Incorrect format for sipdepth\n");
+				return;
+			}
+
+			if (parse_ipv4_addr(tokens[6], &dipaddr)) {
+				printf("Incorrect format for dipaddr\n");
+				return;
+			}
+
+			if (parser_read_uint32(&dipdepth, tokens[7])) {
+				printf("Incorrect format for dipdepth\n");
+				return;
+			}
+
+			if (parser_read_uint16(&sport0, tokens[8])) {
+				printf("Incorrect format for sport0\n");
+				return;
+			}
+
+			if (parser_read_uint16(&sport1, tokens[9])) {
+				printf("Incorrect format for sport1\n");
+				return;
+			}
+
+			if (parser_read_uint16(&dport0, tokens[10])) {
+				printf("Incorrect format for dport0\n");
+				return;
+			}
+
+			if (parser_read_uint16(&dport1, tokens[11])) {
+				printf("Incorrect format for dport1\n");
+				return;
+			}
+
+			if (parser_read_uint8(&proto, tokens[12])) {
+				printf("Incorrect format for proto\n");
+				return;
+			}
+
+			char *e;
+			protomask = strtoul(tokens[13], &e, 16);
+			if (*e || errno == EINVAL || errno == ERANGE) {
+				printf("Incorrect format for protomask - should be in hex \n");
+				return;
+			}
+
+			if (strcmp(tokens[14], "port")) {
+				printf("string  supported port\n");
+				return;
+			}
+
+			if (parser_read_uint32(&port_id, tokens[15])) {
+				printf("Incorrect format for port ID\n");
+				return;
+			}
+
+			key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+			key.key.ipv4_5tuple.src_ip = rte_bswap32((uint32_t) sipaddr.s_addr);
+			key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+			key.key.ipv4_5tuple.dst_ip = rte_bswap32((uint32_t) dipaddr.s_addr);
+			key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+			key.key.ipv4_5tuple.src_port_from = sport0;
+			key.key.ipv4_5tuple.src_port_to = sport1;
+			key.key.ipv4_5tuple.dst_port_from = dport0;
+			key.key.ipv4_5tuple.dst_port_to = dport1;
+			key.key.ipv4_5tuple.proto = proto;
+			key.key.ipv4_5tuple.proto_mask = protomask;
+
+			status = app_pipeline_firewall_add_rule(app, params->pipeline_id,
+					&key, priority, port_id);
+
+			if (status != 0)
+				printf("Command failed\n");
+
+			return;
+
+		}
+
+		/* Parsing add default */
+		if ((0 == strcmp(tokens[1], "default"))
+				&& (0 != strcmp(tokens[1], "bulk"))
+				&& (0 != strcmp(tokens[1], "priority"))) {
+			if (n_tokens > 3) {
+				printf(
+						"too many arguments: \np <pipeline ID> firewall add "
+						"default <port ID>");
+				return;
+			}
+
+			if (n_tokens < 3) {
+				printf(
+						"not enough arguments \np <pipeline ID> firewall add "
+						"default <port ID>");
+				return;
+			}
+
+			if (parser_read_uint32(&port_id, tokens[2])) {
+				printf("Incorrect format for port ID\n");
+				return;
+			}
+
+			status = app_pipeline_firewall_add_default_rule(app,
+					params->pipeline_id, port_id);
+
+			if (status != 0)
+				printf("Command failed\n");
+
+			return;
+		}
+
+		/* Parsing add bulk */
+		if (0 == strcmp(tokens[1], "bulk")) {
+			if (n_tokens > 3) {
+				printf(
+						"too many arguments: \np <pipeline ID> firewall add "
+						"bulk <file>");
+				return;
+			}
+
+			if (n_tokens < 3) {
+				printf(
+						"not enough arguments \np <pipeline ID> firewall add "
+						"bulk <file>");
+				return;
+			}
+
+			filepath = tokens[2];
+			printf("%s", filepath);
+
+			struct app_pipeline_add_bulk_params add_bulk_params;
+			memset(&add_bulk_params, 0, sizeof(struct app_pipeline_add_bulk_params));
+
+			status = app_pipeline_add_bulk_parse_file(filepath,
+					&add_bulk_params);
+			if (status != 0) {
+				printf("Command failed\n");
+				goto end;
+			}
+
+			status = app_pipeline_firewall_add_bulk(app, params->pipeline_id,
+					add_bulk_params.keys, add_bulk_params.n_keys,
+					add_bulk_params.priorities, add_bulk_params.port_ids);
+			if (status != 0) {
+				printf("Command failed\n");
+				goto end;
+			}
+
+			return;
+
+			end:
+			rte_free(add_bulk_params.keys);
+			rte_free(add_bulk_params.priorities);
+			rte_free(add_bulk_params.port_ids);
+			return;
+
+		}
 	}
 
-end:
-	rte_free(add_bulk_params.keys);
-	rte_free(add_bulk_params.priorities);
-	rte_free(add_bulk_params.port_ids);
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_add_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_bulk_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_firewall_add_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		bulk_string, "bulk");
-
-cmdline_parse_token_string_t cmd_firewall_add_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		file_path, NULL);
-
-cmdline_parse_inst_t cmd_firewall_add_bulk = {
-	.f = cmd_firewall_add_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add bulk",
-	.tokens = {
-		(void *) &cmd_firewall_add_bulk_p_string,
-		(void *) &cmd_firewall_add_bulk_pipeline_id,
-		(void *) &cmd_firewall_add_bulk_firewall_string,
-		(void *) &cmd_firewall_add_bulk_add_string,
-		(void *) &cmd_firewall_add_bulk_bulk_string,
-		(void *) &cmd_firewall_add_bulk_file_path_string,
-		NULL,
-	},
-};
-
-/*
- * p firewall del bulk
- */
-
-struct cmd_firewall_del_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
-
-static void
-cmd_firewall_del_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	struct app_pipeline_del_bulk_params del_bulk_params;
-
-	status = app_pipeline_del_bulk_parse_file(params->file_path, &del_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
+	/* Parsing del command */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "del"))) {
+		if (n_tokens > 15) {
+			printf("Command failed firewall add too many arguments\n");
+			return;
+		}
+		if (n_tokens < 2) {
+			printf(
+					"Usage: \n p <id> firewall del ipv4 ... \n p <id> firewall "
+					"del bulk ... \n p <id> firewall del default ...\n");
+			return;
+		}
+
+		if (strcmp(tokens[1], "ipv4") == 0) {
+			if (n_tokens > 12) {
+				printf(
+						"too many arguments: \np <pipeline ID> firewall del"
+						" ipv4 .. ");
+				return;
+			}
+
+			if (n_tokens < 12) {
+				printf(
+						"not enough arguments \np <pipeline ID> firewall del"
+						" ipv4 .. ");
+				return;
+			}
+
+			if (parse_ipv4_addr(tokens[2], &sipaddr)) {
+				printf("Incorrect format for sipaddr\n");
+				return;
+			}
+
+			if (parser_read_uint32(&sipdepth, tokens[3])) {
+				printf("Incorrect format for sipdepth\n");
+				return;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &dipaddr)) {
+				printf("Incorrect format for dipaddr\n");
+				return;
+			}
+
+			if (parser_read_uint32(&dipdepth, tokens[5])) {
+				printf("Incorrect format for dipdepth\n");
+				return;
+			}
+
+			if (parser_read_uint16(&sport0, tokens[6])) {
+				printf("Incorrect format for sport0\n");
+				return;
+			}
+
+			if (parser_read_uint16(&sport1, tokens[7])) {
+				printf("Incorrect format for sport1\n");
+				return;
+			}
+			if (parser_read_uint16(&dport0, tokens[8])) {
+				printf("Incorrect format for dport0\n");
+				return;
+			}
+
+			if (parser_read_uint16(&dport1, tokens[9])) {
+				printf("Incorrect format for dport1\n");
+				return;
+			}
+
+			if (parser_read_uint8(&proto, tokens[10])) {
+				printf("Incorrect format for proto\n");
+				return;
+			}
+
+			char *e;
+			protomask = strtoul(tokens[11], &e, 16);
+			if (*e || errno == EINVAL || errno == ERANGE) {
+				printf("Incorrect format for protomask - should be in hex \n");
+				return;
+			}
+
+			key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+			key.key.ipv4_5tuple.src_ip = rte_bswap32((uint32_t) sipaddr.s_addr);
+			key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+			key.key.ipv4_5tuple.dst_ip = rte_bswap32((uint32_t) dipaddr.s_addr);
+			key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+			key.key.ipv4_5tuple.src_port_from = sport0;
+			key.key.ipv4_5tuple.src_port_to = sport1;
+			key.key.ipv4_5tuple.dst_port_from = dport0;
+			key.key.ipv4_5tuple.dst_port_to = dport1;
+			key.key.ipv4_5tuple.proto = proto;
+			key.key.ipv4_5tuple.proto_mask = protomask;
+
+			status = app_pipeline_firewall_delete_rule(app, params->pipeline_id,
+					&key);
+
+			if (status != 0)
+				printf("Command failed\n");
+
+			return;
+		}
+
+		/* del bulk */
+		if (strcmp(tokens[1], "bulk") == 0) {
+			if (n_tokens > 3) {
+				printf(
+						"too many arguments: \np <pipeline ID> firewall del "
+						"bulk <file>");
+				return;
+			}
+
+			if (n_tokens < 3) {
+				printf(
+						"not enough arguments \np <pipeline ID> firewall del"
+						" bulk <file>");
+				return;
+			}
+
+			filepath = tokens[2];
+			struct app_pipeline_del_bulk_params del_bulk_params;
+			memset(&del_bulk_params, 0, sizeof(struct app_pipeline_del_bulk_params));
+
+			status = app_pipeline_del_bulk_parse_file(filepath,
+					&del_bulk_params);
+			if (status != 0) {
+				printf("Command failed\n");
+				goto end1;
+			}
+
+			status = app_pipeline_firewall_delete_bulk(app, params->pipeline_id,
+					del_bulk_params.keys, del_bulk_params.n_keys);
+			if (status != 0) {
+				printf("Command failed\n");
+				goto end1;
+			}
+			return;
+
+			end1: rte_free(del_bulk_params.keys);
+			return;
+
+		}
+
+		if (strcmp(tokens[1], "default") == 0) {
+			if (n_tokens > 2) {
+				printf(
+						"too many arguments: \np <pipeline ID> firewall del "
+						"default");
+				return;
+			}
+
+			if (n_tokens < 2) {
+				printf(
+						"not enough arguments \np <pipeline ID> firewall del "
+						"default");
+				return;
+			}
+
+			status = app_pipeline_firewall_delete_default_rule(app,
+					params->pipeline_id);
+
+			if (status != 0)
+				printf("Command failed\n");
+
+			return;
+
+		}
 	}
 
-	status = app_pipeline_firewall_delete_bulk(app, params->pipeline_id,
-			del_bulk_params.keys, del_bulk_params.n_keys);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
-
-end:
-	rte_free(del_bulk_params.keys);
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_del_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_bulk_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_firewall_del_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		bulk_string, "bulk");
-
-cmdline_parse_token_string_t cmd_firewall_del_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		file_path, NULL);
-
-cmdline_parse_inst_t cmd_firewall_del_bulk = {
-	.f = cmd_firewall_del_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule del bulk",
-	.tokens = {
-		(void *) &cmd_firewall_del_bulk_p_string,
-		(void *) &cmd_firewall_del_bulk_pipeline_id,
-		(void *) &cmd_firewall_del_bulk_firewall_string,
-		(void *) &cmd_firewall_del_bulk_add_string,
-		(void *) &cmd_firewall_del_bulk_bulk_string,
-		(void *) &cmd_firewall_del_bulk_file_path_string,
-		NULL,
-	},
-};
+	/* Parsing ls command */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "ls"))) {
 
-/*
- * p firewall add default
- */
-struct cmd_firewall_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint8_t port_id;
-};
+		if (n_tokens > 1) {
+			printf("Command firewall ls too many arguments\n");
+			return;
+		}
 
-static void
-cmd_firewall_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		status = app_pipeline_firewall_ls(app, params->pipeline_id);
 
-	status = app_pipeline_firewall_add_default_rule(app,
-		params->pipeline_id,
-		params->port_id);
+		if (status != 0)
+			printf("Command firewall ls failed\n");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_firewall_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result,
-		pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_firewall_add_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	add_string, "add");
-
-cmdline_parse_token_string_t cmd_firewall_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		default_string, "default");
-
-cmdline_parse_token_num_t cmd_firewall_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result, port_id,
-		UINT8);
-
-cmdline_parse_inst_t cmd_firewall_add_default = {
-	.f = cmd_firewall_add_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_default_p_string,
-		(void *) &cmd_firewall_add_default_pipeline_id,
-		(void *) &cmd_firewall_add_default_firewall_string,
-		(void *) &cmd_firewall_add_default_add_string,
-		(void *) &cmd_firewall_add_default_default_string,
-		(void *) &cmd_firewall_add_default_port_id,
-		NULL,
-	},
-};
-
-/*
- * p firewall del default
- */
-struct cmd_firewall_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_firewall_del_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_firewall_delete_default_rule(app,
-		params->pipeline_id);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
 	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		p_string, "p");
 
-cmdline_parse_token_num_t cmd_firewall_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_default_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_firewall_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		default_string, "default");
-
-cmdline_parse_inst_t cmd_firewall_del_default = {
-	.f = cmd_firewall_del_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_default_p_string,
-		(void *) &cmd_firewall_del_default_pipeline_id,
-		(void *) &cmd_firewall_del_default_firewall_string,
-		(void *) &cmd_firewall_del_default_del_string,
-		(void *) &cmd_firewall_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * p firewall ls
- */
-
-struct cmd_firewall_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_firewall_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_firewall_ls(app, params->pipeline_id);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
 }
 
-cmdline_parse_token_string_t cmd_firewall_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, p_string,
+cmdline_parse_token_string_t cmd_firewall_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_parsed_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_firewall_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_ls_result, pipeline_id,
+cmdline_parse_token_num_t cmd_firewall_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_parsed_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_firewall_ls_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result,
+cmdline_parse_token_string_t cmd_firewall_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_parsed_result,
 	firewall_string, "firewall");
 
-cmdline_parse_token_string_t cmd_firewall_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_firewall_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_parsed_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_firewall_ls = {
-	.f = cmd_firewall_ls_parsed,
+cmdline_parse_inst_t cmd_firewall = {
+	.f = cmd_firewall_parsed,
 	.data = NULL,
-	.help_str = "Firewall rule list",
+	.help_str = "\n p <pipeline ID> firewall add priority <priority> ipv4 "
+				"<sipaddr> <sipdepth> <dipaddr> <dipdepth> <sport0> <sport1> "
+				"<dport0> <dport1> <proto> <protomask> port <port ID> \n"
+				"\n p <pipeline ID> firewall add bulk <file>  \n"
+				"\n p <pipeline ID> firewall add default <port ID>\n"
+				"\n p <pipeline ID> firewall del ipv4 <sipaddr> <sipdepth>"
+				"<dipaddr> <dipdepth> <sport0> <sport1> <dport0> <dport1> "
+				"<proto> <protomask> \n"
+				"\n p <pipeline ID> firewall del bulk <file> \n"
+				"\n p <pipeline ID> firewall del default \n"
+				"\n p <pipeline ID> firewall ls \n",
 	.tokens = {
-		(void *) &cmd_firewall_ls_p_string,
-		(void *) &cmd_firewall_ls_pipeline_id,
-		(void *) &cmd_firewall_ls_firewall_string,
-		(void *) &cmd_firewall_ls_ls_string,
+		(void *) &cmd_firewall_p_string,
+		(void *) &cmd_firewall_pipeline_id,
+		(void *) &cmd_firewall_firewall_string,
+		(void *)&cmd_firewall_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall_add_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_ls,
+	(cmdline_parse_inst_t *) &cmd_firewall,
 	NULL,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 5/6] examples/ip_pipeline: modifies flow classifications pipeline CLI
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
                   ` (3 preceding siblings ...)
  2016-05-06 15:57 ` [PATCH 4/6] examples/ip_pipeline: modifies firewall pipeline CLI Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-06 15:57 ` [PATCH 6/6] examples/ip_pipeline: modifies flow action " Michal Jastrzebski
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Tomasz Kulasek, Marcin Kerlin, Slawomir Mrozowicz, Michal Kobylinski

This patch modifies flow classifications pipeline command line
interface. All commands are merged into one cmd_fc_parsed.
Additionally a classification for ipv6, ipv4 and qinq can be added from
configuration file.

1. flow add qinq bulk
File line format:
qinq <svlan> <cvlan> port <port ID> id <flow ID>
File line example:
qinq 1 2 port 3 id 0

2. flow add ipv4 bulk
File line format:
ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>
File line example:
ipv4 1.2.3.4 10.20.30.40 63 127 6 port 2 id 999

3. flow add ipv6 bulk
File line format:
ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Michal Kobylinski <michalx.kobylinski@intel.com>
---
 .../pipeline/pipeline_flow_classification.c        | 2066 ++++++++------------
 1 file changed, 849 insertions(+), 1217 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
index 1921574..1a74baa 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -50,6 +51,13 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_classification.h"
 #include "hash_func.h"
+#include "parser.h"
+
+#define BUF_SIZE			1024
+#define TOKEN_SIZE			32
+#define IPV4_NUM_OF_TOKENS	10
+#define IPV6_NUM_OF_TOKENS	10
+#define QINQ_NUM_OF_TOKENS	7
 
 /*
  * Key conversion
@@ -82,6 +90,13 @@ struct pkt_key_ipv6_5tuple {
 	uint16_t port_dst;
 } __attribute__((__packed__));
 
+struct app_pipeline_add_bulk_params {
+	struct pipeline_fc_key *keys;
+	uint32_t n_keys;
+	uint32_t *port_ids;
+	uint32_t *flow_ids;
+};
+
 static int
 app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 	uint8_t *key_out,
@@ -277,6 +292,446 @@ app_pipeline_fc_key_check(struct pipeline_fc_key *key)
 	}
 }
 
+static int
+app_pipeline_fc_add_qinq_bulk_parse_file(FILE *file,
+		struct app_pipeline_add_bulk_params *params)
+{
+	FILE *f = file;
+	uint16_t num_value16;
+	uint32_t i, num_value, ret_tokens, line = 0;
+	char file_buf[BUF_SIZE];
+	char *tokens[QINQ_NUM_OF_TOKENS];
+
+	ret_tokens = QINQ_NUM_OF_TOKENS;
+
+	i = 0;
+	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
+		int status;
+		uint8_t pos = 0;
+
+		status = parse_tokenize_string(file_buf, tokens, &ret_tokens);
+
+		if (ret_tokens == 0 || tokens[0][0] == '#') {
+			line++;
+			ret_tokens = QINQ_NUM_OF_TOKENS;
+			continue;
+		}
+
+		if (status != 0 || ret_tokens != QINQ_NUM_OF_TOKENS) {
+			if (status == -E2BIG)
+				printf("too many parameters at %d line\n", line + 1);
+			else if (ret_tokens < QINQ_NUM_OF_TOKENS)
+				printf("not enough parameters at %d line, "
+						"missing %d parameters\n",
+						line + 1, QINQ_NUM_OF_TOKENS - ret_tokens);
+			else
+				printf("there was a problem with tokenize at %d line\n", line + 1);
+
+			return -1;
+		}
+
+		status = strcmp(tokens[pos++], "qinq");
+		if (status != 0) {
+			printf("not found keyword \'qinq\' at line %d.\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error svlan: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.qinq.svlan = num_value16;
+		pos++;
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error cvlan: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.qinq.cvlan = num_value16;
+		pos++;
+
+		status = strcmp(tokens[pos++], "port");
+		if (status != 0) {
+			printf("not found keyword \'port\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error port id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->port_ids[i] = num_value;
+		pos++;
+
+		status = strcmp(tokens[pos++], "id");
+		if (status != 0) {
+			printf("not found keyword \'id\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error flow id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->flow_ids[i] = num_value;
+
+		params->keys[i].type = FLOW_KEY_QINQ;
+
+		line++;
+		i++;
+	}
+
+	return 0;
+}
+
+static int
+app_pipeline_fc_add_ipv4_bulk_parse_file(FILE *file,
+		struct app_pipeline_add_bulk_params *params)
+{
+	FILE *f = file;
+	uint16_t num_value16;
+	uint32_t i, num_value, ret_tokens, line = 0;
+	char file_buf[BUF_SIZE];
+	char *tokens[IPV4_NUM_OF_TOKENS];
+	struct in_addr ipv4;
+
+	ret_tokens = IPV4_NUM_OF_TOKENS;
+
+	i = 0;
+	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
+		int status;
+		uint8_t pos = 0;
+
+		status = parse_tokenize_string(file_buf, tokens, &ret_tokens);
+
+		if (ret_tokens == 0 || tokens[0][0] == '#') {
+			line++;
+			ret_tokens = IPV4_NUM_OF_TOKENS;
+			continue;
+		}
+
+		if (status != 0 || ret_tokens != IPV4_NUM_OF_TOKENS) {
+			if (status == -E2BIG)
+				printf("too many parameters at %d line\n", line + 1);
+			else if (ret_tokens < QINQ_NUM_OF_TOKENS)
+				printf("not enough parameters at %d line, "
+						"missing %d parameters\n",
+						line + 1, QINQ_NUM_OF_TOKENS - ret_tokens);
+			else
+				printf("there was a problem with tokenize at %d line\n", line + 1);
+
+			return -1;
+		}
+
+		status = strcmp(tokens[pos++], "ipv4");
+		if (status != 0) {
+			printf("not found keyword \'ipv4\' at line %d.\n", line + 1);
+			return -1;
+		}
+
+		status = parse_ipv4_addr(tokens[pos], &ipv4);
+		if (status != 0) {
+			printf("conversion error src ip: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv4_5tuple.ip_src =
+				rte_bswap32((uint32_t) ipv4.s_addr);
+		pos++;
+
+		status = parse_ipv4_addr(tokens[pos], &ipv4);
+		if (status != 0) {
+			printf("conversion error dst ip: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv4_5tuple.ip_dst =
+				rte_bswap32((uint32_t) ipv4.s_addr);
+		pos++;
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error src port: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv4_5tuple.port_src = num_value16;
+		pos++;
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error dst port: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv4_5tuple.port_dst = num_value16;
+		pos++;
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error proto: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv4_5tuple.proto = num_value;
+		pos++;
+
+		status = strcmp(tokens[pos++], "port");
+		if (status != 0) {
+			printf("not found keyword \'port\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error port id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->port_ids[i] = num_value;
+		pos++;
+
+		status = strcmp(tokens[pos++], "id");
+		if (status != 0) {
+			printf("not found keyword \'id\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error flow id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->flow_ids[i] = num_value;
+
+		params->keys[i].type = FLOW_KEY_IPV4_5TUPLE;
+
+		line++;
+		i++;
+	}
+
+	return 0;
+}
+
+static int
+app_pipeline_fc_add_ipv6_bulk_parse_file(FILE *file,
+		struct app_pipeline_add_bulk_params *params)
+{
+	FILE *f = file;
+	uint16_t num_value16;
+	uint32_t i, num_value, ret_tokens, line = 0;
+	char file_buf[BUF_SIZE];
+	char *tokens[IPV6_NUM_OF_TOKENS];
+	struct in6_addr ipv6;
+
+	ret_tokens = IPV6_NUM_OF_TOKENS;
+
+	i = 0;
+	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
+		int status;
+		uint8_t pos = 0;
+
+		status = parse_tokenize_string(file_buf, tokens, &ret_tokens);
+
+		if (ret_tokens == 0 || tokens[0][0] == '#') {
+			line++;
+			ret_tokens = IPV6_NUM_OF_TOKENS;
+			continue;
+		}
+
+		if (status != 0 || ret_tokens != IPV6_NUM_OF_TOKENS) {
+			if (status == -E2BIG)
+				printf("too many parameters at %d line\n", line + 1);
+			else if (ret_tokens < QINQ_NUM_OF_TOKENS)
+				printf("not enough parameters at %d line, "
+						"missing %d parameters\n",
+						line + 1, QINQ_NUM_OF_TOKENS - ret_tokens);
+			else
+				printf("there was a problem with tokenize at %d line\n", line + 1);
+
+			return -1;
+		}
+
+		status = strcmp(tokens[pos++], "ipv6");
+		if (status != 0) {
+			printf("not found keyword \'ipv6\' at line %d.\n", line + 1);
+			return -1;
+		}
+
+		status = parse_ipv6_addr(tokens[pos], &ipv6);
+		if (status != 0) {
+			printf("conversion error src ip: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		memcpy(params->keys[i].key.ipv6_5tuple.ip_src, ipv6.s6_addr,
+				sizeof(ipv6.s6_addr));
+		pos++;
+
+		status = parse_ipv6_addr(tokens[pos], &ipv6);
+		if (status != 0) {
+			printf("conversion error dst ip: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		memcpy(params->keys[i].key.ipv6_5tuple.ip_dst, ipv6.s6_addr,
+				sizeof(ipv6.s6_addr));
+		pos++;
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error src port: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv6_5tuple.port_src = num_value16;
+		pos++;
+
+		status = parser_read_uint16(&num_value16, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error dst port: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv6_5tuple.port_dst = num_value16;
+		pos++;
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error proto: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->keys[i].key.ipv6_5tuple.proto = num_value;
+		pos++;
+
+		status = strcmp(tokens[pos++], "port");
+		if (status != 0) {
+			printf("not found keyword \'port\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error port id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->port_ids[i] = num_value;
+		pos++;
+
+		status = strcmp(tokens[pos++], "id");
+		if (status != 0) {
+			printf("not found keyword \'id\' at line %d\n", line + 1);
+			return -1;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error flow id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			return -1;
+		}
+		params->flow_ids[i] = num_value;
+
+		params->keys[i].type = FLOW_KEY_IPV6_5TUPLE;
+
+		line++;
+		i++;
+	}
+
+	return 0;
+}
+
+static int
+app_pipeline_fc_add_bulk_parse_file(char *filename,
+		struct app_pipeline_add_bulk_params *params, enum flow_key_type type)
+{
+	FILE *file;
+	int status;
+	char file_buf[BUF_SIZE];
+
+	file = fopen(filename, "r");
+	if (file == NULL) {
+		if (getcwd(file_buf, sizeof(file_buf)) != NULL)
+			printf("not found file %s in the current working dir %s\n",
+					filename, file_buf);
+		return -1;
+	}
+
+	params->n_keys = 0;
+	while (fgets(file_buf, BUF_SIZE, file) != NULL)
+		if (file_buf[0] != '\0' && file_buf[0] != '\n' && file_buf[0] != '#')
+			params->n_keys++;
+	rewind(file);
+
+	if (params->n_keys == 0) {
+		printf("not found any keys in the file %s\n", filename);
+		status = -1;
+		goto end;
+	}
+
+	params->keys = rte_malloc(NULL,
+			params->n_keys * sizeof(struct pipeline_fc_key),
+			RTE_CACHE_LINE_SIZE);
+	if (params->keys == NULL) {
+		printf("out of memory\n");
+		status = -1;
+		goto end;
+	}
+
+	params->port_ids = rte_malloc(NULL,
+			params->n_keys * sizeof(uint32_t),
+			RTE_CACHE_LINE_SIZE);
+	if (params->port_ids == NULL) {
+		printf("out of memory\n");
+		status = -1;
+		goto end;
+	}
+
+	params->flow_ids = rte_malloc(NULL,
+			params->n_keys * sizeof(uint32_t),
+			RTE_CACHE_LINE_SIZE);
+	if (params->flow_ids == NULL) {
+		printf("out of memory\n");
+		status = -1;
+		goto end;
+	}
+
+	switch (type) {
+	case FLOW_KEY_QINQ:
+		status = app_pipeline_fc_add_qinq_bulk_parse_file(file, params);
+		break;
+	case FLOW_KEY_IPV4_5TUPLE:
+		status = app_pipeline_fc_add_ipv4_bulk_parse_file(file, params);
+		break;
+	case FLOW_KEY_IPV6_5TUPLE:
+		status = app_pipeline_fc_add_ipv6_bulk_parse_file(file, params);
+		break;
+	default:
+		status = -1;
+		goto end;
+	}
+
+	if (status != 0) {
+		status = -1;
+		goto end;
+	}
+
+end:
+	fclose(file);
+	return status;
+}
+
 int
 app_pipeline_fc_add(struct app_params *app,
 	uint32_t pipeline_id,
@@ -897,1308 +1352,485 @@ app_pipeline_fc_ls(struct app_params *app,
 	return 0;
 }
 
-/*
- * flow add qinq
- */
-
-struct cmd_fc_add_qinq_result {
+struct cmd_fc_parsed_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
+	cmdline_fixed_string_t command_string;
 };
 
 static void
-cmd_fc_add_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
+cmd_fc_parsed(void *parsed_result, __attribute__((unused)) struct cmdline *cl,
+		void *data __rte_unused)
 {
-	struct cmd_fc_add_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
 	int status;
 
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, cvlan, UINT16);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, port_string,
-		"port");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, port, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flowid_string,
-		"flowid");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, flow_id, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_qinq = {
-	.f = cmd_fc_add_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow add (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_p_string,
-		(void *) &cmd_fc_add_qinq_pipeline_id,
-		(void *) &cmd_fc_add_qinq_flow_string,
-		(void *) &cmd_fc_add_qinq_add_string,
-		(void *) &cmd_fc_add_qinq_qinq_string,
-		(void *) &cmd_fc_add_qinq_svlan,
-		(void *) &cmd_fc_add_qinq_cvlan,
-		(void *) &cmd_fc_add_qinq_port_string,
-		(void *) &cmd_fc_add_qinq_port,
-		(void *) &cmd_fc_add_qinq_flowid_string,
-		(void *) &cmd_fc_add_qinq_flow_id,
-		NULL,
-	},
-};
-
-/*
- * flow add qinq all
- */
-
-struct cmd_fc_add_qinq_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
-
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
-static void
-cmd_fc_add_qinq_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_qinq_all_result *params = parsed_result;
+	uint32_t n_tokens;
+	char *tokens[256];
+	struct pipeline_fc_key key;
 	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input arguments */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+	struct cmd_fc_parsed_result *results =
+			(struct cmd_fc_parsed_result *)parsed_result;
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of output ports\n");
-		return;
-	}
+	enum flow_key_type type;
+	uint32_t sport;
+	uint32_t dport;
+	uint32_t proto;
+	uint32_t svlan;
+	uint32_t cvlan;
+	uint32_t port_id;
+	uint32_t flow_id;
+	struct in_addr sipaddr_ipv4;
+	struct in_addr dipaddr_ipv4;
+	struct in6_addr sipaddr_ipv6;
+	struct in6_addr dipaddr_ipv6;
+	char *file_name;
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+	n_tokens = RTE_DIM(tokens);
+	status = parse_tokenize_string(results->command_string, tokens, &n_tokens);
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
+	if (status) {
+		printf("Command \"flow\": Too many tokens\n");
 		return;
 	}
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
+	if (n_tokens < 1) {
+		printf("Not enough parameters for \"flow add|del|ls\"\n");
 		return;
 	}
 
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-
-		key[pos].type = FLOW_KEY_QINQ;
-		key[pos].key.qinq.svlan = id >> 12;
-		key[pos].key.qinq.cvlan = id & 0xFFF;
-
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
+	if (strcmp(tokens[0], "add") == 0) {
 
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"flow add\"\n");
+			return;
 		}
-	}
-
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, add_string,
-		"add");
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, qinq_string,
-		"qinq");
+		if (strcmp(tokens[1], "default") == 0) {
+			/* p <pipeline ID> flow add default <port ID> */
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, all_string,
-		"all");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_flows,
-		UINT32);
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_ports,
-		UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_qinq_all = {
-	.f = cmd_fc_add_qinq_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_all_p_string,
-		(void *) &cmd_fc_add_qinq_all_pipeline_id,
-		(void *) &cmd_fc_add_qinq_all_flow_string,
-		(void *) &cmd_fc_add_qinq_all_add_string,
-		(void *) &cmd_fc_add_qinq_all_qinq_string,
-		(void *) &cmd_fc_add_qinq_all_all_string,
-		(void *) &cmd_fc_add_qinq_all_n_flows,
-		(void *) &cmd_fc_add_qinq_all_n_ports,
-		NULL,
-	},
-};
-
-/*
- * flow add ipv4_5tuple
- */
-
-struct cmd_fc_add_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
-
-static void
-cmd_fc_add_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_dst);
+			if (n_tokens < 3) {
+				printf("Not enough parameters for \"flow add default <port ID>\"\n");
+				return;
+			}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_src,
-		UINT16);
+			if (parser_read_uint32(&port_id, tokens[2]) != 0) {
+				printf("Incorrect format for port id\n");
+				return;
+			}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_dst,
-		UINT16);
+			status = app_pipeline_fc_add_default(app, results->pipeline_id,
+					port_id);
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, proto,
-		UINT32);
+			if (status != 0)
+				printf("Command failed\n");
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_string,
-		"port");
+			return;
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port,
-		UINT32);
+		} else {
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flowid_string, "flowid");
+			if (n_tokens < 3) {
+				printf("Not enough parameters for \"flow add [ipv4|ipv6|qinq]\"\n");
+				return;
+			}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, flow_id,
-		UINT32);
+			/* parse key type to add */
+			if (strcmp(tokens[1], "qinq") == 0)
+				type = FLOW_KEY_QINQ;
+			else if (strcmp(tokens[1], "ipv4") == 0)
+				type = FLOW_KEY_IPV4_5TUPLE;
+			else if (strcmp(tokens[1], "ipv6") == 0)
+				type = FLOW_KEY_IPV6_5TUPLE;
+			else {
+				printf("Incorrect key type. Should be qinq, ipv4, ipv6 or default.\n");
+				return;
+			}
 
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {
-	.f = cmd_fc_add_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_proto,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_port,
-		(void *) &cmd_fc_add_ipv4_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_id,
-		NULL,
-	},
-};
+			/* check if this is a bulk command */
+			if (strcmp(tokens[2], "bulk") == 0) {
+				/* flow add <key type> bulk <file name> */
+				struct app_pipeline_add_bulk_params params = { 0 };
 
-/*
- * flow add ipv4_5tuple all
- */
+				file_name = tokens[3];
 
-struct cmd_fc_add_ipv4_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+				status = app_pipeline_fc_add_bulk_parse_file(file_name, &params,
+						type);
 
-static void
-cmd_fc_add_ipv4_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+				if (status != 0) {
+					printf("Bulk file parse error\n");
+					return;
+				}
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+				/* Flow add */
+				status = app_pipeline_fc_add_bulk(app, results->pipeline_id,
+						params.keys, params.port_ids, params.flow_ids,
+						params.n_keys);
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+				if (status != 0)
+						printf("Command failed\n");
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+				/* Memory free */
+				rte_free(params.flow_ids);
+				rte_free(params.port_ids);
+				rte_free(params.keys);
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+				return;
+			}
 
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
+			if (type == FLOW_KEY_QINQ) {
+
+				/* (flow add qinq) <svlan> <cvlan> port <port ID> id <flow ID> */
+				if (n_tokens < 8) {
+					printf("Not enough parameters for \"flow add qinq <svlan> <cvlan> port <port ID> id <flow ID>\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+					printf("Incorrect format for \"svlan\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+					printf("Incorrect format for \"cvlan\"\n");
+					return;
+				}
+
+				if (strcmp(tokens[4], "port") != 0) {
+					printf("Missed \"port\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&port_id, tokens[5]) != 0) {
+					printf("Incorrect format for \"port_id\"\n");
+					return;
+				}
+
+				if (strcmp(tokens[6], "id") != 0) {
+					printf("Missed \"id\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
+					printf("Incorrect parameter format for \"id <flow_id>\"\n");
+					return;
+				}
+
+			} else {
+				/* ipv4 / ipv6 */
+
+				if (n_tokens < 11) {
+					printf("Not enough parameters for \"flow add %s\"\n",
+							tokens[1]);
+					return;
+				}
+
+				/* parse source and destination IP addr dependly on key type */
+				if (type == FLOW_KEY_IPV4_5TUPLE) {
+					if (parse_ipv4_addr(tokens[2], &sipaddr_ipv4) != 0) {
+						printf("Incorrect format of IPv4 source address\n");
+						return;
+					}
+					if (parse_ipv4_addr(tokens[3], &dipaddr_ipv4) != 0) {
+						printf("Incorrect format of IPv4 destination address\n");
+						return;
+					}
+
+				} else if (type == FLOW_KEY_IPV6_5TUPLE) {
+					if (parse_ipv6_addr(tokens[2], &sipaddr_ipv6) != 0) {
+						printf("Incorrect format of IPv6 source address\n");
+						return;
+					}
+					if (parse_ipv6_addr(tokens[3], &dipaddr_ipv6) != 0) {
+						printf("Incorrect format of IPv6 destination address\n");
+						return;
+					}
+				}
+
+				if (parser_read_uint32(&sport, tokens[4]) != 0) {
+					printf("Incorrect format of source port\n");
+					return;
+				}
+
+				if (parser_read_uint32(&dport, tokens[5]) != 0) {
+					printf("Incorrect format of destination port\n");
+					return;
+				}
+
+				if (parser_read_uint32(&proto, tokens[6]) != 0) {
+					printf("Incorrect format of proto value\n");
+					return;
+				}
+
+				if (strcmp(tokens[7], "port") != 0) {
+					printf("Missed port identifier\n");
+					return;
+				}
+
+				if (parser_read_uint32(&port_id, tokens[8]) != 0) {
+					printf("Incorrect format of port ID\n");
+					return;
+				}
+
+				if (strcmp(tokens[9], "id") != 0) {
+					printf("Missed id identifier before flow ID\n");
+					return;
+				}
+
+				if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
+					printf("Incorrect format of flow ID\n");
+					return;
+				}
+			}
 
-		key[pos].type = FLOW_KEY_IPV4_5TUPLE;
-		key[pos].key.ipv4_5tuple.ip_src = 0;
-		key[pos].key.ipv4_5tuple.ip_dst = id;
-		key[pos].key.ipv4_5tuple.port_src = 0;
-		key[pos].key.ipv4_5tuple.port_dst = 0;
-		key[pos].key.ipv4_5tuple.proto = 6;
+			/**
+			 * Fill key structure with parsed values
+			 */
+			memset(&key, 0, sizeof(key));
 
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+			switch (type) {
+			case FLOW_KEY_QINQ: /* qinq */
+				key.type = FLOW_KEY_QINQ;
+				key.key.qinq.svlan = svlan;
+				key.key.qinq.cvlan = cvlan;
+				break;
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
+			case FLOW_KEY_IPV4_5TUPLE:	/* ipv4 */
+				key.type = FLOW_KEY_IPV4_5TUPLE;
+				key.key.ipv4_5tuple.ip_src = rte_bswap32(
+						sipaddr_ipv4.s_addr);
+				key.key.ipv4_5tuple.ip_dst = rte_bswap32(
+						dipaddr_ipv4.s_addr);
+				key.key.ipv4_5tuple.port_src = sport;
+				key.key.ipv4_5tuple.port_dst = dport;
+				key.key.ipv4_5tuple.proto = proto;
+				break;
 
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
+			case FLOW_KEY_IPV6_5TUPLE: /* ipv6 */
+				key.type = FLOW_KEY_IPV6_5TUPLE;
+				memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr_ipv6, 16);
+				memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr_ipv6, 16);
+				key.key.ipv6_5tuple.port_src = sport;
+				key.key.ipv6_5tuple.port_dst = dport;
+				key.key.ipv6_5tuple.proto = proto;
+				break;
+			}
 
-			if (status != 0) {
+			status = app_pipeline_fc_add(app, results->pipeline_id,
+					&key, port_id, flow_id);
+			if (status != 0)
 				printf("Command failed\n");
 
-				break;
-			}
+			return;
 		}
 	}
 
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		all_string, "all");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_flows, UINT32);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple_all = {
-	.f = cmd_fc_add_ipv4_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_ports,
-		NULL,
-	},
-};
+	if (strcmp(tokens[0], "del") == 0) {
+		/* ( p <pipeline ID> flow del ) qinq <svlan> <cvlan> */
+		/* ( p <pipeline ID> flow del ) ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> */
+		/* ( p <pipeline ID> flow del ) ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> */
+		/* ( p <pipeline ID> flow del ) default */
 
-/*
- * flow add ipv6_5tuple
- */
-
-struct cmd_fc_add_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
-
-static void
-cmd_fc_add_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_src,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_dst,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, proto,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		port_string, "port");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flowid_string, "flowid");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, flow_id,
-		UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {
-	.f = cmd_fc_add_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_proto,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_port,
-		(void *) &cmd_fc_add_ipv6_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_id,
-		NULL,
-	},
-};
-
-/*
- * flow add ipv6_5tuple all
- */
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"flow del\"\n");
+			return;
+		}
 
-struct cmd_fc_add_ipv6_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+		if (strcmp(tokens[1], "default") == 0) {
 
-static void
-cmd_fc_add_ipv6_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
-
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+			if (n_tokens != 2) {
+				printf("Incorrect number of parameters for \"flow del default\"\n");
+				return;
+			}
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+			status = app_pipeline_fc_del_default(app, results->pipeline_id);
+			if (status != 0)
+				printf("Command failed\n");
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+			return;
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+		} else {
 
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-		uint32_t *x;
+			/* parse key type to delete */
+			if (strcmp(tokens[1], "qinq") == 0)
+				type = FLOW_KEY_QINQ;
+			else if (strcmp(tokens[1], "ipv4") == 0)
+				type = FLOW_KEY_IPV4_5TUPLE;
+			else if (strcmp(tokens[1], "ipv6") == 0)
+				type = FLOW_KEY_IPV6_5TUPLE;
+			else {
+				printf("Unknown key type. Should be qinq, ipv4, ipv6 or default.\n");
+				return;
+			}
 
-		key[pos].type = FLOW_KEY_IPV6_5TUPLE;
-		x = (uint32_t *) key[pos].key.ipv6_5tuple.ip_dst;
-		*x = rte_bswap32(id);
-		key[pos].key.ipv6_5tuple.proto = 6;
+			if (type == FLOW_KEY_QINQ) {
+				/* Parse arguments for q-in-q deletion */
+
+				/* flow del qinq <svlan> <cvlan> */
+
+				if (n_tokens != 4) {
+					printf("Incorrect number of parameters for \"flow del qinq <svlan> <cvlan>\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+					printf("Incorrect format of \"svlan\"\n");
+					return;
+				}
+
+				if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+					printf("Incorrect format of \"cvlan\"\n");
+					return;
+				}
+
+			} else {
+				/* Parse arguments for IPv4/IPv6 deletion */
+				/* flow del [ipv4|ipv6] <sipaddr> <dipaddr> <sport> <dport> <proto> */
+
+				if (n_tokens != 7) {
+					printf("Incorrect number of parameters for \"flow del\"\n");
+					return;
+				}
+
+				if (type == FLOW_KEY_IPV4_5TUPLE) {
+					if (parse_ipv4_addr(tokens[2], &sipaddr_ipv4) != 0) {
+						printf("Incorrect format of IPv4 source address\n");
+						return;
+					}
+					if (parse_ipv4_addr(tokens[3], &dipaddr_ipv4) != 0) {
+						printf("Incorrect format of IPv4 destination address\n");
+						return;
+					}
+
+				} else {
+					if (parse_ipv6_addr(tokens[2], &sipaddr_ipv6) != 0) {
+						printf("Incorrect format of IPv6 source address\n");
+						return;
+					}
+
+					if (parse_ipv6_addr(tokens[3], &dipaddr_ipv6) != 0) {
+						printf("Incorrect format of IPv6 source address\n");
+						return;
+					}
+				}
+
+				if (parser_read_uint32(&sport, tokens[4]) != 0) {
+					printf("Incorrect format of source port\n");
+					return;
+				}
+
+				if (parser_read_uint32(&dport, tokens[5]) != 0) {
+					printf("Incorrect format of destination port\n");
+					return;
+				}
+
+				if (parser_read_uint32(&proto, tokens[6]) != 0) {
+					printf("Incorrect format of proto value\n");
+					return;
+				}
+			}
 
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+			/**
+			 * Set a key structure for key type FLOW_KEY_QINQ,
+			 * FLOW_KEY_IPV4_5TUPLE, FLOW_KEY_IPV6_5TUPLE
+			 */
+			memset(&key, 0, sizeof(key));
+
+			switch (type) {
+			case FLOW_KEY_QINQ:
+				key.type = FLOW_KEY_QINQ;
+				key.key.qinq.svlan = svlan;
+				key.key.qinq.cvlan = cvlan;
+				break;
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
+			case FLOW_KEY_IPV4_5TUPLE:
+				key.type = FLOW_KEY_IPV4_5TUPLE;
+				key.key.ipv4_5tuple.ip_src = rte_bswap32(sipaddr_ipv4.s_addr);
+				key.key.ipv4_5tuple.ip_dst = rte_bswap32(dipaddr_ipv4.s_addr);
+				key.key.ipv4_5tuple.port_src = sport;
+				key.key.ipv4_5tuple.port_dst = dport;
+				key.key.ipv4_5tuple.proto = proto;
+				break;
 
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
+			case FLOW_KEY_IPV6_5TUPLE:
+				key.type = FLOW_KEY_IPV6_5TUPLE;
+				memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr_ipv6, 16);
+				memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr_ipv6, 16);
+				key.key.ipv6_5tuple.port_src = sport;
+				key.key.ipv6_5tuple.port_dst = dport;
+				key.key.ipv6_5tuple.proto = proto;
+			}
 
-			if (status != 0) {
+			status = app_pipeline_fc_del(app, results->pipeline_id, &key);
+			if (status != 0)
 				printf("Command failed\n");
 
-				break;
-			}
+			return;
 		}
 	}
 
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		all_string, "all");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_flows, UINT32);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple_all = {
-	.f = cmd_fc_add_ipv6_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (ipv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_ports,
-		NULL,
-	},
-};
-
-/*
- * flow del qinq
- */
-struct cmd_fc_del_qinq_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-};
-
-static void
-cmd_fc_del_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, cvlan, UINT16);
-
-cmdline_parse_inst_t cmd_fc_del_qinq = {
-	.f = cmd_fc_del_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_del_qinq_p_string,
-		(void *) &cmd_fc_del_qinq_pipeline_id,
-		(void *) &cmd_fc_del_qinq_flow_string,
-		(void *) &cmd_fc_del_qinq_del_string,
-		(void *) &cmd_fc_del_qinq_qinq_string,
-		(void *) &cmd_fc_del_qinq_svlan,
-		(void *) &cmd_fc_del_qinq_cvlan,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv4_5tuple
- */
-
-struct cmd_fc_del_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_src, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_dst, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		proto, UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv4_5tuple = {
-	.f = cmd_fc_del_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv6_5tuple
- */
-
-struct cmd_fc_del_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_src,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_dst,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, proto,
-		UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv6_5tuple = {
-	.f = cmd_fc_del_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow add default
- */
-
-struct cmd_fc_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_fc_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_add_default(app, params->pipeline_id,
-		params->port);
+	if (strcmp(tokens[0], "ls") == 0) {
+		/* p <pipeline ID> flow ls */
 
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result,
-		default_string, "default");
-
-cmdline_parse_token_num_t cmd_fc_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, port, UINT32);
+		if (n_tokens != 1) {
+			printf("Incorrect number of parameters for \"flow ls\"\n");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_default = {
-	.f = cmd_fc_add_default_parsed,
-	.data = NULL,
-	.help_str = "Flow add default",
-	.tokens = {
-		(void *) &cmd_fc_add_default_p_string,
-		(void *) &cmd_fc_add_default_pipeline_id,
-		(void *) &cmd_fc_add_default_flow_string,
-		(void *) &cmd_fc_add_default_add_string,
-		(void *) &cmd_fc_add_default_default_string,
-		(void *) &cmd_fc_add_default_port,
-		NULL,
-	},
-};
+		status = app_pipeline_fc_ls(app, results->pipeline_id);
+		if (status != 0)
+			printf("Command failed\n");
 
-/*
- * flow del default
- */
+		return;
 
-struct cmd_fc_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
+	}
 
-static void
-cmd_fc_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	printf("Incorrect command. Should be \"flow (add|del|ls) ...\"\n");
+	return;
 
-	status = app_pipeline_fc_del_default(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_fc_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result,
-		default_string, "default");
-
-cmdline_parse_inst_t cmd_fc_del_default = {
-	.f = cmd_fc_del_default_parsed,
-	.data = NULL,
-	.help_str = "Flow delete default",
-	.tokens = {
-		(void *) &cmd_fc_del_default_p_string,
-		(void *) &cmd_fc_del_default_pipeline_id,
-		(void *) &cmd_fc_del_default_flow_string,
-		(void *) &cmd_fc_del_default_del_string,
-		(void *) &cmd_fc_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * flow ls
- */
-
-struct cmd_fc_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_fc_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
 
-cmdline_parse_token_string_t cmd_fc_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, p_string, "p");
+cmdline_parse_token_string_t cmd_fc_parsed_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_parsed_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fc_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_ls_result, pipeline_id, UINT32);
+cmdline_parse_token_num_t cmd_fc_parsed_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_parsed_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fc_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result,
-	flow_string, "flow");
+cmdline_parse_token_string_t cmd_fc_parsed_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_parsed_result, flow_string, "flow");
 
-cmdline_parse_token_string_t cmd_fc_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, ls_string,
-	"ls");
+cmdline_parse_token_string_t cmd_fc_parsed_command_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_parsed_result, command_string,
+		TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fc_ls = {
-	.f = cmd_fc_ls_parsed,
+/* One command to rule them all */
+cmdline_parse_inst_t cmd_fc_parsed_all = {
+	.f = cmd_fc_parsed,
 	.data = NULL,
-	.help_str = "Flow list",
+	.help_str =
+			"\n add qinq <svlan> <cvlan> port <port ID> id <flow ID> : Flow add (Q-in-Q)"
+			"\n add qinq bulk <file> : Flow add bulk (Q-in-Q)"
+			"\n add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flow ID> : Flow add (IPv4 5-tuple)"
+			"\n add ipv4 bulk <file> : Flow add bulk (IPv4 5-tuple)"
+			"\n add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flow ID> : Flow add (IPv6 5-tuple)"
+			"\n add ipv6 bulk <file> : Flow add bulk (IPv6 5-tuple)"
+			"\n add default <port ID> : Flow add default"
+			"\n del qinq <svlan> <cvlan> : Flow delete (Q-in-Q)"
+			"\n del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> : Flow delete (IPv4 5-tuple)"
+			"\n del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> : Flow delete (IPv6 5-tuple)"
+			"\n del default : Flow delete default"
+			"\n ls : Flow list",
 	.tokens = {
-		(void *) &cmd_fc_ls_p_string,
-		(void *) &cmd_fc_ls_pipeline_id,
-		(void *) &cmd_fc_ls_flow_string,
-		(void *) &cmd_fc_ls_ls_string,
+		(void *) &cmd_fc_parsed_p_string,
+		(void *) &cmd_fc_parsed_pipeline_id,
+		(void *) &cmd_fc_parsed_flow_string,
+		(void *) &cmd_fc_parsed_command_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_del_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_default,
-	(cmdline_parse_inst_t *) &cmd_fc_del_default,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple_all,
-
-	(cmdline_parse_inst_t *) &cmd_fc_ls,
+	(cmdline_parse_inst_t *) &cmd_fc_parsed_all,
 	NULL,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 6/6] examples/ip_pipeline: modifies flow action pipeline CLI
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
                   ` (4 preceding siblings ...)
  2016-05-06 15:57 ` [PATCH 5/6] examples/ip_pipeline: modifies flow classifications " Michal Jastrzebski
@ 2016-05-06 15:57 ` Michal Jastrzebski
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
  6 siblings, 0 replies; 26+ messages in thread
From: Michal Jastrzebski @ 2016-05-06 15:57 UTC (permalink / raw)
  To: dev; +Cc: Marcin Kerlin, Piotr Azarewicz

All commands merged into one: cmd_action_parsed.

modified bulk command:
action flow bulk
File line format:
flow <flow ID>
meter 0 <cir> <pir> <cbs> <pbs> meter 1 <cir> <pir> <cbs> <pbs> meter 2
<cir> <pir> <cbs> <pbs> meter 3 <cir> <pir> <cbs> <pbs>
policer 0 <action> <action> <action> policer 1 <action> <action>
<action> policer 2 <action> <action> <action> policer 3 <action>
<action> <action>
port <port ID>

at least one meter needs to be provided (can be any meter ID) and at
least one policer needs to be provided (can be any policer ID); for any
flow, for the metering and policer contexts not specified the default
values are applied (file “pipeline_flow_actions_be.c”, function
pipeline_fa_flow_params_set_default())

Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
---
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1826 ++++++++------------
 1 file changed, 764 insertions(+), 1062 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
index 4012121..f629260 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -50,6 +51,7 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_actions.h"
 #include "hash_func.h"
+#include "parser.h"
 
 /*
  * Flow actions pipeline
@@ -58,6 +60,12 @@
 #define N_FLOWS_BULK					4096
 #endif
 
+#define BUF_SIZE						1024
+#define FA_MAX_NUM_OF_TOKENS			48
+#define FA_MIN_NUM_OF_TOKENS			15
+#define FA_MAX_NUM_OF_RULES				4
+#define FA_MIN_NUM_OF_RULES				1
+
 struct app_pipeline_fa_flow {
 	struct pipeline_fa_flow_params params;
 	void *entry_ptr;
@@ -79,6 +87,12 @@ struct app_pipeline_fa {
 	struct app_pipeline_fa_flow *flows;
 } __rte_cache_aligned;
 
+struct app_pipeline_add_bulk_params {
+	struct pipeline_fa_flow_params *keys;
+	uint32_t n_keys;
+	uint32_t *flow_ids;
+};
+
 static void*
 app_pipeline_fa_init(struct pipeline_params *params,
 	__rte_unused void *arg)
@@ -601,6 +615,310 @@ string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
 	return -1;
 }
 
+static int
+app_pipeline_fa_add_bulk_parse_file(char *filename,
+		struct app_pipeline_add_bulk_params *params)
+{
+	FILE *file;
+	char file_buf[BUF_SIZE];
+	char *tokens[FA_MAX_NUM_OF_TOKENS];
+	uint32_t i, num_value, ret_tokens, line = 0;
+	uint64_t num_value64;
+	int status = 0;
+
+	file = fopen(filename, "r");
+	if (file == NULL) {
+		if (getcwd(file_buf, sizeof(file_buf)) != NULL)
+			printf("not found file %s in the current working dir %s\n",
+					filename, file_buf);
+		return -1;
+	}
+
+	params->n_keys = 0;
+	while (fgets(file_buf, BUF_SIZE, file) != NULL)
+		if (file_buf[0] != '\0' && file_buf[0] != '\n' && file_buf[0] != '#')
+			params->n_keys++;
+	rewind(file);
+
+	if (params->n_keys == 0) {
+		printf("not found any keys in the file %s\n", filename);
+		status = -1;
+		goto end;
+	}
+
+	params->keys = rte_malloc(NULL,
+			params->n_keys * sizeof(struct pipeline_fa_flow_params),
+			RTE_CACHE_LINE_SIZE);
+	if (params->keys == NULL) {
+		printf("out of memory\n");
+		status = -1;
+		goto end;
+	}
+
+	params->flow_ids = rte_malloc(NULL,
+			params->n_keys * sizeof(uint32_t),
+			RTE_CACHE_LINE_SIZE);
+	if (params->flow_ids == NULL) {
+		printf("out of memory\n");
+		status = -1;
+		goto end;
+	}
+
+	/* set default values for each key */
+	for (i = 0; i < params->n_keys; i++) {
+		status = pipeline_fa_flow_params_set_default(&params->keys[i]);
+
+		if (status != 0) {
+			printf("there was a problem with the setting default value\n");
+			status = -1;
+			goto end;
+		}
+	}
+
+	i = 0;
+	while (fgets(file_buf, BUF_SIZE, file) != NULL) {
+		uint8_t j, pos = 0, policer_count = 0, meter_count = 0, id_mask = 0;
+
+		ret_tokens = FA_MAX_NUM_OF_TOKENS;
+
+		status = parse_tokenize_string(file_buf, tokens, &ret_tokens);
+
+		if (status != 0) {
+			if (status == -E2BIG)
+				printf("too many parameters at %d line\n", line + 1);
+			else
+				printf("there was a problem with tokenize at %d line\n",
+						line + 1);
+
+			status = -1;
+			goto end;
+
+		} else if (ret_tokens == 0 || tokens[0][0] == '#') {
+			ret_tokens = FA_MAX_NUM_OF_TOKENS;
+			line++;
+			continue;
+
+		} else if (ret_tokens < FA_MIN_NUM_OF_TOKENS) {
+			printf("not enough parameters at %d line\n", line + 1);
+			status = -1;
+			goto end;
+		}
+
+		status = strcmp(tokens[pos++], "flow");
+		if (status != 0) {
+			printf("not found keyword \'flow\' at line %d\n", line + 1);
+			status = -1;
+			goto end;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error flow id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			status = -1;
+			goto end;
+		}
+		params->flow_ids[i] = num_value;
+		pos++;
+
+		/* check the number of occurrences of keywords 'policer' and 'meter' */
+		for (j = 0; j < ret_tokens; j++) {
+			if (strcmp(tokens[j], "policer") == 0)
+				policer_count++;
+			else if (strcmp(tokens[j], "meter") == 0)
+				meter_count++;
+		}
+
+		/* flow + id + port + id = 4 tokens */
+		if (ret_tokens != (uint32_t)(4 + (policer_count * 5) +
+				(meter_count * 6))) {
+			printf("incorrect amount of parameters at %d line for %d policers "
+					"and %d meters\n", line + 1, policer_count, meter_count);
+			status = -1;
+			goto end;
+		}
+
+		if (policer_count == 0) {
+			printf("the lack of any policers at line %d, required at least 1\n",
+					line + 1);
+			status = -1;
+			goto end;
+		} else if (policer_count > PIPELINE_FA_N_TC_MAX) {
+			printf("too much instances of policers at line %d\n", line + 1);
+			status = -1;
+			goto end;
+		}
+
+		if (meter_count == 0) {
+			printf("the lack of any meters at line %d, required at least 1\n",
+					line + 1);
+			status = -1;
+			goto end;
+		} else if (meter_count > PIPELINE_FA_N_TC_MAX) {
+			printf("too much instances of meters at line %d\n", line + 1);
+			status = -1;
+			goto end;
+		}
+
+		/* set up all meters from the parse file */
+		for (j = 0; j < meter_count; j++) {
+
+			status = strcmp(tokens[pos++], "meter");
+			if (status != 0) {
+				printf("not found keyword \'meter\' at line %d.\n", line + 1);
+				status = -1;
+				goto end;
+			}
+
+			status = parser_read_uint32(&num_value, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error meter id: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+
+			if (num_value > PIPELINE_FA_N_TC_MAX - 1) {
+				printf("meter id %d at line %d is not in the range <0,3>\n",
+						num_value, line + 1);
+				status = -1;
+				goto end;
+			}
+
+			if (id_mask & (1 << num_value)) {
+				printf("there were 2 the same ID for meters at line %d",
+						line + 1);
+				status = -1;
+				goto end;
+			}
+			id_mask |= 1 << num_value;
+			pos++;
+
+			struct rte_meter_trtcm_params *m = &params->keys[i].m[num_value];
+
+			status = parser_read_uint64(&num_value64, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error cir: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+			m->cir = num_value64;
+			pos++;
+
+			status = parser_read_uint64(&num_value64, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error pir: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+			m->pir = num_value64;
+			pos++;
+
+			status = parser_read_uint64(&num_value64, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error cbs: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+			m->cbs = num_value64;
+			pos++;
+
+			status = parser_read_uint64(&num_value64, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error pbs: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+			m->pbs = num_value64;
+			pos++;
+		}
+
+		id_mask = 0;
+		/* set up all policers from the parse file */
+		for (j = 0; j < policer_count; j++) {
+
+			status = strcmp(tokens[pos++], "policer");
+			if (status != 0) {
+				printf("not found keyword \'policer\' at line %d.\n", line + 1);
+				status = -1;
+				goto end;
+			}
+
+			status = parser_read_uint32(&num_value, tokens[pos]);
+			if (status != 0) {
+				printf("conversion error policer id: \'%s\' at line %d\n",
+						tokens[pos], line + 1);
+				status = -1;
+				goto end;
+			}
+
+			if (num_value > PIPELINE_FA_N_TC_MAX - 1) {
+				printf("policer id %d at line %d is not in the range <0,3>\n",
+						num_value, line + 1);
+				status = -1;
+				goto end;
+			}
+
+			if (id_mask & (1 << num_value)) {
+				printf("there were 2 the same ID for policers at line %d",
+						line + 1);
+				status = -1;
+				goto end;
+			}
+			id_mask |= 1 << num_value;
+
+			struct pipeline_fa_policer_params *p =
+												&params->keys[i].p[num_value];
+			pos++;
+
+			uint8_t k;
+
+			for (k = 0; k < e_RTE_METER_COLORS; k++) {
+
+				struct pipeline_fa_policer_action *a = &p->action[k];
+
+				status = string_to_policer_action(tokens[pos], a);
+
+				if (status != 0) {
+					printf("there was a problem with the set up"
+							" policer with id %d at line %d with action: %s\n",
+							num_value, line + 1, tokens[pos]);
+					status = 1;
+					goto end;
+				}
+				pos++;
+			}
+		}
+
+		status = strcmp(tokens[pos++], "port");
+		if (status != 0) {
+			printf("not found keyword \'port\' at line %d\n", line + 1);
+			status = -1;
+			goto end;
+		}
+
+		status = parser_read_uint32(&num_value, tokens[pos]);
+		if (status != 0) {
+			printf("conversion error port id: \'%s\' at line %d\n",
+					tokens[pos], line + 1);
+			status = -1;
+			goto end;
+		}
+		params->keys[i].port_id = num_value;
+
+		line++;
+		i++;
+	}
+
+end:
+	fclose(file);
+	return status;
+}
+
 static void
 print_flow(struct app_pipeline_fa *p,
 	uint32_t flow_id,
@@ -690,1114 +1008,498 @@ app_pipeline_fa_dscp_ls(struct app_params *app,
 }
 
 /*
- * Flow meter configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> meter <meter ID> trtcm <trtcm params>
+ * action cmd
  */
 
-struct cmd_fa_meter_config_result {
+struct cmd_action_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
+	cmdline_fixed_string_t action_string;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_fa_meter_config_parsed(
+cmd_action_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_fa_meter_config_result *params = parsed_result;
+	struct cmd_action_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->meter_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	flow_params.m[params->meter_id].cir = params->cir;
-	flow_params.m[params->meter_id].pir = params->pir;
-	flow_params.m[params->meter_id].cbs = params->cbs;
-	flow_params.m[params->meter_id].pbs = params->pbs;
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		1 << params->meter_id,
-		0,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_meter_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config = {
-	.f = cmd_fa_meter_config_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (single flow) ",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_p_string,
-		(void *) &cmd_fa_meter_config_pipeline_id,
-		(void *) &cmd_fa_meter_config_flow_string,
-		(void *) &cmd_fa_meter_config_flow_id,
-		(void *) &cmd_fa_meter_config_meter_string,
-		(void *) &cmd_fa_meter_config_meter_id,
-		(void *) &cmd_fa_meter_config_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
-/*
- * Flow meter configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> meter <meter ID> trtcm <trtcm params>
- */
-
-struct cmd_fa_meter_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
-};
-
-static void
-cmd_fa_meter_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_meter_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
-
-	if ((params->n_flows == 0) ||
-		(params->meter_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	memset(&flow_template, 0, sizeof(flow_template));
-	flow_template.m[params->meter_id].cir = params->cir;
-	flow_template.m[params->meter_id].pir = params->pir;
-	flow_template.m[params->meter_id].cbs = params->cbs;
-	flow_template.m[params->meter_id].pbs = params->pbs;
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos],
-			&flow_template,
-			sizeof(flow_template));
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				1 << params->meter_id,
-				0,
-				0,
-				flow_params);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
-		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config_bulk = {
-	.f = cmd_fa_meter_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_bulk_p_string,
-		(void *) &cmd_fa_meter_config_bulk_pipeline_id,
-		(void *) &cmd_fa_meter_config_bulk_flows_string,
-		(void *) &cmd_fa_meter_config_bulk_n_flows,
-		(void *) &cmd_fa_meter_config_bulk_meter_string,
-		(void *) &cmd_fa_meter_config_bulk_meter_id,
-		(void *) &cmd_fa_meter_config_bulk_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
-/*
- * Flow policer configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> policer <policer ID>
- *    G <action> Y <action> R <action>
- *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
-
-struct cmd_fa_policer_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
-};
-
-static void
-cmd_fa_policer_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->policer_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = string_to_policer_action(params->g_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		1 << params->policer_id,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	green_string, "G");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	g_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	yellow_string, "Y");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	y_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	red_string, "R");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	r_action, "R#Y#G#D");
-
-cmdline_parse_inst_t cmd_fa_policer_config = {
-	.f = cmd_fa_policer_config_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_p_string,
-		(void *) &cmd_fa_policer_config_pipeline_id,
-		(void *) &cmd_fa_policer_config_flow_string,
-		(void *) &cmd_fa_policer_config_flow_id,
-		(void *) &cmd_fa_policer_config_policer_string,
-		(void *) &cmd_fa_policer_config_policer_id,
-		(void *) &cmd_fa_policer_config_green_string,
-		(void *) &cmd_fa_policer_config_g_action,
-		(void *) &cmd_fa_policer_config_yellow_string,
-		(void *) &cmd_fa_policer_config_y_action,
-		(void *) &cmd_fa_policer_config_red_string,
-		(void *) &cmd_fa_policer_config_r_action,
-		NULL,
-	},
-};
-
-/*
- * Flow policer configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> policer <policer ID>
- *    G <action> Y <action> R <action>
- *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
-
-struct cmd_fa_policer_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
-};
-
-static void
-cmd_fa_policer_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id, i;
-	int status;
-
-	if ((params->n_flows == 0) ||
-		(params->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	memset(&flow_template, 0, sizeof(flow_template));
-
-	status = string_to_policer_action(params->g_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-	 &flow_template.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos], &flow_template,
-			sizeof(flow_template));
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				0,
-				1 << params->policer_id,
-				0,
-				flow_params);
 
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
-		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	green_string, "G");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	g_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	yellow_string, "Y");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	y_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	red_string, "R");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	r_action, "R#Y#G#D");
-
-cmdline_parse_inst_t cmd_fa_policer_config_bulk = {
-	.f = cmd_fa_policer_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_bulk_p_string,
-		(void *) &cmd_fa_policer_config_bulk_pipeline_id,
-		(void *) &cmd_fa_policer_config_bulk_flows_string,
-		(void *) &cmd_fa_policer_config_bulk_n_flows,
-		(void *) &cmd_fa_policer_config_bulk_policer_string,
-		(void *) &cmd_fa_policer_config_bulk_policer_id,
-		(void *) &cmd_fa_policer_config_bulk_green_string,
-		(void *) &cmd_fa_policer_config_bulk_g_action,
-		(void *) &cmd_fa_policer_config_bulk_yellow_string,
-		(void *) &cmd_fa_policer_config_bulk_y_action,
-		(void *) &cmd_fa_policer_config_bulk_red_string,
-		(void *) &cmd_fa_policer_config_bulk_r_action,
-		NULL,
-	},
-};
-
-/*
- * Flow output port configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> port <port ID>
- */
-
-struct cmd_fa_output_port_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t port_string;
-	uint32_t port_id;
-};
-
-static void
-cmd_fa_output_port_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	flow_params.port_id = params->port_id;
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		0,
-		1,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_string, "port");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_id, UINT32);
-
-cmdline_parse_inst_t cmd_fa_output_port_config = {
-	.f = cmd_fa_output_port_config_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_p_string,
-		(void *) &cmd_fa_output_port_config_pipeline_id,
-		(void *) &cmd_fa_output_port_config_flow_string,
-		(void *) &cmd_fa_output_port_config_flow_id,
-		(void *) &cmd_fa_output_port_config_port_string,
-		(void *) &cmd_fa_output_port_config_port_id,
-		NULL,
-	},
-};
-
-/*
- * Flow output port configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> ports <n_ports>
- */
-
-struct cmd_fa_output_port_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t ports_string;
-	uint32_t n_ports;
-};
-
-static void
-cmd_fa_output_port_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
-
-	if (params->n_flows == 0) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-		uint32_t port_id = i % params->n_ports;
-
-		flow_id[pos] = i;
-
-		memset(&flow_params[pos], 0, sizeof(flow_params[pos]));
-		flow_params[pos].port_id = port_id;
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				0,
-				0,
-				1,
-				flow_params);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
-		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_ports_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	ports_string, "ports");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fa_output_port_config_bulk = {
-	.f = cmd_fa_output_port_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_bulk_p_string,
-		(void *) &cmd_fa_output_port_config_bulk_pipeline_id,
-		(void *) &cmd_fa_output_port_config_bulk_flows_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_flows,
-		(void *) &cmd_fa_output_port_config_bulk_ports_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_ports,
-		NULL,
-	},
-};
-
-/*
- * Flow DiffServ Code Point (DSCP) translation table configuration
- *
- * p <pipeline ID> dscp <DSCP ID> class <traffic class ID> color <color>
- *
- * <color> = G (green) | Y (yellow) | R (red)
-*/
-
-struct cmd_fa_dscp_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	uint32_t dscp_id;
-	cmdline_fixed_string_t class_string;
-	uint32_t traffic_class_id;
-	cmdline_fixed_string_t color_string;
-	cmdline_fixed_string_t color;
-
-};
-
-static void
-cmd_fa_dscp_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_config_result *params = parsed_result;
-	struct app_params *app = data;
-	enum rte_meter_color color;
-	int status;
-
-	status = string_to_color(params->color, &color);
-	if (status) {
-		printf("Invalid color\n");
-		return;
-	}
-
-	status = app_pipeline_fa_dscp_config(app,
-		params->pipeline_id,
-		params->dscp_id,
-		params->traffic_class_id,
-		color);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_string, "dscp");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_dscp_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_class_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	class_string, "class");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_traffic_class_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	traffic_class_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color_string, "color");
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color, "G#Y#R");
-
-cmdline_parse_inst_t cmd_fa_dscp_config = {
-	.f = cmd_fa_dscp_config_parsed,
-	.data = NULL,
-	.help_str = "Flow DSCP translation table configuration",
-	.tokens = {
-		(void *) &cmd_fa_dscp_config_p_string,
-		(void *) &cmd_fa_dscp_config_pipeline_id,
-		(void *) &cmd_fa_dscp_config_dscp_string,
-		(void *) &cmd_fa_dscp_config_dscp_id,
-		(void *) &cmd_fa_dscp_config_class_string,
-		(void *) &cmd_fa_dscp_config_traffic_class_id,
-		(void *) &cmd_fa_dscp_config_color_string,
-		(void *) &cmd_fa_dscp_config_color,
-		NULL,
-	},
-};
-
-/*
- * Flow policer stats read
- *
- * p <pipeline ID> flow <flow ID> policer <policer ID> stats
- */
-
-struct cmd_fa_policer_stats_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t stats_string;
-};
-
-static void
-cmd_fa_policer_stats_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_stats_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_policer_stats stats;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	status = app_pipeline_fa_flow_policer_stats_read(app,
-		params->pipeline_id,
-		params->flow_id,
-		params->policer_id,
-		1,
-		&stats);
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf("Command \"action\": Too many parameters.\n");
 		return;
 	}
 
-	/* Display stats */
-	printf("\tPkts G: %" PRIu64
-		"\tPkts Y: %" PRIu64
-		"\tPkts R: %" PRIu64
-		"\tPkts D: %" PRIu64 "\n",
-		stats.n_pkts[e_RTE_METER_GREEN],
-		stats.n_pkts[e_RTE_METER_YELLOW],
-		stats.n_pkts[e_RTE_METER_RED],
-		stats.n_pkts_drop);
-}
+	/* "action flow" or "action flow bulk" or "action flow ls" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "flow"))) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id;
 
-cmdline_parse_token_string_t cmd_fa_policer_stats_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	p_string, "p");
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"action flow\" or"
+					" \"action flow bulk\" or \"action flow ls\".\n");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_policer_stats_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	pipeline_id, UINT32);
+		/* action flow */
+		if (0 == parser_read_uint32(&flow_id, tokens[1])) {
+			if (n_tokens < 3) {
+				printf("Not enough parameters for \"action flow\".\n");
+				return;
+			}
 
-cmdline_parse_token_string_t cmd_fa_policer_stats_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_string, "flow");
+			/*
+			 * Flow meter configuration (single flow)
+			 *
+			 * p <pipeline ID> action flow <flow ID> meter <meter ID>
+			 * trtcm <cir> <pir> <cbs> <pbs>
+			 */
+			if (0 == strcmp(tokens[2], "meter")) {
+				uint32_t meter_id;
 
-cmdline_parse_token_num_t cmd_fa_policer_stats_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_id, UINT32);
+				if (n_tokens != 9) {
+					printf("Incorrect number of parameters for action flow"
+						" meter configuration.\n");
+					return;
+				}
 
-cmdline_parse_token_string_t cmd_fa_policer_stats_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_string, "policer");
+				if (parser_read_uint32(&meter_id, tokens[3])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is meter id.\n",
+						tokens[3]);
+					return;
+				}
+				if (meter_id >= PIPELINE_FA_N_TC_MAX) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected meter id is less than %d.\n",
+						tokens[3], PIPELINE_FA_N_TC_MAX);
+					return;
+				}
+				if (strcmp(tokens[4], "trtcm")) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is word \"trtcm\".\n",
+						tokens[4]);
+					return;
+				}
+				if (parser_read_uint64(&flow_params.m[meter_id].cir,
+					tokens[5])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is cir.\n",
+						tokens[5]);
+					return;
+				}
+				if (parser_read_uint64(&flow_params.m[meter_id].pir,
+					tokens[6])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is pir.\n",
+						tokens[6]);
+					return;
+				}
+				if (parser_read_uint64(&flow_params.m[meter_id].cbs,
+					tokens[7])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is cbs.\n",
+						tokens[7]);
+					return;
+				}
+				if (parser_read_uint64(&flow_params.m[meter_id].pbs,
+					tokens[8])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is pbs.\n",
+						tokens[8]);
+					return;
+				}
 
-cmdline_parse_token_num_t cmd_fa_policer_stats_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_id, UINT32);
+				status = app_pipeline_fa_flow_config(app,
+					params->pipeline_id,
+					flow_id,
+					1 << meter_id,
+					0,
+					0,
+					&flow_params);
+				if (status != 0)
+					printf("Command \"action flow meter\" failed.\n");
 
-cmdline_parse_token_string_t cmd_fa_policer_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	stats_string, "stats");
+				return;
+			}
+			/*
+			 * Flow policer configuration (single flow)
+			 *
+			 * p <pipeline ID> action flow <flow ID> policer <policer ID>
+			 *    g <action> y <action> r <action>
+			 *
+			 * <action> = G (green) | Y (yellow) | R (red) | D (drop)
+			 */
+			else if (0 == strcmp(tokens[2], "policer")) {
+				uint32_t policer_id;
 
-cmdline_parse_inst_t cmd_fa_policer_stats = {
-	.f = cmd_fa_policer_stats_parsed,
-	.data = NULL,
-	.help_str = "Flow policer stats read",
-	.tokens = {
-		(void *) &cmd_fa_policer_stats_p_string,
-		(void *) &cmd_fa_policer_stats_pipeline_id,
-		(void *) &cmd_fa_policer_stats_flow_string,
-		(void *) &cmd_fa_policer_stats_flow_id,
-		(void *) &cmd_fa_policer_stats_policer_string,
-		(void *) &cmd_fa_policer_stats_policer_id,
-		(void *) &cmd_fa_policer_stats_string,
-		NULL,
-	},
-};
-
-/*
- * Flow list
- *
- * p <pipeline ID> flow ls
- */
-
-struct cmd_fa_flow_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t actions_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_fa_flow_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_flow_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fa_flow_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+				if (n_tokens != 10) {
+					printf("Incorrect number of parameters for action flow"
+						" policer configuration.\n");
+					return;
+				}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	p_string, "p");
+				if (parser_read_uint32(&policer_id, tokens[3])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is policer id.\n",
+						tokens[3]);
+					return;
+				}
+				if (policer_id >= PIPELINE_FA_N_TC_MAX) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected policer id is less than %d.\n",
+						tokens[3], PIPELINE_FA_N_TC_MAX);
+					return;
+				}
+				if (strcmp(tokens[4], "g")) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is word \"g\".\n",
+						tokens[4]);
+					return;
+				}
+				if (string_to_policer_action(tokens[5],
+					&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is policer green action.\n",
+						tokens[5]);
+					return;
+				}
+				if (strcmp(tokens[6], "y")) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is word \"y\".\n",
+						tokens[6]);
+					return;
+				}
+				if (string_to_policer_action(tokens[7],
+					&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is policer yellow action.\n",
+						tokens[7]);
+					return;
+				}
+				if (strcmp(tokens[8], "r")) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is word \"r\".\n",
+						tokens[8]);
+					return;
+				}
+				if (string_to_policer_action(tokens[9],
+					&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is policer red action.\n",
+						tokens[9]);
+					return;
+				}
 
-cmdline_parse_token_num_t cmd_fa_flow_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_flow_ls_result,
-	pipeline_id, UINT32);
+				status = app_pipeline_fa_flow_config(app,
+					params->pipeline_id,
+					flow_id,
+					0,
+					1 << policer_id,
+					0,
+					&flow_params);
+				if (status != 0)
+					printf("Command \"action flow policer\" failed.\n");
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	flow_string, "flow");
+				return;
+			}
+			/*
+			 * Flow output port configuration (single flow)
+			 *
+			 * p <pipeline ID> action flow <flow ID> port <port ID>
+			 */
+			else if (0 == strcmp(tokens[2], "port")) {
+				if (n_tokens != 4) {
+					printf("Incorrect number of parameters for action flow"
+						" output port configuration.\n");
+					return;
+				}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_actions_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	actions_string, "actions");
+				if (parser_read_uint32(&flow_params.port_id, tokens[3])) {
+					printf("Incorrect parameter: \"%s\"."
+						" Expected parameter is port id.\n",
+						tokens[3]);
+					return;
+				}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	ls_string, "ls");
+				status = app_pipeline_fa_flow_config(app,
+					params->pipeline_id,
+					flow_id,
+					0,
+					0,
+					1,
+					&flow_params);
+				if (status != 0)
+					printf("Command \"action flow port\" failed.\n");
 
-cmdline_parse_inst_t cmd_fa_flow_ls = {
-	.f = cmd_fa_flow_ls_parsed,
-	.data = NULL,
-	.help_str = "Flow actions list",
-	.tokens = {
-		(void *) &cmd_fa_flow_ls_p_string,
-		(void *) &cmd_fa_flow_ls_pipeline_id,
-		(void *) &cmd_fa_flow_ls_flow_string,
-		(void *) &cmd_fa_flow_ls_actions_string,
-		(void *) &cmd_fa_flow_ls_ls_string,
-		NULL,
-	},
-};
-
-/*
- * Flow DiffServ Code Point (DSCP) translation table list
- *
- * p <pipeline ID> dscp ls
- */
-
-struct cmd_fa_dscp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_fa_dscp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fa_dscp_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
+				return;
+			}
+			/*
+			 * Flow policer stats read
+			 *
+			 * p <pipeline ID> action flow <flow ID> stats
+			 */
+			else if (0 == strcmp(tokens[2], "stats")) {
+				struct pipeline_fa_policer_stats stats;
+				uint32_t policer_id;
+
+				if (n_tokens != 3) {
+					printf("Incorrect number of parameters for action flow"
+						" policer stats read.\n");
+					return;
+				}
+
+				for (policer_id = 0;
+					policer_id < PIPELINE_FA_N_TC_MAX;
+					policer_id++) {
+					status = app_pipeline_fa_flow_policer_stats_read(app,
+						params->pipeline_id,
+						flow_id,
+						policer_id,
+						1,
+						&stats);
+					if (status != 0) {
+						printf("Command \"action flow stats\" for policer %"
+							PRIu32 " failed.\n", policer_id);
+						return;
+					}
+
+					/* Display stats */
+					printf("\tPolicer: %" PRIu32
+						"\tPkts G: %" PRIu64
+						"\tPkts Y: %" PRIu64
+						"\tPkts R: %" PRIu64
+						"\tPkts D: %" PRIu64 "\n",
+						policer_id,
+						stats.n_pkts[e_RTE_METER_GREEN],
+						stats.n_pkts[e_RTE_METER_YELLOW],
+						stats.n_pkts[e_RTE_METER_RED],
+						stats.n_pkts_drop);
+				}
+
+				return;
+			}
+			else {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is word \"meter\" or \"policer\" or"
+					" \"port\" or \"stats\".\n",
+					tokens[2]);
+				return;
+			}
+		}
+		/*
+		 * Flow meter, policer and output port configuration (multiple flows)
+		 *
+		 * p <pipeline ID> action flow bulk <file>
+		 */
+		else if (0 == strcmp(tokens[1], "bulk")) {
+			struct app_pipeline_add_bulk_params bulk_params;
+
+			if (n_tokens != 3) {
+				printf(
+					"Incorrect number of parameters for action flow bulk.\n");
+				return;
+			}
+
+			bulk_params.keys = NULL;
+			bulk_params.flow_ids = NULL;
+
+			status = app_pipeline_fa_add_bulk_parse_file(tokens[2],
+				&bulk_params);
+			if (status != 0) {
+				printf("Command \"action flow bulk\" failed.\n");
+				rte_free(bulk_params.keys);
+				rte_free(bulk_params.flow_ids);
+				return;
+			}
+
+			status = app_pipeline_fa_flow_config_bulk(app,
+				params->pipeline_id,
+				bulk_params.flow_ids,
+				bulk_params.n_keys,
+				0x0F,
+				0x0F,
+				1,
+				bulk_params.keys);
+			if (status != 0)
+				printf("Command \"action flow bulk\" failed.\n");
+
+			rte_free(bulk_params.keys);
+			rte_free(bulk_params.flow_ids);
+			return;
+		}
+		/*
+		 * Flow list
+		 *
+		 * p <pipeline ID> action flow ls
+		 */
+		else if (0 == strcmp(tokens[1], "ls")) {
+			if (n_tokens != 2) {
+				printf("Incorrect number of parameters for action flow ls.\n");
+				return;
+			}
+
+			status = app_pipeline_fa_flow_ls(app, params->pipeline_id);
+			if (status != 0)
+				printf("Command \"action flow ls\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is flow id or word \"bulk\" or"
+				" word \"ls\".\n",
+				tokens[1]);
+			return;
+		}
+	}
+
+	/* "action dscp" or "action dscp ls" */
+	if ((n_tokens > 0) && (0 == strcmp(tokens[0], "dscp"))) {
+		uint32_t dscp_id;
+
+		if (n_tokens < 2) {
+			printf("Not enough parameters for \"action dscp\" or"
+					" \"action dscp ls\".\n");
+			return;
+		}
+
+		/*
+		 * Flow DiffServ Code Point (DSCP) translation table configuration
+		 *
+		 * p <pipeline ID> action dscp <DSCP ID> class <traffic class ID>
+		 * color <color>
+		 *
+		 * <color> = G (green) | Y (yellow) | R (red)
+		 */
+		if (0 == parser_read_uint32(&dscp_id, tokens[1])) {
+			enum rte_meter_color color;
+			uint32_t traffic_class_id;
+
+			if (n_tokens != 6) {
+				printf("Incorrect number of parameters for action dscp.\n");
+				return;
+			}
+
+			if (strcmp(tokens[2], "class")) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is word \"class\".\n",
+					tokens[2]);
+				return;
+			}
+			if (parser_read_uint32(&traffic_class_id, tokens[3])) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is traffic class id.\n",
+					tokens[3]);
+				return;
+			}
+			if (strcmp(tokens[4], "color")) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is word \"color\".\n",
+					tokens[4]);
+				return;
+			}
+			if (string_to_color(tokens[5], &color)) {
+				printf("Incorrect parameter: \"%s\"."
+					" Expected parameter is color.\n",
+					tokens[5]);
+				return;
+			}
+
+			status = app_pipeline_fa_dscp_config(app,
+				params->pipeline_id,
+				dscp_id,
+				traffic_class_id,
+				color);
+			if (status != 0)
+				printf("Command \"action dscp\" failed.\n");
+
+			return;
+		}
+		/*
+		 * Flow DiffServ Code Point (DSCP) translation table list
+		 *
+		 * p <pipeline ID> action dscp ls
+		 */
+		else if (0 == strcmp(tokens[1], "ls")) {
+			if (n_tokens != 2) {
+				printf("Incorrect number of parameters for action dscp ls.\n");
+				return;
+			}
+
+			status = app_pipeline_fa_dscp_ls(app, params->pipeline_id);
+			if (status != 0)
+				printf("Command \"action dscp ls\" failed.\n");
+
+			return;
+		}
+		else {
+			printf("Incorrect parameter: \"%s\"."
+				" Expected parameter is dscp id or word \"ls\".\n",
+				tokens[1]);
+			return;
+		}
+	}
+
+	printf("!Command \"action\" failed."
+		" Expected parameter is \"flow\" or \"dscp\".\n");
+	return;
 }
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	p_string, "p");
+static cmdline_parse_token_string_t cmd_action_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fa_dscp_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	pipeline_id, UINT32);
+static cmdline_parse_token_num_t cmd_action_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	dscp_string, "dscp");
+static cmdline_parse_token_string_t cmd_action_action_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_action_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fa_dscp_ls = {
-	.f = cmd_fa_dscp_ls_parsed,
+cmdline_parse_inst_t cmd_action = {
+	.f = cmd_action_parsed,
 	.data = NULL,
-	.help_str = "Flow DSCP translaton table list",
+	.help_str =
+		"\n Flow meter configuration (single flow):"
+		"\n p <pipeline ID> action flow <flow ID> meter <meter ID> trtcm <cir>"
+		" <pir> <cbs> <pbs>"
+		"\n Flow policer configuration (single flow):"
+		"\n p <pipeline ID> action flow <flow ID> policer <policer ID> g"
+		" <action> y <action> r <action>"
+		"\n Flow output port configuration (single flow):"
+		"\n p <pipeline ID> action flow <flow ID> port <port ID>"
+		"\n Flow meter, policer and output port configuration (multiple flows):"
+		"\n p <pipeline ID> action flow bulk <file>"
+		"\n Flow policer stats read:"
+		"\n p <pipeline ID> action flow <flow ID> stats"
+		"\n Flow actions list:"
+		"\n p <pipeline ID> action flow ls"
+		"\n Flow DSCP translation table configuration:"
+		"\n p <pipeline ID> action dscp <dscp ID> class <class ID> color"
+		" <color>"
+		"\n Flow DSCP translaton table list:"
+		"\n p <pipeline ID> action dscp ls",
 	.tokens = {
-		(void *) &cmd_fa_dscp_ls_p_string,
-		(void *) &cmd_fa_dscp_ls_pipeline_id,
-		(void *) &cmd_fa_dscp_ls_dscp_string,
-		(void *) &cmd_fa_dscp_ls_string,
+		(void *) &cmd_action_p_string,
+		(void *) &cmd_action_pipeline_id,
+		(void *) &cmd_action_action_string,
+		(void *) &cmd_action_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config,
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_stats,
-	(cmdline_parse_inst_t *) &cmd_fa_flow_ls,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_ls,
+	(cmdline_parse_inst_t *) &cmd_action,
 	NULL,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements
  2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
                   ` (5 preceding siblings ...)
  2016-05-06 15:57 ` [PATCH 6/6] examples/ip_pipeline: modifies flow action " Michal Jastrzebski
@ 2016-05-20 14:35 ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
                     ` (8 more replies)
  6 siblings, 9 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Using the latest librte_cmdline improvements, the CLI implementation of the
ip_pipeline application is streamlined and improved, which results in
eliminating thousands of lines of code from the application, thus leading to
code that is easier to maintain and extend.

v2 changes:
- added functions for parsing hex values
- added standard error messages for CLI and file bulk
- for all CLI commands: separate code paths for each flavor of each command
(e.g. route add, route add default, route ls, route del, route del default,
etc do not share any line of code)
- for bulk commands: simplified error checking
- added additional config files

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Piotr Azarewicz (7):
  examples/ip_pipeline: add helper functions for parsing string
  examples/ip_pipeline: modifies common pipeline CLI
  examples/ip_pipeline: modifies firewall pipeline CLI
  examples/ip_pipeline: modifies flow classifications pipeline CLI
  examples/ip_pipeline: modifies flow action pipeline CLI
  examples/ip_pipeline: modifies routing pipeline CLI
  examples/ip_pipeline: update edge router usecase

 examples/ip_pipeline/Makefile                      |    1 +
 examples/ip_pipeline/config/action.cfg             |   68 +
 examples/ip_pipeline/config/action.sh              |  119 ++
 examples/ip_pipeline/config/action.txt             |    8 +
 .../ip_pipeline/config/edge_router_downstream.cfg  |   30 +-
 .../ip_pipeline/config/edge_router_downstream.sh   |    7 +-
 .../ip_pipeline/config/edge_router_upstream.cfg    |   36 +-
 .../ip_pipeline/config/edge_router_upstream.sh     |   37 +-
 examples/ip_pipeline/config/firewall.cfg           |   68 +
 examples/ip_pipeline/config/firewall.sh            |   13 +
 examples/ip_pipeline/config/firewall.txt           |    9 +
 examples/ip_pipeline/config/flow.cfg               |   72 +
 examples/ip_pipeline/config/flow.sh                |   25 +
 examples/ip_pipeline/config/flow.txt               |   17 +
 examples/ip_pipeline/config/l2fwd.cfg              |    5 +-
 examples/ip_pipeline/config/l3fwd.cfg              |    9 +-
 examples/ip_pipeline/config/l3fwd.sh               |   32 +-
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 +
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 +
 examples/ip_pipeline/config_parse.c                |  257 +--
 examples/ip_pipeline/parser.c                      |  745 +++++++
 examples/ip_pipeline/parser.h                      |   54 +-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  452 ++---
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |    9 +
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1461 +++++---------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   12 +
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1505 +++++---------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   11 +
 .../pipeline/pipeline_flow_classification.c        | 2082 +++++++++-----------
 .../pipeline/pipeline_flow_classification.h        |   28 +
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1636 ++++-----------
 examples/ip_pipeline/thread_fe.c                   |   36 +-
 32 files changed, 4009 insertions(+), 4948 deletions(-)
 create mode 100644 examples/ip_pipeline/config/action.cfg
 create mode 100644 examples/ip_pipeline/config/action.sh
 create mode 100644 examples/ip_pipeline/config/action.txt
 create mode 100644 examples/ip_pipeline/config/firewall.cfg
 create mode 100644 examples/ip_pipeline/config/firewall.sh
 create mode 100644 examples/ip_pipeline/config/firewall.txt
 create mode 100644 examples/ip_pipeline/config/flow.cfg
 create mode 100644 examples/ip_pipeline/config/flow.sh
 create mode 100644 examples/ip_pipeline/config/flow.txt
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 create mode 100644 examples/ip_pipeline/parser.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 1/7] examples/ip_pipeline: add helper functions for parsing string
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Add a couple of additional functions that will allow to parse many types
of input parameters, i.e.: bool, 16, 32, 64 bits, hex, etc.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/Makefile       |    1 +
 examples/ip_pipeline/config_parse.c |  257 +-----------
 examples/ip_pipeline/parser.c       |  745 +++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/parser.h       |   54 ++-
 4 files changed, 791 insertions(+), 266 deletions(-)
 create mode 100644 examples/ip_pipeline/parser.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 10fe1ba..5827117 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -50,6 +50,7 @@ INC += $(wildcard *.h) $(wildcard pipeline/*.h)
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += parser.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index e5efd03..ff917f3 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -30,6 +30,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -229,13 +230,6 @@ app_print_usage(char *prgname)
 	rte_exit(0, app_usage, prgname, app_params_default.config_file);
 }
 
-#define skip_white_spaces(pos)			\
-({						\
-	__typeof__(pos) _p = (pos);		\
-	for ( ; isspace(*_p); _p++);		\
-	_p;					\
-})
-
 #define PARSER_PARAM_ADD_CHECK(result, params_array, section_name)	\
 do {									\
 	APP_CHECK((result != -EINVAL),					\
@@ -248,44 +242,6 @@ do {									\
 		"Parse error in section \"%s\"", section_name);		\
 } while (0)
 
-int
-parser_read_arg_bool(const char *p)
-{
-	p = skip_white_spaces(p);
-	int result = -EINVAL;
-
-	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
-		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
-		p += 3;
-		result = 1;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'n')) ||
-		((p[0] == 'O') && (p[1] == 'N'))) {
-		p += 2;
-		result = 1;
-	}
-
-	if (((p[0] == 'n') && (p[1] == 'o')) ||
-		((p[0] == 'N') && (p[1] == 'O'))) {
-		p += 2;
-		result = 0;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
-		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
-		p += 3;
-		result = 0;
-	}
-
-	p = skip_white_spaces(p);
-
-	if (p[0] != '\0')
-		return -EINVAL;
-
-	return result;
-}
-
 #define PARSE_ERROR(exp, section, entry)				\
 APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"\n", section, entry)
 
@@ -318,217 +274,6 @@ APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"\n",\
 APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"\n",\
 	section, entry)
 
-int
-parser_read_uint64(uint64_t *value, const char *p)
-{
-	char *next;
-	uint64_t val;
-
-	p = skip_white_spaces(p);
-	if (!isdigit(*p))
-		return -EINVAL;
-
-	val = strtoul(p, &next, 10);
-	if (p == next)
-		return -EINVAL;
-
-	p = next;
-	switch (*p) {
-	case 'T':
-		val *= 1024ULL;
-		/* fall through */
-	case 'G':
-		val *= 1024ULL;
-		/* fall through */
-	case 'M':
-		val *= 1024ULL;
-		/* fall through */
-	case 'k':
-	case 'K':
-		val *= 1024ULL;
-		p++;
-		break;
-	}
-
-	p = skip_white_spaces(p);
-	if (*p != '\0')
-		return -EINVAL;
-
-	*value = val;
-	return 0;
-}
-
-int
-parser_read_uint32(uint32_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT32_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
-{
-	size_t num_len;
-	char num[8];
-
-	uint32_t s = 0, c = 0, h = 0, val;
-	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
-	const char *next = skip_white_spaces(entry);
-	char type;
-
-	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
-	while (*next != '\0') {
-		/* If everything parsed nothing should left */
-		if (s_parsed && c_parsed && h_parsed)
-			return -EINVAL;
-
-		type = *next;
-		switch (type) {
-		case 's':
-		case 'S':
-			if (s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-			s_parsed = 1;
-			next++;
-			break;
-		case 'c':
-		case 'C':
-			if (c_parsed || h_parsed)
-				return -EINVAL;
-			c_parsed = 1;
-			next++;
-			break;
-		case 'h':
-		case 'H':
-			if (h_parsed)
-				return -EINVAL;
-			h_parsed = 1;
-			next++;
-			break;
-		default:
-			/* If it start from digit it must be only core id. */
-			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-
-			type = 'C';
-		}
-
-		for (num_len = 0; *next != '\0'; next++, num_len++) {
-			if (num_len == RTE_DIM(num))
-				return -EINVAL;
-
-			if (!isdigit(*next))
-				break;
-
-			num[num_len] = *next;
-		}
-
-		if (num_len == 0 && type != 'h' && type != 'H')
-			return -EINVAL;
-
-		if (num_len != 0 && (type == 'h' || type == 'H'))
-			return -EINVAL;
-
-		num[num_len] = '\0';
-		val = strtol(num, NULL, 10);
-
-		h = 0;
-		switch (type) {
-		case 's':
-		case 'S':
-			s = val;
-			break;
-		case 'c':
-		case 'C':
-			c = val;
-			break;
-		case 'h':
-		case 'H':
-			h = 1;
-			break;
-		}
-	}
-
-	*socket = s;
-	*core = c;
-	*ht = h;
-	return 0;
-}
-
-static uint32_t
-get_hex_val(char c)
-{
-	switch (c) {
-	case '0': case '1': case '2': case '3': case '4': case '5':
-	case '6': case '7': case '8': case '9':
-		return c - '0';
-	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-		return c - 'A' + 10;
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-		return c - 'a' + 10;
-	default:
-		return 0;
-	}
-}
-
-int
-parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
-{
-	char *c;
-	uint32_t len, i;
-
-	/* Check input parameters */
-	if ((src == NULL) ||
-		(dst == NULL) ||
-		(size == NULL) ||
-		(*size == 0))
-		return -1;
-
-	len = strlen(src);
-	if (((len & 3) != 0) ||
-		(len > (*size) * 2))
-		return -1;
-	*size = len / 2;
-
-	for (c = src; *c != 0; c++) {
-		if ((((*c) >= '0') && ((*c) <= '9')) ||
-			(((*c) >= 'A') && ((*c) <= 'F')) ||
-			(((*c) >= 'a') && ((*c) <= 'f')))
-			continue;
-
-		return -1;
-	}
-
-	/* Convert chars to bytes */
-	for (i = 0; i < *size; i++)
-		dst[i] = get_hex_val(src[2 * i]) * 16 +
-			get_hex_val(src[2 * i + 1]);
-
-	return 0;
-}
-
-static size_t
-skip_digits(const char *src)
-{
-	size_t i;
-
-	for (i = 0; isdigit(src[i]); i++);
-
-	return i;
-}
-
 static int
 validate_name(const char *name, const char *prefix, int num)
 {
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
new file mode 100644
index 0000000..689e206
--- /dev/null
+++ b/examples/ip_pipeline/parser.c
@@ -0,0 +1,745 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For my_ether_aton() function:
+ *
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For inet_pton4() and inet_pton6() functions:
+ *
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+#include "parser.h"
+
+static uint32_t
+get_hex_val(char c)
+{
+	switch (c) {
+	case '0': case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+		return c - '0';
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+		return c - 'A' + 10;
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+		return c - 'a' + 10;
+	default:
+		return 0;
+	}
+}
+
+int
+parser_read_arg_bool(const char *p)
+{
+	p = skip_white_spaces(p);
+	int result = -EINVAL;
+
+	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+		p += 3;
+		result = 1;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'n')) ||
+		((p[0] == 'O') && (p[1] == 'N'))) {
+		p += 2;
+		result = 1;
+	}
+
+	if (((p[0] == 'n') && (p[1] == 'o')) ||
+		((p[0] == 'N') && (p[1] == 'O'))) {
+		p += 2;
+		result = 0;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+		p += 3;
+		result = 0;
+	}
+
+	p = skip_white_spaces(p);
+
+	if (p[0] != '\0')
+		return -EINVAL;
+
+	return result;
+}
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+
+	val = strtoul(p, &next, 16);
+	if (p == next)
+		return -EINVAL;
+
+	p = skip_white_spaces(next);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32_hex(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16_hex(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
+{
+	uint32_t i;
+
+	if ((string == NULL) ||
+		(tokens == NULL) ||
+		(*n_tokens < 1))
+		return -EINVAL;
+
+	for (i = 0; i < *n_tokens; i++) {
+		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
+		if (tokens[i] == NULL)
+			break;
+	}
+
+	if ((i == *n_tokens) &&
+		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
+		return -E2BIG;
+
+	*n_tokens = i;
+	return 0;
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+	char *c;
+	uint32_t len, i;
+
+	/* Check input parameters */
+	if ((src == NULL) ||
+		(dst == NULL) ||
+		(size == NULL) ||
+		(*size == 0))
+		return -1;
+
+	len = strlen(src);
+	if (((len & 3) != 0) ||
+		(len > (*size) * 2))
+		return -1;
+	*size = len / 2;
+
+	for (c = src; *c != 0; c++) {
+		if ((((*c) >= '0') && ((*c) <= '9')) ||
+			(((*c) >= 'A') && ((*c) <= 'F')) ||
+			(((*c) >= 'a') && ((*c) <= 'f')))
+			continue;
+
+		return -1;
+	}
+
+	/* Convert chars to bytes */
+	for (i = 0; i < *size; i++)
+		dst[i] = get_hex_val(src[2 * i]) * 16 +
+			get_hex_val(src[2 * i + 1]);
+
+	return 0;
+}
+
+int
+parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels)
+{
+	uint32_t n_max_labels = *n_labels, count = 0;
+
+	/* Check for void list of labels */
+	if (strcmp(string, "<void>") == 0) {
+		*n_labels = 0;
+		return 0;
+	}
+
+	/* At least one label should be present */
+	for ( ; (*string != '\0'); ) {
+		char *next;
+		int value;
+
+		if (count >= n_max_labels)
+			return -1;
+
+		if (count > 0) {
+			if (string[0] != ':')
+				return -1;
+
+			string++;
+		}
+
+		value = strtol(string, &next, 10);
+		if (next == string)
+			return -1;
+		string = next;
+
+		labels[count++] = (uint32_t) value;
+	}
+
+	*n_labels = count;
+	return 0;
+}
+
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+	static const char digits[] = "0123456789";
+	int saw_digit, octets, ch;
+	unsigned char tmp[INADDRSZ], *tp;
+
+	saw_digit = 0;
+	octets = 0;
+	*(tp = tmp) = 0;
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		pch = strchr(digits, ch);
+		if (pch != NULL) {
+			unsigned int new = *tp * 10 + (pch - digits);
+
+			if (new > 255)
+				return 0;
+			if (!saw_digit) {
+				if (++octets > 4)
+					return 0;
+				saw_digit = 1;
+			}
+			*tp = (unsigned char)new;
+		} else if (ch == '.' && saw_digit) {
+			if (octets == 4)
+				return 0;
+			*++tp = 0;
+			saw_digit = 0;
+		} else
+			return 0;
+	}
+	if (octets < 4)
+		return 0;
+
+	memcpy(dst, tmp, INADDRSZ);
+	return 1;
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+	static const char xdigits_l[] = "0123456789abcdef",
+		xdigits_u[] = "0123456789ABCDEF";
+	unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
+	const char *xdigits = 0, *curtok = 0;
+	int ch = 0, saw_xdigit = 0, count_xdigit = 0;
+	unsigned int val = 0;
+	unsigned dbloct_count = 0;
+
+	memset((tp = tmp), '\0', IN6ADDRSZ);
+	endp = tp + IN6ADDRSZ;
+	colonp = NULL;
+	/* Leading :: requires some special handling. */
+	if (*src == ':')
+		if (*++src != ':')
+			return 0;
+	curtok = src;
+	saw_xdigit = count_xdigit = 0;
+	val = 0;
+
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		pch = strchr((xdigits = xdigits_l), ch);
+		if (pch == NULL)
+			pch = strchr((xdigits = xdigits_u), ch);
+		if (pch != NULL) {
+			if (count_xdigit >= 4)
+				return 0;
+			val <<= 4;
+			val |= (pch - xdigits);
+			if (val > 0xffff)
+				return 0;
+			saw_xdigit = 1;
+			count_xdigit++;
+			continue;
+		}
+		if (ch == ':') {
+			curtok = src;
+			if (!saw_xdigit) {
+				if (colonp)
+					return 0;
+				colonp = tp;
+				continue;
+			} else if (*src == '\0') {
+				return 0;
+			}
+			if (tp + sizeof(int16_t) > endp)
+				return 0;
+			*tp++ = (unsigned char) ((val >> 8) & 0xff);
+			*tp++ = (unsigned char) (val & 0xff);
+			saw_xdigit = 0;
+			count_xdigit = 0;
+			val = 0;
+			dbloct_count++;
+			continue;
+		}
+		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+		    inet_pton4(curtok, tp) > 0) {
+			tp += INADDRSZ;
+			saw_xdigit = 0;
+			dbloct_count += 2;
+			break;  /* '\0' was seen by inet_pton4(). */
+		}
+		return 0;
+	}
+	if (saw_xdigit) {
+		if (tp + sizeof(int16_t) > endp)
+			return 0;
+		*tp++ = (unsigned char) ((val >> 8) & 0xff);
+		*tp++ = (unsigned char) (val & 0xff);
+		dbloct_count++;
+	}
+	if (colonp != NULL) {
+		/* if we already have 8 double octets, having a colon means error */
+		if (dbloct_count == 8)
+			return 0;
+
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		const int n = tp - colonp;
+		int i;
+
+		for (i = 1; i <= n; i++) {
+			endp[-i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+	if (tp != endp)
+		return 0;
+	memcpy(dst, tmp, IN6ADDRSZ);
+	return 1;
+}
+
+static struct ether_addr *
+my_ether_aton(const char *a)
+{
+	int i;
+	char *end;
+	unsigned long o[ETHER_ADDR_LEN];
+	static struct ether_addr ether_addr;
+
+	i = 0;
+	do {
+		errno = 0;
+		o[i] = strtoul(a, &end, 16);
+		if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
+			return NULL;
+		a = end + 1;
+	} while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0);
+
+	/* Junk at the end of line */
+	if (end[0] != 0)
+		return NULL;
+
+	/* Support the format XX:XX:XX:XX:XX:XX */
+	if (i == ETHER_ADDR_LEN) {
+		while (i-- != 0) {
+			if (o[i] > UINT8_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i] = (uint8_t)o[i];
+		}
+	/* Support the format XXXX:XXXX:XXXX */
+	} else if (i == ETHER_ADDR_LEN / 2) {
+		while (i-- != 0) {
+			if (o[i] > UINT16_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
+			ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
+		}
+	/* unknown format */
+	} else
+		return NULL;
+
+	return (struct ether_addr *)&ether_addr;
+}
+
+int
+parse_ipv4_addr(const char *token, struct in_addr *ipv4)
+{
+	if (strlen(token) >= INET_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton4(token, (unsigned char *)ipv4) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_ipv6_addr(const char *token, struct in6_addr *ipv6)
+{
+	if (strlen(token) >= INET6_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton6(token, (unsigned char *)ipv6) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_mac_addr(const char *token, struct ether_addr *addr)
+{
+	struct ether_addr *tmp;
+
+	tmp = my_ether_aton(token);
+	if (tmp == NULL)
+		return -1;
+
+	memcpy(addr, tmp, sizeof(struct ether_addr));
+	return 0;
+}
+
+int
+parse_pipeline_core(uint32_t *socket,
+	uint32_t *core,
+	uint32_t *ht,
+	const char *entry)
+{
+	size_t num_len;
+	char num[8];
+
+	uint32_t s = 0, c = 0, h = 0, val;
+	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+	const char *next = skip_white_spaces(entry);
+	char type;
+
+	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+	while (*next != '\0') {
+		/* If everything parsed nothing should left */
+		if (s_parsed && c_parsed && h_parsed)
+			return -EINVAL;
+
+		type = *next;
+		switch (type) {
+		case 's':
+		case 'S':
+			if (s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+			s_parsed = 1;
+			next++;
+			break;
+		case 'c':
+		case 'C':
+			if (c_parsed || h_parsed)
+				return -EINVAL;
+			c_parsed = 1;
+			next++;
+			break;
+		case 'h':
+		case 'H':
+			if (h_parsed)
+				return -EINVAL;
+			h_parsed = 1;
+			next++;
+			break;
+		default:
+			/* If it start from digit it must be only core id. */
+			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+
+			type = 'C';
+		}
+
+		for (num_len = 0; *next != '\0'; next++, num_len++) {
+			if (num_len == RTE_DIM(num))
+				return -EINVAL;
+
+			if (!isdigit(*next))
+				break;
+
+			num[num_len] = *next;
+		}
+
+		if (num_len == 0 && type != 'h' && type != 'H')
+			return -EINVAL;
+
+		if (num_len != 0 && (type == 'h' || type == 'H'))
+			return -EINVAL;
+
+		num[num_len] = '\0';
+		val = strtol(num, NULL, 10);
+
+		h = 0;
+		switch (type) {
+		case 's':
+		case 'S':
+			s = val;
+			break;
+		case 'c':
+		case 'C':
+			c = val;
+			break;
+		case 'h':
+		case 'H':
+			h = 1;
+			break;
+		}
+	}
+
+	*socket = s;
+	*core = c;
+	*ht = h;
+	return 0;
+}
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 58b59da..9bd36af 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -34,17 +34,51 @@
 #ifndef __INCLUDE_PARSER_H__
 #define __INCLUDE_PARSER_H__
 
-int
-parser_read_arg_bool(const char *p);
+#include <stdint.h>
 
-int
-parser_read_uint64(uint64_t *value, const char *p);
+#include <rte_ip.h>
+#include <rte_ether.h>
 
-int
-parser_read_uint32(uint32_t *value, const char *p);
+#define PARSE_DELIMITER				" \f\n\r\t\v"
 
-int
-parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
 
-#endif
+static inline size_t
+skip_digits(const char *src)
+{
+	size_t i;
+
+	for (i = 0; isdigit(src[i]); i++)
+		;
+
+	return i;
+}
+
+int parser_read_arg_bool(const char *p);
+
+int parser_read_uint64(uint64_t *value, const char *p);
+int parser_read_uint32(uint32_t *value, const char *p);
+int parser_read_uint16(uint16_t *value, const char *p);
+int parser_read_uint8(uint8_t *value, const char *p);
 
+int parser_read_uint64_hex(uint64_t *value, const char *p);
+int parser_read_uint32_hex(uint32_t *value, const char *p);
+int parser_read_uint16_hex(uint16_t *value, const char *p);
+int parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
+int parse_ipv4_addr(const char *token, struct in_addr *ipv4);
+int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
+int parse_mac_addr(const char *token, struct ether_addr *addr);
+int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
+
+int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 2/7] examples/ip_pipeline: modifies common pipeline CLI
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz, Tomasz Kulasek, Michal Kobylinski

All link commands are merged into one command:
cmd_link_parsed.
Improve run command to allow run periodically.
Adding static keyword to a lot of token declarations.

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Michal Kobylinski <michalx.kobylinski@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  452 ++++++++++----------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |    9 +
 examples/ip_pipeline/thread_fe.c                   |   36 +-
 3 files changed, 244 insertions(+), 253 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index a691d42..dc37a5f 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,10 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
 #include <cmdline.h>
 
 #include "pipeline_common_fe.h"
+#include "parser.h"
 
 int
 app_pipeline_ping(struct app_params *app,
@@ -464,16 +462,16 @@ cmd_ping_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_ping_p_string =
+static cmdline_parse_token_string_t cmd_ping_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_ping_pipeline_id =
+static cmdline_parse_token_num_t cmd_ping_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_ping_ping_string =
+static cmdline_parse_token_string_t cmd_ping_ping_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
 
-cmdline_parse_inst_t cmd_ping = {
+static cmdline_parse_inst_t cmd_ping = {
 	.f = cmd_ping_parsed,
 	.data = NULL,
 	.help_str = "Pipeline ping",
@@ -498,6 +496,7 @@ struct cmd_stats_port_in_result {
 	uint32_t port_in_id;
 
 };
+
 static void
 cmd_stats_port_in_parsed(
 	void *parsed_result,
@@ -531,23 +530,23 @@ cmd_stats_port_in_parsed(
 		stats.stats.n_pkts_drop);
 }
 
-cmdline_parse_token_string_t cmd_stats_port_in_p_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_port_in_port_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_stats_port_in_in_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, in_string,
 		"in");
 
@@ -555,7 +554,7 @@ cmdline_parse_token_string_t cmd_stats_port_in_in_string =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, port_in_id,
 		UINT32);
 
-cmdline_parse_inst_t cmd_stats_port_in = {
+static cmdline_parse_inst_t cmd_stats_port_in = {
 	.f = cmd_stats_port_in_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port stats",
@@ -617,31 +616,31 @@ cmd_stats_port_out_parsed(
 		stats.stats.n_pkts_drop);
 }
 
-cmdline_parse_token_string_t cmd_stats_port_out_p_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
 	"p");
 
-cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_port_out_port_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_stats_port_out_out_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
 		"out");
 
-cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
+static cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, port_out_id,
 		UINT32);
 
-cmdline_parse_inst_t cmd_stats_port_out = {
+static cmdline_parse_inst_t cmd_stats_port_out = {
 	.f = cmd_stats_port_out_parsed,
 	.data = NULL,
 	.help_str = "Pipeline output port stats",
@@ -707,26 +706,26 @@ cmd_stats_table_parsed(
 		stats.n_pkts_dropped_lkp_miss);
 }
 
-cmdline_parse_token_string_t cmd_stats_table_p_string =
+static cmdline_parse_token_string_t cmd_stats_table_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_table_stats_string =
+static cmdline_parse_token_string_t cmd_stats_table_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_table_table_string =
+static cmdline_parse_token_string_t cmd_stats_table_table_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
 		"table");
 
-cmdline_parse_token_num_t cmd_stats_table_table_id =
+static cmdline_parse_token_num_t cmd_stats_table_table_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
 
-cmdline_parse_inst_t cmd_stats_table = {
+static cmdline_parse_inst_t cmd_stats_table = {
 	.f = cmd_stats_table_parsed,
 	.data = NULL,
 	.help_str = "Pipeline table stats",
@@ -771,31 +770,31 @@ cmd_port_in_enable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_port_in_enable_p_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
+static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_enable_port_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
 	"port");
 
-cmdline_parse_token_string_t cmd_port_in_enable_in_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
 		"in");
 
-cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
+static cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, port_in_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
 		enable_string, "enable");
 
-cmdline_parse_inst_t cmd_port_in_enable = {
+static cmdline_parse_inst_t cmd_port_in_enable = {
 	.f = cmd_port_in_enable_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port enable",
@@ -841,31 +840,31 @@ cmd_port_in_disable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_port_in_disable_p_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
+static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_disable_port_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_port_in_disable_in_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
 		"in");
 
-cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
+static cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, port_in_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
 		disable_string, "disable");
 
-cmdline_parse_inst_t cmd_port_in_disable = {
+static cmdline_parse_inst_t cmd_port_in_disable = {
 	.f = cmd_port_in_disable_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port disable",
@@ -963,219 +962,144 @@ print_link_info(struct app_link_params *p)
 	printf("\n");
 }
 
-struct cmd_link_config_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t config_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-};
-
-static void
-cmd_link_config_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_config_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	uint32_t link_id = params->link_id;
-	uint32_t ip  = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	uint32_t depth = params->depth;
-
-	status = app_link_config(app, link_id, ip, depth);
-	if (status)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
-
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
-	}
-}
-
-cmdline_parse_token_string_t cmd_link_config_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, link_string,
-		"link");
-
-cmdline_parse_token_num_t cmd_link_config_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, link_id, UINT32);
-
-cmdline_parse_token_string_t cmd_link_config_config_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, config_string,
-		"config");
-
-cmdline_parse_token_ipaddr_t cmd_link_config_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_link_config_result, ip);
-
-cmdline_parse_token_num_t cmd_link_config_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, depth, UINT32);
-
-cmdline_parse_inst_t cmd_link_config = {
-	.f = cmd_link_config_parsed,
-	.data = NULL,
-	.help_str = "Link configuration",
-	.tokens = {
-		(void *)&cmd_link_config_link_string,
-		(void *)&cmd_link_config_link_id,
-		(void *)&cmd_link_config_config_string,
-		(void *)&cmd_link_config_ip,
-		(void *)&cmd_link_config_depth,
-		NULL,
-	},
-};
-
 /*
- * link up
+ * link
+ *
+ * link config:
+ *    link <linkid> config <ipaddr> <depth>
+ *
+ * link up:
+ *    link <linkid> up
+ *
+ * link down:
+ *    link <linkid> down
+ *
+ * link ls:
+ *    link ls
  */
 
-struct cmd_link_up_result {
+struct cmd_link_result {
 	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t up_string;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_link_up_parsed(
+cmd_link_parsed(
 	void *parsed_result,
 	__attribute__((unused)) struct cmdline *cl,
-	void *data)
+	 void *data)
 {
-	struct cmd_link_up_result *params = parsed_result;
+	struct cmd_link_result *params = parsed_result;
 	struct app_params *app = data;
+
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	status = app_link_up(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
+	uint32_t link_id;
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status != 0) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "link");
+		return;
 	}
-}
-
-cmdline_parse_token_string_t cmd_link_up_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, link_string,
-		"link");
 
-cmdline_parse_token_num_t cmd_link_up_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_up_result, link_id, UINT32);
+	/* link ls */
+	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
+		for (link_id = 0; link_id < app->n_links; link_id++) {
+			struct app_link_params *p;
 
-cmdline_parse_token_string_t cmd_link_up_up_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, up_string, "up");
+			APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+			print_link_info(p);
+		}
+		return;
+	} /* link ls */
 
-cmdline_parse_inst_t cmd_link_up = {
-	.f = cmd_link_up_parsed,
-	.data = NULL,
-	.help_str = "Link UP",
-	.tokens = {
-		(void *)&cmd_link_up_link_string,
-		(void *)&cmd_link_up_link_id,
-		(void *)&cmd_link_up_up_string,
-		NULL,
-	},
-};
+	if (n_tokens < 2) {
+		printf(CMD_MSG_MISMATCH_ARGS, "link");
+		return;
+	}
 
-/*
- * link down
- */
+	if (parser_read_uint32(&link_id, tokens[0])) {
+		printf(CMD_MSG_INVALID_ARG, "linkid");
+		return;
+	}
 
-struct cmd_link_down_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t down_string;
-};
+	/* link config */
+	if (strcmp(tokens[1], "config") == 0) {
+		struct in_addr ipaddr_ipv4;
+		uint32_t depth;
 
-static void
-cmd_link_down_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_link_down_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link config");
+			return;
+		}
 
-	status = app_link_down(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
+		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
-	}
-}
+		if (parser_read_uint32(&depth, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_link_down_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, link_string,
-		"link");
+		status = app_link_config(app,
+			link_id,
+			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
+			depth);
+		if (status)
+			printf(CMD_MSG_FAIL, "link config");
 
-cmdline_parse_token_num_t cmd_link_down_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_down_result, link_id, UINT32);
+		return;
+	} /* link config */
 
-cmdline_parse_token_string_t cmd_link_down_down_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, down_string,
-		"down");
+	/* link up */
+	if (strcmp(tokens[1], "up") == 0) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link up");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_link_down = {
-	.f = cmd_link_down_parsed,
-	.data = NULL,
-	.help_str = "Link DOWN",
-	.tokens = {
-		(void *) &cmd_link_down_link_string,
-		(void *) &cmd_link_down_link_id,
-		(void *) &cmd_link_down_down_string,
-		NULL,
-	},
-};
+		status = app_link_up(app, link_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "link up");
 
-/*
- * link ls
- */
+		return;
+	} /* link up */
 
-struct cmd_link_ls_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_fixed_string_t ls_string;
-};
+	/* link down */
+	if (strcmp(tokens[1], "down") == 0) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link down");
+			return;
+		}
 
-static void
-cmd_link_ls_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct app_params *app = data;
-	uint32_t link_id;
+		status = app_link_down(app, link_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "link down");
 
-	for (link_id = 0; link_id < app->n_links; link_id++) {
-		struct app_link_params *p;
+		return;
+	} /* link down */
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
-	}
+	printf(CMD_MSG_MISMATCH_ARGS, "link");
 }
 
-cmdline_parse_token_string_t cmd_link_ls_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, link_string,
-		"link");
+static cmdline_parse_token_string_t cmd_link_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
 
-cmdline_parse_token_string_t cmd_link_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, ls_string, "ls");
+static cmdline_parse_token_string_t cmd_link_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_link_ls = {
-	.f = cmd_link_ls_parsed,
+static cmdline_parse_inst_t cmd_link = {
+	.f = cmd_link_parsed,
 	.data = NULL,
-	.help_str = "Link list",
+	.help_str = "link config / up / down / ls",
 	.tokens = {
-		(void *)&cmd_link_ls_link_string,
-		(void *)&cmd_link_ls_ls_string,
+		(void *) &cmd_link_link_string,
+		(void *) &cmd_link_multi_string,
 		NULL,
 	},
 };
@@ -1212,6 +1136,11 @@ static cmdline_parse_inst_t cmd_quit = {
 
 /*
  * run
+ *
+ *    run <file>
+ *    run <file> [<count> [<interval>]]
+	 <count> default is 1
+ *       <interval> is measured in milliseconds, default is 1 second
  */
 
 static void
@@ -1233,9 +1162,9 @@ app_run_file(
 	close(fd);
 }
 
-struct cmd_run_file_result {
+struct cmd_run_result {
 	cmdline_fixed_string_t run_string;
-	char file_name[APP_FILE_NAME_SIZE];
+	cmdline_multi_string_t multi_string;
 };
 
 static void
@@ -1244,25 +1173,87 @@ cmd_run_parsed(
 	struct cmdline *cl,
 	__attribute__((unused)) void *data)
 {
-	struct cmd_run_file_result *params = parsed_result;
+	struct cmd_run_result *params = parsed_result;
+
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
+	char *file_name;
+	uint32_t count, interval, i;
+
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "run");
+		return;
+	}
+
+	switch (n_tokens) {
+	case 0:
+		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
+		return;
+
+	case 1:
+		file_name = tokens[0];
+		count = 1;
+		interval = 1000;
+		break;
+
+	case 2:
+		file_name = tokens[0];
 
-	app_run_file(cl->ctx, params->file_name);
+		if (parser_read_uint32(&count, tokens[1]) ||
+			(count == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "count");
+			return;
+		}
+
+		interval = 1000;
+		break;
+
+	case 3:
+		file_name = tokens[0];
+
+		if (parser_read_uint32(&count, tokens[1]) ||
+			(count == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "count");
+			return;
+		}
+
+		if (parser_read_uint32(&interval, tokens[2]) ||
+			(interval == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "interval");
+			return;
+		}
+		break;
+
+	default:
+		printf(CMD_MSG_MISMATCH_ARGS, "run");
+		return;
+	}
+
+	for (i = 0; i < count; i++) {
+		app_run_file(cl->ctx, file_name);
+		if (interval)
+			usleep(interval * 1000);
+	}
 }
 
-cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, run_string,
-		"run");
+static cmdline_parse_token_string_t cmd_run_run_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
 
-cmdline_parse_token_string_t cmd_run_file_name =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, file_name, NULL);
+static cmdline_parse_token_string_t cmd_run_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_run = {
+
+static cmdline_parse_inst_t cmd_run = {
 	.f = cmd_run_parsed,
 	.data = NULL,
 	.help_str = "Run CLI script file",
 	.tokens = {
 		(void *) &cmd_run_run_string,
-		(void *) &cmd_run_file_name,
+		(void *) &cmd_run_multi_string,
 		NULL,
 	},
 };
@@ -1270,12 +1261,7 @@ cmdline_parse_inst_t cmd_run = {
 static cmdline_parse_ctx_t pipeline_common_cmds[] = {
 	(cmdline_parse_inst_t *) &cmd_quit,
 	(cmdline_parse_inst_t *) &cmd_run,
-
-	(cmdline_parse_inst_t *) &cmd_link_config,
-	(cmdline_parse_inst_t *) &cmd_link_up,
-	(cmdline_parse_inst_t *) &cmd_link_down,
-	(cmdline_parse_inst_t *) &cmd_link_ls,
-
+	(cmdline_parse_inst_t *) &cmd_link,
 	(cmdline_parse_inst_t *) &cmd_ping,
 	(cmdline_parse_inst_t *) &cmd_stats_port_in,
 	(cmdline_parse_inst_t *) &cmd_stats_port_out,
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
index cfad963..f93ff74 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
@@ -231,4 +231,13 @@ app_link_down(struct app_params *app,
 int
 app_pipeline_common_cmd_push(struct app_params *app);
 
+#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
+#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
+#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
+#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
+#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
+#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
+#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
+#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
+
 #endif
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
index 4a435f7..d1b72b4 100644
--- a/examples/ip_pipeline/thread_fe.c
+++ b/examples/ip_pipeline/thread_fe.c
@@ -5,10 +5,6 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
 
 #include "thread.h"
 #include "thread_fe.h"
@@ -259,26 +255,26 @@ cmd_pipeline_enable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
 
-cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
 		NULL);
 
-cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
 		"pipeline");
 
-cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
+static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
 		"enable");
 
-cmdline_parse_inst_t cmd_pipeline_enable = {
+static cmdline_parse_inst_t cmd_pipeline_enable = {
 	.f = cmd_pipeline_enable_parsed,
 	.data = NULL,
 	.help_str = "Enable pipeline on specified core",
@@ -333,26 +329,26 @@ cmd_pipeline_disable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
 
-cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
 		NULL);
 
-cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
 		pipeline_string, "pipeline");
 
-cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
+static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
 		"disable");
 
-cmdline_parse_inst_t cmd_pipeline_disable = {
+static cmdline_parse_inst_t cmd_pipeline_disable = {
 	.f = cmd_pipeline_disable_parsed,
 	.data = NULL,
 	.help_str = "Disable pipeline on specified core",
@@ -405,19 +401,19 @@ cmd_thread_headroom_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_thread_headroom_t_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 	t_string, "t");
 
-cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 	t_id_string, NULL);
 
-cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 		headroom_string, "headroom");
 
-cmdline_parse_inst_t cmd_thread_headroom = {
+static cmdline_parse_inst_t cmd_thread_headroom = {
 	.f = cmd_thread_headroom_parsed,
 	.data = NULL,
 	.help_str = "Display thread headroom",
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 3/7] examples/ip_pipeline: modifies firewall pipeline CLI
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz, Daniel Mrzyglod

Each command are merged into one: cmd_firewall_parsed.
ADD command format is changed:
p <pipeline ID> firewall add priority <priority> ipv4 <sipaddr>
<sipdepth> <dipaddr> <dipdepth> <sport0> <sport1> <dport0> <dport1>
<proto> <protomask> port <port ID>

and bulk command was modified:
1. firewall add bulk
File line format:
priority <priority> ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
<sport0> <sport1> <dport0> <dport1> <proto> <protomask> port <port ID>
(protomask is a hex value)
File line example:
priority 0 ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF port 3

2. firewall del bulk
File line format:
ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth> <sport0> <sport1>
<dport0> <dport1> <proto> <protomask>
File line example:
ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/firewall.cfg          |   68 +
 examples/ip_pipeline/config/firewall.sh           |   13 +
 examples/ip_pipeline/config/firewall.txt          |    9 +
 examples/ip_pipeline/pipeline/pipeline_firewall.c | 1461 ++++++++-------------
 examples/ip_pipeline/pipeline/pipeline_firewall.h |   12 +
 5 files changed, 622 insertions(+), 941 deletions(-)
 create mode 100644 examples/ip_pipeline/config/firewall.cfg
 create mode 100644 examples/ip_pipeline/config/firewall.sh
 create mode 100644 examples/ip_pipeline/config/firewall.txt

diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
new file mode 100644
index 0000000..2f5dd9f
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.cfg
@@ -0,0 +1,68 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             _______________
+; RXQ0.0 --->|               |---> TXQ0.0
+;            |               |
+; RXQ1.0 --->|               |---> TXQ1.0
+;            |   Firewall    |
+; RXQ2.0 --->|               |---> TXQ2.0
+;            |               |
+; RXQ3.0 --->|               |---> TXQ3.0
+;            |_______________|
+;                    |
+;                    +-----------> SINK0 (default rule)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FIREWALL
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+n_rules = 4096
+pkt_type = ipv4
+;pkt_type = vlan_ipv4
+;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
new file mode 100644
index 0000000..c83857e
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.sh
@@ -0,0 +1,13 @@
+#
+# run ./config/firewall.sh
+#
+
+p 1 firewall add default 4 #SINK0
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
+
+#p 1 firewall add bulk ./config/firewall.txt
+
+p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
new file mode 100644
index 0000000..54cfffd
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.txt
@@ -0,0 +1,9 @@
+#
+# p <pipelineid> firewall add bulk ./config/firewall.txt
+# p <pipelineid> firewall del bulk ./config/firewall.txt
+#
+
+priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
+priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
+priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
+priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
index fd897d5..30b22a1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -30,9 +30,11 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
 
@@ -43,15 +45,11 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_firewall.h"
-
-#define BUF_SIZE		1024
+#include "parser.h"
 
 struct app_pipeline_firewall_rule {
 	struct pipeline_firewall_key key;
@@ -75,18 +73,6 @@ struct app_pipeline_firewall {
 	void *default_rule_entry_ptr;
 };
 
-struct app_pipeline_add_bulk_params {
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	uint32_t *priorities;
-	uint32_t *port_ids;
-};
-
-struct app_pipeline_del_bulk_params {
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-};
-
 static void
 print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
 {
@@ -272,356 +258,118 @@ app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
 	}
 }
 
-static int
-app_pipeline_add_bulk_parse_file(char *filename,
-		struct app_pipeline_add_bulk_params *params)
+int
+app_pipeline_firewall_load_file(char *filename,
+	struct pipeline_firewall_key *keys,
+	uint32_t *priorities,
+	uint32_t *port_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
 {
-	FILE *f;
-	char file_buf[BUF_SIZE];
-	uint32_t i;
-	int status = 0;
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
 
-	f = fopen(filename, "r");
-	if (f == NULL)
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(priorities == NULL) ||
+		(port_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
 		return -1;
-
-	params->n_keys = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
-	rewind(f);
-
-	if (params->n_keys == 0) {
-		status = -1;
-		goto end;
-	}
-
-	params->keys = rte_malloc(NULL,
-			params->n_keys * sizeof(struct pipeline_firewall_key),
-			RTE_CACHE_LINE_SIZE);
-	if (params->keys == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	params->priorities = rte_malloc(NULL,
-			params->n_keys * sizeof(uint32_t),
-			RTE_CACHE_LINE_SIZE);
-	if (params->priorities == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	params->port_ids = rte_malloc(NULL,
-			params->n_keys * sizeof(uint32_t),
-			RTE_CACHE_LINE_SIZE);
-	if (params->port_ids == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	i = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
-
-		str = strtok(file_buf, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->priorities[i] = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->port_ids[i] = atoi(str);
-		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-
-		i++;
-	}
-
-end:
-	fclose(f);
-	return status;
-}
-
-static int
-app_pipeline_del_bulk_parse_file(char *filename,
-		struct app_pipeline_del_bulk_params *params)
-{
-	FILE *f;
-	char file_buf[BUF_SIZE];
-	uint32_t i;
-	int status = 0;
 
+	/* Open input file */
 	f = fopen(filename, "r");
-	if (f == NULL)
+	if (f == NULL) {
+		*line = 0;
 		return -1;
-
-	params->n_keys = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
-	rewind(f);
-
-	if (params->n_keys == 0) {
-		status = -1;
-		goto end;
-	}
-
-	params->keys = rte_malloc(NULL,
-			params->n_keys * sizeof(struct pipeline_firewall_key),
-			RTE_CACHE_LINE_SIZE);
-	if (params->keys == NULL) {
-		status = -1;
-		goto end;
 	}
 
-	i = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
-
-		str = strtok(file_buf, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
-
-		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		uint32_t priority = 0;
+		struct in_addr sipaddr;
+		uint32_t sipdepth = 0;
+		struct in_addr dipaddr;
+		uint32_t dipdepth = 0;
+		uint16_t sport0 = 0;
+		uint16_t sport1 = 0;
+		uint16_t dport0 = 0;
+		uint16_t dport1 = 0;
+		uint8_t proto = 0;
+		uint8_t protomask = 0;
+		uint32_t port_id = 0;
+
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 15) ||
+			strcmp(tokens[0], "priority") ||
+			parser_read_uint32(&priority, tokens[1]) ||
+			strcmp(tokens[2], "ipv4") ||
+			parse_ipv4_addr(tokens[3], &sipaddr) ||
+			parser_read_uint32(&sipdepth, tokens[4]) ||
+			parse_ipv4_addr(tokens[5], &dipaddr) ||
+			parser_read_uint32(&dipdepth, tokens[6]) ||
+			parser_read_uint16(&sport0, tokens[7]) ||
+			parser_read_uint16(&sport1, tokens[8]) ||
+			parser_read_uint16(&dport0, tokens[9]) ||
+			parser_read_uint16(&dport1, tokens[10]) ||
+			parser_read_uint8(&proto, tokens[11]) ||
+			parser_read_uint8_hex(&protomask, tokens[12]) ||
+			strcmp(tokens[13], "port") ||
+			parser_read_uint32(&port_id, tokens[14]))
+			goto error1;
+
+		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		keys[i].key.ipv4_5tuple.src_ip =
+			rte_be_to_cpu_32(sipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
+		keys[i].key.ipv4_5tuple.dst_ip =
+			rte_be_to_cpu_32(dipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		keys[i].key.ipv4_5tuple.src_port_from = sport0;
+		keys[i].key.ipv4_5tuple.src_port_to = sport1;
+		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
+		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
+		keys[i].key.ipv4_5tuple.proto = proto;
+		keys[i].key.ipv4_5tuple.proto_mask = protomask;
+
+		port_ids[i] = port_id;
+		priorities[i] = priority;
+
+		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
+			goto error1;
 
 		i++;
 	}
 
-	for (i = 0; i < params->n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&params->keys[i]) != 0) {
-			status = -1;
-			goto end;
-		}
-	}
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
 
-end:
+error1:
+	*line = l;
 	fclose(f);
-	return status;
+	return -1;
 }
 
 int
@@ -804,14 +552,14 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 		return -1;
 
 	rules = rte_malloc(NULL,
-			n_keys * sizeof(struct app_pipeline_firewall_rule *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct app_pipeline_firewall_rule *),
+		RTE_CACHE_LINE_SIZE);
 	if (rules == NULL)
 		return -1;
 
 	new_rules = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (new_rules == NULL) {
 		rte_free(rules);
 		return -1;
@@ -834,8 +582,9 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
 		new_rules[i] = (rules[i] == NULL);
 		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL, sizeof(*rules[i]),
-					RTE_CACHE_LINE_SIZE);
+			rules[i] = rte_malloc(NULL,
+				sizeof(*rules[i]),
+				RTE_CACHE_LINE_SIZE);
 
 			if (rules[i] == NULL) {
 				uint32_t j;
@@ -852,8 +601,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 
 	keys_found = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (keys_found == NULL) {
 		uint32_t j;
 
@@ -867,8 +616,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 
 	entries_ptr = rte_malloc(NULL,
-			n_keys * sizeof(struct rte_pipeline_table_entry *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct rte_pipeline_table_entry *),
+		RTE_CACHE_LINE_SIZE);
 	if (entries_ptr == NULL) {
 		uint32_t j;
 
@@ -883,8 +632,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 	for (i = 0; i < n_keys; i++) {
 		entries_ptr[i] = rte_malloc(NULL,
-				sizeof(struct rte_pipeline_table_entry),
-				RTE_CACHE_LINE_SIZE);
+			sizeof(struct rte_pipeline_table_entry),
+			RTE_CACHE_LINE_SIZE);
 
 		if (entries_ptr[i] == NULL) {
 			uint32_t j;
@@ -1030,8 +779,8 @@ app_pipeline_firewall_delete_bulk(struct app_params *app,
 		return -1;
 
 	rules = rte_malloc(NULL,
-			n_keys * sizeof(struct app_pipeline_firewall_rule *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct app_pipeline_firewall_rule *),
+		RTE_CACHE_LINE_SIZE);
 	if (rules == NULL)
 		return -1;
 
@@ -1044,8 +793,8 @@ app_pipeline_firewall_delete_bulk(struct app_params *app,
 	}
 
 	keys_found = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (keys_found == NULL) {
 		rte_free(rules);
 		return -1;
@@ -1197,662 +946,492 @@ app_pipeline_firewall_delete_default_rule(struct app_params *app,
 }
 
 /*
- * p firewall add ipv4
+ * firewall
+ *
+ * firewall add:
+ *    p <pipelineid> firewall add priority <priority>
+ *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
+ *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
+ *       port <portid>
+ *       Note: <protomask> is a hex value
+ *
+ *    p <pipelineid> firewall add bulk <file>
+ *
+ * firewall add default:
+ *    p <pipelineid> firewall add default <port ID>
+ *
+ * firewall del:
+ *    p <pipelineid> firewall del
+ *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
+ *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
+ *
+ *    p <pipelineid> firewall del bulk <file>
+ *
+ * firewall del default:
+ *    p <pipelineid> firewall del default
+ *
+ * firewall ls:
+ *    p <pipelineid> firewall ls
  */
 
-struct cmd_firewall_add_ipv4_result {
+struct cmd_firewall_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_string;
-	int32_t priority;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-	uint8_t port_id;
+	cmdline_multi_string_t multi_string;
 };
 
-static void
-cmd_firewall_add_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
+static void cmd_firewall_parsed(void *parsed_result,
+	__attribute__((unused))  struct cmdline *cl,
 	void *data)
 {
-	struct cmd_firewall_add_ipv4_result *params = parsed_result;
+	struct cmd_firewall_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_firewall_key key;
 	int status;
 
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_add_rule(app,
-		params->pipeline_id,
-		&key,
-		params->priority,
-		params->port_id);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_priority =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, priority,
-		INT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip);
+	char *tokens[17];
+	uint32_t n_tokens = RTE_DIM(tokens);
 
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip_mask,
-		UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto_mask, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		port_id, UINT8);
-
-cmdline_parse_inst_t cmd_firewall_add_ipv4 = {
-	.f = cmd_firewall_add_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_ipv4_p_string,
-		(void *) &cmd_firewall_add_ipv4_pipeline_id,
-		(void *) &cmd_firewall_add_ipv4_firewall_string,
-		(void *) &cmd_firewall_add_ipv4_add_string,
-		(void *) &cmd_firewall_add_ipv4_ipv4_string,
-		(void *) &cmd_firewall_add_ipv4_priority,
-		(void *) &cmd_firewall_add_ipv4_src_ip,
-		(void *) &cmd_firewall_add_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_dst_ip,
-		(void *) &cmd_firewall_add_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_src_port_from,
-		(void *) &cmd_firewall_add_ipv4_src_port_to,
-		(void *) &cmd_firewall_add_ipv4_dst_port_from,
-		(void *) &cmd_firewall_add_ipv4_dst_port_to,
-		(void *) &cmd_firewall_add_ipv4_proto,
-		(void *) &cmd_firewall_add_ipv4_proto_mask,
-		(void *) &cmd_firewall_add_ipv4_port_id,
-		NULL,
-	},
-};
-
-/*
- * p firewall del ipv4
- */
-
-struct cmd_firewall_del_ipv4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_string;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-};
-
-static void
-cmd_firewall_del_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_ipv4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_firewall_key key;
-	int status;
-
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_delete_rule(app,
-		params->pipeline_id,
-		&key);
-
-	if (status != 0) {
-		printf("Command failed\n");
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
 		return;
 	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		del_string, "del");
 
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip_mask,
-		UINT32);
+	/* firewall add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "priority") == 0)) {
+		struct pipeline_firewall_key key;
+		uint32_t priority;
+		struct in_addr sipaddr;
+		uint32_t sipdepth;
+		struct in_addr dipaddr;
+		uint32_t dipdepth;
+		uint16_t sport0;
+		uint16_t sport1;
+		uint16_t dport0;
+		uint16_t dport1;
+		uint8_t proto;
+		uint8_t protomask;
+		uint32_t port_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 16) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		src_port_from, UINT16);
+		if (parser_read_uint32(&priority, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "priority");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_port_to,
-		UINT16);
+		if (strcmp(tokens[3], "ipv4")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_from, UINT16);
+		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "sipaddr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_to, UINT16);
+		if (parser_read_uint32(&sipdepth, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "sipdepth");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		proto, UINT8);
+		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "dipaddr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, proto_mask,
-		UINT8);
+		if (parser_read_uint32(&dipdepth, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "dipdepth");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_del_ipv4 = {
-	.f = cmd_firewall_del_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_ipv4_p_string,
-		(void *) &cmd_firewall_del_ipv4_pipeline_id,
-		(void *) &cmd_firewall_del_ipv4_firewall_string,
-		(void *) &cmd_firewall_del_ipv4_del_string,
-		(void *) &cmd_firewall_del_ipv4_ipv4_string,
-		(void *) &cmd_firewall_del_ipv4_src_ip,
-		(void *) &cmd_firewall_del_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_dst_ip,
-		(void *) &cmd_firewall_del_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_src_port_from,
-		(void *) &cmd_firewall_del_ipv4_src_port_to,
-		(void *) &cmd_firewall_del_ipv4_dst_port_from,
-		(void *) &cmd_firewall_del_ipv4_dst_port_to,
-		(void *) &cmd_firewall_del_ipv4_proto,
-		(void *) &cmd_firewall_del_ipv4_proto_mask,
-		NULL,
-	},
-};
+		if (parser_read_uint16(&sport0, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "sport0");
+			return;
+		}
 
-/*
- * p firewall add bulk
- */
+		if (parser_read_uint16(&sport1, tokens[9])) {
+			printf(CMD_MSG_INVALID_ARG, "sport1");
+			return;
+		}
 
-struct cmd_firewall_add_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
+		if (parser_read_uint16(&dport0, tokens[10])) {
+			printf(CMD_MSG_INVALID_ARG, "dport0");
+			return;
+		}
 
-static void
-cmd_firewall_add_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (parser_read_uint16(&dport1, tokens[11])) {
+			printf(CMD_MSG_INVALID_ARG, "dport1");
+			return;
+		}
 
-	struct app_pipeline_add_bulk_params add_bulk_params;
+		if (parser_read_uint8(&proto, tokens[12])) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-	status = app_pipeline_add_bulk_parse_file(params->file_path, &add_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		if (parser_read_uint8_hex(&protomask, tokens[13])) {
+			printf(CMD_MSG_INVALID_ARG, "protomask");
+			return;
+		}
 
-	status = app_pipeline_firewall_add_bulk(app, params->pipeline_id, add_bulk_params.keys,
-			add_bulk_params.n_keys, add_bulk_params.priorities, add_bulk_params.port_ids);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		if (strcmp(tokens[14], "port")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-end:
-	rte_free(add_bulk_params.keys);
-	rte_free(add_bulk_params.priorities);
-	rte_free(add_bulk_params.port_ids);
-}
+		if (parser_read_uint32(&port_id, tokens[15])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result, p_string,
-		"p");
+		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		key.key.ipv4_5tuple.src_port_from = sport0;
+		key.key.ipv4_5tuple.src_port_to = sport1;
+		key.key.ipv4_5tuple.dst_port_from = dport0;
+		key.key.ipv4_5tuple.dst_port_to = dport1;
+		key.key.ipv4_5tuple.proto = proto;
+		key.key.ipv4_5tuple.proto_mask = protomask;
+
+		status = app_pipeline_firewall_add_rule(app,
+			params->pipeline_id,
+			&key,
+			priority,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add");
 
-cmdline_parse_token_num_t cmd_firewall_add_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_bulk_result, pipeline_id,
-		UINT32);
+		return;
+	} /* firewall add */
+
+	/* firewall add bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_firewall_key *keys;
+		uint32_t *priorities, *port_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		firewall_string, "firewall");
+		filename = tokens[2];
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		add_string, "add");
+		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
+		if (keys == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
+		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		bulk_string, "bulk");
+		priorities = malloc(n_keys * sizeof(uint32_t));
+		if (priorities == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		file_path, NULL);
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_add_bulk = {
-	.f = cmd_firewall_add_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add bulk",
-	.tokens = {
-		(void *) &cmd_firewall_add_bulk_p_string,
-		(void *) &cmd_firewall_add_bulk_pipeline_id,
-		(void *) &cmd_firewall_add_bulk_firewall_string,
-		(void *) &cmd_firewall_add_bulk_add_string,
-		(void *) &cmd_firewall_add_bulk_bulk_string,
-		(void *) &cmd_firewall_add_bulk_file_path_string,
-		NULL,
-	},
-};
+		status = app_pipeline_firewall_load_file(filename,
+			keys,
+			priorities,
+			port_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(port_ids);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-/*
- * p firewall del bulk
- */
+		status = app_pipeline_firewall_add_bulk(app,
+			params->pipeline_id,
+			keys,
+			n_keys,
+			priorities,
+			port_ids);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add bulk");
+
+		free(keys);
+		free(priorities);
+		free(port_ids);
+		return;
+	} /* firewall add bulk */
 
-struct cmd_firewall_del_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
+	/* firewall add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-static void
-cmd_firewall_del_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
+			return;
+		}
 
-	struct app_pipeline_del_bulk_params del_bulk_params;
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	status = app_pipeline_del_bulk_parse_file(params->file_path, &del_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		status = app_pipeline_firewall_add_default_rule(app,
+			params->pipeline_id,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add default");
 
-	status = app_pipeline_firewall_delete_bulk(app, params->pipeline_id,
-			del_bulk_params.keys, del_bulk_params.n_keys);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		return;
+	} /* firewall add default */
+
+	/* firewall del */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0)) {
+		struct pipeline_firewall_key key;
+		struct in_addr sipaddr;
+		uint32_t sipdepth;
+		struct in_addr dipaddr;
+		uint32_t dipdepth;
+		uint16_t sport0;
+		uint16_t sport1;
+		uint16_t dport0;
+		uint16_t dport1;
+		uint8_t proto;
+		uint8_t protomask;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 12) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
+			return;
+		}
 
-end:
-	rte_free(del_bulk_params.keys);
-}
+		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "sipaddr");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result, p_string,
-		"p");
+		if (parser_read_uint32(&sipdepth, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "sipdepth");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_bulk_result, pipeline_id,
-		UINT32);
+		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "dipaddr");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		firewall_string, "firewall");
+		if (parser_read_uint32(&dipdepth, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "dipdepth");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		del_string, "del");
+		if (parser_read_uint16(&sport0, tokens[6])) {
+			printf(CMD_MSG_INVALID_ARG, "sport0");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		bulk_string, "bulk");
+		if (parser_read_uint16(&sport1, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "sport1");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		file_path, NULL);
+		if (parser_read_uint16(&dport0, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "dport0");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_del_bulk = {
-	.f = cmd_firewall_del_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule del bulk",
-	.tokens = {
-		(void *) &cmd_firewall_del_bulk_p_string,
-		(void *) &cmd_firewall_del_bulk_pipeline_id,
-		(void *) &cmd_firewall_del_bulk_firewall_string,
-		(void *) &cmd_firewall_del_bulk_add_string,
-		(void *) &cmd_firewall_del_bulk_bulk_string,
-		(void *) &cmd_firewall_del_bulk_file_path_string,
-		NULL,
-	},
-};
+		if (parser_read_uint16(&dport1, tokens[9])) {
+			printf(CMD_MSG_INVALID_ARG, "dport1");
+			return;
+		}
 
-/*
- * p firewall add default
- */
-struct cmd_firewall_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint8_t port_id;
-};
+		if (parser_read_uint8(&proto, tokens[10])) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-static void
-cmd_firewall_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (parser_read_uint8_hex(&protomask, tokens[11])) {
+			printf(CMD_MSG_INVALID_ARG, "protomask");
+			return;
+		}
 
-	status = app_pipeline_firewall_add_default_rule(app,
-		params->pipeline_id,
-		params->port_id);
+		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		key.key.ipv4_5tuple.src_port_from = sport0;
+		key.key.ipv4_5tuple.src_port_to = sport1;
+		key.key.ipv4_5tuple.dst_port_from = dport0;
+		key.key.ipv4_5tuple.dst_port_to = dport1;
+		key.key.ipv4_5tuple.proto = proto;
+		key.key.ipv4_5tuple.proto_mask = protomask;
+
+		status = app_pipeline_firewall_delete_rule(app,
+			params->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_firewall_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	add_string, "add");
+	} /* firewall del */
+
+	/* firewall del bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_firewall_key *keys;
+		uint32_t *priorities, *port_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		default_string, "default");
+		filename = tokens[2];
 
-cmdline_parse_token_num_t cmd_firewall_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result, port_id,
-		UINT8);
+		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
+		if (keys == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
+		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
 
-cmdline_parse_inst_t cmd_firewall_add_default = {
-	.f = cmd_firewall_add_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_default_p_string,
-		(void *) &cmd_firewall_add_default_pipeline_id,
-		(void *) &cmd_firewall_add_default_firewall_string,
-		(void *) &cmd_firewall_add_default_add_string,
-		(void *) &cmd_firewall_add_default_default_string,
-		(void *) &cmd_firewall_add_default_port_id,
-		NULL,
-	},
-};
+		priorities = malloc(n_keys * sizeof(uint32_t));
+		if (priorities == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(keys);
+			return;
+		}
 
-/*
- * p firewall del default
- */
-struct cmd_firewall_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-static void
-cmd_firewall_del_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		status = app_pipeline_firewall_load_file(filename,
+			keys,
+			priorities,
+			port_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(port_ids);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-	status = app_pipeline_firewall_delete_default_rule(app,
-		params->pipeline_id);
+		status = app_pipeline_firewall_delete_bulk(app,
+			params->pipeline_id,
+			keys,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del bulk");
 
-	if (status != 0) {
-		printf("Command failed\n");
+		free(port_ids);
+		free(priorities);
+		free(keys);
 		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_firewall_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_default_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		del_string, "del");
+	} /* firewall del bulk */
+
+	/* firewall del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		default_string, "default");
+		status = app_pipeline_firewall_delete_default_rule(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del default");
 
-cmdline_parse_inst_t cmd_firewall_del_default = {
-	.f = cmd_firewall_del_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_default_p_string,
-		(void *) &cmd_firewall_del_default_pipeline_id,
-		(void *) &cmd_firewall_del_default_firewall_string,
-		(void *) &cmd_firewall_del_default_del_string,
-		(void *) &cmd_firewall_del_default_default_string,
-		NULL,
-	},
-};
+		return;
 
-/*
- * p firewall ls
- */
+	} /* firewall del default */
 
-struct cmd_firewall_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_firewall_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	/* firewall ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
+			return;
+		}
 
-	status = app_pipeline_firewall_ls(app, params->pipeline_id);
+		status = app_pipeline_firewall_ls(app, params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall ls");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
+	} /* firewall ls */
+
+	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
 }
 
-cmdline_parse_token_string_t cmd_firewall_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, p_string,
-		"p");
+static cmdline_parse_token_string_t cmd_firewall_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_firewall_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_ls_result, pipeline_id,
-		UINT32);
+static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_firewall_ls_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result,
-	firewall_string, "firewall");
+static cmdline_parse_token_string_t cmd_firewall_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
+	"firewall");
 
-cmdline_parse_token_string_t cmd_firewall_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_firewall_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_firewall_ls = {
-	.f = cmd_firewall_ls_parsed,
+static cmdline_parse_inst_t cmd_firewall = {
+	.f = cmd_firewall_parsed,
 	.data = NULL,
-	.help_str = "Firewall rule list",
+	.help_str =	"firewall add / add bulk / add default / del / del bulk"
+		" / del default / ls",
 	.tokens = {
-		(void *) &cmd_firewall_ls_p_string,
-		(void *) &cmd_firewall_ls_pipeline_id,
-		(void *) &cmd_firewall_ls_firewall_string,
-		(void *) &cmd_firewall_ls_ls_string,
+		(void *) &cmd_firewall_p_string,
+		(void *) &cmd_firewall_pipeline_id,
+		(void *) &cmd_firewall_firewall_string,
+		(void *) &cmd_firewall_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall_add_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_ls,
+	(cmdline_parse_inst_t *) &cmd_firewall,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.h b/examples/ip_pipeline/pipeline/pipeline_firewall.h
index ccc4e64..aa79a2a 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.h
@@ -72,6 +72,18 @@ int
 app_pipeline_firewall_delete_default_rule(struct app_params *app,
 	uint32_t pipeline_id);
 
+#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
+#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
+#endif
+
+int
+app_pipeline_firewall_load_file(char *filename,
+	struct pipeline_firewall_key *keys,
+	uint32_t *priorities,
+	uint32_t *port_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_firewall;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 4/7] examples/ip_pipeline: modifies flow classifications pipeline CLI
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (2 preceding siblings ...)
  2016-05-20 14:35   ` [PATCH v2 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev
  Cc: Piotr Azarewicz, Tomasz Kulasek, Marcin Kerlin,
	Slawomir Mrozowicz, Michal Kobylinski

This patch modifies flow classifications pipeline command line
interface. All commands are merged into one cmd_fc_parsed.
Additionally a classification for ipv6, ipv4 and qinq can be added from
configuration file.

1. flow add qinq bulk
File line format:
qinq <svlan> <cvlan> port <port ID> id <flow ID>
File line example:
qinq 1 2 port 3 id 0

2. flow add ipv4 bulk
File line format:
ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>
File line example:
ipv4 1.2.3.4 10.20.30.40 63 127 6 port 2 id 999

3. flow add ipv6 bulk
File line format:
ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Michal Kobylinski <michalx.kobylinski@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/flow.cfg               |   72 +
 examples/ip_pipeline/config/flow.sh                |   25 +
 examples/ip_pipeline/config/flow.txt               |   17 +
 .../pipeline/pipeline_flow_classification.c        | 2082 +++++++++-----------
 .../pipeline/pipeline_flow_classification.h        |   28 +
 5 files changed, 1027 insertions(+), 1197 deletions(-)
 create mode 100644 examples/ip_pipeline/config/flow.cfg
 create mode 100644 examples/ip_pipeline/config/flow.sh
 create mode 100644 examples/ip_pipeline/config/flow.txt

diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
new file mode 100644
index 0000000..6895d39
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.cfg
@@ -0,0 +1,72 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ________________
+; RXQ0.0 --->|                |---> TXQ0.0
+;            |                |
+; RXQ1.0 --->|                |---> TXQ1.0
+;            |      Flow      |
+; RXQ2.0 --->| Classification |---> TXQ2.0
+;            |                |
+; RXQ3.0 --->|                |---> TXQ3.0
+;            |________________|
+;                    |
+;                    +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FLOW_CLASSIFICATION
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+n_flows = 65536
+;key_size = 8                ; QinQ key size
+;key_offset = 270            ; QinQ key offset
+;key_mask = 0000FFF00000FFF0 ; QinQ key mask
+key_size = 16                               ; IPv4 5-tuple key size
+key_offset = 278                            ; IPv4 5-tuple key offset
+key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
+flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
new file mode 100644
index 0000000..489c707
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.sh
@@ -0,0 +1,25 @@
+#
+# run ./config/flow.sh
+#
+
+################################################################################
+# Flow classification (QinQ)
+################################################################################
+#p 1 flow add default 4 #SINK0
+#p 1 flow add qinq 100 200 port 0 id 0
+#p 1 flow add qinq 101 201 port 1 id 1
+#p 1 flow add qinq 102 202 port 2 id 2
+#p 1 flow add qinq 103 203 port 3 id 3
+
+#p 1 flow add qinq bulk ./config/flow.txt
+
+################################################################################
+# Flow classification (IPv4 5-tuple)
+################################################################################
+p 1 flow add default 4 #SINK0
+p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
+p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
+p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
+p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
+
+#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
new file mode 100644
index 0000000..c1a141d
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.txt
@@ -0,0 +1,17 @@
+#
+# p <pipelineid> flow add qinq bulk ./config/flow.txt
+#
+
+#qinq 100 200 port 0 id 0
+#qinq 101 201 port 1 id 1
+#qinq 102 202 port 2 id 2
+#qinq 103 203 port 3 id 3
+
+#
+# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
+#
+
+ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
+ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
+ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
+ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
index 1921574..e49c881 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -43,13 +44,12 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_classification.h"
 #include "hash_func.h"
+#include "parser.h"
 
 /*
  * Key conversion
@@ -96,9 +96,9 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		struct pkt_key_qinq *qinq = key_buffer;
 
 		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_bswap16(key_in->key.qinq.svlan);
+		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
 		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_bswap16(key_in->key.qinq.cvlan);
+		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key8(qinq, 8, 0);
@@ -112,10 +112,10 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		ipv4->ttl = 0;
 		ipv4->proto = key_in->key.ipv4_5tuple.proto;
 		ipv4->checksum = 0;
-		ipv4->ip_src = rte_bswap32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_bswap32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_bswap16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_bswap16(key_in->key.ipv4_5tuple.port_dst);
+		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
+		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
+		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
+		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key16(ipv4, 16, 0);
@@ -132,8 +132,8 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		ipv6->hop_limit = 0;
 		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
 		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_bswap16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_bswap16(key_in->key.ipv6_5tuple.port_dst);
+		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
+		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key64(ipv6, 64, 0);
@@ -278,6 +278,283 @@ app_pipeline_fc_key_check(struct pipeline_fc_key *key)
 }
 
 int
+app_pipeline_fc_load_file_qinq(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		uint16_t svlan, cvlan;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 7) ||
+			strcmp(tokens[0], "qinq") ||
+			parser_read_uint16(&svlan, tokens[1]) ||
+			parser_read_uint16(&cvlan, tokens[2]) ||
+			strcmp(tokens[3], "port") ||
+			parser_read_uint32(&portid, tokens[4]) ||
+			strcmp(tokens[5], "id") ||
+			parser_read_uint32(&flowid, tokens[6]))
+			goto error1;
+
+		keys[i].type = FLOW_KEY_QINQ;
+		keys[i].key.qinq.svlan = svlan;
+		keys[i].key.qinq.cvlan = cvlan;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error1;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error1:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+int
+app_pipeline_fc_load_file_ipv4(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		struct in_addr sipaddr, dipaddr;
+		uint16_t sport, dport;
+		uint8_t proto;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error2;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 10) ||
+			strcmp(tokens[0], "ipv4") ||
+			parse_ipv4_addr(tokens[1], &sipaddr) ||
+			parse_ipv4_addr(tokens[2], &dipaddr) ||
+			parser_read_uint16(&sport, tokens[3]) ||
+			parser_read_uint16(&dport, tokens[4]) ||
+			parser_read_uint8(&proto, tokens[5]) ||
+			strcmp(tokens[6], "port") ||
+			parser_read_uint32(&portid, tokens[7]) ||
+			strcmp(tokens[8], "id") ||
+			parser_read_uint32(&flowid, tokens[9]))
+			goto error2;
+
+		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
+		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.port_src = sport;
+		keys[i].key.ipv4_5tuple.port_dst = dport;
+		keys[i].key.ipv4_5tuple.proto = proto;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error2;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error2:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+int
+app_pipeline_fc_load_file_ipv6(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		struct in6_addr sipaddr, dipaddr;
+		uint16_t sport, dport;
+		uint8_t proto;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error3;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 10) ||
+			strcmp(tokens[0], "ipv6") ||
+			parse_ipv6_addr(tokens[1], &sipaddr) ||
+			parse_ipv6_addr(tokens[2], &dipaddr) ||
+			parser_read_uint16(&sport, tokens[3]) ||
+			parser_read_uint16(&dport, tokens[4]) ||
+			parser_read_uint8(&proto, tokens[5]) ||
+			strcmp(tokens[6], "port") ||
+			parser_read_uint32(&portid, tokens[7]) ||
+			strcmp(tokens[8], "id") ||
+			parser_read_uint32(&flowid, tokens[9]))
+			goto error3;
+
+		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(keys[i].key.ipv6_5tuple.ip_src,
+			sipaddr.s6_addr,
+			sizeof(sipaddr.s6_addr));
+		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
+			dipaddr.s6_addr,
+			sizeof(dipaddr.s6_addr));
+		keys[i].key.ipv6_5tuple.port_src = sport;
+		keys[i].key.ipv6_5tuple.port_dst = dport;
+		keys[i].key.ipv6_5tuple.proto = proto;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error3;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error3:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+
+
+int
 app_pipeline_fc_add(struct app_params *app,
 	uint32_t pipeline_id,
 	struct pipeline_fc_key *key,
@@ -896,1309 +1173,720 @@ app_pipeline_fc_ls(struct app_params *app,
 
 	return 0;
 }
-
 /*
- * flow add qinq
- */
-
-struct cmd_fc_add_qinq_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
-
-static void
-cmd_fc_add_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, cvlan, UINT16);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, port_string,
-		"port");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, port, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flowid_string,
-		"flowid");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, flow_id, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_qinq = {
-	.f = cmd_fc_add_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow add (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_p_string,
-		(void *) &cmd_fc_add_qinq_pipeline_id,
-		(void *) &cmd_fc_add_qinq_flow_string,
-		(void *) &cmd_fc_add_qinq_add_string,
-		(void *) &cmd_fc_add_qinq_qinq_string,
-		(void *) &cmd_fc_add_qinq_svlan,
-		(void *) &cmd_fc_add_qinq_cvlan,
-		(void *) &cmd_fc_add_qinq_port_string,
-		(void *) &cmd_fc_add_qinq_port,
-		(void *) &cmd_fc_add_qinq_flowid_string,
-		(void *) &cmd_fc_add_qinq_flow_id,
-		NULL,
-	},
-};
-
-/*
- * flow add qinq all
+ * flow
+ *
+ * flow add:
+ *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
+ *    p <pipelineid> flow add qinq bulk <file>
+ *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
+ *    p <pipelineid> flow add ipv4 bulk <file>
+ *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
+ *    p <pipelineid> flow add ipv6 bulk <file>
+ *
+ * flow add default:
+ *    p <pipelineid> flow add default <portid>
+ *
+ * flow del:
+ *    p <pipelineid> flow del qinq <svlan> <cvlan>
+ *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
+ *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
+ *
+ * flow del default:
+ *    p <pipelineid> flow del default
+ *
+ * flow ls:
+ *    p <pipelineid> flow ls
  */
 
-struct cmd_fc_add_qinq_all_result {
+struct cmd_flow_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
+	cmdline_multi_string_t multi_string;
 };
 
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
 static void
-cmd_fc_add_qinq_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
+cmd_flow_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
 	void *data)
 {
-	struct cmd_fc_add_qinq_all_result *params = parsed_result;
+	struct cmd_flow_result *results = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input arguments */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of output ports\n");
-		return;
-	}
-
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
+	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
 		return;
 	}
 
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-
-		key[pos].type = FLOW_KEY_QINQ;
-		key[pos].key.qinq.svlan = id >> 12;
-		key[pos].key.qinq.cvlan = id & 0xFFF;
-
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* flow add qinq */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		uint32_t svlan;
+		uint32_t cvlan;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 8) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
+			return;
 		}
-	}
-
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, p_string,
-		"p");
+		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "svlan");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "cvlan");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, flow_string,
-		"flow");
+		if (strcmp(tokens[4], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, add_string,
-		"add");
+		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, qinq_string,
-		"qinq");
+		if (strcmp(tokens[6], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, all_string,
-		"all");
+		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_flows,
-		UINT32);
+		key.type = FLOW_KEY_QINQ;
+		key.key.qinq.svlan = svlan;
+		key.key.qinq.cvlan = cvlan;
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_ports,
-		UINT32);
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add qinq");
 
-cmdline_parse_inst_t cmd_fc_add_qinq_all = {
-	.f = cmd_fc_add_qinq_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_all_p_string,
-		(void *) &cmd_fc_add_qinq_all_pipeline_id,
-		(void *) &cmd_fc_add_qinq_all_flow_string,
-		(void *) &cmd_fc_add_qinq_all_add_string,
-		(void *) &cmd_fc_add_qinq_all_qinq_string,
-		(void *) &cmd_fc_add_qinq_all_all_string,
-		(void *) &cmd_fc_add_qinq_all_n_flows,
-		(void *) &cmd_fc_add_qinq_all_n_ports,
-		NULL,
-	},
-};
+		return;
+	} /* flow add qinq */
+
+	/* flow add ipv4 */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		struct in_addr sipaddr;
+		struct in_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 11) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
+			return;
+		}
 
-/*
- * flow add ipv4_5tuple
- */
+		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
+			return;
+		}
+		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
+			return;
+		}
 
-struct cmd_fc_add_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-static void
-cmd_fc_add_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, p_string,
-		"p");
+		if (strcmp(tokens[7], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flow_string, "flow");
+		if (strcmp(tokens[9], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		add_string, "add");
+		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
+		key.type = FLOW_KEY_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.port_src = sport;
+		key.key.ipv4_5tuple.port_dst = dport;
+		key.key.ipv4_5tuple.proto = proto;
+
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv4");
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_src);
+		return;
+	} /* flow add ipv4 */
+
+	/* flow add ipv6 */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		struct in6_addr sipaddr;
+		struct in6_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 11) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_dst);
+		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
+			return;
+		}
+		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_src,
-		UINT16);
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_dst,
-		UINT16);
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, proto,
-		UINT32);
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_string,
-		"port");
+		if (strcmp(tokens[7], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port,
-		UINT32);
+		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flowid_string, "flowid");
+		if (strcmp(tokens[9], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, flow_id,
-		UINT32);
+		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {
-	.f = cmd_fc_add_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_proto,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_port,
-		(void *) &cmd_fc_add_ipv4_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_id,
-		NULL,
-	},
-};
+		key.type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
+		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
+		key.key.ipv6_5tuple.port_src = sport;
+		key.key.ipv6_5tuple.port_dst = dport;
+		key.key.ipv6_5tuple.proto = proto;
+
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv6");
 
-/*
- * flow add ipv4_5tuple all
- */
+		return;
+	} /* flow add ipv6 */
+
+	/* flow add qinq bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
+			return;
+		}
 
-struct cmd_fc_add_ipv4_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+		filename = tokens[3];
 
-static void
-cmd_fc_add_ipv4_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fc_load_file_qinq(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add qinq bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
 		return;
-	}
-
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
+	} /* flow add qinq bulk */
+
+	/* flow add ipv4 bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
+			return;
+		}
 
-		key[pos].type = FLOW_KEY_IPV4_5TUPLE;
-		key[pos].key.ipv4_5tuple.ip_src = 0;
-		key[pos].key.ipv4_5tuple.ip_dst = id;
-		key[pos].key.ipv4_5tuple.port_src = 0;
-		key[pos].key.ipv4_5tuple.port_dst = 0;
-		key[pos].key.ipv4_5tuple.proto = 6;
+		filename = tokens[3];
 
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-			if (status != 0) {
-				printf("Command failed\n");
+		status = app_pipeline_fc_load_file_ipv4(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-				break;
-			}
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
+		return;
+	} /* flow add ipv4 bulk */
+
+	/* flow add ipv6 bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
+			return;
 		}
-	}
 
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
+		filename = tokens[3];
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		p_string, "p");
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		pipeline_id, UINT32);
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		flow_string, "flow");
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		add_string, "add");
+		status = app_pipeline_fc_load_file_ipv6(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
+		return;
+	} /* flow add ipv6 bulk */
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		all_string, "all");
+	/* flow add default*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_flows, UINT32);
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_ports, UINT32);
+		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple_all = {
-	.f = cmd_fc_add_ipv4_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_ports,
-		NULL,
-	},
-};
+		status = app_pipeline_fc_add_default(app,
+			results->pipeline_id,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add default");
 
-/*
- * flow add ipv6_5tuple
- */
+		return;
+	} /* flow add default */
 
-struct cmd_fc_add_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
+	/* flow del qinq */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0)) {
+		struct pipeline_fc_key key;
+		uint32_t svlan;
+		uint32_t cvlan;
 
-static void
-cmd_fc_add_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
+		memset(&key, 0, sizeof(key));
 
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		p_string, "p");
+		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "svlan");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "cvlan");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flow_string, "flow");
+		key.type = FLOW_KEY_QINQ;
+		key.key.qinq.svlan = svlan;
+		key.key.qinq.cvlan = cvlan;
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		add_string, "add");
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del qinq");
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
+		return;
+	} /* flow del qinq */
+
+	/* flow del ipv4 */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0)) {
+		struct pipeline_fc_key key;
+		struct in_addr sipaddr;
+		struct in_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 7) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_src);
+		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
+			return;
+		}
+		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_dst);
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_src,
-		UINT16);
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_dst,
-		UINT16);
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, proto,
-		UINT32);
+		key.type = FLOW_KEY_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.port_src = sport;
+		key.key.ipv4_5tuple.port_dst = dport;
+		key.key.ipv4_5tuple.proto = proto;
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		port_string, "port");
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del ipv4");
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port,
-		UINT32);
+		return;
+	} /* flow del ipv4 */
+
+	/* flow del ipv6 */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0)) {
+		struct pipeline_fc_key key;
+		struct in6_addr sipaddr;
+		struct in6_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 7) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flowid_string, "flowid");
+		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, flow_id,
-		UINT32);
+		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {
-	.f = cmd_fc_add_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_proto,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_port,
-		(void *) &cmd_fc_add_ipv6_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_id,
-		NULL,
-	},
-};
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-/*
- * flow add ipv6_5tuple all
- */
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-struct cmd_fc_add_ipv6_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-static void
-cmd_fc_add_ipv6_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+		key.type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
+		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
+		key.key.ipv6_5tuple.port_src = sport;
+		key.key.ipv6_5tuple.port_dst = dport;
+		key.key.ipv6_5tuple.proto = proto;
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del ipv6");
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
 		return;
-	}
+	} /* flow del ipv6 */
+
+	/* flow del default*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
+			return;
+		}
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fc_del_default(app,
+			results->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del default");
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
 		return;
-	}
-
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-		uint32_t *x;
-
-		key[pos].type = FLOW_KEY_IPV6_5TUPLE;
-		x = (uint32_t *) key[pos].key.ipv6_5tuple.ip_dst;
-		*x = rte_bswap32(id);
-		key[pos].key.ipv6_5tuple.proto = 6;
-
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+	} /* flow del default */
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* flow ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
+			return;
 		}
-	}
-
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		all_string, "all");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_flows, UINT32);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple_all = {
-	.f = cmd_fc_add_ipv6_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (ipv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_ports,
-		NULL,
-	},
-};
-
-/*
- * flow del qinq
- */
-struct cmd_fc_del_qinq_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-};
-
-static void
-cmd_fc_del_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, cvlan, UINT16);
-
-cmdline_parse_inst_t cmd_fc_del_qinq = {
-	.f = cmd_fc_del_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_del_qinq_p_string,
-		(void *) &cmd_fc_del_qinq_pipeline_id,
-		(void *) &cmd_fc_del_qinq_flow_string,
-		(void *) &cmd_fc_del_qinq_del_string,
-		(void *) &cmd_fc_del_qinq_qinq_string,
-		(void *) &cmd_fc_del_qinq_svlan,
-		(void *) &cmd_fc_del_qinq_cvlan,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv4_5tuple
- */
-
-struct cmd_fc_del_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		p_string, "p");
 
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		pipeline_id, UINT32);
+		status = app_pipeline_fc_ls(app, results->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow ls");
 
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_src, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_dst, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		proto, UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv4_5tuple = {
-	.f = cmd_fc_del_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv6_5tuple
- */
-
-struct cmd_fc_del_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_src,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_dst,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, proto,
-		UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv6_5tuple = {
-	.f = cmd_fc_del_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow add default
- */
-
-struct cmd_fc_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_fc_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_add_default(app, params->pipeline_id,
-		params->port);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result,
-		default_string, "default");
-
-cmdline_parse_token_num_t cmd_fc_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, port, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_default = {
-	.f = cmd_fc_add_default_parsed,
-	.data = NULL,
-	.help_str = "Flow add default",
-	.tokens = {
-		(void *) &cmd_fc_add_default_p_string,
-		(void *) &cmd_fc_add_default_pipeline_id,
-		(void *) &cmd_fc_add_default_flow_string,
-		(void *) &cmd_fc_add_default_add_string,
-		(void *) &cmd_fc_add_default_default_string,
-		(void *) &cmd_fc_add_default_port,
-		NULL,
-	},
-};
-
-/*
- * flow del default
- */
-
-struct cmd_fc_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_fc_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_del_default(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result,
-		default_string, "default");
-
-cmdline_parse_inst_t cmd_fc_del_default = {
-	.f = cmd_fc_del_default_parsed,
-	.data = NULL,
-	.help_str = "Flow delete default",
-	.tokens = {
-		(void *) &cmd_fc_del_default_p_string,
-		(void *) &cmd_fc_del_default_pipeline_id,
-		(void *) &cmd_fc_del_default_flow_string,
-		(void *) &cmd_fc_del_default_del_string,
-		(void *) &cmd_fc_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * flow ls
- */
-
-struct cmd_fc_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_fc_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		return;
+	} /* flow ls */
 
-	status = app_pipeline_fc_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
+	printf(CMD_MSG_MISMATCH_ARGS, "flow");
 }
 
-cmdline_parse_token_string_t cmd_fc_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, p_string, "p");
+static cmdline_parse_token_string_t cmd_flow_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fc_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_ls_result, pipeline_id, UINT32);
+static cmdline_parse_token_num_t cmd_flow_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fc_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result,
-	flow_string, "flow");
+static cmdline_parse_token_string_t cmd_flow_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
 
-cmdline_parse_token_string_t cmd_fc_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_flow_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
+		TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fc_ls = {
-	.f = cmd_fc_ls_parsed,
+static cmdline_parse_inst_t cmd_flow = {
+	.f = cmd_flow_parsed,
 	.data = NULL,
-	.help_str = "Flow list",
+	.help_str = "flow add / add bulk / add default / del / del default / ls",
 	.tokens = {
-		(void *) &cmd_fc_ls_p_string,
-		(void *) &cmd_fc_ls_pipeline_id,
-		(void *) &cmd_fc_ls_flow_string,
-		(void *) &cmd_fc_ls_ls_string,
+		(void *) &cmd_flow_p_string,
+		(void *) &cmd_flow_pipeline_id,
+		(void *) &cmd_flow_flow_string,
+		(void *) &cmd_flow_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_del_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_default,
-	(cmdline_parse_inst_t *) &cmd_fc_del_default,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple_all,
-
-	(cmdline_parse_inst_t *) &cmd_fc_ls,
+	(cmdline_parse_inst_t *) &cmd_flow,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
index 9c77500..6c5ed38 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
@@ -102,6 +102,34 @@ int
 app_pipeline_fc_del_default(struct app_params *app,
 	uint32_t pipeline_id);
 
+#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
+#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
+#endif
+
+int
+app_pipeline_fc_load_file_qinq(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
+int
+app_pipeline_fc_load_file_ipv4(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
+int
+app_pipeline_fc_load_file_ipv6(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_flow_classification;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 5/7] examples/ip_pipeline: modifies flow action pipeline CLI
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (3 preceding siblings ...)
  2016-05-20 14:35   ` [PATCH v2 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz, Marcin Kerlin

All commands merged into one: cmd_action_parsed.

modified bulk command:
action flow bulk
File line format:
flow <flow ID>
meter 0 <cir> <pir> <cbs> <pbs> meter 1 <cir> <pir> <cbs> <pbs> meter 2
<cir> <pir> <cbs> <pbs> meter 3 <cir> <pir> <cbs> <pbs>
policer 0 <action> <action> <action> policer 1 <action> <action>
<action> policer 2 <action> <action> <action> policer 3 <action>
<action> <action>
port <port ID>

Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/action.cfg             |   68 +
 examples/ip_pipeline/config/action.sh              |  119 ++
 examples/ip_pipeline/config/action.txt             |    8 +
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1505 +++++++-------------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   11 +
 5 files changed, 707 insertions(+), 1004 deletions(-)
 create mode 100644 examples/ip_pipeline/config/action.cfg
 create mode 100644 examples/ip_pipeline/config/action.sh
 create mode 100644 examples/ip_pipeline/config/action.txt

diff --git a/examples/ip_pipeline/config/action.cfg b/examples/ip_pipeline/config/action.cfg
new file mode 100644
index 0000000..994ae94
--- /dev/null
+++ b/examples/ip_pipeline/config/action.cfg
@@ -0,0 +1,68 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ________________
+; RXQ0.0 --->|                |---> TXQ0.0
+;            |                |
+; RXQ1.0 --->|                |---> TXQ1.0
+;            |      Flow      |
+; RXQ2.0 --->|     Actions    |---> TXQ2.0
+;            |                |
+; RXQ3.0 --->|                |---> TXQ3.0
+;            |________________|
+;
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FLOW_ACTIONS
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
+n_flows = 65536
+n_meters_per_flow = 4
+flow_id_offset = 286; ipdaddr
+ip_hdr_offset = 270
+color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
new file mode 100644
index 0000000..2986ae6
--- /dev/null
+++ b/examples/ip_pipeline/config/action.sh
@@ -0,0 +1,119 @@
+#
+# run ./config/action.sh
+#
+
+p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 0 g G y Y r R
+p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 1 g G y Y r R
+p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 2 g G y Y r R
+p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 3 g G y Y r R
+p 1 action flow 0 port 0
+
+p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 0 g G y Y r R
+p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 1 g G y Y r R
+p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 2 g G y Y r R
+p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 3 g G y Y r R
+p 1 action flow 1 port 1
+
+p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 0 g G y Y r R
+p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 1 g G y Y r R
+p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 2 g G y Y r R
+p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 3 g G y Y r R
+p 1 action flow 2 port 2
+
+p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 0 g G y Y r R
+p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 1 g G y Y r R
+p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 2 g G y Y r R
+p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 3 g G y Y r R
+p 1 action flow 3 port 3
+
+#p 1 action flow bulk ./config/action.txt
+
+#p 1 action flow ls
+
+p 1 action flow 0 stats
+p 1 action flow 1 stats
+p 1 action flow 2 stats
+p 1 action flow 3 stats
+
+p 1 action dscp 0 class 0 color G
+p 1 action dscp 1 class 1 color G
+p 1 action dscp 2 class 2 color G
+p 1 action dscp 3 class 3 color G
+p 1 action dscp 4 class 0 color G
+p 1 action dscp 5 class 1 color G
+p 1 action dscp 6 class 2 color G
+p 1 action dscp 7 class 3 color G
+p 1 action dscp 8 class 0 color G
+p 1 action dscp 9 class 1 color G
+p 1 action dscp 10 class 2 color G
+p 1 action dscp 11 class 3 color G
+p 1 action dscp 12 class 0 color G
+p 1 action dscp 13 class 1 color G
+p 1 action dscp 14 class 2 color G
+p 1 action dscp 15 class 3 color G
+p 1 action dscp 16 class 0 color G
+p 1 action dscp 17 class 1 color G
+p 1 action dscp 18 class 2 color G
+p 1 action dscp 19 class 3 color G
+p 1 action dscp 20 class 0 color G
+p 1 action dscp 21 class 1 color G
+p 1 action dscp 22 class 2 color G
+p 1 action dscp 23 class 3 color G
+p 1 action dscp 24 class 0 color G
+p 1 action dscp 25 class 1 color G
+p 1 action dscp 26 class 2 color G
+p 1 action dscp 27 class 3 color G
+p 1 action dscp 27 class 0 color G
+p 1 action dscp 29 class 1 color G
+p 1 action dscp 30 class 2 color G
+p 1 action dscp 31 class 3 color G
+p 1 action dscp 32 class 0 color G
+p 1 action dscp 33 class 1 color G
+p 1 action dscp 34 class 2 color G
+p 1 action dscp 35 class 3 color G
+p 1 action dscp 36 class 0 color G
+p 1 action dscp 37 class 1 color G
+p 1 action dscp 38 class 2 color G
+p 1 action dscp 39 class 3 color G
+p 1 action dscp 40 class 0 color G
+p 1 action dscp 41 class 1 color G
+p 1 action dscp 42 class 2 color G
+p 1 action dscp 43 class 3 color G
+p 1 action dscp 44 class 0 color G
+p 1 action dscp 45 class 1 color G
+p 1 action dscp 46 class 2 color G
+p 1 action dscp 47 class 3 color G
+p 1 action dscp 48 class 0 color G
+p 1 action dscp 49 class 1 color G
+p 1 action dscp 50 class 2 color G
+p 1 action dscp 51 class 3 color G
+p 1 action dscp 52 class 0 color G
+p 1 action dscp 53 class 1 color G
+p 1 action dscp 54 class 2 color G
+p 1 action dscp 55 class 3 color G
+p 1 action dscp 56 class 0 color G
+p 1 action dscp 57 class 1 color G
+p 1 action dscp 58 class 2 color G
+p 1 action dscp 59 class 3 color G
+p 1 action dscp 60 class 0 color G
+p 1 action dscp 61 class 1 color G
+p 1 action dscp 62 class 2 color G
+p 1 action dscp 63 class 3 color G
+
+p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
new file mode 100644
index 0000000..f14207b
--- /dev/null
+++ b/examples/ip_pipeline/config/action.txt
@@ -0,0 +1,8 @@
+#
+# p <pipelineid> action flow bulk ./config/action.txt
+#
+
+flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
+flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
+flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
+flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
index 4012121..7560051 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -43,13 +44,12 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_actions.h"
 #include "hash_func.h"
+#include "parser.h"
 
 /*
  * Flow actions pipeline
@@ -689,1115 +689,612 @@ app_pipeline_fa_dscp_ls(struct app_params *app,
 	return 0;
 }
 
-/*
- * Flow meter configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> meter <meter ID> trtcm <trtcm params>
- */
-
-struct cmd_fa_meter_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
-};
-
-static void
-cmd_fa_meter_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_meter_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->meter_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	flow_params.m[params->meter_id].cir = params->cir;
-	flow_params.m[params->meter_id].pir = params->pir;
-	flow_params.m[params->meter_id].cbs = params->cbs;
-	flow_params.m[params->meter_id].pbs = params->pbs;
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		1 << params->meter_id,
-		0,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_meter_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config = {
-	.f = cmd_fa_meter_config_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (single flow) ",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_p_string,
-		(void *) &cmd_fa_meter_config_pipeline_id,
-		(void *) &cmd_fa_meter_config_flow_string,
-		(void *) &cmd_fa_meter_config_flow_id,
-		(void *) &cmd_fa_meter_config_meter_string,
-		(void *) &cmd_fa_meter_config_meter_id,
-		(void *) &cmd_fa_meter_config_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
-/*
- * Flow meter configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> meter <meter ID> trtcm <trtcm params>
- */
-
-struct cmd_fa_meter_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
-};
-
-static void
-cmd_fa_meter_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
+int
+app_pipeline_fa_load_file(char *filename,
+	uint32_t *flow_ids,
+	struct pipeline_fa_flow_params *p,
+	uint32_t *n_flows,
+	uint32_t *line)
 {
-	struct cmd_fa_meter_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
 
-	if ((params->n_flows == 0) ||
-		(params->meter_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(flow_ids == NULL) ||
+		(p == NULL) ||
+		(n_flows == NULL) ||
+		(*n_flows == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
-		return;
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
 	}
 
-	memset(&flow_template, 0, sizeof(flow_template));
-	flow_template.m[params->meter_id].cir = params->cir;
-	flow_template.m[params->meter_id].pir = params->pir;
-	flow_template.m[params->meter_id].cbs = params->cbs;
-	flow_template.m[params->meter_id].pbs = params->pbs;
+	/* Read file */
+	for (i = 0, l = 1; i < *n_flows; l++) {
+		char *tokens[64];
+		uint32_t n_tokens = RTE_DIM(tokens);
 
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
+		int status;
 
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos],
-			&flow_template,
-			sizeof(flow_template));
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
 
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				1 << params->meter_id,
-				0,
-				0,
-				flow_params);
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
 
-			if (status != 0) {
-				printf("Command failed\n");
 
-				break;
-			}
-		}
+		if ((n_tokens != 64) ||
+			/* flow */
+			strcmp(tokens[0], "flow") ||
+			parser_read_uint32(&flow_ids[i], tokens[1]) ||
+
+			/* meter & policer 0 */
+			strcmp(tokens[2], "meter") ||
+			strcmp(tokens[3], "0") ||
+			strcmp(tokens[4], "trtcm") ||
+			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
+			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
+			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
+			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
+			strcmp(tokens[9], "policer") ||
+			strcmp(tokens[10], "0") ||
+			strcmp(tokens[11], "g") ||
+			string_to_policer_action(tokens[12],
+				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[13], "y") ||
+			string_to_policer_action(tokens[14],
+				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[15], "r") ||
+			string_to_policer_action(tokens[16],
+				&p[i].p[0].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 1 */
+			strcmp(tokens[17], "meter") ||
+			strcmp(tokens[18], "1") ||
+			strcmp(tokens[19], "trtcm") ||
+			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
+			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
+			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
+			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
+			strcmp(tokens[24], "policer") ||
+			strcmp(tokens[25], "1") ||
+			strcmp(tokens[26], "g") ||
+			string_to_policer_action(tokens[27],
+				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[28], "y") ||
+			string_to_policer_action(tokens[29],
+				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[30], "r") ||
+			string_to_policer_action(tokens[31],
+				&p[i].p[1].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 2 */
+			strcmp(tokens[32], "meter") ||
+			strcmp(tokens[33], "2") ||
+			strcmp(tokens[34], "trtcm") ||
+			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
+			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
+			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
+			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
+			strcmp(tokens[39], "policer") ||
+			strcmp(tokens[40], "2") ||
+			strcmp(tokens[41], "g") ||
+			string_to_policer_action(tokens[42],
+				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[43], "y") ||
+			string_to_policer_action(tokens[44],
+				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[45], "r") ||
+			string_to_policer_action(tokens[46],
+				&p[i].p[2].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 3 */
+			strcmp(tokens[47], "meter") ||
+			strcmp(tokens[48], "3") ||
+			strcmp(tokens[49], "trtcm") ||
+			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
+			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
+			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
+			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
+			strcmp(tokens[54], "policer") ||
+			strcmp(tokens[55], "3") ||
+			strcmp(tokens[56], "g") ||
+			string_to_policer_action(tokens[57],
+				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[58], "y") ||
+			string_to_policer_action(tokens[59],
+				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[60], "r") ||
+			string_to_policer_action(tokens[61],
+				&p[i].p[3].action[e_RTE_METER_RED]) ||
+
+			/* port */
+			strcmp(tokens[62], "port") ||
+			parser_read_uint32(&p[i].port_id, tokens[63]))
+			goto error1;
+
+		i++;
 	}
 
-	rte_free(flow_params);
-	rte_free(flow_id);
+	/* Close file */
+	*n_flows = i;
+	fclose(f);
+	return 0;
 
+error1:
+	*line = l;
+	fclose(f);
+	return -1;
 }
 
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config_bulk = {
-	.f = cmd_fa_meter_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_bulk_p_string,
-		(void *) &cmd_fa_meter_config_bulk_pipeline_id,
-		(void *) &cmd_fa_meter_config_bulk_flows_string,
-		(void *) &cmd_fa_meter_config_bulk_n_flows,
-		(void *) &cmd_fa_meter_config_bulk_meter_string,
-		(void *) &cmd_fa_meter_config_bulk_meter_id,
-		(void *) &cmd_fa_meter_config_bulk_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
 /*
- * Flow policer configuration (single flow)
+ * action
  *
- * p <pipeline ID> flow <flow ID> policer <policer ID>
- *    G <action> Y <action> R <action>
+ * flow meter, policer and output port configuration:
+ *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
  *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
-
-struct cmd_fa_policer_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
-};
-
-static void
-cmd_fa_policer_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->policer_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = string_to_policer_action(params->g_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		1 << params->policer_id,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	green_string, "G");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	g_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	yellow_string, "Y");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	y_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	red_string, "R");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	r_action, "R#Y#G#D");
-
-cmdline_parse_inst_t cmd_fa_policer_config = {
-	.f = cmd_fa_policer_config_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_p_string,
-		(void *) &cmd_fa_policer_config_pipeline_id,
-		(void *) &cmd_fa_policer_config_flow_string,
-		(void *) &cmd_fa_policer_config_flow_id,
-		(void *) &cmd_fa_policer_config_policer_string,
-		(void *) &cmd_fa_policer_config_policer_id,
-		(void *) &cmd_fa_policer_config_green_string,
-		(void *) &cmd_fa_policer_config_g_action,
-		(void *) &cmd_fa_policer_config_yellow_string,
-		(void *) &cmd_fa_policer_config_y_action,
-		(void *) &cmd_fa_policer_config_red_string,
-		(void *) &cmd_fa_policer_config_r_action,
-		NULL,
-	},
-};
-
-/*
- * Flow policer configuration (multiple flows)
+ *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
+ *  <action> is one of the following:
+ *      G = recolor to green
+ *      Y = recolor as yellow
+ *      R = recolor as red
+ *      D = drop
  *
- * p <pipeline ID> flows <n_flows> policer <policer ID>
- *    G <action> Y <action> R <action>
+ *    p <pipelineid> action flow <flowid> port <port ID>
  *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
+ *    p <pipelineid> action flow bulk <file>
+ *
+ * flow policer stats read:
+ *    p <pipelineid> action flow <flowid> stats
+ *
+ * flow ls:
+ *    p <pipelineid> action flow ls
+ *
+ * dscp table configuration:
+ *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
+ *
+ * dscp table ls:
+ *    p <pipelineid> action dscp ls
+**/
 
-struct cmd_fa_policer_config_bulk_result {
+struct cmd_action_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
+	cmdline_fixed_string_t action_string;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_fa_policer_config_bulk_parsed(
+cmd_action_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_fa_policer_config_bulk_result *params = parsed_result;
+	struct cmd_action_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id, i;
-	int status;
 
-	if ((params->n_flows == 0) ||
-		(params->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status != 0) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "action");
 		return;
 	}
 
-	memset(&flow_template, 0, sizeof(flow_template));
-
-	status = string_to_policer_action(params->g_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-	 &flow_template.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos], &flow_template,
-			sizeof(flow_template));
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				0,
-				1 << params->policer_id,
-				0,
-				flow_params);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* action flow meter */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "meter") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, meter_id;
+
+		if (n_tokens != 9) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
+			return;
 		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_string, "policer");
 
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_id, UINT32);
+		memset(&flow_params, 0, sizeof(flow_params));
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	green_string, "G");
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	g_action, "R#Y#G#D");
+		if (parser_read_uint32(&meter_id, tokens[3]) ||
+			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
+			printf(CMD_MSG_INVALID_ARG, "meterid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	yellow_string, "Y");
+		if (strcmp(tokens[4], "trtcm")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	y_action, "R#Y#G#D");
+		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "cir");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	red_string, "R");
+		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
+			printf(CMD_MSG_INVALID_ARG, "pir");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	r_action, "R#Y#G#D");
+		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "cbs");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_policer_config_bulk = {
-	.f = cmd_fa_policer_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_bulk_p_string,
-		(void *) &cmd_fa_policer_config_bulk_pipeline_id,
-		(void *) &cmd_fa_policer_config_bulk_flows_string,
-		(void *) &cmd_fa_policer_config_bulk_n_flows,
-		(void *) &cmd_fa_policer_config_bulk_policer_string,
-		(void *) &cmd_fa_policer_config_bulk_policer_id,
-		(void *) &cmd_fa_policer_config_bulk_green_string,
-		(void *) &cmd_fa_policer_config_bulk_g_action,
-		(void *) &cmd_fa_policer_config_bulk_yellow_string,
-		(void *) &cmd_fa_policer_config_bulk_y_action,
-		(void *) &cmd_fa_policer_config_bulk_red_string,
-		(void *) &cmd_fa_policer_config_bulk_r_action,
-		NULL,
-	},
-};
+		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "pbs");
+			return;
+		}
 
-/*
- * Flow output port configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> port <port ID>
- */
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			1 << meter_id,
+			0,
+			0,
+			&flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow meter");
 
-struct cmd_fa_output_port_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t port_string;
-	uint32_t port_id;
-};
+		return;
+	} /* action flow meter */
+
+	/* action flow policer */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "policer") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, policer_id;
+
+		if (n_tokens != 10) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
+			return;
+		}
 
-static void
-cmd_fa_output_port_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
+		memset(&flow_params, 0, sizeof(flow_params));
 
-	flow_params.port_id = params->port_id;
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		0,
-		1,
-		&flow_params);
+		if (parser_read_uint32(&policer_id, tokens[3]) ||
+			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
+			printf(CMD_MSG_INVALID_ARG, "policerid");
+			return;
+		}
 
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (strcmp(tokens[4], "g")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "g");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	p_string, "p");
+		if (string_to_policer_action(tokens[5],
+			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
+			printf(CMD_MSG_INVALID_ARG, "gaction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	pipeline_id, UINT32);
+		if (strcmp(tokens[6], "y")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "y");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_string, "flow");
+		if (string_to_policer_action(tokens[7],
+			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
+			printf(CMD_MSG_INVALID_ARG, "yaction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_id, UINT32);
+		if (strcmp(tokens[8], "r")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "r");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_string, "port");
+		if (string_to_policer_action(tokens[9],
+			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
+			printf(CMD_MSG_INVALID_ARG, "raction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_id, UINT32);
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			0,
+			1 << policer_id,
+			0,
+			&flow_params);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "action flow policer");
 
-cmdline_parse_inst_t cmd_fa_output_port_config = {
-	.f = cmd_fa_output_port_config_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_p_string,
-		(void *) &cmd_fa_output_port_config_pipeline_id,
-		(void *) &cmd_fa_output_port_config_flow_string,
-		(void *) &cmd_fa_output_port_config_flow_id,
-		(void *) &cmd_fa_output_port_config_port_string,
-		(void *) &cmd_fa_output_port_config_port_id,
-		NULL,
-	},
-};
+		return;
+	} /* action flow policer */
+
+	/* action flow port */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "port") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, port_id;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
+			return;
+		}
 
-/*
- * Flow output port configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> ports <n_ports>
- */
+		memset(&flow_params, 0, sizeof(flow_params));
 
-struct cmd_fa_output_port_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t ports_string;
-	uint32_t n_ports;
-};
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-static void
-cmd_fa_output_port_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
+		if (parser_read_uint32(&port_id, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	if (params->n_flows == 0) {
-		printf("Invalid arguments\n");
-		return;
-	}
+		flow_params.port_id = port_id;
 
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			0,
+			0,
+			1,
+			&flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow port");
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
 		return;
-	}
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-		uint32_t port_id = i % params->n_ports;
-
-		flow_id[pos] = i;
-
-		memset(&flow_params[pos], 0, sizeof(flow_params[pos]));
-		flow_params[pos].port_id = port_id;
+	} /* action flow port */
+
+	/* action flow stats */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "stats") == 0)) {
+		struct pipeline_fa_policer_stats stats;
+		uint32_t flow_id, policer_id;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
+			return;
+		}
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-			status = app_pipeline_fa_flow_config_bulk(app,
+		for (policer_id = 0;
+			policer_id < PIPELINE_FA_N_TC_MAX;
+			policer_id++) {
+			status = app_pipeline_fa_flow_policer_stats_read(app,
 				params->pipeline_id,
 				flow_id,
-				pos + 1,
-				0,
-				0,
+				policer_id,
 				1,
-				flow_params);
-
+				&stats);
 			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
+				printf(CMD_MSG_FAIL, "action flow stats");
+				return;
 			}
-		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_ports_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	ports_string, "ports");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fa_output_port_config_bulk = {
-	.f = cmd_fa_output_port_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_bulk_p_string,
-		(void *) &cmd_fa_output_port_config_bulk_pipeline_id,
-		(void *) &cmd_fa_output_port_config_bulk_flows_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_flows,
-		(void *) &cmd_fa_output_port_config_bulk_ports_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_ports,
-		NULL,
-	},
-};
-
-/*
- * Flow DiffServ Code Point (DSCP) translation table configuration
- *
- * p <pipeline ID> dscp <DSCP ID> class <traffic class ID> color <color>
- *
- * <color> = G (green) | Y (yellow) | R (red)
-*/
 
-struct cmd_fa_dscp_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	uint32_t dscp_id;
-	cmdline_fixed_string_t class_string;
-	uint32_t traffic_class_id;
-	cmdline_fixed_string_t color_string;
-	cmdline_fixed_string_t color;
-
-};
-
-static void
-cmd_fa_dscp_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_config_result *params = parsed_result;
-	struct app_params *app = data;
-	enum rte_meter_color color;
-	int status;
+			/* Display stats */
+			printf("\tPolicer: %" PRIu32
+				"\tPkts G: %" PRIu64
+				"\tPkts Y: %" PRIu64
+				"\tPkts R: %" PRIu64
+				"\tPkts D: %" PRIu64 "\n",
+				policer_id,
+				stats.n_pkts[e_RTE_METER_GREEN],
+				stats.n_pkts[e_RTE_METER_YELLOW],
+				stats.n_pkts[e_RTE_METER_RED],
+				stats.n_pkts_drop);
+		}
 
-	status = string_to_color(params->color, &color);
-	if (status) {
-		printf("Invalid color\n");
 		return;
-	}
-
-	status = app_pipeline_fa_dscp_config(app,
-		params->pipeline_id,
-		params->dscp_id,
-		params->traffic_class_id,
-		color);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_string, "dscp");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_dscp_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_class_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	class_string, "class");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_traffic_class_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	traffic_class_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color_string, "color");
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color, "G#Y#R");
+	} /* action flow stats */
+
+	/* action flow bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_fa_flow_params *flow_params;
+		uint32_t *flow_ids, n_flows, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_dscp_config = {
-	.f = cmd_fa_dscp_config_parsed,
-	.data = NULL,
-	.help_str = "Flow DSCP translation table configuration",
-	.tokens = {
-		(void *) &cmd_fa_dscp_config_p_string,
-		(void *) &cmd_fa_dscp_config_pipeline_id,
-		(void *) &cmd_fa_dscp_config_dscp_string,
-		(void *) &cmd_fa_dscp_config_dscp_id,
-		(void *) &cmd_fa_dscp_config_class_string,
-		(void *) &cmd_fa_dscp_config_traffic_class_id,
-		(void *) &cmd_fa_dscp_config_color_string,
-		(void *) &cmd_fa_dscp_config_color,
-		NULL,
-	},
-};
+		filename = tokens[2];
 
-/*
- * Flow policer stats read
- *
- * p <pipeline ID> flow <flow ID> policer <policer ID> stats
- */
+		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
+		flow_ids = malloc(n_flows * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
 
-struct cmd_fa_policer_stats_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t stats_string;
-};
+		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
+		if (flow_params == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(flow_ids);
+			return;
+		}
 
-static void
-cmd_fa_policer_stats_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_stats_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_policer_stats stats;
-	int status;
+		status = app_pipeline_fa_load_file(filename,
+			flow_ids,
+			flow_params,
+			&n_flows,
+			&line);
+		if (status) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_params);
+			free(flow_ids);
+			return;
+		}
 
-	status = app_pipeline_fa_flow_policer_stats_read(app,
-		params->pipeline_id,
-		params->flow_id,
-		params->policer_id,
-		1,
-		&stats);
-	if (status != 0) {
-		printf("Command failed\n");
+		status = app_pipeline_fa_flow_config_bulk(app,
+			params->pipeline_id,
+			flow_ids,
+			n_flows,
+			0xF,
+			0xF,
+			1,
+			flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow bulk");
+
+		free(flow_params);
+		free(flow_ids);
 		return;
-	}
-
-	/* Display stats */
-	printf("\tPkts G: %" PRIu64
-		"\tPkts Y: %" PRIu64
-		"\tPkts R: %" PRIu64
-		"\tPkts D: %" PRIu64 "\n",
-		stats.n_pkts[e_RTE_METER_GREEN],
-		stats.n_pkts[e_RTE_METER_YELLOW],
-		stats.n_pkts[e_RTE_METER_RED],
-		stats.n_pkts_drop);
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	stats_string, "stats");
-
-cmdline_parse_inst_t cmd_fa_policer_stats = {
-	.f = cmd_fa_policer_stats_parsed,
-	.data = NULL,
-	.help_str = "Flow policer stats read",
-	.tokens = {
-		(void *) &cmd_fa_policer_stats_p_string,
-		(void *) &cmd_fa_policer_stats_pipeline_id,
-		(void *) &cmd_fa_policer_stats_flow_string,
-		(void *) &cmd_fa_policer_stats_flow_id,
-		(void *) &cmd_fa_policer_stats_policer_string,
-		(void *) &cmd_fa_policer_stats_policer_id,
-		(void *) &cmd_fa_policer_stats_string,
-		NULL,
-	},
-};
-
-/*
- * Flow list
- *
- * p <pipeline ID> flow ls
- */
+	} /* action flow bulk */
+
+	/* action flow ls */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		(strcmp(tokens[1], "ls") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
+			return;
+		}
 
-struct cmd_fa_flow_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t actions_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_fa_flow_ls(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow ls");
 
-static void
-cmd_fa_flow_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_flow_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fa_flow_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		return;
+	} /* action flow ls */
+
+	/* action dscp */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "dscp") == 0) &&
+		strcmp(tokens[1], "ls")) {
+		uint32_t dscp_id, tc_id;
+		enum rte_meter_color color;
+
+		if (n_tokens != 6) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	p_string, "p");
+		if (parser_read_uint32(&dscp_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "dscpid");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_flow_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_flow_ls_result,
-	pipeline_id, UINT32);
+		if (strcmp(tokens[2], "class")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "class");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	flow_string, "flow");
+		if (parser_read_uint32(&tc_id, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "classid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_actions_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	actions_string, "actions");
+		if (strcmp(tokens[4], "color")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "color");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	ls_string, "ls");
+		if (string_to_color(tokens[5], &color)) {
+			printf(CMD_MSG_INVALID_ARG, "colorid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_flow_ls = {
-	.f = cmd_fa_flow_ls_parsed,
-	.data = NULL,
-	.help_str = "Flow actions list",
-	.tokens = {
-		(void *) &cmd_fa_flow_ls_p_string,
-		(void *) &cmd_fa_flow_ls_pipeline_id,
-		(void *) &cmd_fa_flow_ls_flow_string,
-		(void *) &cmd_fa_flow_ls_actions_string,
-		(void *) &cmd_fa_flow_ls_ls_string,
-		NULL,
-	},
-};
+		status = app_pipeline_fa_dscp_config(app,
+			params->pipeline_id,
+			dscp_id,
+			tc_id,
+			color);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "action dscp");
 
-/*
- * Flow DiffServ Code Point (DSCP) translation table list
- *
- * p <pipeline ID> dscp ls
- */
+		return;
+	} /* action dscp */
+
+	/* action dscp ls */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "dscp") == 0) &&
+		(strcmp(tokens[1], "ls") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
+			return;
+		}
 
-struct cmd_fa_dscp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_fa_dscp_ls(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "action dscp ls");
 
-static void
-cmd_fa_dscp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		return;
+	} /* action dscp ls */
 
-	status = app_pipeline_fa_dscp_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
+	printf(CMD_MSG_FAIL, "action");
 }
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	p_string, "p");
+static cmdline_parse_token_string_t cmd_action_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fa_dscp_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	pipeline_id, UINT32);
+static cmdline_parse_token_num_t cmd_action_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	dscp_string, "dscp");
+static cmdline_parse_token_string_t cmd_action_action_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_action_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fa_dscp_ls = {
-	.f = cmd_fa_dscp_ls_parsed,
+cmdline_parse_inst_t cmd_action = {
+	.f = cmd_action_parsed,
 	.data = NULL,
-	.help_str = "Flow DSCP translaton table list",
+	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
 	.tokens = {
-		(void *) &cmd_fa_dscp_ls_p_string,
-		(void *) &cmd_fa_dscp_ls_pipeline_id,
-		(void *) &cmd_fa_dscp_ls_dscp_string,
-		(void *) &cmd_fa_dscp_ls_string,
+		(void *) &cmd_action_p_string,
+		(void *) &cmd_action_pipeline_id,
+		(void *) &cmd_action_action_string,
+		(void *) &cmd_action_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config,
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_stats,
-	(cmdline_parse_inst_t *) &cmd_fa_flow_ls,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_ls,
+	(cmdline_parse_inst_t *) &cmd_action,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
index f2cd0cb..9c60974 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
@@ -73,6 +73,17 @@ app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
 	int clear,
 	struct pipeline_fa_policer_stats *stats);
 
+#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
+#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
+#endif
+
+int
+app_pipeline_fa_load_file(char *filename,
+	uint32_t *flow_ids,
+	struct pipeline_fa_flow_params *p,
+	uint32_t *n_flows,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_flow_actions;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 6/7] examples/ip_pipeline: modifies routing pipeline CLI
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (4 preceding siblings ...)
  2016-05-20 14:35   ` [PATCH v2 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-05-20 14:35   ` [PATCH v2 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Several routing commands are merged into two commands:
route and arp - these two commands are handled by cli library.
Rest of the commands are handled internaly by the pipeline code.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/l2fwd.cfg            |    5 +-
 examples/ip_pipeline/config/l3fwd.cfg            |    9 +-
 examples/ip_pipeline/config/l3fwd.sh             |   32 +-
 examples/ip_pipeline/config/l3fwd_arp.cfg        |   70 +
 examples/ip_pipeline/config/l3fwd_arp.sh         |   43 +
 examples/ip_pipeline/pipeline/pipeline_routing.c | 1636 ++++++----------------
 6 files changed, 551 insertions(+), 1244 deletions(-)
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh

diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
index c743a14..a1df9e6 100644
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ b/examples/ip_pipeline/config/l2fwd.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,9 @@
 ;            |________________|
 ;
 
+[EAL]
+log_level = 0
+
 [PIPELINE0]
 type = MASTER
 core = 0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
index 5449dc3..02c8f36 100644
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ b/examples/ip_pipeline/config/l3fwd.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,9 @@
 ; 2	Ethernet header		256 		14
 ; 3	IPv4 header		270 		20
 
+[EAL]
+log_level = 0
+
 [PIPELINE0]
 type = MASTER
 core = 0
@@ -59,5 +62,7 @@ type = ROUTING
 core = 1
 pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
 pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet; encap = ethernet / ethernet_qinq / ethernet_mpls
+encap = ethernet
+;encap = ethernet_qinq
+;encap = ethernet_mpls
 ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
index 2774010..47406aa 100644
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ b/examples/ip_pipeline/config/l3fwd.sh
@@ -1,9 +1,33 @@
+#
+# run ./config/l3fwd.sh
+#
+
 ################################################################################
 # Routing: encap = ethernet, arp = off
 ################################################################################
 p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
+p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
+p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
+p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
+p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
 p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_qinq, arp = off
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
+#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
+#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
+#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
+#p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_mpls, arp = off
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
+#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
+#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
+#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
+#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
new file mode 100644
index 0000000..2c63c8f
--- /dev/null
+++ b/examples/ip_pipeline/config/l3fwd_arp.cfg
@@ -0,0 +1,70 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             _______________
+; RXQ0.0 --->|               |---> TXQ0.0
+;            |               |
+; RXQ1.0 --->|               |---> TXQ1.0
+;            |    Routing    |
+; RXQ2.0 --->|               |---> TXQ2.0
+;            |               |
+; RXQ3.0 --->|               |---> TXQ3.0
+;            |_______________|
+;                    |
+;                    +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = ROUTING
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+encap = ethernet
+;encap = ethernet_qinq
+;encap = ethernet_mpls
+n_arp_entries = 1024
+ip_hdr_offset = 270
+arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
new file mode 100644
index 0000000..20bea58
--- /dev/null
+++ b/examples/ip_pipeline/config/l3fwd_arp.sh
@@ -0,0 +1,43 @@
+#
+# run ./config/l3fwd_arp.sh
+#
+
+################################################################################
+# ARP
+################################################################################
+p 1 arp add default 4 #SINK0
+p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
+p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
+p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
+p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
+p 1 arp ls
+
+################################################################################
+# Routing: encap = ethernet, arp = on
+################################################################################
+p 1 route add default 4 #SINK0
+p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
+p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
+p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
+p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
+p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_qinq, arp = on
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
+#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
+#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
+#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
+#p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_mpls, arp = on
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
+#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
+#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
+#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
+#p 1 route ls
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index eab89f2..c68e470 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,11 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_routing.h"
+#include "parser.h"
 
 struct app_pipeline_routing_route {
 	struct pipeline_routing_route_key key;
@@ -853,1376 +852,539 @@ app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
 	return 0;
 }
 
-static int
-parse_labels(char *string, uint32_t *labels, uint32_t *n_labels)
-{
-	uint32_t n_max_labels = *n_labels, count = 0;
-
-	/* Check for void list of labels */
-	if (strcmp(string, "<void>") == 0) {
-		*n_labels = 0;
-		return 0;
-	}
-
-	/* At least one label should be present */
-	for ( ; (*string != '\0'); ) {
-		char *next;
-		int value;
-
-		if (count >= n_max_labels)
-			return -1;
-
-		if (count > 0) {
-			if (string[0] != ':')
-				return -1;
-
-			string++;
-		}
-
-		value = strtol(string, &next, 10);
-		if (next == string)
-			return -1;
-		string = next;
-
-		labels[count++] = (uint32_t) value;
-	}
-
-	*n_labels = count;
-	return 0;
-}
-
 /*
- * route add (mpls = no, qinq = no, arp = no)
- */
-
-struct cmd_route_add1_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-};
-
-static void
-cmd_route_add1_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add1_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = 0;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add1_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add1_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add1_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add1_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add1_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add1_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add1_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add1_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add1_result, macaddr);
-
-static cmdline_parse_inst_t cmd_route_add1 = {
-	.f = cmd_route_add1_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add1_p_string,
-		(void *)&cmd_route_add1_p,
-		(void *)&cmd_route_add1_route_string,
-		(void *)&cmd_route_add1_add_string,
-		(void *)&cmd_route_add1_ip,
-		(void *)&cmd_route_add1_depth,
-		(void *)&cmd_route_add1_port_string,
-		(void *)&cmd_route_add1_port,
-		(void *)&cmd_route_add1_ether_string,
-		(void *)&cmd_route_add1_macaddr,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = no, arp = yes)
+ * route
+ *
+ * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
+ *
+ * route add default:
+ *    p <pipelineid> route add default <portid>
+ *
+ * route del:
+ *    p <pipelineid> route del <ipaddr> <depth>
+ *
+ * route del default:
+ *    p <pipelineid> route del default
+ *
+ * route ls:
+ *    p <pipelineid> route ls
  */
 
-struct cmd_route_add2_result {
+struct cmd_route_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_route_add2_parsed(
+cmd_route_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_route_add2_result *params = parsed_result;
+	struct cmd_route_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add2_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add2_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add2_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add2_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add2_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, nh_ip);
-
-static cmdline_parse_inst_t cmd_route_add2 = {
-	.f = cmd_route_add2_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add2_p_string,
-		(void *)&cmd_route_add2_p,
-		(void *)&cmd_route_add2_route_string,
-		(void *)&cmd_route_add2_add_string,
-		(void *)&cmd_route_add2_ip,
-		(void *)&cmd_route_add2_depth,
-		(void *)&cmd_route_add2_port_string,
-		(void *)&cmd_route_add2_port,
-		(void *)&cmd_route_add2_ether_string,
-		(void *)&cmd_route_add2_nh_ip,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = no)
- */
 
-struct cmd_route_add3_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add3_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add3_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf(CMD_MSG_TOO_MANY_ARGS, "route");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add3_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add3_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add3_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add3_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add3_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add3_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, port_string,
-	"port");
 
-static cmdline_parse_token_num_t cmd_route_add3_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add3_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add3_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add3_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, qinq_string,
-	"qinq");
-
-static cmdline_parse_token_num_t cmd_route_add3_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, svlan, UINT32);
-
-static cmdline_parse_token_num_t cmd_route_add3_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, cvlan, UINT32);
-
-static cmdline_parse_inst_t cmd_route_add3 = {
-	.f = cmd_route_add3_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add3_p_string,
-		(void *)&cmd_route_add3_p,
-		(void *)&cmd_route_add3_route_string,
-		(void *)&cmd_route_add3_add_string,
-		(void *)&cmd_route_add3_ip,
-		(void *)&cmd_route_add3_depth,
-		(void *)&cmd_route_add3_port_string,
-		(void *)&cmd_route_add3_port,
-		(void *)&cmd_route_add3_ether_string,
-		(void *)&cmd_route_add3_macaddr,
-		(void *)&cmd_route_add3_qinq_string,
-		(void *)&cmd_route_add3_svlan,
-		(void *)&cmd_route_add3_cvlan,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = yes)
- */
-
-struct cmd_route_add4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add4_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add4_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add4_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add4_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, ip);
+	/* route add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_route_key key;
+		struct pipeline_routing_route_data route_data;
+		struct in_addr ipv4, nh_ipv4;
+		struct ether_addr mac_addr;
+		uint32_t depth, port_id, svlan, cvlan, i;
+		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
+		uint32_t n_labels = RTE_DIM(mpls_labels);
+
+		memset(&key, 0, sizeof(key));
+		memset(&route_data, 0, sizeof(route_data));
+
+		if (n_tokens < 7) {
+			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
+			return;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, depth, UINT32);
+		if (parse_ipv4_addr(tokens[1], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, port_string,
-	"port");
+		if (parser_read_uint32(&depth, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, port, UINT32);
+		if (strcmp(tokens[3], "port")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, ether_string,
-	"ether");
+		if (parser_read_uint32(&port_id, tokens[4])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static cmdline_parse_token_ipaddr_t cmd_route_add4_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, nh_ip);
+		if (strcmp(tokens[5], "ether")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, qinq_string,
-	"qinq");
+		if (parse_mac_addr(tokens[6], &mac_addr)) {
+			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
+				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
+				return;
+			}
 
-static cmdline_parse_token_num_t cmd_route_add4_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, svlan, UINT32);
+			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, cvlan, UINT32);
+		if (n_tokens > 7) {
+			if (strcmp(tokens[7], "mpls") == 0) {
+				if (n_tokens != 9) {
+					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
+					return;
+				}
+
+				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
+					printf(CMD_MSG_INVALID_ARG, "mpls labels");
+					return;
+				}
+
+				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
+			} else if (strcmp(tokens[7], "qinq") == 0) {
+				if (n_tokens != 10) {
+					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
+					return;
+				}
+
+				if (parser_read_uint32(&svlan, tokens[8])) {
+					printf(CMD_MSG_INVALID_ARG, "svlan");
+					return;
+				}
+				if (parser_read_uint32(&cvlan, tokens[9])) {
+					printf(CMD_MSG_INVALID_ARG, "cvlan");
+					return;
+				}
+
+				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
+			} else {
+				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
+				return;
+			}
+		}
 
-static cmdline_parse_inst_t cmd_route_add4 = {
-	.f = cmd_route_add4_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add4_p_string,
-		(void *)&cmd_route_add4_p,
-		(void *)&cmd_route_add4_route_string,
-		(void *)&cmd_route_add4_add_string,
-		(void *)&cmd_route_add4_ip,
-		(void *)&cmd_route_add4_depth,
-		(void *)&cmd_route_add4_port_string,
-		(void *)&cmd_route_add4_port,
-		(void *)&cmd_route_add4_ether_string,
-		(void *)&cmd_route_add4_nh_ip,
-		(void *)&cmd_route_add4_qinq_string,
-		(void *)&cmd_route_add4_svlan,
-		(void *)&cmd_route_add4_cvlan,
-		NULL,
-	},
-};
+		switch (route_data.flags) {
+		case 0:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			break;
 
-/*
- * route add (mpls = yes, qinq = no, arp = no)
- */
+		case PIPELINE_ROUTING_ROUTE_ARP:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			break;
 
-struct cmd_route_add5_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
+		case PIPELINE_ROUTING_ROUTE_MPLS:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			for (i = 0; i < n_labels; i++)
+				route_data.l2.mpls.labels[i] = mpls_labels[i];
+			route_data.l2.mpls.n_labels = n_labels;
+			break;
 
-static void
-cmd_route_add5_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add5_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
+		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			for (i = 0; i < n_labels; i++)
+				route_data.l2.mpls.labels[i] = mpls_labels[i];
+			route_data.l2.mpls.n_labels = n_labels;
+			break;
 
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
+		case PIPELINE_ROUTING_ROUTE_QINQ:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			route_data.l2.qinq.svlan = svlan;
+			route_data.l2.qinq.cvlan = cvlan;
+			break;
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
+		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
+		default:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			route_data.l2.qinq.svlan = svlan;
+			route_data.l2.qinq.cvlan = cvlan;
+			break;
+		}
 
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.depth = depth;
 
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
+		status = app_pipeline_routing_add_route(app,
+			params->p,
+			&key,
+			&route_data);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route add");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add5_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add5_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add5_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add5_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add5_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add5_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add5_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add5_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add5_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add5 = {
-	.f = cmd_route_add5_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add5_p_string,
-		(void *)&cmd_route_add5_p,
-		(void *)&cmd_route_add5_route_string,
-		(void *)&cmd_route_add5_add_string,
-		(void *)&cmd_route_add5_ip,
-		(void *)&cmd_route_add5_depth,
-		(void *)&cmd_route_add5_port_string,
-		(void *)&cmd_route_add5_port,
-		(void *)&cmd_route_add5_ether_string,
-		(void *)&cmd_route_add5_macaddr,
-		(void *)&cmd_route_add5_mpls_string,
-		(void *)&cmd_route_add5_mpls_labels,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = yes, qinq = no, arp = yes)
- */
+	} /* route add */
 
-struct cmd_route_add6_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
+	/* route add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-static void
-cmd_route_add6_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add6_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
+			return;
+		}
 
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
+		status = app_pipeline_routing_add_default_route(app,
+			params->p,
+			port_id);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route add default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add6_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add6_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add6_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, add_string,
-	"add");
+	} /* route add default */
 
-static cmdline_parse_token_ipaddr_t cmd_route_add6_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, ip);
+	/* route del*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_route_key key;
+		struct in_addr ipv4;
+		uint32_t depth;
 
-static cmdline_parse_token_num_t cmd_route_add6_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, depth, UINT32);
+		memset(&key, 0, sizeof(key));
 
-static cmdline_parse_token_string_t cmd_route_add6_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add6_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add6_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, nh_ip);
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add6 = {
-	.f = cmd_route_add6_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add6_p_string,
-		(void *)&cmd_route_add6_p,
-		(void *)&cmd_route_add6_route_string,
-		(void *)&cmd_route_add6_add_string,
-		(void *)&cmd_route_add6_ip,
-		(void *)&cmd_route_add6_depth,
-		(void *)&cmd_route_add6_port_string,
-		(void *)&cmd_route_add6_port,
-		(void *)&cmd_route_add6_ether_string,
-		(void *)&cmd_route_add6_nh_ip,
-		(void *)&cmd_route_add6_mpls_string,
-		(void *)&cmd_route_add6_mpls_labels,
-		NULL,
-	},
-};
-
-/*
- * route del
- */
-
-struct cmd_route_del_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-};
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route del");
+			return;
+		}
 
-static void
-cmd_route_del_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_del_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
+		if (parse_ipv4_addr(tokens[1], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	int status;
+		if (parser_read_uint32(&depth, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.depth = depth;
 
-	status = app_pipeline_routing_delete_route(app, params->p, &key);
+		status = app_pipeline_routing_delete_route(app, params->p, &key);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,
-	"del");
-
-static cmdline_parse_token_ipaddr_t cmd_route_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_del_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_del_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT32);
-
-static cmdline_parse_inst_t cmd_route_del = {
-	.f = cmd_route_del_parsed,
-	.data = NULL,
-	.help_str = "Route delete",
-	.tokens = {
-		(void *)&cmd_route_del_p_string,
-		(void *)&cmd_route_del_p,
-		(void *)&cmd_route_del_route_string,
-		(void *)&cmd_route_del_del_string,
-		(void *)&cmd_route_del_ip,
-		(void *)&cmd_route_del_depth,
-		NULL,
-	},
-};
-
-/*
- * route add default
- */
-
-struct cmd_route_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_route_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	} /* route del */
+
+	/* route del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
+			return;
+		}
 
-	status = app_pipeline_routing_add_default_route(app, params->p,
-			params->port);
+		status = app_pipeline_routing_delete_default_route(app,
+			params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route del default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, p, UINT32);
-
-cmdline_parse_token_string_t cmd_route_add_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		route_string, "route");
-
-cmdline_parse_token_string_t cmd_route_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_route_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-	default_string, "default");
-
-cmdline_parse_token_num_t cmd_route_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result,
-		port, UINT32);
+	} /* route del default */
 
-cmdline_parse_inst_t cmd_route_add_default = {
-	.f = cmd_route_add_default_parsed,
-	.data = NULL,
-	.help_str = "Route default set",
-	.tokens = {
-		(void *)&cmd_route_add_default_p_string,
-		(void *)&cmd_route_add_default_p,
-		(void *)&cmd_route_add_default_route_string,
-		(void *)&cmd_route_add_default_add_string,
-		(void *)&cmd_route_add_default_default_string,
-		(void *)&cmd_route_add_default_port,
-		NULL,
-	},
-};
-
-/*
- * route del default
- */
-
-struct cmd_route_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_route_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_route_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	/* route ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
+			return;
+		}
 
-	status = app_pipeline_routing_delete_default_route(app, params->p);
+		status = app_pipeline_routing_route_ls(app, params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route ls");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		del_string, "del");
-
-static cmdline_parse_token_string_t cmd_route_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-	default_string, "default");
-
-
-static cmdline_parse_inst_t cmd_route_del_default = {
-	.f = cmd_route_del_default_parsed,
-	.data = NULL,
-	.help_str = "Route default clear",
-	.tokens = {
-		(void *)&cmd_route_del_default_p_string,
-		(void *)&cmd_route_del_default_p,
-		(void *)&cmd_route_del_default_route_string,
-		(void *)&cmd_route_del_default_del_string,
-		(void *)&cmd_route_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * route ls
- */
+	} /* route ls */
 
-struct cmd_route_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_route_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_routing_route_ls(app, params->p);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
+	printf(CMD_MSG_MISMATCH_ARGS, "route");
 }
 
-static cmdline_parse_token_string_t cmd_route_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, p_string, "p");
+static cmdline_parse_token_string_t cmd_route_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
 
-static cmdline_parse_token_num_t cmd_route_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_ls_result, p, UINT32);
+static cmdline_parse_token_num_t cmd_route_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
 
-static cmdline_parse_token_string_t cmd_route_ls_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result,
-	route_string, "route");
+static cmdline_parse_token_string_t cmd_route_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
 
-static cmdline_parse_token_string_t cmd_route_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_route_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_inst_t cmd_route_ls = {
-	.f = cmd_route_ls_parsed,
+static cmdline_parse_inst_t cmd_route = {
+	.f = cmd_route_parsed,
 	.data = NULL,
-	.help_str = "Route list",
+	.help_str = "route add / add default / del / del default / ls",
 	.tokens = {
-		(void *)&cmd_route_ls_p_string,
-		(void *)&cmd_route_ls_p,
-		(void *)&cmd_route_ls_route_string,
-		(void *)&cmd_route_ls_ls_string,
+		(void *)&cmd_route_p_string,
+		(void *)&cmd_route_p,
+		(void *)&cmd_route_route_string,
+		(void *)&cmd_route_multi_string,
 		NULL,
 	},
 };
 
 /*
- * arp add
+ * arp
+ *
+ * arp add:
+ *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
+ *
+ * arp add default:
+ *    p <pipelineid> arp add default <portid>
+ *
+ * arp del:
+ *    p <pipelineid> arp del <portid> <ipaddr>
+ *
+ * arp del default:
+ *    p <pipelineid> arp del default
+ *
+ * arp ls:
+ *    p <pipelineid> arp ls
  */
 
-struct cmd_arp_add_result {
+struct cmd_arp_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
-	struct ether_addr macaddr;
-
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_arp_add_parsed(
+cmd_arp_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_arp_add_result *params = parsed_result;
+	struct cmd_arp_result *params = parsed_result;
 	struct app_params *app = data;
 
-	struct pipeline_routing_arp_key key;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.port_id = params->port_id;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
-
-	status = app_pipeline_routing_add_arp_entry(app,
-		params->p,
-		&key,
-		&params->macaddr);
-
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_add_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_add_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, "arp");
 
-static cmdline_parse_token_string_t cmd_arp_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, "add");
+	/* arp add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_arp_key key;
+		struct in_addr ipv4;
+		struct ether_addr mac_addr;
+		uint32_t port_id;
 
-static cmdline_parse_token_num_t cmd_arp_add_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, port_id, UINT32);
-
-static cmdline_parse_token_ipaddr_t cmd_arp_add_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_add_result, ip);
-
-static cmdline_parse_token_etheraddr_t cmd_arp_add_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, macaddr);
-
-static cmdline_parse_inst_t cmd_arp_add = {
-	.f = cmd_arp_add_parsed,
-	.data = NULL,
-	.help_str = "ARP add",
-	.tokens = {
-		(void *)&cmd_arp_add_p_string,
-		(void *)&cmd_arp_add_p,
-		(void *)&cmd_arp_add_arp_string,
-		(void *)&cmd_arp_add_add_string,
-		(void *)&cmd_arp_add_port_id,
-		(void *)&cmd_arp_add_ip,
-		(void *)&cmd_arp_add_macaddr,
-		NULL,
-	},
-};
+		memset(&key, 0, sizeof(key));
 
-/*
- * arp del
- */
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
+			return;
+		}
 
-struct cmd_arp_del_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
-};
+		if (parser_read_uint32(&port_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static void
-cmd_arp_del_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_del_result *params = parsed_result;
-	struct app_params *app = data;
+		if (parse_ipv4_addr(tokens[2], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	struct pipeline_routing_arp_key key;
-	int status;
+		if (parse_mac_addr(tokens[3], &mac_addr)) {
+			printf(CMD_MSG_INVALID_ARG, "macaddr");
+			return;
+		}
 
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.port_id = params->port_id;
+		key.type = PIPELINE_ROUTING_ARP_IPV4;
+		key.key.ipv4.port_id = port_id;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
 
-	status = app_pipeline_routing_delete_arp_entry(app, params->p, &key);
+		status = app_pipeline_routing_add_arp_entry(app,
+			params->p,
+			&key,
+			&mac_addr);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp add");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arp");
+	} /* arp add */
 
-static cmdline_parse_token_string_t cmd_arp_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, "del");
-
-static cmdline_parse_token_num_t cmd_arp_del_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, port_id, UINT32);
-
-static cmdline_parse_token_ipaddr_t cmd_arp_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_del_result, ip);
-
-static cmdline_parse_inst_t cmd_arp_del = {
-	.f = cmd_arp_del_parsed,
-	.data = NULL,
-	.help_str = "ARP delete",
-	.tokens = {
-		(void *)&cmd_arp_del_p_string,
-		(void *)&cmd_arp_del_p,
-		(void *)&cmd_arp_del_arp_string,
-		(void *)&cmd_arp_del_del_string,
-		(void *)&cmd_arp_del_port_id,
-		(void *)&cmd_arp_del_ip,
-		NULL,
-	},
-};
+	/* arp add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-/*
- * arp add default
- */
-
-struct cmd_arp_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port_id;
-};
-
-static void
-cmd_arp_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_add_default_result *params = parsed_result;
-	struct app_params *app = data;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
+			return;
+		}
 
-	int status;
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	status = app_pipeline_routing_add_default_arp_entry(app,
-		params->p,
-		params->port_id);
+		status = app_pipeline_routing_add_default_arp_entry(app,
+			params->p,
+			port_id);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp add default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, arp_string,
-	"arp");
+	} /* arp add default */
 
-static cmdline_parse_token_string_t cmd_arp_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, add_string,
-	"add");
+	/* arp del*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_arp_key key;
+		struct in_addr ipv4;
+		uint32_t port_id;
 
-static cmdline_parse_token_string_t cmd_arp_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result,
-		default_string, "default");
+		memset(&key, 0, sizeof(key));
 
-static cmdline_parse_token_num_t cmd_arp_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, port_id,
-	UINT32);
-
-static cmdline_parse_inst_t cmd_arp_add_default = {
-	.f = cmd_arp_add_default_parsed,
-	.data = NULL,
-	.help_str = "ARP add default",
-	.tokens = {
-		(void *)&cmd_arp_add_default_p_string,
-		(void *)&cmd_arp_add_default_p,
-		(void *)&cmd_arp_add_default_arp_string,
-		(void *)&cmd_arp_add_default_add_string,
-		(void *)&cmd_arp_add_default_default_string,
-		(void *)&cmd_arp_add_default_port_id,
-		NULL,
-	},
-};
-
-/*
- * arp del default
- */
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
+			return;
+		}
 
-struct cmd_arp_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
+		if (parser_read_uint32(&port_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static void
-cmd_arp_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_del_default_result *params = parsed_result;
-	struct app_params *app = data;
+		if (parse_ipv4_addr(tokens[2], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	int status;
+		key.type = PIPELINE_ROUTING_ARP_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.port_id = port_id;
 
-	status = app_pipeline_routing_delete_default_arp_entry(app, params->p);
+		status = app_pipeline_routing_delete_arp_entry(app,
+			params->p,
+			&key);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, arp_string,
-	"arp");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, del_string,
-	"del");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result,
-		default_string, "default");
-
-static cmdline_parse_inst_t cmd_arp_del_default = {
-	.f = cmd_arp_del_default_parsed,
-	.data = NULL,
-	.help_str = "ARP delete default",
-	.tokens = {
-		(void *)&cmd_arp_del_default_p_string,
-		(void *)&cmd_arp_del_default_p,
-		(void *)&cmd_arp_del_default_arp_string,
-		(void *)&cmd_arp_del_default_del_string,
-		(void *)&cmd_arp_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * arp ls
- */
+	} /* arp del */
+
+	/* arp del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+			if (n_tokens != 2) {
+				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
+				return;
+			}
+
+			status = app_pipeline_routing_delete_default_arp_entry(app,
+				params->p);
+			if (status != 0)
+				printf(CMD_MSG_FAIL, "arp del default");
+
+			return;
+	} /* arp del default */
+
+	/* arp ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
+			return;
+		}
 
-struct cmd_arp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_routing_arp_ls(app, params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp ls");
 
-static void
-cmd_arp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing *p;
-
-	p = app_pipeline_data_fe(app, params->p, &pipeline_routing);
-	if (p == NULL)
 		return;
+	} /* arp ls */
 
-	app_pipeline_routing_arp_ls(app, params->p);
+	printf(CMD_MSG_FAIL, "arp");
 }
 
-static cmdline_parse_token_string_t cmd_arp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
-	"p");
+static cmdline_parse_token_string_t cmd_arp_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
 
-static cmdline_parse_token_num_t cmd_arp_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+static cmdline_parse_token_num_t cmd_arp_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
 
-static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
-	"arp");
+static cmdline_parse_token_string_t cmd_arp_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
 
-static cmdline_parse_token_string_t cmd_arp_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_arp_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_inst_t cmd_arp_ls = {
-	.f = cmd_arp_ls_parsed,
+static cmdline_parse_inst_t cmd_arp = {
+	.f = cmd_arp_parsed,
 	.data = NULL,
-	.help_str = "ARP list",
+	.help_str = "arp add / add default / del / del default / ls",
 	.tokens = {
-		(void *)&cmd_arp_ls_p_string,
-		(void *)&cmd_arp_ls_p,
-		(void *)&cmd_arp_ls_arp_string,
-		(void *)&cmd_arp_ls_ls_string,
+		(void *)&cmd_arp_p_string,
+		(void *)&cmd_arp_p,
+		(void *)&cmd_arp_arp_string,
+		(void *)&cmd_arp_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route_add1,
-	(cmdline_parse_inst_t *)&cmd_route_add2,
-	(cmdline_parse_inst_t *)&cmd_route_add3,
-	(cmdline_parse_inst_t *)&cmd_route_add4,
-	(cmdline_parse_inst_t *)&cmd_route_add5,
-	(cmdline_parse_inst_t *)&cmd_route_add6,
-	(cmdline_parse_inst_t *)&cmd_route_del,
-	(cmdline_parse_inst_t *)&cmd_route_add_default,
-	(cmdline_parse_inst_t *)&cmd_route_del_default,
-	(cmdline_parse_inst_t *)&cmd_route_ls,
-	(cmdline_parse_inst_t *)&cmd_arp_add,
-	(cmdline_parse_inst_t *)&cmd_arp_del,
-	(cmdline_parse_inst_t *)&cmd_arp_add_default,
-	(cmdline_parse_inst_t *)&cmd_arp_del_default,
-	(cmdline_parse_inst_t *)&cmd_arp_ls,
+	(cmdline_parse_inst_t *)&cmd_route,
+	(cmdline_parse_inst_t *)&cmd_arp,
 	NULL,
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 7/7] examples/ip_pipeline: update edge router usecase
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (5 preceding siblings ...)
  2016-05-20 14:35   ` [PATCH v2 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
@ 2016-05-20 14:35   ` Piotr Azarewicz
  2016-06-07 20:34   ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
  8 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-05-20 14:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Update edge router usecase config files to use bulk commands.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 .../ip_pipeline/config/edge_router_downstream.cfg  |   30 +++++++++++-----
 .../ip_pipeline/config/edge_router_downstream.sh   |    7 ++--
 .../ip_pipeline/config/edge_router_upstream.cfg    |   36 +++++++++++++------
 .../ip_pipeline/config/edge_router_upstream.sh     |   37 +++++++++-----------
 4 files changed, 67 insertions(+), 43 deletions(-)

diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
index 85bbab8..c6b4e1f 100644
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ b/examples/ip_pipeline/config/edge_router_downstream.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -36,9 +36,9 @@
 ;   network) contains the following functional blocks: Packet RX & Routing,
 ;   Traffic management and Packet TX. The input packets are assumed to be
 ;   IPv4, while the output packets are Q-in-Q IPv4.
-
+;
 ;  A simple implementation for this functional pipeline is presented below.
-
+;
 ;                  Packet Rx &                Traffic Management               Packet Tx
 ;                   Routing                    (Pass-Through)                (Pass-Through)
 ;             _____________________  SWQ0  ______________________  SWQ4  _____________________
@@ -50,11 +50,23 @@
 ;            |                     | SWQ3 |                      | SWQ7 |                     |
 ; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
 ;            |_____________________|      |______________________|      |_____________________|
-;                       |                 _|_ ^ _|_ ^ _|_ ^ _|_ ^
-;                       |                |___|||___|||___|||___||
-;                       +--> SINK0       |___|||___|||___|||___||
-;                      (route miss)        |__|  |__|  |__|  |__|
-;                                          TM0   TM1   TM2   TM3
+;                       |                  |  ^  |  ^  |  ^  |  ^
+;                       |                  |__|  |__|  |__|  |__|
+;                       +--> SINK0          TM0   TM1   TM2   TM3
+;                      (Default)
+;
+; Input packet: Ethernet/IPv4
+; Output packet: Ethernet/QinQ/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
 
 [PIPELINE0]
 type = MASTER
@@ -67,7 +79,7 @@ pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
 pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
 encap = ethernet_qinq
 qinq_sched = test
-ip_hdr_offset = 270; mbuf (128) + headroom (128) + ethernet header (14) = 270
+ip_hdr_offset = 270
 
 [PIPELINE2]
 type = PASS-THROUGH
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
index ce46beb..67c3a0d 100644
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ b/examples/ip_pipeline/config/edge_router_downstream.sh
@@ -1,3 +1,7 @@
+#
+# run ./config/edge_router_downstream.sh
+#
+
 ################################################################################
 # Routing: Ether QinQ, ARP off
 ################################################################################
@@ -6,5 +10,4 @@ p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
 p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
 p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
 p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-
-p 1 route ls
+#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
index a08c5cc..dea42b9 100644
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ b/examples/ip_pipeline/config/edge_router_upstream.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,7 @@
 ;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+
 ;   An edge router typically sits between two networks such as the provider
 ;   core network and the provider access network. A typical packet processing
 ;   pipeline for the upstream traffic (i.e. traffic from access to core
@@ -36,10 +37,10 @@
 ;   Flow classification, Metering, Routing and Packet TX. The input packets
 ;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
 ;  (with variable number of labels per route).
-
+;
 ;   A simple implementation for this functional pipeline is presented below.
-
-;             Packet Rx &       Pass-Through    Flow-Classification   Flow-Actions         Routing
+;
+;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
 :              Firewall
 ;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
 ; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
@@ -51,8 +52,21 @@
 ; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
 ;            |__________|       |__________|       |__________|       |__________|       |__________|
 ;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Route Miss)
+;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
+;
+; Input packet: Ethernet/QinQ/IPv4
+; Output packet: Ethernet/MPLS/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3     QinQ header             270             8
+; 4	IPv4 header		278 		20
 
+[EAL]
+log_level = 0
 
 [PIPELINE0]
 type = MASTER
@@ -72,10 +86,10 @@ core = 2
 pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
 pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
 dma_size = 8
-dma_dst_offset = 128; mbuf (128)
-dma_src_offset = 268; mbuf (128) + headroom (128) + 1st ethertype offset (12) = 268
+dma_dst_offset = 128
+dma_src_offset = 268; 1st Ethertype offset
 dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size = 136
+dma_hash_offset = 136; dma_dst_offset + dma_size
 
 [PIPELINE3]
 type = FLOW_CLASSIFICATION
@@ -86,7 +100,7 @@ n_flows = 65536
 key_size = 8; dma_size
 key_offset = 128; dma_dst_offset
 hash_offset = 136; dma_hash_offset
-flowid_offset = 192; mbuf (128) + 64
+flowid_offset = 192
 
 [PIPELINE4]
 type = FLOW_ACTIONS
@@ -96,7 +110,7 @@ pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
 n_flows = 65536
 n_meters_per_flow = 1
 flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278; mbuf (128) + headroom (128) + ethernet (14) + qinq (8) = 278
+ip_hdr_offset = 278
 color_offset = 196; flowid_offset + sizeof(flow_id)
 
 [PIPELINE5]
@@ -106,5 +120,5 @@ pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
 pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
 encap = ethernet_mpls
 mpls_color_mark = yes
-ip_hdr_offset = 278; mbuf (128) + headroom (128) + ethernet (14) + qinq (8) = 278
+ip_hdr_offset = 278
 color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
index eeba600..5d574c1 100644
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ b/examples/ip_pipeline/config/edge_router_upstream.sh
@@ -1,24 +1,26 @@
-################################################
-# Firewall Rules:4 for 4 ports
-################################################
-p 1 firewall add ipv4 1 0.0.0.0 8 0.0.0.0 10 0 0 0 0 6 1 0
-p 1 firewall add ipv4 1 0.0.0.0 8 0.64.0.0 10 0 0 0 0 6 1 1
-p 1 firewall add ipv4 1 0.0.0.0 8 0.128.0.0 10 0 0 0 0 6 1 2
-p 1 firewall add ipv4 1 0.0.0.0 8 0.192.0.0 10 0 0 0 0 6 1 3
-p 1 firewall add default 4 #SINK0
+#
+# run ./config/edge_router_upstream.sh
+#
 
+################################################################################
+# Firewall
+################################################################################
+p 1 firewall add default 4 #SINK0
+p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
+#p 1 firewall ls
 
 ################################################################################
-# Flow classification
+# Flow Classification
 ################################################################################
 p 3 flow add default 4 #SINK1
-p 3 flow add qinq all 65536 4
+p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
+#p 3 flow ls
 
 ################################################################################
-# Flow Actions - Metering
+# Flow Actions - Metering and Policing
 ################################################################################
-p 4 flows 65536 meter 0 trtcm 1250000000 1250000000 100000000 100000000
-p 4 flows 65536 ports 4
+p 4 action flow bulk ./config/edge_router_upstream_action.txt
+#p 4 action flow ls
 
 ################################################################################
 # Routing: Ether MPLS, ARP off
@@ -28,11 +30,4 @@ p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
 p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
 p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
 p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-
-################################################################################
-# List all configurations
-################################################################################
-p 1 firewall ls
-#p 3 flow ls
-#p 4 flow actions ls
-p 5 route ls
+#p 5 route ls
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (6 preceding siblings ...)
  2016-05-20 14:35   ` [PATCH v2 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
@ 2016-06-07 20:34   ` Thomas Monjalon
  2016-06-08 10:01     ` Azarewicz, PiotrX T
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
  8 siblings, 1 reply; 26+ messages in thread
From: Thomas Monjalon @ 2016-06-07 20:34 UTC (permalink / raw)
  To: Piotr Azarewicz, Michal Jastrzebski; +Cc: dev

> Piotr Azarewicz (7):
>   examples/ip_pipeline: add helper functions for parsing string
>   examples/ip_pipeline: modifies common pipeline CLI
>   examples/ip_pipeline: modifies firewall pipeline CLI
>   examples/ip_pipeline: modifies flow classifications pipeline CLI
>   examples/ip_pipeline: modifies flow action pipeline CLI
>   examples/ip_pipeline: modifies routing pipeline CLI
>   examples/ip_pipeline: update edge router usecase

Please take care of the authorship in patches 2, 3 and 4.
It is probably wrong. You can fix it with git commit --amend --author
in an interactive rebase.
To avoid such issue, you must use git-am to apply patches.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements
  2016-06-07 20:34   ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
@ 2016-06-08 10:01     ` Azarewicz, PiotrX T
  0 siblings, 0 replies; 26+ messages in thread
From: Azarewicz, PiotrX T @ 2016-06-08 10:01 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Jastrzebski, MichalX K

> > Piotr Azarewicz (7):
> >   examples/ip_pipeline: add helper functions for parsing string
> >   examples/ip_pipeline: modifies common pipeline CLI
> >   examples/ip_pipeline: modifies firewall pipeline CLI
> >   examples/ip_pipeline: modifies flow classifications pipeline CLI
> >   examples/ip_pipeline: modifies flow action pipeline CLI
> >   examples/ip_pipeline: modifies routing pipeline CLI
> >   examples/ip_pipeline: update edge router usecase
> 
> Please take care of the authorship in patches 2, 3 and 4.
> It is probably wrong. You can fix it with git commit --amend --author in an
> interactive rebase.
> To avoid such issue, you must use git-am to apply patches.

Thanks Thomas for hints.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 0/7] examples/ip_pipeline: CLI rework and improvements
  2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
                     ` (7 preceding siblings ...)
  2016-06-07 20:34   ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
@ 2016-06-08 10:35   ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
                       ` (7 more replies)
  8 siblings, 8 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Using the latest librte_cmdline improvements, the CLI implementation of the
ip_pipeline application is streamlined and improved, which results in
eliminating thousands of lines of code from the application, thus leading to
code that is easier to maintain and extend.

v3 changes:
- fix the authorship in patches

v2 changes:
- added functions for parsing hex values
- added standard error messages for CLI and file bulk
- for all CLI commands: separate code paths for each flavor of each command
(e.g. route add, route add default, route ls, route del, route del default,
etc do not share any line of code)
- for bulk commands: simplified error checking
- added additional config files

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Daniel Mrzyglod (1):
  examples/ip_pipeline: modifies firewall pipeline CLI

Piotr Azarewicz (4):
  examples/ip_pipeline: add helper functions for parsing string
  examples/ip_pipeline: modifies flow action pipeline CLI
  examples/ip_pipeline: modifies routing pipeline CLI
  examples/ip_pipeline: update edge router usecase

Tomasz Kulasek (2):
  examples/ip_pipeline: modifies common pipeline CLI
  examples/ip_pipeline: modifies flow classifications pipeline CLI

 examples/ip_pipeline/Makefile                      |    1 +
 examples/ip_pipeline/config/action.cfg             |   68 +
 examples/ip_pipeline/config/action.sh              |  119 ++
 examples/ip_pipeline/config/action.txt             |    8 +
 .../ip_pipeline/config/edge_router_downstream.cfg  |   30 +-
 .../ip_pipeline/config/edge_router_downstream.sh   |    7 +-
 .../ip_pipeline/config/edge_router_upstream.cfg    |   36 +-
 .../ip_pipeline/config/edge_router_upstream.sh     |   37 +-
 examples/ip_pipeline/config/firewall.cfg           |   68 +
 examples/ip_pipeline/config/firewall.sh            |   13 +
 examples/ip_pipeline/config/firewall.txt           |    9 +
 examples/ip_pipeline/config/flow.cfg               |   72 +
 examples/ip_pipeline/config/flow.sh                |   25 +
 examples/ip_pipeline/config/flow.txt               |   17 +
 examples/ip_pipeline/config/l2fwd.cfg              |    5 +-
 examples/ip_pipeline/config/l3fwd.cfg              |    9 +-
 examples/ip_pipeline/config/l3fwd.sh               |   32 +-
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 +
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 +
 examples/ip_pipeline/config_parse.c                |  257 +--
 examples/ip_pipeline/parser.c                      |  745 +++++++
 examples/ip_pipeline/parser.h                      |   54 +-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  452 ++---
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |    9 +
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1461 +++++---------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   12 +
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1505 +++++---------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   11 +
 .../pipeline/pipeline_flow_classification.c        | 2082 +++++++++-----------
 .../pipeline/pipeline_flow_classification.h        |   28 +
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1636 ++++-----------
 examples/ip_pipeline/thread_fe.c                   |   36 +-
 32 files changed, 4009 insertions(+), 4948 deletions(-)
 create mode 100644 examples/ip_pipeline/config/action.cfg
 create mode 100644 examples/ip_pipeline/config/action.sh
 create mode 100644 examples/ip_pipeline/config/action.txt
 create mode 100644 examples/ip_pipeline/config/firewall.cfg
 create mode 100644 examples/ip_pipeline/config/firewall.sh
 create mode 100644 examples/ip_pipeline/config/firewall.txt
 create mode 100644 examples/ip_pipeline/config/flow.cfg
 create mode 100644 examples/ip_pipeline/config/flow.sh
 create mode 100644 examples/ip_pipeline/config/flow.txt
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 create mode 100644 examples/ip_pipeline/parser.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 1/7] examples/ip_pipeline: add helper functions for parsing string
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
                       ` (6 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Add a couple of additional functions that will allow to parse many types
of input parameters, i.e.: bool, 16, 32, 64 bits, hex, etc.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/Makefile       |    1 +
 examples/ip_pipeline/config_parse.c |  257 +-----------
 examples/ip_pipeline/parser.c       |  745 +++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/parser.h       |   54 ++-
 4 files changed, 791 insertions(+), 266 deletions(-)
 create mode 100644 examples/ip_pipeline/parser.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 10fe1ba..5827117 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -50,6 +50,7 @@ INC += $(wildcard *.h) $(wildcard pipeline/*.h)
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += parser.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse_tm.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index e5efd03..ff917f3 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -30,6 +30,7 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -229,13 +230,6 @@ app_print_usage(char *prgname)
 	rte_exit(0, app_usage, prgname, app_params_default.config_file);
 }
 
-#define skip_white_spaces(pos)			\
-({						\
-	__typeof__(pos) _p = (pos);		\
-	for ( ; isspace(*_p); _p++);		\
-	_p;					\
-})
-
 #define PARSER_PARAM_ADD_CHECK(result, params_array, section_name)	\
 do {									\
 	APP_CHECK((result != -EINVAL),					\
@@ -248,44 +242,6 @@ do {									\
 		"Parse error in section \"%s\"", section_name);		\
 } while (0)
 
-int
-parser_read_arg_bool(const char *p)
-{
-	p = skip_white_spaces(p);
-	int result = -EINVAL;
-
-	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
-		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
-		p += 3;
-		result = 1;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'n')) ||
-		((p[0] == 'O') && (p[1] == 'N'))) {
-		p += 2;
-		result = 1;
-	}
-
-	if (((p[0] == 'n') && (p[1] == 'o')) ||
-		((p[0] == 'N') && (p[1] == 'O'))) {
-		p += 2;
-		result = 0;
-	}
-
-	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
-		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
-		p += 3;
-		result = 0;
-	}
-
-	p = skip_white_spaces(p);
-
-	if (p[0] != '\0')
-		return -EINVAL;
-
-	return result;
-}
-
 #define PARSE_ERROR(exp, section, entry)				\
 APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"\n", section, entry)
 
@@ -318,217 +274,6 @@ APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"\n",\
 APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"\n",\
 	section, entry)
 
-int
-parser_read_uint64(uint64_t *value, const char *p)
-{
-	char *next;
-	uint64_t val;
-
-	p = skip_white_spaces(p);
-	if (!isdigit(*p))
-		return -EINVAL;
-
-	val = strtoul(p, &next, 10);
-	if (p == next)
-		return -EINVAL;
-
-	p = next;
-	switch (*p) {
-	case 'T':
-		val *= 1024ULL;
-		/* fall through */
-	case 'G':
-		val *= 1024ULL;
-		/* fall through */
-	case 'M':
-		val *= 1024ULL;
-		/* fall through */
-	case 'k':
-	case 'K':
-		val *= 1024ULL;
-		p++;
-		break;
-	}
-
-	p = skip_white_spaces(p);
-	if (*p != '\0')
-		return -EINVAL;
-
-	*value = val;
-	return 0;
-}
-
-int
-parser_read_uint32(uint32_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT32_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
-{
-	size_t num_len;
-	char num[8];
-
-	uint32_t s = 0, c = 0, h = 0, val;
-	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
-	const char *next = skip_white_spaces(entry);
-	char type;
-
-	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
-	while (*next != '\0') {
-		/* If everything parsed nothing should left */
-		if (s_parsed && c_parsed && h_parsed)
-			return -EINVAL;
-
-		type = *next;
-		switch (type) {
-		case 's':
-		case 'S':
-			if (s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-			s_parsed = 1;
-			next++;
-			break;
-		case 'c':
-		case 'C':
-			if (c_parsed || h_parsed)
-				return -EINVAL;
-			c_parsed = 1;
-			next++;
-			break;
-		case 'h':
-		case 'H':
-			if (h_parsed)
-				return -EINVAL;
-			h_parsed = 1;
-			next++;
-			break;
-		default:
-			/* If it start from digit it must be only core id. */
-			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
-				return -EINVAL;
-
-			type = 'C';
-		}
-
-		for (num_len = 0; *next != '\0'; next++, num_len++) {
-			if (num_len == RTE_DIM(num))
-				return -EINVAL;
-
-			if (!isdigit(*next))
-				break;
-
-			num[num_len] = *next;
-		}
-
-		if (num_len == 0 && type != 'h' && type != 'H')
-			return -EINVAL;
-
-		if (num_len != 0 && (type == 'h' || type == 'H'))
-			return -EINVAL;
-
-		num[num_len] = '\0';
-		val = strtol(num, NULL, 10);
-
-		h = 0;
-		switch (type) {
-		case 's':
-		case 'S':
-			s = val;
-			break;
-		case 'c':
-		case 'C':
-			c = val;
-			break;
-		case 'h':
-		case 'H':
-			h = 1;
-			break;
-		}
-	}
-
-	*socket = s;
-	*core = c;
-	*ht = h;
-	return 0;
-}
-
-static uint32_t
-get_hex_val(char c)
-{
-	switch (c) {
-	case '0': case '1': case '2': case '3': case '4': case '5':
-	case '6': case '7': case '8': case '9':
-		return c - '0';
-	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-		return c - 'A' + 10;
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-		return c - 'a' + 10;
-	default:
-		return 0;
-	}
-}
-
-int
-parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
-{
-	char *c;
-	uint32_t len, i;
-
-	/* Check input parameters */
-	if ((src == NULL) ||
-		(dst == NULL) ||
-		(size == NULL) ||
-		(*size == 0))
-		return -1;
-
-	len = strlen(src);
-	if (((len & 3) != 0) ||
-		(len > (*size) * 2))
-		return -1;
-	*size = len / 2;
-
-	for (c = src; *c != 0; c++) {
-		if ((((*c) >= '0') && ((*c) <= '9')) ||
-			(((*c) >= 'A') && ((*c) <= 'F')) ||
-			(((*c) >= 'a') && ((*c) <= 'f')))
-			continue;
-
-		return -1;
-	}
-
-	/* Convert chars to bytes */
-	for (i = 0; i < *size; i++)
-		dst[i] = get_hex_val(src[2 * i]) * 16 +
-			get_hex_val(src[2 * i + 1]);
-
-	return 0;
-}
-
-static size_t
-skip_digits(const char *src)
-{
-	size_t i;
-
-	for (i = 0; isdigit(src[i]); i++);
-
-	return i;
-}
-
 static int
 validate_name(const char *name, const char *prefix, int num)
 {
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
new file mode 100644
index 0000000..689e206
--- /dev/null
+++ b/examples/ip_pipeline/parser.c
@@ -0,0 +1,745 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For my_ether_aton() function:
+ *
+ * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the University of California, Berkeley nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For inet_pton4() and inet_pton6() functions:
+ *
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+#include "parser.h"
+
+static uint32_t
+get_hex_val(char c)
+{
+	switch (c) {
+	case '0': case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+		return c - '0';
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+		return c - 'A' + 10;
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+		return c - 'a' + 10;
+	default:
+		return 0;
+	}
+}
+
+int
+parser_read_arg_bool(const char *p)
+{
+	p = skip_white_spaces(p);
+	int result = -EINVAL;
+
+	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+		((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+		p += 3;
+		result = 1;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'n')) ||
+		((p[0] == 'O') && (p[1] == 'N'))) {
+		p += 2;
+		result = 1;
+	}
+
+	if (((p[0] == 'n') && (p[1] == 'o')) ||
+		((p[0] == 'N') && (p[1] == 'O'))) {
+		p += 2;
+		result = 0;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+		((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+		p += 3;
+		result = 0;
+	}
+
+	p = skip_white_spaces(p);
+
+	if (p[0] != '\0')
+		return -EINVAL;
+
+	return result;
+}
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+
+	val = strtoul(p, &next, 16);
+	if (p == next)
+		return -EINVAL;
+
+	p = skip_white_spaces(next);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32_hex(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16_hex(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
+{
+	uint32_t i;
+
+	if ((string == NULL) ||
+		(tokens == NULL) ||
+		(*n_tokens < 1))
+		return -EINVAL;
+
+	for (i = 0; i < *n_tokens; i++) {
+		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
+		if (tokens[i] == NULL)
+			break;
+	}
+
+	if ((i == *n_tokens) &&
+		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
+		return -E2BIG;
+
+	*n_tokens = i;
+	return 0;
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+	char *c;
+	uint32_t len, i;
+
+	/* Check input parameters */
+	if ((src == NULL) ||
+		(dst == NULL) ||
+		(size == NULL) ||
+		(*size == 0))
+		return -1;
+
+	len = strlen(src);
+	if (((len & 3) != 0) ||
+		(len > (*size) * 2))
+		return -1;
+	*size = len / 2;
+
+	for (c = src; *c != 0; c++) {
+		if ((((*c) >= '0') && ((*c) <= '9')) ||
+			(((*c) >= 'A') && ((*c) <= 'F')) ||
+			(((*c) >= 'a') && ((*c) <= 'f')))
+			continue;
+
+		return -1;
+	}
+
+	/* Convert chars to bytes */
+	for (i = 0; i < *size; i++)
+		dst[i] = get_hex_val(src[2 * i]) * 16 +
+			get_hex_val(src[2 * i + 1]);
+
+	return 0;
+}
+
+int
+parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels)
+{
+	uint32_t n_max_labels = *n_labels, count = 0;
+
+	/* Check for void list of labels */
+	if (strcmp(string, "<void>") == 0) {
+		*n_labels = 0;
+		return 0;
+	}
+
+	/* At least one label should be present */
+	for ( ; (*string != '\0'); ) {
+		char *next;
+		int value;
+
+		if (count >= n_max_labels)
+			return -1;
+
+		if (count > 0) {
+			if (string[0] != ':')
+				return -1;
+
+			string++;
+		}
+
+		value = strtol(string, &next, 10);
+		if (next == string)
+			return -1;
+		string = next;
+
+		labels[count++] = (uint32_t) value;
+	}
+
+	*n_labels = count;
+	return 0;
+}
+
+#define INADDRSZ 4
+#define IN6ADDRSZ 16
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+	static const char digits[] = "0123456789";
+	int saw_digit, octets, ch;
+	unsigned char tmp[INADDRSZ], *tp;
+
+	saw_digit = 0;
+	octets = 0;
+	*(tp = tmp) = 0;
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		pch = strchr(digits, ch);
+		if (pch != NULL) {
+			unsigned int new = *tp * 10 + (pch - digits);
+
+			if (new > 255)
+				return 0;
+			if (!saw_digit) {
+				if (++octets > 4)
+					return 0;
+				saw_digit = 1;
+			}
+			*tp = (unsigned char)new;
+		} else if (ch == '.' && saw_digit) {
+			if (octets == 4)
+				return 0;
+			*++tp = 0;
+			saw_digit = 0;
+		} else
+			return 0;
+	}
+	if (octets < 4)
+		return 0;
+
+	memcpy(dst, tmp, INADDRSZ);
+	return 1;
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+	static const char xdigits_l[] = "0123456789abcdef",
+		xdigits_u[] = "0123456789ABCDEF";
+	unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
+	const char *xdigits = 0, *curtok = 0;
+	int ch = 0, saw_xdigit = 0, count_xdigit = 0;
+	unsigned int val = 0;
+	unsigned dbloct_count = 0;
+
+	memset((tp = tmp), '\0', IN6ADDRSZ);
+	endp = tp + IN6ADDRSZ;
+	colonp = NULL;
+	/* Leading :: requires some special handling. */
+	if (*src == ':')
+		if (*++src != ':')
+			return 0;
+	curtok = src;
+	saw_xdigit = count_xdigit = 0;
+	val = 0;
+
+	while ((ch = *src++) != '\0') {
+		const char *pch;
+
+		pch = strchr((xdigits = xdigits_l), ch);
+		if (pch == NULL)
+			pch = strchr((xdigits = xdigits_u), ch);
+		if (pch != NULL) {
+			if (count_xdigit >= 4)
+				return 0;
+			val <<= 4;
+			val |= (pch - xdigits);
+			if (val > 0xffff)
+				return 0;
+			saw_xdigit = 1;
+			count_xdigit++;
+			continue;
+		}
+		if (ch == ':') {
+			curtok = src;
+			if (!saw_xdigit) {
+				if (colonp)
+					return 0;
+				colonp = tp;
+				continue;
+			} else if (*src == '\0') {
+				return 0;
+			}
+			if (tp + sizeof(int16_t) > endp)
+				return 0;
+			*tp++ = (unsigned char) ((val >> 8) & 0xff);
+			*tp++ = (unsigned char) (val & 0xff);
+			saw_xdigit = 0;
+			count_xdigit = 0;
+			val = 0;
+			dbloct_count++;
+			continue;
+		}
+		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+		    inet_pton4(curtok, tp) > 0) {
+			tp += INADDRSZ;
+			saw_xdigit = 0;
+			dbloct_count += 2;
+			break;  /* '\0' was seen by inet_pton4(). */
+		}
+		return 0;
+	}
+	if (saw_xdigit) {
+		if (tp + sizeof(int16_t) > endp)
+			return 0;
+		*tp++ = (unsigned char) ((val >> 8) & 0xff);
+		*tp++ = (unsigned char) (val & 0xff);
+		dbloct_count++;
+	}
+	if (colonp != NULL) {
+		/* if we already have 8 double octets, having a colon means error */
+		if (dbloct_count == 8)
+			return 0;
+
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		const int n = tp - colonp;
+		int i;
+
+		for (i = 1; i <= n; i++) {
+			endp[-i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+	if (tp != endp)
+		return 0;
+	memcpy(dst, tmp, IN6ADDRSZ);
+	return 1;
+}
+
+static struct ether_addr *
+my_ether_aton(const char *a)
+{
+	int i;
+	char *end;
+	unsigned long o[ETHER_ADDR_LEN];
+	static struct ether_addr ether_addr;
+
+	i = 0;
+	do {
+		errno = 0;
+		o[i] = strtoul(a, &end, 16);
+		if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
+			return NULL;
+		a = end + 1;
+	} while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0);
+
+	/* Junk at the end of line */
+	if (end[0] != 0)
+		return NULL;
+
+	/* Support the format XX:XX:XX:XX:XX:XX */
+	if (i == ETHER_ADDR_LEN) {
+		while (i-- != 0) {
+			if (o[i] > UINT8_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i] = (uint8_t)o[i];
+		}
+	/* Support the format XXXX:XXXX:XXXX */
+	} else if (i == ETHER_ADDR_LEN / 2) {
+		while (i-- != 0) {
+			if (o[i] > UINT16_MAX)
+				return NULL;
+			ether_addr.addr_bytes[i * 2] = (uint8_t)(o[i] >> 8);
+			ether_addr.addr_bytes[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
+		}
+	/* unknown format */
+	} else
+		return NULL;
+
+	return (struct ether_addr *)&ether_addr;
+}
+
+int
+parse_ipv4_addr(const char *token, struct in_addr *ipv4)
+{
+	if (strlen(token) >= INET_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton4(token, (unsigned char *)ipv4) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_ipv6_addr(const char *token, struct in6_addr *ipv6)
+{
+	if (strlen(token) >= INET6_ADDRSTRLEN)
+		return -EINVAL;
+
+	if (inet_pton6(token, (unsigned char *)ipv6) != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+parse_mac_addr(const char *token, struct ether_addr *addr)
+{
+	struct ether_addr *tmp;
+
+	tmp = my_ether_aton(token);
+	if (tmp == NULL)
+		return -1;
+
+	memcpy(addr, tmp, sizeof(struct ether_addr));
+	return 0;
+}
+
+int
+parse_pipeline_core(uint32_t *socket,
+	uint32_t *core,
+	uint32_t *ht,
+	const char *entry)
+{
+	size_t num_len;
+	char num[8];
+
+	uint32_t s = 0, c = 0, h = 0, val;
+	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+	const char *next = skip_white_spaces(entry);
+	char type;
+
+	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+	while (*next != '\0') {
+		/* If everything parsed nothing should left */
+		if (s_parsed && c_parsed && h_parsed)
+			return -EINVAL;
+
+		type = *next;
+		switch (type) {
+		case 's':
+		case 'S':
+			if (s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+			s_parsed = 1;
+			next++;
+			break;
+		case 'c':
+		case 'C':
+			if (c_parsed || h_parsed)
+				return -EINVAL;
+			c_parsed = 1;
+			next++;
+			break;
+		case 'h':
+		case 'H':
+			if (h_parsed)
+				return -EINVAL;
+			h_parsed = 1;
+			next++;
+			break;
+		default:
+			/* If it start from digit it must be only core id. */
+			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+
+			type = 'C';
+		}
+
+		for (num_len = 0; *next != '\0'; next++, num_len++) {
+			if (num_len == RTE_DIM(num))
+				return -EINVAL;
+
+			if (!isdigit(*next))
+				break;
+
+			num[num_len] = *next;
+		}
+
+		if (num_len == 0 && type != 'h' && type != 'H')
+			return -EINVAL;
+
+		if (num_len != 0 && (type == 'h' || type == 'H'))
+			return -EINVAL;
+
+		num[num_len] = '\0';
+		val = strtol(num, NULL, 10);
+
+		h = 0;
+		switch (type) {
+		case 's':
+		case 'S':
+			s = val;
+			break;
+		case 'c':
+		case 'C':
+			c = val;
+			break;
+		case 'h':
+		case 'H':
+			h = 1;
+			break;
+		}
+	}
+
+	*socket = s;
+	*core = c;
+	*ht = h;
+	return 0;
+}
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 58b59da..9bd36af 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -34,17 +34,51 @@
 #ifndef __INCLUDE_PARSER_H__
 #define __INCLUDE_PARSER_H__
 
-int
-parser_read_arg_bool(const char *p);
+#include <stdint.h>
 
-int
-parser_read_uint64(uint64_t *value, const char *p);
+#include <rte_ip.h>
+#include <rte_ether.h>
 
-int
-parser_read_uint32(uint32_t *value, const char *p);
+#define PARSE_DELIMITER				" \f\n\r\t\v"
 
-int
-parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
 
-#endif
+static inline size_t
+skip_digits(const char *src)
+{
+	size_t i;
+
+	for (i = 0; isdigit(src[i]); i++)
+		;
+
+	return i;
+}
+
+int parser_read_arg_bool(const char *p);
+
+int parser_read_uint64(uint64_t *value, const char *p);
+int parser_read_uint32(uint32_t *value, const char *p);
+int parser_read_uint16(uint16_t *value, const char *p);
+int parser_read_uint8(uint8_t *value, const char *p);
 
+int parser_read_uint64_hex(uint64_t *value, const char *p);
+int parser_read_uint32_hex(uint32_t *value, const char *p);
+int parser_read_uint16_hex(uint16_t *value, const char *p);
+int parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
+int parse_ipv4_addr(const char *token, struct in_addr *ipv4);
+int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
+int parse_mac_addr(const char *token, struct ether_addr *addr);
+int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
+
+int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 2/7] examples/ip_pipeline: modifies common pipeline CLI
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
                       ` (5 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Tomasz Kulasek, Michal Kobylinski

From: Tomasz Kulasek <tomaszx.kulasek@intel.com>

All link commands are merged into one command:
cmd_link_parsed.
Improve run command to allow run periodically.
Adding static keyword to a lot of token declarations.

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Michal Kobylinski <michalx.kobylinski@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  452 ++++++++++----------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |    9 +
 examples/ip_pipeline/thread_fe.c                   |   36 +-
 3 files changed, 244 insertions(+), 253 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index a691d42..dc37a5f 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,10 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
 #include <cmdline.h>
 
 #include "pipeline_common_fe.h"
+#include "parser.h"
 
 int
 app_pipeline_ping(struct app_params *app,
@@ -464,16 +462,16 @@ cmd_ping_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_ping_p_string =
+static cmdline_parse_token_string_t cmd_ping_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_ping_pipeline_id =
+static cmdline_parse_token_num_t cmd_ping_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_ping_ping_string =
+static cmdline_parse_token_string_t cmd_ping_ping_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
 
-cmdline_parse_inst_t cmd_ping = {
+static cmdline_parse_inst_t cmd_ping = {
 	.f = cmd_ping_parsed,
 	.data = NULL,
 	.help_str = "Pipeline ping",
@@ -498,6 +496,7 @@ struct cmd_stats_port_in_result {
 	uint32_t port_in_id;
 
 };
+
 static void
 cmd_stats_port_in_parsed(
 	void *parsed_result,
@@ -531,23 +530,23 @@ cmd_stats_port_in_parsed(
 		stats.stats.n_pkts_drop);
 }
 
-cmdline_parse_token_string_t cmd_stats_port_in_p_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_port_in_port_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_stats_port_in_in_string =
+static cmdline_parse_token_string_t cmd_stats_port_in_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, in_string,
 		"in");
 
@@ -555,7 +554,7 @@ cmdline_parse_token_string_t cmd_stats_port_in_in_string =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, port_in_id,
 		UINT32);
 
-cmdline_parse_inst_t cmd_stats_port_in = {
+static cmdline_parse_inst_t cmd_stats_port_in = {
 	.f = cmd_stats_port_in_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port stats",
@@ -617,31 +616,31 @@ cmd_stats_port_out_parsed(
 		stats.stats.n_pkts_drop);
 }
 
-cmdline_parse_token_string_t cmd_stats_port_out_p_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
 	"p");
 
-cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_port_out_port_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_stats_port_out_out_string =
+static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
 		"out");
 
-cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
+static cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, port_out_id,
 		UINT32);
 
-cmdline_parse_inst_t cmd_stats_port_out = {
+static cmdline_parse_inst_t cmd_stats_port_out = {
 	.f = cmd_stats_port_out_parsed,
 	.data = NULL,
 	.help_str = "Pipeline output port stats",
@@ -707,26 +706,26 @@ cmd_stats_table_parsed(
 		stats.n_pkts_dropped_lkp_miss);
 }
 
-cmdline_parse_token_string_t cmd_stats_table_p_string =
+static cmdline_parse_token_string_t cmd_stats_table_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
+static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_stats_table_stats_string =
+static cmdline_parse_token_string_t cmd_stats_table_stats_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
 		"stats");
 
-cmdline_parse_token_string_t cmd_stats_table_table_string =
+static cmdline_parse_token_string_t cmd_stats_table_table_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
 		"table");
 
-cmdline_parse_token_num_t cmd_stats_table_table_id =
+static cmdline_parse_token_num_t cmd_stats_table_table_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
 
-cmdline_parse_inst_t cmd_stats_table = {
+static cmdline_parse_inst_t cmd_stats_table = {
 	.f = cmd_stats_table_parsed,
 	.data = NULL,
 	.help_str = "Pipeline table stats",
@@ -771,31 +770,31 @@ cmd_port_in_enable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_port_in_enable_p_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
+static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_enable_port_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
 	"port");
 
-cmdline_parse_token_string_t cmd_port_in_enable_in_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
 		"in");
 
-cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
+static cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, port_in_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
+static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
 		enable_string, "enable");
 
-cmdline_parse_inst_t cmd_port_in_enable = {
+static cmdline_parse_inst_t cmd_port_in_enable = {
 	.f = cmd_port_in_enable_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port enable",
@@ -841,31 +840,31 @@ cmd_port_in_disable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_port_in_disable_p_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
 		"p");
 
-cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
+static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_disable_port_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
 		"port");
 
-cmdline_parse_token_string_t cmd_port_in_disable_in_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
 		"in");
 
-cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
+static cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, port_in_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
+static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
 		disable_string, "disable");
 
-cmdline_parse_inst_t cmd_port_in_disable = {
+static cmdline_parse_inst_t cmd_port_in_disable = {
 	.f = cmd_port_in_disable_parsed,
 	.data = NULL,
 	.help_str = "Pipeline input port disable",
@@ -963,219 +962,144 @@ print_link_info(struct app_link_params *p)
 	printf("\n");
 }
 
-struct cmd_link_config_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t config_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-};
-
-static void
-cmd_link_config_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_config_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	uint32_t link_id = params->link_id;
-	uint32_t ip  = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	uint32_t depth = params->depth;
-
-	status = app_link_config(app, link_id, ip, depth);
-	if (status)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
-
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
-	}
-}
-
-cmdline_parse_token_string_t cmd_link_config_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, link_string,
-		"link");
-
-cmdline_parse_token_num_t cmd_link_config_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, link_id, UINT32);
-
-cmdline_parse_token_string_t cmd_link_config_config_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, config_string,
-		"config");
-
-cmdline_parse_token_ipaddr_t cmd_link_config_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_link_config_result, ip);
-
-cmdline_parse_token_num_t cmd_link_config_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, depth, UINT32);
-
-cmdline_parse_inst_t cmd_link_config = {
-	.f = cmd_link_config_parsed,
-	.data = NULL,
-	.help_str = "Link configuration",
-	.tokens = {
-		(void *)&cmd_link_config_link_string,
-		(void *)&cmd_link_config_link_id,
-		(void *)&cmd_link_config_config_string,
-		(void *)&cmd_link_config_ip,
-		(void *)&cmd_link_config_depth,
-		NULL,
-	},
-};
-
 /*
- * link up
+ * link
+ *
+ * link config:
+ *    link <linkid> config <ipaddr> <depth>
+ *
+ * link up:
+ *    link <linkid> up
+ *
+ * link down:
+ *    link <linkid> down
+ *
+ * link ls:
+ *    link ls
  */
 
-struct cmd_link_up_result {
+struct cmd_link_result {
 	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t up_string;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_link_up_parsed(
+cmd_link_parsed(
 	void *parsed_result,
 	__attribute__((unused)) struct cmdline *cl,
-	void *data)
+	 void *data)
 {
-	struct cmd_link_up_result *params = parsed_result;
+	struct cmd_link_result *params = parsed_result;
 	struct app_params *app = data;
+
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	status = app_link_up(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
+	uint32_t link_id;
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status != 0) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "link");
+		return;
 	}
-}
-
-cmdline_parse_token_string_t cmd_link_up_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, link_string,
-		"link");
 
-cmdline_parse_token_num_t cmd_link_up_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_up_result, link_id, UINT32);
+	/* link ls */
+	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
+		for (link_id = 0; link_id < app->n_links; link_id++) {
+			struct app_link_params *p;
 
-cmdline_parse_token_string_t cmd_link_up_up_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, up_string, "up");
+			APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+			print_link_info(p);
+		}
+		return;
+	} /* link ls */
 
-cmdline_parse_inst_t cmd_link_up = {
-	.f = cmd_link_up_parsed,
-	.data = NULL,
-	.help_str = "Link UP",
-	.tokens = {
-		(void *)&cmd_link_up_link_string,
-		(void *)&cmd_link_up_link_id,
-		(void *)&cmd_link_up_up_string,
-		NULL,
-	},
-};
+	if (n_tokens < 2) {
+		printf(CMD_MSG_MISMATCH_ARGS, "link");
+		return;
+	}
 
-/*
- * link down
- */
+	if (parser_read_uint32(&link_id, tokens[0])) {
+		printf(CMD_MSG_INVALID_ARG, "linkid");
+		return;
+	}
 
-struct cmd_link_down_result {
-	cmdline_fixed_string_t link_string;
-	uint32_t link_id;
-	cmdline_fixed_string_t down_string;
-};
+	/* link config */
+	if (strcmp(tokens[1], "config") == 0) {
+		struct in_addr ipaddr_ipv4;
+		uint32_t depth;
 
-static void
-cmd_link_down_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_link_down_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link config");
+			return;
+		}
 
-	status = app_link_down(app, params->link_id);
-	if (status != 0)
-		printf("Command failed\n");
-	else {
-		struct app_link_params *p;
+		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id,
-			p);
-		print_link_info(p);
-	}
-}
+		if (parser_read_uint32(&depth, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_link_down_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, link_string,
-		"link");
+		status = app_link_config(app,
+			link_id,
+			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
+			depth);
+		if (status)
+			printf(CMD_MSG_FAIL, "link config");
 
-cmdline_parse_token_num_t cmd_link_down_link_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_down_result, link_id, UINT32);
+		return;
+	} /* link config */
 
-cmdline_parse_token_string_t cmd_link_down_down_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, down_string,
-		"down");
+	/* link up */
+	if (strcmp(tokens[1], "up") == 0) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link up");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_link_down = {
-	.f = cmd_link_down_parsed,
-	.data = NULL,
-	.help_str = "Link DOWN",
-	.tokens = {
-		(void *) &cmd_link_down_link_string,
-		(void *) &cmd_link_down_link_id,
-		(void *) &cmd_link_down_down_string,
-		NULL,
-	},
-};
+		status = app_link_up(app, link_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "link up");
 
-/*
- * link ls
- */
+		return;
+	} /* link up */
 
-struct cmd_link_ls_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_fixed_string_t ls_string;
-};
+	/* link down */
+	if (strcmp(tokens[1], "down") == 0) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "link down");
+			return;
+		}
 
-static void
-cmd_link_ls_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct app_params *app = data;
-	uint32_t link_id;
+		status = app_link_down(app, link_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "link down");
 
-	for (link_id = 0; link_id < app->n_links; link_id++) {
-		struct app_link_params *p;
+		return;
+	} /* link down */
 
-		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-		print_link_info(p);
-	}
+	printf(CMD_MSG_MISMATCH_ARGS, "link");
 }
 
-cmdline_parse_token_string_t cmd_link_ls_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, link_string,
-		"link");
+static cmdline_parse_token_string_t cmd_link_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
 
-cmdline_parse_token_string_t cmd_link_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, ls_string, "ls");
+static cmdline_parse_token_string_t cmd_link_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_link_ls = {
-	.f = cmd_link_ls_parsed,
+static cmdline_parse_inst_t cmd_link = {
+	.f = cmd_link_parsed,
 	.data = NULL,
-	.help_str = "Link list",
+	.help_str = "link config / up / down / ls",
 	.tokens = {
-		(void *)&cmd_link_ls_link_string,
-		(void *)&cmd_link_ls_ls_string,
+		(void *) &cmd_link_link_string,
+		(void *) &cmd_link_multi_string,
 		NULL,
 	},
 };
@@ -1212,6 +1136,11 @@ static cmdline_parse_inst_t cmd_quit = {
 
 /*
  * run
+ *
+ *    run <file>
+ *    run <file> [<count> [<interval>]]
+	 <count> default is 1
+ *       <interval> is measured in milliseconds, default is 1 second
  */
 
 static void
@@ -1233,9 +1162,9 @@ app_run_file(
 	close(fd);
 }
 
-struct cmd_run_file_result {
+struct cmd_run_result {
 	cmdline_fixed_string_t run_string;
-	char file_name[APP_FILE_NAME_SIZE];
+	cmdline_multi_string_t multi_string;
 };
 
 static void
@@ -1244,25 +1173,87 @@ cmd_run_parsed(
 	struct cmdline *cl,
 	__attribute__((unused)) void *data)
 {
-	struct cmd_run_file_result *params = parsed_result;
+	struct cmd_run_result *params = parsed_result;
+
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
+	char *file_name;
+	uint32_t count, interval, i;
+
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "run");
+		return;
+	}
+
+	switch (n_tokens) {
+	case 0:
+		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
+		return;
+
+	case 1:
+		file_name = tokens[0];
+		count = 1;
+		interval = 1000;
+		break;
+
+	case 2:
+		file_name = tokens[0];
 
-	app_run_file(cl->ctx, params->file_name);
+		if (parser_read_uint32(&count, tokens[1]) ||
+			(count == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "count");
+			return;
+		}
+
+		interval = 1000;
+		break;
+
+	case 3:
+		file_name = tokens[0];
+
+		if (parser_read_uint32(&count, tokens[1]) ||
+			(count == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "count");
+			return;
+		}
+
+		if (parser_read_uint32(&interval, tokens[2]) ||
+			(interval == 0)) {
+			printf(CMD_MSG_INVALID_ARG, "interval");
+			return;
+		}
+		break;
+
+	default:
+		printf(CMD_MSG_MISMATCH_ARGS, "run");
+		return;
+	}
+
+	for (i = 0; i < count; i++) {
+		app_run_file(cl->ctx, file_name);
+		if (interval)
+			usleep(interval * 1000);
+	}
 }
 
-cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, run_string,
-		"run");
+static cmdline_parse_token_string_t cmd_run_run_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
 
-cmdline_parse_token_string_t cmd_run_file_name =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, file_name, NULL);
+static cmdline_parse_token_string_t cmd_run_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_run = {
+
+static cmdline_parse_inst_t cmd_run = {
 	.f = cmd_run_parsed,
 	.data = NULL,
 	.help_str = "Run CLI script file",
 	.tokens = {
 		(void *) &cmd_run_run_string,
-		(void *) &cmd_run_file_name,
+		(void *) &cmd_run_multi_string,
 		NULL,
 	},
 };
@@ -1270,12 +1261,7 @@ cmdline_parse_inst_t cmd_run = {
 static cmdline_parse_ctx_t pipeline_common_cmds[] = {
 	(cmdline_parse_inst_t *) &cmd_quit,
 	(cmdline_parse_inst_t *) &cmd_run,
-
-	(cmdline_parse_inst_t *) &cmd_link_config,
-	(cmdline_parse_inst_t *) &cmd_link_up,
-	(cmdline_parse_inst_t *) &cmd_link_down,
-	(cmdline_parse_inst_t *) &cmd_link_ls,
-
+	(cmdline_parse_inst_t *) &cmd_link,
 	(cmdline_parse_inst_t *) &cmd_ping,
 	(cmdline_parse_inst_t *) &cmd_stats_port_in,
 	(cmdline_parse_inst_t *) &cmd_stats_port_out,
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
index cfad963..f93ff74 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
@@ -231,4 +231,13 @@ app_link_down(struct app_params *app,
 int
 app_pipeline_common_cmd_push(struct app_params *app);
 
+#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
+#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
+#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
+#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
+#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
+#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
+#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
+#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
+
 #endif
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
index 4a435f7..d1b72b4 100644
--- a/examples/ip_pipeline/thread_fe.c
+++ b/examples/ip_pipeline/thread_fe.c
@@ -5,10 +5,6 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
 
 #include "thread.h"
 #include "thread_fe.h"
@@ -259,26 +255,26 @@ cmd_pipeline_enable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
 
-cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
 		NULL);
 
-cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
 		"pipeline");
 
-cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
+static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
+static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
 		"enable");
 
-cmdline_parse_inst_t cmd_pipeline_enable = {
+static cmdline_parse_inst_t cmd_pipeline_enable = {
 	.f = cmd_pipeline_enable_parsed,
 	.data = NULL,
 	.help_str = "Enable pipeline on specified core",
@@ -333,26 +329,26 @@ cmd_pipeline_disable_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
 
-cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
 		NULL);
 
-cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
 		pipeline_string, "pipeline");
 
-cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
+static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
 		UINT32);
 
-cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
+static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
 		"disable");
 
-cmdline_parse_inst_t cmd_pipeline_disable = {
+static cmdline_parse_inst_t cmd_pipeline_disable = {
 	.f = cmd_pipeline_disable_parsed,
 	.data = NULL,
 	.help_str = "Disable pipeline on specified core",
@@ -405,19 +401,19 @@ cmd_thread_headroom_parsed(
 		printf("Command failed\n");
 }
 
-cmdline_parse_token_string_t cmd_thread_headroom_t_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 	t_string, "t");
 
-cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 	t_id_string, NULL);
 
-cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
+static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
 	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
 		headroom_string, "headroom");
 
-cmdline_parse_inst_t cmd_thread_headroom = {
+static cmdline_parse_inst_t cmd_thread_headroom = {
 	.f = cmd_thread_headroom_parsed,
 	.data = NULL,
 	.help_str = "Display thread headroom",
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 3/7] examples/ip_pipeline: modifies firewall pipeline CLI
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
                       ` (4 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Daniel Mrzyglod

From: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>

Each command are merged into one: cmd_firewall_parsed.
ADD command format is changed:
p <pipeline ID> firewall add priority <priority> ipv4 <sipaddr>
<sipdepth> <dipaddr> <dipdepth> <sport0> <sport1> <dport0> <dport1>
<proto> <protomask> port <port ID>

and bulk command was modified:
1. firewall add bulk
File line format:
priority <priority> ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
<sport0> <sport1> <dport0> <dport1> <proto> <protomask> port <port ID>
(protomask is a hex value)
File line example:
priority 0 ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF port 3

2. firewall del bulk
File line format:
ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth> <sport0> <sport1>
<dport0> <dport1> <proto> <protomask>
File line example:
ipv4 1.2.3.0 24 10.20.30.40 32 0 63 64 127 6 0xF

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/firewall.cfg          |   68 +
 examples/ip_pipeline/config/firewall.sh           |   13 +
 examples/ip_pipeline/config/firewall.txt          |    9 +
 examples/ip_pipeline/pipeline/pipeline_firewall.c | 1461 ++++++++-------------
 examples/ip_pipeline/pipeline/pipeline_firewall.h |   12 +
 5 files changed, 622 insertions(+), 941 deletions(-)
 create mode 100644 examples/ip_pipeline/config/firewall.cfg
 create mode 100644 examples/ip_pipeline/config/firewall.sh
 create mode 100644 examples/ip_pipeline/config/firewall.txt

diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
new file mode 100644
index 0000000..2f5dd9f
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.cfg
@@ -0,0 +1,68 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             _______________
+; RXQ0.0 --->|               |---> TXQ0.0
+;            |               |
+; RXQ1.0 --->|               |---> TXQ1.0
+;            |   Firewall    |
+; RXQ2.0 --->|               |---> TXQ2.0
+;            |               |
+; RXQ3.0 --->|               |---> TXQ3.0
+;            |_______________|
+;                    |
+;                    +-----------> SINK0 (default rule)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FIREWALL
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+n_rules = 4096
+pkt_type = ipv4
+;pkt_type = vlan_ipv4
+;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
new file mode 100644
index 0000000..c83857e
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.sh
@@ -0,0 +1,13 @@
+#
+# run ./config/firewall.sh
+#
+
+p 1 firewall add default 4 #SINK0
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
+p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
+
+#p 1 firewall add bulk ./config/firewall.txt
+
+p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
new file mode 100644
index 0000000..54cfffd
--- /dev/null
+++ b/examples/ip_pipeline/config/firewall.txt
@@ -0,0 +1,9 @@
+#
+# p <pipelineid> firewall add bulk ./config/firewall.txt
+# p <pipelineid> firewall del bulk ./config/firewall.txt
+#
+
+priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
+priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
+priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
+priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
index fd897d5..30b22a1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -30,9 +30,11 @@
  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
 
@@ -43,15 +45,11 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_firewall.h"
-
-#define BUF_SIZE		1024
+#include "parser.h"
 
 struct app_pipeline_firewall_rule {
 	struct pipeline_firewall_key key;
@@ -75,18 +73,6 @@ struct app_pipeline_firewall {
 	void *default_rule_entry_ptr;
 };
 
-struct app_pipeline_add_bulk_params {
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	uint32_t *priorities;
-	uint32_t *port_ids;
-};
-
-struct app_pipeline_del_bulk_params {
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-};
-
 static void
 print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
 {
@@ -272,356 +258,118 @@ app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
 	}
 }
 
-static int
-app_pipeline_add_bulk_parse_file(char *filename,
-		struct app_pipeline_add_bulk_params *params)
+int
+app_pipeline_firewall_load_file(char *filename,
+	struct pipeline_firewall_key *keys,
+	uint32_t *priorities,
+	uint32_t *port_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
 {
-	FILE *f;
-	char file_buf[BUF_SIZE];
-	uint32_t i;
-	int status = 0;
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
 
-	f = fopen(filename, "r");
-	if (f == NULL)
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(priorities == NULL) ||
+		(port_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
 		return -1;
-
-	params->n_keys = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
-	rewind(f);
-
-	if (params->n_keys == 0) {
-		status = -1;
-		goto end;
-	}
-
-	params->keys = rte_malloc(NULL,
-			params->n_keys * sizeof(struct pipeline_firewall_key),
-			RTE_CACHE_LINE_SIZE);
-	if (params->keys == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	params->priorities = rte_malloc(NULL,
-			params->n_keys * sizeof(uint32_t),
-			RTE_CACHE_LINE_SIZE);
-	if (params->priorities == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	params->port_ids = rte_malloc(NULL,
-			params->n_keys * sizeof(uint32_t),
-			RTE_CACHE_LINE_SIZE);
-	if (params->port_ids == NULL) {
-		status = -1;
-		goto end;
-	}
-
-	i = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
-
-		str = strtok(file_buf, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->priorities[i] = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
 		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->port_ids[i] = atoi(str);
-		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-
-		i++;
-	}
-
-end:
-	fclose(f);
-	return status;
-}
-
-static int
-app_pipeline_del_bulk_parse_file(char *filename,
-		struct app_pipeline_del_bulk_params *params)
-{
-	FILE *f;
-	char file_buf[BUF_SIZE];
-	uint32_t i;
-	int status = 0;
 
+	/* Open input file */
 	f = fopen(filename, "r");
-	if (f == NULL)
+	if (f == NULL) {
+		*line = 0;
 		return -1;
-
-	params->n_keys = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL)
-		params->n_keys++;
-	rewind(f);
-
-	if (params->n_keys == 0) {
-		status = -1;
-		goto end;
-	}
-
-	params->keys = rte_malloc(NULL,
-			params->n_keys * sizeof(struct pipeline_firewall_key),
-			RTE_CACHE_LINE_SIZE);
-	if (params->keys == NULL) {
-		status = -1;
-		goto end;
 	}
 
-	i = 0;
-	while (fgets(file_buf, BUF_SIZE, f) != NULL) {
-		char *str;
-
-		str = strtok(file_buf, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str);
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<16;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str)<<8;
-
-		str = strtok(NULL, " .");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip |= atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_ip_mask = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.src_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_from = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.dst_port_to = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		params->keys[i].key.ipv4_5tuple.proto = atoi(str);
-
-		str = strtok(NULL, " ");
-		if (str == NULL) {
-			status = -1;
-			goto end;
-		}
-		/* Need to add 2 to str to skip leading 0x */
-		params->keys[i].key.ipv4_5tuple.proto_mask = strtol(str+2, NULL, 16);
-
-		params->keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		uint32_t priority = 0;
+		struct in_addr sipaddr;
+		uint32_t sipdepth = 0;
+		struct in_addr dipaddr;
+		uint32_t dipdepth = 0;
+		uint16_t sport0 = 0;
+		uint16_t sport1 = 0;
+		uint16_t dport0 = 0;
+		uint16_t dport1 = 0;
+		uint8_t proto = 0;
+		uint8_t protomask = 0;
+		uint32_t port_id = 0;
+
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 15) ||
+			strcmp(tokens[0], "priority") ||
+			parser_read_uint32(&priority, tokens[1]) ||
+			strcmp(tokens[2], "ipv4") ||
+			parse_ipv4_addr(tokens[3], &sipaddr) ||
+			parser_read_uint32(&sipdepth, tokens[4]) ||
+			parse_ipv4_addr(tokens[5], &dipaddr) ||
+			parser_read_uint32(&dipdepth, tokens[6]) ||
+			parser_read_uint16(&sport0, tokens[7]) ||
+			parser_read_uint16(&sport1, tokens[8]) ||
+			parser_read_uint16(&dport0, tokens[9]) ||
+			parser_read_uint16(&dport1, tokens[10]) ||
+			parser_read_uint8(&proto, tokens[11]) ||
+			parser_read_uint8_hex(&protomask, tokens[12]) ||
+			strcmp(tokens[13], "port") ||
+			parser_read_uint32(&port_id, tokens[14]))
+			goto error1;
+
+		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		keys[i].key.ipv4_5tuple.src_ip =
+			rte_be_to_cpu_32(sipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
+		keys[i].key.ipv4_5tuple.dst_ip =
+			rte_be_to_cpu_32(dipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		keys[i].key.ipv4_5tuple.src_port_from = sport0;
+		keys[i].key.ipv4_5tuple.src_port_to = sport1;
+		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
+		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
+		keys[i].key.ipv4_5tuple.proto = proto;
+		keys[i].key.ipv4_5tuple.proto_mask = protomask;
+
+		port_ids[i] = port_id;
+		priorities[i] = priority;
+
+		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
+			goto error1;
 
 		i++;
 	}
 
-	for (i = 0; i < params->n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&params->keys[i]) != 0) {
-			status = -1;
-			goto end;
-		}
-	}
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
 
-end:
+error1:
+	*line = l;
 	fclose(f);
-	return status;
+	return -1;
 }
 
 int
@@ -804,14 +552,14 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 		return -1;
 
 	rules = rte_malloc(NULL,
-			n_keys * sizeof(struct app_pipeline_firewall_rule *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct app_pipeline_firewall_rule *),
+		RTE_CACHE_LINE_SIZE);
 	if (rules == NULL)
 		return -1;
 
 	new_rules = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (new_rules == NULL) {
 		rte_free(rules);
 		return -1;
@@ -834,8 +582,9 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
 		new_rules[i] = (rules[i] == NULL);
 		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL, sizeof(*rules[i]),
-					RTE_CACHE_LINE_SIZE);
+			rules[i] = rte_malloc(NULL,
+				sizeof(*rules[i]),
+				RTE_CACHE_LINE_SIZE);
 
 			if (rules[i] == NULL) {
 				uint32_t j;
@@ -852,8 +601,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 
 	keys_found = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (keys_found == NULL) {
 		uint32_t j;
 
@@ -867,8 +616,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 
 	entries_ptr = rte_malloc(NULL,
-			n_keys * sizeof(struct rte_pipeline_table_entry *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct rte_pipeline_table_entry *),
+		RTE_CACHE_LINE_SIZE);
 	if (entries_ptr == NULL) {
 		uint32_t j;
 
@@ -883,8 +632,8 @@ app_pipeline_firewall_add_bulk(struct app_params *app,
 	}
 	for (i = 0; i < n_keys; i++) {
 		entries_ptr[i] = rte_malloc(NULL,
-				sizeof(struct rte_pipeline_table_entry),
-				RTE_CACHE_LINE_SIZE);
+			sizeof(struct rte_pipeline_table_entry),
+			RTE_CACHE_LINE_SIZE);
 
 		if (entries_ptr[i] == NULL) {
 			uint32_t j;
@@ -1030,8 +779,8 @@ app_pipeline_firewall_delete_bulk(struct app_params *app,
 		return -1;
 
 	rules = rte_malloc(NULL,
-			n_keys * sizeof(struct app_pipeline_firewall_rule *),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(struct app_pipeline_firewall_rule *),
+		RTE_CACHE_LINE_SIZE);
 	if (rules == NULL)
 		return -1;
 
@@ -1044,8 +793,8 @@ app_pipeline_firewall_delete_bulk(struct app_params *app,
 	}
 
 	keys_found = rte_malloc(NULL,
-			n_keys * sizeof(int),
-			RTE_CACHE_LINE_SIZE);
+		n_keys * sizeof(int),
+		RTE_CACHE_LINE_SIZE);
 	if (keys_found == NULL) {
 		rte_free(rules);
 		return -1;
@@ -1197,662 +946,492 @@ app_pipeline_firewall_delete_default_rule(struct app_params *app,
 }
 
 /*
- * p firewall add ipv4
+ * firewall
+ *
+ * firewall add:
+ *    p <pipelineid> firewall add priority <priority>
+ *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
+ *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
+ *       port <portid>
+ *       Note: <protomask> is a hex value
+ *
+ *    p <pipelineid> firewall add bulk <file>
+ *
+ * firewall add default:
+ *    p <pipelineid> firewall add default <port ID>
+ *
+ * firewall del:
+ *    p <pipelineid> firewall del
+ *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
+ *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
+ *
+ *    p <pipelineid> firewall del bulk <file>
+ *
+ * firewall del default:
+ *    p <pipelineid> firewall del default
+ *
+ * firewall ls:
+ *    p <pipelineid> firewall ls
  */
 
-struct cmd_firewall_add_ipv4_result {
+struct cmd_firewall_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_string;
-	int32_t priority;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-	uint8_t port_id;
+	cmdline_multi_string_t multi_string;
 };
 
-static void
-cmd_firewall_add_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
+static void cmd_firewall_parsed(void *parsed_result,
+	__attribute__((unused))  struct cmdline *cl,
 	void *data)
 {
-	struct cmd_firewall_add_ipv4_result *params = parsed_result;
+	struct cmd_firewall_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_firewall_key key;
 	int status;
 
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_add_rule(app,
-		params->pipeline_id,
-		&key,
-		params->priority,
-		params->port_id);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_firewall_add_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_priority =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, priority,
-		INT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip);
+	char *tokens[17];
+	uint32_t n_tokens = RTE_DIM(tokens);
 
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip_mask,
-		UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		src_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_from, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		dst_port_to, UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		proto_mask, UINT8);
-
-cmdline_parse_token_num_t cmd_firewall_add_ipv4_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result,
-		port_id, UINT8);
-
-cmdline_parse_inst_t cmd_firewall_add_ipv4 = {
-	.f = cmd_firewall_add_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_ipv4_p_string,
-		(void *) &cmd_firewall_add_ipv4_pipeline_id,
-		(void *) &cmd_firewall_add_ipv4_firewall_string,
-		(void *) &cmd_firewall_add_ipv4_add_string,
-		(void *) &cmd_firewall_add_ipv4_ipv4_string,
-		(void *) &cmd_firewall_add_ipv4_priority,
-		(void *) &cmd_firewall_add_ipv4_src_ip,
-		(void *) &cmd_firewall_add_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_dst_ip,
-		(void *) &cmd_firewall_add_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_add_ipv4_src_port_from,
-		(void *) &cmd_firewall_add_ipv4_src_port_to,
-		(void *) &cmd_firewall_add_ipv4_dst_port_from,
-		(void *) &cmd_firewall_add_ipv4_dst_port_to,
-		(void *) &cmd_firewall_add_ipv4_proto,
-		(void *) &cmd_firewall_add_ipv4_proto_mask,
-		(void *) &cmd_firewall_add_ipv4_port_id,
-		NULL,
-	},
-};
-
-/*
- * p firewall del ipv4
- */
-
-struct cmd_firewall_del_ipv4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_string;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-};
-
-static void
-cmd_firewall_del_ipv4_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_ipv4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_firewall_key key;
-	int status;
-
-	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.src_ip = rte_bswap32(
-		(uint32_t) params->src_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
-	key.key.ipv4_5tuple.dst_ip = rte_bswap32(
-		(uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
-	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
-	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
-	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
-	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
-	key.key.ipv4_5tuple.proto = params->proto;
-	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
-
-	status = app_pipeline_firewall_delete_rule(app,
-		params->pipeline_id,
-		&key);
-
-	if (status != 0) {
-		printf("Command failed\n");
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
 		return;
 	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		del_string, "del");
 
-cmdline_parse_token_string_t cmd_firewall_del_ipv4_ipv4_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		ipv4_string, "ipv4");
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_src_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip_mask,
-		UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_dst_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip_mask,
-		UINT32);
+	/* firewall add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "priority") == 0)) {
+		struct pipeline_firewall_key key;
+		uint32_t priority;
+		struct in_addr sipaddr;
+		uint32_t sipdepth;
+		struct in_addr dipaddr;
+		uint32_t dipdepth;
+		uint16_t sport0;
+		uint16_t sport1;
+		uint16_t dport0;
+		uint16_t dport1;
+		uint8_t proto;
+		uint8_t protomask;
+		uint32_t port_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 16) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		src_port_from, UINT16);
+		if (parser_read_uint32(&priority, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "priority");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_port_to,
-		UINT16);
+		if (strcmp(tokens[3], "ipv4")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_from, UINT16);
+		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "sipaddr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		dst_port_to, UINT16);
+		if (parser_read_uint32(&sipdepth, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "sipdepth");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result,
-		proto, UINT8);
+		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "dipaddr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, proto_mask,
-		UINT8);
+		if (parser_read_uint32(&dipdepth, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "dipdepth");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_del_ipv4 = {
-	.f = cmd_firewall_del_ipv4_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_ipv4_p_string,
-		(void *) &cmd_firewall_del_ipv4_pipeline_id,
-		(void *) &cmd_firewall_del_ipv4_firewall_string,
-		(void *) &cmd_firewall_del_ipv4_del_string,
-		(void *) &cmd_firewall_del_ipv4_ipv4_string,
-		(void *) &cmd_firewall_del_ipv4_src_ip,
-		(void *) &cmd_firewall_del_ipv4_src_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_dst_ip,
-		(void *) &cmd_firewall_del_ipv4_dst_ip_mask,
-		(void *) &cmd_firewall_del_ipv4_src_port_from,
-		(void *) &cmd_firewall_del_ipv4_src_port_to,
-		(void *) &cmd_firewall_del_ipv4_dst_port_from,
-		(void *) &cmd_firewall_del_ipv4_dst_port_to,
-		(void *) &cmd_firewall_del_ipv4_proto,
-		(void *) &cmd_firewall_del_ipv4_proto_mask,
-		NULL,
-	},
-};
+		if (parser_read_uint16(&sport0, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "sport0");
+			return;
+		}
 
-/*
- * p firewall add bulk
- */
+		if (parser_read_uint16(&sport1, tokens[9])) {
+			printf(CMD_MSG_INVALID_ARG, "sport1");
+			return;
+		}
 
-struct cmd_firewall_add_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
+		if (parser_read_uint16(&dport0, tokens[10])) {
+			printf(CMD_MSG_INVALID_ARG, "dport0");
+			return;
+		}
 
-static void
-cmd_firewall_add_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (parser_read_uint16(&dport1, tokens[11])) {
+			printf(CMD_MSG_INVALID_ARG, "dport1");
+			return;
+		}
 
-	struct app_pipeline_add_bulk_params add_bulk_params;
+		if (parser_read_uint8(&proto, tokens[12])) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-	status = app_pipeline_add_bulk_parse_file(params->file_path, &add_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		if (parser_read_uint8_hex(&protomask, tokens[13])) {
+			printf(CMD_MSG_INVALID_ARG, "protomask");
+			return;
+		}
 
-	status = app_pipeline_firewall_add_bulk(app, params->pipeline_id, add_bulk_params.keys,
-			add_bulk_params.n_keys, add_bulk_params.priorities, add_bulk_params.port_ids);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		if (strcmp(tokens[14], "port")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-end:
-	rte_free(add_bulk_params.keys);
-	rte_free(add_bulk_params.priorities);
-	rte_free(add_bulk_params.port_ids);
-}
+		if (parser_read_uint32(&port_id, tokens[15])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result, p_string,
-		"p");
+		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		key.key.ipv4_5tuple.src_port_from = sport0;
+		key.key.ipv4_5tuple.src_port_to = sport1;
+		key.key.ipv4_5tuple.dst_port_from = dport0;
+		key.key.ipv4_5tuple.dst_port_to = dport1;
+		key.key.ipv4_5tuple.proto = proto;
+		key.key.ipv4_5tuple.proto_mask = protomask;
+
+		status = app_pipeline_firewall_add_rule(app,
+			params->pipeline_id,
+			&key,
+			priority,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add");
 
-cmdline_parse_token_num_t cmd_firewall_add_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_bulk_result, pipeline_id,
-		UINT32);
+		return;
+	} /* firewall add */
+
+	/* firewall add bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_firewall_key *keys;
+		uint32_t *priorities, *port_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		firewall_string, "firewall");
+		filename = tokens[2];
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		add_string, "add");
+		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
+		if (keys == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
+		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		bulk_string, "bulk");
+		priorities = malloc(n_keys * sizeof(uint32_t));
+		if (priorities == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_bulk_result,
-		file_path, NULL);
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_add_bulk = {
-	.f = cmd_firewall_add_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add bulk",
-	.tokens = {
-		(void *) &cmd_firewall_add_bulk_p_string,
-		(void *) &cmd_firewall_add_bulk_pipeline_id,
-		(void *) &cmd_firewall_add_bulk_firewall_string,
-		(void *) &cmd_firewall_add_bulk_add_string,
-		(void *) &cmd_firewall_add_bulk_bulk_string,
-		(void *) &cmd_firewall_add_bulk_file_path_string,
-		NULL,
-	},
-};
+		status = app_pipeline_firewall_load_file(filename,
+			keys,
+			priorities,
+			port_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(port_ids);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-/*
- * p firewall del bulk
- */
+		status = app_pipeline_firewall_add_bulk(app,
+			params->pipeline_id,
+			keys,
+			n_keys,
+			priorities,
+			port_ids);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add bulk");
+
+		free(keys);
+		free(priorities);
+		free(port_ids);
+		return;
+	} /* firewall add bulk */
 
-struct cmd_firewall_del_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t bulk_string;
-	cmdline_fixed_string_t file_path;
-};
+	/* firewall add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-static void
-cmd_firewall_del_bulk_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
+			return;
+		}
 
-	struct app_pipeline_del_bulk_params del_bulk_params;
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	status = app_pipeline_del_bulk_parse_file(params->file_path, &del_bulk_params);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		status = app_pipeline_firewall_add_default_rule(app,
+			params->pipeline_id,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall add default");
 
-	status = app_pipeline_firewall_delete_bulk(app, params->pipeline_id,
-			del_bulk_params.keys, del_bulk_params.n_keys);
-	if (status != 0) {
-		printf("Command failed\n");
-		goto end;
-	}
+		return;
+	} /* firewall add default */
+
+	/* firewall del */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0)) {
+		struct pipeline_firewall_key key;
+		struct in_addr sipaddr;
+		uint32_t sipdepth;
+		struct in_addr dipaddr;
+		uint32_t dipdepth;
+		uint16_t sport0;
+		uint16_t sport1;
+		uint16_t dport0;
+		uint16_t dport1;
+		uint8_t proto;
+		uint8_t protomask;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 12) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
+			return;
+		}
 
-end:
-	rte_free(del_bulk_params.keys);
-}
+		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "sipaddr");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result, p_string,
-		"p");
+		if (parser_read_uint32(&sipdepth, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "sipdepth");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_firewall_del_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_bulk_result, pipeline_id,
-		UINT32);
+		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
+			printf(CMD_MSG_INVALID_ARG, "dipaddr");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		firewall_string, "firewall");
+		if (parser_read_uint32(&dipdepth, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "dipdepth");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		del_string, "del");
+		if (parser_read_uint16(&sport0, tokens[6])) {
+			printf(CMD_MSG_INVALID_ARG, "sport0");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_bulk_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		bulk_string, "bulk");
+		if (parser_read_uint16(&sport1, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "sport1");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_bulk_file_path_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_bulk_result,
-		file_path, NULL);
+		if (parser_read_uint16(&dport0, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "dport0");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_firewall_del_bulk = {
-	.f = cmd_firewall_del_bulk_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule del bulk",
-	.tokens = {
-		(void *) &cmd_firewall_del_bulk_p_string,
-		(void *) &cmd_firewall_del_bulk_pipeline_id,
-		(void *) &cmd_firewall_del_bulk_firewall_string,
-		(void *) &cmd_firewall_del_bulk_add_string,
-		(void *) &cmd_firewall_del_bulk_bulk_string,
-		(void *) &cmd_firewall_del_bulk_file_path_string,
-		NULL,
-	},
-};
+		if (parser_read_uint16(&dport1, tokens[9])) {
+			printf(CMD_MSG_INVALID_ARG, "dport1");
+			return;
+		}
 
-/*
- * p firewall add default
- */
-struct cmd_firewall_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint8_t port_id;
-};
+		if (parser_read_uint8(&proto, tokens[10])) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-static void
-cmd_firewall_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		if (parser_read_uint8_hex(&protomask, tokens[11])) {
+			printf(CMD_MSG_INVALID_ARG, "protomask");
+			return;
+		}
 
-	status = app_pipeline_firewall_add_default_rule(app,
-		params->pipeline_id,
-		params->port_id);
+		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
+		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
+		key.key.ipv4_5tuple.src_port_from = sport0;
+		key.key.ipv4_5tuple.src_port_to = sport1;
+		key.key.ipv4_5tuple.dst_port_from = dport0;
+		key.key.ipv4_5tuple.dst_port_to = dport1;
+		key.key.ipv4_5tuple.proto = proto;
+		key.key.ipv4_5tuple.proto_mask = protomask;
+
+		status = app_pipeline_firewall_delete_rule(app,
+			params->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_firewall_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_add_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-	add_string, "add");
+	} /* firewall del */
+
+	/* firewall del bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_firewall_key *keys;
+		uint32_t *priorities, *port_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
-		default_string, "default");
+		filename = tokens[2];
 
-cmdline_parse_token_num_t cmd_firewall_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result, port_id,
-		UINT8);
+		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
+		if (keys == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
+		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
 
-cmdline_parse_inst_t cmd_firewall_add_default = {
-	.f = cmd_firewall_add_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule add",
-	.tokens = {
-		(void *) &cmd_firewall_add_default_p_string,
-		(void *) &cmd_firewall_add_default_pipeline_id,
-		(void *) &cmd_firewall_add_default_firewall_string,
-		(void *) &cmd_firewall_add_default_add_string,
-		(void *) &cmd_firewall_add_default_default_string,
-		(void *) &cmd_firewall_add_default_port_id,
-		NULL,
-	},
-};
+		priorities = malloc(n_keys * sizeof(uint32_t));
+		if (priorities == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(keys);
+			return;
+		}
 
-/*
- * p firewall del default
- */
-struct cmd_firewall_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-static void
-cmd_firewall_del_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		status = app_pipeline_firewall_load_file(filename,
+			keys,
+			priorities,
+			port_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(port_ids);
+			free(priorities);
+			free(keys);
+			return;
+		}
 
-	status = app_pipeline_firewall_delete_default_rule(app,
-		params->pipeline_id);
+		status = app_pipeline_firewall_delete_bulk(app,
+			params->pipeline_id,
+			keys,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del bulk");
 
-	if (status != 0) {
-		printf("Command failed\n");
+		free(port_ids);
+		free(priorities);
+		free(keys);
 		return;
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_firewall_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_default_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_firewall_del_default_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		del_string, "del");
+	} /* firewall del bulk */
+
+	/* firewall del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_firewall_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
-		default_string, "default");
+		status = app_pipeline_firewall_delete_default_rule(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall del default");
 
-cmdline_parse_inst_t cmd_firewall_del_default = {
-	.f = cmd_firewall_del_default_parsed,
-	.data = NULL,
-	.help_str = "Firewall default rule delete",
-	.tokens = {
-		(void *) &cmd_firewall_del_default_p_string,
-		(void *) &cmd_firewall_del_default_pipeline_id,
-		(void *) &cmd_firewall_del_default_firewall_string,
-		(void *) &cmd_firewall_del_default_del_string,
-		(void *) &cmd_firewall_del_default_default_string,
-		NULL,
-	},
-};
+		return;
 
-/*
- * p firewall ls
- */
+	} /* firewall del default */
 
-struct cmd_firewall_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_firewall_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	/* firewall ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
+			return;
+		}
 
-	status = app_pipeline_firewall_ls(app, params->pipeline_id);
+		status = app_pipeline_firewall_ls(app, params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "firewall ls");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
+	} /* firewall ls */
+
+	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
 }
 
-cmdline_parse_token_string_t cmd_firewall_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, p_string,
-		"p");
+static cmdline_parse_token_string_t cmd_firewall_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_firewall_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_ls_result, pipeline_id,
-		UINT32);
+static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_firewall_ls_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result,
-	firewall_string, "firewall");
+static cmdline_parse_token_string_t cmd_firewall_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
+	"firewall");
 
-cmdline_parse_token_string_t cmd_firewall_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_firewall_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_firewall_ls = {
-	.f = cmd_firewall_ls_parsed,
+static cmdline_parse_inst_t cmd_firewall = {
+	.f = cmd_firewall_parsed,
 	.data = NULL,
-	.help_str = "Firewall rule list",
+	.help_str =	"firewall add / add bulk / add default / del / del bulk"
+		" / del default / ls",
 	.tokens = {
-		(void *) &cmd_firewall_ls_p_string,
-		(void *) &cmd_firewall_ls_pipeline_id,
-		(void *) &cmd_firewall_ls_firewall_string,
-		(void *) &cmd_firewall_ls_ls_string,
+		(void *) &cmd_firewall_p_string,
+		(void *) &cmd_firewall_pipeline_id,
+		(void *) &cmd_firewall_firewall_string,
+		(void *) &cmd_firewall_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall_add_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_ipv4,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_bulk,
-	(cmdline_parse_inst_t *) &cmd_firewall_add_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_del_default,
-	(cmdline_parse_inst_t *) &cmd_firewall_ls,
+	(cmdline_parse_inst_t *) &cmd_firewall,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.h b/examples/ip_pipeline/pipeline/pipeline_firewall.h
index ccc4e64..aa79a2a 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.h
@@ -72,6 +72,18 @@ int
 app_pipeline_firewall_delete_default_rule(struct app_params *app,
 	uint32_t pipeline_id);
 
+#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
+#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
+#endif
+
+int
+app_pipeline_firewall_load_file(char *filename,
+	struct pipeline_firewall_key *keys,
+	uint32_t *priorities,
+	uint32_t *port_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_firewall;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 4/7] examples/ip_pipeline: modifies flow classifications pipeline CLI
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
                       ` (2 preceding siblings ...)
  2016-06-08 10:35     ` [PATCH v3 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
                       ` (3 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Tomasz Kulasek, Marcin Kerlin, Slawomir Mrozowicz, Michal Kobylinski

From: Tomasz Kulasek <tomaszx.kulasek@intel.com>

This patch modifies flow classifications pipeline command line
interface. All commands are merged into one cmd_fc_parsed.
Additionally a classification for ipv6, ipv4 and qinq can be added from
configuration file.

1. flow add qinq bulk
File line format:
qinq <svlan> <cvlan> port <port ID> id <flow ID>
File line example:
qinq 1 2 port 3 id 0

2. flow add ipv4 bulk
File line format:
ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>
File line example:
ipv4 1.2.3.4 10.20.30.40 63 127 6 port 2 id 999

3. flow add ipv6 bulk
File line format:
ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id
<flowID>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Michal Kobylinski <michalx.kobylinski@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/flow.cfg               |   72 +
 examples/ip_pipeline/config/flow.sh                |   25 +
 examples/ip_pipeline/config/flow.txt               |   17 +
 .../pipeline/pipeline_flow_classification.c        | 2082 +++++++++-----------
 .../pipeline/pipeline_flow_classification.h        |   28 +
 5 files changed, 1027 insertions(+), 1197 deletions(-)
 create mode 100644 examples/ip_pipeline/config/flow.cfg
 create mode 100644 examples/ip_pipeline/config/flow.sh
 create mode 100644 examples/ip_pipeline/config/flow.txt

diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
new file mode 100644
index 0000000..6895d39
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.cfg
@@ -0,0 +1,72 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ________________
+; RXQ0.0 --->|                |---> TXQ0.0
+;            |                |
+; RXQ1.0 --->|                |---> TXQ1.0
+;            |      Flow      |
+; RXQ2.0 --->| Classification |---> TXQ2.0
+;            |                |
+; RXQ3.0 --->|                |---> TXQ3.0
+;            |________________|
+;                    |
+;                    +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FLOW_CLASSIFICATION
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+n_flows = 65536
+;key_size = 8                ; QinQ key size
+;key_offset = 270            ; QinQ key offset
+;key_mask = 0000FFF00000FFF0 ; QinQ key mask
+key_size = 16                               ; IPv4 5-tuple key size
+key_offset = 278                            ; IPv4 5-tuple key offset
+key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
+flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
new file mode 100644
index 0000000..489c707
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.sh
@@ -0,0 +1,25 @@
+#
+# run ./config/flow.sh
+#
+
+################################################################################
+# Flow classification (QinQ)
+################################################################################
+#p 1 flow add default 4 #SINK0
+#p 1 flow add qinq 100 200 port 0 id 0
+#p 1 flow add qinq 101 201 port 1 id 1
+#p 1 flow add qinq 102 202 port 2 id 2
+#p 1 flow add qinq 103 203 port 3 id 3
+
+#p 1 flow add qinq bulk ./config/flow.txt
+
+################################################################################
+# Flow classification (IPv4 5-tuple)
+################################################################################
+p 1 flow add default 4 #SINK0
+p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
+p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
+p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
+p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
+
+#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
new file mode 100644
index 0000000..c1a141d
--- /dev/null
+++ b/examples/ip_pipeline/config/flow.txt
@@ -0,0 +1,17 @@
+#
+# p <pipelineid> flow add qinq bulk ./config/flow.txt
+#
+
+#qinq 100 200 port 0 id 0
+#qinq 101 201 port 1 id 1
+#qinq 102 202 port 2 id 2
+#qinq 103 203 port 3 id 3
+
+#
+# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
+#
+
+ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
+ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
+ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
+ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
index 1921574..e49c881 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -43,13 +44,12 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_classification.h"
 #include "hash_func.h"
+#include "parser.h"
 
 /*
  * Key conversion
@@ -96,9 +96,9 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		struct pkt_key_qinq *qinq = key_buffer;
 
 		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_bswap16(key_in->key.qinq.svlan);
+		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
 		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_bswap16(key_in->key.qinq.cvlan);
+		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key8(qinq, 8, 0);
@@ -112,10 +112,10 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		ipv4->ttl = 0;
 		ipv4->proto = key_in->key.ipv4_5tuple.proto;
 		ipv4->checksum = 0;
-		ipv4->ip_src = rte_bswap32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_bswap32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_bswap16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_bswap16(key_in->key.ipv4_5tuple.port_dst);
+		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
+		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
+		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
+		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key16(ipv4, 16, 0);
@@ -132,8 +132,8 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
 		ipv6->hop_limit = 0;
 		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
 		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_bswap16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_bswap16(key_in->key.ipv6_5tuple.port_dst);
+		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
+		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
 
 		if (signature)
 			*signature = (uint32_t) hash_default_key64(ipv6, 64, 0);
@@ -278,6 +278,283 @@ app_pipeline_fc_key_check(struct pipeline_fc_key *key)
 }
 
 int
+app_pipeline_fc_load_file_qinq(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		uint16_t svlan, cvlan;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 7) ||
+			strcmp(tokens[0], "qinq") ||
+			parser_read_uint16(&svlan, tokens[1]) ||
+			parser_read_uint16(&cvlan, tokens[2]) ||
+			strcmp(tokens[3], "port") ||
+			parser_read_uint32(&portid, tokens[4]) ||
+			strcmp(tokens[5], "id") ||
+			parser_read_uint32(&flowid, tokens[6]))
+			goto error1;
+
+		keys[i].type = FLOW_KEY_QINQ;
+		keys[i].key.qinq.svlan = svlan;
+		keys[i].key.qinq.cvlan = cvlan;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error1;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error1:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+int
+app_pipeline_fc_load_file_ipv4(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		struct in_addr sipaddr, dipaddr;
+		uint16_t sport, dport;
+		uint8_t proto;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error2;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 10) ||
+			strcmp(tokens[0], "ipv4") ||
+			parse_ipv4_addr(tokens[1], &sipaddr) ||
+			parse_ipv4_addr(tokens[2], &dipaddr) ||
+			parser_read_uint16(&sport, tokens[3]) ||
+			parser_read_uint16(&dport, tokens[4]) ||
+			parser_read_uint8(&proto, tokens[5]) ||
+			strcmp(tokens[6], "port") ||
+			parser_read_uint32(&portid, tokens[7]) ||
+			strcmp(tokens[8], "id") ||
+			parser_read_uint32(&flowid, tokens[9]))
+			goto error2;
+
+		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
+		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		keys[i].key.ipv4_5tuple.port_src = sport;
+		keys[i].key.ipv4_5tuple.port_dst = dport;
+		keys[i].key.ipv4_5tuple.proto = proto;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error2;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error2:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+int
+app_pipeline_fc_load_file_ipv6(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line)
+{
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
+
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(keys == NULL) ||
+		(port_ids == NULL) ||
+		(flow_ids == NULL) ||
+		(n_keys == NULL) ||
+		(*n_keys == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
+
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
+	}
+
+	/* Read file */
+	for (i = 0, l = 1; i < *n_keys; l++) {
+		char *tokens[32];
+		uint32_t n_tokens = RTE_DIM(tokens);
+
+		struct in6_addr sipaddr, dipaddr;
+		uint16_t sport, dport;
+		uint8_t proto;
+		uint32_t portid, flowid;
+		int status;
+
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
+
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error3;
+
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
+
+		if ((n_tokens != 10) ||
+			strcmp(tokens[0], "ipv6") ||
+			parse_ipv6_addr(tokens[1], &sipaddr) ||
+			parse_ipv6_addr(tokens[2], &dipaddr) ||
+			parser_read_uint16(&sport, tokens[3]) ||
+			parser_read_uint16(&dport, tokens[4]) ||
+			parser_read_uint8(&proto, tokens[5]) ||
+			strcmp(tokens[6], "port") ||
+			parser_read_uint32(&portid, tokens[7]) ||
+			strcmp(tokens[8], "id") ||
+			parser_read_uint32(&flowid, tokens[9]))
+			goto error3;
+
+		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(keys[i].key.ipv6_5tuple.ip_src,
+			sipaddr.s6_addr,
+			sizeof(sipaddr.s6_addr));
+		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
+			dipaddr.s6_addr,
+			sizeof(dipaddr.s6_addr));
+		keys[i].key.ipv6_5tuple.port_src = sport;
+		keys[i].key.ipv6_5tuple.port_dst = dport;
+		keys[i].key.ipv6_5tuple.proto = proto;
+
+		port_ids[i] = portid;
+		flow_ids[i] = flowid;
+
+		if (app_pipeline_fc_key_check(&keys[i]))
+			goto error3;
+
+		i++;
+	}
+
+	/* Close file */
+	*n_keys = i;
+	fclose(f);
+	return 0;
+
+error3:
+	*line = l;
+	fclose(f);
+	return -1;
+}
+
+
+
+int
 app_pipeline_fc_add(struct app_params *app,
 	uint32_t pipeline_id,
 	struct pipeline_fc_key *key,
@@ -896,1309 +1173,720 @@ app_pipeline_fc_ls(struct app_params *app,
 
 	return 0;
 }
-
 /*
- * flow add qinq
- */
-
-struct cmd_fc_add_qinq_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
-
-static void
-cmd_fc_add_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, cvlan, UINT16);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, port_string,
-		"port");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, port, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_qinq_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flowid_string,
-		"flowid");
-
-cmdline_parse_token_num_t cmd_fc_add_qinq_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, flow_id, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_qinq = {
-	.f = cmd_fc_add_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow add (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_p_string,
-		(void *) &cmd_fc_add_qinq_pipeline_id,
-		(void *) &cmd_fc_add_qinq_flow_string,
-		(void *) &cmd_fc_add_qinq_add_string,
-		(void *) &cmd_fc_add_qinq_qinq_string,
-		(void *) &cmd_fc_add_qinq_svlan,
-		(void *) &cmd_fc_add_qinq_cvlan,
-		(void *) &cmd_fc_add_qinq_port_string,
-		(void *) &cmd_fc_add_qinq_port,
-		(void *) &cmd_fc_add_qinq_flowid_string,
-		(void *) &cmd_fc_add_qinq_flow_id,
-		NULL,
-	},
-};
-
-/*
- * flow add qinq all
+ * flow
+ *
+ * flow add:
+ *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
+ *    p <pipelineid> flow add qinq bulk <file>
+ *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
+ *    p <pipelineid> flow add ipv4 bulk <file>
+ *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
+ *    p <pipelineid> flow add ipv6 bulk <file>
+ *
+ * flow add default:
+ *    p <pipelineid> flow add default <portid>
+ *
+ * flow del:
+ *    p <pipelineid> flow del qinq <svlan> <cvlan>
+ *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
+ *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
+ *
+ * flow del default:
+ *    p <pipelineid> flow del default
+ *
+ * flow ls:
+ *    p <pipelineid> flow ls
  */
 
-struct cmd_fc_add_qinq_all_result {
+struct cmd_flow_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
 	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t qinq_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
+	cmdline_multi_string_t multi_string;
 };
 
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
 static void
-cmd_fc_add_qinq_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
+cmd_flow_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
 	void *data)
 {
-	struct cmd_fc_add_qinq_all_result *params = parsed_result;
+	struct cmd_flow_result *results = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input arguments */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of output ports\n");
-		return;
-	}
-
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
-
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
+	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
+	if (status) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
 		return;
 	}
 
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-
-		key[pos].type = FLOW_KEY_QINQ;
-		key[pos].key.qinq.svlan = id >> 12;
-		key[pos].key.qinq.cvlan = id & 0xFFF;
-
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* flow add qinq */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		uint32_t svlan;
+		uint32_t cvlan;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 8) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
+			return;
 		}
-	}
-
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, p_string,
-		"p");
+		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "svlan");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "cvlan");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, flow_string,
-		"flow");
+		if (strcmp(tokens[4], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, add_string,
-		"add");
+		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, qinq_string,
-		"qinq");
+		if (strcmp(tokens[6], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_qinq_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_all_result, all_string,
-		"all");
+		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_flows,
-		UINT32);
+		key.type = FLOW_KEY_QINQ;
+		key.key.qinq.svlan = svlan;
+		key.key.qinq.cvlan = cvlan;
 
-cmdline_parse_token_num_t cmd_fc_add_qinq_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_all_result, n_ports,
-		UINT32);
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add qinq");
 
-cmdline_parse_inst_t cmd_fc_add_qinq_all = {
-	.f = cmd_fc_add_qinq_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_add_qinq_all_p_string,
-		(void *) &cmd_fc_add_qinq_all_pipeline_id,
-		(void *) &cmd_fc_add_qinq_all_flow_string,
-		(void *) &cmd_fc_add_qinq_all_add_string,
-		(void *) &cmd_fc_add_qinq_all_qinq_string,
-		(void *) &cmd_fc_add_qinq_all_all_string,
-		(void *) &cmd_fc_add_qinq_all_n_flows,
-		(void *) &cmd_fc_add_qinq_all_n_ports,
-		NULL,
-	},
-};
+		return;
+	} /* flow add qinq */
+
+	/* flow add ipv4 */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		struct in_addr sipaddr;
+		struct in_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 11) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
+			return;
+		}
 
-/*
- * flow add ipv4_5tuple
- */
+		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
+			return;
+		}
+		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
+			return;
+		}
 
-struct cmd_fc_add_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-static void
-cmd_fc_add_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, p_string,
-		"p");
+		if (strcmp(tokens[7], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flow_string, "flow");
+		if (strcmp(tokens[9], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		add_string, "add");
+		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
+		key.type = FLOW_KEY_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.port_src = sport;
+		key.key.ipv4_5tuple.port_dst = dport;
+		key.key.ipv4_5tuple.proto = proto;
+
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv4");
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_src);
+		return;
+	} /* flow add ipv4 */
+
+	/* flow add ipv6 */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0) &&
+		strcmp(tokens[2], "bulk")) {
+		struct pipeline_fc_key key;
+		struct in6_addr sipaddr;
+		struct in6_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+		uint32_t port_id;
+		uint32_t flow_id;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 11) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_dst);
+		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
+			return;
+		}
+		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_src,
-		UINT16);
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_dst,
-		UINT16);
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, proto,
-		UINT32);
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_string,
-		"port");
+		if (strcmp(tokens[7], "port") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port,
-		UINT32);
+		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,
-		flowid_string, "flowid");
+		if (strcmp(tokens[9], "id") != 0) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "id");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, flow_id,
-		UINT32);
+		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {
-	.f = cmd_fc_add_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv4_5tuple_proto,
-		(void *) &cmd_fc_add_ipv4_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_port,
-		(void *) &cmd_fc_add_ipv4_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_flow_id,
-		NULL,
-	},
-};
+		key.type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
+		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
+		key.key.ipv6_5tuple.port_src = sport;
+		key.key.ipv6_5tuple.port_dst = dport;
+		key.key.ipv6_5tuple.proto = proto;
+
+		status = app_pipeline_fc_add(app,
+			results->pipeline_id,
+			&key,
+			port_id,
+			flow_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv6");
 
-/*
- * flow add ipv4_5tuple all
- */
+		return;
+	} /* flow add ipv6 */
+
+	/* flow add qinq bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
+			return;
+		}
 
-struct cmd_fc_add_ipv4_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+		filename = tokens[3];
 
-static void
-cmd_fc_add_ipv4_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv4_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fc_load_file_qinq(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add qinq bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
 		return;
-	}
-
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
+	} /* flow add qinq bulk */
+
+	/* flow add ipv4 bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
+			return;
+		}
 
-		key[pos].type = FLOW_KEY_IPV4_5TUPLE;
-		key[pos].key.ipv4_5tuple.ip_src = 0;
-		key[pos].key.ipv4_5tuple.ip_dst = id;
-		key[pos].key.ipv4_5tuple.port_src = 0;
-		key[pos].key.ipv4_5tuple.port_dst = 0;
-		key[pos].key.ipv4_5tuple.proto = 6;
+		filename = tokens[3];
 
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-			if (status != 0) {
-				printf("Command failed\n");
+		status = app_pipeline_fc_load_file_ipv4(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-				break;
-			}
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
+		return;
+	} /* flow add ipv4 bulk */
+
+	/* flow add ipv6 bulk */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0) &&
+		(strcmp(tokens[2], "bulk") == 0)) {
+		struct pipeline_fc_key *keys;
+		uint32_t *port_ids, *flow_ids, n_keys, line;
+		char *filename;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
+			return;
 		}
-	}
 
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
+		filename = tokens[3];
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		p_string, "p");
+		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
+		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
+		if (keys == NULL)
+			return;
+		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		pipeline_id, UINT32);
+		port_ids = malloc(n_keys * sizeof(uint32_t));
+		if (port_ids == NULL) {
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		flow_string, "flow");
+		flow_ids = malloc(n_keys * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		add_string, "add");
+		status = app_pipeline_fc_load_file_ipv6(filename,
+			keys,
+			port_ids,
+			flow_ids,
+			&n_keys,
+			&line);
+		if (status != 0) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_ids);
+			free(port_ids);
+			free(keys);
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
+		status = app_pipeline_fc_add_bulk(app,
+			results->pipeline_id,
+			keys,
+			port_ids,
+			flow_ids,
+			n_keys);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
+
+		free(flow_ids);
+		free(port_ids);
+		free(keys);
+		return;
+	} /* flow add ipv6 bulk */
 
-cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		all_string, "all");
+	/* flow add default*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_flows, UINT32);
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_all_result,
-		n_ports, UINT32);
+		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple_all = {
-	.f = cmd_fc_add_ipv4_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv4_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_ipv4_5tuple_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv4_5tuple_all_n_ports,
-		NULL,
-	},
-};
+		status = app_pipeline_fc_add_default(app,
+			results->pipeline_id,
+			port_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow add default");
 
-/*
- * flow add ipv6_5tuple
- */
+		return;
+	} /* flow add default */
 
-struct cmd_fc_add_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t flowid_string;
-	uint32_t flow_id;
-};
+	/* flow del qinq */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "qinq") == 0)) {
+		struct pipeline_fc_key key;
+		uint32_t svlan;
+		uint32_t cvlan;
 
-static void
-cmd_fc_add_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
+		memset(&key, 0, sizeof(key));
 
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_add(app,
-		params->pipeline_id,
-		&key,
-		params->port,
-		params->flow_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		p_string, "p");
+		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "svlan");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, pipeline_id,
-		UINT32);
+		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "cvlan");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flow_string, "flow");
+		key.type = FLOW_KEY_QINQ;
+		key.key.qinq.svlan = svlan;
+		key.key.qinq.cvlan = cvlan;
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		add_string, "add");
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del qinq");
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
+		return;
+	} /* flow del qinq */
+
+	/* flow del ipv4 */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv4") == 0)) {
+		struct pipeline_fc_key key;
+		struct in_addr sipaddr;
+		struct in_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 7) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_src);
+		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
+			return;
+		}
+		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
+			return;
+		}
 
-cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_dst);
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_src,
-		UINT16);
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_dst,
-		UINT16);
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, proto,
-		UINT32);
+		key.type = FLOW_KEY_IPV4_5TUPLE;
+		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
+		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
+		key.key.ipv4_5tuple.port_src = sport;
+		key.key.ipv4_5tuple.port_dst = dport;
+		key.key.ipv4_5tuple.proto = proto;
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		port_string, "port");
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del ipv4");
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port,
-		UINT32);
+		return;
+	} /* flow del ipv4 */
+
+	/* flow del ipv6 */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "ipv6") == 0)) {
+		struct pipeline_fc_key key;
+		struct in6_addr sipaddr;
+		struct in6_addr dipaddr;
+		uint32_t sport;
+		uint32_t dport;
+		uint32_t proto;
+
+		memset(&key, 0, sizeof(key));
+
+		if (n_tokens != 7) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flowid_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,
-		flowid_string, "flowid");
+		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, flow_id,
-		UINT32);
+		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {
-	.f = cmd_fc_add_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow add (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_add_ipv6_5tuple_proto,
-		(void *) &cmd_fc_add_ipv6_5tuple_port_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_port,
-		(void *) &cmd_fc_add_ipv6_5tuple_flowid_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_flow_id,
-		NULL,
-	},
-};
+		if (parser_read_uint32(&sport, tokens[4]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "sport");
+			return;
+		}
 
-/*
- * flow add ipv6_5tuple all
- */
+		if (parser_read_uint32(&dport, tokens[5]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "dport");
+			return;
+		}
 
-struct cmd_fc_add_ipv6_5tuple_all_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_fixed_string_t all_string;
-	uint32_t n_flows;
-	uint32_t n_ports;
-};
+		if (parser_read_uint32(&proto, tokens[6]) != 0) {
+			printf(CMD_MSG_INVALID_ARG, "proto");
+			return;
+		}
 
-static void
-cmd_fc_add_ipv6_5tuple_all_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_ipv6_5tuple_all_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key *key;
-	uint32_t *port_id;
-	uint32_t *flow_id;
-	uint32_t id;
-
-	/* Check input parameters */
-	if (params->n_flows == 0) {
-		printf("Invalid number of flows\n");
-		return;
-	}
+		key.type = FLOW_KEY_IPV6_5TUPLE;
+		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
+		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
+		key.key.ipv6_5tuple.port_src = sport;
+		key.key.ipv6_5tuple.port_dst = dport;
+		key.key.ipv6_5tuple.proto = proto;
 
-	if (params->n_ports == 0) {
-		printf("Invalid number of ports\n");
-		return;
-	}
+		status = app_pipeline_fc_del(app,
+			results->pipeline_id,
+			&key);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del ipv6");
 
-	/* Memory allocation */
-	key = rte_zmalloc(NULL,
-		N_FLOWS_BULK * sizeof(*key),
-		RTE_CACHE_LINE_SIZE);
-	if (key == NULL) {
-		printf("Memory allocation failed\n");
 		return;
-	}
+	} /* flow del ipv6 */
+
+	/* flow del default*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
+			return;
+		}
 
-	port_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*port_id),
-		RTE_CACHE_LINE_SIZE);
-	if (port_id == NULL) {
-		rte_free(key);
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fc_del_default(app,
+			results->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow del default");
 
-	flow_id = rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(*flow_id),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		rte_free(port_id);
-		rte_free(key);
-		printf("Memory allocation failed\n");
 		return;
-	}
-
-	/* Flow add */
-	for (id = 0; id < params->n_flows; id++) {
-		uint32_t pos = id & (N_FLOWS_BULK - 1);
-		uint32_t *x;
-
-		key[pos].type = FLOW_KEY_IPV6_5TUPLE;
-		x = (uint32_t *) key[pos].key.ipv6_5tuple.ip_dst;
-		*x = rte_bswap32(id);
-		key[pos].key.ipv6_5tuple.proto = 6;
-
-		port_id[pos] = id % params->n_ports;
-		flow_id[pos] = id;
+	} /* flow del default */
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(id == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fc_add_bulk(app,
-				params->pipeline_id,
-				key,
-				port_id,
-				flow_id,
-				pos + 1);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* flow ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
+			return;
 		}
-	}
-
-	/* Memory free */
-	rte_free(flow_id);
-	rte_free(port_id);
-	rte_free(key);
-}
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		all_string, "all");
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_flows, UINT32);
-
-cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_all_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_all_result,
-		n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple_all = {
-	.f = cmd_fc_add_ipv6_5tuple_all_parsed,
-	.data = NULL,
-	.help_str = "Flow add all (ipv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_add_ipv6_5tuple_all_p_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_pipeline_id,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_flow_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_add_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_ipv6_5tuple_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_all_string,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_flows,
-		(void *) &cmd_fc_add_ipv6_5tuple_all_n_ports,
-		NULL,
-	},
-};
-
-/*
- * flow del qinq
- */
-struct cmd_fc_del_qinq_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t qinq_string;
-	uint16_t svlan;
-	uint16_t cvlan;
-};
-
-static void
-cmd_fc_del_qinq_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_qinq_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_QINQ;
-	key.key.qinq.svlan = params->svlan;
-	key.key.qinq.cvlan = params->cvlan;
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_qinq_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, qinq_string,
-		"qinq");
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, svlan, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_qinq_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, cvlan, UINT16);
-
-cmdline_parse_inst_t cmd_fc_del_qinq = {
-	.f = cmd_fc_del_qinq_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (Q-in-Q)",
-	.tokens = {
-		(void *) &cmd_fc_del_qinq_p_string,
-		(void *) &cmd_fc_del_qinq_pipeline_id,
-		(void *) &cmd_fc_del_qinq_flow_string,
-		(void *) &cmd_fc_del_qinq_del_string,
-		(void *) &cmd_fc_del_qinq_qinq_string,
-		(void *) &cmd_fc_del_qinq_svlan,
-		(void *) &cmd_fc_del_qinq_cvlan,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv4_5tuple
- */
-
-struct cmd_fc_del_ipv4_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv4_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv4_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv4_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV4_5TUPLE;
-	key.key.ipv4_5tuple.ip_src = rte_bswap32(
-		params->ip_src.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.ip_dst = rte_bswap32(
-		params->ip_dst.addr.ipv4.s_addr);
-	key.key.ipv4_5tuple.port_src = params->port_src;
-	key.key.ipv4_5tuple.port_dst = params->port_dst;
-	key.key.ipv4_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		p_string, "p");
 
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		pipeline_id, UINT32);
+		status = app_pipeline_fc_ls(app, results->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "flow ls");
 
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ipv4_5tuple_string, "ipv4_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_src =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_dst =
-	TOKEN_IPV4_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_src, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		port_dst, UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result,
-		proto, UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv4_5tuple = {
-	.f = cmd_fc_del_ipv4_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv4 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv4_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv4_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv4_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv4_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow del ipv6_5tuple
- */
-
-struct cmd_fc_del_ipv6_5tuple_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t ipv6_5tuple_string;
-	cmdline_ipaddr_t ip_src;
-	cmdline_ipaddr_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-	uint32_t proto;
-};
-
-static void
-cmd_fc_del_ipv6_5tuple_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_ipv6_5tuple_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fc_key key;
-	int status;
-
-	memset(&key, 0, sizeof(key));
-	key.type = FLOW_KEY_IPV6_5TUPLE;
-	memcpy(key.key.ipv6_5tuple.ip_src,
-		params->ip_src.addr.ipv6.s6_addr,
-		16);
-	memcpy(key.key.ipv6_5tuple.ip_dst,
-		params->ip_dst.addr.ipv6.s6_addr,
-		16);
-	key.key.ipv6_5tuple.port_src = params->port_src;
-	key.key.ipv6_5tuple.port_dst = params->port_dst;
-	key.key.ipv6_5tuple.proto = params->proto;
-
-	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		p_string, "p");
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		flow_string, "flow");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		del_string, "del");
-
-cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result,
-		ipv6_5tuple_string, "ipv6_5tuple");
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_src =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_src);
-
-cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_dst =
-	TOKEN_IPV6_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_dst);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_src =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_src,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_dst =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_dst,
-		UINT16);
-
-cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, proto,
-		UINT32);
-
-cmdline_parse_inst_t cmd_fc_del_ipv6_5tuple = {
-	.f = cmd_fc_del_ipv6_5tuple_parsed,
-	.data = NULL,
-	.help_str = "Flow delete (IPv6 5-tuple)",
-	.tokens = {
-		(void *) &cmd_fc_del_ipv6_5tuple_p_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_pipeline_id,
-		(void *) &cmd_fc_del_ipv6_5tuple_flow_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_del_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_ip_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_src,
-		(void *) &cmd_fc_del_ipv6_5tuple_port_dst,
-		(void *) &cmd_fc_del_ipv6_5tuple_proto,
-		NULL,
-	},
-};
-
-/*
- * flow add default
- */
-
-struct cmd_fc_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_fc_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_add_default(app, params->pipeline_id,
-		params->port);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_add_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_add_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result, add_string,
-		"add");
-
-cmdline_parse_token_string_t cmd_fc_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_result,
-		default_string, "default");
-
-cmdline_parse_token_num_t cmd_fc_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_result, port, UINT32);
-
-cmdline_parse_inst_t cmd_fc_add_default = {
-	.f = cmd_fc_add_default_parsed,
-	.data = NULL,
-	.help_str = "Flow add default",
-	.tokens = {
-		(void *) &cmd_fc_add_default_p_string,
-		(void *) &cmd_fc_add_default_pipeline_id,
-		(void *) &cmd_fc_add_default_flow_string,
-		(void *) &cmd_fc_add_default_add_string,
-		(void *) &cmd_fc_add_default_default_string,
-		(void *) &cmd_fc_add_default_port,
-		NULL,
-	},
-};
-
-/*
- * flow del default
- */
-
-struct cmd_fc_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_fc_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fc_del_default(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fc_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, p_string,
-		"p");
-
-cmdline_parse_token_num_t cmd_fc_del_default_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_result, pipeline_id,
-		UINT32);
-
-cmdline_parse_token_string_t cmd_fc_del_default_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, flow_string,
-		"flow");
-
-cmdline_parse_token_string_t cmd_fc_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result, del_string,
-		"del");
-
-cmdline_parse_token_string_t cmd_fc_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_result,
-		default_string, "default");
-
-cmdline_parse_inst_t cmd_fc_del_default = {
-	.f = cmd_fc_del_default_parsed,
-	.data = NULL,
-	.help_str = "Flow delete default",
-	.tokens = {
-		(void *) &cmd_fc_del_default_p_string,
-		(void *) &cmd_fc_del_default_pipeline_id,
-		(void *) &cmd_fc_del_default_flow_string,
-		(void *) &cmd_fc_del_default_del_string,
-		(void *) &cmd_fc_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * flow ls
- */
-
-struct cmd_fc_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_fc_ls_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fc_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		return;
+	} /* flow ls */
 
-	status = app_pipeline_fc_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
+	printf(CMD_MSG_MISMATCH_ARGS, "flow");
 }
 
-cmdline_parse_token_string_t cmd_fc_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, p_string, "p");
+static cmdline_parse_token_string_t cmd_flow_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fc_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fc_ls_result, pipeline_id, UINT32);
+static cmdline_parse_token_num_t cmd_flow_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fc_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result,
-	flow_string, "flow");
+static cmdline_parse_token_string_t cmd_flow_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
 
-cmdline_parse_token_string_t cmd_fc_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_flow_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
+		TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fc_ls = {
-	.f = cmd_fc_ls_parsed,
+static cmdline_parse_inst_t cmd_flow = {
+	.f = cmd_flow_parsed,
 	.data = NULL,
-	.help_str = "Flow list",
+	.help_str = "flow add / add bulk / add default / del / del default / ls",
 	.tokens = {
-		(void *) &cmd_fc_ls_p_string,
-		(void *) &cmd_fc_ls_pipeline_id,
-		(void *) &cmd_fc_ls_flow_string,
-		(void *) &cmd_fc_ls_ls_string,
+		(void *) &cmd_flow_p_string,
+		(void *) &cmd_flow_pipeline_id,
+		(void *) &cmd_flow_flow_string,
+		(void *) &cmd_flow_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_del_qinq,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv4_5tuple,
-	(cmdline_parse_inst_t *) &cmd_fc_del_ipv6_5tuple,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_default,
-	(cmdline_parse_inst_t *) &cmd_fc_del_default,
-
-	(cmdline_parse_inst_t *) &cmd_fc_add_qinq_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple_all,
-	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple_all,
-
-	(cmdline_parse_inst_t *) &cmd_fc_ls,
+	(cmdline_parse_inst_t *) &cmd_flow,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
index 9c77500..6c5ed38 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
@@ -102,6 +102,34 @@ int
 app_pipeline_fc_del_default(struct app_params *app,
 	uint32_t pipeline_id);
 
+#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
+#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
+#endif
+
+int
+app_pipeline_fc_load_file_qinq(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
+int
+app_pipeline_fc_load_file_ipv4(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
+int
+app_pipeline_fc_load_file_ipv6(char *filename,
+	struct pipeline_fc_key *keys,
+	uint32_t *port_ids,
+	uint32_t *flow_ids,
+	uint32_t *n_keys,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_flow_classification;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 5/7] examples/ip_pipeline: modifies flow action pipeline CLI
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
                       ` (3 preceding siblings ...)
  2016-06-08 10:35     ` [PATCH v3 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
                       ` (2 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz, Marcin Kerlin

All commands merged into one: cmd_action_parsed.

modified bulk command:
action flow bulk
File line format:
flow <flow ID>
meter 0 <cir> <pir> <cbs> <pbs> meter 1 <cir> <pir> <cbs> <pbs> meter 2
<cir> <pir> <cbs> <pbs> meter 3 <cir> <pir> <cbs> <pbs>
policer 0 <action> <action> <action> policer 1 <action> <action>
<action> policer 2 <action> <action> <action> policer 3 <action>
<action> <action>
port <port ID>

Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/action.cfg             |   68 +
 examples/ip_pipeline/config/action.sh              |  119 ++
 examples/ip_pipeline/config/action.txt             |    8 +
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1505 +++++++-------------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   11 +
 5 files changed, 707 insertions(+), 1004 deletions(-)
 create mode 100644 examples/ip_pipeline/config/action.cfg
 create mode 100644 examples/ip_pipeline/config/action.sh
 create mode 100644 examples/ip_pipeline/config/action.txt

diff --git a/examples/ip_pipeline/config/action.cfg b/examples/ip_pipeline/config/action.cfg
new file mode 100644
index 0000000..994ae94
--- /dev/null
+++ b/examples/ip_pipeline/config/action.cfg
@@ -0,0 +1,68 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ________________
+; RXQ0.0 --->|                |---> TXQ0.0
+;            |                |
+; RXQ1.0 --->|                |---> TXQ1.0
+;            |      Flow      |
+; RXQ2.0 --->|     Actions    |---> TXQ2.0
+;            |                |
+; RXQ3.0 --->|                |---> TXQ3.0
+;            |________________|
+;
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = FLOW_ACTIONS
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
+n_flows = 65536
+n_meters_per_flow = 4
+flow_id_offset = 286; ipdaddr
+ip_hdr_offset = 270
+color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
new file mode 100644
index 0000000..2986ae6
--- /dev/null
+++ b/examples/ip_pipeline/config/action.sh
@@ -0,0 +1,119 @@
+#
+# run ./config/action.sh
+#
+
+p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 0 g G y Y r R
+p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 1 g G y Y r R
+p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 2 g G y Y r R
+p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 0 policer 3 g G y Y r R
+p 1 action flow 0 port 0
+
+p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 0 g G y Y r R
+p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 1 g G y Y r R
+p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 2 g G y Y r R
+p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 1 policer 3 g G y Y r R
+p 1 action flow 1 port 1
+
+p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 0 g G y Y r R
+p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 1 g G y Y r R
+p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 2 g G y Y r R
+p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 2 policer 3 g G y Y r R
+p 1 action flow 2 port 2
+
+p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 0 g G y Y r R
+p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 1 g G y Y r R
+p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 2 g G y Y r R
+p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
+p 1 action flow 3 policer 3 g G y Y r R
+p 1 action flow 3 port 3
+
+#p 1 action flow bulk ./config/action.txt
+
+#p 1 action flow ls
+
+p 1 action flow 0 stats
+p 1 action flow 1 stats
+p 1 action flow 2 stats
+p 1 action flow 3 stats
+
+p 1 action dscp 0 class 0 color G
+p 1 action dscp 1 class 1 color G
+p 1 action dscp 2 class 2 color G
+p 1 action dscp 3 class 3 color G
+p 1 action dscp 4 class 0 color G
+p 1 action dscp 5 class 1 color G
+p 1 action dscp 6 class 2 color G
+p 1 action dscp 7 class 3 color G
+p 1 action dscp 8 class 0 color G
+p 1 action dscp 9 class 1 color G
+p 1 action dscp 10 class 2 color G
+p 1 action dscp 11 class 3 color G
+p 1 action dscp 12 class 0 color G
+p 1 action dscp 13 class 1 color G
+p 1 action dscp 14 class 2 color G
+p 1 action dscp 15 class 3 color G
+p 1 action dscp 16 class 0 color G
+p 1 action dscp 17 class 1 color G
+p 1 action dscp 18 class 2 color G
+p 1 action dscp 19 class 3 color G
+p 1 action dscp 20 class 0 color G
+p 1 action dscp 21 class 1 color G
+p 1 action dscp 22 class 2 color G
+p 1 action dscp 23 class 3 color G
+p 1 action dscp 24 class 0 color G
+p 1 action dscp 25 class 1 color G
+p 1 action dscp 26 class 2 color G
+p 1 action dscp 27 class 3 color G
+p 1 action dscp 27 class 0 color G
+p 1 action dscp 29 class 1 color G
+p 1 action dscp 30 class 2 color G
+p 1 action dscp 31 class 3 color G
+p 1 action dscp 32 class 0 color G
+p 1 action dscp 33 class 1 color G
+p 1 action dscp 34 class 2 color G
+p 1 action dscp 35 class 3 color G
+p 1 action dscp 36 class 0 color G
+p 1 action dscp 37 class 1 color G
+p 1 action dscp 38 class 2 color G
+p 1 action dscp 39 class 3 color G
+p 1 action dscp 40 class 0 color G
+p 1 action dscp 41 class 1 color G
+p 1 action dscp 42 class 2 color G
+p 1 action dscp 43 class 3 color G
+p 1 action dscp 44 class 0 color G
+p 1 action dscp 45 class 1 color G
+p 1 action dscp 46 class 2 color G
+p 1 action dscp 47 class 3 color G
+p 1 action dscp 48 class 0 color G
+p 1 action dscp 49 class 1 color G
+p 1 action dscp 50 class 2 color G
+p 1 action dscp 51 class 3 color G
+p 1 action dscp 52 class 0 color G
+p 1 action dscp 53 class 1 color G
+p 1 action dscp 54 class 2 color G
+p 1 action dscp 55 class 3 color G
+p 1 action dscp 56 class 0 color G
+p 1 action dscp 57 class 1 color G
+p 1 action dscp 58 class 2 color G
+p 1 action dscp 59 class 3 color G
+p 1 action dscp 60 class 0 color G
+p 1 action dscp 61 class 1 color G
+p 1 action dscp 62 class 2 color G
+p 1 action dscp 63 class 3 color G
+
+p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
new file mode 100644
index 0000000..f14207b
--- /dev/null
+++ b/examples/ip_pipeline/config/action.txt
@@ -0,0 +1,8 @@
+#
+# p <pipelineid> action flow bulk ./config/action.txt
+#
+
+flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
+flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
+flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
+flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
index 4012121..7560051 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <sys/queue.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_hexdump.h>
@@ -43,13 +44,12 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_flow_actions.h"
 #include "hash_func.h"
+#include "parser.h"
 
 /*
  * Flow actions pipeline
@@ -689,1115 +689,612 @@ app_pipeline_fa_dscp_ls(struct app_params *app,
 	return 0;
 }
 
-/*
- * Flow meter configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> meter <meter ID> trtcm <trtcm params>
- */
-
-struct cmd_fa_meter_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
-};
-
-static void
-cmd_fa_meter_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_meter_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->meter_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	flow_params.m[params->meter_id].cir = params->cir;
-	flow_params.m[params->meter_id].pir = params->pir;
-	flow_params.m[params->meter_id].cbs = params->cbs;
-	flow_params.m[params->meter_id].pbs = params->pbs;
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		1 << params->meter_id,
-		0,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_meter_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_result, pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config = {
-	.f = cmd_fa_meter_config_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (single flow) ",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_p_string,
-		(void *) &cmd_fa_meter_config_pipeline_id,
-		(void *) &cmd_fa_meter_config_flow_string,
-		(void *) &cmd_fa_meter_config_flow_id,
-		(void *) &cmd_fa_meter_config_meter_string,
-		(void *) &cmd_fa_meter_config_meter_id,
-		(void *) &cmd_fa_meter_config_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
-/*
- * Flow meter configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> meter <meter ID> trtcm <trtcm params>
- */
-
-struct cmd_fa_meter_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t meter_string;
-	uint32_t meter_id;
-	cmdline_fixed_string_t trtcm_string;
-	uint64_t cir;
-	uint64_t pir;
-	uint64_t cbs;
-	uint64_t pbs;
-};
-
-static void
-cmd_fa_meter_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
+int
+app_pipeline_fa_load_file(char *filename,
+	uint32_t *flow_ids,
+	struct pipeline_fa_flow_params *p,
+	uint32_t *n_flows,
+	uint32_t *line)
 {
-	struct cmd_fa_meter_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
+	FILE *f = NULL;
+	char file_buf[1024];
+	uint32_t i, l;
 
-	if ((params->n_flows == 0) ||
-		(params->meter_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+	/* Check input arguments */
+	if ((filename == NULL) ||
+		(flow_ids == NULL) ||
+		(p == NULL) ||
+		(n_flows == NULL) ||
+		(*n_flows == 0) ||
+		(line == NULL)) {
+		if (line)
+			*line = 0;
+		return -1;
+		}
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
-		return;
+	/* Open input file */
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		*line = 0;
+		return -1;
 	}
 
-	memset(&flow_template, 0, sizeof(flow_template));
-	flow_template.m[params->meter_id].cir = params->cir;
-	flow_template.m[params->meter_id].pir = params->pir;
-	flow_template.m[params->meter_id].cbs = params->cbs;
-	flow_template.m[params->meter_id].pbs = params->pbs;
+	/* Read file */
+	for (i = 0, l = 1; i < *n_flows; l++) {
+		char *tokens[64];
+		uint32_t n_tokens = RTE_DIM(tokens);
 
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
+		int status;
 
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos],
-			&flow_template,
-			sizeof(flow_template));
+		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
+			break;
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
+		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
+		if (status)
+			goto error1;
 
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				1 << params->meter_id,
-				0,
-				0,
-				flow_params);
+		if ((n_tokens == 0) || (tokens[0][0] == '#'))
+			continue;
 
-			if (status != 0) {
-				printf("Command failed\n");
 
-				break;
-			}
-		}
+		if ((n_tokens != 64) ||
+			/* flow */
+			strcmp(tokens[0], "flow") ||
+			parser_read_uint32(&flow_ids[i], tokens[1]) ||
+
+			/* meter & policer 0 */
+			strcmp(tokens[2], "meter") ||
+			strcmp(tokens[3], "0") ||
+			strcmp(tokens[4], "trtcm") ||
+			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
+			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
+			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
+			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
+			strcmp(tokens[9], "policer") ||
+			strcmp(tokens[10], "0") ||
+			strcmp(tokens[11], "g") ||
+			string_to_policer_action(tokens[12],
+				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[13], "y") ||
+			string_to_policer_action(tokens[14],
+				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[15], "r") ||
+			string_to_policer_action(tokens[16],
+				&p[i].p[0].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 1 */
+			strcmp(tokens[17], "meter") ||
+			strcmp(tokens[18], "1") ||
+			strcmp(tokens[19], "trtcm") ||
+			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
+			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
+			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
+			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
+			strcmp(tokens[24], "policer") ||
+			strcmp(tokens[25], "1") ||
+			strcmp(tokens[26], "g") ||
+			string_to_policer_action(tokens[27],
+				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[28], "y") ||
+			string_to_policer_action(tokens[29],
+				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[30], "r") ||
+			string_to_policer_action(tokens[31],
+				&p[i].p[1].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 2 */
+			strcmp(tokens[32], "meter") ||
+			strcmp(tokens[33], "2") ||
+			strcmp(tokens[34], "trtcm") ||
+			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
+			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
+			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
+			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
+			strcmp(tokens[39], "policer") ||
+			strcmp(tokens[40], "2") ||
+			strcmp(tokens[41], "g") ||
+			string_to_policer_action(tokens[42],
+				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[43], "y") ||
+			string_to_policer_action(tokens[44],
+				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[45], "r") ||
+			string_to_policer_action(tokens[46],
+				&p[i].p[2].action[e_RTE_METER_RED]) ||
+
+			/* meter & policer 3 */
+			strcmp(tokens[47], "meter") ||
+			strcmp(tokens[48], "3") ||
+			strcmp(tokens[49], "trtcm") ||
+			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
+			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
+			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
+			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
+			strcmp(tokens[54], "policer") ||
+			strcmp(tokens[55], "3") ||
+			strcmp(tokens[56], "g") ||
+			string_to_policer_action(tokens[57],
+				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
+			strcmp(tokens[58], "y") ||
+			string_to_policer_action(tokens[59],
+				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
+			strcmp(tokens[60], "r") ||
+			string_to_policer_action(tokens[61],
+				&p[i].p[3].action[e_RTE_METER_RED]) ||
+
+			/* port */
+			strcmp(tokens[62], "port") ||
+			parser_read_uint32(&p[i].port_id, tokens[63]))
+			goto error1;
+
+		i++;
 	}
 
-	rte_free(flow_params);
-	rte_free(flow_id);
+	/* Close file */
+	*n_flows = i;
+	fclose(f);
+	return 0;
 
+error1:
+	*line = l;
+	fclose(f);
+	return -1;
 }
 
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_meter_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_string, "meter");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_meter_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	meter_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_meter_config_bulk_trtcm_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	trtcm_string, "trtcm");
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pir =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pir, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_cbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	cbs, UINT64);
-
-cmdline_parse_token_num_t cmd_fa_meter_config_bulk_pbs =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_meter_config_bulk_result,
-	pbs, UINT64);
-
-cmdline_parse_inst_t cmd_fa_meter_config_bulk = {
-	.f = cmd_fa_meter_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow meter configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_meter_config_bulk_p_string,
-		(void *) &cmd_fa_meter_config_bulk_pipeline_id,
-		(void *) &cmd_fa_meter_config_bulk_flows_string,
-		(void *) &cmd_fa_meter_config_bulk_n_flows,
-		(void *) &cmd_fa_meter_config_bulk_meter_string,
-		(void *) &cmd_fa_meter_config_bulk_meter_id,
-		(void *) &cmd_fa_meter_config_bulk_trtcm_string,
-		(void *) &cmd_fa_meter_config_cir,
-		(void *) &cmd_fa_meter_config_pir,
-		(void *) &cmd_fa_meter_config_cbs,
-		(void *) &cmd_fa_meter_config_pbs,
-		NULL,
-	},
-};
-
 /*
- * Flow policer configuration (single flow)
+ * action
  *
- * p <pipeline ID> flow <flow ID> policer <policer ID>
- *    G <action> Y <action> R <action>
+ * flow meter, policer and output port configuration:
+ *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
  *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
-
-struct cmd_fa_policer_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
-};
-
-static void
-cmd_fa_policer_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
-
-	if (params->policer_id >= PIPELINE_FA_N_TC_MAX) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = string_to_policer_action(params->g_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_params.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		1 << params->policer_id,
-		0,
-		&flow_params);
-
-	if (status != 0)
-		printf("Command failed\n");
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	green_string, "G");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	g_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	yellow_string, "Y");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	y_action, "R#Y#G#D");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	red_string, "R");
-
-cmdline_parse_token_string_t cmd_fa_policer_config_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_result,
-	r_action, "R#Y#G#D");
-
-cmdline_parse_inst_t cmd_fa_policer_config = {
-	.f = cmd_fa_policer_config_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_p_string,
-		(void *) &cmd_fa_policer_config_pipeline_id,
-		(void *) &cmd_fa_policer_config_flow_string,
-		(void *) &cmd_fa_policer_config_flow_id,
-		(void *) &cmd_fa_policer_config_policer_string,
-		(void *) &cmd_fa_policer_config_policer_id,
-		(void *) &cmd_fa_policer_config_green_string,
-		(void *) &cmd_fa_policer_config_g_action,
-		(void *) &cmd_fa_policer_config_yellow_string,
-		(void *) &cmd_fa_policer_config_y_action,
-		(void *) &cmd_fa_policer_config_red_string,
-		(void *) &cmd_fa_policer_config_r_action,
-		NULL,
-	},
-};
-
-/*
- * Flow policer configuration (multiple flows)
+ *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
+ *  <action> is one of the following:
+ *      G = recolor to green
+ *      Y = recolor as yellow
+ *      R = recolor as red
+ *      D = drop
  *
- * p <pipeline ID> flows <n_flows> policer <policer ID>
- *    G <action> Y <action> R <action>
+ *    p <pipelineid> action flow <flowid> port <port ID>
  *
- * <action> = G (green) | Y (yellow) | R (red) | D (drop)
- */
+ *    p <pipelineid> action flow bulk <file>
+ *
+ * flow policer stats read:
+ *    p <pipelineid> action flow <flowid> stats
+ *
+ * flow ls:
+ *    p <pipelineid> action flow ls
+ *
+ * dscp table configuration:
+ *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
+ *
+ * dscp table ls:
+ *    p <pipelineid> action dscp ls
+**/
 
-struct cmd_fa_policer_config_bulk_result {
+struct cmd_action_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t green_string;
-	cmdline_fixed_string_t g_action;
-	cmdline_fixed_string_t yellow_string;
-	cmdline_fixed_string_t y_action;
-	cmdline_fixed_string_t red_string;
-	cmdline_fixed_string_t r_action;
+	cmdline_fixed_string_t action_string;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_fa_policer_config_bulk_parsed(
+cmd_action_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_fa_policer_config_bulk_result *params = parsed_result;
+	struct cmd_action_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_template, *flow_params;
-	uint32_t *flow_id, i;
-	int status;
 
-	if ((params->n_flows == 0) ||
-		(params->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		printf("Invalid arguments\n");
-		return;
-	}
-
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
+	if (status != 0) {
+		printf(CMD_MSG_TOO_MANY_ARGS, "action");
 		return;
 	}
 
-	memset(&flow_template, 0, sizeof(flow_template));
-
-	status = string_to_policer_action(params->g_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_GREEN]);
-	if (status)
-		printf("Invalid policer green action\n");
-
-	status = string_to_policer_action(params->y_action,
-	 &flow_template.p[params->policer_id].action[e_RTE_METER_YELLOW]);
-	if (status)
-		printf("Invalid policer yellow action\n");
-
-	status = string_to_policer_action(params->r_action,
-		&flow_template.p[params->policer_id].action[e_RTE_METER_RED]);
-	if (status)
-		printf("Invalid policer red action\n");
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-
-		flow_id[pos] = i;
-		memcpy(&flow_params[pos], &flow_template,
-			sizeof(flow_template));
-
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
-
-			status = app_pipeline_fa_flow_config_bulk(app,
-				params->pipeline_id,
-				flow_id,
-				pos + 1,
-				0,
-				1 << params->policer_id,
-				0,
-				flow_params);
-
-			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
-			}
+	/* action flow meter */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "meter") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, meter_id;
+
+		if (n_tokens != 9) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
+			return;
 		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_string, "policer");
 
-cmdline_parse_token_num_t cmd_fa_policer_config_bulk_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	policer_id, UINT32);
+		memset(&flow_params, 0, sizeof(flow_params));
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_green_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	green_string, "G");
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_g_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	g_action, "R#Y#G#D");
+		if (parser_read_uint32(&meter_id, tokens[3]) ||
+			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
+			printf(CMD_MSG_INVALID_ARG, "meterid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_yellow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	yellow_string, "Y");
+		if (strcmp(tokens[4], "trtcm")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_y_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	y_action, "R#Y#G#D");
+		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
+			printf(CMD_MSG_INVALID_ARG, "cir");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_red_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	red_string, "R");
+		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
+			printf(CMD_MSG_INVALID_ARG, "pir");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_policer_config_bulk_r_action =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_config_bulk_result,
-	r_action, "R#Y#G#D");
+		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
+			printf(CMD_MSG_INVALID_ARG, "cbs");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_policer_config_bulk = {
-	.f = cmd_fa_policer_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow policer configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_policer_config_bulk_p_string,
-		(void *) &cmd_fa_policer_config_bulk_pipeline_id,
-		(void *) &cmd_fa_policer_config_bulk_flows_string,
-		(void *) &cmd_fa_policer_config_bulk_n_flows,
-		(void *) &cmd_fa_policer_config_bulk_policer_string,
-		(void *) &cmd_fa_policer_config_bulk_policer_id,
-		(void *) &cmd_fa_policer_config_bulk_green_string,
-		(void *) &cmd_fa_policer_config_bulk_g_action,
-		(void *) &cmd_fa_policer_config_bulk_yellow_string,
-		(void *) &cmd_fa_policer_config_bulk_y_action,
-		(void *) &cmd_fa_policer_config_bulk_red_string,
-		(void *) &cmd_fa_policer_config_bulk_r_action,
-		NULL,
-	},
-};
+		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
+			printf(CMD_MSG_INVALID_ARG, "pbs");
+			return;
+		}
 
-/*
- * Flow output port configuration (single flow)
- *
- * p <pipeline ID> flow <flow ID> port <port ID>
- */
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			1 << meter_id,
+			0,
+			0,
+			&flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow meter");
 
-struct cmd_fa_output_port_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t port_string;
-	uint32_t port_id;
-};
+		return;
+	} /* action flow meter */
+
+	/* action flow policer */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "policer") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, policer_id;
+
+		if (n_tokens != 10) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
+			return;
+		}
 
-static void
-cmd_fa_output_port_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params flow_params;
-	int status;
+		memset(&flow_params, 0, sizeof(flow_params));
 
-	flow_params.port_id = params->port_id;
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-	status = app_pipeline_fa_flow_config(app,
-		params->pipeline_id,
-		params->flow_id,
-		0,
-		0,
-		1,
-		&flow_params);
+		if (parser_read_uint32(&policer_id, tokens[3]) ||
+			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
+			printf(CMD_MSG_INVALID_ARG, "policerid");
+			return;
+		}
 
-	if (status != 0)
-		printf("Command failed\n");
-}
+		if (strcmp(tokens[4], "g")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "g");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	p_string, "p");
+		if (string_to_policer_action(tokens[5],
+			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
+			printf(CMD_MSG_INVALID_ARG, "gaction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	pipeline_id, UINT32);
+		if (strcmp(tokens[6], "y")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "y");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_string, "flow");
+		if (string_to_policer_action(tokens[7],
+			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
+			printf(CMD_MSG_INVALID_ARG, "yaction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	flow_id, UINT32);
+		if (strcmp(tokens[8], "r")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "r");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_output_port_config_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_string, "port");
+		if (string_to_policer_action(tokens[9],
+			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
+			printf(CMD_MSG_INVALID_ARG, "raction");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_output_port_config_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_result,
-	port_id, UINT32);
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			0,
+			1 << policer_id,
+			0,
+			&flow_params);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "action flow policer");
 
-cmdline_parse_inst_t cmd_fa_output_port_config = {
-	.f = cmd_fa_output_port_config_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (single flow)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_p_string,
-		(void *) &cmd_fa_output_port_config_pipeline_id,
-		(void *) &cmd_fa_output_port_config_flow_string,
-		(void *) &cmd_fa_output_port_config_flow_id,
-		(void *) &cmd_fa_output_port_config_port_string,
-		(void *) &cmd_fa_output_port_config_port_id,
-		NULL,
-	},
-};
+		return;
+	} /* action flow policer */
+
+	/* action flow port */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "port") == 0)) {
+		struct pipeline_fa_flow_params flow_params;
+		uint32_t flow_id, port_id;
+
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
+			return;
+		}
 
-/*
- * Flow output port configuration (multiple flows)
- *
- * p <pipeline ID> flows <n_flows> ports <n_ports>
- */
+		memset(&flow_params, 0, sizeof(flow_params));
 
-struct cmd_fa_output_port_config_bulk_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flows_string;
-	uint32_t n_flows;
-	cmdline_fixed_string_t ports_string;
-	uint32_t n_ports;
-};
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-static void
-cmd_fa_output_port_config_bulk_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_output_port_config_bulk_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_flow_params *flow_params;
-	uint32_t *flow_id;
-	uint32_t i;
+		if (parser_read_uint32(&port_id, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	if (params->n_flows == 0) {
-		printf("Invalid arguments\n");
-		return;
-	}
+		flow_params.port_id = port_id;
 
-	flow_id = (uint32_t *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_id == NULL) {
-		printf("Memory allocation failed\n");
-		return;
-	}
+		status = app_pipeline_fa_flow_config(app,
+			params->pipeline_id,
+			flow_id,
+			0,
+			0,
+			1,
+			&flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow port");
 
-	flow_params = (struct pipeline_fa_flow_params *) rte_malloc(NULL,
-		N_FLOWS_BULK * sizeof(struct pipeline_fa_flow_params),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_params == NULL) {
-		rte_free(flow_id);
-		printf("Memory allocation failed\n");
 		return;
-	}
-
-	for (i = 0; i < params->n_flows; i++) {
-		uint32_t pos = i % N_FLOWS_BULK;
-		uint32_t port_id = i % params->n_ports;
-
-		flow_id[pos] = i;
-
-		memset(&flow_params[pos], 0, sizeof(flow_params[pos]));
-		flow_params[pos].port_id = port_id;
+	} /* action flow port */
+
+	/* action flow stats */
+	if ((n_tokens >= 3) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		strcmp(tokens[1], "bulk") &&
+		strcmp(tokens[1], "ls") &&
+		(strcmp(tokens[2], "stats") == 0)) {
+		struct pipeline_fa_policer_stats stats;
+		uint32_t flow_id, policer_id;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
+			return;
+		}
 
-		if ((pos == N_FLOWS_BULK - 1) ||
-			(i == params->n_flows - 1)) {
-			int status;
+		if (parser_read_uint32(&flow_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "flowid");
+			return;
+		}
 
-			status = app_pipeline_fa_flow_config_bulk(app,
+		for (policer_id = 0;
+			policer_id < PIPELINE_FA_N_TC_MAX;
+			policer_id++) {
+			status = app_pipeline_fa_flow_policer_stats_read(app,
 				params->pipeline_id,
 				flow_id,
-				pos + 1,
-				0,
-				0,
+				policer_id,
 				1,
-				flow_params);
-
+				&stats);
 			if (status != 0) {
-				printf("Command failed\n");
-
-				break;
+				printf(CMD_MSG_FAIL, "action flow stats");
+				return;
 			}
-		}
-	}
-
-	rte_free(flow_params);
-	rte_free(flow_id);
-
-}
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_flows_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	flows_string, "flows");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_flows =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_flows, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_output_port_config_bulk_ports_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	ports_string, "ports");
-
-cmdline_parse_token_num_t cmd_fa_output_port_config_bulk_n_ports =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_output_port_config_bulk_result,
-	n_ports, UINT32);
-
-cmdline_parse_inst_t cmd_fa_output_port_config_bulk = {
-	.f = cmd_fa_output_port_config_bulk_parsed,
-	.data = NULL,
-	.help_str = "Flow output port configuration (multiple flows)",
-	.tokens = {
-		(void *) &cmd_fa_output_port_config_bulk_p_string,
-		(void *) &cmd_fa_output_port_config_bulk_pipeline_id,
-		(void *) &cmd_fa_output_port_config_bulk_flows_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_flows,
-		(void *) &cmd_fa_output_port_config_bulk_ports_string,
-		(void *) &cmd_fa_output_port_config_bulk_n_ports,
-		NULL,
-	},
-};
-
-/*
- * Flow DiffServ Code Point (DSCP) translation table configuration
- *
- * p <pipeline ID> dscp <DSCP ID> class <traffic class ID> color <color>
- *
- * <color> = G (green) | Y (yellow) | R (red)
-*/
 
-struct cmd_fa_dscp_config_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	uint32_t dscp_id;
-	cmdline_fixed_string_t class_string;
-	uint32_t traffic_class_id;
-	cmdline_fixed_string_t color_string;
-	cmdline_fixed_string_t color;
-
-};
-
-static void
-cmd_fa_dscp_config_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_config_result *params = parsed_result;
-	struct app_params *app = data;
-	enum rte_meter_color color;
-	int status;
+			/* Display stats */
+			printf("\tPolicer: %" PRIu32
+				"\tPkts G: %" PRIu64
+				"\tPkts Y: %" PRIu64
+				"\tPkts R: %" PRIu64
+				"\tPkts D: %" PRIu64 "\n",
+				policer_id,
+				stats.n_pkts[e_RTE_METER_GREEN],
+				stats.n_pkts[e_RTE_METER_YELLOW],
+				stats.n_pkts[e_RTE_METER_RED],
+				stats.n_pkts_drop);
+		}
 
-	status = string_to_color(params->color, &color);
-	if (status) {
-		printf("Invalid color\n");
 		return;
-	}
-
-	status = app_pipeline_fa_dscp_config(app,
-		params->pipeline_id,
-		params->dscp_id,
-		params->traffic_class_id,
-		color);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_string, "dscp");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_dscp_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	dscp_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_class_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	class_string, "class");
-
-cmdline_parse_token_num_t cmd_fa_dscp_config_traffic_class_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_config_result,
-	traffic_class_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color_string, "color");
-
-cmdline_parse_token_string_t cmd_fa_dscp_config_color =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_config_result,
-	color, "G#Y#R");
+	} /* action flow stats */
+
+	/* action flow bulk */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		(strcmp(tokens[1], "bulk") == 0)) {
+		struct pipeline_fa_flow_params *flow_params;
+		uint32_t *flow_ids, n_flows, line;
+		char *filename;
+
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_dscp_config = {
-	.f = cmd_fa_dscp_config_parsed,
-	.data = NULL,
-	.help_str = "Flow DSCP translation table configuration",
-	.tokens = {
-		(void *) &cmd_fa_dscp_config_p_string,
-		(void *) &cmd_fa_dscp_config_pipeline_id,
-		(void *) &cmd_fa_dscp_config_dscp_string,
-		(void *) &cmd_fa_dscp_config_dscp_id,
-		(void *) &cmd_fa_dscp_config_class_string,
-		(void *) &cmd_fa_dscp_config_traffic_class_id,
-		(void *) &cmd_fa_dscp_config_color_string,
-		(void *) &cmd_fa_dscp_config_color,
-		NULL,
-	},
-};
+		filename = tokens[2];
 
-/*
- * Flow policer stats read
- *
- * p <pipeline ID> flow <flow ID> policer <policer ID> stats
- */
+		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
+		flow_ids = malloc(n_flows * sizeof(uint32_t));
+		if (flow_ids == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			return;
+		}
 
-struct cmd_fa_policer_stats_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	uint32_t flow_id;
-	cmdline_fixed_string_t policer_string;
-	uint32_t policer_id;
-	cmdline_fixed_string_t stats_string;
-};
+		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
+		if (flow_params == NULL) {
+			printf(CMD_MSG_OUT_OF_MEMORY);
+			free(flow_ids);
+			return;
+		}
 
-static void
-cmd_fa_policer_stats_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_policer_stats_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_fa_policer_stats stats;
-	int status;
+		status = app_pipeline_fa_load_file(filename,
+			flow_ids,
+			flow_params,
+			&n_flows,
+			&line);
+		if (status) {
+			printf(CMD_MSG_FILE_ERR, filename, line);
+			free(flow_params);
+			free(flow_ids);
+			return;
+		}
 
-	status = app_pipeline_fa_flow_policer_stats_read(app,
-		params->pipeline_id,
-		params->flow_id,
-		params->policer_id,
-		1,
-		&stats);
-	if (status != 0) {
-		printf("Command failed\n");
+		status = app_pipeline_fa_flow_config_bulk(app,
+			params->pipeline_id,
+			flow_ids,
+			n_flows,
+			0xF,
+			0xF,
+			1,
+			flow_params);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow bulk");
+
+		free(flow_params);
+		free(flow_ids);
 		return;
-	}
-
-	/* Display stats */
-	printf("\tPkts G: %" PRIu64
-		"\tPkts Y: %" PRIu64
-		"\tPkts R: %" PRIu64
-		"\tPkts D: %" PRIu64 "\n",
-		stats.n_pkts[e_RTE_METER_GREEN],
-		stats.n_pkts[e_RTE_METER_YELLOW],
-		stats.n_pkts[e_RTE_METER_RED],
-		stats.n_pkts_drop);
-}
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	p_string, "p");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	pipeline_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_string, "flow");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_flow_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	flow_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_policer_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_string, "policer");
-
-cmdline_parse_token_num_t cmd_fa_policer_stats_policer_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_policer_stats_result,
-	policer_id, UINT32);
-
-cmdline_parse_token_string_t cmd_fa_policer_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_policer_stats_result,
-	stats_string, "stats");
-
-cmdline_parse_inst_t cmd_fa_policer_stats = {
-	.f = cmd_fa_policer_stats_parsed,
-	.data = NULL,
-	.help_str = "Flow policer stats read",
-	.tokens = {
-		(void *) &cmd_fa_policer_stats_p_string,
-		(void *) &cmd_fa_policer_stats_pipeline_id,
-		(void *) &cmd_fa_policer_stats_flow_string,
-		(void *) &cmd_fa_policer_stats_flow_id,
-		(void *) &cmd_fa_policer_stats_policer_string,
-		(void *) &cmd_fa_policer_stats_policer_id,
-		(void *) &cmd_fa_policer_stats_string,
-		NULL,
-	},
-};
-
-/*
- * Flow list
- *
- * p <pipeline ID> flow ls
- */
+	} /* action flow bulk */
+
+	/* action flow ls */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "flow") == 0) &&
+		(strcmp(tokens[1], "ls") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
+			return;
+		}
 
-struct cmd_fa_flow_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t actions_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_fa_flow_ls(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "action flow ls");
 
-static void
-cmd_fa_flow_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_flow_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_fa_flow_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
-}
+		return;
+	} /* action flow ls */
+
+	/* action dscp */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "dscp") == 0) &&
+		strcmp(tokens[1], "ls")) {
+		uint32_t dscp_id, tc_id;
+		enum rte_meter_color color;
+
+		if (n_tokens != 6) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	p_string, "p");
+		if (parser_read_uint32(&dscp_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "dscpid");
+			return;
+		}
 
-cmdline_parse_token_num_t cmd_fa_flow_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_flow_ls_result,
-	pipeline_id, UINT32);
+		if (strcmp(tokens[2], "class")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "class");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	flow_string, "flow");
+		if (parser_read_uint32(&tc_id, tokens[3])) {
+			printf(CMD_MSG_INVALID_ARG, "classid");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_actions_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	actions_string, "actions");
+		if (strcmp(tokens[4], "color")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "color");
+			return;
+		}
 
-cmdline_parse_token_string_t cmd_fa_flow_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_flow_ls_result,
-	ls_string, "ls");
+		if (string_to_color(tokens[5], &color)) {
+			printf(CMD_MSG_INVALID_ARG, "colorid");
+			return;
+		}
 
-cmdline_parse_inst_t cmd_fa_flow_ls = {
-	.f = cmd_fa_flow_ls_parsed,
-	.data = NULL,
-	.help_str = "Flow actions list",
-	.tokens = {
-		(void *) &cmd_fa_flow_ls_p_string,
-		(void *) &cmd_fa_flow_ls_pipeline_id,
-		(void *) &cmd_fa_flow_ls_flow_string,
-		(void *) &cmd_fa_flow_ls_actions_string,
-		(void *) &cmd_fa_flow_ls_ls_string,
-		NULL,
-	},
-};
+		status = app_pipeline_fa_dscp_config(app,
+			params->pipeline_id,
+			dscp_id,
+			tc_id,
+			color);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "action dscp");
 
-/*
- * Flow DiffServ Code Point (DSCP) translation table list
- *
- * p <pipeline ID> dscp ls
- */
+		return;
+	} /* action dscp */
+
+	/* action dscp ls */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "dscp") == 0) &&
+		(strcmp(tokens[1], "ls") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
+			return;
+		}
 
-struct cmd_fa_dscp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t dscp_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_fa_dscp_ls(app,
+			params->pipeline_id);
+		if (status)
+			printf(CMD_MSG_FAIL, "action dscp ls");
 
-static void
-cmd_fa_dscp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_fa_dscp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+		return;
+	} /* action dscp ls */
 
-	status = app_pipeline_fa_dscp_ls(app, params->pipeline_id);
-	if (status != 0)
-		printf("Command failed\n");
+	printf(CMD_MSG_FAIL, "action");
 }
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	p_string, "p");
+static cmdline_parse_token_string_t cmd_action_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
 
-cmdline_parse_token_num_t cmd_fa_dscp_ls_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	pipeline_id, UINT32);
+static cmdline_parse_token_num_t cmd_action_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_dscp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result,
-	dscp_string, "dscp");
+static cmdline_parse_token_string_t cmd_action_action_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
 
-cmdline_parse_token_string_t cmd_fa_dscp_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_fa_dscp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_action_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-cmdline_parse_inst_t cmd_fa_dscp_ls = {
-	.f = cmd_fa_dscp_ls_parsed,
+cmdline_parse_inst_t cmd_action = {
+	.f = cmd_action_parsed,
 	.data = NULL,
-	.help_str = "Flow DSCP translaton table list",
+	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
 	.tokens = {
-		(void *) &cmd_fa_dscp_ls_p_string,
-		(void *) &cmd_fa_dscp_ls_pipeline_id,
-		(void *) &cmd_fa_dscp_ls_dscp_string,
-		(void *) &cmd_fa_dscp_ls_string,
+		(void *) &cmd_action_p_string,
+		(void *) &cmd_action_pipeline_id,
+		(void *) &cmd_action_action_string,
+		(void *) &cmd_action_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config,
-	(cmdline_parse_inst_t *) &cmd_fa_meter_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config,
-	(cmdline_parse_inst_t *) &cmd_fa_output_port_config_bulk,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_config,
-	(cmdline_parse_inst_t *) &cmd_fa_policer_stats,
-	(cmdline_parse_inst_t *) &cmd_fa_flow_ls,
-	(cmdline_parse_inst_t *) &cmd_fa_dscp_ls,
+	(cmdline_parse_inst_t *) &cmd_action,
 	NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
index f2cd0cb..9c60974 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
@@ -73,6 +73,17 @@ app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
 	int clear,
 	struct pipeline_fa_policer_stats *stats);
 
+#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
+#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
+#endif
+
+int
+app_pipeline_fa_load_file(char *filename,
+	uint32_t *flow_ids,
+	struct pipeline_fa_flow_params *p,
+	uint32_t *n_flows,
+	uint32_t *line);
+
 extern struct pipeline_type pipeline_flow_actions;
 
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 6/7] examples/ip_pipeline: modifies routing pipeline CLI
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
                       ` (4 preceding siblings ...)
  2016-06-08 10:35     ` [PATCH v3 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 10:35     ` [PATCH v3 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
  2016-06-08 14:46     ` [PATCH v3 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Several routing commands are merged into two commands:
route and arp - these two commands are handled by cli library.
Rest of the commands are handled internaly by the pipeline code.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/l2fwd.cfg            |    5 +-
 examples/ip_pipeline/config/l3fwd.cfg            |    9 +-
 examples/ip_pipeline/config/l3fwd.sh             |   32 +-
 examples/ip_pipeline/config/l3fwd_arp.cfg        |   70 +
 examples/ip_pipeline/config/l3fwd_arp.sh         |   43 +
 examples/ip_pipeline/pipeline/pipeline_routing.c | 1636 ++++++----------------
 6 files changed, 551 insertions(+), 1244 deletions(-)
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 create mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh

diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
index c743a14..a1df9e6 100644
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ b/examples/ip_pipeline/config/l2fwd.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,9 @@
 ;            |________________|
 ;
 
+[EAL]
+log_level = 0
+
 [PIPELINE0]
 type = MASTER
 core = 0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
index 5449dc3..02c8f36 100644
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ b/examples/ip_pipeline/config/l3fwd.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,9 @@
 ; 2	Ethernet header		256 		14
 ; 3	IPv4 header		270 		20
 
+[EAL]
+log_level = 0
+
 [PIPELINE0]
 type = MASTER
 core = 0
@@ -59,5 +62,7 @@ type = ROUTING
 core = 1
 pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
 pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet; encap = ethernet / ethernet_qinq / ethernet_mpls
+encap = ethernet
+;encap = ethernet_qinq
+;encap = ethernet_mpls
 ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
index 2774010..47406aa 100644
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ b/examples/ip_pipeline/config/l3fwd.sh
@@ -1,9 +1,33 @@
+#
+# run ./config/l3fwd.sh
+#
+
 ################################################################################
 # Routing: encap = ethernet, arp = off
 ################################################################################
 p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
+p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
+p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
+p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
+p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
 p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_qinq, arp = off
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
+#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
+#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
+#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
+#p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_mpls, arp = off
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
+#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
+#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
+#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
+#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
new file mode 100644
index 0000000..2c63c8f
--- /dev/null
+++ b/examples/ip_pipeline/config/l3fwd_arp.cfg
@@ -0,0 +1,70 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             _______________
+; RXQ0.0 --->|               |---> TXQ0.0
+;            |               |
+; RXQ1.0 --->|               |---> TXQ1.0
+;            |    Routing    |
+; RXQ2.0 --->|               |---> TXQ2.0
+;            |               |
+; RXQ3.0 --->|               |---> TXQ3.0
+;            |_______________|
+;                    |
+;                    +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = ROUTING
+core = 1
+pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
+pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
+encap = ethernet
+;encap = ethernet_qinq
+;encap = ethernet_mpls
+n_arp_entries = 1024
+ip_hdr_offset = 270
+arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
new file mode 100644
index 0000000..20bea58
--- /dev/null
+++ b/examples/ip_pipeline/config/l3fwd_arp.sh
@@ -0,0 +1,43 @@
+#
+# run ./config/l3fwd_arp.sh
+#
+
+################################################################################
+# ARP
+################################################################################
+p 1 arp add default 4 #SINK0
+p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
+p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
+p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
+p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
+p 1 arp ls
+
+################################################################################
+# Routing: encap = ethernet, arp = on
+################################################################################
+p 1 route add default 4 #SINK0
+p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
+p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
+p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
+p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
+p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_qinq, arp = on
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
+#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
+#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
+#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
+#p 1 route ls
+
+################################################################################
+# Routing: encap = ethernet_mpls, arp = on
+################################################################################
+#p 1 route add default 4 #SINK0
+#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
+#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
+#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
+#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
+#p 1 route ls
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index eab89f2..c68e470 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,11 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_num.h>
 #include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
 
 #include "app.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_routing.h"
+#include "parser.h"
 
 struct app_pipeline_routing_route {
 	struct pipeline_routing_route_key key;
@@ -853,1376 +852,539 @@ app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
 	return 0;
 }
 
-static int
-parse_labels(char *string, uint32_t *labels, uint32_t *n_labels)
-{
-	uint32_t n_max_labels = *n_labels, count = 0;
-
-	/* Check for void list of labels */
-	if (strcmp(string, "<void>") == 0) {
-		*n_labels = 0;
-		return 0;
-	}
-
-	/* At least one label should be present */
-	for ( ; (*string != '\0'); ) {
-		char *next;
-		int value;
-
-		if (count >= n_max_labels)
-			return -1;
-
-		if (count > 0) {
-			if (string[0] != ':')
-				return -1;
-
-			string++;
-		}
-
-		value = strtol(string, &next, 10);
-		if (next == string)
-			return -1;
-		string = next;
-
-		labels[count++] = (uint32_t) value;
-	}
-
-	*n_labels = count;
-	return 0;
-}
-
 /*
- * route add (mpls = no, qinq = no, arp = no)
- */
-
-struct cmd_route_add1_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-};
-
-static void
-cmd_route_add1_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add1_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = 0;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add1_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add1_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add1_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add1_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add1_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add1_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add1_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add1_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add1_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add1_result, macaddr);
-
-static cmdline_parse_inst_t cmd_route_add1 = {
-	.f = cmd_route_add1_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add1_p_string,
-		(void *)&cmd_route_add1_p,
-		(void *)&cmd_route_add1_route_string,
-		(void *)&cmd_route_add1_add_string,
-		(void *)&cmd_route_add1_ip,
-		(void *)&cmd_route_add1_depth,
-		(void *)&cmd_route_add1_port_string,
-		(void *)&cmd_route_add1_port,
-		(void *)&cmd_route_add1_ether_string,
-		(void *)&cmd_route_add1_macaddr,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = no, arp = yes)
+ * route
+ *
+ * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
+ *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
+ *
+ * route add default:
+ *    p <pipelineid> route add default <portid>
+ *
+ * route del:
+ *    p <pipelineid> route del <ipaddr> <depth>
+ *
+ * route del default:
+ *    p <pipelineid> route del default
+ *
+ * route ls:
+ *    p <pipelineid> route ls
  */
 
-struct cmd_route_add2_result {
+struct cmd_route_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_route_add2_parsed(
+cmd_route_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_route_add2_result *params = parsed_result;
+	struct cmd_route_result *params = parsed_result;
 	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add2_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add2_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add2_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add2_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add2_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add2_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add2_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, nh_ip);
-
-static cmdline_parse_inst_t cmd_route_add2 = {
-	.f = cmd_route_add2_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = no, qinq = no, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add2_p_string,
-		(void *)&cmd_route_add2_p,
-		(void *)&cmd_route_add2_route_string,
-		(void *)&cmd_route_add2_add_string,
-		(void *)&cmd_route_add2_ip,
-		(void *)&cmd_route_add2_depth,
-		(void *)&cmd_route_add2_port_string,
-		(void *)&cmd_route_add2_port,
-		(void *)&cmd_route_add2_ether_string,
-		(void *)&cmd_route_add2_nh_ip,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = no)
- */
 
-struct cmd_route_add3_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add3_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add3_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf(CMD_MSG_TOO_MANY_ARGS, "route");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add3_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add3_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add3_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add3_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add3_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add3_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, port_string,
-	"port");
 
-static cmdline_parse_token_num_t cmd_route_add3_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add3_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add3_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add3_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add3_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, qinq_string,
-	"qinq");
-
-static cmdline_parse_token_num_t cmd_route_add3_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, svlan, UINT32);
-
-static cmdline_parse_token_num_t cmd_route_add3_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, cvlan, UINT32);
-
-static cmdline_parse_inst_t cmd_route_add3 = {
-	.f = cmd_route_add3_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add3_p_string,
-		(void *)&cmd_route_add3_p,
-		(void *)&cmd_route_add3_route_string,
-		(void *)&cmd_route_add3_add_string,
-		(void *)&cmd_route_add3_ip,
-		(void *)&cmd_route_add3_depth,
-		(void *)&cmd_route_add3_port_string,
-		(void *)&cmd_route_add3_port,
-		(void *)&cmd_route_add3_ether_string,
-		(void *)&cmd_route_add3_macaddr,
-		(void *)&cmd_route_add3_qinq_string,
-		(void *)&cmd_route_add3_svlan,
-		(void *)&cmd_route_add3_cvlan,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = no, qinq = yes, arp = yes)
- */
-
-struct cmd_route_add4_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t qinq_string;
-	uint32_t svlan;
-	uint32_t cvlan;
-};
-
-static void
-cmd_route_add4_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add4_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	int status;
-
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_QINQ |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	route_data.l2.qinq.svlan = params->svlan;
-	route_data.l2.qinq.cvlan = params->cvlan;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add4_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add4_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add4_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add4_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add4_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, ip);
+	/* route add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_route_key key;
+		struct pipeline_routing_route_data route_data;
+		struct in_addr ipv4, nh_ipv4;
+		struct ether_addr mac_addr;
+		uint32_t depth, port_id, svlan, cvlan, i;
+		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
+		uint32_t n_labels = RTE_DIM(mpls_labels);
+
+		memset(&key, 0, sizeof(key));
+		memset(&route_data, 0, sizeof(route_data));
+
+		if (n_tokens < 7) {
+			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
+			return;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, depth, UINT32);
+		if (parse_ipv4_addr(tokens[1], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, port_string,
-	"port");
+		if (parser_read_uint32(&depth, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, port, UINT32);
+		if (strcmp(tokens[3], "port")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, ether_string,
-	"ether");
+		if (parser_read_uint32(&port_id, tokens[4])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static cmdline_parse_token_ipaddr_t cmd_route_add4_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, nh_ip);
+		if (strcmp(tokens[5], "ether")) {
+			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
+			return;
+		}
 
-static cmdline_parse_token_string_t cmd_route_add4_qinq_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, qinq_string,
-	"qinq");
+		if (parse_mac_addr(tokens[6], &mac_addr)) {
+			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
+				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
+				return;
+			}
 
-static cmdline_parse_token_num_t cmd_route_add4_svlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, svlan, UINT32);
+			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
+		}
 
-static cmdline_parse_token_num_t cmd_route_add4_cvlan =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, cvlan, UINT32);
+		if (n_tokens > 7) {
+			if (strcmp(tokens[7], "mpls") == 0) {
+				if (n_tokens != 9) {
+					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
+					return;
+				}
+
+				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
+					printf(CMD_MSG_INVALID_ARG, "mpls labels");
+					return;
+				}
+
+				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
+			} else if (strcmp(tokens[7], "qinq") == 0) {
+				if (n_tokens != 10) {
+					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
+					return;
+				}
+
+				if (parser_read_uint32(&svlan, tokens[8])) {
+					printf(CMD_MSG_INVALID_ARG, "svlan");
+					return;
+				}
+				if (parser_read_uint32(&cvlan, tokens[9])) {
+					printf(CMD_MSG_INVALID_ARG, "cvlan");
+					return;
+				}
+
+				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
+			} else {
+				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
+				return;
+			}
+		}
 
-static cmdline_parse_inst_t cmd_route_add4 = {
-	.f = cmd_route_add4_parsed,
-	.data = NULL,
-	.help_str = "Route add (qinq = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add4_p_string,
-		(void *)&cmd_route_add4_p,
-		(void *)&cmd_route_add4_route_string,
-		(void *)&cmd_route_add4_add_string,
-		(void *)&cmd_route_add4_ip,
-		(void *)&cmd_route_add4_depth,
-		(void *)&cmd_route_add4_port_string,
-		(void *)&cmd_route_add4_port,
-		(void *)&cmd_route_add4_ether_string,
-		(void *)&cmd_route_add4_nh_ip,
-		(void *)&cmd_route_add4_qinq_string,
-		(void *)&cmd_route_add4_svlan,
-		(void *)&cmd_route_add4_cvlan,
-		NULL,
-	},
-};
+		switch (route_data.flags) {
+		case 0:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			break;
 
-/*
- * route add (mpls = yes, qinq = no, arp = no)
- */
+		case PIPELINE_ROUTING_ROUTE_ARP:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			break;
 
-struct cmd_route_add5_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	struct ether_addr macaddr;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
+		case PIPELINE_ROUTING_ROUTE_MPLS:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			for (i = 0; i < n_labels; i++)
+				route_data.l2.mpls.labels[i] = mpls_labels[i];
+			route_data.l2.mpls.n_labels = n_labels;
+			break;
 
-static void
-cmd_route_add5_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add5_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
+		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			for (i = 0; i < n_labels; i++)
+				route_data.l2.mpls.labels[i] = mpls_labels[i];
+			route_data.l2.mpls.n_labels = n_labels;
+			break;
 
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
+		case PIPELINE_ROUTING_ROUTE_QINQ:
+			route_data.port_id = port_id;
+			route_data.ethernet.macaddr = mac_addr;
+			route_data.l2.qinq.svlan = svlan;
+			route_data.l2.qinq.cvlan = cvlan;
+			break;
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
+		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
+		default:
+			route_data.port_id = port_id;
+			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
+			route_data.l2.qinq.svlan = svlan;
+			route_data.l2.qinq.cvlan = cvlan;
+			break;
+		}
 
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS;
-	route_data.port_id = params->port;
-	route_data.ethernet.macaddr = params->macaddr;
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.depth = depth;
 
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
+		status = app_pipeline_routing_add_route(app,
+			params->p,
+			&key,
+			&route_data);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route add");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add5_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add5_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add5_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, add_string,
-	"add");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add5_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add5_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_add5_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, depth, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add5_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add5_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_etheraddr_t cmd_route_add5_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add5_result, macaddr);
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add5_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add5 = {
-	.f = cmd_route_add5_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = no)",
-	.tokens = {
-		(void *)&cmd_route_add5_p_string,
-		(void *)&cmd_route_add5_p,
-		(void *)&cmd_route_add5_route_string,
-		(void *)&cmd_route_add5_add_string,
-		(void *)&cmd_route_add5_ip,
-		(void *)&cmd_route_add5_depth,
-		(void *)&cmd_route_add5_port_string,
-		(void *)&cmd_route_add5_port,
-		(void *)&cmd_route_add5_ether_string,
-		(void *)&cmd_route_add5_macaddr,
-		(void *)&cmd_route_add5_mpls_string,
-		(void *)&cmd_route_add5_mpls_labels,
-		NULL,
-	},
-};
-
-/*
- * route add (mpls = yes, qinq = no, arp = yes)
- */
+	} /* route add */
 
-struct cmd_route_add6_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-	cmdline_fixed_string_t port_string;
-	uint32_t port;
-	cmdline_fixed_string_t ether_string;
-	cmdline_ipaddr_t nh_ip;
-	cmdline_fixed_string_t mpls_string;
-	cmdline_fixed_string_t mpls_labels;
-};
+	/* route add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-static void
-cmd_route_add6_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add6_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data route_data;
-	uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-	uint32_t n_labels = RTE_DIM(mpls_labels);
-	uint32_t i;
-	int status;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
+			return;
+		}
 
-	/* Parse MPLS labels */
-	status = parse_labels(params->mpls_labels, mpls_labels, &n_labels);
-	if (status) {
-		printf("MPLS labels parse error\n");
-		return;
-	}
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
-
-	route_data.flags = PIPELINE_ROUTING_ROUTE_MPLS |
-		PIPELINE_ROUTING_ROUTE_ARP;
-	route_data.port_id = params->port;
-	route_data.ethernet.ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	for (i = 0; i < n_labels; i++)
-		route_data.l2.mpls.labels[i] = mpls_labels[i];
-	route_data.l2.mpls.n_labels = n_labels;
-
-	status = app_pipeline_routing_add_route(app,
-		params->p,
-		&key,
-		&route_data);
+		status = app_pipeline_routing_add_default_route(app,
+			params->p,
+			port_id);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route add default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add6_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add6_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_add6_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, add_string,
-	"add");
+	} /* route add default */
 
-static cmdline_parse_token_ipaddr_t cmd_route_add6_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, ip);
+	/* route del*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_route_key key;
+		struct in_addr ipv4;
+		uint32_t depth;
 
-static cmdline_parse_token_num_t cmd_route_add6_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, depth, UINT32);
+		memset(&key, 0, sizeof(key));
 
-static cmdline_parse_token_string_t cmd_route_add6_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, port_string,
-	"port");
-
-static cmdline_parse_token_num_t cmd_route_add6_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, port, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_add6_ether_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, ether_string,
-	"ether");
-
-static cmdline_parse_token_ipaddr_t cmd_route_add6_nh_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, nh_ip);
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_string,
-	"mpls");
-
-static cmdline_parse_token_string_t cmd_route_add6_mpls_labels =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_labels,
-	NULL);
-
-static cmdline_parse_inst_t cmd_route_add6 = {
-	.f = cmd_route_add6_parsed,
-	.data = NULL,
-	.help_str = "Route add (mpls = yes, arp = yes)",
-	.tokens = {
-		(void *)&cmd_route_add6_p_string,
-		(void *)&cmd_route_add6_p,
-		(void *)&cmd_route_add6_route_string,
-		(void *)&cmd_route_add6_add_string,
-		(void *)&cmd_route_add6_ip,
-		(void *)&cmd_route_add6_depth,
-		(void *)&cmd_route_add6_port_string,
-		(void *)&cmd_route_add6_port,
-		(void *)&cmd_route_add6_ether_string,
-		(void *)&cmd_route_add6_nh_ip,
-		(void *)&cmd_route_add6_mpls_string,
-		(void *)&cmd_route_add6_mpls_labels,
-		NULL,
-	},
-};
-
-/*
- * route del
- */
-
-struct cmd_route_del_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t ip;
-	uint32_t depth;
-};
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route del");
+			return;
+		}
 
-static void
-cmd_route_del_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_del_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing_route_key key;
+		if (parse_ipv4_addr(tokens[1], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	int status;
+		if (parser_read_uint32(&depth, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "depth");
+			return;
+		}
 
-	/* Create route */
-	key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.depth = params->depth;
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.depth = depth;
 
-	status = app_pipeline_routing_delete_route(app, params->p, &key);
+		status = app_pipeline_routing_delete_route(app, params->p, &key);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,
-	"route");
-
-static cmdline_parse_token_string_t cmd_route_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,
-	"del");
-
-static cmdline_parse_token_ipaddr_t cmd_route_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_route_del_result, ip);
-
-static cmdline_parse_token_num_t cmd_route_del_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT32);
-
-static cmdline_parse_inst_t cmd_route_del = {
-	.f = cmd_route_del_parsed,
-	.data = NULL,
-	.help_str = "Route delete",
-	.tokens = {
-		(void *)&cmd_route_del_p_string,
-		(void *)&cmd_route_del_p,
-		(void *)&cmd_route_del_route_string,
-		(void *)&cmd_route_del_del_string,
-		(void *)&cmd_route_del_ip,
-		(void *)&cmd_route_del_depth,
-		NULL,
-	},
-};
-
-/*
- * route add default
- */
-
-struct cmd_route_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port;
-};
-
-static void
-cmd_route_add_default_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_add_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	} /* route del */
+
+	/* route del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		if (n_tokens != 2) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
+			return;
+		}
 
-	status = app_pipeline_routing_add_default_route(app, params->p,
-			params->port);
+		status = app_pipeline_routing_delete_default_route(app,
+			params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route del default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, p, UINT32);
-
-cmdline_parse_token_string_t cmd_route_add_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		route_string, "route");
-
-cmdline_parse_token_string_t cmd_route_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-		add_string, "add");
-
-cmdline_parse_token_string_t cmd_route_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
-	default_string, "default");
-
-cmdline_parse_token_num_t cmd_route_add_default_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result,
-		port, UINT32);
+	} /* route del default */
 
-cmdline_parse_inst_t cmd_route_add_default = {
-	.f = cmd_route_add_default_parsed,
-	.data = NULL,
-	.help_str = "Route default set",
-	.tokens = {
-		(void *)&cmd_route_add_default_p_string,
-		(void *)&cmd_route_add_default_p,
-		(void *)&cmd_route_add_default_route_string,
-		(void *)&cmd_route_add_default_add_string,
-		(void *)&cmd_route_add_default_default_string,
-		(void *)&cmd_route_add_default_port,
-		NULL,
-	},
-};
-
-/*
- * route del default
- */
-
-struct cmd_route_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
-
-static void
-cmd_route_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_route_del_default_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
+	/* route ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
+			return;
+		}
 
-	status = app_pipeline_routing_delete_default_route(app, params->p);
+		status = app_pipeline_routing_route_ls(app, params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "route ls");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_route_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_route_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_del_default_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-		del_string, "del");
-
-static cmdline_parse_token_string_t cmd_route_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
-	default_string, "default");
-
-
-static cmdline_parse_inst_t cmd_route_del_default = {
-	.f = cmd_route_del_default_parsed,
-	.data = NULL,
-	.help_str = "Route default clear",
-	.tokens = {
-		(void *)&cmd_route_del_default_p_string,
-		(void *)&cmd_route_del_default_p,
-		(void *)&cmd_route_del_default_route_string,
-		(void *)&cmd_route_del_default_del_string,
-		(void *)&cmd_route_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * route ls
- */
+	} /* route ls */
 
-struct cmd_route_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t ls_string;
-};
-
-static void
-cmd_route_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	status = app_pipeline_routing_route_ls(app, params->p);
-
-	if (status != 0) {
-		printf("Command failed\n");
-		return;
-	}
+	printf(CMD_MSG_MISMATCH_ARGS, "route");
 }
 
-static cmdline_parse_token_string_t cmd_route_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, p_string, "p");
+static cmdline_parse_token_string_t cmd_route_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
 
-static cmdline_parse_token_num_t cmd_route_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_ls_result, p, UINT32);
+static cmdline_parse_token_num_t cmd_route_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
 
-static cmdline_parse_token_string_t cmd_route_ls_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result,
-	route_string, "route");
+static cmdline_parse_token_string_t cmd_route_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
 
-static cmdline_parse_token_string_t cmd_route_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_route_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_inst_t cmd_route_ls = {
-	.f = cmd_route_ls_parsed,
+static cmdline_parse_inst_t cmd_route = {
+	.f = cmd_route_parsed,
 	.data = NULL,
-	.help_str = "Route list",
+	.help_str = "route add / add default / del / del default / ls",
 	.tokens = {
-		(void *)&cmd_route_ls_p_string,
-		(void *)&cmd_route_ls_p,
-		(void *)&cmd_route_ls_route_string,
-		(void *)&cmd_route_ls_ls_string,
+		(void *)&cmd_route_p_string,
+		(void *)&cmd_route_p,
+		(void *)&cmd_route_route_string,
+		(void *)&cmd_route_multi_string,
 		NULL,
 	},
 };
 
 /*
- * arp add
+ * arp
+ *
+ * arp add:
+ *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
+ *
+ * arp add default:
+ *    p <pipelineid> arp add default <portid>
+ *
+ * arp del:
+ *    p <pipelineid> arp del <portid> <ipaddr>
+ *
+ * arp del default:
+ *    p <pipelineid> arp del default
+ *
+ * arp ls:
+ *    p <pipelineid> arp ls
  */
 
-struct cmd_arp_add_result {
+struct cmd_arp_result {
 	cmdline_fixed_string_t p_string;
 	uint32_t p;
 	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
-	struct ether_addr macaddr;
-
+	cmdline_multi_string_t multi_string;
 };
 
 static void
-cmd_arp_add_parsed(
+cmd_arp_parsed(
 	void *parsed_result,
 	__rte_unused struct cmdline *cl,
 	void *data)
 {
-	struct cmd_arp_add_result *params = parsed_result;
+	struct cmd_arp_result *params = parsed_result;
 	struct app_params *app = data;
 
-	struct pipeline_routing_arp_key key;
+	char *tokens[16];
+	uint32_t n_tokens = RTE_DIM(tokens);
 	int status;
 
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.port_id = params->port_id;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
-
-	status = app_pipeline_routing_add_arp_entry(app,
-		params->p,
-		&key,
-		&params->macaddr);
-
+	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
 	if (status != 0) {
-		printf("Command failed\n");
+		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
 		return;
 	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_add_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_add_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, "arp");
 
-static cmdline_parse_token_string_t cmd_arp_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, "add");
+	/* arp add */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_arp_key key;
+		struct in_addr ipv4;
+		struct ether_addr mac_addr;
+		uint32_t port_id;
 
-static cmdline_parse_token_num_t cmd_arp_add_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, port_id, UINT32);
-
-static cmdline_parse_token_ipaddr_t cmd_arp_add_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_add_result, ip);
-
-static cmdline_parse_token_etheraddr_t cmd_arp_add_macaddr =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, macaddr);
-
-static cmdline_parse_inst_t cmd_arp_add = {
-	.f = cmd_arp_add_parsed,
-	.data = NULL,
-	.help_str = "ARP add",
-	.tokens = {
-		(void *)&cmd_arp_add_p_string,
-		(void *)&cmd_arp_add_p,
-		(void *)&cmd_arp_add_arp_string,
-		(void *)&cmd_arp_add_add_string,
-		(void *)&cmd_arp_add_port_id,
-		(void *)&cmd_arp_add_ip,
-		(void *)&cmd_arp_add_macaddr,
-		NULL,
-	},
-};
+		memset(&key, 0, sizeof(key));
 
-/*
- * arp del
- */
+		if (n_tokens != 4) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
+			return;
+		}
 
-struct cmd_arp_del_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	uint32_t port_id;
-	cmdline_ipaddr_t ip;
-};
+		if (parser_read_uint32(&port_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static void
-cmd_arp_del_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_del_result *params = parsed_result;
-	struct app_params *app = data;
+		if (parse_ipv4_addr(tokens[2], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	struct pipeline_routing_arp_key key;
-	int status;
+		if (parse_mac_addr(tokens[3], &mac_addr)) {
+			printf(CMD_MSG_INVALID_ARG, "macaddr");
+			return;
+		}
 
-	key.type = PIPELINE_ROUTING_ARP_IPV4;
-	key.key.ipv4.ip = rte_cpu_to_be_32(params->ip.addr.ipv4.s_addr);
-	key.key.ipv4.port_id = params->port_id;
+		key.type = PIPELINE_ROUTING_ARP_IPV4;
+		key.key.ipv4.port_id = port_id;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
 
-	status = app_pipeline_routing_delete_arp_entry(app, params->p, &key);
+		status = app_pipeline_routing_add_arp_entry(app,
+			params->p,
+			&key,
+			&mac_addr);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp add");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arp");
+	} /* arp add */
 
-static cmdline_parse_token_string_t cmd_arp_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, "del");
-
-static cmdline_parse_token_num_t cmd_arp_del_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, port_id, UINT32);
-
-static cmdline_parse_token_ipaddr_t cmd_arp_del_ip =
-	TOKEN_IPV4_INITIALIZER(struct cmd_arp_del_result, ip);
-
-static cmdline_parse_inst_t cmd_arp_del = {
-	.f = cmd_arp_del_parsed,
-	.data = NULL,
-	.help_str = "ARP delete",
-	.tokens = {
-		(void *)&cmd_arp_del_p_string,
-		(void *)&cmd_arp_del_p,
-		(void *)&cmd_arp_del_arp_string,
-		(void *)&cmd_arp_del_del_string,
-		(void *)&cmd_arp_del_port_id,
-		(void *)&cmd_arp_del_ip,
-		NULL,
-	},
-};
+	/* arp add default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "add") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+		uint32_t port_id;
 
-/*
- * arp add default
- */
-
-struct cmd_arp_add_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t default_string;
-	uint32_t port_id;
-};
-
-static void
-cmd_arp_add_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_add_default_result *params = parsed_result;
-	struct app_params *app = data;
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
+			return;
+		}
 
-	int status;
+		if (parser_read_uint32(&port_id, tokens[2])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-	status = app_pipeline_routing_add_default_arp_entry(app,
-		params->p,
-		params->port_id);
+		status = app_pipeline_routing_add_default_arp_entry(app,
+			params->p,
+			port_id);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp add default");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_add_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_add_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_add_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, arp_string,
-	"arp");
+	} /* arp add default */
 
-static cmdline_parse_token_string_t cmd_arp_add_default_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, add_string,
-	"add");
+	/* arp del*/
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		strcmp(tokens[1], "default")) {
+		struct pipeline_routing_arp_key key;
+		struct in_addr ipv4;
+		uint32_t port_id;
 
-static cmdline_parse_token_string_t cmd_arp_add_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result,
-		default_string, "default");
+		memset(&key, 0, sizeof(key));
 
-static cmdline_parse_token_num_t cmd_arp_add_default_port_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, port_id,
-	UINT32);
-
-static cmdline_parse_inst_t cmd_arp_add_default = {
-	.f = cmd_arp_add_default_parsed,
-	.data = NULL,
-	.help_str = "ARP add default",
-	.tokens = {
-		(void *)&cmd_arp_add_default_p_string,
-		(void *)&cmd_arp_add_default_p,
-		(void *)&cmd_arp_add_default_arp_string,
-		(void *)&cmd_arp_add_default_add_string,
-		(void *)&cmd_arp_add_default_default_string,
-		(void *)&cmd_arp_add_default_port_id,
-		NULL,
-	},
-};
-
-/*
- * arp del default
- */
+		if (n_tokens != 3) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
+			return;
+		}
 
-struct cmd_arp_del_default_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_fixed_string_t default_string;
-};
+		if (parser_read_uint32(&port_id, tokens[1])) {
+			printf(CMD_MSG_INVALID_ARG, "portid");
+			return;
+		}
 
-static void
-cmd_arp_del_default_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_del_default_result *params = parsed_result;
-	struct app_params *app = data;
+		if (parse_ipv4_addr(tokens[2], &ipv4)) {
+			printf(CMD_MSG_INVALID_ARG, "ipaddr");
+			return;
+		}
 
-	int status;
+		key.type = PIPELINE_ROUTING_ARP_IPV4;
+		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
+		key.key.ipv4.port_id = port_id;
 
-	status = app_pipeline_routing_delete_default_arp_entry(app, params->p);
+		status = app_pipeline_routing_delete_arp_entry(app,
+			params->p,
+			&key);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp del");
 
-	if (status != 0) {
-		printf("Command failed\n");
 		return;
-	}
-}
-
-static cmdline_parse_token_string_t cmd_arp_del_default_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_arp_del_default_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_default_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_del_default_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, arp_string,
-	"arp");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, del_string,
-	"del");
-
-static cmdline_parse_token_string_t cmd_arp_del_default_default_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result,
-		default_string, "default");
-
-static cmdline_parse_inst_t cmd_arp_del_default = {
-	.f = cmd_arp_del_default_parsed,
-	.data = NULL,
-	.help_str = "ARP delete default",
-	.tokens = {
-		(void *)&cmd_arp_del_default_p_string,
-		(void *)&cmd_arp_del_default_p,
-		(void *)&cmd_arp_del_default_arp_string,
-		(void *)&cmd_arp_del_default_del_string,
-		(void *)&cmd_arp_del_default_default_string,
-		NULL,
-	},
-};
-
-/*
- * arp ls
- */
+	} /* arp del */
+
+	/* arp del default */
+	if ((n_tokens >= 2) &&
+		(strcmp(tokens[0], "del") == 0) &&
+		(strcmp(tokens[1], "default") == 0)) {
+			if (n_tokens != 2) {
+				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
+				return;
+			}
+
+			status = app_pipeline_routing_delete_default_arp_entry(app,
+				params->p);
+			if (status != 0)
+				printf(CMD_MSG_FAIL, "arp del default");
+
+			return;
+	} /* arp del default */
+
+	/* arp ls */
+	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
+		if (n_tokens != 1) {
+			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
+			return;
+		}
 
-struct cmd_arp_ls_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t ls_string;
-};
+		status = app_pipeline_routing_arp_ls(app, params->p);
+		if (status != 0)
+			printf(CMD_MSG_FAIL, "arp ls");
 
-static void
-cmd_arp_ls_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_ls_result *params = parsed_result;
-	struct app_params *app = data;
-	struct pipeline_routing *p;
-
-	p = app_pipeline_data_fe(app, params->p, &pipeline_routing);
-	if (p == NULL)
 		return;
+	} /* arp ls */
 
-	app_pipeline_routing_arp_ls(app, params->p);
+	printf(CMD_MSG_FAIL, "arp");
 }
 
-static cmdline_parse_token_string_t cmd_arp_ls_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
-	"p");
+static cmdline_parse_token_string_t cmd_arp_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
 
-static cmdline_parse_token_num_t cmd_arp_ls_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+static cmdline_parse_token_num_t cmd_arp_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
 
-static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
-	"arp");
+static cmdline_parse_token_string_t cmd_arp_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
 
-static cmdline_parse_token_string_t cmd_arp_ls_ls_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, ls_string,
-	"ls");
+static cmdline_parse_token_string_t cmd_arp_multi_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
+	TOKEN_STRING_MULTI);
 
-static cmdline_parse_inst_t cmd_arp_ls = {
-	.f = cmd_arp_ls_parsed,
+static cmdline_parse_inst_t cmd_arp = {
+	.f = cmd_arp_parsed,
 	.data = NULL,
-	.help_str = "ARP list",
+	.help_str = "arp add / add default / del / del default / ls",
 	.tokens = {
-		(void *)&cmd_arp_ls_p_string,
-		(void *)&cmd_arp_ls_p,
-		(void *)&cmd_arp_ls_arp_string,
-		(void *)&cmd_arp_ls_ls_string,
+		(void *)&cmd_arp_p_string,
+		(void *)&cmd_arp_p,
+		(void *)&cmd_arp_arp_string,
+		(void *)&cmd_arp_multi_string,
 		NULL,
 	},
 };
 
 static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route_add1,
-	(cmdline_parse_inst_t *)&cmd_route_add2,
-	(cmdline_parse_inst_t *)&cmd_route_add3,
-	(cmdline_parse_inst_t *)&cmd_route_add4,
-	(cmdline_parse_inst_t *)&cmd_route_add5,
-	(cmdline_parse_inst_t *)&cmd_route_add6,
-	(cmdline_parse_inst_t *)&cmd_route_del,
-	(cmdline_parse_inst_t *)&cmd_route_add_default,
-	(cmdline_parse_inst_t *)&cmd_route_del_default,
-	(cmdline_parse_inst_t *)&cmd_route_ls,
-	(cmdline_parse_inst_t *)&cmd_arp_add,
-	(cmdline_parse_inst_t *)&cmd_arp_del,
-	(cmdline_parse_inst_t *)&cmd_arp_add_default,
-	(cmdline_parse_inst_t *)&cmd_arp_del_default,
-	(cmdline_parse_inst_t *)&cmd_arp_ls,
+	(cmdline_parse_inst_t *)&cmd_route,
+	(cmdline_parse_inst_t *)&cmd_arp,
 	NULL,
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 7/7] examples/ip_pipeline: update edge router usecase
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
                       ` (5 preceding siblings ...)
  2016-06-08 10:35     ` [PATCH v3 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
@ 2016-06-08 10:35     ` Piotr Azarewicz
  2016-06-08 14:46     ` [PATCH v3 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
  7 siblings, 0 replies; 26+ messages in thread
From: Piotr Azarewicz @ 2016-06-08 10:35 UTC (permalink / raw)
  To: dev; +Cc: Piotr Azarewicz

Update edge router usecase config files to use bulk commands.

Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 .../ip_pipeline/config/edge_router_downstream.cfg  |   30 +++++++++++-----
 .../ip_pipeline/config/edge_router_downstream.sh   |    7 ++--
 .../ip_pipeline/config/edge_router_upstream.cfg    |   36 +++++++++++++------
 .../ip_pipeline/config/edge_router_upstream.sh     |   37 +++++++++-----------
 4 files changed, 67 insertions(+), 43 deletions(-)

diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
index 85bbab8..c6b4e1f 100644
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ b/examples/ip_pipeline/config/edge_router_downstream.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -36,9 +36,9 @@
 ;   network) contains the following functional blocks: Packet RX & Routing,
 ;   Traffic management and Packet TX. The input packets are assumed to be
 ;   IPv4, while the output packets are Q-in-Q IPv4.
-
+;
 ;  A simple implementation for this functional pipeline is presented below.
-
+;
 ;                  Packet Rx &                Traffic Management               Packet Tx
 ;                   Routing                    (Pass-Through)                (Pass-Through)
 ;             _____________________  SWQ0  ______________________  SWQ4  _____________________
@@ -50,11 +50,23 @@
 ;            |                     | SWQ3 |                      | SWQ7 |                     |
 ; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
 ;            |_____________________|      |______________________|      |_____________________|
-;                       |                 _|_ ^ _|_ ^ _|_ ^ _|_ ^
-;                       |                |___|||___|||___|||___||
-;                       +--> SINK0       |___|||___|||___|||___||
-;                      (route miss)        |__|  |__|  |__|  |__|
-;                                          TM0   TM1   TM2   TM3
+;                       |                  |  ^  |  ^  |  ^  |  ^
+;                       |                  |__|  |__|  |__|  |__|
+;                       +--> SINK0          TM0   TM1   TM2   TM3
+;                      (Default)
+;
+; Input packet: Ethernet/IPv4
+; Output packet: Ethernet/QinQ/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3	IPv4 header		270 		20
+
+[EAL]
+log_level = 0
 
 [PIPELINE0]
 type = MASTER
@@ -67,7 +79,7 @@ pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
 pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
 encap = ethernet_qinq
 qinq_sched = test
-ip_hdr_offset = 270; mbuf (128) + headroom (128) + ethernet header (14) = 270
+ip_hdr_offset = 270
 
 [PIPELINE2]
 type = PASS-THROUGH
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
index ce46beb..67c3a0d 100644
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ b/examples/ip_pipeline/config/edge_router_downstream.sh
@@ -1,3 +1,7 @@
+#
+# run ./config/edge_router_downstream.sh
+#
+
 ################################################################################
 # Routing: Ether QinQ, ARP off
 ################################################################################
@@ -6,5 +10,4 @@ p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
 p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
 p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
 p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-
-p 1 route ls
+#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
index a08c5cc..dea42b9 100644
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ b/examples/ip_pipeline/config/edge_router_upstream.cfg
@@ -1,6 +1,6 @@
 ;   BSD LICENSE
 ;
-;   Copyright(c) 2015 Intel Corporation. All rights reserved.
+;   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
 ;   All rights reserved.
 ;
 ;   Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,7 @@
 ;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+
 ;   An edge router typically sits between two networks such as the provider
 ;   core network and the provider access network. A typical packet processing
 ;   pipeline for the upstream traffic (i.e. traffic from access to core
@@ -36,10 +37,10 @@
 ;   Flow classification, Metering, Routing and Packet TX. The input packets
 ;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
 ;  (with variable number of labels per route).
-
+;
 ;   A simple implementation for this functional pipeline is presented below.
-
-;             Packet Rx &       Pass-Through    Flow-Classification   Flow-Actions         Routing
+;
+;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
 :              Firewall
 ;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
 ; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
@@ -51,8 +52,21 @@
 ; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
 ;            |__________|       |__________|       |__________|       |__________|       |__________|
 ;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Route Miss)
+;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
+;
+; Input packet: Ethernet/QinQ/IPv4
+; Output packet: Ethernet/MPLS/IPv4
+;
+; Packet buffer layout:
+; #	Field Name		Offset (Bytes)	Size (Bytes)
+; 0	Mbuf			0 		128
+; 1	Headroom		128 		128
+; 2	Ethernet header		256 		14
+; 3     QinQ header             270             8
+; 4	IPv4 header		278 		20
 
+[EAL]
+log_level = 0
 
 [PIPELINE0]
 type = MASTER
@@ -72,10 +86,10 @@ core = 2
 pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
 pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
 dma_size = 8
-dma_dst_offset = 128; mbuf (128)
-dma_src_offset = 268; mbuf (128) + headroom (128) + 1st ethertype offset (12) = 268
+dma_dst_offset = 128
+dma_src_offset = 268; 1st Ethertype offset
 dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size = 136
+dma_hash_offset = 136; dma_dst_offset + dma_size
 
 [PIPELINE3]
 type = FLOW_CLASSIFICATION
@@ -86,7 +100,7 @@ n_flows = 65536
 key_size = 8; dma_size
 key_offset = 128; dma_dst_offset
 hash_offset = 136; dma_hash_offset
-flowid_offset = 192; mbuf (128) + 64
+flowid_offset = 192
 
 [PIPELINE4]
 type = FLOW_ACTIONS
@@ -96,7 +110,7 @@ pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
 n_flows = 65536
 n_meters_per_flow = 1
 flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278; mbuf (128) + headroom (128) + ethernet (14) + qinq (8) = 278
+ip_hdr_offset = 278
 color_offset = 196; flowid_offset + sizeof(flow_id)
 
 [PIPELINE5]
@@ -106,5 +120,5 @@ pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
 pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
 encap = ethernet_mpls
 mpls_color_mark = yes
-ip_hdr_offset = 278; mbuf (128) + headroom (128) + ethernet (14) + qinq (8) = 278
+ip_hdr_offset = 278
 color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
index eeba600..5d574c1 100644
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ b/examples/ip_pipeline/config/edge_router_upstream.sh
@@ -1,24 +1,26 @@
-################################################
-# Firewall Rules:4 for 4 ports
-################################################
-p 1 firewall add ipv4 1 0.0.0.0 8 0.0.0.0 10 0 0 0 0 6 1 0
-p 1 firewall add ipv4 1 0.0.0.0 8 0.64.0.0 10 0 0 0 0 6 1 1
-p 1 firewall add ipv4 1 0.0.0.0 8 0.128.0.0 10 0 0 0 0 6 1 2
-p 1 firewall add ipv4 1 0.0.0.0 8 0.192.0.0 10 0 0 0 0 6 1 3
-p 1 firewall add default 4 #SINK0
+#
+# run ./config/edge_router_upstream.sh
+#
 
+################################################################################
+# Firewall
+################################################################################
+p 1 firewall add default 4 #SINK0
+p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
+#p 1 firewall ls
 
 ################################################################################
-# Flow classification
+# Flow Classification
 ################################################################################
 p 3 flow add default 4 #SINK1
-p 3 flow add qinq all 65536 4
+p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
+#p 3 flow ls
 
 ################################################################################
-# Flow Actions - Metering
+# Flow Actions - Metering and Policing
 ################################################################################
-p 4 flows 65536 meter 0 trtcm 1250000000 1250000000 100000000 100000000
-p 4 flows 65536 ports 4
+p 4 action flow bulk ./config/edge_router_upstream_action.txt
+#p 4 action flow ls
 
 ################################################################################
 # Routing: Ether MPLS, ARP off
@@ -28,11 +30,4 @@ p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
 p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
 p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
 p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-
-################################################################################
-# List all configurations
-################################################################################
-p 1 firewall ls
-#p 3 flow ls
-#p 4 flow actions ls
-p 5 route ls
+#p 5 route ls
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 0/7] examples/ip_pipeline: CLI rework and improvements
  2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
                       ` (6 preceding siblings ...)
  2016-06-08 10:35     ` [PATCH v3 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
@ 2016-06-08 14:46     ` Thomas Monjalon
  7 siblings, 0 replies; 26+ messages in thread
From: Thomas Monjalon @ 2016-06-08 14:46 UTC (permalink / raw)
  To: Piotr Azarewicz; +Cc: dev

2016-06-08 12:35, Piotr Azarewicz:
> Using the latest librte_cmdline improvements, the CLI implementation of the
> ip_pipeline application is streamlined and improved, which results in
> eliminating thousands of lines of code from the application, thus leading to
> code that is easier to maintain and extend.
> 
> v3 changes:
> - fix the authorship in patches
> 
> v2 changes:
> - added functions for parsing hex values
> - added standard error messages for CLI and file bulk
> - for all CLI commands: separate code paths for each flavor of each command
> (e.g. route add, route add default, route ls, route del, route del default,
> etc do not share any line of code)
> - for bulk commands: simplified error checking
> - added additional config files
> 
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> 
> Daniel Mrzyglod (1):
>   examples/ip_pipeline: modifies firewall pipeline CLI
> 
> Piotr Azarewicz (4):
>   examples/ip_pipeline: add helper functions for parsing string
>   examples/ip_pipeline: modifies flow action pipeline CLI
>   examples/ip_pipeline: modifies routing pipeline CLI
>   examples/ip_pipeline: update edge router usecase
> 
> Tomasz Kulasek (2):
>   examples/ip_pipeline: modifies common pipeline CLI
>   examples/ip_pipeline: modifies flow classifications pipeline CLI

Applied, thanks

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-06-08 14:46 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-06 15:57 [PATCH 0/6] ip_pipeline: CLI rework and improvements Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 1/6] examples/ip_pipeline: add helper functions for parsing string Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 2/6] examples/ip_pipeline: modifies common pipeline CLI Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 3/6] examples/ip_pipeline: modifies routing commands Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 4/6] examples/ip_pipeline: modifies firewall pipeline CLI Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 5/6] examples/ip_pipeline: modifies flow classifications " Michal Jastrzebski
2016-05-06 15:57 ` [PATCH 6/6] examples/ip_pipeline: modifies flow action " Michal Jastrzebski
2016-05-20 14:35 ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
2016-05-20 14:35   ` [PATCH v2 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
2016-06-07 20:34   ` [PATCH v2 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon
2016-06-08 10:01     ` Azarewicz, PiotrX T
2016-06-08 10:35   ` [PATCH v3 " Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 1/7] examples/ip_pipeline: add helper functions for parsing string Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 2/7] examples/ip_pipeline: modifies common pipeline CLI Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 3/7] examples/ip_pipeline: modifies firewall " Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 4/7] examples/ip_pipeline: modifies flow classifications " Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 5/7] examples/ip_pipeline: modifies flow action " Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 6/7] examples/ip_pipeline: modifies routing " Piotr Azarewicz
2016-06-08 10:35     ` [PATCH v3 7/7] examples/ip_pipeline: update edge router usecase Piotr Azarewicz
2016-06-08 14:46     ` [PATCH v3 0/7] examples/ip_pipeline: CLI rework and improvements Thomas Monjalon

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.