diff mbox

[dpdk-dev,v3,3/6] e1000: ntuple filter functions replace old ones for 2tuple and 5tuple filter

Message ID 1423543713-21624-4-git-send-email-jingjing.wu@intel.com (mailing list archive)
State Accepted, archived
Headers show

Commit Message

Wu, Jingjing Feb. 10, 2015, 4:48 a.m. UTC
This patch defines new functions dealing with ntuple filters which is
corresponding to 2tuple filter for 82580 and i350 in HW, and to 5tuple
filter for 82576 in HW.
It removes old functions which deal with 2tuple and 5tuple filters in igb driver.
Ntuple filter is dealt with through entrance eth_igb_filter_ctrl.

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_e1000/e1000_ethdev.h |  69 ++-
 lib/librte_pmd_e1000/igb_ethdev.c   | 869 ++++++++++++++++++++++++------------
 2 files changed, 647 insertions(+), 291 deletions(-)
diff mbox

Patch

diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h
index d155e77..571a70d 100644
--- a/lib/librte_pmd_e1000/e1000_ethdev.h
+++ b/lib/librte_pmd_e1000/e1000_ethdev.h
@@ -67,14 +67,6 @@ 
 
 #define E1000_IMIR_DSTPORT             0x0000FFFF
 #define E1000_IMIR_PRIORITY            0xE0000000
-#define E1000_IMIR_EXT_SIZE_BP         0x00001000
-#define E1000_IMIR_EXT_CTRL_UGR        0x00002000
-#define E1000_IMIR_EXT_CTRL_ACK        0x00004000
-#define E1000_IMIR_EXT_CTRL_PSH        0x00008000
-#define E1000_IMIR_EXT_CTRL_RST        0x00010000
-#define E1000_IMIR_EXT_CTRL_SYN        0x00020000
-#define E1000_IMIR_EXT_CTRL_FIN        0x00040000
-#define E1000_IMIR_EXT_CTRL_BP         0x00080000
 #define E1000_MAX_TTQF_FILTERS         8
 #define E1000_2TUPLE_MAX_PRI           7
 
@@ -96,11 +88,6 @@ 
 #define E1000_MAX_FTQF_FILTERS           8
 #define E1000_FTQF_PROTOCOL_MASK         0x000000FF
 #define E1000_FTQF_5TUPLE_MASK_SHIFT     28
-#define E1000_FTQF_PROTOCOL_COMP_MASK    0x10000000
-#define E1000_FTQF_SOURCE_ADDR_MASK      0x20000000
-#define E1000_FTQF_DEST_ADDR_MASK        0x40000000
-#define E1000_FTQF_SOURCE_PORT_MASK      0x80000000
-#define E1000_FTQF_VF_MASK_EN            0x00008000
 #define E1000_FTQF_QUEUE_MASK            0x03ff0000
 #define E1000_FTQF_QUEUE_SHIFT           16
 #define E1000_FTQF_QUEUE_ENABLE          0x00000100
@@ -131,6 +118,56 @@  struct e1000_vf_info {
 	uint16_t tx_rate;
 };
 
+TAILQ_HEAD(e1000_5tuple_filter_list, e1000_5tuple_filter);
+TAILQ_HEAD(e1000_2tuple_filter_list, e1000_2tuple_filter);
+
+struct e1000_5tuple_filter_info {
+	uint32_t dst_ip;
+	uint32_t src_ip;
+	uint16_t dst_port;
+	uint16_t src_port;
+	uint8_t proto;           /* l4 protocol. */
+	/* the packet matched above 5tuple and contain any set bit will hit this filter. */
+	uint8_t tcp_flags;
+	uint8_t priority;        /* seven levels (001b-111b), 111b is highest,
+				      used when more than one filter matches. */
+	uint8_t dst_ip_mask:1,   /* if mask is 1b, do not compare dst ip. */
+		src_ip_mask:1,   /* if mask is 1b, do not compare src ip. */
+		dst_port_mask:1, /* if mask is 1b, do not compare dst port. */
+		src_port_mask:1, /* if mask is 1b, do not compare src port. */
+		proto_mask:1;    /* if mask is 1b, do not compare protocol. */
+};
+
+struct e1000_2tuple_filter_info {
+	uint16_t dst_port;
+	uint8_t proto;           /* l4 protocol. */
+	/* the packet matched above 2tuple and contain any set bit will hit this filter. */
+	uint8_t tcp_flags;
+	uint8_t priority;        /* seven levels (001b-111b), 111b is highest,
+				      used when more than one filter matches. */
+	uint8_t dst_ip_mask:1,   /* if mask is 1b, do not compare dst ip. */
+		src_ip_mask:1,   /* if mask is 1b, do not compare src ip. */
+		dst_port_mask:1, /* if mask is 1b, do not compare dst port. */
+		src_port_mask:1, /* if mask is 1b, do not compare src port. */
+		proto_mask:1;    /* if mask is 1b, do not compare protocol. */
+};
+
+/* 5tuple filter structure */
+struct e1000_5tuple_filter {
+	TAILQ_ENTRY(e1000_5tuple_filter) entries;
+	uint16_t index;       /* the index of 5tuple filter */
+	struct e1000_5tuple_filter_info filter_info;
+	uint16_t queue;       /* rx queue assigned to */
+};
+
+/* 2tuple filter structure */
+struct e1000_2tuple_filter {
+	TAILQ_ENTRY(e1000_2tuple_filter) entries;
+	uint16_t index;         /* the index of 2tuple filter */
+	struct e1000_2tuple_filter_info filter_info;
+	uint16_t queue;       /* rx queue assigned to */
+};
+
 /*
  * Structure to store filters' info.
  */
