DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville
@ 2014-08-01  7:08 Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 1/6] i40e: flow director resource reserve and initialize on i40e Jingjing Wu
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

The patch set supports flow director programming on fortville.
It includes:
 - reserve i40e resources for flow director, such as queue and vsi.
 - support the new ethdev AP Irx_classification_filter_ctl for all 
   the configuration or queries for receive classification filters.
 - support programming 6 flow types for the flow director filters,
   which is called PCTYPE in fortville: ipv4, tcpv4, udpv4, ipv6,
   tcpv6, udpv6.
 - support flushing flow director table (all filters).
 - support match statistics and FD ID report.
 - all fix the the Marco conflict between rte_ip.h and netinet/in.h. 

jingjing.wu (6):
  i40e: flow director resource reserve and initialize on i40e
  lib/librte_net: fix the Marco conflict between rte_ip.h and netinet/in.h
  ethdev: define new ethdev API rx_classification_filter_ctl
  i40e: function implement in i40e for flow director filter programming
  app/test-pmd: add commands and config functions for i40e flow director support
  i40e: support FD ID report and match counter for i40e flow director

 app/test-pmd/cmdline.c              | 665 ++++++++++++++++++++++++++++++++++++
 app/test-pmd/config.c               |  54 ++-
 app/test-pmd/testpmd.c              |  22 ++
 app/test-pmd/testpmd.h              |  57 ++++
 lib/librte_ether/Makefile           |   3 +-
 lib/librte_ether/rte_eth_features.h |  64 ++++
 lib/librte_ether/rte_ethdev.c       |  19 +-
 lib/librte_ether/rte_ethdev.h       | 108 +++---
 lib/librte_net/rte_ip.h             |   5 +-
 lib/librte_pmd_i40e/Makefile        |   5 +
 lib/librte_pmd_i40e/i40e_ethdev.c   |  98 +++++-
 lib/librte_pmd_i40e/i40e_ethdev.h   |  32 +-
 lib/librte_pmd_i40e/i40e_fdir.c     | 355 +++++++++++++++++++
 lib/librte_pmd_i40e/i40e_rxtx.c     | 176 +++++++++-
 lib/librte_pmd_i40e/rte_i40e.h      | 125 +++++++
 15 files changed, 1727 insertions(+), 61 deletions(-)
 create mode 100644 lib/librte_ether/rte_eth_features.h
 create mode 100644 lib/librte_pmd_i40e/i40e_fdir.c
 create mode 100644 lib/librte_pmd_i40e/rte_i40e.h

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 1/6] i40e: flow director resource reserve and initialize on i40e
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 2/6] lib/librte_net: fix the Marco conflict Jingjing Wu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

flow director resource reserve and initialize on i40e, it includes
 - queue initialization and switch on and vsi creation during setup
 - queue vsi for flow director release during close


Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/Makefile      |   1 +
 lib/librte_pmd_i40e/i40e_ethdev.c |  40 +++++++++--
 lib/librte_pmd_i40e/i40e_ethdev.h |  22 ++++++-
 lib/librte_pmd_i40e/i40e_fdir.c   | 135 ++++++++++++++++++++++++++++++++++++++
 lib/librte_pmd_i40e/i40e_rxtx.c   | 127 +++++++++++++++++++++++++++++++++++
 5 files changed, 318 insertions(+), 7 deletions(-)
 create mode 100644 lib/librte_pmd_i40e/i40e_fdir.c

diff --git a/lib/librte_pmd_i40e/Makefile b/lib/librte_pmd_i40e/Makefile
index 4b31675..6537654 100644
--- a/lib/librte_pmd_i40e/Makefile
+++ b/lib/librte_pmd_i40e/Makefile
@@ -87,6 +87,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev_vf.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_pf.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_fdir.c
 # this lib depends upon:
 DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_eal lib/librte_ether
 DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_mempool lib/librte_mbuf
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 9ed31b5..47125c7 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -516,6 +516,7 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 
 err_setup_pf_switch:
 	rte_free(pf->main_vsi);
+	i40e_fdir_teardown(pf);
 err_get_mac_addr:
 err_configure_lan_hmc:
 	(void)i40e_shutdown_lan_hmc(hw);
@@ -728,6 +729,7 @@ i40e_dev_close(struct rte_eth_dev *dev)
 
 	/* release all the existing VSIs and VEBs */
 	i40e_vsi_release(pf->main_vsi);
+	i40e_fdir_teardown(pf);
 
 	/* shutdown the adminq */
 	i40e_aq_queue_shutdown(hw, true);
@@ -2262,7 +2264,11 @@ i40e_vsi_release(struct i40e_vsi *vsi)
 	TAILQ_FOREACH(f, &vsi->mac_list, next)
 		rte_free(f);
 
