[dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support

Jingjing Wu jingjing.wu at intel.com
Fri Aug 1 09:08:35 CEST 2014


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 command to support flushing flow director table

Signed-off-by: jingjing.wu <jingjing.wu at 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(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 345be11..bf7e45c 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>
@@ -655,6 +663,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 */
 		);
 	}
 }
@@ -7304,6 +7331,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,
+				 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,
+				 udp4_flow.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,
+				 tcp4_flow.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,
+				 ip6_flow.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,
+				 udp6_flow.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,
+				 tcp6_flow.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 */
@@ -7429,6 +8089,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 c72f6ee..4c40afe 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 e8a4b45..d0d4fc1 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -1676,6 +1676,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 ac86bfe..1e6d16f 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.
  */
-- 
1.8.1.4



More information about the dev mailing list