diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 87ec402..e1e13ba 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -119,6 +119,8 @@ This section should contain new features added in this release. Sample format:
 
   Only available with Mellanox OFED >= 3.2.
 
+* **Added Flow director enhancements on Intel X710/XL710.**
+
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index af87298..39a7280 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -6618,58 +6618,69 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
 	 */
 	static const uint64_t valid_fdir_inset_table[] = {
 		[I40E_FILTER_PCTYPE_FRAG_IPV4] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
 		I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_PROTO |
 		I40E_INSET_IPV4_TTL,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
 		I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
 		I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
 		I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
 		I40E_INSET_SCTP_VT,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
 		I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_PROTO |
 		I40E_INSET_IPV4_TTL,
 		[I40E_FILTER_PCTYPE_FRAG_IPV6] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
 		I40E_INSET_IPV6_TC | I40E_INSET_IPV6_NEXT_HDR |
 		I40E_INSET_IPV6_HOP_LIMIT,
 		[I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
 		I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
 		[I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
 		I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
 		[I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
 		I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
 		I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
 		I40E_INSET_SCTP_VT,
 		[I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
 		I40E_INSET_IPV6_TC | I40E_INSET_IPV6_NEXT_HDR |
 		I40E_INSET_IPV6_HOP_LIMIT,
 		[I40E_FILTER_PCTYPE_L2_PAYLOAD] =
+		I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
 		I40E_INSET_TUNNEL_ID |
 		I40E_INSET_LAST_ETHER_TYPE,
 	};
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index e4ac79d..e905f9f 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -687,34 +687,50 @@ i40e_fdir_configure(struct rte_eth_dev *dev)
 	return ret;
 }
 
-static inline void
+static inline int
 i40e_fdir_fill_ether_head(const struct rte_eth_fdir_input *fdir_input,
-			       unsigned char *pkt)
+			       unsigned char *pkt, bool vlan)
 {
-	struct ether_hdr *ether = (struct ether_hdr *)pkt;
+	static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
+	uint16_t *ether_type;
+	uint8_t len = 2 * sizeof(struct ether_addr);
+
+	pkt += 2 * sizeof(struct ether_addr);
+	if (vlan && fdir_input->flow_ext.vlan_tci) {
+		rte_memcpy(pkt, vlan_frame, sizeof(vlan_frame));
+		rte_memcpy(pkt + sizeof(uint16_t),
+			   &fdir_input->flow_ext.vlan_tci,
+			   sizeof(uint16_t));
+		pkt += sizeof(vlan_frame);
+		len += sizeof(vlan_frame);
+	}
+	ether_type = (uint16_t *)pkt;
+
 	switch (fdir_input->flow_type) {
 	case RTE_ETH_FLOW_L2_PAYLOAD:
-		ether->ether_type = fdir_input->flow.l2_flow.ether_type;
+		*ether_type = fdir_input->flow.l2_flow.ether_type;
 		break;
 	case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
 	case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
 	case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
 	case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
 	case RTE_ETH_FLOW_FRAG_IPV4:
-		ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		*ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
 		break;
 	case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
 	case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
 	case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP:
 	case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
 	case RTE_ETH_FLOW_FRAG_IPV6:
-		ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		*ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
 		break;
 	default:
 		PMD_DRV_LOG(ERR, "unknown flow type %u.",
 			    fdir_input->flow_type);
-		break;
+		return -1;
 	}
+	len += sizeof(uint16_t);
+	return len;
 }
 
 static inline void
@@ -814,6 +830,8 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf,
 	struct sctp_hdr *sctp;
 	uint8_t size, dst = 0;
 	uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/
+	int len;
+	static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
 	static uint8_t gre4_frame[] = {0x08, 0,
 			0x45, 0, 0, 0x3A, 0, 0, 0, 0, 0x40, 0x2F,
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0x08, 0,
@@ -833,6 +851,14 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf,
 			0, 0, 0, 0}; /*Mac + IP + NVGRE hdr*/
 
 	inner_pkt += 2 * sizeof(struct ether_addr);
+	if (fdir_input->flow_ext.vlan_tci) {
+		rte_memcpy(inner_pkt, vlan_frame, sizeof(vlan_frame));
+		rte_memcpy(inner_pkt + sizeof(uint16_t),
+			   &fdir_input->flow_ext.vlan_tci,
+			   sizeof(uint16_t));
+		inner_pkt += sizeof(vlan_frame);
+	}
+
 	/* fill the tunnel header if required */
 	switch (fdir_input->flow.tunnel_flow.tunnel_type) {
 	case RTE_FDIR_TUNNEL_TYPE_GRE:
@@ -862,7 +888,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf,
 			   &fdir_input->flow.tunnel_flow.tunnel_id,
 			   I40E_TUNNEL_KEY_LEN);
 		/* fill the ethernet and IP head of inner frame */
-		i40e_fdir_fill_ether_head(fdir_input, inner_pkt);
+		i40e_fdir_fill_ether_head(fdir_input, inner_pkt, FALSE);
 		inner_pkt += sizeof(struct ether_hdr);
 		break;
 	case RTE_FDIR_TUNNEL_TYPE_NVGRE:
@@ -872,13 +898,13 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf,
 			   &fdir_input->flow.tunnel_flow.tunnel_id,
 			   I40E_TUNNEL_KEY_LEN);
 		/* fill the Ether header of inner frame */
-		i40e_fdir_fill_ether_head(fdir_input, inner_pkt);
+		i40e_fdir_fill_ether_head(fdir_input, inner_pkt, FALSE);
 		inner_pkt += sizeof(struct ether_hdr);
 		break;
 	default:
 		/* fill the Ether header of single frame */
-		i40e_fdir_fill_ether_head(fdir_input, raw_pkt);
-		inner_pkt = raw_pkt + sizeof(struct ether_hdr);
+		len = i40e_fdir_fill_ether_head(fdir_input, raw_pkt, TRUE);
+		inner_pkt = raw_pkt + len;
 		break;
 	}
 
@@ -1123,6 +1149,7 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
 		PMD_DRV_LOG(ERR, "construct packet for fdir fails.");
 		return ret;
 	}
+
 	pctype = i40e_flowtype_to_pctype(filter->input.flow_type);
 	ret = i40e_fdir_filter_programming(pf, pctype, filter, add);
 	if (ret < 0) {