-	if (vsi->type != I40E_VSI_MAIN) {
+	/*
+	 * For FDIR vsi, there is not actual HW VSI needed, no need to
+	 * call adminq and removing fromtailq.
+	 */
+	if (vsi->type != I40E_VSI_MAIN && vsi->type != I40E_VSI_FDIR) {
 		/* Remove vsi from parent's sibling list */
 		if (vsi->parent_vsi == NULL || vsi->parent_vsi->veb == NULL) {
 			PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL\n");
@@ -2379,7 +2385,8 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	struct ether_addr broadcast =
 		{.addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
 
-	if (type != I40E_VSI_MAIN && uplink_vsi == NULL) {
+	if (type != I40E_VSI_MAIN && type != I40E_VSI_FDIR &&
+		uplink_vsi == NULL) {
 		PMD_DRV_LOG(ERR, "VSI setup failed, "
 			"VSI link shouldn't be NULL\n");
 		return NULL;
@@ -2392,7 +2399,8 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	}
 
 	/* If uplink vsi didn't setup VEB, create one first */
-	if (type != I40E_VSI_MAIN && uplink_vsi->veb == NULL) {
+	if (type != I40E_VSI_MAIN && type != I40E_VSI_FDIR &&
+		uplink_vsi->veb == NULL) {
 		uplink_vsi->veb = i40e_veb_setup(pf, uplink_vsi);
 
 		if (NULL == uplink_vsi->veb) {
@@ -2420,6 +2428,9 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	case I40E_VSI_SRIOV :
 		vsi->nb_qps = pf->vf_nb_qps;
 		break;
+	case I40E_VSI_FDIR:
+		vsi->nb_qps = pf->fdir_nb_qps;
+		break;
 	default:
 		goto fail_mem;
 	}
@@ -2432,7 +2443,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
 	vsi->base_queue = ret;
 
 	/* VF has MSIX interrupt in VF range, don't allocate here */
-	if (type != I40E_VSI_SRIOV) {
+	if (type != I40E_VSI_SRIOV && type != I40E_VSI_FDIR) {
 		ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
 		if (ret < 0) {
 			PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
@@ -2561,8 +2572,16 @@ i40e_vsi_setup(struct i40e_pf *pf,
 		 * Since VSI is not created yet, only configure parameter,
 		 * will add vsi below.
 		 */
-	}
-	else {
+	} else if (type == I40E_VSI_FDIR) {
+		vsi->info.valid_sections = 0;
+		vsi->seid = 0;
+		vsi->vsi_id = 0;
+		/*
+		 * No actual HW VSI needed, will return here without
+		 * calling adminq and adding to tailq.
+		 */
+		return vsi;
+	} else {
 		PMD_DRV_LOG(ERR, "VSI: Not support other type VSI yet\n");
 		goto fail_msix_alloc;
 	}
@@ -2749,6 +2768,13 @@ i40e_pf_setup(struct i40e_pf *pf)
 		return ret;
 	}
 
+	if (pf->flags & I40E_FLAG_FDIR) {
+		ret = i40e_fdir_setup(pf);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to setup flow director\n");
+			pf->flags &= ~I40E_FLAG_FDIR;
+		}
+	}
 	/* VSI setup */
 	vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN, NULL, 0);
 	if (!vsi) {
@@ -2762,6 +2788,8 @@ i40e_pf_setup(struct i40e_pf *pf)
 	/* Configure filter control */
 	memset(&settings, 0, sizeof(settings));
 	settings.hash_lut_size = I40E_HASH_LUT_SIZE_128;
+	if (pf->flags & I40E_FLAG_FDIR)
+		settings.enable_fdir = TRUE;
 	/* Enable ethtype and macvlan filters */
 	settings.enable_ethtype = TRUE;
 	settings.enable_macvlan = TRUE;
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
index 64deef2..c2c7fa9 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -46,11 +46,12 @@
 /* number of VSIs and queue default setting */
 #define I40E_MAX_QP_NUM_PER_VF    16
 #define I40E_DEFAULT_QP_NUM_VMDQ  64
-#define I40E_DEFAULT_QP_NUM_FDIR  64
+#define I40E_DEFAULT_QP_NUM_FDIR  1
 #define I40E_UINT32_BIT_SIZE      (CHAR_BIT * sizeof(uint32_t))
 #define I40E_VFTA_SIZE            (4096 / I40E_UINT32_BIT_SIZE)
 /* Default TC traffic in case DCB is not enabled */
 #define I40E_DEFAULT_TCMAP        0x1
+#define I40E_FDIR_QUEUE_ID        0
 
 /* i40e flags */
 #define I40E_FLAG_RSS                   (1ULL << 0)
@@ -189,6 +190,16 @@ struct i40e_pf_vf {
 };
 
 /*
+ *  A structure used to define fields of a FDIR related info.
+ */
+struct i40e_fdir_info {
+	struct i40e_vsi *fdir_vsi;     /* pointer to fdir VSI structure */
+	uint16_t match_counter_index;  /* Statistic counter index used for fdir*/
+	struct i40e_tx_queue *txq;
+	struct i40e_rx_queue *rxq;
+};
+
+/*
  * Structure to store private data specific for PF instance.
  */
 struct i40e_pf {
@@ -216,6 +227,7 @@ struct i40e_pf {
 	uint16_t vmdq_nb_qps; /* The number of queue pairs of VMDq */
 	uint16_t vf_nb_qps; /* The number of queue pairs of VF */
 	uint16_t fdir_nb_qps; /* The number of queue pairs of Flow Director */
+	struct i40e_fdir_info fdir; /* flow director info */
 };
 
 enum pending_msg {
@@ -312,6 +324,14 @@ void i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi);
 int i40e_vsi_vlan_pvid_set(struct i40e_vsi *vsi,
 				struct i40e_vsi_vlan_pvid_info *info);
 int i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on);
+enum i40e_status_code
+i40e_fdir_setup_tx_resources(struct i40e_pf *pf,
+				    unsigned int socket_id);
+enum i40e_status_code
+i40e_fdir_setup_rx_resources(struct i40e_pf *pf,
+				    unsigned int socket_id);
+int i40e_fdir_setup(struct i40e_pf *pf);
+void i40e_fdir_teardown(struct i40e_pf *pf);
 
 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
diff --git a/lib/librte_pmd_i40e/i40e_fdir.c b/lib/librte_pmd_i40e/i40e_fdir.c
new file mode 100644
index 0000000..ecb4a95
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_fdir.c
@@ -0,0 +1,135 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_mbuf.h>
+
+#include "i40e_logs.h"
+#include "i40e/i40e_type.h"
+#include "i40e_ethdev.h"
+#include "i40e_rxtx.h"
+
+#define I40E_COUNTER_PF           2
+#define I40E_COUNTER_INDEX_FDIR(pf_id)   (0 + (pf_id) * I40E_COUNTER_PF)
+
+/*
+ * i40e_fdir_setup - reserve and initialize the Flow Director resources
+ * @pf: board private structure
+ **/
+int
+i40e_fdir_setup(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_vsi *vsi;
+	int err = I40E_SUCCESS;
+
+	PMD_DRV_LOG(INFO, "FDIR HW Capabilities, guaranteed = %u,"
+			"best_effort = %u.\n",
+			hw->func_caps.fd_filters_guaranteed,
+			hw->func_caps.fd_filters_best_effort);
+
+	/* find existing or make new FDIR VSI */
+	vsi = pf->fdir.fdir_vsi;
+	if (!vsi) {
+		vsi = i40e_vsi_setup(pf, I40E_VSI_FDIR, NULL, 0);
+		if (!vsi) {
+			PMD_DRV_LOG(ERR, "Couldn't create FDIR VSI\n");
+			return I40E_ERR_NO_AVAILABLE_VSI;
+		}
+		pf->fdir.fdir_vsi = vsi;
+	}
+	/*dev queue setup*/
+	err = i40e_fdir_setup_tx_resources(pf, 0);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to setup fdir TX resources\n");
+		goto fail_setup_tx;
+	}
+	err = i40e_fdir_setup_rx_resources(pf, 0);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to setup fdir TX resources\n");
+		goto fail_setup_rx;
+	}
+
+	err = i40e_tx_queue_init(pf->fdir.txq);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to do fdir TX initialization\n");
+		goto fail_mem;
+	}
+
+	/* need switch on before dev start*/
+	err = i40e_switch_tx_queue(hw, vsi->base_queue + I40E_FDIR_QUEUE_ID, TRUE);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to do fdir TX initialization\n");
+		goto fail_mem;
+	}
+	pf->fdir.match_counter_index = I40E_COUNTER_INDEX_FDIR(hw->pf_id);
+	return I40E_SUCCESS;
+
+fail_mem:
+	i40e_dev_rx_queue_release(pf->fdir.rxq);
+fail_setup_rx:
+	i40e_dev_tx_queue_release(pf->fdir.txq);
+fail_setup_tx:
+	i40e_vsi_release(vsi);
+	return err;
+}
+
+
+/*
+ * i40e_fdir_teardown - release the Flow Director resources
+ * @pf: board private structure
+ */
+void
+i40e_fdir_teardown(struct i40e_pf *pf)
+{
+	struct i40e_vsi *vsi;
+
+	vsi = pf->fdir.fdir_vsi;
+	i40e_dev_rx_queue_release(pf->fdir.rxq);
+	pf->fdir.rxq = NULL;
+	i40e_dev_tx_queue_release(pf->fdir.txq);
+	pf->fdir.txq = NULL;
+	i40e_vsi_release(vsi);
+	pf->fdir.fdir_vsi = NULL;
+	return;
+}
diff --git a/lib/librte_pmd_i40e/i40e_rxtx.c b/lib/librte_pmd_i40e/i40e_rxtx.c
index 83b9462..ad60d20 100644
--- a/lib/librte_pmd_i40e/i40e_rxtx.c
+++ b/lib/librte_pmd_i40e/i40e_rxtx.c
@@ -1978,6 +1978,8 @@ i40e_tx_queue_init(struct i40e_tx_queue *txq)
 	tx_ctx.base = txq->tx_ring_phys_addr / I40E_QUEUE_BASE_ADDR_UNIT;
 	tx_ctx.qlen = txq->nb_tx_desc;
 	tx_ctx.rdylist = rte_le_to_cpu_16(vsi->info.qs_handle[0]);
+	if (vsi->type == I40E_VSI_FDIR)
+		tx_ctx.fd_ena = TRUE;
 
 	err = i40e_clear_lan_tx_queue_context(hw, pf_q);
 	if (err != I40E_SUCCESS) {
@@ -2201,3 +2203,128 @@ i40e_dev_clear_queues(struct rte_eth_dev *dev)
 		i40e_reset_rx_queue(dev->data->rx_queues[i]);
 	}
 }
+
+enum i40e_status_code
+i40e_fdir_setup_tx_resources(struct i40e_pf *pf,
+				    unsigned int socket_id)
+{
+	struct i40e_tx_queue *txq;
+	const struct rte_memzone *tz = NULL;
+	uint32_t ring_size;
+	struct rte_eth_dev *dev = pf->adapter->eth_dev;
+
+#define I40E_FDIR_NUM_TX_DESC  I40E_MIN_RING_DESC
+	if (!pf) {
+		PMD_DRV_LOG(ERR, "PF is not available");
+		return I40E_ERR_BAD_PTR;
+	}
+
+	/* Allocate the TX queue data structure. */
+	txq = rte_zmalloc_socket("i40e fdir tx queue",
+				  sizeof(struct i40e_tx_queue),
+				  CACHE_LINE_SIZE,
+				  socket_id);
+	if (!txq) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+					"tx queue structure\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	/* Allocate TX hardware ring descriptors. */
+	ring_size = sizeof(struct i40e_tx_desc) * I40E_FDIR_NUM_TX_DESC;
+	ring_size = RTE_ALIGN(ring_size, I40E_DMA_MEM_ALIGN);
+
+	tz = i40e_ring_dma_zone_reserve(dev,
+					"fdir_tx_ring",
+					I40E_FDIR_QUEUE_ID,
+					ring_size,
+					socket_id);
+	if (!tz) {
+		i40e_dev_tx_queue_release(txq);
+		PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	txq->nb_tx_desc = I40E_FDIR_NUM_TX_DESC;
+	txq->queue_id = I40E_FDIR_QUEUE_ID;
+	txq->reg_idx = pf->fdir.fdir_vsi->base_queue + I40E_FDIR_QUEUE_ID;
+	txq->vsi = pf->fdir.fdir_vsi;
+
+#ifdef RTE_LIBRTE_XEN_DOM0
+	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+#else
+	txq->tx_ring_phys_addr = (uint64_t)tz->phys_addr;
+#endif
+	txq->tx_ring = (struct i40e_tx_desc *)tz->addr;
+	/*
+	 * don't need to allocate software ring and reset for the fdir
+	 * program queue just set the queue has been configured.
+	 */
+	txq->q_set = TRUE;
+	pf->fdir.txq = txq;
+
+	return I40E_SUCCESS;
+}
+
+enum i40e_status_code
+i40e_fdir_setup_rx_resources(struct i40e_pf *pf,
+				    unsigned int socket_id)
+{
+	struct i40e_rx_queue *rxq;
+	const struct rte_memzone *rz = NULL;
+	uint32_t ring_size;
+	struct rte_eth_dev *dev = pf->adapter->eth_dev;
+
+#define I40E_FDIR_NUM_RX_DESC  I40E_MIN_RING_DESC
+	if (!pf) {
+		PMD_DRV_LOG(ERR, "PF is not available");
+		return I40E_ERR_BAD_PTR;
+	}
+
+	/* Allocate the TX queue data structure. */
+	rxq = rte_zmalloc_socket("i40e fdir rx queue",
+				  sizeof(struct i40e_rx_queue),
+				  CACHE_LINE_SIZE,
+				  socket_id);
+	if (!rxq) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+					"rx queue structure\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	/* Allocate TX hardware ring descriptors. */
+	ring_size = sizeof(union i40e_rx_desc) * I40E_FDIR_NUM_RX_DESC;
+	ring_size = RTE_ALIGN(ring_size, I40E_DMA_MEM_ALIGN);
+
+	rz = i40e_ring_dma_zone_reserve(dev,
+					"fdir_rx_ring",
+					I40E_FDIR_QUEUE_ID,
+					ring_size,
+					socket_id);
+	if (!rz) {
+		i40e_dev_rx_queue_release(rxq);
+		PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for RX\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	rxq->nb_rx_desc = I40E_FDIR_NUM_RX_DESC;
+	rxq->queue_id = I40E_FDIR_QUEUE_ID;
+	rxq->reg_idx = pf->fdir.fdir_vsi->base_queue + I40E_FDIR_QUEUE_ID;
+	rxq->vsi = pf->fdir.fdir_vsi;
+
+#ifdef RTE_LIBRTE_XEN_DOM0
+	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+#else
+	rxq->rx_ring_phys_addr = (uint64_t)rz->phys_addr;
+#endif
+	rxq->rx_ring = (union i40e_rx_desc *)rz->addr;
+
+	/*
+	 * Don't need to allocate software ring and reset for the fdir
+	 * rx queue, just set the queue has been configured.
+	 */
+	rxq->q_set = TRUE;
+	pf->fdir.rxq = rxq;
+
+	return I40E_SUCCESS;
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 2/6] lib/librte_net: fix the Marco conflict
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 1/6] i40e: flow director resource reserve and initialize on i40e Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 3/6] ethdev: define new ethdev API rx_classification_filter_ctl Jingjing Wu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

fix the Marco conflict between rte_ip.h and netinet/in.h

Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
---
 lib/librte_net/rte_ip.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h
index e3f65c1..0f0b3b0 100644
--- a/lib/librte_net/rte_ip.h
+++ b/lib/librte_net/rte_ip.h
@@ -116,6 +116,8 @@ struct ipv4_hdr {
 
 #define	IPV4_HDR_OFFSET_UNITS	8
 
+#ifndef _NETINET_IN_H
+#ifndef _NETINET_IN_H_
 /* IPv4 protocols */
 #define IPPROTO_IP         0  /**< dummy for IP */
 #define IPPROTO_HOPOPTS    0  /**< IP6 hop-by-hop options */
@@ -226,7 +228,8 @@ struct ipv4_hdr {
 #define IPPROTO_DIVERT   254  /**< divert pseudo-protocol */
 #define IPPROTO_RAW      255  /**< raw IP packet */
 #define IPPROTO_MAX      256  /**< maximum protocol number */
-
+#endif
+#endif
 /*
  * IPv4 address types
  */
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 3/6] ethdev: define new ethdev API rx_classification_filter_ctl
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 1/6] i40e: flow director resource reserve and initialize on i40e Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 2/6] lib/librte_net: fix the Marco conflict Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 4/6] i40e: function implement in i40e for flow director filter programming Jingjing Wu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

support a new ethdev API rx_classification_filter_ctl for all 
the configuration or queries for receive classification filters.
this patch supports commands the API used below:
  RTE_CMD_FDIR_RULE_ADD
  RTE_CMD_FDIR_RULE_DEL
  RTE_CMD_FDIR_FLUSH
  RTE_CMD_FDIR_INFO_GET

Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
---
 lib/librte_ether/Makefile           |   3 +-
 lib/librte_ether/rte_eth_features.h |  64 +++++++++++++++++++++
 lib/librte_ether/rte_ethdev.c       |  19 ++++++-
 lib/librte_ether/rte_ethdev.h       | 108 +++++++++++++++++++++++-------------
 4 files changed, 154 insertions(+), 40 deletions(-)
 create mode 100644 lib/librte_ether/rte_eth_features.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index b310f8b..03dec8a 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -46,8 +46,9 @@ SRCS-y += rte_ethdev.c
 #
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
+SYMLINK-y-include += rte_eth_features.h
 
 # this lib depends upon:
-DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
+DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf lib/librte_net
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ether/rte_eth_features.h b/lib/librte_ether/rte_eth_features.h
new file mode 100644
index 0000000..ba5eccb
--- /dev/null
+++ b/lib/librte_ether/rte_eth_features.h
@@ -0,0 +1,64 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_FEATURES_H_
+#define _RTE_ETH_FEATURES_H_
+
+/**
+ * @file
+ *
+ * Ethernet device specific features
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Commands defined for NIC specific features */
+enum rte_eth_command {
+	RTE_CMD_UNKNOWN = 0,
+	RTE_CMD_FDIR_RULE_ADD,
+	/**< Command to add a new FDIR filter rule. */
+	RTE_CMD_FDIR_RULE_DEL,
+	/**< Command to delete a FDIR filter rule. */
+	RTE_CMD_FDIR_FLUSH,
+	/**< Command to clear all FDIR filter rules. */
+	RTE_CMD_FDIR_INFO_GET,
+	/**< Command to get FDIR information. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_FEATURES_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index fd1010a..10a08de 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -41,7 +41,6 @@
 #include <errno.h>
 #include <stdint.h>
 #include <inttypes.h>
-#include <netinet/in.h>
 
 #include <rte_byteorder.h>
 #include <rte_log.h>
@@ -66,6 +65,7 @@
 #include <rte_errno.h>
 #include <rte_spinlock.h>
 #include <rte_string_fns.h>
+#include <rte_ip.h>
 
 #include "rte_ether.h"
 #include "rte_ethdev.h"
@@ -3002,3 +3002,20 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	return (*dev->dev_ops->get_flex_filter)(dev, index, filter,
 						rx_queue);
 }
+
+int
+rte_eth_dev_rx_classification_filter_ctl(uint8_t port_id,
+					 enum rte_eth_command cmd,
+					 void *args)
+{
+	struct rte_eth_dev *dev;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_classification_filter_ctl,
+								-ENOTSUP);
+	return (*dev->dev_ops->rx_classification_filter_ctl)(dev, cmd, args);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 50df654..a2d9596 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -177,6 +177,7 @@ extern "C" {
 #include <rte_pci.h>
 #include <rte_mbuf.h>
 #include "rte_ether.h"
+#include "rte_eth_features.h"
 
 /**
  * A structure used to retrieve statistics for an Ethernet port.
@@ -345,47 +346,47 @@ struct rte_eth_rss_conf {
 #define ETH_RSS_IPV4_UDP_SHIFT                6
 #define ETH_RSS_IPV6_UDP_SHIFT                7
 #define ETH_RSS_IPV6_UDP_EX_SHIFT             8
-/* for 40G only */
-#define ETH_RSS_NONF_IPV4_UDP_SHIFT           31
-#define ETH_RSS_NONF_IPV4_TCP_SHIFT           33
-#define ETH_RSS_NONF_IPV4_SCTP_SHIFT          34
-#define ETH_RSS_NONF_IPV4_OTHER_SHIFT         35
-#define ETH_RSS_FRAG_IPV4_SHIFT               36
-#define ETH_RSS_NONF_IPV6_UDP_SHIFT           41
-#define ETH_RSS_NONF_IPV6_TCP_SHIFT           43
-#define ETH_RSS_NONF_IPV6_SCTP_SHIFT          44
-#define ETH_RSS_NONF_IPV6_OTHER_SHIFT         45
-#define ETH_RSS_FRAG_IPV6_SHIFT               46
-#define ETH_RSS_FCOE_OX_SHIFT                 48
-#define ETH_RSS_FCOE_RX_SHIFT                 49
-#define ETH_RSS_FCOE_OTHER_SHIFT              50
-#define ETH_RSS_L2_PAYLOAD_SHIFT              63
+/* Packet Classification Type for 40G only */
+#define ETH_PCTYPE_NONF_IPV4_UDP              31
+#define ETH_PCTYPE_NONF_IPV4_TCP              33
+#define ETH_PCTYPE_NONF_IPV4_SCTP             34
+#define ETH_PCTYPE_NONF_IPV4_OTHER            35
+#define ETH_PCTYPE_FRAG_IPV4                  36
+#define ETH_PCTYPE_NONF_IPV6_UDP              41
+#define ETH_PCTYPE_NONF_IPV6_TCP              43
+#define ETH_PCTYPE_NONF_IPV6_SCTP             44
+#define ETH_PCTYPE_NONF_IPV6_OTHER            45
+#define ETH_PCTYPE_FRAG_IPV6                  46
+#define ETH_PCTYPE_FCOE_OX                    48 /* not used */
+#define ETH_PCTYPE_FCOE_RX                    49 /* not used */
+#define ETH_PCTYPE_FCOE_OTHER                 50 /* not used */
+#define ETH_PCTYPE_L2_PAYLOAD                 63
 
 /* for 1G & 10G */
-#define ETH_RSS_IPV4                    ((uint16_t)1 << ETH_RSS_IPV4_SHIFT)
-#define ETH_RSS_IPV4_TCP                ((uint16_t)1 << ETH_RSS_IPV4_TCP_SHIFT)
-#define ETH_RSS_IPV6                    ((uint16_t)1 << ETH_RSS_IPV6_SHIFT)
-#define ETH_RSS_IPV6_EX                 ((uint16_t)1 << ETH_RSS_IPV6_EX_SHIFT)
-#define ETH_RSS_IPV6_TCP                ((uint16_t)1 << ETH_RSS_IPV6_TCP_SHIFT)
-#define ETH_RSS_IPV6_TCP_EX             ((uint16_t)1 << ETH_RSS_IPV6_TCP_EX_SHIFT)
-#define ETH_RSS_IPV4_UDP                ((uint16_t)1 << ETH_RSS_IPV4_UDP_SHIFT)
-#define ETH_RSS_IPV6_UDP                ((uint16_t)1 << ETH_RSS_IPV6_UDP_SHIFT)
-#define ETH_RSS_IPV6_UDP_EX             ((uint16_t)1 << ETH_RSS_IPV6_UDP_EX_SHIFT)
+#define ETH_RSS_IPV4                    (1 << ETH_RSS_IPV4_SHIFT)
+#define ETH_RSS_IPV4_TCP                (1 << ETH_RSS_IPV4_TCP_SHIFT)
+#define ETH_RSS_IPV6                    (1 << ETH_RSS_IPV6_SHIFT)
+#define ETH_RSS_IPV6_EX                 (1 << ETH_RSS_IPV6_EX_SHIFT)
+#define ETH_RSS_IPV6_TCP                (1 << ETH_RSS_IPV6_TCP_SHIFT)
+#define ETH_RSS_IPV6_TCP_EX             (1 << ETH_RSS_IPV6_TCP_EX_SHIFT)
+#define ETH_RSS_IPV4_UDP                (1 << ETH_RSS_IPV4_UDP_SHIFT)
+#define ETH_RSS_IPV6_UDP                (1 << ETH_RSS_IPV6_UDP_SHIFT)
+#define ETH_RSS_IPV6_UDP_EX             (1 << ETH_RSS_IPV6_UDP_EX_SHIFT)
 /* for 40G only */
-#define ETH_RSS_NONF_IPV4_UDP           ((uint64_t)1 << ETH_RSS_NONF_IPV4_UDP_SHIFT)
-#define ETH_RSS_NONF_IPV4_TCP           ((uint64_t)1 << ETH_RSS_NONF_IPV4_TCP_SHIFT)
-#define ETH_RSS_NONF_IPV4_SCTP          ((uint64_t)1 << ETH_RSS_NONF_IPV4_SCTP_SHIFT)
-#define ETH_RSS_NONF_IPV4_OTHER         ((uint64_t)1 << ETH_RSS_NONF_IPV4_OTHER_SHIFT)
-#define ETH_RSS_FRAG_IPV4               ((uint64_t)1 << ETH_RSS_FRAG_IPV4_SHIFT)
-#define ETH_RSS_NONF_IPV6_UDP           ((uint64_t)1 << ETH_RSS_NONF_IPV6_UDP_SHIFT)
-#define ETH_RSS_NONF_IPV6_TCP           ((uint64_t)1 << ETH_RSS_NONF_IPV6_TCP_SHIFT)
-#define ETH_RSS_NONF_IPV6_SCTP          ((uint64_t)1 << ETH_RSS_NONF_IPV6_SCTP_SHIFT)
-#define ETH_RSS_NONF_IPV6_OTHER         ((uint64_t)1 << ETH_RSS_NONF_IPV6_OTHER_SHIFT)
-#define ETH_RSS_FRAG_IPV6               ((uint64_t)1 << ETH_RSS_FRAG_IPV6_SHIFT)
-#define ETH_RSS_FCOE_OX                 ((uint64_t)1 << ETH_RSS_FCOE_OX_SHIFT) /* not used */
-#define ETH_RSS_FCOE_RX                 ((uint64_t)1 << ETH_RSS_FCOE_RX_SHIFT) /* not used */
-#define ETH_RSS_FCOE_OTHER              ((uint64_t)1 << ETH_RSS_FCOE_OTHER_SHIFT) /* not used */
-#define ETH_RSS_L2_PAYLOAD              ((uint64_t)1 << ETH_RSS_L2_PAYLOAD_SHIFT)
+#define ETH_RSS_NONF_IPV4_UDP           (1ULL << ETH_PCTYPE_NONF_IPV4_UDP)
+#define ETH_RSS_NONF_IPV4_TCP           (1ULL << ETH_PCTYPE_NONF_IPV4_TCP)
+#define ETH_RSS_NONF_IPV4_SCTP          (1ULL << ETH_PCTYPE_NONF_IPV4_SCTP)
+#define ETH_RSS_NONF_IPV4_OTHER         (1ULL << ETH_PCTYPE_NONF_IPV4_OTHER)
+#define ETH_RSS_FRAG_IPV4               (1ULL << ETH_PCTYPE_FRAG_IPV4)
+#define ETH_RSS_NONF_IPV6_UDP           (1ULL << ETH_PCTYPE_NONF_IPV6_UDP)
+#define ETH_RSS_NONF_IPV6_TCP           (1ULL << ETH_PCTYPE_NONF_IPV6_TCP)
+#define ETH_RSS_NONF_IPV6_SCTP          (1ULL << ETH_PCTYPE_NONF_IPV6_SCTP)
+#define ETH_RSS_NONF_IPV6_OTHER         (1ULL << ETH_PCTYPE_NONF_IPV6_OTHER)
+#define ETH_RSS_FRAG_IPV6               (1ULL << ETH_PCTYPE_FRAG_IPV6)
+#define ETH_RSS_FCOE_OX                 (1ULL << ETH_PCTYPE_FCOE_OX)
+#define ETH_RSS_FCOE_RX                 (1ULL << ETH_PCTYPE_FCOE_RX)
+#define ETH_RSS_FCOE_OTHER              (1ULL << ETH_PCTYPE_FCOE_OTHER)
+#define ETH_RSS_L2_PAYLOAD              (1ULL << ETH_PCTYPE_L2_PAYLOAD)
 
 #define ETH_RSS_IP ( \
 		ETH_RSS_IPV4 | \
@@ -1361,6 +1362,11 @@ typedef int (*eth_get_flex_filter_t)(struct rte_eth_dev *dev,
 			uint16_t *rx_queue);
 /**< @internal Get a flex filter rule on an Ethernet device */
 
+typedef int (*eth_rx_classification_filter_ctl_t)(struct rte_eth_dev *dev,
+						  enum rte_eth_command cmd,
+						  void *arg);
+/**< @internal receive classification filter control operations */
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -1467,6 +1473,8 @@ struct eth_dev_ops {
 	eth_add_flex_filter_t          add_flex_filter;      /**< add flex filter. */
 	eth_remove_flex_filter_t       remove_flex_filter;   /**< remove flex filter. */
 	eth_get_flex_filter_t          get_flex_filter;      /**< get flex filter. */
+	/*common ccontrol function for receive classification filters*/
+	eth_rx_classification_filter_ctl_t rx_classification_filter_ctl;
 };
 
 /**
@@ -3557,6 +3565,30 @@ int rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index);
 int rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 			struct rte_flex_filter *filter, uint16_t *rx_queue);
 
+
+/**
+ * Configure the receive classification filter, including hash function
+ * selection. The commands are NIC specific in its exported public header
+ * file. Different types of NIC may have different commands.
+ * All the supported commands are defined in 'rte_eth_features.h'.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param cmd
+ *   The command.
+ * @param args
+ *   A pointer to arguments defined specifically for the command.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if <port_id> is invalid.
+ *   - others depends on the specific command implementation.
+ */
+int rte_eth_dev_rx_classification_filter_ctl(uint8_t port_id,
+					     enum rte_eth_command cmd,
+					     void *args);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 4/6] i40e: function implement in i40e for flow director filter programming
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
                   ` (2 preceding siblings ...)
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 3/6] ethdev: define new ethdev API rx_classification_filter_ctl Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support Jingjing Wu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

support the API ops defined in ethdev, the behavior according to each command:

  RTE_CMD_FDIR_RULE_ADD: add a new FDIR filter rule.
  RTE_CMD_FDIR_RULE_DEL: delete a FDIR filter rule. 
  RTE_CMD_FDIR_FLUSH   : clear all FDIR filter rules.
  RTE_CMD_FDIR_INFO_GET: get FDIR information.

Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/Makefile      |   4 +
 lib/librte_pmd_i40e/i40e_ethdev.c |  53 +++++++++
 lib/librte_pmd_i40e/i40e_ethdev.h |  10 ++
 lib/librte_pmd_i40e/i40e_fdir.c   | 220 ++++++++++++++++++++++++++++++++++++++
 lib/librte_pmd_i40e/rte_i40e.h    | 125 ++++++++++++++++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 lib/librte_pmd_i40e/rte_i40e.h

diff --git a/lib/librte_pmd_i40e/Makefile b/lib/librte_pmd_i40e/Makefile
index 6537654..3da20c5 100644
--- a/lib/librte_pmd_i40e/Makefile
+++ b/lib/librte_pmd_i40e/Makefile
@@ -88,6 +88,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev_vf.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_pf.c
 SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_fdir.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_I40E_PMD)-include := rte_i40e.h
+
 # this lib depends upon:
 DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_eal lib/librte_ether
 DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_mempool lib/librte_mbuf
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 47125c7..c4637be 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -48,6 +48,7 @@
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
 #include <rte_dev.h>
+#include <rte_eth_features.h>
 
 #include "i40e_logs.h"
 #include "i40e/i40e_register_x710_int.h"
@@ -203,6 +204,9 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 				    struct rte_eth_rss_conf *rss_conf);
 static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 				      struct rte_eth_rss_conf *rss_conf);
+static int i40e_rx_classification_filter_ctl(struct rte_eth_dev *dev,
+					     enum rte_eth_command cmd,
+					     void *args);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
@@ -248,6 +252,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
 	.reta_query                   = i40e_dev_rss_reta_query,
 	.rss_hash_update              = i40e_dev_rss_hash_update,
 	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
+	.rx_classification_filter_ctl = i40e_rx_classification_filter_ctl,
 };
 
 static struct eth_driver rte_i40e_pmd = {
@@ -3984,3 +3989,51 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 
 	return 0;
 }
+
+static int
+i40e_rx_classification_filter_ctl(struct rte_eth_dev *dev,
+				  enum rte_eth_command cmd,
+				  void *args)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct rte_i40e_fdir_entry *fdir_entry;
+	struct rte_i40e_fdir_info *fdir_info;
+	int ret = I40E_SUCCESS;
+
+	switch (cmd) {
+	case RTE_CMD_FDIR_RULE_ADD:
+		if (args == NULL)
+			return I40E_ERR_PARAM;
+		fdir_entry = (struct rte_i40e_fdir_entry *)args;
+		ret = i40e_fdir_filter_programming(pf,
+			fdir_entry->soft_id,
+			&fdir_entry->input,
+			&fdir_entry->action,
+			TRUE);
+		break;
+	case RTE_CMD_FDIR_RULE_DEL:
+		if (args == NULL)
+			return I40E_ERR_PARAM;
+		fdir_entry = (struct rte_i40e_fdir_entry *)args;
+		ret = i40e_fdir_filter_programming(pf,
+			fdir_entry->soft_id,
+			&fdir_entry->input,
+			&fdir_entry->action,
+			FALSE);
+		break;
+	case RTE_CMD_FDIR_INFO_GET:
+		if (args == NULL)
+			return I40E_ERR_PARAM;
+		fdir_info = (struct rte_i40e_fdir_info *)args;
+		i40e_fdir_info_get(dev, fdir_info);
+		break;
+	case RTE_CMD_FDIR_FLUSH:
+		ret = i40e_fdir_flush(pf);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "unknown command type %u\n", cmd);
+		ret = I40E_ERR_PARAM;
+		break;
+	}
+	return ret;
+}
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
index c2c7fa9..7755f5a 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -34,6 +34,8 @@
 #ifndef _I40E_ETHDEV_H_
 #define _I40E_ETHDEV_H_
 
+#include "rte_i40e.h"
+
 #define I40E_AQ_LEN               32
 #define I40E_AQ_BUF_SZ            4096
 /* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
@@ -332,6 +334,14 @@ i40e_fdir_setup_rx_resources(struct i40e_pf *pf,
 				    unsigned int socket_id);
 int i40e_fdir_setup(struct i40e_pf *pf);
 void i40e_fdir_teardown(struct i40e_pf *pf);
+int i40e_fdir_flush(struct i40e_pf *pf);
+int i40e_fdir_filter_programming(struct i40e_pf *pf,
+			uint16_t soft_id,
+			struct rte_i40e_fdir_input *fdir_filter,
+			struct rte_i40e_fdir_action *fdir_action,
+			bool add);
+void i40e_fdir_info_get(struct rte_eth_dev *dev,
+			   struct rte_i40e_fdir_info *fdir);
 
 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
diff --git a/lib/librte_pmd_i40e/i40e_fdir.c b/lib/librte_pmd_i40e/i40e_fdir.c
index ecb4a95..373a366 100644
--- a/lib/librte_pmd_i40e/i40e_fdir.c
+++ b/lib/librte_pmd_i40e/i40e_fdir.c
@@ -48,10 +48,23 @@
 #include "i40e/i40e_type.h"
 #include "i40e_ethdev.h"
 #include "i40e_rxtx.h"
+/* Wait count and inteval for fdir filter programming */
+#define I40E_FDIR_WAIT_COUNT       10
+#define I40E_FDIR_WAIT_INTERVAL_US 1000
+/* Wait count and inteval for fdir filter flush */
+#define I40E_FDIR_FLUSH_RETRY       5
+#define I40E_FDIR_FLUSH_INTERVAL_MS 5000
 
 #define I40E_COUNTER_PF           2
 #define I40E_COUNTER_INDEX_FDIR(pf_id)   (0 + (pf_id) * I40E_COUNTER_PF)
 
+#ifndef RTE_MBUF_DATA_DMA_ADDR
+#define RTE_MBUF_DATA_DMA_ADDR(mb) \
+	((uint64_t)((mb)->buf_physaddr + \
+	(uint64_t)((char *)((mb)->pkt.data) - \
+	(char *)(mb)->buf_addr)))
+#endif
+
 /*
  * i40e_fdir_setup - reserve and initialize the Flow Director resources
  * @pf: board private structure
@@ -133,3 +146,210 @@ i40e_fdir_teardown(struct i40e_pf *pf)
 	pf->fdir.fdir_vsi = NULL;
 	return;
 }
+
+/*
+ * i40e_fdir_flush - clear all filters of Flow Director
+ * @pf: board private structure
+ */
+int
+i40e_fdir_flush(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	uint32_t reg;
+	uint16_t guarant_cnt, best_cnt;
+	int i;
+
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_1, I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
+	I40E_WRITE_FLUSH(hw);
+
+	for (i = 0; i < I40E_FDIR_FLUSH_RETRY; i++) {
+		rte_delay_ms(I40E_FDIR_FLUSH_INTERVAL_MS);
+		reg = I40E_READ_REG(hw, I40E_PFQF_CTL_1);
+		if (!(reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK))
+			break;
+	}
+	if (i >= I40E_FDIR_FLUSH_RETRY) {
+		PMD_DRV_LOG(ERR, "FD table did not flush, may need more time\n");
+		return I40E_ERR_TIMEOUT;
+	}
+	guarant_cnt = (uint16_t)((I40E_READ_REG(hw, I40E_PFQF_FDSTAT) &
+				I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) >>
+				I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT);
+	best_cnt = (uint16_t)((I40E_READ_REG(hw, I40E_PFQF_FDSTAT) &
+				I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
+				I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+	if (guarant_cnt != 0 || best_cnt != 0) {
+		PMD_DRV_LOG(ERR, "Failed to flush FD table\n");
+		return I40E_ERR_CONFIG;
+	} else
+		PMD_DRV_LOG(INFO, "FD table Flush success\n");
+	return I40E_SUCCESS;
+}
+
+/* Construct the tx flags */
+static inline uint64_t
+i40e_build_ctob(uint32_t td_cmd,
+		uint32_t td_offset,
+		unsigned int size,
+		uint32_t td_tag)
+{
+	return rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DATA |
+			((uint64_t)td_cmd  << I40E_TXD_QW1_CMD_SHIFT) |
+			((uint64_t)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
+			((uint64_t)size  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
+			((uint64_t)td_tag  << I40E_TXD_QW1_L2TAG1_SHIFT));
+}
+
+/*
+ * Program A flow diretor filter rule.
+ * Is done by Flow Director Programming
+ * Descriptor  followed by packet structure that contains the filter fields
+ * need to match.
+ */
+int
+i40e_fdir_filter_programming(struct i40e_pf *pf,
+			uint16_t soft_id,
+			struct rte_i40e_fdir_input *fdir_input,
+			struct rte_i40e_fdir_action *fdir_action,
+			bool add)
+{
+	struct i40e_tx_queue *txq = pf->fdir.txq;
+	volatile struct i40e_tx_desc *txdp;
+	struct rte_mbuf *mbuf = fdir_input->data;
+	volatile struct i40e_filter_program_desc *fdirdp;
+	uint64_t dma_addr;
+	uint32_t td_cmd;
+	uint16_t i;
+	uint8_t dest;
+
+	PMD_DRV_LOG(INFO, "filling filter prgramming descriptor\n");
+	fdirdp = (volatile struct i40e_filter_program_desc *)
+			(&(txq->tx_ring[txq->tx_tail]));
+
+	fdirdp->qindex_flex_ptype_vsi =
+			rte_cpu_to_le_32((fdir_action->rx_queue <<
+					  I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
+					  I40E_TXD_FLTR_QW0_QINDEX_MASK);
+
+	fdirdp->qindex_flex_ptype_vsi |=
+			rte_cpu_to_le_32((fdir_input->flex_off <<
+					  I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) &
+					  I40E_TXD_FLTR_QW0_FLEXOFF_MASK);
+
+	fdirdp->qindex_flex_ptype_vsi |=
+			rte_cpu_to_le_32((fdir_input->pctype <<
+					  I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) &
+					  I40E_TXD_FLTR_QW0_PCTYPE_MASK);
+
+	/* Use LAN VSI Id if not programmed by user */
+	if (fdir_input->dest_vsi == 0)
+		fdirdp->qindex_flex_ptype_vsi |=
+			rte_cpu_to_le_32((pf->main_vsi->vsi_id <<
+					  I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) &
+					  I40E_TXD_FLTR_QW0_DEST_VSI_MASK);
+	else
+		fdirdp->qindex_flex_ptype_vsi |=
+			rte_cpu_to_le_32((fdir_input->dest_vsi <<
+					  I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) &
+					  I40E_TXD_FLTR_QW0_DEST_VSI_MASK);
+
+	fdirdp->dtype_cmd_cntindex =
+			rte_cpu_to_le_32(I40E_TX_DESC_DTYPE_FILTER_PROG);
+
+	if (add)
+		fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(
+				I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
+				I40E_TXD_FLTR_QW1_PCMD_SHIFT);
+	else
+		fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(
+				I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
+				I40E_TXD_FLTR_QW1_PCMD_SHIFT);
+
+	if (fdir_action->drop == RTE_I40E_DEST_DROP_PACKET)
+		dest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
+	else
+		dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
+	fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32((dest <<
+				I40E_TXD_FLTR_QW1_DEST_SHIFT) &
+				I40E_TXD_FLTR_QW1_DEST_MASK);
+
+	fdirdp->dtype_cmd_cntindex |=
+		rte_cpu_to_le_32((fdir_action->report_status<<
+				I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) &
+				I40E_TXD_FLTR_QW1_FD_STATUS_MASK);
+
+	fdirdp->dtype_cmd_cntindex |=
+			rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK);
+	if (fdir_action->cnt_index != 0)
+		fdirdp->dtype_cmd_cntindex |=
+				rte_cpu_to_le_32((fdir_action->cnt_index <<
+				I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
+				I40E_TXD_FLTR_QW1_CNTINDEX_MASK);
+	else
+		fdirdp->dtype_cmd_cntindex |=
+				rte_cpu_to_le_32((pf->fdir.match_counter_index <<
+				I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
+				I40E_TXD_FLTR_QW1_CNTINDEX_MASK);
+
+	fdirdp->fd_id = rte_cpu_to_le_32(soft_id);
+	txq->tx_tail++;
+	if (txq->tx_tail >= txq->nb_tx_desc)
+		txq->tx_tail = 0;
+
+	PMD_DRV_LOG(INFO, "filling transmit descriptor\n");
+	txdp = &(txq->tx_ring[txq->tx_tail]);
+	dma_addr = RTE_MBUF_DATA_DMA_ADDR(mbuf);
+	txdp->buffer_addr = rte_cpu_to_le_64(dma_addr);
+	td_cmd = I40E_TX_DESC_CMD_EOP |
+		 I40E_TX_DESC_CMD_RS  |
+		 I40E_TX_DESC_CMD_DUMMY;
+
+	txdp->cmd_type_offset_bsz =
+		i40e_build_ctob(td_cmd, 0,
+				mbuf->pkt.data_len, 0);
+
+	txq->tx_tail++;
+	if (txq->tx_tail >= txq->nb_tx_desc)
+		txq->tx_tail = 0;
+	/* Update the tx tail register */
+	rte_wmb();
+	I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
+
+	for (i = 0; i < I40E_FDIR_WAIT_COUNT; i++) {
+		rte_delay_us(I40E_FDIR_WAIT_INTERVAL_US);
+		if (txdp->cmd_type_offset_bsz &
+				rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
+			break;
+	}
+	if (i >= I40E_FDIR_WAIT_COUNT) {
+		PMD_DRV_LOG(ERR, "Failed to program FDIR filter\n");
+		return I40E_ERR_TIMEOUT;
+	}
+
+	return I40E_SUCCESS;
+}
+
+/*
+ * i40e_fdir_info_get - get information of Flow Director
+ * @dev: ethernet device to add filter to
+ * @fdir: a pointer to a structure of type *rte_eth_dev_fdir* to be filled with
+ *    the flow director information.
+ **/
+void
+i40e_fdir_info_get(struct rte_eth_dev *dev, struct rte_i40e_fdir_info *fdir)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t pfqf_ctl;
+
+	pfqf_ctl = I40E_READ_REG(hw, I40E_PFQF_CTL_0);
+	fdir->mode = pfqf_ctl & I40E_PFQF_CTL_0_FD_ENA_MASK ? 1 : 0;
+	fdir->guarant_spc = (uint16_t)hw->func_caps.fd_filters_guaranteed;
+	fdir->guarant_cnt = (uint16_t)((I40E_READ_REG(hw, I40E_PFQF_FDSTAT) &
+				I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) >>
+				I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT);
+	fdir->best_spc = (uint16_t)hw->func_caps.fd_filters_best_effort;
+	fdir->best_cnt = (uint16_t)((I40E_READ_REG(hw, I40E_PFQF_FDSTAT) &
+				I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
+				I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+	return;
+}
diff --git a/lib/librte_pmd_i40e/rte_i40e.h b/lib/librte_pmd_i40e/rte_i40e.h
new file mode 100644
index 0000000..699ea53
--- /dev/null
+++ b/lib/librte_pmd_i40e/rte_i40e.h
@@ -0,0 +1,125 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_I40E_H_
+#define _RTE_I40E_H_
+
+/**
+ * @file
+ *
+ * RTE I40E
+ *
+ * The I40E defines the commands and structures specifically for i40e hardware
+ * features. As different types of NIC hardware may have different features,
+ * they might not be common for all types of NIC hardwares. The commands and
+ * structures can be used in applications directly together with generalized
+ * APIs declared in rte_ethdev.h. The commands couldn't be supported by
+ * non-i40e PMD.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define I40E_FDIR_PKT_LEN                   512
+#define I40E_FDIR_IP_DEFAULT_LEN            0x003C
+#define I40E_FDIR_IP_DEFAULT_TTL            0x40
+#define I40E_FDIR_IP_DEFAULT_VERSION_IHL    0x45
+#define I40E_FDIR_TCP_DEFAULT_DATAOFF       0x50
+#define I40E_FDIR_IPv6_DEFAULT_VTC_FLOW     0x60300000
+#define I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN  0x0014
+#define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS   0xFF
+#define I40E_FDIR_UDP_DEFAULT_LEN           0x0028
+
+enum rte_i40e_fdir_status {
+	RTE_I40E_FDIR_NO_REPORT_STATUS = 0, /**< no report FDIR. */
+	RTE_I40E_FDIR_REPORT_FD_ID,         /**< only report FD ID. */
+	RTE_I40E_FDIR_REPORT_FD_ID_FLEX_4,  /**< report FD ID and 4 flex bytes. */
+	RTE_I40E_FDIR_REPORT_FLEX_8,        /**< report 8 flex bytes. */
+};
+
+#define RTE_I40E_DEST_DROP_PACKET          0x01
+#define RTE_I40E_DEST_DIRECT_PACKET_QINDEX 0x02
+
+/**
+ * A structure used to define the input for an flow director filter entry
+ */
+struct rte_i40e_fdir_input {
+	uint8_t  pctype;
+	uint8_t  flex_off;
+	uint16_t dest_vsi; /**< destination VSI*/
+	struct rte_mbuf *data; /**< mbuf store raw packet used to program */
+};
+
+/**
+ * A structure used to define an action when match FDIR packet filter.
+ */
+struct rte_i40e_fdir_action {
+	uint16_t rx_queue;       /**< queue assigned to if fdir match. */
+	uint16_t cnt_index;      /**< statistic count index */
+	uint8_t  drop;            /**< accept or reject */
+	enum rte_i40e_fdir_status report_status;  /**< status report. */
+};
+
+/**
+ * For commands:
+ * 'RTE_CMD_FDIR_RULE_ADD'
+ * 'RTE_CMD_FDIR_RULE_DEL'
+ *
+ * A structure used to define the flow director filter entry
+ */
+struct rte_i40e_fdir_entry {
+	uint16_t soft_id;               /**< id */
+	struct rte_i40e_fdir_input input;   /**< input set */
+	struct rte_i40e_fdir_action action; /**< action taken when match */
+};
+
+/**
+ * For commands:
+ * 'RTE_CMD_FDIR_INFO_GET'
+ *
+ * A structure used for user to get the information of fdir feature.
+ */
+struct rte_i40e_fdir_info {
+	uint8_t  mode;         /**< 0 is disable, 1 is enable. */
+	uint16_t guarant_spc;  /**< guaranteed spaces.*/
+	uint16_t guarant_cnt;  /**< Number of filters in guaranteed spaces. */
+	uint16_t best_spc;     /**< best effort spaces.*/
+	uint16_t best_cnt;     /**< Number of filters in best effort spaces. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_I40E_H_ */
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
                   ` (3 preceding siblings ...)
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 4/6] i40e: function implement in i40e for flow director filter programming Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 6/6] i40e: support FD ID report and match counter for i40e flow director Jingjing Wu
  2014-08-15  1:33 ` [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Cao, Min
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

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@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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH 6/6] i40e: support FD ID report and match counter for i40e flow director
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
                   ` (4 preceding siblings ...)
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support Jingjing Wu
@ 2014-08-01  7:08 ` Jingjing Wu
  2014-08-15  1:33 ` [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Cao, Min
  6 siblings, 0 replies; 8+ messages in thread
From: Jingjing Wu @ 2014-08-01  7:08 UTC (permalink / raw)
  To: dev

support to get the fdir_match counter
support to set the FDIR flag and FD_ID reported in mbuf

Signed-off-by: jingjing.wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c |  5 ++++
 lib/librte_pmd_i40e/i40e_rxtx.c   | 49 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index c4637be..c518375 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -1112,6 +1112,9 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 			    I40E_GLPRT_PTC9522L(hw->port),
 			    pf->offset_loaded, &os->tx_size_big,
 			    &ns->tx_size_big);