@@ -138,6 +175,12 @@  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];
+	/* Bit mask for every used 5tuple filter */
+	uint8_t fivetuple_mask;
+	struct e1000_5tuple_filter_list fivetuple_list;
+	/* Bit mask for every used 2tuple filter */
+	uint8_t twotuple_mask;
+	struct e1000_2tuple_filter_list twotuple_list;
 };
 
 /*
diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c
index 2a268b8..51f47cc 100644
--- a/lib/librte_pmd_e1000/igb_ethdev.c
+++ b/lib/librte_pmd_e1000/igb_ethdev.c
@@ -154,14 +154,10 @@  static int eth_igb_add_syn_filter(struct rte_eth_dev *dev,
 static int eth_igb_remove_syn_filter(struct rte_eth_dev *dev);
 static int eth_igb_get_syn_filter(struct rte_eth_dev *dev,
 			struct rte_syn_filter *filter, uint16_t *rx_queue);
-static int eth_igb_add_2tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index,
-			struct rte_2tuple_filter *filter, uint16_t rx_queue);
-static int eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index);
-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 igb_add_2tuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter);
+static int igb_remove_2tuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter);
 static int eth_igb_add_flex_filter(struct rte_eth_dev *dev,
 			uint16_t index,
 			struct rte_flex_filter *filter, uint16_t rx_queue);
@@ -170,14 +166,18 @@  static int eth_igb_remove_flex_filter(struct rte_eth_dev *dev,
 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_add_5tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index,
-			struct rte_5tuple_filter *filter, uint16_t rx_queue);
-static int eth_igb_remove_5tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index);
-static int eth_igb_get_5tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index,
-			struct rte_5tuple_filter *filter, uint16_t *rx_queue);
+static int igb_add_5tuple_filter_82576(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter);
+static int igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter);
+static int igb_add_del_ntuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *filter,
+			bool add);
+static int igb_get_ntuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *filter);
+static int igb_ntuple_filter_handle(struct rte_eth_dev *dev,
+				enum rte_filter_op filter_op,
+				void *arg);
 static int igb_add_del_ethertype_filter(struct rte_eth_dev *dev,
 			struct rte_eth_ethertype_filter *filter,
 			bool add);
@@ -268,15 +268,9 @@  static struct eth_dev_ops eth_igb_ops = {
 	.add_syn_filter          = eth_igb_add_syn_filter,
 	.remove_syn_filter       = eth_igb_remove_syn_filter,
 	.get_syn_filter          = eth_igb_get_syn_filter,
-	.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,
 	.filter_ctrl             = eth_igb_filter_ctrl,
 };
 
@@ -470,6 +464,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 +597,12 @@  eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
 	/* enable support intr */
 	igb_intr_enable(eth_dev);
 
+	/* initialize ntuple filter list */
+	TAILQ_INIT(&filter_info->twotuple_list);
+	filter_info->twotuple_mask = 0;
+	TAILQ_INIT(&filter_info->fivetuple_list);
+	filter_info->fivetuple_mask = 0;
+
 	return 0;
 
 err_late:
@@ -926,7 +928,11 @@  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_5tuple_filter *p_5tuple, *p_5tuple_next;
+	struct e1000_2tuple_filter *p_2tuple, *p_2tuple_next;
 
 	igb_intr_disable(hw);
 	igb_pf_reset_hw(hw);
@@ -949,6 +955,24 @@  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 ntuple filters of the device */
+	for (p_5tuple = TAILQ_FIRST(&filter_info->fivetuple_list);
+	     p_5tuple != NULL; p_5tuple = p_5tuple_next) {
+		p_5tuple_next = TAILQ_NEXT(p_5tuple, entries);
+		TAILQ_REMOVE(&filter_info->fivetuple_list,
+			     p_5tuple, entries);
+		rte_free(p_5tuple);
+	}
+	filter_info->fivetuple_mask = 0;
+	for (p_2tuple = TAILQ_FIRST(&filter_info->twotuple_list);
+	     p_2tuple != NULL; p_2tuple = p_2tuple_next) {
+		p_2tuple_next = TAILQ_NEXT(p_2tuple, entries);
+		TAILQ_REMOVE(&filter_info->twotuple_list,
+			     p_2tuple, entries);
+		rte_free(p_2tuple);
+	}
+	filter_info->twotuple_mask = 0;
 }
 
 static void
@@ -2491,165 +2515,209 @@  eth_igb_get_syn_filter(struct rte_eth_dev *dev,
 		return -ENOSYS; \
 } while (0)
 
