[dpdk-dev,v2,7/7] app/testpmd: add commands and config functions for i40e flow director support

Message ID 1409105634-29980-8-git-send-email-jingjing.wu@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Jingjing Wu Aug. 27, 2014, 2:13 a.m. UTC
  add structure definition to construct programming packet.
add commands to programming 6 flow types for the flow director filters,
which is called PCTYPE in fortville: ipv4, tcpv4, udpv4, ipv6, tcpv6, udpv6
add commands to support flushing flow director table and get info
 
Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
Reviewed-by: Helin Zhang <helin.zhang@intel.com>
Reviewed-by: Jing Chen <jing.d.chen@intel.com>
Reviewed-by: Jijiang Liu <jijiang.liu@intel.com>
 
---
 app/test-pmd/cmdline.c | 665 +++++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/config.c  |  54 +++-
 app/test-pmd/testpmd.c |  22 ++
 app/test-pmd/testpmd.h |  57 +++++
 4 files changed, 786 insertions(+), 12 deletions(-)
  

Comments

Thomas Monjalon Aug. 27, 2014, 2:35 p.m. UTC | #1
Hi Jingjing,

2014-08-27 10:13, Jingjing Wu:
> add structure definition to construct programming packet.

What is a "programming packet"?

> +#ifdef RTE_LIBRTE_I40E_PMD
> +			"i40e_flow_director_filter (port_id) (add|del)"
> +			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
> +			" flexwords (flexwords_value) (drop|fwd)"
> +			" queue (queue_id) fd_id (fd_id_value)\n"
> +			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
> +
> +			"i40e_flow_director_filter (port_id) (add|del)"
> +			" flow (udp4|tcp4|udp6|tcp6)"
> +			" src (src_ip_address) (src_port)"
> +			" dst (dst_ip_address) (dst_port)"
> +			" flexwords (flexwords_value) (drop|fwd)"
> +			" queue (queue_id) fd_id (fd_id_value)\n"
> +			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
> +
> +			"i40e_flush_flow_diretor (port_id)\n"
> +			"    Flush all flow director entries of a device on i40e NIC.\n\n"
> +#endif /* RTE_LIBRTE_I40E_PMD */

I'd really like to stop seeing this kind of thing.
We cannot add some ifdef for each PMD in generic code.

I stopped reading after that.

Sorry, I don't want to be rude but my feeling is that adding such feature
with global picture in mind is not easy. I know you want to offer all i40e
capabilities but you should think at future evolutions and how other drivers
will be integrated with yours.

Thanks
  
Venkatesan, Venky Aug. 27, 2014, 4:54 p.m. UTC | #2
On 8/27/2014 7:35 AM, Thomas Monjalon wrote:
> Hi Jingjing,
>
> 2014-08-27 10:13, Jingjing Wu:
>> add structure definition to construct programming packet.
> What is a "programming packet"?
>
>> +#ifdef RTE_LIBRTE_I40E_PMD
>> +			"i40e_flow_director_filter (port_id) (add|del)"
>> +			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
>> +			" flexwords (flexwords_value) (drop|fwd)"
>> +			" queue (queue_id) fd_id (fd_id_value)\n"
>> +			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
>> +
>> +			"i40e_flow_director_filter (port_id) (add|del)"
>> +			" flow (udp4|tcp4|udp6|tcp6)"
>> +			" src (src_ip_address) (src_port)"
>> +			" dst (dst_ip_address) (dst_port)"
>> +			" flexwords (flexwords_value) (drop|fwd)"
>> +			" queue (queue_id) fd_id (fd_id_value)\n"
>> +			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
>> +
>> +			"i40e_flush_flow_diretor (port_id)\n"
>> +			"    Flush all flow director entries of a device on i40e NIC.\n\n"
>> +#endif /* RTE_LIBRTE_I40E_PMD */
> I'd really like to stop seeing this kind of thing.
> We cannot add some ifdef for each PMD in generic code.
>
> I stopped reading after that.
>
> Sorry, I don't want to be rude but my feeling is that adding such feature
> with global picture in mind is not easy. I know you want to offer all i40e
> capabilities but you should think at future evolutions and how other drivers
> will be integrated with yours.
>
> Thanks
Second that. Any PMD-specifics need to be contained within the PMD 
itself, and not in generic code. Please rework this.
-Venky
  
Jingjing Wu Aug. 28, 2014, 3:51 a.m. UTC | #3
Hi, Thomas

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, August 27, 2014 10:36 PM
> To: Wu, Jingjing
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 7/7]app/testpmd: add commands and config functions for
> i40e flow director support
> 
> Hi Jingjing,
> 
> 2014-08-27 10:13, Jingjing Wu:
> > add structure definition to construct programming packet.
> 
> What is a "programming packet"?
For Fortville, we need to set a flow director filter by sending a packet which contains the input set values through the queue belonging to flow director.
> 
> > +#ifdef RTE_LIBRTE_I40E_PMD
> > +			"i40e_flow_director_filter (port_id) (add|del)"
> > +			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
> > +			" flexwords (flexwords_value) (drop|fwd)"
> > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > +			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
> > +
> > +			"i40e_flow_director_filter (port_id) (add|del)"
> > +			" flow (udp4|tcp4|udp6|tcp6)"
> > +			" src (src_ip_address) (src_port)"
> > +			" dst (dst_ip_address) (dst_port)"
> > +			" flexwords (flexwords_value) (drop|fwd)"
> > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > +			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
> > +
> > +			"i40e_flush_flow_diretor (port_id)\n"
> > +			"    Flush all flow director entries of a device on i40e NIC.\n\n"
> > +#endif /* RTE_LIBRTE_I40E_PMD */
> 
> I'd really like to stop seeing this kind of thing.
> We cannot add some ifdef for each PMD in generic code.
> 
> I stopped reading after that.
> 
> Sorry, I don't want to be rude but my feeling is that adding such feature
> with global picture in mind is not easy. I know you want to offer all i40e
> capabilities but you should think at future evolutions and how other drivers
> will be integrated with yours.
> 

