[dpdk-dev] igb: integrate flex filter to new API

Message ID 1422593303-15308-1-git-send-email-zhida.zang@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

zzang Jan. 30, 2015, 4:48 a.m. UTC
  changes:
igb: remove old functions that deal with flex filter
igb: add new functions that deal with flex filter(fit for new API)
testpmd: change the entry for flex filter in cmdline
testpmd: change function call to get flex filter in config
doc: change doc that describes how to use flex filter related functions

Signed-off-by: Zhida Zang <zhida.zang@intel.com>
---
 app/test-pmd/cmdline.c                      | 244 ++++++++++----------
 app/test-pmd/config.c                       |  37 ++--
 app/test-pmd/testpmd.h                      |   2 +-
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  56 ++---
 lib/librte_ether/rte_eth_ctrl.h             |  20 ++
 lib/librte_pmd_e1000/e1000_ethdev.h         |  20 ++
 lib/librte_pmd_e1000/igb_ethdev.c           | 331 +++++++++++++++++-----------
 7 files changed, 410 insertions(+), 300 deletions(-)
  

Comments

Jingjing Wu Feb. 15, 2015, 4:07 a.m. UTC | #1
v2 changes:
 - split one patch to patch series
 - change the command's format in testpmd.
 - add doc changes in testpmd_funcs.rst
 - correct the errors reported by checkpatch.pl

The patch set uses new filter_ctrl API to replace old flex filter APIs.
It uses new functions and structure to replace old ones in igb driver, new commands to replace old ones in testpmd, and removes the old APIs.


Jingjing Wu (5):
  ethdev: define flex filter type and its structure
  e1000: new functions replace old ones for flex filter
  testpmd: new commands for flex filter
  ethdev: remove old APIs and structures of syn filter
  doc: commands changed in testpmd_funcs for flex filter

 app/test-pmd/cmdline.c                      | 239 ++++++++------------
 app/test-pmd/config.c                       |  33 ---
 app/test-pmd/testpmd.h                      |   1 -
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  56 +----
 lib/librte_ether/rte_eth_ctrl.h             |  20 ++
 lib/librte_ether/rte_ethdev.c               |  51 -----
 lib/librte_ether/rte_ethdev.h               |  89 --------
 lib/librte_pmd_e1000/e1000_ethdev.h         |  27 ++-
 lib/librte_pmd_e1000/igb_ethdev.c           | 332 +++++++++++++++++-----------
 9 files changed, 352 insertions(+), 496 deletions(-)
  
De Lara Guarch, Pablo Feb. 21, 2015, 1:53 a.m. UTC | #2
The patch set uses new filter_ctrl API to replace old flex filter APIs.
It uses new functions and structure to replace old ones in igb driver, new commands to replace old ones in testpmd, and removes the old APIs.

v3 changes:
 - fix testpmd documentation

v2 changes:
 - split one patch to patch series
 - change the command's format in testpmd.
 - add doc changes in testpmd_funcs.rst
 - correct the errors reported by checkpatch.pl

Jingjing Wu (5):
  ethdev: define flex filter type and its structure
  e1000: new functions replace old ones for flex filter
  testpmd: new commands for flex filter
  ethdev: remove old APIs and structures of flex filter
  doc: commands changed in testpmd_funcs for flex filter

 app/test-pmd/cmdline.c                      |  239 ++++++++------------
 app/test-pmd/config.c                       |   33 ---
 app/test-pmd/testpmd.h                      |    1 -
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   64 ++----
 lib/librte_ether/rte_eth_ctrl.h             |   20 ++
 lib/librte_ether/rte_ethdev.c               |   51 ----
 lib/librte_ether/rte_ethdev.h               |   89 -------
 lib/librte_pmd_e1000/e1000_ethdev.h         |   27 ++-
 lib/librte_pmd_e1000/igb_ethdev.c           |  332 +++++++++++++++++----------
 9 files changed, 356 insertions(+), 500 deletions(-)
  
Thomas Monjalon Feb. 22, 2015, 1:29 a.m. UTC | #3
2015-02-21 01:53, Pablo de Lara:
> The patch set uses new filter_ctrl API to replace old flex filter APIs.
> It uses new functions and structure to replace old ones in igb driver, new commands to replace old ones in testpmd, and removes the old APIs.
> 
> v3 changes:
>  - fix testpmd documentation
> 
> v2 changes:
>  - split one patch to patch series
>  - change the command's format in testpmd.
>  - add doc changes in testpmd_funcs.rst
>  - correct the errors reported by checkpatch.pl
> 
> Jingjing Wu (5):
>   ethdev: define flex filter type and its structure
>   e1000: new functions replace old ones for flex filter
>   testpmd: new commands for flex filter
>   ethdev: remove old APIs and structures of flex filter
>   doc: commands changed in testpmd_funcs for flex filter

Applied, thanks.
I also updated version map to remove old API.
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4beb404..2f99d23 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -691,14 +691,19 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"get_syn_filter (port_id) "
 			"    get syn filter info.\n\n"
 
-			"add_flex_filter (port_id) len (len_value) bytes (bytes_string) mask (mask_value)"
-			" priority (prio_value) queue (queue_id) index (idx)\n"
+			"flex_filter add (port_id) len (len_value)"
+			" bytes (bytes_string) mask (mask_value)"
+			" priority (prio_value) queue (queue_id)\n"
 			"    add a flex filter.\n\n"
 