+	i40e_stat_update_32(hw, I40E_GLQF_PCNT(pf->fdir.match_counter_index),
+			   pf->offset_loaded,
+			   &os->fd_sb_match, &ns->fd_sb_match);
 	/* GLPRT_MSPDC not supported */
 	/* GLPRT_XEC not supported */
 
@@ -1125,6 +1128,7 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	stats->obytes   = ns->eth.tx_bytes;
 	stats->oerrors  = ns->eth.tx_errors;
 	stats->imcasts  = ns->eth.rx_multicast;
+	stats->fdirmatch = ns->fd_sb_match;
 
 	if (pf->main_vsi)
 		i40e_update_vsi_stats(pf->main_vsi);
@@ -1190,6 +1194,7 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	printf("mac_short_packet_dropped: %lu\n",
 			ns->mac_short_packet_dropped);
 	printf("checksum_error:           %lu\n", ns->checksum_error);
+	printf("fdir_match:               %lu\n", ns->fd_sb_match);
 	printf("***************** PF stats end ********************\n");
 #endif /* RTE_LIBRTE_I40E_DEBUG_DRIVER */
 }
diff --git a/lib/librte_pmd_i40e/i40e_rxtx.c b/lib/librte_pmd_i40e/i40e_rxtx.c
index ad60d20..759fd75 100644
--- a/lib/librte_pmd_i40e/i40e_rxtx.c
+++ b/lib/librte_pmd_i40e/i40e_rxtx.c
@@ -110,6 +110,10 @@ i40e_rxd_status_to_pkt_flags(uint64_t qword)
 					I40E_RX_DESC_FLTSTAT_RSS_HASH) ==
 			I40E_RX_DESC_FLTSTAT_RSS_HASH) ? PKT_RX_RSS_HASH : 0);
 