-/*
- * add a 2tuple 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.
- */
-static int
-eth_igb_add_2tuple_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_2tuple_filter *filter, uint16_t rx_queue)
+/* translate elements in struct rte_eth_ntuple_filter to struct e1000_2tuple_filter_info*/
+static inline int
+ntuple_filter_to_2tuple(struct rte_eth_ntuple_filter *filter,
+			struct e1000_2tuple_filter_info *filter_info)
 {
-	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t ttqf, imir = 0;
-	uint32_t imir_ext = 0;
-
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
-
-	if (index >= E1000_MAX_TTQF_FILTERS ||
-		rx_queue >= IGB_MAX_RX_QUEUE_NUM ||
-		filter->priority > E1000_2TUPLE_MAX_PRI)
+	if (filter->queue >= IGB_MAX_RX_QUEUE_NUM)
+		return -EINVAL;
+	if (filter->priority > E1000_2TUPLE_MAX_PRI)
 		return -EINVAL;  /* filter index is out of range. */
-	if  (filter->tcp_flags > TCP_FLAG_ALL)
+	if (filter->tcp_flags > TCP_FLAG_ALL)
 		return -EINVAL;  /* flags is invalid. */
 
-	ttqf = E1000_READ_REG(hw, E1000_TTQF(index));
-	if (ttqf & E1000_TTQF_QUEUE_ENABLE)
-		return -EINVAL;  /* filter index is in use. */
-
-	imir = (uint32_t)(filter->dst_port & E1000_IMIR_DSTPORT);
-	if (filter->dst_port_mask == 1) /* 1b means not compare. */
-		imir |= E1000_IMIR_PORT_BP;
-	else
-		imir &= ~E1000_IMIR_PORT_BP;
+	switch (filter->dst_port_mask) {
+	case UINT16_MAX:
+		filter_info->dst_port_mask = 0;
+		filter_info->dst_port = filter->dst_port;
+		break;
+	case 0:
+		filter_info->dst_port_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid dst_port mask.");
+		return -EINVAL;
+	}
 
-	imir |= filter->priority << E1000_IMIR_PRIORITY_SHIFT;
+	switch (filter->proto_mask) {
+	case UINT8_MAX:
+		filter_info->proto_mask = 0;
+		filter_info->proto = filter->proto;
+		break;
+	case 0:
+		filter_info->proto_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid protocol mask.");
+		return -EINVAL;
+	}
 
-	ttqf = 0;
-	ttqf |= E1000_TTQF_QUEUE_ENABLE;
-	ttqf |= (uint32_t)(rx_queue << E1000_TTQF_QUEUE_SHIFT);
-	ttqf |= (uint32_t)(filter->protocol & E1000_TTQF_PROTOCOL_MASK);
-	if (filter->protocol_mask == 1)
-		ttqf |= E1000_TTQF_MASK_ENABLE;
+	filter_info->priority = (uint8_t)filter->priority;
+	if (filter->flags & RTE_NTUPLE_FLAGS_TCP_FLAG)
+		filter_info->tcp_flags = filter->tcp_flags;
 	else
-		ttqf &= ~E1000_TTQF_MASK_ENABLE;
+		filter_info->tcp_flags = 0;
 
-	imir_ext |= E1000_IMIR_EXT_SIZE_BP;
-	/* tcp flags bits setting. */
-	if (filter->tcp_flags & TCP_FLAG_ALL) {
-		if (filter->tcp_flags & TCP_UGR_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_UGR;
-		if (filter->tcp_flags & TCP_ACK_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_ACK;
-		if (filter->tcp_flags & TCP_PSH_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_PSH;
-		if (filter->tcp_flags & TCP_RST_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_RST;
-		if (filter->tcp_flags & TCP_SYN_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_SYN;
-		if (filter->tcp_flags & TCP_FIN_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_FIN;
-		imir_ext &= ~E1000_IMIR_EXT_CTRL_BP;
-	} else
-		imir_ext |= E1000_IMIR_EXT_CTRL_BP;
-	E1000_WRITE_REG(hw, E1000_IMIR(index), imir);
-	E1000_WRITE_REG(hw, E1000_TTQF(index), ttqf);
-	E1000_WRITE_REG(hw, E1000_IMIREXT(index), imir_ext);
 	return 0;
 }
 
+static inline struct e1000_2tuple_filter *
+igb_2tuple_filter_lookup(struct e1000_2tuple_filter_list *filter_list,
+			struct e1000_2tuple_filter_info *key)
+{
+	struct e1000_2tuple_filter *it;
+
+	TAILQ_FOREACH(it, filter_list, entries) {
+		if (memcmp(key, &it->filter_info,
+			sizeof(struct e1000_2tuple_filter_info)) == 0) {
+			return it;
+		}
+	}
+	return NULL;
+}
+
 /*
- * remove a 2tuple filter
+ * igb_add_2tuple_filter - add a 2tuple filter
  *
  * @param
  * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates.
+ * ntuple_filter: ponter to the filter that will be added.
  *
  * @return
  *    - On success, zero.
  *    - On failure, a negative value.
  */
 static int
-eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev,
-			uint16_t index)
+igb_add_2tuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_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_2tuple_filter *filter;
+	uint32_t ttqf = E1000_TTQF_DISABLE_MASK;
+	uint32_t imir, imir_ext = E1000_IMIREXT_SIZE_BP;
+	int i, ret;
+
+	filter = rte_zmalloc("e1000_2tuple_filter",
+			sizeof(struct e1000_2tuple_filter), 0);
+	if (filter == NULL)
+		return -ENOMEM;
 
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
+	ret = ntuple_filter_to_2tuple(ntuple_filter,
+				      &filter->filter_info);
+	if (ret < 0) {
+		rte_free(filter);
+		return ret;
+	}
+	if (igb_2tuple_filter_lookup(&filter_info->twotuple_list,
+					 &filter->filter_info) != NULL) {
+		PMD_DRV_LOG(ERR, "filter exists.");
+		rte_free(filter);
+		return -EEXIST;
+	}
+	filter->queue = ntuple_filter->queue;
 
-	if (index >= E1000_MAX_TTQF_FILTERS)
-		return -EINVAL;  /* filter index is out of range */
+	/*
+	 * look for an unused 2tuple filter index,
+	 * and insert the filter to list.
+	 */
+	for (i = 0; i < E1000_MAX_TTQF_FILTERS; i++) {
+		if (!(filter_info->twotuple_mask & (1 << i))) {
+			filter_info->twotuple_mask |= 1 << i;
+			filter->index = i;
+			TAILQ_INSERT_TAIL(&filter_info->twotuple_list,
+					  filter,
+					  entries);
+			break;
+		}
+	}
+	if (i >= E1000_MAX_TTQF_FILTERS) {
+		PMD_DRV_LOG(ERR, "2tuple filters are full.");
+		rte_free(filter);
+		return -ENOSYS;
+	}
+
+	imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
+	if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
+		imir |= E1000_IMIR_PORT_BP;
+	else
+		imir &= ~E1000_IMIR_PORT_BP;
 
-	E1000_WRITE_REG(hw, E1000_TTQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIR(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0);
+	imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+
+	ttqf |= E1000_TTQF_QUEUE_ENABLE;
+	ttqf |= (uint32_t)(filter->queue << E1000_TTQF_QUEUE_SHIFT);
+	ttqf |= (uint32_t)(filter->filter_info.proto & E1000_TTQF_PROTOCOL_MASK);
+	if (filter->filter_info.proto_mask == 0)
+		ttqf &= ~E1000_TTQF_MASK_ENABLE;
+
+	/* tcp flags bits setting. */
+	if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
+		if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_URG;
+		if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_ACK;
+		if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_PSH;
+		if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_RST;
+		if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_SYN;
+		if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_FIN;
+	} else
+		imir_ext |= E1000_IMIREXT_CTRL_BP;
+	E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
+	E1000_WRITE_REG(hw, E1000_TTQF(i), ttqf);
+	E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
 	return 0;
 }
 
 /*
- * get a 2tuple filter
+ * igb_remove_2tuple_filter - remove a 2tuple filter
  *
  * @param
  * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates.
- * filter: ponter to the filter that returns.
- * *rx_queue: pointer of the queue id the filter assigned to.
+ * ntuple_filter: ponter to the filter that will be removed.
  *
  * @return
  *    - On success, zero.
  *    - On failure, a negative value.
  */
 static int
-eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_2tuple_filter *filter, uint16_t *rx_queue)
+igb_remove_2tuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t imir, ttqf, imir_ext;
-
-	MAC_TYPE_FILTER_SUP_EXT(hw->mac.type);
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+	struct e1000_2tuple_filter_info filter_2tuple;
+	struct e1000_2tuple_filter *filter;
+	int ret;
 
-	if (index >= E1000_MAX_TTQF_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+	memset(&filter_2tuple, 0, sizeof(struct e1000_2tuple_filter_info));
+	ret = ntuple_filter_to_2tuple(ntuple_filter,
+				      &filter_2tuple);
+	if (ret < 0)
+		return ret;
 
-	ttqf = E1000_READ_REG(hw, E1000_TTQF(index));
-	if (ttqf & E1000_TTQF_QUEUE_ENABLE) {
-		imir = E1000_READ_REG(hw, E1000_IMIR(index));
-		filter->protocol = ttqf & E1000_TTQF_PROTOCOL_MASK;
-		filter->protocol_mask = (ttqf & E1000_TTQF_MASK_ENABLE) ? 1 : 0;
-		*rx_queue = (ttqf & E1000_TTQF_RX_QUEUE_MASK) >>
-				E1000_TTQF_QUEUE_SHIFT;
-		filter->dst_port = (uint16_t)(imir & E1000_IMIR_DSTPORT);
-		filter->dst_port_mask = (imir & E1000_IMIR_PORT_BP) ? 1 : 0;
-		filter->priority = (imir & E1000_IMIR_PRIORITY) >>
-			E1000_IMIR_PRIORITY_SHIFT;
-
-		imir_ext = E1000_READ_REG(hw, E1000_IMIREXT(index));
-		if (!(imir_ext & E1000_IMIR_EXT_CTRL_BP)) {
-			if (imir_ext & E1000_IMIR_EXT_CTRL_UGR)
-				filter->tcp_flags |= TCP_UGR_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_ACK)
-				filter->tcp_flags |= TCP_ACK_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_PSH)
-				filter->tcp_flags |= TCP_PSH_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_RST)
-				filter->tcp_flags |= TCP_RST_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_SYN)
-				filter->tcp_flags |= TCP_SYN_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_FIN)
-				filter->tcp_flags |= TCP_FIN_FLAG;
-		} else
-			filter->tcp_flags = 0;
-		return 0;
+	filter = igb_2tuple_filter_lookup(&filter_info->twotuple_list,
+					 &filter_2tuple);
+	if (filter == NULL) {
+		PMD_DRV_LOG(ERR, "filter doesn't exist.");
+		return -ENOENT;
 	}