-			"remove_flex_filter (port_id) index (idx)\n"
-			"    remove a flex filter.\n\n"
+			"flex_filter del (port_id) len (len_value)"
+			" bytes (bytes_string) mask (mask_value)"
+			" priority (prio_value)\n"
+			"    del a flex filter.\n\n"
 
-			"get_flex_filter (port_id) index (idx)\n"
+			"flex_filter get (port_id) len (len_value)"
+			" bytes (bytes_string) mask (mask_value)"
+			"priority (prio_value)\n"
 			"    get info of a flex filter.\n\n"
 
 			"flow_director_filter (port_id) (add|del)"
@@ -7723,9 +7728,10 @@  cmdline_parse_inst_t cmd_get_5tuple_filter = {
 	},
 };
 
-/* *** ADD/REMOVE A flex FILTER *** */
+/* *** Add/Del/Get flex filter *** */
 struct cmd_flex_filter_result {
 	cmdline_fixed_string_t filter;
+	cmdline_fixed_string_t ops;
 	uint8_t port_id;
 	cmdline_fixed_string_t len;
 	uint8_t len_value;
@@ -7737,8 +7743,6 @@  struct cmd_flex_filter_result {
 	uint8_t priority_value;
 	cmdline_fixed_string_t queue;
 	uint16_t queue_id;
-	cmdline_fixed_string_t index;
-	uint16_t index_value;
 };
 
 static int xdigit2val(unsigned char c)
@@ -7759,105 +7763,101 @@  cmd_flex_filter_parsed(void *parsed_result,
 			  __attribute__((unused)) void *data)
 {
 	int ret = 0;
-	struct rte_flex_filter filter;
+	struct rte_eth_flex_filter filter;
 	struct cmd_flex_filter_result *res = parsed_result;
 	char *bytes_ptr, *mask_ptr;
 	uint16_t len, i, j;
 	char c;
-	int val, mod = 0;
-	uint32_t dword = 0;
+	int val;
 	uint8_t byte = 0;
 	uint8_t hex = 0;
 
-	if (!strcmp(res->filter, "add_flex_filter")) {
-		if (res->len_value > 128) {
-			printf("the len exceed the max length 128\n");
-			return;
-		}
-		memset(&filter, 0, sizeof(struct rte_flex_filter));
-		filter.len = res->len_value;
-		filter.priority = res->priority_value;
-		bytes_ptr = res->bytes_value;
-		mask_ptr = res->mask_value;
-
-		j = 0;
-		 /* translate bytes string to uint_32 array. */
-		if (bytes_ptr[0] == '0' && ((bytes_ptr[1] == 'x') ||
-			(bytes_ptr[1] == 'X')))
-			bytes_ptr += 2;
-		len = strnlen(bytes_ptr, res->len_value * 2);
-		if (len == 0 || (len % 8 != 0)) {
-			printf("please check len and bytes input\n");
+	if (res->len_value > 128) {
+		printf("the len exceed the max length 128\n");
+		return;
+	}
+	memset(&filter, 0, sizeof(struct rte_eth_flex_filter));
+	filter.len = res->len_value;
+	filter.priority = res->priority_value;
+	filter.queue = res->queue_id;
+	bytes_ptr = res->bytes_value;
+	mask_ptr = res->mask_value;
+
+	j = 0;
+	 /* translate bytes string to uint_32 array. */
+	if (bytes_ptr[0] == '0' && ((bytes_ptr[1] == 'x') ||
+		(bytes_ptr[1] == 'X')))
+		bytes_ptr += 2;
+	len = strnlen(bytes_ptr, res->len_value * 2);
+	if (len == 0 || (len % 8 != 0)) {
+		printf("please check len and bytes input\n");
+		return;
+	}
+	for (i = 0; i < len; i++) {
+		c = bytes_ptr[i];
+		if (isxdigit(c) == 0) {
+			/* invalid characters. */
+			printf("invalid input\n");
 			return;
 		}
-		for (i = 0; i < len; i++) {
-			c = bytes_ptr[i];
-			if (isxdigit(c) == 0) {
-				/* invalid characters. */
-				printf("invalid input\n");
-				return;
-			}
-			val = xdigit2val(c);
-			mod = i % 8;
-			if (i % 2) {
-				byte |= val;
-				dword |= byte << (4 * mod - 4);
-				byte = 0;
-			} else
-				byte |= val << 4;
-			if (mod == 7) {
-				filter.dwords[j] = dword;
-				printf("dwords[%d]:%08x ", j, filter.dwords[j]);
-				j++;
-				dword = 0;
-			}
-		}
-		printf("\n");
-		 /* translate mask string to uint8_t array. */
-		j = 0;
-		if (mask_ptr[0] == '0' && ((mask_ptr[1] == 'x') ||
-			(mask_ptr[1] == 'X')))
-			mask_ptr += 2;
-		len = strnlen(mask_ptr, (res->len_value+3)/4);
-		if (len == 0) {
+		val = xdigit2val(c);
+		if (i % 2) {
+			byte |= val;
+			filter.bytes[j] = byte;
+			printf("bytes[%d]:%02x ", j, filter.bytes[j]);
+			j++;
+			byte = 0;
+		} else
+			byte |= val << 4;
+	}
+	printf("\n");
+	 /* translate mask string to uint8_t array. */
+	j = 0;
+	if (mask_ptr[0] == '0' && ((mask_ptr[1] == 'x') ||
+		(mask_ptr[1] == 'X')))
+		mask_ptr += 2;
+	len = strnlen(mask_ptr, (res->len_value+3)/4);
+	if (len == 0) {
+		printf("invalid input\n");
+		return;
+	}
+	for (i = 0; i < len; i++) {
+		c = mask_ptr[i];
+		if (isxdigit(c) == 0) {
+			/* invalid characters. */
 			printf("invalid input\n");
 			return;
 		}
-		for (i = 0; i < len; i++) {
-			c = mask_ptr[i];
-			if (isxdigit(c) == 0) {
-				/* invalid characters. */
-				printf("invalid input\n");
-				return;
-			}
-			val = xdigit2val(c);
-			hex |= (uint8_t)(val & 0x8) >> 3;
-			hex |= (uint8_t)(val & 0x4) >> 1;
-			hex |= (uint8_t)(val & 0x2) << 1;
-			hex |= (uint8_t)(val & 0x1) << 3;
-			if (i % 2) {
-				byte |= hex << 4;
-				filter.mask[j] = byte;
-				printf("mask[%d]:%02x ", j, filter.mask[j]);
-				j++;
-				byte = 0;
-			} else
-				byte |= hex;
-			hex = 0;
-		}
-		printf("\n");
-		printf("call function rte_eth_dev_add_flex_filter: "
-			"index = %d, queue-id = %d, len = %d, priority = %d\n",
-			res->index_value, res->queue_id,
-			filter.len, filter.priority);
-		ret = rte_eth_dev_add_flex_filter(res->port_id, res->index_value,
-				&filter, res->queue_id);
+		val = xdigit2val(c);
+		hex |= (uint8_t)(val & 0x8) >> 3;
+		hex |= (uint8_t)(val & 0x4) >> 1;
+		hex |= (uint8_t)(val & 0x2) << 1;
+		hex |= (uint8_t)(val & 0x1) << 3;
+		if (i % 2) {
+			byte |= hex << 4;
+			filter.mask[j] = byte;
+			printf("mask[%d]:%02x ", j, filter.mask[j]);
+			j++;
+			byte = 0;
+		} else
+			byte |= hex;
+		hex = 0;
+	}
+	printf("\n");
 
-	} else if (!strcmp(res->filter, "remove_flex_filter"))
-		ret = rte_eth_dev_remove_flex_filter(res->port_id,
-			res->index_value);
-	else if (!strcmp(res->filter, "get_flex_filter"))
-		get_flex_filter(res->port_id, res->index_value);
+	if (!strcmp(res->ops, "add"))
+		ret = rte_eth_dev_filter_ctrl(res->port_id,
+				RTE_ETH_FILTER_FLEXIBLE,
+				RTE_ETH_FILTER_ADD,
+				&filter);
+
+	else if (!strcmp(res->ops, "del"))
+		ret = rte_eth_dev_filter_ctrl(res->port_id,
+				RTE_ETH_FILTER_FLEXIBLE,
+				RTE_ETH_FILTER_DELETE,
+				&filter);
+	else if (!strcmp(res->ops, "get"))
+		get_flex_filter(res->port_id, &filter);
 
 	if (ret < 0)
 		printf("flex filter setting error: (%s)\n", strerror(-ret));
@@ -7896,21 +7896,25 @@  cmdline_parse_token_string_t cmd_flex_filter_queue =
 cmdline_parse_token_num_t cmd_flex_filter_queue_id =
 	TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
 				queue_id, UINT16);
-cmdline_parse_token_string_t cmd_flex_filter_index =
+cmdline_parse_token_string_t cmd_flex_filter_add =
 	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
-				index, "index");
-cmdline_parse_token_num_t cmd_flex_filter_index_value =
-	TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
-				index_value, UINT16);
-cmdline_parse_token_string_t cmd_flex_filter_add_filter =
+				ops, "add");
+cmdline_parse_token_string_t cmd_flex_filter_del =
+	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+				ops, "del");
+cmdline_parse_token_string_t cmd_flex_filter_get =
 	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