Sorry to make you feel uncomfortable for such code. Just as you say, I want to offer more i40e capabilities. I will rework code in testpmd. 

> Thanks
> --
> Thomas
  
Thomas Monjalon Aug. 28, 2014, 8:50 a.m. UTC | #4
2014-08-28 03:51, Wu, Jingjing:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2014-08-27 10:13, Jingjing Wu:
> > > add structure definition to construct programming packet.
> > 
> > What is a "programming packet"?
> 
> For Fortville, we need to set a flow director filter by sending a
> packet which contains the input set values through the queue
> belonging to flow director.

OK. To be more clear, some detailed explanations are required in the
commit log. Please try to be very descriptive.
You can think comments like this:
- if comments are absolutely needed to understand the code, you should
put comments in the code (or write the code differently)
- if some feature context can help for the review, you should explain
context and design in the commit log

> > > +#ifdef RTE_LIBRTE_I40E_PMD
> > > +			"i40e_flow_director_filter (port_id) (add|del)"
> > > +			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
> > > +			" flexwords (flexwords_value) (drop|fwd)"
> > > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > > +			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
> > > +
> > > +			"i40e_flow_director_filter (port_id) (add|del)"
> > > +			" flow (udp4|tcp4|udp6|tcp6)"
> > > +			" src (src_ip_address) (src_port)"
> > > +			" dst (dst_ip_address) (dst_port)"
> > > +			" flexwords (flexwords_value) (drop|fwd)"
> > > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > > +			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
> > > +
> > > +			"i40e_flush_flow_diretor (port_id)\n"
> > > +			"    Flush all flow director entries of a device on i40e NIC.\n\n"
> > > +#endif /* RTE_LIBRTE_I40E_PMD */
> > 
> > I'd really like to stop seeing this kind of thing.
> > We cannot add some ifdef for each PMD in generic code.
> > 
> > I stopped reading after that.
> > 
> > Sorry, I don't want to be rude but my feeling is that adding such feature
> > with global picture in mind is not easy. I know you want to offer all i40e
> > capabilities but you should think at future evolutions and how other drivers
> > will be integrated with yours.
> > 
> 
> Sorry to make you feel uncomfortable for such code. Just as you say,
> I want to offer more i40e capabilities. I will rework code in testpmd. 

Thanks
  
Jingjing Wu Aug. 28, 2014, 9:01 a.m. UTC | #5
Hi, Thomas

Thanks for your tips.

I have another question:
If we use the way 'rx_classification_filter_ctl' works, the specific structures defined in rte_i40e.h will be visible in user's application, such as testpmd.
I know I shouldn't make commands linked with i40e like what I did before. But will the i40e specific structures become visible be acceptable?



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, August 28, 2014 4:51 PM
> To: Wu, Jingjing
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 7/7]app/testpmd: add commands and config functions for
> i40e flow director support
> 
> 2014-08-28 03:51, Wu, Jingjing:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > 2014-08-27 10:13, Jingjing Wu:
> > > > add structure definition to construct programming packet.
> > >
> > > What is a "programming packet"?
> >
> > For Fortville, we need to set a flow director filter by sending a
> > packet which contains the input set values through the queue
> > belonging to flow director.
> 
> OK. To be more clear, some detailed explanations are required in the
> commit log. Please try to be very descriptive.
> You can think comments like this:
> - if comments are absolutely needed to understand the code, you should
> put comments in the code (or write the code differently)
> - if some feature context can help for the review, you should explain
> context and design in the commit log
> 
> > > > +#ifdef RTE_LIBRTE_I40E_PMD
> > > > +			"i40e_flow_director_filter (port_id) (add|del)"
> > > > +			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
> > > > +			" flexwords (flexwords_value) (drop|fwd)"
> > > > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > > > +			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
> > > > +
> > > > +			"i40e_flow_director_filter (port_id) (add|del)"
> > > > +			" flow (udp4|tcp4|udp6|tcp6)"
> > > > +			" src (src_ip_address) (src_port)"
> > > > +			" dst (dst_ip_address) (dst_port)"
> > > > +			" flexwords (flexwords_value) (drop|fwd)"
> > > > +			" queue (queue_id) fd_id (fd_id_value)\n"
> > > > +			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
> > > > +
> > > > +			"i40e_flush_flow_diretor (port_id)\n"
> > > > +			"    Flush all flow director entries of a device on i40e NIC.\n\n"
> > > > +#endif /* RTE_LIBRTE_I40E_PMD */
> > >
> > > I'd really like to stop seeing this kind of thing.
> > > We cannot add some ifdef for each PMD in generic code.
> > >
> > > I stopped reading after that.
> > >
> > > Sorry, I don't want to be rude but my feeling is that adding such feature
> > > with global picture in mind is not easy. I know you want to offer all i40e
> > > capabilities but you should think at future evolutions and how other drivers
> > > will be integrated with yours.
> > >
> >
> > Sorry to make you feel uncomfortable for such code. Just as you say,
> > I want to offer more i40e capabilities. I will rework code in testpmd.
> 
> Thanks
> --
> Thomas
  