-	return -ENOENT;
+
+	filter_info->twotuple_mask &= ~(1 << filter->index);
+	TAILQ_REMOVE(&filter_info->twotuple_list, filter, entries);
+	rte_free(filter);
+
+	E1000_WRITE_REG(hw, E1000_TTQF(filter->index), E1000_TTQF_DISABLE_MASK);
+	E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
+	E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
+	return 0;
 }
 
 /*
@@ -2807,192 +2875,265 @@  eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index,
 	return -ENOENT;
 }
 
-/*
- * add a 5tuple 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.
- */
-static int
-eth_igb_add_5tuple_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_5tuple_filter *filter, uint16_t rx_queue)
+/* translate elements in struct rte_eth_ntuple_filter to struct e1000_5tuple_filter_info*/
+static inline int
+ntuple_filter_to_5tuple_82576(struct rte_eth_ntuple_filter *filter,
+			struct e1000_5tuple_filter_info *filter_info)
 {
-	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t ftqf, spqf = 0;
-	uint32_t imir = 0;
-	uint32_t imir_ext = 0;
+	if (filter->queue >= IGB_MAX_RX_QUEUE_NUM_82576)
+		return -EINVAL;
+	if (filter->priority > E1000_2TUPLE_MAX_PRI)
+		return -EINVAL;  /* filter index is out of range. */
+	if (filter->tcp_flags > TCP_FLAG_ALL)
+		return -EINVAL;  /* flags is invalid. */
 
-	if (hw->mac.type != e1000_82576)
-		return -ENOSYS;
+	switch (filter->dst_ip_mask) {
+	case UINT32_MAX:
+		filter_info->dst_ip_mask = 0;
+		filter_info->dst_ip = filter->dst_ip;
+		break;
+	case 0:
+		filter_info->dst_ip_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid dst_ip mask.");
+		return -EINVAL;
+	}
 
-	if (index >= E1000_MAX_FTQF_FILTERS ||
-		rx_queue >= IGB_MAX_RX_QUEUE_NUM_82576)
-		return -EINVAL;  /* filter index is out of range. */
+	switch (filter->src_ip_mask) {
+	case UINT32_MAX:
+		filter_info->src_ip_mask = 0;
+		filter_info->src_ip = filter->src_ip;
+		break;
+	case 0:
+		filter_info->src_ip_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid src_ip mask.");
+		return -EINVAL;
+	}
 
-	ftqf = E1000_READ_REG(hw, E1000_FTQF(index));
-	if (ftqf & E1000_FTQF_QUEUE_ENABLE)
-		return -EINVAL;  /* filter index is in use. */
-
-	ftqf = 0;
-	ftqf |= filter->protocol & E1000_FTQF_PROTOCOL_MASK;
-	if (filter->src_ip_mask == 1) /* 1b means not compare. */
-		ftqf |= E1000_FTQF_SOURCE_ADDR_MASK;
-	if (filter->dst_ip_mask == 1)
-		ftqf |= E1000_FTQF_DEST_ADDR_MASK;
-	if (filter->src_port_mask == 1)
-		ftqf |= E1000_FTQF_SOURCE_PORT_MASK;
-	if (filter->protocol_mask == 1)
-		ftqf |= E1000_FTQF_PROTOCOL_COMP_MASK;
-	ftqf |= (rx_queue << E1000_FTQF_QUEUE_SHIFT) & E1000_FTQF_QUEUE_MASK;
-	ftqf |= E1000_FTQF_VF_MASK_EN;
-	ftqf |= E1000_FTQF_QUEUE_ENABLE;
-	E1000_WRITE_REG(hw, E1000_FTQF(index), ftqf);
-	E1000_WRITE_REG(hw, E1000_DAQF(index), filter->dst_ip);
-	E1000_WRITE_REG(hw, E1000_SAQF(index), filter->src_ip);
+	switch (filter->dst_port_mask) {
+	case UINT16_MAX:
+		filter_info->dst_port_mask = 0;
+		filter_info->dst_port = filter->dst_port;
+		break;
+	case 0:
+		filter_info->dst_port_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid dst_port mask.");
+		return -EINVAL;
+	}
+
+	switch (filter->src_port_mask) {
+	case UINT16_MAX:
+		filter_info->src_port_mask = 0;
+		filter_info->src_port = filter->src_port;
+		break;
+	case 0:
+		filter_info->src_port_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid src_port mask.");
+		return -EINVAL;
+	}
 
-	spqf |= filter->src_port & E1000_SPQF_SRCPORT;
-	E1000_WRITE_REG(hw, E1000_SPQF(index), spqf);
+	switch (filter->proto_mask) {
+	case UINT8_MAX:
+		filter_info->proto_mask = 0;
+		filter_info->proto = filter->proto;
+		break;
+	case 0:
+		filter_info->proto_mask = 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "invalid protocol mask.");
+		return -EINVAL;
+	}
 