-				filter, "add_flex_filter");
+				ops, "get");
+cmdline_parse_token_string_t cmd_flex_filter_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+				filter, "flex_filter");
 cmdline_parse_inst_t cmd_add_flex_filter = {
 	.f = cmd_flex_filter_parsed,
 	.data = NULL,
 	.help_str = "add a flex filter",
 	.tokens = {
-		(void *)&cmd_flex_filter_add_filter,
+		(void *)&cmd_flex_filter_filter,
+		(void *)&cmd_flex_filter_add,
 		(void *)&cmd_flex_filter_port_id,
 		(void *)&cmd_flex_filter_len,
 		(void *)&cmd_flex_filter_len_value,
@@ -7922,40 +7926,44 @@  cmdline_parse_inst_t cmd_add_flex_filter = {
 		(void *)&cmd_flex_filter_priority_value,
 		(void *)&cmd_flex_filter_queue,
 		(void *)&cmd_flex_filter_queue_id,
-		(void *)&cmd_flex_filter_index,
-		(void *)&cmd_flex_filter_index_value,
 		NULL,
 	},
 };
-
-cmdline_parse_token_string_t cmd_flex_filter_remove_filter =
-	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
-				filter, "remove_flex_filter");
 cmdline_parse_inst_t cmd_remove_flex_filter = {
 	.f = cmd_flex_filter_parsed,
 	.data = NULL,
 	.help_str = "remove a flex filter",
 	.tokens = {
-		(void *)&cmd_flex_filter_remove_filter,
+		(void *)&cmd_flex_filter_filter,
+		(void *)&cmd_flex_filter_del,
 		(void *)&cmd_flex_filter_port_id,
-		(void *)&cmd_flex_filter_index,
-		(void *)&cmd_flex_filter_index_value,
+		(void *)&cmd_flex_filter_len,
+		(void *)&cmd_flex_filter_len_value,
+		(void *)&cmd_flex_filter_bytes,
+		(void *)&cmd_flex_filter_bytes_value,
+		(void *)&cmd_flex_filter_mask,
+		(void *)&cmd_flex_filter_mask_value,
+		(void *)&cmd_flex_filter_priority,
+		(void *)&cmd_flex_filter_priority_value,
 		NULL,
 	},
 };