Thomas Monjalon Aug. 28, 2014, 11 a.m. UTC | #6
2014-08-28 09:01, Wu, Jingjing:
> I have another question:
> If we use the way 'rx_classification_filter_ctl' works, the specific
> structures defined in rte_i40e.h will be visible in user's application,
> such as testpmd.
> I know I shouldn't make commands linked with i40e like what I did before.
> But will the i40e specific structures become visible be acceptable?

I think testpmd should be limited to generic API.
So it wouldn't be acceptable to be dependent of i40e files.
But having some specific i40e tests in examples or app/test is OK.
  
Ananyev, Konstantin Aug. 28, 2014, 11:30 a.m. UTC | #7
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Thomas Monjalon
> Sent: Thursday, August 28, 2014 12:01 PM
> To: Wu, Jingjing
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 7/7]app/testpmd: add commands and config functions for i40e flow director support
> 
> 2014-08-28 09:01, Wu, Jingjing:
> > I have another question:
> > If we use the way 'rx_classification_filter_ctl' works, the specific
> > structures defined in rte_i40e.h will be visible in user's application,
> > such as testpmd.
> > I know I shouldn't make commands linked with i40e like what I did before.
> > But will the i40e specific structures become visible be acceptable?
> 
> I think testpmd should be limited to generic API.
> So it wouldn't be acceptable to be dependent of i40e files.
> But having some specific i40e tests in examples or app/test is OK.
> 

Probably I didn't get you right:
Are you suggesting to have a new clone of testpmd for any new device we are going to support?
That seems like too much hassle to me.
Plus what to do if someone would like to test configuration with two different devices involved: ixgbe and i40e for example? 
I suggest we keep one testpmd for all devices we support.
Of course we'll probably have to make some rework to avoid if (strncmp(drv_name, "xxx") spread all over it.
We need to find some better way to discover/setup HW specific features.
Thanks
Konstantin
  
Thomas Monjalon Aug. 28, 2014, 12:02 p.m. UTC | #8
2014-08-28 11:30, Ananyev, Konstantin:
> From: Thomas Monjalon
> > 2014-08-28 09:01, Wu, Jingjing:
> > > I have another question:
> > > If we use the way 'rx_classification_filter_ctl' works, the specific
> > > structures defined in rte_i40e.h will be visible in user's application,
> > > such as testpmd.
> > > I know I shouldn't make commands linked with i40e like what I did before.
> > > But will the i40e specific structures become visible be acceptable?
> > 
> > I think testpmd should be limited to generic API.
> > So it wouldn't be acceptable to be dependent of i40e files.
> > But having some specific i40e tests in examples or app/test is OK.
> > 
> 
> Probably I didn't get you right:

Indeed ;)

> Are you suggesting to have a new clone of testpmd for any new device
> we are going to support?

No. I say there shouldn't be any PMD dependency on testpmd.
It means we should use only generic API.

> That seems like too much hassle to me.
> Plus what to do if someone would like to test configuration with two
> different devices involved: ixgbe and i40e for example?

ixgbe and i40e features should use the same generic API for flow director.

> I suggest we keep one testpmd for all devices we support.
> Of course we'll probably have to make some rework to avoid
> if (strncmp(drv_name, "xxx") spread all over it.
> We need to find some better way to discover/setup HW specific features.

Agreed
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b04a4e8..d4729e7 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -74,6 +74,14 @@ 
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+#include <rte_sctp.h>
+#include <rte_eth_features.h>
+#ifdef RTE_LIBRTE_I40E_PMD
+#include <rte_i40e.h>
+#endif /* RTE_LIBRTE_I40E_PMD */
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -660,6 +668,25 @@  static void cmd_help_long_parsed(void *parsed_result,
 
 			"get_flex_filter (port_id) index (idx)\n"
 			"    get info of a flex filter.\n\n"
+
+#ifdef RTE_LIBRTE_I40E_PMD
+			"i40e_flow_director_filter (port_id) (add|del)"
+			" flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)"
+			" flexwords (flexwords_value) (drop|fwd)"
+			" queue (queue_id) fd_id (fd_id_value)\n"
+			"    Add/Del a IP type flow director filter for i40e NIC.\n\n"
+
+			"i40e_flow_director_filter (port_id) (add|del)"
+			" flow (udp4|tcp4|udp6|tcp6)"
+			" src (src_ip_address) (src_port)"
+			" dst (dst_ip_address) (dst_port)"
+			" flexwords (flexwords_value) (drop|fwd)"
+			" queue (queue_id) fd_id (fd_id_value)\n"
+			"    Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n"
+
+			"i40e_flush_flow_diretor (port_id)\n"
+			"    Flush all flow director entries of a device on i40e NIC.\n\n"
+#endif /* RTE_LIBRTE_I40E_PMD */
 		);
 	}
 }
