diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h
index 71eb5fb..2433759 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,68 @@ 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.
+ */
+struct e1000_filter_info {
+	/* 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;
+};
+
 /*
  * Structure to store private data for each driver instance (for each port).
  */
@@ -140,6 +189,7 @@ struct e1000_adapter {
 	struct e1000_interrupt  intr;
 	struct e1000_vfta       shadow_vfta;
 	struct e1000_vf_info    *vfdata;
+	struct e1000_filter_info filter;
 };
 
 #define E1000_DEV_PRIVATE_TO_HW(adapter) \
@@ -157,6 +207,9 @@ struct e1000_adapter {
 #define E1000_DEV_PRIVATE_TO_P_VFDATA(adapter) \
         (&((struct e1000_adapter *)adapter)->vfdata)
 
+#define E1000_DEV_PRIVATE_TO_FILTER_INFO(adapter) \
+	(&((struct e1000_adapter *)adapter)->filter)
+
 /*
  * RX/TX IGB function prototypes
  */
diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c
index 873d65e..551283e 100644
--- a/lib/librte_pmd_e1000/igb_ethdev.c
+++ b/lib/librte_pmd_e1000/igb_ethdev.c
@@ -162,14 +162,10 @@ static int eth_igb_remove_ethertype_filter(struct rte_eth_dev *dev,
 static int eth_igb_get_ethertype_filter(struct rte_eth_dev *dev,
 			uint16_t index,
 			struct rte_ethertype_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);
@@ -178,14 +174,22 @@ 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 eth_igb_filter_ctrl(struct rte_eth_dev *dev,
+		     enum rte_filter_type filter_type,
+		     enum rte_filter_op filter_op,
+		     void *arg);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -267,15 +271,10 @@ static struct eth_dev_ops eth_igb_ops = {
 	.add_ethertype_filter    = eth_igb_add_ethertype_filter,
 	.remove_ethertype_filter = eth_igb_remove_ethertype_filter,
 	.get_ethertype_filter    = eth_igb_get_ethertype_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,
 };
 
 /*
@@ -468,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;
@@ -599,6 +600,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:
@@ -924,7 +931,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);
@@ -947,6 +958,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
@@ -2388,7 +2417,7 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev,
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != e1000_82580 && (type) != e1000_i350 &&\
 		(type) != e1000_82576)\
-		return -ENOSYS;\
+		return -ENOTSUP;\
 } while (0)
 
 /*
@@ -2595,165 +2624,209 @@ eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index,
 		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;
+
+	/*
+	 * 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;
+	}
 
-	if (index >= E1000_MAX_TTQF_FILTERS)
-		return -EINVAL;  /* filter index is out of range */
+	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;
+
+	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;
 
-	E1000_WRITE_REG(hw, E1000_TTQF(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIR(index), 0);
-	E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0);
+	/* 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;
 }
 
 /*
@@ -2911,192 +2984,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. */
+	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;
+	}
 
-	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->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;
 
-	if (hw->mac.type != e1000_82576)
+	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 (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
@@ -3149,6 +3295,196 @@ 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 int
+eth_igb_filter_ctrl(struct rte_eth_dev *dev,
+		     enum rte_filter_type filter_type,
+		     enum rte_filter_op filter_op,
+		     void *arg)
+{
+	int ret = -EINVAL;
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_NTUPLE:
+		ret = igb_ntuple_filter_handle(dev, filter_op, arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+							filter_type);
+		break;
+	}
+
+	return ret;
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