-
-cmdline_parse_token_string_t cmd_flex_filter_get_filter =
-	TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
-				filter, "get_flex_filter");
 cmdline_parse_inst_t cmd_get_flex_filter = {
 	.f = cmd_flex_filter_parsed,
 	.data = NULL,
 	.help_str = "get a flex filter",
 	.tokens = {
-		(void *)&cmd_flex_filter_get_filter,
+		(void *)&cmd_flex_filter_filter,
+		(void *)&cmd_flex_filter_get,
 		(void *)&cmd_flex_filter_port_id,
-		(void *)&cmd_flex_filter_index,
-		(void *)&cmd_flex_filter_index_value,
+		(void *)&cmd_flex_filter_len,
+		(void *)&cmd_flex_filter_len_value,
+		(void *)&cmd_flex_filter_bytes,
+		(void *)&cmd_flex_filter_bytes_value,
+		(void *)&cmd_flex_filter_mask,
+		(void *)&cmd_flex_filter_mask_value,
+		(void *)&cmd_flex_filter_priority,
+		(void *)&cmd_flex_filter_priority_value,
 		NULL,
 	},
 };
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index c40f819..8a44e4a 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -2252,36 +2252,43 @@  get_5tuple_filter(uint8_t port_id, uint16_t index)
 			filter.priority, filter.tcp_flags, rx_queue);
 	}
 }
-void
-get_flex_filter(uint8_t port_id, uint16_t index)
 
+void
+get_flex_filter(uint8_t port_id, struct rte_eth_flex_filter *filter)
 {
-	struct rte_flex_filter filter;
+	struct rte_eth_flex_filter flex_filter;
 	int ret = 0;
-	uint16_t rx_queue;
 	int i, j;
 
-	memset(&filter, 0, sizeof(filter));
-	ret = rte_eth_dev_get_flex_filter(port_id, index,
-				&filter, &rx_queue);
+	memset(&flex_filter, 0, sizeof(flex_filter));
+	flex_filter.len = filter->len;
+	memcpy(flex_filter.bytes, filter->bytes, 128);
+	memcpy(flex_filter.mask, filter->mask, 16);
+	flex_filter.priority = filter->priority;
+	ret = rte_eth_dev_filter_ctrl(port_id,
+					RTE_ETH_FILTER_FLEXIBLE,
+					RTE_ETH_FILTER_GET,
+					&flex_filter);
 	if (ret < 0) {
 		if (ret == (-ENOENT))
-			printf("filter[%d] is not enabled\n", index);
+			printf("filter does not exist\n");
 		else
 			printf("get flex filter fails(%s)\n", strerror(-ret));
 		return;
 	} else {
-		printf("filter[%d]: ", index);
-		printf("\n    length: %d", filter.len);
-		printf("\n    dword[]: 0x");
-		for (i = 0; i < 32; i++)
-			printf("%08x ", (unsigned)rte_be_to_cpu_32(filter.dwords[i]));
+		printf("filter: ");
+		printf("\n    length: %d", flex_filter.len);
+		printf("\n    byte[]: 0x");
+		for (i = 0; i < 8; i++)
+			printf("%02x ",
+				(unsigned)flex_filter.bytes[i]);
 		printf("\n    mask[]: 0b");
 		for (i = 0; i < 16; i++) {
 			for (j = 0; j < 8; j++)
-				printf("%c", (filter.mask[i] & (1 << j)) ? '1' : '0');
+				printf("%c", (flex_filter.mask[i] & (1 << j))
+					? '1' : '0');
 		}
 		printf("\n    priority: %d    queue: %d\n",
-			filter.priority, rx_queue);
+			flex_filter.priority, flex_filter.queue);
 	}
 }
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 8f5e6c7..3f9697f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -557,7 +557,7 @@  void get_syn_filter(uint8_t port_id);
 void get_ethertype_filter(uint8_t port_id, uint16_t index);
 void get_2tuple_filter(uint8_t port_id, uint16_t index);
 void get_5tuple_filter(uint8_t port_id, uint16_t index);
-void get_flex_filter(uint8_t port_id, uint16_t index);
+void get_flex_filter(uint8_t port_id, struct rte_eth_flex_filter *filter);
 int port_id_is_invalid(portid_t port_id);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 218835a..0324fc3 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1595,15 +1595,18 @@  Example:
 
     syn filter: on, priority: high, queue: 3
 