+	/* Check if FDIR Match */
+	flags |= (uint16_t)(qword & (1 << I40E_RX_DESC_STATUS_FLM_SHIFT) ?
+							PKT_RX_FDIR : 0);
+
 	return flags;
 }
 
@@ -626,7 +630,22 @@ i40e_rx_scan_hw_ring(struct i40e_rx_queue *rxq)
 			mb->ol_flags = pkt_flags;
 			if (pkt_flags & PKT_RX_RSS_HASH)
 				mb->pkt.hash.rss = rte_le_to_cpu_32(\
-					rxdp->wb.qword0.hi_dword.rss);
+					rxdp[j].wb.qword0.hi_dword.rss);
+			if (pkt_flags & PKT_RX_FDIR) {
+#ifdef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+				if (((qword1 >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) &
+						I40E_RX_DESC_FLTSTAT_RSS_HASH) ==
+						I40E_RX_DESC_FLTSTAT_RSV_FD_ID)
+					mb->pkt.hash.fdir.id = (uint16_t)
+						rte_le_to_cpu_32(rxdp[j].wb.qword0.hi_dword.fd);
+#else
+				if (((rxdp[j].wb.qword2.ext_status >>
+					I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT) &
+					0x03) == 0x01)
+					mb->pkt.hash.fdir.id = (uint16_t)
+						rte_le_to_cpu_32(rxdp[j].wb.qword3.hi_dword.fd_id);
+#endif
+			}
 		}
 
 		for (j = 0; j < I40E_LOOK_AHEAD; j++)