-	imir |= (uint32_t)(filter->dst_port & E1000_IMIR_DSTPORT);
-	if (filter->dst_port_mask == 1) /* 1b means not compare. */
-		imir |= E1000_IMIR_PORT_BP;
+	filter_info->priority = (uint8_t)filter->priority;
+	if (filter->flags & RTE_NTUPLE_FLAGS_TCP_FLAG)
+		filter_info->tcp_flags = filter->tcp_flags;
 	else
-		imir &= ~E1000_IMIR_PORT_BP;
-	imir |= filter->priority << E1000_IMIR_PRIORITY_SHIFT;
+		filter_info->tcp_flags = 0;
 
-	imir_ext |= E1000_IMIR_EXT_SIZE_BP;
-	/* tcp flags bits setting. */
-	if (filter->tcp_flags & TCP_FLAG_ALL) {
-		if (filter->tcp_flags & TCP_UGR_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_UGR;
-		if (filter->tcp_flags & TCP_ACK_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_ACK;
-		if (filter->tcp_flags & TCP_PSH_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_PSH;
-		if (filter->tcp_flags & TCP_RST_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_RST;
-		if (filter->tcp_flags & TCP_SYN_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_SYN;
-		if (filter->tcp_flags & TCP_FIN_FLAG)
-			imir_ext |= E1000_IMIR_EXT_CTRL_FIN;
-	} else
-		imir_ext |= E1000_IMIR_EXT_CTRL_BP;
-	E1000_WRITE_REG(hw, E1000_IMIR(index), imir);
-	E1000_WRITE_REG(hw, E1000_IMIREXT(index), imir_ext);
 	return 0;
 }
 
+static inline struct e1000_5tuple_filter *
+igb_5tuple_filter_lookup_82576(struct e1000_5tuple_filter_list *filter_list,
+			struct e1000_5tuple_filter_info *key)
+{
+	struct e1000_5tuple_filter *it;
+
+	TAILQ_FOREACH(it, filter_list, entries) {
+		if (memcmp(key, &it->filter_info,
+			sizeof(struct e1000_5tuple_filter_info)) == 0) {
+			return it;
+		}
+	}
+	return NULL;
+}
+
 /*
- * remove a 5tuple filter
+ * igb_add_5tuple_filter_82576 - add a 5tuple filter
  *
  * @param
  * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates
+ * ntuple_filter: ponter to the filter that will be added.
  *
  * @return
  *    - On success, zero.
  *    - On failure, a negative value.
  */
 static int
-eth_igb_remove_5tuple_filter(struct rte_eth_dev *dev,
-				uint16_t index)
+igb_add_5tuple_filter_82576(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_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_5tuple_filter *filter;
+	uint32_t ftqf = E1000_FTQF_VF_BP | E1000_FTQF_MASK;
+	uint32_t spqf, imir, imir_ext = E1000_IMIREXT_SIZE_BP;
+	uint8_t i;
+	int ret;
+
+	filter = rte_zmalloc("e1000_5tuple_filter",
+			sizeof(struct e1000_5tuple_filter), 0);
+	if (filter == NULL)
+		return -ENOMEM;
+
+	ret = ntuple_filter_to_5tuple_82576(ntuple_filter,
+					    &filter->filter_info);
+	if (ret < 0) {
+		rte_free(filter);
+		return ret;
+	}
 
-	if (hw->mac.type != e1000_82576)
+	if (igb_5tuple_filter_lookup_82576(&filter_info->fivetuple_list,
+					 &filter->filter_info) != NULL) {
+		PMD_DRV_LOG(ERR, "filter exists.");
+		rte_free(filter);
+		return -EEXIST;
+	}
+	filter->queue = ntuple_filter->queue;
+
+	/*
+	 * look for an unused 5tuple filter index,
+	 * and insert the filter to list.
+	 */
+	for (i = 0; i < E1000_MAX_FTQF_FILTERS; i++) {
+		if (!(filter_info->fivetuple_mask & (1 << i))) {
+			filter_info->fivetuple_mask |= 1 << i;
+			filter->index = i;
+			TAILQ_INSERT_TAIL(&filter_info->fivetuple_list,
+					  filter,
+					  entries);
+			break;
+		}
+	}
+	if (i >= E1000_MAX_FTQF_FILTERS) {
+		PMD_DRV_LOG(ERR, "5tuple filters are full.");
+		rte_free(filter);
 		return -ENOSYS;
+	}
 
-	if (index >= E1000_MAX_FTQF_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+	ftqf |= filter->filter_info.proto & E1000_FTQF_PROTOCOL_MASK;
+	if (filter->filter_info.src_ip_mask == 0) /* 0b means compare. */
+		ftqf &= ~E1000_FTQF_MASK_SOURCE_ADDR_BP;
+	if (filter->filter_info.dst_ip_mask == 0)
+		ftqf &= ~E1000_FTQF_MASK_DEST_ADDR_BP;
+	if (filter->filter_info.src_port_mask == 0)
+		ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
+	if (filter->filter_info.proto_mask == 0)
+		ftqf &= ~E1000_FTQF_MASK_PROTO_BP;
+	ftqf |= (filter->queue << E1000_FTQF_QUEUE_SHIFT) &
+		E1000_FTQF_QUEUE_MASK;
+	ftqf |= E1000_FTQF_QUEUE_ENABLE;
+	E1000_WRITE_REG(hw, E1000_FTQF(i), ftqf);
+	E1000_WRITE_REG(hw, E1000_DAQF(i), filter->filter_info.dst_ip);
+	E1000_WRITE_REG(hw, E1000_SAQF(i), filter->filter_info.src_ip);
+
+	spqf = filter->filter_info.src_port & E1000_SPQF_SRCPORT;
+	E1000_WRITE_REG(hw, E1000_SPQF(i), spqf);
 
-	E1000_WRITE_REG(hw, E1000_FTQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_DAQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_SAQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_SPQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIR(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0);
+	imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
+	if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
+		imir |= E1000_IMIR_PORT_BP;
+	else
+		imir &= ~E1000_IMIR_PORT_BP;
+	imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+
+	/* tcp flags bits setting. */
+	if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
+		if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_URG;
+		if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_ACK;
+		if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_PSH;
+		if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_RST;
+		if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_SYN;
+		if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
+			imir_ext |= E1000_IMIREXT_CTRL_FIN;
+	} else
+		imir_ext |= E1000_IMIREXT_CTRL_BP;
+	E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
+	E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
 	return 0;
 }
 
 /*
- * get a 5tuple filter
+ * igb_remove_5tuple_filter_82576 - remove a 5tuple filter
  *
  * @param
  * dev: Pointer to struct rte_eth_dev.
- * index: the index the filter allocates
- * filter: ponter to the filter that returns
- * *rx_queue: pointer of the queue id the filter assigned to
+ * ntuple_filter: ponter to the filter that will be removed.
  *
  * @return
  *    - On success, zero.
  *    - On failure, a negative value.
  */
 static int
-eth_igb_get_5tuple_filter(struct rte_eth_dev *dev, uint16_t index,
-			struct rte_5tuple_filter *filter, uint16_t *rx_queue)
+igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev,
+				struct rte_eth_ntuple_filter *ntuple_filter)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t spqf, ftqf, imir, imir_ext;
-
-	if (hw->mac.type != e1000_82576)
-		return -ENOSYS;
+	struct e1000_filter_info *filter_info =
+		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+	struct e1000_5tuple_filter_info filter_5tuple;
+	struct e1000_5tuple_filter *filter;
+	int ret;
 
-	if (index >= E1000_MAX_FTQF_FILTERS)
-		return -EINVAL;  /* filter index is out of range. */
+	memset(&filter_5tuple, 0, sizeof(struct e1000_5tuple_filter_info));
+	ret = ntuple_filter_to_5tuple_82576(ntuple_filter,
+					    &filter_5tuple);
+	if (ret < 0)
+		return ret;
 
-	ftqf = E1000_READ_REG(hw, E1000_FTQF(index));
-	if (ftqf & E1000_FTQF_QUEUE_ENABLE) {
-		filter->src_ip_mask =
-			(ftqf & E1000_FTQF_SOURCE_ADDR_MASK) ? 1 : 0;
-		filter->dst_ip_mask =
-			(ftqf & E1000_FTQF_DEST_ADDR_MASK) ? 1 : 0;
-		filter->src_port_mask =
-			(ftqf & E1000_FTQF_SOURCE_PORT_MASK) ? 1 : 0;
-		filter->protocol_mask =
-			(ftqf & E1000_FTQF_PROTOCOL_COMP_MASK) ? 1 : 0;
-		filter->protocol =
-			(uint8_t)ftqf & E1000_FTQF_PROTOCOL_MASK;
-		*rx_queue = (uint16_t)((ftqf & E1000_FTQF_QUEUE_MASK) >>
-				E1000_FTQF_QUEUE_SHIFT);
-
-		spqf = E1000_READ_REG(hw, E1000_SPQF(index));
-		filter->src_port = spqf & E1000_SPQF_SRCPORT;
-
-		filter->dst_ip = E1000_READ_REG(hw, E1000_DAQF(index));
-		filter->src_ip = E1000_READ_REG(hw, E1000_SAQF(index));
-
-		imir = E1000_READ_REG(hw, E1000_IMIR(index));
-		filter->dst_port_mask = (imir & E1000_IMIR_PORT_BP) ? 1 : 0;
-		filter->dst_port = (uint16_t)(imir & E1000_IMIR_DSTPORT);
-		filter->priority = (imir & E1000_IMIR_PRIORITY) >>
-			E1000_IMIR_PRIORITY_SHIFT;
-
-		imir_ext = E1000_READ_REG(hw, E1000_IMIREXT(index));
-		if (!(imir_ext & E1000_IMIR_EXT_CTRL_BP)) {
-			if (imir_ext & E1000_IMIR_EXT_CTRL_UGR)
-				filter->tcp_flags |= TCP_UGR_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_ACK)
-				filter->tcp_flags |= TCP_ACK_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_PSH)
-				filter->tcp_flags |= TCP_PSH_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_RST)
-				filter->tcp_flags |= TCP_RST_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_SYN)
-				filter->tcp_flags |= TCP_SYN_FLAG;
-			if (imir_ext & E1000_IMIR_EXT_CTRL_FIN)
-				filter->tcp_flags |= TCP_FIN_FLAG;
-		} else
-			filter->tcp_flags = 0;
-		return 0;
+	filter = igb_5tuple_filter_lookup_82576(&filter_info->fivetuple_list,
+					 &filter_5tuple);
+	if (filter == NULL) {
+		PMD_DRV_LOG(ERR, "filter doesn't exist.");
+		return -ENOENT;
 	}
-	return -ENOENT;
+
+	filter_info->fivetuple_mask &= ~(1 << filter->index);
+	TAILQ_REMOVE(&filter_info->fivetuple_list, filter, entries);
+	rte_free(filter);
+
+	E1000_WRITE_REG(hw, E1000_FTQF(filter->index),
+			E1000_FTQF_VF_BP | E1000_FTQF_MASK);
+	E1000_WRITE_REG(hw, E1000_DAQF(filter->index), 0);
+	E1000_WRITE_REG(hw, E1000_SAQF(filter->index), 0);
+	E1000_WRITE_REG(hw, E1000_SPQF(filter->index), 0);
+	E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
+	E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
+	return 0;
 }
 
 static int