-add_flex_filter
+flex_filter
 ~~~~~~~~~~~~~~~
 
 Add a Flex filter,
 which recognizes any arbitrary pattern within the first 128 bytes of the packet
 and routes packets into one of the receive queues.
+or
+Del(get) a Flex filter,
+which recognizes any arbitrary pattern within the first 128 bytes of the packet
 
-add_flex_filter (port_id) len (len_value) bytes (bytes_string) mask (mask_value)
-priority (prio_value) queue (queue_id) index (idx)
+flex_filter (add|del|get) (port_id) len (len_value) bytes (bytes_string)
+mask (mask_value) priority (prio_value) [queue (queue_id)]
 
 The available information parameters are:
 
@@ -1617,49 +1620,18 @@  The available information parameters are:
 
 *   prio_value: the priority of this filter.
 
-*   queue_id: The receive queue associated with this Flex filter.
-
-*   index: the index of this Flex filter
+*   queue_id: The receive queue associated with this Flex filter.(used when add
+while del|get not)
 
 Example:
 
 .. code-block:: console
 
-   testpmd> add_flex_filter 0 len 16 bytes 0x00000000000000000000000008060000 mask 000C priority 3 queue 3 index 0
-
-Assign a packet whose 13th and 14th bytes are 0x0806 to queue 3.
-
-remove_flex_filter
-~~~~~~~~~~~~~~~~~~
-
-Remove a Flex filter
+   testpmd> flex_filter add 0 len 16 bytes 0x00000000000000000000000008060000
+        mask 000C priority 3 queue 3
 
-remove_flex_filter (port_id) index (idx)
+   testpmd> flex_filter del 0 len 16 bytes 0x00000000000000000000000008060000
+        mask 000C priority 3
 
-get_flex_filter
-~~~~~~~~~~~~~~~
-
-Get and display a Flex filter
-
-get_flex_filter (port_id) index (idx)
-
-Example:
-
-.. code-block:: console
-
-    testpmd> get_flex_filter 0 index 0
-
-    filter[0]:
-
-        length: 16
-
-        dword[]: 0x00000000 00000000 00000000 08060000 00000000 00000000 00000000
-    00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-    00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-    00000000 00000000 00000000 00000000 00000000 00000000 00000000
-
-        mask[]:
-    0b0000000000001100000000000000000000000000000000000000000000000000000000
-    0000000000000000000000000000000000000000000000000000000000
-
-        priority: 3   queue: 3
+   testpmd> flex_filter get 0 len 16 bytes 0x00000000000000000000000008060000
+        mask 000C priority 3
diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 5d9c387..03c6b66 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -55,6 +55,7 @@  enum rte_filter_type {
 	RTE_ETH_FILTER_ETHERTYPE,
 	RTE_ETH_FILTER_TUNNEL,
 	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_FLEXIBLE,
 	RTE_ETH_FILTER_MAX
 };
 
@@ -116,6 +117,25 @@  struct rte_eth_ethertype_filter {
 	uint16_t queue;               /**< Queue assigned to when match*/
 };
 
+#define RTE_FLEX_FILTER_MAXLEN	128	/**< bytes to use in flex filter. */
+#define RTE_FLEX_FILTER_MASK_SIZE	\
+	(RTE_ALIGN(RTE_FLEX_FILTER_MAXLEN, sizeof(char)) / sizeof(char))
+					/**< mask bytes in flex filter. */
+
+/**
+ *  A structure used to define the flex filter entry
+ *  to support RTE_ETH_FILTER_FLEXIBLE with RTE_ETH_FILTER_ADD,
+ *  RTE_ETH_FILTER_DELETE and RTE_ETH_FILTER_GET operations.
+ */
+struct rte_eth_flex_filter {
+	uint16_t len;
+	uint8_t bytes[RTE_FLEX_FILTER_MAXLEN];  /**< flex bytes in big endian.*/
+	uint8_t mask[RTE_FLEX_FILTER_MASK_SIZE];    /**< if mask bit is 1b, do
+					not compare corresponding byte. */
+	uint8_t priority;
+	uint16_t queue;       /**< Queue assigned to when match. */
+};
+
 /**
  * Tunneled type.
  */
diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h
index d155e77..c054aaf 100644
--- a/lib/librte_pmd_e1000/e1000_ethdev.h
+++ b/lib/librte_pmd_e1000/e1000_ethdev.h
@@ -131,6 +131,24 @@  struct e1000_vf_info {
 	uint16_t tx_rate;
 };
 
+TAILQ_HEAD(e1000_flex_filter_list, e1000_flex_filter);
+
+struct e1000_flex_filter_info {
+	uint16_t len;
+	uint32_t dwords[32];  /**< flex bytes in big endian. */
+	uint8_t mask[16];     /**< if mask bit is 1b, do not compare
+				   corresponding byte in dwords. */
+	uint8_t priority;
+};
+
+/* Flex filter structure */
+struct e1000_flex_filter {
+	TAILQ_ENTRY(e1000_flex_filter) entries;
+	uint16_t index; /* index of flex filter */
+	struct e1000_flex_filter_info filter_info;
+	uint16_t queue; /* rx queue assigned to */
+};
+
 /*
  * Structure to store filters' info.
  */