@@ -864,6 +883,20 @@ i40e_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		if (pkt_flags & PKT_RX_RSS_HASH)
 			rxm->pkt.hash.rss =
 				rte_le_to_cpu_32(rxd.wb.qword0.hi_dword.rss);
+		if (pkt_flags & PKT_RX_FDIR) {
+#ifdef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+			if (((qword1 >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) &
+					I40E_RX_DESC_FLTSTAT_RSS_HASH) ==
+					I40E_RX_DESC_FLTSTAT_RSV_FD_ID)
+				rxm->pkt.hash.fdir.id = (uint16_t)
+					rte_le_to_cpu_32(rxd.wb.qword0.hi_dword.fd);
+#else
+			if (((rxd.wb.qword2.ext_status >> I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT) &
+				0x03) == 0x01)
+				rxm->pkt.hash.fdir.id = (uint16_t)
+					rte_le_to_cpu_32(rxd.wb.qword3.hi_dword.fd_id);
+#endif
+		}
 
 		rx_pkts[nb_rx++] = rxm;
 	}
@@ -1017,6 +1050,20 @@ i40e_recv_scattered_pkts(void *rx_queue,
 		if (pkt_flags & PKT_RX_RSS_HASH)
 			rxm->pkt.hash.rss =
 				rte_le_to_cpu_32(rxd.wb.qword0.hi_dword.rss);
+		if (pkt_flags & PKT_RX_FDIR) {
+#ifdef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+			if (((qword1 >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) &
+					I40E_RX_DESC_FLTSTAT_RSS_HASH) ==
+					I40E_RX_DESC_FLTSTAT_RSV_FD_ID)
+				rxm->pkt.hash.fdir.id = (uint16_t)
+					rte_le_to_cpu_32(rxd.wb.qword0.hi_dword.fd);
+#else
+			if (((rxd.wb.qword2.ext_status >> I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT) &
+				0x03) == 0x01)
+				rxm->pkt.hash.fdir.id = (uint16_t)
+					rte_le_to_cpu_32(rxd.wb.qword3.hi_dword.fd_id);
+#endif
+		}
 
 		/* Prefetch data of first segment, if configured to do so. */
 		rte_prefetch0(first_seg->pkt.data);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville
  2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
                   ` (5 preceding siblings ...)
  2014-08-01  7:08 ` [dpdk-dev] [PATCH 6/6] i40e: support FD ID report and match counter for i40e flow director Jingjing Wu