@@ -3045,6 +3186,175 @@  eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	return 0;
 }
 
+/*
+ * igb_add_del_ntuple_filter - add or delete a ntuple filter
+ *
+ * @param
+ * dev: Pointer to struct rte_eth_dev.
+ * ntuple_filter: Pointer to struct rte_eth_ntuple_filter
+ * add: if true, add filter, if false, remove filter
+ *
+ * @return
+ *    - On success, zero.
+ *    - On failure, a negative value.
+ */
+static int
+igb_add_del_ntuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_filter,
+			bool add)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
+
+	switch (ntuple_filter->flags) {
+	case RTE_5TUPLE_FLAGS:
+	case (RTE_5TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG):
+		if (hw->mac.type != e1000_82576)
+			return -ENOTSUP;
+		if (add)
+			ret = igb_add_5tuple_filter_82576(dev,
+							  ntuple_filter);
+		else
+			ret = igb_remove_5tuple_filter_82576(dev,
+							     ntuple_filter);
+		break;
+	case RTE_2TUPLE_FLAGS:
+	case (RTE_2TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG):
+		if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350)
+			return -ENOTSUP;
+		if (add)
+			ret = igb_add_2tuple_filter(dev, ntuple_filter);
+		else
+			ret = igb_remove_2tuple_filter(dev, ntuple_filter);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * igb_get_ntuple_filter - get a ntuple filter
+ *
+ * @param
+ * dev: Pointer to struct rte_eth_dev.
+ * ntuple_filter: Pointer to struct rte_eth_ntuple_filter
+ *
+ * @return
+ *    - On success, zero.
+ *    - On failure, a negative value.
+ */
+static int
+igb_get_ntuple_filter(struct rte_eth_dev *dev,
+			struct rte_eth_ntuple_filter *ntuple_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_5tuple_filter_info filter_5tuple;
+	struct e1000_2tuple_filter_info filter_2tuple;
+	struct e1000_5tuple_filter *p_5tuple_filter;
+	struct e1000_2tuple_filter *p_2tuple_filter;
+	int ret;
+
+	switch (ntuple_filter->flags) {
+	case RTE_5TUPLE_FLAGS:
+	case (RTE_5TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG):
+		if (hw->mac.type != e1000_82576)
+			return -ENOTSUP;
+		memset(&filter_5tuple,
+			0,
+			sizeof(struct e1000_5tuple_filter_info));
+		ret = ntuple_filter_to_5tuple_82576(ntuple_filter,
+						    &filter_5tuple);
+		if (ret < 0)
+			return ret;
+		p_5tuple_filter = igb_5tuple_filter_lookup_82576(
+					&filter_info->fivetuple_list,
+					&filter_5tuple);
+		if (p_5tuple_filter == NULL) {
+			PMD_DRV_LOG(ERR, "filter doesn't exist.");
+			return -ENOENT;
+		}
+		ntuple_filter->queue = p_5tuple_filter->queue;
+		break;
+	case RTE_2TUPLE_FLAGS:
+	case (RTE_2TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG):
+		if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350)
+			return -ENOTSUP;
+		memset(&filter_2tuple,
+			0,
+			sizeof(struct e1000_2tuple_filter_info));
+		ret = ntuple_filter_to_2tuple(ntuple_filter, &filter_2tuple);
+		if (ret < 0)
+			return ret;
+		p_2tuple_filter = igb_2tuple_filter_lookup(
+					&filter_info->twotuple_list,
+					&filter_2tuple);
+		if (p_2tuple_filter == NULL) {
+			PMD_DRV_LOG(ERR, "filter doesn't exist.");
+			return -ENOENT;
+		}
+		ntuple_filter->queue = p_2tuple_filter->queue;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * igb_ntuple_filter_handle - Handle operations for ntuple filter.
+ * @dev: pointer to rte_eth_dev structure
+ * @filter_op:operation will be taken.
+ * @arg: a pointer to specific structure corresponding to the filter_op
+ */
+static int
+igb_ntuple_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;
+
+	MAC_TYPE_FILTER_SUP(hw->mac.type);
+
+	if (filter_op == RTE_ETH_FILTER_NOP)
+		return 0;
+
+	if (arg == NULL) {
+		PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u.",
+			    filter_op);
+		return -EINVAL;
+	}
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_ADD:
+		ret = igb_add_del_ntuple_filter(dev,
+			(struct rte_eth_ntuple_filter *)arg,
+			TRUE);
+		break;
+	case RTE_ETH_FILTER_DELETE:
+		ret = igb_add_del_ntuple_filter(dev,
+			(struct rte_eth_ntuple_filter *)arg,
+			FALSE);
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = igb_get_ntuple_filter(dev,
+			(struct rte_eth_ntuple_filter *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unsupported operation %u.", filter_op);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static inline int
 igb_ethertype_filter_lookup(struct e1000_filter_info *filter_info,
 			uint16_t ethertype)
@@ -3234,6 +3544,9 @@  eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 	int ret = -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_NTUPLE:
+		ret = igb_ntuple_filter_handle(dev, filter_op, arg);
+		break;
 	case RTE_ETH_FILTER_ETHERTYPE:
 		ret = igb_ethertype_filter_handle(dev, filter_op, arg);
 		break;