@@ -138,6 +156,8 @@  struct e1000_filter_info {
 	uint8_t ethertype_mask; /* Bit mask for every used ethertype filter */
 	/* store used ethertype filters*/
 	uint16_t ethertype_filters[E1000_MAX_ETQF_FILTERS];
+	uint8_t flex_mask;	/* Bit mask for every used flex filter */
+	struct e1000_flex_filter_list flex_list;
 };
 
 /*
diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c
index 2a268b8..eaa8689 100644
--- a/lib/librte_pmd_e1000/igb_ethdev.c
+++ b/lib/librte_pmd_e1000/igb_ethdev.c
@@ -162,14 +162,14 @@  static int eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev,
 static int eth_igb_get_2tuple_filter(struct rte_eth_dev *dev,
 			uint16_t index,
 			struct rte_2tuple_filter *filter, uint16_t *rx_queue);
-static int eth_igb_add_flex_filter(struct rte_eth_dev *dev,
-			uint16_t index,
-			struct rte_flex_filter *filter, uint16_t rx_queue);
-static int eth_igb_remove_flex_filter(struct rte_eth_dev *dev,
-			uint16_t index);
-static int eth_igb_get_flex_filter(struct rte_eth_dev *dev,
-			uint16_t index,
-			struct rte_flex_filter *filter, uint16_t *rx_queue);
+static int eth_igb_flex_filter_set(struct rte_eth_dev *dev,
+			struct rte_eth_flex_filter *filter,
+			bool add);
+static int eth_igb_flex_filter_get(struct rte_eth_dev *dev,
+			struct rte_eth_flex_filter *filter);
+static int eth_igb_flex_filter_handle(struct rte_eth_dev *dev,
+			enum rte_filter_op filter_op,
+			void *arg);
 static int eth_igb_add_5tuple_filter(struct rte_eth_dev *dev,
 			uint16_t index,
 			struct rte_5tuple_filter *filter, uint16_t rx_queue);
@@ -271,9 +271,6 @@  static struct eth_dev_ops eth_igb_ops = {
 	.add_2tuple_filter       = eth_igb_add_2tuple_filter,
 	.remove_2tuple_filter    = eth_igb_remove_2tuple_filter,
 	.get_2tuple_filter       = eth_igb_get_2tuple_filter,
-	.add_flex_filter         = eth_igb_add_flex_filter,
-	.remove_flex_filter      = eth_igb_remove_flex_filter,
-	.get_flex_filter         = eth_igb_get_flex_filter,
 	.add_5tuple_filter       = eth_igb_add_5tuple_filter,
 	.remove_5tuple_filter    = eth_igb_remove_5tuple_filter,
 	.get_5tuple_filter       = eth_igb_get_5tuple_filter,
@@ -470,6 +467,8 @@  eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
 		E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
 	struct e1000_vfta * shadow_vfta =
 			E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private);
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private);
 	uint32_t ctrl_ext;
 
 	pci_dev = eth_dev->pci_dev;
@@ -601,6 +600,9 @@  eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
 	/* enable support intr */
 	igb_intr_enable(eth_dev);
 
+	TAILQ_INIT(&filter_info->flex_list);
+	filter_info->flex_mask = 0;
+
 	return 0;
 
 err_late:
@@ -926,7 +928,10 @@  static void
 eth_igb_stop(struct rte_eth_dev *dev)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
 	struct rte_eth_link link;
+	struct e1000_flex_filter *p_flex;
 
 	igb_intr_disable(hw);
 	igb_pf_reset_hw(hw);
@@ -949,6 +954,13 @@  eth_igb_stop(struct rte_eth_dev *dev)
 	/* clear the recorded link status */
 	memset(&link, 0, sizeof(link));
 	rte_igb_dev_atomic_write_link_status(dev, &link);
+
+	/* Remove all flex filters of the device */
+	while ((p_flex = TAILQ_FIRST(&filter_info->flex_list))) {
+		TAILQ_REMOVE(&filter_info->flex_list, p_flex, entries);
+		rte_free(p_flex);
+	}
+	filter_info->flex_mask = 0;
 }
 
 static void
@@ -2652,161 +2664,229 @@  eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index,
 	return -ENOENT;
 }
 
-/*
- * add a flex filter
- *
- * @param
- * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates.
- * filter: ponter to the filter that will be added.
- * rx_queue: the queue id the filter assigned to.
- *
- * @return
- *    - On success, zero.
- *     - On failure, a negative value.
+/* add/del/get a flex filter
  */
+static inline struct e1000_flex_filter *
+eth_igb_flex_filter_lookup(struct e1000_flex_filter_list *filter_list,
+			struct e1000_flex_filter_info *key)
+{
+	struct e1000_flex_filter *it;
+
+	TAILQ_FOREACH(it, filter_list, entries) {
+		if (memcmp(key, &it->filter_info,
+			sizeof(struct e1000_flex_filter_info)) == 0)
+			return it;
+	}
+
+	return NULL;
+}
+
 static int