@ 2014-08-15  1:33 ` Cao, Min
  6 siblings, 0 replies; 8+ messages in thread
From: Cao, Min @ 2014-08-15  1:33 UTC (permalink / raw)
  To: dev

Tested-by: Cao Min <Min.Cao@intel.com>
This patch add i40e flow director fucntion, testpmd can works OK with it.
It is ready to be integrated to dpdk.org.

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jingjing Wu
Sent: Friday, August 01, 2014 3:09 PM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville

The patch set supports flow director programming on fortville.
It includes:
 - reserve i40e resources for flow director, such as queue and vsi.
 - support the new ethdev AP Irx_classification_filter_ctl for all 
   the configuration or queries for receive classification filters.
 - support programming 6 flow types for the flow director filters,
   which is called PCTYPE in fortville: ipv4, tcpv4, udpv4, ipv6,
   tcpv6, udpv6.
 - support flushing flow director table (all filters).
 - support match statistics and FD ID report.
 - all fix the the Marco conflict between rte_ip.h and netinet/in.h. 

jingjing.wu (6):
  i40e: flow director resource reserve and initialize on i40e
  lib/librte_net: fix the Marco conflict between rte_ip.h and netinet/in.h
  ethdev: define new ethdev API rx_classification_filter_ctl
  i40e: function implement in i40e for flow director filter programming
  app/test-pmd: add commands and config functions for i40e flow director support
  i40e: support FD ID report and match counter for i40e flow director

 app/test-pmd/cmdline.c              | 665 ++++++++++++++++++++++++++++++++++++
 app/test-pmd/config.c               |  54 ++-
 app/test-pmd/testpmd.c              |  22 ++
 app/test-pmd/testpmd.h              |  57 ++++
 lib/librte_ether/Makefile           |   3 +-
 lib/librte_ether/rte_eth_features.h |  64 ++++
 lib/librte_ether/rte_ethdev.c       |  19 +-
 lib/librte_ether/rte_ethdev.h       | 108 +++---
 lib/librte_net/rte_ip.h             |   5 +-
 lib/librte_pmd_i40e/Makefile        |   5 +
 lib/librte_pmd_i40e/i40e_ethdev.c   |  98 +++++-
 lib/librte_pmd_i40e/i40e_ethdev.h   |  32 +-
 lib/librte_pmd_i40e/i40e_fdir.c     | 355 +++++++++++++++++++
 lib/librte_pmd_i40e/i40e_rxtx.c     | 176 +++++++++-
 lib/librte_pmd_i40e/rte_i40e.h      | 125 +++++++
 15 files changed, 1727 insertions(+), 61 deletions(-)
 create mode 100644 lib/librte_ether/rte_eth_features.h
 create mode 100644 lib/librte_pmd_i40e/i40e_fdir.c
 create mode 100644 lib/librte_pmd_i40e/rte_i40e.h

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-08-15  4:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-01  7:08 [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 1/6] i40e: flow director resource reserve and initialize on i40e Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 2/6] lib/librte_net: fix the Marco conflict Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 3/6] ethdev: define new ethdev API rx_classification_filter_ctl Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 4/6] i40e: function implement in i40e for flow director filter programming Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support Jingjing Wu
2014-08-01  7:08 ` [dpdk-dev] [PATCH 6/6] i40e: support FD ID report and match counter for i40e flow director Jingjing Wu
2014-08-15  1:33 ` [dpdk-dev] [PATCH 0/6] Support flow director programming on fortville Cao, Min

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).