@@ -7403,6 +7430,639 @@  cmdline_parse_inst_t cmd_get_flex_filter = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+#ifdef RTE_LIBRTE_I40E_PMD
+/* *** deal with i40e flow director filter *** */
+struct cmd_i40e_flow_director_result {
+	cmdline_fixed_string_t flow_director_filter;
+	uint8_t port_id;
+	cmdline_fixed_string_t ops;
+	cmdline_fixed_string_t flow;
+	cmdline_fixed_string_t flow_type;
+	cmdline_fixed_string_t src;
+	cmdline_ipaddr_t ip_src;
+	uint16_t port_src;
+	cmdline_fixed_string_t dst;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t port_dst;
+	cmdline_fixed_string_t flexwords;
+	cmdline_fixed_string_t flexwords_value;
+	cmdline_fixed_string_t drop;
+	cmdline_fixed_string_t queue;
+	uint16_t  queue_id;
+	cmdline_fixed_string_t fd_id;
+	uint32_t  fd_id_value;
+};
+
+static inline int
+parse_flexwords(const char *q_arg, uint16_t *flexwords)
+{
+#define MAX_NUM_WORD 8
+	char s[256];
+	const char *p, *p0 = q_arg;
+	char *end;
+	unsigned long int_fld[MAX_NUM_WORD];
+	char *str_fld[MAX_NUM_WORD];
+	int i;
+	unsigned size;
+	int num_words = -1;
+
+	p = strchr(p0, '(');
+	if (p == NULL)
+		return -1;
+	++p;
+	p0 = strchr(p, ')');
+	if (p0 == NULL)
+		return -1;
+
+	size = p0 - p;
+	if (size >= sizeof(s))
+		return -1;
+
+	snprintf(s, sizeof(s), "%.*s", size, p);
+	num_words = rte_strsplit(s, sizeof(s), str_fld, MAX_NUM_WORD, ',');
+	if (num_words < 0 || num_words > MAX_NUM_WORD)
+		return -1;
+	for (i = 0; i < num_words; i++) {
+		errno = 0;
+		int_fld[i] = strtoul(str_fld[i], &end, 0);
+		if (errno != 0 || end == str_fld[i] || int_fld[i] > UINT16_MAX)
+			return -1;
+		flexwords[i] = rte_cpu_to_be_16((uint16_t)int_fld[i]);
+	}
+	return num_words;
+}
+
+static inline struct rte_mbuf *
+tx_mbuf_alloc(struct rte_mempool *mp)
+{
+	struct rte_mbuf *m;
+
+	m = __rte_mbuf_raw_alloc(mp);
+	__rte_mbuf_sanity_check_raw(m, RTE_MBUF_PKT, 0);
+	return m;
+}
+
+static inline void
+rte_i40e_fdir_construct_ip4_input(struct ipv4_other_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv4_hdr *ip;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
+	/* set len to 46 bytes by default */
+	ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
+	ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL;
+
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	ip->src_addr = flow->dst_ip;
+	ip->dst_addr = flow->src_ip;
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static inline void
+rte_i40e_fdir_construct_udp4_input(struct ipv4_udp_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv4_hdr *ip;
+	struct udp_hdr *udp;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv4_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
+	/* set len to by default */
+	ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
+	ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL;
+
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	ip->src_addr = flow->dst_ip;
+	ip->dst_addr = flow->src_ip;
+	ip->next_proto_id = IPPROTO_UDP;
+	udp->src_port = flow->dst_port;
+	udp->dst_port = flow->src_port;
+	udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static inline void
+rte_i40e_fdir_construct_tcp4_input(struct ipv4_tcp_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv4_hdr *ip;
+	struct tcp_hdr *tcp;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv4_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
+	/* set len by default */
+	ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
+	ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL;
+
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	ip->src_addr = flow->dst_ip;
+	ip->dst_addr = flow->src_ip;
+	ip->next_proto_id = IPPROTO_TCP;
+	tcp->src_port = flow->dst_port;
+	tcp->dst_port = flow->src_port;
+	tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static inline void
+rte_i40e_fdir_construct_ip6_input(struct ipv6_other_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv6_hdr *ip;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);
+	ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN);
+	ip->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
+
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	rte_memcpy(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN);
+	rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN);
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static inline void
+rte_i40e_fdir_construct_udp6_input(struct ipv6_udp_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv6_hdr *ip;
+	struct udp_hdr *udp;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv6_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv6_hdr) + sizeof(struct udp_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);
+	ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN);
+	ip->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	rte_memcpy(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN);
+	rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN);
+	ip->proto = IPPROTO_UDP;
+	udp->src_port = flow->dst_port;
+	udp->dst_port = flow->src_port;
+	udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static inline void
+rte_i40e_fdir_construct_tcp6_input(struct ipv6_tcp_flow *flow,
+			unsigned char *raw_pkt)
+{
+	struct ether_hdr *ether;
+	struct ipv6_hdr *ip;
+	struct tcp_hdr *tcp;
+	unsigned char *payload;
+
+	ether = (struct ether_hdr *)raw_pkt;
+	ip = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr));
+	tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv6_hdr));
+	payload = raw_pkt + sizeof(struct ether_hdr) +
+			sizeof(struct ipv6_hdr) + sizeof(struct tcp_hdr);
+
+	ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);
+	ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN);
+	ip->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
+	/*
+	 * The source and destination fields in the transmitted packet need
+	 * to be presented in a reversed order with respect to the expected
+	 * received packets.
+	 */
+	rte_memcpy(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN);
+	rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN);
+	ip->proto = IPPROTO_TCP;
+	tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;
+	tcp->src_port = flow->dst_port;
+	tcp->dst_port = flow->src_port;
+	(void)rte_memcpy(payload,
+			 flow->flexwords,
+			 BYTES_PER_WORD * flow->num_flexwords);
+}
+
+static void
+cmd_i40e_flow_director_parsed(void *parsed_result,
+			  __attribute__((unused)) struct cmdline *cl,
+			  __attribute__((unused)) void *data)
+{
+	struct cmd_i40e_flow_director_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_i40e_fdir_entry entry;
+	struct rte_mbuf *m_pkt = NULL;
+	uint16_t flexwords[8];
+	enum rte_eth_command cmd;
+	int num_flexwords;
+	int ret = 0;
+
+	memset(flexwords, 0, sizeof(flexwords));
+	memset(&entry, 0, sizeof(struct rte_i40e_fdir_entry));
+	num_flexwords = parse_flexwords(res->flexwords_value, flexwords);
+	if (num_flexwords < 0) {
+		printf("error: Cannot pase flexwords input.\n");
+		return;
+	}
+	port = &ports[res->port_id];
+	m_pkt = tx_mbuf_alloc(port->i40e_fdir_mp);
+	if (m_pkt == NULL) {
+		printf("error: Cannot malloc mbuf for fdir.\n");
+		return;
+	}
+
+	if (!strcmp(res->flow_type, "ip4")) {
+		struct ipv4_other_flow ip4_flow;
+		memset(&ip4_flow, 0, sizeof(struct ipv4_other_flow));
+		/* no need to convert, already big endian. */
+		if (res->ip_dst.family == AF_INET)
+			ip4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_src.family == AF_INET)
+			ip4_flow.src_ip = res->ip_src.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		ip4_flow.num_flexwords = num_flexwords;
+		rte_memcpy(ip4_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_ip4_input(&ip4_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV4_OTHER;
+	} else if (!strcmp(res->flow_type, "udp4")) {
+		struct ipv4_udp_flow udp4_flow;
+		memset(&udp4_flow, 0, sizeof(struct ipv4_udp_flow));
+		/* no need to convert, already big endian. */
+		if (res->ip_dst.family == AF_INET)
+			udp4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_src.family == AF_INET)
+			udp4_flow.src_ip = res->ip_src.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		/* need convert to big endian. */
+		udp4_flow.dst_port = rte_cpu_to_be_16(res->port_dst);
+		udp4_flow.src_port = rte_cpu_to_be_16(res->port_src);
+		udp4_flow.num_flexwords = num_flexwords;
+		rte_memcpy(udp4_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_udp4_input(&udp4_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV4_UDP;
+	} else if (!strcmp(res->flow_type, "tcp4")) {
+		struct ipv4_tcp_flow tcp4_flow;
+		memset(&tcp4_flow, 0, sizeof(struct ipv4_tcp_flow));
+		if (res->ip_dst.family == AF_INET)
+			tcp4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_src.family == AF_INET)
+			tcp4_flow.src_ip = res->ip_src.addr.ipv4.s_addr;
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		/* need convert to big endian. */
+		tcp4_flow.dst_port = rte_cpu_to_be_16(res->port_dst);
+		tcp4_flow.src_port = rte_cpu_to_be_16(res->port_src);
+		tcp4_flow.num_flexwords = num_flexwords;
+		rte_memcpy(tcp4_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_tcp4_input(&tcp4_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV4_TCP;
+	} else if (!strcmp(res->flow_type, "ip6")) {
+		struct ipv6_other_flow ip6_flow;
+		memset(&ip6_flow, 0, sizeof(struct ipv6_other_flow));
+		if (res->ip_src.family == AF_INET6)
+			(void)rte_memcpy(&(ip6_flow.src_ip),
+					 &(res->ip_src.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_dst.family == AF_INET6)
+			(void)rte_memcpy(&(ip6_flow.dst_ip),
+					 &(res->ip_dst.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		ip6_flow.num_flexwords = num_flexwords;
+		rte_memcpy(ip6_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_ip6_input(&ip6_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV6_OTHER;
+	} else if (!strcmp(res->flow_type, "udp6")) {
+		struct ipv6_udp_flow udp6_flow;
+		memset(&udp6_flow, 0, sizeof(struct ipv6_udp_flow));
+		if (res->ip_src.family == AF_INET6)
+			(void)rte_memcpy(&(udp6_flow.src_ip),
+					 &(res->ip_src.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_dst.family == AF_INET6)
+			(void)rte_memcpy(&(udp6_flow.dst_ip),
+					 &(res->ip_dst.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		udp6_flow.dst_port = rte_cpu_to_be_16(res->port_dst);
+		udp6_flow.src_port = rte_cpu_to_be_16(res->port_src);
+		udp6_flow.num_flexwords = num_flexwords;
+		rte_memcpy(udp6_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_udp6_input(&udp6_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV6_UDP;
+	} else if (!strcmp(res->flow_type, "tcp6")) {
+		struct ipv6_tcp_flow tcp6_flow;
+		memset(&tcp6_flow, 0, sizeof(struct ipv6_tcp_flow));
+		if (res->ip_src.family == AF_INET6)
+			(void)rte_memcpy(&(tcp6_flow.src_ip),
+					 &(res->ip_src.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		if (res->ip_dst.family == AF_INET6)
+			(void)rte_memcpy(&(tcp6_flow.dst_ip),
+					 &(res->ip_dst.addr.ipv6),
+					 sizeof(struct in6_addr));
+		else {
+			printf("error paramters.\n");
+			goto pktbuf_free;
+		}
+		tcp6_flow.dst_port = rte_cpu_to_be_16(res->port_dst);
+		tcp6_flow.src_port = rte_cpu_to_be_16(res->port_src);
+		tcp6_flow.num_flexwords = num_flexwords;
+		rte_memcpy(tcp6_flow.flexwords,
+				 flexwords,
+				 BYTES_PER_WORD * num_flexwords);
+		rte_i40e_fdir_construct_tcp6_input(&tcp6_flow, m_pkt->pkt.data);
+		entry.input.pctype = ETH_PCTYPE_NONF_IPV6_TCP;
+	}
+	m_pkt->pkt.data_len = I40E_FDIR_PKT_LEN;
+	m_pkt->pkt.next = NULL;
+
+	entry.input.data = m_pkt;
+	entry.input.dest_vsi = 0; /* if set to 0, will use main vsi by default*/
+	entry.input.flex_off = 0;  /*use 0 by default*/
+	if (!strcmp(res->drop, "drop"))
+		entry.action.drop = RTE_I40E_DEST_DROP_PACKET;
+	else
+		entry.action.drop = RTE_I40E_DEST_DIRECT_PACKET_QINDEX;
+	/* set to report FD ID by default temporary*/
+	entry.action.report_status = RTE_I40E_FDIR_REPORT_FD_ID;
+	entry.action.rx_queue = res->queue_id;
+	/* use 0 by default, will set it to fdir counter per dev */
+	entry.action.cnt_index = 0;
+	entry.soft_id = res->fd_id_value;
+	if (!strcmp(res->ops, "add"))
+		cmd = RTE_CMD_FDIR_RULE_ADD;
+	else
+		cmd = RTE_CMD_FDIR_RULE_DEL;
+	ret = rte_eth_dev_rx_classification_filter_ctl(res->port_id, cmd, &entry);
+	if (ret < 0)
+		printf("i40e flow director programming error,"
+			" return code = %d \n", ret);
+pktbuf_free:
+	rte_pktmbuf_free(entry.input.data);
+}
+
+cmdline_parse_token_string_t cmd_i40e_flow_director_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 flow_director_filter, "i40e_flow_director_filter");
+cmdline_parse_token_num_t cmd_i40e_flow_director_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      port_id, UINT8);
+cmdline_parse_token_string_t cmd_i40e_flow_director_ops =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 ops, "add#del");
+cmdline_parse_token_string_t cmd_i40e_flow_director_flow =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 flow, "flow");
+cmdline_parse_token_string_t cmd_i40e_flow_director_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 flow_type, "ip4#tcp4#udp4#ip6#tcp6#udp6");
+cmdline_parse_token_string_t cmd_i40e_flow_director_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 src, "src");
+cmdline_parse_token_ipaddr_t cmd_i40e_flow_director_ip_src =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 ip_src);
+cmdline_parse_token_num_t cmd_i40e_flow_director_port_src =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      port_src, UINT16);
+cmdline_parse_token_string_t cmd_i40e_flow_director_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 dst, "dst");
+cmdline_parse_token_ipaddr_t cmd_i40e_flow_director_ip_dst =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 ip_dst);
+cmdline_parse_token_num_t cmd_i40e_flow_director_port_dst =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      port_dst, UINT16);
+cmdline_parse_token_string_t cmd_i40e_flow_director_flexwords =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 flexwords, "flexwords");
+cmdline_parse_token_string_t cmd_i40e_flow_director_flexwords_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      flexwords_value, NULL);
+cmdline_parse_token_string_t cmd_i40e_flow_director_drop =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 drop, "drop#fwd");
+cmdline_parse_token_string_t cmd_i40e_flow_director_queue =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 queue, "queue");
+cmdline_parse_token_num_t cmd_i40e_flow_director_queue_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      queue_id, UINT16);
+cmdline_parse_token_string_t cmd_i40e_flow_director_fd_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result,
+				 fd_id, "fd_id");
+cmdline_parse_token_num_t cmd_i40e_flow_director_fd_id_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result,
+			      fd_id_value, UINT32);
+
+cmdline_parse_inst_t cmd_i40e_add_del_ip_flow_director = {
+	.f = cmd_i40e_flow_director_parsed,
+	.data = NULL,
+	.help_str = "add or delete a ip flow director entry on i40e NIC",
+	.tokens = {
+		(void *)&cmd_i40e_flow_director_filter,
+		(void *)&cmd_i40e_flow_director_port_id,
+		(void *)&cmd_i40e_flow_director_ops,
+		(void *)&cmd_i40e_flow_director_flow,
+		(void *)&cmd_i40e_flow_director_flow_type,
+		(void *)&cmd_i40e_flow_director_src,
+		(void *)&cmd_i40e_flow_director_ip_src,
+		(void *)&cmd_i40e_flow_director_dst,
+		(void *)&cmd_i40e_flow_director_ip_dst,
+		(void *)&cmd_i40e_flow_director_flexwords,
+		(void *)&cmd_i40e_flow_director_flexwords_value,
+		(void *)&cmd_i40e_flow_director_drop,
+		(void *)&cmd_i40e_flow_director_queue,
+		(void *)&cmd_i40e_flow_director_queue_id,
+		(void *)&cmd_i40e_flow_director_fd_id,
+		(void *)&cmd_i40e_flow_director_fd_id_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_i40e_add_del_udp_flow_director = {
+	.f = cmd_i40e_flow_director_parsed,
+	.data = NULL,
+	.help_str = "add or delete a udp/tcp flow director entry on i40e NIC",
+	.tokens = {
+		(void *)&cmd_i40e_flow_director_filter,
+		(void *)&cmd_i40e_flow_director_port_id,
+		(void *)&cmd_i40e_flow_director_ops,
+		(void *)&cmd_i40e_flow_director_flow,
+		(void *)&cmd_i40e_flow_director_flow_type,
+		(void *)&cmd_i40e_flow_director_src,
+		(void *)&cmd_i40e_flow_director_ip_src,
+		(void *)&cmd_i40e_flow_director_port_src,
+		(void *)&cmd_i40e_flow_director_dst,
+		(void *)&cmd_i40e_flow_director_ip_dst,
+		(void *)&cmd_i40e_flow_director_port_dst,
+		(void *)&cmd_i40e_flow_director_flexwords,
+		(void *)&cmd_i40e_flow_director_flexwords_value,
+		(void *)&cmd_i40e_flow_director_drop,
+		(void *)&cmd_i40e_flow_director_queue,
+		(void *)&cmd_i40e_flow_director_queue_id,
+		(void *)&cmd_i40e_flow_director_fd_id,
+		(void *)&cmd_i40e_flow_director_fd_id_value,
+		NULL,
+	},
+};
+
+struct cmd_i40e_flush_flow_director_result {
+	cmdline_fixed_string_t flush_flow_director;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_i40e_flush_flow_director_flush =
+	TOKEN_STRING_INITIALIZER(struct cmd_i40e_flush_flow_director_result,
+				 flush_flow_director, "i40e_flush_flow_director");
+cmdline_parse_token_num_t cmd_i40e_flush_flow_director_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_i40e_flush_flow_director_result,
+			      port_id, UINT8);
+
+static void
+cmd_i40e_flush_flow_director_parsed(void *parsed_result,
+			  __attribute__((unused)) struct cmdline *cl,
+			  __attribute__((unused)) void *data)
+{
+	struct cmd_i40e_flow_director_result *res = parsed_result;
+	int ret = 0;
+
+	ret = rte_eth_dev_rx_classification_filter_ctl(res->port_id,
+			RTE_CMD_FDIR_FLUSH, NULL);
+	if (ret < 0)
+		printf("i40e flow director table flushing error,"
+			" return code = %d \n", ret);
+}
+
+cmdline_parse_inst_t cmd_i40e_flush_flow_director = {
+	.f = cmd_i40e_flush_flow_director_parsed,
+	.data = NULL,
+	.help_str = "flush all flow director entries of a device on i40e NIC",
+	.tokens = {
+		(void *)&cmd_i40e_flush_flow_director_flush,
+		(void *)&cmd_i40e_flush_flow_director_port_id,
+		NULL,
+	},
+};
+#endif /* RTE_LIBRTE_I40E_PMD */
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -7529,6 +8189,11 @@  cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_remove_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_get_flex_filter,
+#ifdef RTE_LIBRTE_I40E_PMD
+	(cmdline_parse_inst_t *)&cmd_i40e_add_del_ip_flow_director,
+	(cmdline_parse_inst_t *)&cmd_i40e_add_del_udp_flow_director,
+	(cmdline_parse_inst_t *)&cmd_i40e_flush_flow_director,
+#endif /* RTE_LIBRTE_I40E_PMD */
 	NULL,
 };
 
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 606e34a..86a52c3 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -93,6 +93,10 @@ 
 #include <rte_ether.h>
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
+#include <rte_eth_features.h>
+#ifdef RTE_LIBRTE_I40E_PMD
+#include <rte_i40e.h>
+#endif /* RTE_LIBRTE_I40E_PMD */
 
 #include "testpmd.h"
 
@@ -1781,26 +1785,52 @@  fdir_remove_signature_filter(portid_t port_id,
 void
 fdir_get_infos(portid_t port_id)
 {
-	struct rte_eth_fdir fdir_infos;
+	struct rte_eth_dev_info dev_info;
 
 	static const char *fdir_stats_border = "########################";
 
 	if (port_id_is_invalid(port_id))
 		return;
 
-	rte_eth_dev_fdir_get_infos(port_id, &fdir_infos);
-
 	printf("\n  %s FDIR infos for port %-2d     %s\n",
 	       fdir_stats_border, port_id, fdir_stats_border);
-
-	printf("  collision: %-10"PRIu64"  free:     %"PRIu64"\n"
-	       "  maxhash:   %-10"PRIu64"  maxlen:   %"PRIu64"\n"
-	       "  add:       %-10"PRIu64"  remove:   %"PRIu64"\n"
-	       "  f_add:     %-10"PRIu64"  f_remove: %"PRIu64"\n",
-	       (uint64_t)(fdir_infos.collision), (uint64_t)(fdir_infos.free),
-	       (uint64_t)(fdir_infos.maxhash), (uint64_t)(fdir_infos.maxlen),
-	       fdir_infos.add, fdir_infos.remove,
-	       fdir_infos.f_add, fdir_infos.f_remove);
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+#ifdef RTE_LIBRTE_I40E_PMD
+	if (strstr(dev_info.driver_name, "i40e") != NULL) {
+		struct rte_i40e_fdir_info i40e_fdir_info;
+		memset(&i40e_fdir_info, 0, sizeof(struct rte_i40e_fdir_info));
+		rte_eth_dev_rx_classification_filter_ctl(port_id,
+			RTE_CMD_FDIR_INFO_GET, (void *)&i40e_fdir_info);
+		if (i40e_fdir_info.mode) {
+			printf("  FDIR is enabled\n");
+			printf("  guarant_space: %-10"PRIu16
+			       "  best_space:     %"PRIu16"\n",
+			       i40e_fdir_info.guarant_spc,
+			       i40e_fdir_info.best_spc);
+			printf("  guarant_count: %-10"PRIu16
+			       "  best_count:     %"PRIu16"\n",
+			       i40e_fdir_info.guarant_cnt,
+			       i40e_fdir_info.best_cnt);
+		} else
+			printf("  FDIR is disabled\n");
+	} else {
+#endif /* RTE_LIBRTE_I40E_PMD */
+		struct rte_eth_fdir fdir_infos;
+
+		rte_eth_dev_fdir_get_infos(port_id, &fdir_infos);
+
+		printf("  collision: %-10"PRIu64"  free:     %"PRIu64"\n"
+		       "  maxhash:   %-10"PRIu64"  maxlen:   %"PRIu64"\n"
+		       "  add:       %-10"PRIu64"  remove:   %"PRIu64"\n"
+		       "  f_add:     %-10"PRIu64"  f_remove: %"PRIu64"\n",
+		       (uint64_t)(fdir_infos.collision), (uint64_t)(fdir_infos.free),
+		       (uint64_t)(fdir_infos.maxhash), (uint64_t)(fdir_infos.maxlen),
+		       fdir_infos.add, fdir_infos.remove,
+		       fdir_infos.f_add, fdir_infos.f_remove);
+#ifdef RTE_LIBRTE_I40E_PMD
+	}
+#endif /* RTE_LIBRTE_I40E_PMD */
 	printf("  %s############################%s\n",
 	       fdir_stats_border, fdir_stats_border);
 }
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index a112559..f36866a 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -1688,6 +1688,28 @@  init_port_config(void)
 		port = &ports[pid];
 		port->dev_conf.rxmode = rx_mode;
 		port->dev_conf.fdir_conf = fdir_conf;
+#ifdef RTE_LIBRTE_I40E_PMD
+#define I40E_FDIR_NB_MBUF          4
+#define I40E_FDIR_MBUF_SIZE        (512 + sizeof(struct rte_mbuf))
+#define I40E_FDIR_PKT_LEN          512
+#define MEMPOOL_CACHE_SIZE         256
+#define I40E_FDIR_MBUF_NAME        "FDIR_MBUF_POOL"
+
+		port->i40e_fdir_mp = rte_mempool_lookup(I40E_FDIR_MBUF_NAME);
+		if (port->i40e_fdir_mp == NULL) {
+			port->i40e_fdir_mp = rte_mempool_create(I40E_FDIR_MBUF_NAME,
+				I40E_FDIR_NB_MBUF, I40E_FDIR_MBUF_SIZE,
+				MEMPOOL_CACHE_SIZE,
+				sizeof(struct rte_pktmbuf_pool_private),
+				rte_pktmbuf_pool_init, NULL,
+				rte_pktmbuf_init, NULL,
+				0, 0);
+
+			if (port->i40e_fdir_mp == NULL)
+				printf("error: Cannot init mbuf pool for"
+					"i40e flow director.\n");
+		}
+#endif /* RTE_LIBRTE_I40E_PMD */
 		if (nb_rxq > 1) {
 			port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL;
 			port->dev_conf.rx_adv_conf.rss_conf.rss_hf = rss_hf;
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index b8322a2..ddcc9e9 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -73,6 +73,9 @@  int main(int argc, char **argv);
 #define NUMA_NO_CONFIG 0xFF
 #define UMA_NO_CONFIG  0xFF
 
+#define BYTES_PER_WORD  2
+#define IPV6_ADDR_LEN 16
+
 typedef uint8_t  lcoreid_t;
 typedef uint8_t  portid_t;
 typedef uint16_t queueid_t;
@@ -155,6 +158,9 @@  struct rte_port {
 	uint8_t			dcb_flag;   /**< enable dcb */
 	struct rte_eth_rxconf   rx_conf;    /**< rx configuration */
 	struct rte_eth_txconf   tx_conf;    /**< tx configuration */
+#ifdef RTE_LIBRTE_I40E_PMD
+	struct rte_mempool      *i40e_fdir_mp;  /**< mempool used for fdir programing */
+#endif /* RTE_LIBRTE_I40E_PMD */
 };
 
 /**
@@ -352,6 +358,57 @@  extern uint32_t param_total_num_mbufs;
 
 extern struct rte_fdir_conf fdir_conf;
 
+#ifdef RTE_LIBRTE_I40E_PMD
+struct ipv4_udp_flow {
+	uint32_t src_ip;         /**< IPv4 source address to match. */
+	uint32_t dst_ip;         /**< IPv4 destination address to match. */
+	uint16_t src_port;       /**< UDP Source port to match. */
+	uint16_t dst_port;       /**< UDP Destination port to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+
+struct ipv4_tcp_flow {
+	uint32_t src_ip;         /**< IPv4 source address to match. */
+	uint32_t dst_ip;         /**< IPv4 destination address to match. */
+	uint16_t src_port;       /**< TCP Source port to match. */
+	uint16_t dst_port;       /**< TCP Destination port to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+
+struct ipv4_other_flow {
+	uint32_t src_ip;         /**< IPv4 source address to match. */
+	uint32_t dst_ip;         /**< IPv4 destination address to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+
+struct ipv6_udp_flow {
+	uint32_t src_ip[4];      /**< IPv6 source address to match. */
+	uint32_t dst_ip[4];      /**< IPv6 destination address to match. */
+	uint16_t src_port;       /**< UDP Source port to match. */
+	uint16_t dst_port;       /**< UDP Destination port to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+
+struct ipv6_tcp_flow {
+	uint32_t src_ip[4];      /**< IPv6 source address to match. */
+	uint32_t dst_ip[4];      /**< IPv6 destination address to match. */
+	uint16_t src_port;       /**< TCP Source port to match. */
+	uint16_t dst_port;       /**< TCP Destination port to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+
+struct ipv6_other_flow {
+	uint32_t src_ip[4];      /**< IPv6 source address to match. */
+	uint32_t dst_ip[4];      /**< IPv6 destination address to match. */
+	uint8_t num_flexwords;   /**< number of the flexwords. */
+	uint16_t flexwords[8];   /**< flexwords in payload. */
+};
+#endif /* RTE_LIBRTE_I40E_PMD */
 /*
  * Configuration of packet segments used by the "txonly" processing engine.
  */