-eth_igb_add_flex_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_flex_filter *filter, uint16_t rx_queue)
+eth_igb_flex_filter_set(struct rte_eth_dev *dev,
+			struct rte_eth_flex_filter *filter,
+			bool add)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+	struct e1000_flex_filter *flex_filter, *it;
 	uint32_t wufc, en_bits = 0;
 	uint32_t queueing = 0;
 	uint32_t reg_off = 0;
 	uint8_t i, j = 0;
 
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
-
-	if (index >= E1000_MAX_FLEXIBLE_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+	flex_filter = rte_zmalloc("e1000_flex_filter",
+			sizeof(struct e1000_flex_filter), 0);
+	if (flex_filter == NULL)
+		return -ENOMEM;
 
-	if (filter->len == 0 || filter->len > E1000_MAX_FLEX_FILTER_LEN ||
-		filter->len % 8 != 0 ||
-		filter->priority > E1000_MAX_FLEX_FILTER_PRI)
-		return -EINVAL;
+	flex_filter->filter_info.len = filter->len;
+	flex_filter->filter_info.priority = filter->priority;
+	memcpy(flex_filter->filter_info.dwords, filter->bytes, filter->len);
+	memcpy(flex_filter->filter_info.mask, filter->mask,
+			RTE_ALIGN(filter->len, sizeof(char)) / sizeof(char));
 
 	wufc = E1000_READ_REG(hw, E1000_WUFC);
-	en_bits = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index);
-	if ((wufc & en_bits) == en_bits)
-		return -EINVAL;  /* the filter is in use. */
+	if (flex_filter->index < E1000_MAX_FHFT)
+		reg_off = E1000_FHFT(flex_filter->index);
+	else
+		reg_off = E1000_FHFT_EXT(flex_filter->index - E1000_MAX_FHFT);
 
-	E1000_WRITE_REG(hw, E1000_WUFC,
-		wufc | E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index));
+	if (add) {
+		if (filter->len == 0 || filter->len > E1000_MAX_FLEX_FILTER_LEN
+			|| filter->len % 8 != 0 ||
+			filter->priority > E1000_MAX_FLEX_FILTER_PRI)
+			return -EINVAL;
+
+		if (eth_igb_flex_filter_lookup(&filter_info->flex_list,
+				&flex_filter->filter_info) != NULL) {
+			PMD_DRV_LOG(ERR, "filter exists.");
+			rte_free(flex_filter);
+			return -EEXIST;
+		}
 
-	j = 0;
-	if (index < E1000_MAX_FHFT)
-		reg_off = E1000_FHFT(index);
-	else
-		reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT);
-
-	for (i = 0; i < 16; i++) {
-		E1000_WRITE_REG(hw, reg_off + i*4*4, filter->dwords[j]);
-		E1000_WRITE_REG(hw, reg_off + (i*4+1)*4, filter->dwords[++j]);
-		E1000_WRITE_REG(hw, reg_off + (i*4+2)*4,
-				(uint32_t)filter->mask[i]);
-		++j;
-	}
-	queueing |= filter->len |
-		(rx_queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) |
-		(filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT);
-	E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET, queueing);
-	return 0;
-}
+		flex_filter->queue = filter->queue;
 
-/*
- * remove a flex filter
- *
- * @param
- * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates.
- *
- * @return
- *    - On success, zero.
- *    - On failure, a negative value.
- */
-static int
-eth_igb_remove_flex_filter(struct rte_eth_dev *dev,
-				uint16_t index)
-{
-	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t wufc, reg_off = 0;
-	uint8_t i;
+		/*
+		 * look for an unused flex filter index
+		 * and insert the filter into the list.
+		 */
+		for (i = 0; i < E1000_MAX_FLEXIBLE_FILTERS; i++) {
+			if (!(filter_info->flex_mask & (1 << i))) {
+				filter_info->flex_mask |= 1 << i;
+				flex_filter->index = i;
+				TAILQ_INSERT_TAIL(&filter_info->flex_list,
+					flex_filter,
+					entries);
+				break;
+			}
+		}
+		if (i >= E1000_MAX_FLEXIBLE_FILTERS) {
+			PMD_DRV_LOG(ERR, "flex filters are full.");
+			rte_free(flex_filter);
+			return -ENOSYS;
+		}
 
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
+		en_bits = E1000_WUFC_FLEX_HQ |
+				(E1000_WUFC_FLX0 << flex_filter->index);
+		if ((wufc & en_bits) == en_bits)
+			return -EINVAL;  /* the filter is in use. */
 
-	if (index >= E1000_MAX_FLEXIBLE_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+		E1000_WRITE_REG(hw, E1000_WUFC, wufc | E1000_WUFC_FLEX_HQ |
+				(E1000_WUFC_FLX0 << flex_filter->index));
 
-	wufc = E1000_READ_REG(hw, E1000_WUFC);
-	E1000_WRITE_REG(hw, E1000_WUFC, wufc & (~(E1000_WUFC_FLX0 << index)));
+		j = 0;
 
-	if (index < E1000_MAX_FHFT)
-		reg_off = E1000_FHFT(index);
-	else
-		reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT);
 
-	for (i = 0; i < 64; i++)
-		E1000_WRITE_REG(hw, reg_off + i*4, 0);
+		for (i = 0; i < 16; i++) {
+			E1000_WRITE_REG(hw, reg_off + i*4*4,
+					flex_filter->filter_info.dwords[j]);
+			E1000_WRITE_REG(hw, reg_off + (i*4+1)*4,
+					flex_filter->filter_info.dwords[++j]);
+			E1000_WRITE_REG(hw, reg_off + (i*4+2)*4,
+					(uint32_t)filter->mask[i]);
+			++j;
+		}
+		queueing |= filter->len |
+			(filter->queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) |
+			(filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT);
+		E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET,
+				queueing);
+	} else {
+		it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
+				&flex_filter->filter_info);
+		if (it == NULL) {
+			PMD_DRV_LOG(ERR, "filter doesn't exist.");
+			rte_free(flex_filter);
+			return -ENOENT;
+		}
+
+		E1000_WRITE_REG(hw, E1000_WUFC, wufc &
+			(~(E1000_WUFC_FLX0 << it->index)));
+
+		for (i = 0; i < 64; i++)
+			E1000_WRITE_REG(hw, reg_off + i*4, 0);
+
+		filter_info->flex_mask &= ~(1 << it->index);
+		TAILQ_REMOVE(&filter_info->flex_list, it, entries);
+		rte_free(it);
+		rte_free(flex_filter);
+	}
+
 	return 0;
 }
 
-/*
- * get a flex filter
- *
- * @param
- * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates.
- * filter: ponter to the filter that returns.
- * *rx_queue: the pointer of the queue id the filter assigned to.
- *
- * @return
- *    - On success, zero.
- *    - On failure, a negative value.
- */
 static int
-eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_flex_filter *filter, uint16_t *rx_queue)
+eth_igb_flex_filter_get(struct rte_eth_dev *dev,
+			struct rte_eth_flex_filter *filter)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+	struct e1000_flex_filter flex_filter, *it;
 	uint32_t wufc, queueing, wufc_en = 0;
-	uint8_t i, j;
-
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
 
-	if (index >= E1000_MAX_FLEXIBLE_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+	memset(&flex_filter, 0, sizeof(struct e1000_flex_filter));
+	flex_filter.filter_info.len = filter->len;
+	flex_filter.filter_info.priority = filter->priority;
+	memcpy(flex_filter.filter_info.dwords, filter->bytes, filter->len);
+	memcpy(flex_filter.filter_info.mask, filter->mask,
+			RTE_ALIGN(filter->len, sizeof(char)) / sizeof(char));
+
+	it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
+			&flex_filter.filter_info);
+	if (it == NULL) {
+		PMD_DRV_LOG(ERR, "filter doesn't exist.");
+		return -ENOENT;
+	}
 
 	wufc = E1000_READ_REG(hw, E1000_WUFC);
-	wufc_en = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index);
+	wufc_en = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << it->index);
 
 	if ((wufc & wufc_en) == wufc_en) {
 		uint32_t reg_off = 0;
-		j = 0;
-		if (index < E1000_MAX_FHFT)
-			reg_off = E1000_FHFT(index);
+		if (it->index < E1000_MAX_FHFT)
+			reg_off = E1000_FHFT(it->index);
 		else
-			reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT);
-
-		for (i = 0; i < 16; i++, j = i * 2) {
-			filter->dwords[j] =
-				E1000_READ_REG(hw, reg_off + i*4*4);
-			filter->dwords[j+1] =
-				E1000_READ_REG(hw, reg_off + (i*4+1)*4);
-			filter->mask[i] =
-				E1000_READ_REG(hw, reg_off + (i*4+2)*4);
-		}
+			reg_off = E1000_FHFT_EXT(it->index - E1000_MAX_FHFT);
+
 		queueing = E1000_READ_REG(hw,
 				reg_off + E1000_FHFT_QUEUEING_OFFSET);
-		filter->len = queueing & E1000_FHFT_QUEUEING_LEN;
-		filter->priority = (queueing & E1000_FHFT_QUEUEING_PRIO) >>
-			E1000_FHFT_QUEUEING_PRIO_SHIFT;
-		*rx_queue = (queueing & E1000_FHFT_QUEUEING_QUEUE) >>
+		filter->queue = (queueing & E1000_FHFT_QUEUEING_QUEUE) >>
 			E1000_FHFT_QUEUEING_QUEUE_SHIFT;
 		return 0;
 	}
 	return -ENOENT;
 }
 
+static int
+eth_igb_flex_filter_handle(struct rte_eth_dev *dev,
+			enum rte_filter_op filter_op,
+			void *arg)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	MAC_TYPE_FILTER_SUP(hw->mac.type);
+
+	if (filter_op == RTE_ETH_FILTER_NOP)
+		return ret;
+
+	if (arg == NULL) {
+		PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u",
+			    filter_op);
+		return -EINVAL;
+	}
+
+	if (((struct rte_eth_flex_filter *)arg)->len == 0) {
+		PMD_DRV_LOG(ERR, "filter length shouldn't be 0");
+		return -EINVAL;
+	}
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_ADD:
+		ret = eth_igb_flex_filter_set(dev,
+				(struct rte_eth_flex_filter *)arg,
+				TRUE);
+		break;
+	case RTE_ETH_FILTER_DELETE:
+		ret = eth_igb_flex_filter_set(dev,
+				(struct rte_eth_flex_filter *)arg,
+				FALSE);
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = eth_igb_flex_filter_get(dev,
+				(struct rte_eth_flex_filter *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unsupported operation %u\n", filter_op);
+		ret = -ENOSYS;
+		break;
+	}
+
+	return ret;
+}
+
 /*
  * add a 5tuple filter
  *
@@ -3237,6 +3317,9 @@  eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 	case RTE_ETH_FILTER_ETHERTYPE:
 		ret = igb_ethertype_filter_handle(dev, filter_op, arg);
 		break;
+	case RTE_ETH_FILTER_FLEXIBLE:
+		ret = eth_igb_flex_filter_handle(dev, filter_op, arg);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 							filter_type);