DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 08/23] broadcom: localize mapping from eth_dev to pci
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand,
	Stephen Hemminger
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

Use existing information about pci and interrupt handle to minimize
the number of places that assume eth_dev contains pci_device
information.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Acked-by: Jan Blunck <jblunck@infradead.org>
---
 drivers/net/bnxt/bnxt_ethdev.c | 22 +++++++++++++---------
 drivers/net/bnxt/bnxt_ring.c   | 16 ++++++----------
 2 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 035fe07..529b6c8 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -743,6 +743,8 @@ static int bnxt_reta_query_op(struct rte_eth_dev *eth_dev,
 {
 	struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
 	struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
+	struct rte_intr_handle *intr_handle
+		= &bp->pdev->intr_handle;
 
 	/* Retrieve from the default VNIC */
 	if (!vnic)
@@ -759,7 +761,7 @@ static int bnxt_reta_query_op(struct rte_eth_dev *eth_dev,
 	/* EW - need to revisit here copying from u64 to u16 */
 	memcpy(reta_conf, vnic->rss_table, reta_size);
 
-	if (rte_intr_allow_others(&eth_dev->pci_dev->intr_handle)) {
+	if (rte_intr_allow_others(intr_handle)) {
 		if (eth_dev->data->dev_conf.intr_conf.lsc != 0)
 			bnxt_dev_lsc_intr_setup(eth_dev);
 	}
@@ -1009,11 +1011,12 @@ static bool bnxt_vf_pciid(uint16_t id)
 
 static int bnxt_init_board(struct rte_eth_dev *eth_dev)
 {
-	int rc;
 	struct bnxt *bp = eth_dev->data->dev_private;
+	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
+	int rc;
 
 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
-	if (!eth_dev->pci_dev->mem_resource[0].addr) {
+	if (!pci_dev->mem_resource[0].addr) {
 		RTE_LOG(ERR, PMD,
 			"Cannot find PCI device base address, aborting\n");
 		rc = -ENODEV;
@@ -1021,9 +1024,9 @@ static int bnxt_init_board(struct rte_eth_dev *eth_dev)
 	}
 
 	bp->eth_dev = eth_dev;
-	bp->pdev = eth_dev->pci_dev;
+	bp->pdev = pci_dev;
 
-	bp->bar0 = (void *)eth_dev->pci_dev->mem_resource[0].addr;
+	bp->bar0 = (void *)pci_dev->mem_resource[0].addr;
 	if (!bp->bar0) {
 		RTE_LOG(ERR, PMD, "Cannot map device registers, aborting\n");
 		rc = -ENOMEM;
@@ -1043,6 +1046,7 @@ static int bnxt_init_board(struct rte_eth_dev *eth_dev)
 static int
 bnxt_dev_init(struct rte_eth_dev *eth_dev)
 {
+	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
 	static int version_printed;
 	struct bnxt *bp;
 	int rc;
@@ -1050,10 +1054,10 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 	if (version_printed++ == 0)
 		RTE_LOG(INFO, PMD, "%s", bnxt_version);
 
-	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	rte_eth_copy_pci_info(eth_dev, pci_dev);
 	bp = eth_dev->data->dev_private;
 
-	if (bnxt_vf_pciid(eth_dev->pci_dev->id.device_id))
+	if (bnxt_vf_pciid(pci_dev->id.device_id))
 		bp->flags |= BNXT_FLAG_VF;
 
 	rc = bnxt_init_board(eth_dev);
@@ -1121,8 +1125,8 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 
 	RTE_LOG(INFO, PMD,
 		DRV_MODULE_NAME " found at mem %" PRIx64 ", node addr %pM\n",
-		eth_dev->pci_dev->mem_resource[0].phys_addr,
-		eth_dev->pci_dev->mem_resource[0].addr);
+		pci_dev->mem_resource[0].phys_addr,
+		pci_dev->mem_resource[0].addr);
 
 	bp->dev_stopped = 0;
 
diff --git a/drivers/net/bnxt/bnxt_ring.c b/drivers/net/bnxt/bnxt_ring.c
index 3f81ffc..0fafa13 100644
--- a/drivers/net/bnxt/bnxt_ring.c
+++ b/drivers/net/bnxt/bnxt_ring.c
@@ -209,6 +209,7 @@ int bnxt_alloc_rings(struct bnxt *bp, uint16_t qidx,
  */
 int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 {
+	struct rte_pci_device *pci_dev = bp->pdev;
 	unsigned int i;
 	int rc = 0;
 
@@ -222,8 +223,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 					  0, HWRM_NA_SIGNATURE);
 		if (rc)
 			goto err_out;
-		cpr->cp_doorbell =
-		    (char *)bp->eth_dev->pci_dev->mem_resource[2].addr;
+		cpr->cp_doorbell = pci_dev->mem_resource[2].addr;
 		B_CP_DIS_DB(cpr, cpr->cp_raw_cons);
 		bp->grp_info[0].cp_fw_ring_id = cp_ring->fw_ring_id;
 	}
@@ -242,8 +242,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 					idx, HWRM_NA_SIGNATURE);
 		if (rc)
 			goto err_out;
-		cpr->cp_doorbell =
-		    (char *)bp->eth_dev->pci_dev->mem_resource[2].addr +
+		cpr->cp_doorbell = (char *)pci_dev->mem_resource[2].addr +
 		    idx * 0x80;
 		bp->grp_info[idx].cp_fw_ring_id = cp_ring->fw_ring_id;
 		B_CP_DIS_DB(cpr, cpr->cp_raw_cons);
@@ -255,8 +254,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 		if (rc)
 			goto err_out;
 		rxr->rx_prod = 0;
-		rxr->rx_doorbell =
-		    (char *)bp->eth_dev->pci_dev->mem_resource[2].addr +
+		rxr->rx_doorbell = (char *)pci_dev->mem_resource[2].addr +
 		    idx * 0x80;
 		bp->grp_info[idx].rx_fw_ring_id = ring->fw_ring_id;
 		B_RX_DB(rxr->rx_doorbell, rxr->rx_prod);
@@ -283,8 +281,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 		if (rc)
 			goto err_out;
 
-		cpr->cp_doorbell =
-		    (char *)bp->eth_dev->pci_dev->mem_resource[2].addr +
+		cpr->cp_doorbell = (char *)pci_dev->mem_resource[2].addr +
 		    idx * 0x80;
 		bp->grp_info[idx].cp_fw_ring_id = cp_ring->fw_ring_id;
 		B_CP_DIS_DB(cpr, cpr->cp_raw_cons);
@@ -296,8 +293,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp)
 		if (rc)
 			goto err_out;
 
-		txr->tx_doorbell =
-		    (char *)bp->eth_dev->pci_dev->mem_resource[2].addr +
+		txr->tx_doorbell = (char *)pci_dev->mem_resource[2].addr +
 		    idx * 0x80;
 	}
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 07/23] i40e: localize mapping of eth_dev to pci
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand,
	Stephen Hemminger
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

Simplify later changes to eth_dev.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Acked-by: Jan Blunck <jblunck@infradead.org>
---
 drivers/net/i40e/i40e_ethdev.c    | 77 ++++++++++++++++++++++++---------------
 drivers/net/i40e/i40e_ethdev.h    |  3 ++
 drivers/net/i40e/i40e_ethdev_vf.c | 58 ++++++++++++++++-------------
 3 files changed, 83 insertions(+), 55 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67778ba..ba5795e 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -373,8 +373,8 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
 			       uint64_t *offset,
 			       uint64_t *stat);
 static void i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue);
-static void i40e_dev_interrupt_handler(
-		__rte_unused struct rte_intr_handle *handle, void *param);
+static void i40e_dev_interrupt_handler(struct rte_intr_handle *handle,
+				       void *param);
 static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
 				uint32_t base, uint32_t num);
 static void i40e_res_pool_destroy(struct i40e_res_pool_info *pool);
@@ -907,7 +907,7 @@ is_floating_veb_supported(struct rte_devargs *devargs)
 static void
 config_floating_veb(struct rte_eth_dev *dev)
 {
-	struct rte_pci_device *pci_dev = dev->pci_dev;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -931,6 +931,7 @@ static int
 eth_i40e_dev_init(struct rte_eth_dev *dev)
 {
 	struct rte_pci_device *pci_dev;
+	struct rte_intr_handle *intr_handle;
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct i40e_vsi *vsi;
@@ -952,7 +953,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 		i40e_set_tx_function(dev);
 		return 0;
 	}
-	pci_dev = dev->pci_dev;
+	pci_dev = I40E_DEV_TO_PCI(dev);
+	intr_handle = &pci_dev->intr_handle;
 
 	rte_eth_copy_pci_info(dev, pci_dev);
 
@@ -1148,15 +1150,15 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 	i40e_pf_host_init(dev);
 
 	/* register callback func to eal lib */
-	rte_intr_callback_register(&(pci_dev->intr_handle),
-		i40e_dev_interrupt_handler, (void *)dev);
+	rte_intr_callback_register(intr_handle,
+				   i40e_dev_interrupt_handler, dev);
 
 	/* configure and enable device interrupt */
 	i40e_pf_config_irq0(hw, TRUE);
 	i40e_pf_enable_irq0(hw);
 
 	/* enable uio intr after callback register */
-	rte_intr_enable(&(pci_dev->intr_handle));
+	rte_intr_enable(intr_handle);
 	/*
 	 * Add an ethertype filter to drop all flow control frames transmitted
 	 * from VSIs. By doing so, we stop VF from sending out PAUSE or PFC
@@ -1204,6 +1206,7 @@ static int
 eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 {
 	struct rte_pci_device *pci_dev;
+	struct rte_intr_handle *intr_handle;
 	struct i40e_hw *hw;
 	struct i40e_filter_control_settings settings;
 	int ret;
@@ -1215,7 +1218,8 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 		return 0;
 
 	hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	pci_dev = dev->pci_dev;
+	pci_dev = I40E_DEV_TO_PCI(dev);
+	intr_handle = &pci_dev->intr_handle;
 
 	if (hw->adapter_stopped == 0)
 		i40e_dev_close(dev);
@@ -1245,11 +1249,11 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 	dev->data->mac_addrs = NULL;
 
 	/* disable uio intr before callback unregister */
-	rte_intr_disable(&(pci_dev->intr_handle));
+	rte_intr_disable(intr_handle);
 
 	/* register callback func to eal lib */
-	rte_intr_callback_unregister(&(pci_dev->intr_handle),
-		i40e_dev_interrupt_handler, (void *)dev);
+	rte_intr_callback_unregister(intr_handle,
+				     i40e_dev_interrupt_handler, dev);
 
 	return 0;
 }
@@ -1335,7 +1339,8 @@ void
 i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
 {
 	struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
 	uint16_t msix_vect = vsi->msix_intr;
 	uint16_t i;
@@ -1448,7 +1453,8 @@ void
 i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
 {
 	struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
 	uint16_t msix_vect = vsi->msix_intr;
 	uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
@@ -1519,7 +1525,8 @@ static void
 i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
 {
 	struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
 	uint16_t interval = i40e_calc_itr_interval(\
 		RTE_LIBRTE_I40E_ITR_INTERVAL);
@@ -1550,7 +1557,8 @@ static void
 i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
 {
 	struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
 	uint16_t msix_intr, i;
 
@@ -1675,7 +1683,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct i40e_vsi *main_vsi = pf->main_vsi;
 	int ret, i;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t intr_vector = 0;
 
 	hw->adapter_stopped = 0;
@@ -1808,7 +1817,8 @@ i40e_dev_stop(struct rte_eth_dev *dev)
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_vsi *main_vsi = pf->main_vsi;
 	struct i40e_mirror_rule *p_mirror;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	int i;
 
 	/* Disable all queues */
@@ -1859,6 +1869,8 @@ i40e_dev_close(struct rte_eth_dev *dev)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t reg;
 	int i;
 
@@ -1870,7 +1882,7 @@ i40e_dev_close(struct rte_eth_dev *dev)
 
 	/* Disable interrupt */
 	i40e_pf_disable_irq0(hw);
-	rte_intr_disable(&(dev->pci_dev->intr_handle));
+	rte_intr_disable(intr_handle);
 
 	/* shutdown and destroy the HMC */
 	i40e_shutdown_lan_hmc(hw);
@@ -2582,13 +2594,14 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct i40e_vsi *vsi = pf->main_vsi;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
 
 	dev_info->max_rx_queues = vsi->nb_qps;
 	dev_info->max_tx_queues = vsi->nb_qps;
 	dev_info->min_rx_bufsize = I40E_BUF_SIZE_MIN;
 	dev_info->max_rx_pktlen = I40E_FRAME_SIZE_MAX;
 	dev_info->max_mac_addrs = vsi->max_macaddrs;
-	dev_info->max_vfs = dev->pci_dev->max_vfs;
+	dev_info->max_vfs = pci_dev->max_vfs;
 	dev_info->rx_offload_capa =
 		DEV_RX_OFFLOAD_VLAN_STRIP |
 		DEV_RX_OFFLOAD_QINQ_STRIP |
@@ -3490,9 +3503,10 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
 	uint16_t qp_count = 0, vsi_count = 0;
 
-	if (dev->pci_dev->max_vfs && !hw->func_caps.sr_iov_1_1) {
+	if (pci_dev->max_vfs && !hw->func_caps.sr_iov_1_1) {
 		PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV");
 		return -EINVAL;
 	}
@@ -3533,10 +3547,10 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
 
 	/* VF queue/VSI allocation */
 	pf->vf_qp_offset = pf->lan_qp_offset + pf->lan_nb_qps;
-	if (hw->func_caps.sr_iov_1_1 && dev->pci_dev->max_vfs) {
+	if (hw->func_caps.sr_iov_1_1 && pci_dev->max_vfs) {
 		pf->flags |= I40E_FLAG_SRIOV;
 		pf->vf_nb_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
-		pf->vf_num = dev->pci_dev->max_vfs;
+		pf->vf_num = pci_dev->max_vfs;
 		PMD_DRV_LOG(DEBUG, "%u VF VSIs, %u queues per VF VSI, "
 			    "in total %u queues", pf->vf_num, pf->vf_nb_qps,
 			    pf->vf_nb_qps * pf->vf_num);
@@ -5526,7 +5540,7 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
  *  void
  */
 static void
-i40e_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+i40e_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
 			   void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
@@ -5573,7 +5587,7 @@ i40e_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
 done:
 	/* Enable interrupt */
 	i40e_pf_enable_irq0(hw);
-	rte_intr_enable(&(dev->pci_dev->intr_handle));
+	rte_intr_enable(intr_handle);
 }
 
 static int
@@ -8124,10 +8138,11 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 static void
 i40e_enable_extended_tag(struct rte_eth_dev *dev)
 {
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
 	uint32_t buf = 0;
 	int ret;
 
-	ret = rte_eal_pci_read_config(dev->pci_dev, &buf, sizeof(buf),
+	ret = rte_eal_pci_read_config(pci_dev, &buf, sizeof(buf),
 				      PCI_DEV_CAP_REG);
 	if (ret < 0) {
 		PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
@@ -8140,7 +8155,7 @@ i40e_enable_extended_tag(struct rte_eth_dev *dev)
 	}
 
 	buf = 0;
-	ret = rte_eal_pci_read_config(dev->pci_dev, &buf, sizeof(buf),
+	ret = rte_eal_pci_read_config(pci_dev, &buf, sizeof(buf),
 				      PCI_DEV_CTRL_REG);
 	if (ret < 0) {
 		PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
@@ -8152,7 +8167,7 @@ i40e_enable_extended_tag(struct rte_eth_dev *dev)
 		return;
 	}
 	buf |= PCI_DEV_CTRL_EXT_TAG_MASK;
-	ret = rte_eal_pci_write_config(dev->pci_dev, &buf, sizeof(buf),
+	ret = rte_eal_pci_write_config(pci_dev, &buf, sizeof(buf),
 				       PCI_DEV_CTRL_REG);
 	if (ret < 0) {
 		PMD_DRV_LOG(ERR, "Failed to write PCI offset 0x%x",
@@ -9555,7 +9570,8 @@ i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
 static int
 i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t interval =
 		i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
@@ -9580,7 +9596,7 @@ i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 				I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
 
 	I40E_WRITE_FLUSH(hw);
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(&pci_dev->intr_handle);
 
 	return 0;
 }
@@ -9588,7 +9604,8 @@ i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t msix_intr;
 
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 298cef4..da8dd7e 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -617,6 +617,9 @@ void i40e_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 void i40e_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 	struct rte_eth_txq_info *qinfo);
 
+#define I40E_DEV_TO_PCI(eth_dev) \
+	(eth_dev->pci_dev)
+
 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
 	(&((struct i40e_adapter *)adapter)->pf)
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index aa306d6..a4d8a66 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -718,7 +718,8 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
 	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
 		sizeof(struct i40e_virtchnl_vector_map)];
 	struct i40e_virtchnl_irq_map_info *map_info;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t vector_id;
 	int i, err;
 
@@ -1401,7 +1402,7 @@ i40evf_handle_aq_msg(struct rte_eth_dev *dev)
  *  void
  */
 static void
-i40evf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+i40evf_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
 			     void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
@@ -1431,15 +1432,15 @@ i40evf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
 
 done:
 	i40evf_enable_irq0(hw);
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 }
 
 static int
 i40evf_dev_init(struct rte_eth_dev *eth_dev)
 {
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(\
-			eth_dev->data->dev_private);
-	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
+	struct i40e_hw *hw
+		= I40E_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(eth_dev);
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -1458,15 +1459,15 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 	}
 
-	rte_eth_copy_pci_info(eth_dev, eth_dev->pci_dev);
+	rte_eth_copy_pci_info(eth_dev, pci_dev);
 
-	hw->vendor_id = eth_dev->pci_dev->id.vendor_id;
-	hw->device_id = eth_dev->pci_dev->id.device_id;
-	hw->subsystem_vendor_id = eth_dev->pci_dev->id.subsystem_vendor_id;
-	hw->subsystem_device_id = eth_dev->pci_dev->id.subsystem_device_id;
-	hw->bus.device = eth_dev->pci_dev->addr.devid;
-	hw->bus.func = eth_dev->pci_dev->addr.function;
-	hw->hw_addr = (void *)eth_dev->pci_dev->mem_resource[0].addr;
+	hw->vendor_id = pci_dev->id.vendor_id;
+	hw->device_id = pci_dev->id.device_id;
+	hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+	hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->bus.device = pci_dev->addr.devid;
+	hw->bus.func = pci_dev->addr.function;
+	hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
 	hw->adapter_stopped = 0;
 
 	if(i40evf_init_vf(eth_dev) != 0) {
@@ -1853,7 +1854,8 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
 {
 	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	if (!rte_intr_allow_others(intr_handle)) {
 		I40E_WRITE_REG(hw,
@@ -1885,7 +1887,8 @@ i40evf_disable_queues_intr(struct rte_eth_dev *dev)
 {
 	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	if (!rte_intr_allow_others(intr_handle)) {
 		I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
@@ -1911,7 +1914,8 @@ i40evf_disable_queues_intr(struct rte_eth_dev *dev)
 static int
 i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t interval =
 		i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
@@ -1937,7 +1941,7 @@ i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 
 	I40EVF_WRITE_FLUSH(hw);
 
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(&pci_dev->intr_handle);
 
 	return 0;
 }
@@ -1945,7 +1949,8 @@ i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint16_t msix_intr;
 
@@ -2025,7 +2030,8 @@ i40evf_dev_start(struct rte_eth_dev *dev)
 {
 	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t intr_vector = 0;
 
 	PMD_INIT_FUNC_TRACE();
@@ -2090,7 +2096,8 @@ i40evf_dev_start(struct rte_eth_dev *dev)
 static void
 i40evf_dev_stop(struct rte_eth_dev *dev)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -2285,7 +2292,8 @@ static void
 i40evf_dev_close(struct rte_eth_dev *dev)
 {
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_pci_device *pci_dev = dev->pci_dev;
+	struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	i40evf_dev_stop(dev);
 	hw->adapter_stopped = 1;
@@ -2293,11 +2301,11 @@ i40evf_dev_close(struct rte_eth_dev *dev)
 	i40evf_reset_vf(hw);
 	i40e_shutdown_adminq(hw);
 	/* disable uio intr before callback unregister */
-	rte_intr_disable(&pci_dev->intr_handle);
+	rte_intr_disable(intr_handle);
 
 	/* unregister callback func from eal lib */
-	rte_intr_callback_unregister(&pci_dev->intr_handle,
-		i40evf_dev_interrupt_handler, (void *)dev);
+	rte_intr_callback_unregister(intr_handle,
+				     i40evf_dev_interrupt_handler, dev);
 	i40evf_disable_irq0(hw);
 }
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 06/23] ixgbe: localize mapping from eth_dev to pci_device
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand,
	Stephen Hemminger
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

Since later changes will change where PCI information is,
localize mapping in one macro.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Acked-by: Jan Blunck <jblunck@infradead.org>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 120 ++++++++++++++++++++++-----------------
 drivers/net/ixgbe/ixgbe_ethdev.h |   3 +
 drivers/net/ixgbe/ixgbe_pf.c     |   4 +-
 3 files changed, 74 insertions(+), 53 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index edc9b22..2d05751 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -233,7 +233,8 @@ static void ixgbe_dev_link_status_print(struct rte_eth_dev *dev);
 static int ixgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev);
 static int ixgbe_dev_rxq_interrupt_setup(struct rte_eth_dev *dev);
 static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev);
-static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev);
+static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev,
+				      struct rte_intr_handle *handle);
 static void ixgbe_dev_interrupt_handler(struct rte_intr_handle *handle,
 		void *param);
 static void ixgbe_dev_interrupt_delayed_handler(void *param);
@@ -1083,7 +1084,8 @@ ixgbe_swfw_lock_reset(struct ixgbe_hw *hw)
 static int
 eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 {
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
 	struct ixgbe_vfta *shadow_vfta =
@@ -1127,7 +1129,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 
 		return 0;
 	}
-	pci_dev = eth_dev->pci_dev;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
 
@@ -1272,12 +1273,11 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 		     eth_dev->data->port_id, pci_dev->id.vendor_id,
 		     pci_dev->id.device_id);
 
-	rte_intr_callback_register(&pci_dev->intr_handle,
-				   ixgbe_dev_interrupt_handler,
-				   (void *)eth_dev);
+	rte_intr_callback_register(intr_handle,
+				   ixgbe_dev_interrupt_handler, eth_dev);
 
 	/* enable uio/vfio intr/eventfd mapping */
-	rte_intr_enable(&pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	/* enable support intr */
 	ixgbe_enable_intr(eth_dev);
@@ -1293,7 +1293,8 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 static int
 eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
 {
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw;
 
 	PMD_INIT_FUNC_TRACE();
@@ -1302,7 +1303,6 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
 		return -EPERM;
 
 	hw = IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
-	pci_dev = eth_dev->pci_dev;
 
 	if (hw->adapter_stopped == 0)
 		ixgbe_dev_close(eth_dev);
@@ -1315,9 +1315,9 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
 	ixgbe_swfw_lock_reset(hw);
 
 	/* disable uio intr before callback unregister */
-	rte_intr_disable(&(pci_dev->intr_handle));
-	rte_intr_callback_unregister(&(pci_dev->intr_handle),
-		ixgbe_dev_interrupt_handler, (void *)eth_dev);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle, 
+				     ixgbe_dev_interrupt_handler, eth_dev);
 
 	/* uninitialize PF if max_vfs not zero */
 	ixgbe_pf_host_uninit(eth_dev);
@@ -1381,7 +1381,8 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 {
 	int diag;
 	uint32_t tc, tcs;
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
 	struct ixgbe_vfta *shadow_vfta =
@@ -1419,8 +1420,6 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 	}
 
-	pci_dev = eth_dev->pci_dev;
-
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
 
 	hw->device_id = pci_dev->id.device_id;
@@ -1513,10 +1512,9 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 		return -EIO;
 	}
 
-	rte_intr_callback_register(&pci_dev->intr_handle,
-				   ixgbevf_dev_interrupt_handler,
-				   (void *)eth_dev);
-	rte_intr_enable(&pci_dev->intr_handle);
+	rte_intr_callback_register(intr_handle,
+				   ixgbevf_dev_interrupt_handler, eth_dev);
+	rte_intr_enable(intr_handle);
 	ixgbevf_intr_enable(hw);
 
 	PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x mac.type=%s",
@@ -1531,8 +1529,9 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
 static int
 eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw;
-	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -1554,10 +1553,9 @@ eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
 	rte_free(eth_dev->data->mac_addrs);
 	eth_dev->data->mac_addrs = NULL;
 
-	rte_intr_disable(&pci_dev->intr_handle);
-	rte_intr_callback_unregister(&pci_dev->intr_handle,
-				     ixgbevf_dev_interrupt_handler,
-				     (void *)eth_dev);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ixgbevf_dev_interrupt_handler, eth_dev);
 
 	return 0;
 }
@@ -1947,6 +1945,8 @@ ixgbe_vmdq_vlan_hw_filter_enable(struct rte_eth_dev *dev)
 static int
 ixgbe_check_vf_rss_rxq_num(struct rte_eth_dev *dev, uint16_t nb_rx_q)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+
 	switch (nb_rx_q) {
 	case 1:
 	case 2:
@@ -1960,7 +1960,7 @@ ixgbe_check_vf_rss_rxq_num(struct rte_eth_dev *dev, uint16_t nb_rx_q)
 	}
 
 	RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool = nb_rx_q;
-	RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx = dev->pci_dev->max_vfs * nb_rx_q;
+	RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx = pci_dev->max_vfs * nb_rx_q;
 
 	return 0;
 }
@@ -2191,7 +2191,8 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct ixgbe_vf_info *vfinfo =
 		*IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t intr_vector = 0;
 	int err, link_up = 0, negotiate = 0;
 	uint32_t speed = 0;
@@ -2291,7 +2292,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
 
 	/* Restore vf rate limit */
 	if (vfinfo != NULL) {
-		for (vf = 0; vf < dev->pci_dev->max_vfs; vf++)
+		for (vf = 0; vf < pci_dev->max_vfs; vf++)
 			for (idx = 0; idx < IXGBE_MAX_QUEUE_NUM_PER_VF; idx++)
 				if (vfinfo[vf].tx_rate[idx] != 0)
 					ixgbe_set_vf_rate_limit(dev, vf,
@@ -2368,8 +2369,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
 			ixgbe_dev_lsc_interrupt_setup(dev);
 	} else {
 		rte_intr_callback_unregister(intr_handle,
-					     ixgbe_dev_interrupt_handler,
-					     (void *)dev);
+					     ixgbe_dev_interrupt_handler, dev);
 		if (dev->data->dev_conf.intr_conf.lsc != 0)
 			PMD_INIT_LOG(INFO, "lsc won't enable because of"
 				     " no intr multiplex\n");
@@ -2408,7 +2408,8 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
 	struct ixgbe_filter_info *filter_info =
 		IXGBE_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
 	struct ixgbe_5tuple_filter *p_5tuple, *p_5tuple_next;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	int vf;
 
 	PMD_INIT_FUNC_TRACE();
@@ -2423,8 +2424,7 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
 	/* stop adapter */
 	ixgbe_stop_adapter(hw);
 
-	for (vf = 0; vfinfo != NULL &&
-		     vf < dev->pci_dev->max_vfs; vf++)
+	for (vf = 0; vfinfo != NULL && vf < pci_dev->max_vfs; vf++)
 		vfinfo[vf].clear_to_send = false;
 
 	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) {
@@ -3031,6 +3031,7 @@ ixgbevf_dev_stats_reset(struct rte_eth_dev *dev)
 static void
 ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
 
@@ -3049,7 +3050,7 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->max_rx_pktlen = 15872; /* includes CRC, cf MAXFRS register */
 	dev_info->max_mac_addrs = hw->mac.num_rar_entries;
 	dev_info->max_hash_mac_addrs = IXGBE_VMDQ_NUM_UC_MAC;
-	dev_info->max_vfs = dev->pci_dev->max_vfs;
+	dev_info->max_vfs = pci_dev->max_vfs;
 	if (hw->mac.type == ixgbe_mac_82598EB)
 		dev_info->max_vmdq_pools = ETH_16_POOLS;
 	else
@@ -3163,6 +3164,7 @@ static void
 ixgbevf_dev_info_get(struct rte_eth_dev *dev,
 		     struct rte_eth_dev_info *dev_info)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
 	dev_info->max_rx_queues = (uint16_t)hw->mac.max_rx_queues;
@@ -3171,7 +3173,7 @@ ixgbevf_dev_info_get(struct rte_eth_dev *dev,
 	dev_info->max_rx_pktlen = 15872; /* includes CRC, cf MAXFRS reg */
 	dev_info->max_mac_addrs = hw->mac.num_rar_entries;
 	dev_info->max_hash_mac_addrs = IXGBE_VMDQ_NUM_UC_MAC;
-	dev_info->max_vfs = dev->pci_dev->max_vfs;
+	dev_info->max_vfs = pci_dev->max_vfs;
 	if (hw->mac.type == ixgbe_mac_82598EB)
 		dev_info->max_vmdq_pools = ETH_16_POOLS;
 	else
@@ -3433,6 +3435,7 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
 static void
 ixgbe_dev_link_status_print(struct rte_eth_dev *dev)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
 	struct rte_eth_link link;
 
 	memset(&link, 0, sizeof(link));
@@ -3448,10 +3451,10 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev)
 				(int)(dev->data->port_id));
 	}
 	PMD_INIT_LOG(DEBUG, "PCI Address: " PCI_PRI_FMT,
-				dev->pci_dev->addr.domain,
-				dev->pci_dev->addr.bus,
-				dev->pci_dev->addr.devid,
-				dev->pci_dev->addr.function);
+				pci_dev->addr.domain,
+				pci_dev->addr.bus,
+				pci_dev->addr.devid,
+				pci_dev->addr.function);
 }
 
 /*
@@ -3465,7 +3468,8 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev)
  *  - On failure, a negative value.
  */
 static int
-ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
+ixgbe_dev_interrupt_action(struct rte_eth_dev *dev,
+			   struct rte_intr_handle *intr_handle)
 {
 	struct ixgbe_interrupt *intr =
 		IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
@@ -3515,7 +3519,7 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
 	} else {
 		PMD_DRV_LOG(DEBUG, "enable intr immediately");
 		ixgbe_enable_intr(dev);
-		rte_intr_enable(&(dev->pci_dev->intr_handle));
+		rte_intr_enable(intr_handle);
 	}
 
 
@@ -3540,6 +3544,8 @@ static void
 ixgbe_dev_interrupt_delayed_handler(void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_interrupt *intr =
 		IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 	struct ixgbe_hw *hw =
@@ -3564,7 +3570,7 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
 
 	PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]", eicr);
 	ixgbe_enable_intr(dev);
-	rte_intr_enable(&(dev->pci_dev->intr_handle));
+	rte_intr_enable(intr_handle);
 }
 
 /**
@@ -3580,13 +3586,13 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
  *  void
  */
 static void
-ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+ixgbe_dev_interrupt_handler(struct rte_intr_handle *handle,
 			    void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
 	ixgbe_dev_interrupt_get_status(dev);
-	ixgbe_dev_interrupt_action(dev);
+	ixgbe_dev_interrupt_action(dev, handle);
 }
 
 static int
@@ -4196,7 +4202,8 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint32_t intr_vector = 0;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	int err, mask = 0;
 
@@ -4259,7 +4266,8 @@ static void
 ixgbevf_dev_stop(struct rte_eth_dev *dev)
 {
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -5061,6 +5069,8 @@ ixgbe_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t rule_id)
 static int
 ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t mask;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -5070,7 +5080,7 @@ ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 	RTE_SET_USED(queue_id);
 	IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
 
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	return 0;
 }
@@ -5093,6 +5103,8 @@ ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 ixgbe_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t mask;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -5112,7 +5124,7 @@ ixgbe_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 		mask &= (1 << (queue_id - 32));
 		IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
 	}
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	return 0;
 }
@@ -5216,7 +5228,8 @@ ixgbe_set_ivar_map(struct ixgbe_hw *hw, int8_t direction,
 static void
 ixgbevf_configure_msix(struct rte_eth_dev *dev)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint32_t q_idx;
@@ -5249,7 +5262,8 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
 static void
 ixgbe_configure_msix(struct rte_eth_dev *dev)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint32_t queue_id, base = IXGBE_MISC_VEC_ID;
@@ -5367,6 +5381,7 @@ static int ixgbe_set_queue_rate_limit(struct rte_eth_dev *dev,
 static int ixgbe_set_vf_rate_limit(struct rte_eth_dev *dev, uint16_t vf,
 	uint16_t tx_rate, uint64_t q_msk)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct ixgbe_vf_info *vfinfo =
 		*(IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private));
@@ -5381,7 +5396,7 @@ static int ixgbe_set_vf_rate_limit(struct rte_eth_dev *dev, uint16_t vf,
 		return -EINVAL;
 
 	if (vfinfo != NULL) {
-		for (vf_idx = 0; vf_idx < dev->pci_dev->max_vfs; vf_idx++) {
+		for (vf_idx = 0; vf_idx < pci_dev->max_vfs; vf_idx++) {
 			if (vf_idx == vf)
 				continue;
 			for (idx = 0; idx < RTE_DIM(vfinfo[vf_idx].tx_rate);
@@ -7194,15 +7209,16 @@ ixgbe_e_tag_insertion_en_dis(struct rte_eth_dev *dev,
 			     struct rte_eth_l2_tunnel_conf *l2_tunnel,
 			     bool en)
 {
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(dev);
 	int ret = 0;
 	uint32_t vmtir, vmvir;
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	if (l2_tunnel->vf_id >= dev->pci_dev->max_vfs) {
+	if (l2_tunnel->vf_id >= pci_dev->max_vfs) {
 		PMD_DRV_LOG(ERR,
 			    "VF id %u should be less than %u",
 			    l2_tunnel->vf_id,
-			    dev->pci_dev->max_vfs);
+			    pci_dev->max_vfs);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h
index 4ff6338..a0e02aa 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/ixgbe/ixgbe_ethdev.h
@@ -291,6 +291,9 @@ struct ixgbe_adapter {
 	struct rte_timecounter      tx_tstamp_tc;
 };
 
+#define IXGBE_DEV_TO_PCI(eth_dev) \
+	(eth_dev->pci_dev)
+
 #define IXGBE_DEV_PRIVATE_TO_HW(adapter)\
 	(&((struct ixgbe_adapter *)adapter)->hw)
 
diff --git a/drivers/net/ixgbe/ixgbe_pf.c b/drivers/net/ixgbe/ixgbe_pf.c
index 26395e4..cb10265 100644
--- a/drivers/net/ixgbe/ixgbe_pf.c
+++ b/drivers/net/ixgbe/ixgbe_pf.c
@@ -61,7 +61,9 @@
 static inline uint16_t
 dev_num_vf(struct rte_eth_dev *eth_dev)
 {
-	return eth_dev->pci_dev->max_vfs;
+	struct rte_pci_device *pci_dev = IXGBE_DEV_TO_PCI(eth_dev);
+
+	return pci_dev->max_vfs;
 }
 
 static inline
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 05/23] e1000: localize mapping from eth_dev to pci
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

Create one macro for where PCI device information is extracted
from ethernet device. Makes later changes easier to review, and test.

Acked-by: Jan Blunck <jblunck@infradead.org>
---
 drivers/net/e1000/e1000_ethdev.h |  2 +
 drivers/net/e1000/em_ethdev.c    | 50 +++++++++++---------
 drivers/net/e1000/igb_ethdev.c   | 99 ++++++++++++++++++++++------------------
 drivers/net/e1000/igb_pf.c       |  4 +-
 4 files changed, 87 insertions(+), 68 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethdev.h b/drivers/net/e1000/e1000_ethdev.h
index 6c25c8d..134f8b9 100644
--- a/drivers/net/e1000/e1000_ethdev.h
+++ b/drivers/net/e1000/e1000_ethdev.h
@@ -286,6 +286,8 @@ struct e1000_adapter {
 #define E1000_DEV_PRIVATE_TO_FILTER_INFO(adapter) \
 	(&((struct e1000_adapter *)adapter)->filter)
 
+#define E1000_DEV_TO_PCI(eth_dev) \
+	(eth_dev->pci_dev)
 /*
  * RX/TX IGB function prototypes
  */
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index aee3d34..014e575 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -83,7 +83,8 @@ static int eth_em_flow_ctrl_set(struct rte_eth_dev *dev,
 static int eth_em_interrupt_setup(struct rte_eth_dev *dev);
 static int eth_em_rxq_interrupt_setup(struct rte_eth_dev *dev);
 static int eth_em_interrupt_get_status(struct rte_eth_dev *dev);
-static int eth_em_interrupt_action(struct rte_eth_dev *dev);
+static int eth_em_interrupt_action(struct rte_eth_dev *dev,
+				   struct rte_intr_handle *handle);
 static void eth_em_interrupt_handler(struct rte_intr_handle *handle,
 							void *param);
 
@@ -287,7 +288,8 @@ eth_em_dev_is_ich8(struct e1000_hw *hw)
 static int
 eth_em_dev_init(struct rte_eth_dev *eth_dev)
 {
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(eth_dev->data->dev_private);
 	struct e1000_hw *hw =
@@ -295,8 +297,6 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 	struct e1000_vfta * shadow_vfta =
 		E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private);
 
-	pci_dev = eth_dev->pci_dev;
-
 	eth_dev->dev_ops = &eth_em_ops;
 	eth_dev->rx_pkt_burst = (eth_rx_burst_t)&eth_em_recv_pkts;
 	eth_dev->tx_pkt_burst = (eth_tx_burst_t)&eth_em_xmit_pkts;
@@ -351,8 +351,8 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 		     eth_dev->data->port_id, pci_dev->id.vendor_id,
 		     pci_dev->id.device_id);
 
-	rte_intr_callback_register(&(pci_dev->intr_handle),
-		eth_em_interrupt_handler, (void *)eth_dev);
+	rte_intr_callback_register(intr_handle,
+				   eth_em_interrupt_handler, eth_dev);
 
 	return 0;
 }
@@ -360,17 +360,16 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 static int
 eth_em_dev_uninit(struct rte_eth_dev *eth_dev)
 {
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(eth_dev);
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(eth_dev->data->dev_private);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	PMD_INIT_FUNC_TRACE();
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return -EPERM;
 
-	pci_dev = eth_dev->pci_dev;
-
 	if (adapter->stopped == 0)
 		eth_em_close(eth_dev);
 
@@ -382,9 +381,9 @@ eth_em_dev_uninit(struct rte_eth_dev *eth_dev)
 	eth_dev->data->mac_addrs = NULL;
 
 	/* disable uio intr before callback unregister */
-	rte_intr_disable(&(pci_dev->intr_handle));
-	rte_intr_callback_unregister(&(pci_dev->intr_handle),
-		eth_em_interrupt_handler, (void *)eth_dev);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     eth_em_interrupt_handler, eth_dev);
 
 	return 0;
 }
@@ -556,7 +555,9 @@ eth_em_start(struct rte_eth_dev *dev)
 		E1000_DEV_PRIVATE(dev->data->dev_private);
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev =
+		E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	int ret, mask;
 	uint32_t intr_vector = 0;
 	uint32_t *speeds;
@@ -738,7 +739,8 @@ eth_em_stop(struct rte_eth_dev *dev)
 {
 	struct rte_eth_link link;
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	em_rxq_intr_disable(hw);
 	em_lsc_intr_disable(hw);
@@ -999,9 +1001,11 @@ static int
 eth_em_rx_queue_intr_enable(struct rte_eth_dev *dev, __rte_unused uint16_t queue_id)
 {
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	em_rxq_intr_enable(hw);
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	return 0;
 }
@@ -1536,8 +1540,10 @@ eth_em_interrupt_get_status(struct rte_eth_dev *dev)
  *  - On failure, a negative value.
  */
 static int
-eth_em_interrupt_action(struct rte_eth_dev *dev)
+eth_em_interrupt_action(struct rte_eth_dev *dev,
+			struct rte_intr_handle *intr_handle)
 {
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_interrupt *intr =
@@ -1550,7 +1556,7 @@ eth_em_interrupt_action(struct rte_eth_dev *dev)
 		return -1;
 
 	intr->flags &= ~E1000_FLAG_NEED_LINK_UPDATE;
-	rte_intr_enable(&(dev->pci_dev->intr_handle));
+	rte_intr_enable(intr_handle);
 
 	/* set get_link_status to check register later */
 	hw->mac.get_link_status = 1;
@@ -1571,8 +1577,8 @@ eth_em_interrupt_action(struct rte_eth_dev *dev)
 		PMD_INIT_LOG(INFO, " Port %d: Link Down", dev->data->port_id);
 	}
 	PMD_INIT_LOG(DEBUG, "PCI Address: %04d:%02d:%02d:%d",
-		     dev->pci_dev->addr.domain, dev->pci_dev->addr.bus,
-		     dev->pci_dev->addr.devid, dev->pci_dev->addr.function);
+		     pci_dev->addr.domain, pci_dev->addr.bus,
+		     pci_dev->addr.devid, pci_dev->addr.function);
 
 	tctl = E1000_READ_REG(hw, E1000_TCTL);
 	rctl = E1000_READ_REG(hw, E1000_RCTL);
@@ -1604,13 +1610,13 @@ eth_em_interrupt_action(struct rte_eth_dev *dev)
  *  void
  */
 static void
-eth_em_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
-							void *param)
+eth_em_interrupt_handler(struct rte_intr_handle *handle,
+			 void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
 	eth_em_interrupt_get_status(dev);
-	eth_em_interrupt_action(dev);
+	eth_em_interrupt_action(dev, handle);
 	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 }
 
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 2fddf0c..e0115ea 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -132,7 +132,8 @@ static int  eth_igb_flow_ctrl_set(struct rte_eth_dev *dev,
 static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev);
 static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev);
 static int eth_igb_interrupt_get_status(struct rte_eth_dev *dev);
-static int eth_igb_interrupt_action(struct rte_eth_dev *dev);
+static int eth_igb_interrupt_action(struct rte_eth_dev *dev,
+				    struct rte_intr_handle *handle);
 static void eth_igb_interrupt_handler(struct rte_intr_handle *handle,
 							void *param);
 static int  igb_hardware_init(struct e1000_hw *hw);
@@ -668,15 +669,16 @@ igb_pf_reset_hw(struct e1000_hw *hw)
 }
 
 static void
-igb_identify_hardware(struct rte_eth_dev *dev)
+igb_identify_hardware(struct rte_eth_dev *dev, struct rte_pci_device *pci_dev)
 {
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	hw->vendor_id = dev->pci_dev->id.vendor_id;
-	hw->device_id = dev->pci_dev->id.device_id;
-	hw->subsystem_vendor_id = dev->pci_dev->id.subsystem_vendor_id;
-	hw->subsystem_device_id = dev->pci_dev->id.subsystem_device_id;
+
+	hw->vendor_id = pci_dev->id.vendor_id;
+	hw->device_id = pci_dev->id.device_id;
+	hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+	hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
 
 	e1000_set_mac_type(hw);
 
@@ -743,7 +745,7 @@ static int
 eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 {
 	int error = 0;
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(eth_dev);
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
 	struct e1000_vfta * shadow_vfta =
@@ -755,8 +757,6 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 
 	uint32_t ctrl_ext;
 
-	pci_dev = eth_dev->pci_dev;
-
 	eth_dev->dev_ops = &eth_igb_ops;
 	eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
 	eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
@@ -774,7 +774,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 
 	hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
 
-	igb_identify_hardware(eth_dev);
+	igb_identify_hardware(eth_dev, pci_dev);
 	if (e1000_setup_init_funcs(hw, FALSE) != E1000_SUCCESS) {
 		error = -EIO;
 		goto err_late;
@@ -908,6 +908,7 @@ static int
 eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
 {
 	struct rte_pci_device *pci_dev;
+	struct rte_intr_handle *intr_handle;
 	struct e1000_hw *hw;
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(eth_dev->data->dev_private);
@@ -918,7 +919,8 @@ eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
 		return -EPERM;
 
 	hw = E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
-	pci_dev = eth_dev->pci_dev;
+	pci_dev = E1000_DEV_TO_PCI(eth_dev);
+	intr_handle = &pci_dev->intr_handle;
 
 	if (adapter->stopped == 0)
 		eth_igb_close(eth_dev);
@@ -937,9 +939,9 @@ eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
 	igb_pf_host_uninit(eth_dev);
 
 	/* disable uio intr before callback unregister */
-	rte_intr_disable(&(pci_dev->intr_handle));
-	rte_intr_callback_unregister(&(pci_dev->intr_handle),
-		eth_igb_interrupt_handler, (void *)eth_dev);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     eth_igb_interrupt_handler, eth_dev);
 
 	return 0;
 }
@@ -951,6 +953,7 @@ static int
 eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 {
 	struct rte_pci_device *pci_dev;
+	struct rte_intr_handle *intr_handle;
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(eth_dev->data->dev_private);
 	struct e1000_hw *hw =
@@ -973,8 +976,7 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 	}
 
-	pci_dev = eth_dev->pci_dev;
-
+	pci_dev = E1000_DEV_TO_PCI(eth_dev);
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
 
 	hw->device_id = pci_dev->id.device_id;
@@ -1038,9 +1040,9 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 		     eth_dev->data->port_id, pci_dev->id.vendor_id,
 		     pci_dev->id.device_id, "igb_mac_82576_vf");
 
-	rte_intr_callback_register(&pci_dev->intr_handle,
-				   eth_igbvf_interrupt_handler,
-				   (void *)eth_dev);
+	intr_handle = &pci_dev->intr_handle;
+	rte_intr_callback_register(intr_handle,
+				   eth_igbvf_interrupt_handler, eth_dev);
 
 	return 0;
 }
@@ -1050,7 +1052,7 @@ eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev)
 {
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(eth_dev->data->dev_private);
-	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(eth_dev);
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -1217,7 +1219,8 @@ eth_igb_start(struct rte_eth_dev *dev)
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(dev->data->dev_private);
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	int ret, mask;
 	uint32_t intr_vector = 0;
 	uint32_t ctrl_ext;
@@ -1425,11 +1428,12 @@ eth_igb_stop(struct rte_eth_dev *dev)
 	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_filter_info *filter_info =
 		E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
 	struct rte_eth_link link;
 	struct e1000_flex_filter *p_flex;
 	struct e1000_5tuple_filter *p_5tuple, *p_5tuple_next;
 	struct e1000_2tuple_filter *p_2tuple, *p_2tuple_next;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	igb_intr_disable(hw);
 
@@ -1529,7 +1533,8 @@ eth_igb_close(struct rte_eth_dev *dev)
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(dev->data->dev_private);
 	struct rte_eth_link link;
-	struct rte_pci_device *pci_dev;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	eth_igb_stop(dev);
 	adapter->stopped = 1;
@@ -1549,10 +1554,9 @@ eth_igb_close(struct rte_eth_dev *dev)
 
 	igb_dev_free_queues(dev);
 
-	pci_dev = dev->pci_dev;
-	if (pci_dev->intr_handle.intr_vec) {
-		rte_free(pci_dev->intr_handle.intr_vec);
-		pci_dev->intr_handle.intr_vec = NULL;
+	if (intr_handle->intr_vec) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
 	}
 
 	memset(&link, 0, sizeof(link));
@@ -2633,12 +2637,14 @@ eth_igb_interrupt_get_status(struct rte_eth_dev *dev)
  *  - On failure, a negative value.
  */
 static int
-eth_igb_interrupt_action(struct rte_eth_dev *dev)
+eth_igb_interrupt_action(struct rte_eth_dev *dev,
+			 struct rte_intr_handle *intr_handle)
 {
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_interrupt *intr =
 		E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
 	uint32_t tctl, rctl;
 	struct rte_eth_link link;
 	int ret;
@@ -2649,7 +2655,7 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
 	}
 
 	igb_intr_enable(dev);
-	rte_intr_enable(&(dev->pci_dev->intr_handle));
+	rte_intr_enable(intr_handle);
 
 	if (intr->flags & E1000_FLAG_NEED_LINK_UPDATE) {
 		intr->flags &= ~E1000_FLAG_NEED_LINK_UPDATE;
@@ -2677,10 +2683,10 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
 		}
 
 		PMD_INIT_LOG(DEBUG, "PCI Address: %04d:%02d:%02d:%d",
-			     dev->pci_dev->addr.domain,
-			     dev->pci_dev->addr.bus,
-			     dev->pci_dev->addr.devid,
-			     dev->pci_dev->addr.function);
+			     pci_dev->addr.domain,
+			     pci_dev->addr.bus,
+			     pci_dev->addr.devid,
+			     pci_dev->addr.function);
 		tctl = E1000_READ_REG(hw, E1000_TCTL);
 		rctl = E1000_READ_REG(hw, E1000_RCTL);
 		if (link.link_status) {
@@ -2713,13 +2719,12 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
  *  void
  */
 static void
-eth_igb_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
-							void *param)
+eth_igb_interrupt_handler(struct rte_intr_handle *handle, void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
 	eth_igb_interrupt_get_status(dev);
-	eth_igb_interrupt_action(dev);
+	eth_igb_interrupt_action(dev, handle);
 }
 
 static int
@@ -2759,7 +2764,7 @@ void igbvf_mbx_process(struct rte_eth_dev *dev)
 }
 
 static int
-eth_igbvf_interrupt_action(struct rte_eth_dev *dev)
+eth_igbvf_interrupt_action(struct rte_eth_dev *dev, struct rte_intr_handle *intr_handle)
 {
 	struct e1000_interrupt *intr =
 		E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
@@ -2770,19 +2775,19 @@ eth_igbvf_interrupt_action(struct rte_eth_dev *dev)
 	}
 
 	igbvf_intr_enable(dev);
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	return 0;
 }
 
 static void
-eth_igbvf_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+eth_igbvf_interrupt_handler(struct rte_intr_handle *handle,
 			    void *param)
 {
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
 	eth_igbvf_interrupt_get_status(dev);
-	eth_igbvf_interrupt_action(dev);
+	eth_igbvf_interrupt_action(dev, handle);
 }
 
 static int
@@ -3055,8 +3060,9 @@ igbvf_dev_start(struct rte_eth_dev *dev)
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct e1000_adapter *adapter =
 		E1000_DEV_PRIVATE(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	int ret;
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
 	uint32_t intr_vector = 0;
 
 	PMD_INIT_FUNC_TRACE();
@@ -3110,7 +3116,8 @@ igbvf_dev_start(struct rte_eth_dev *dev)
 static void
 igbvf_dev_stop(struct rte_eth_dev *dev)
 {
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -5095,6 +5102,8 @@ eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 	uint32_t mask = 1 << queue_id;
 	uint32_t regval;
 
@@ -5102,7 +5111,7 @@ eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 	E1000_WRITE_REG(hw, E1000_EIMS, regval | mask);
 	E1000_WRITE_FLUSH(hw);
 
-	rte_intr_enable(&dev->pci_dev->intr_handle);
+	rte_intr_enable(intr_handle);
 
 	return 0;
 }
@@ -5166,8 +5175,8 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
 	uint32_t vec = E1000_MISC_VEC_ID;
 	uint32_t base = E1000_MISC_VEC_ID;
 	uint32_t misc_shift = 0;
-
-	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
 	/* won't configure msix register if no mapping is done
 	 * between intr vector and event fd
diff --git a/drivers/net/e1000/igb_pf.c b/drivers/net/e1000/igb_pf.c
index 5845bc2..67da3c2 100644
--- a/drivers/net/e1000/igb_pf.c
+++ b/drivers/net/e1000/igb_pf.c
@@ -57,7 +57,9 @@
 static inline uint16_t
 dev_num_vf(struct rte_eth_dev *eth_dev)
 {
-	return eth_dev->pci_dev->max_vfs;
+	struct rte_pci_device *pci_dev = E1000_DEV_TO_PCI(eth_dev);
+
+	return pci_dev->max_vfs;
 }
 
 static inline
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 04/23] pmd: remove useless reset of dev_info->dev_pci
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand,
	Stephen Hemminger
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

Since rte_eth_dev_info_get does memset() on dev_info before
calling device specific code, the explicit assignment of NULL
in all these virtual drivers has no effect.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Acked-by: Jan Blunck <jblunck@infradead.org>
---
 app/test/virtual_pmd.c                    | 1 -
 drivers/net/af_packet/rte_eth_af_packet.c | 1 -
 drivers/net/bonding/rte_eth_bond_pmd.c    | 1 -
 drivers/net/null/rte_eth_null.c           | 1 -
 drivers/net/pcap/rte_eth_pcap.c           | 1 -
 drivers/net/ring/rte_eth_ring.c           | 1 -
 drivers/net/xenvirt/rte_eth_xenvirt.c     | 1 -
 7 files changed, 7 deletions(-)

diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index 65b44c6..e0447fd 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -117,7 +117,6 @@ virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused,
 	dev_info->max_tx_queues = (uint16_t)512;
 
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 }
 
 static int
diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c
index ff45068..2951f86 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -287,7 +287,6 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->max_rx_queues = (uint16_t)internals->nb_queues;
 	dev_info->max_tx_queues = (uint16_t)internals->nb_queues;
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 }
 
 static void
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index a80b6fa..74af658 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -1675,7 +1675,6 @@ bond_ethdev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->max_tx_queues = (uint16_t)512;
 
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 
 	dev_info->rx_offload_capa = internals->rx_offload_capa;
 	dev_info->tx_offload_capa = internals->tx_offload_capa;
diff --git a/drivers/net/null/rte_eth_null.c b/drivers/net/null/rte_eth_null.c
index 836d982..b4f253a 100644
--- a/drivers/net/null/rte_eth_null.c
+++ b/drivers/net/null/rte_eth_null.c
@@ -301,7 +301,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 	dev_info->reta_size = internals->reta_size;
 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
 }
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c
index 0162f44..7253b9a 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/rte_eth_pcap.c
@@ -559,7 +559,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 	dev_info->max_rx_queues = dev->data->nb_rx_queues;
 	dev_info->max_tx_queues = dev->data->nb_tx_queues;
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 }
 
 static void
diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index c1767c4..dc99a1f 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -179,7 +179,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 	dev_info->max_rx_queues = (uint16_t)internals->max_rx_queues;
 	dev_info->max_tx_queues = (uint16_t)internals->max_tx_queues;
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 }
 
 static void
diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c b/drivers/net/xenvirt/rte_eth_xenvirt.c
index c08a056..609824b 100644
--- a/drivers/net/xenvirt/rte_eth_xenvirt.c
+++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
@@ -337,7 +337,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 	dev_info->max_rx_queues = (uint16_t)1;
 	dev_info->max_tx_queues = (uint16_t)1;
 	dev_info->min_rx_bufsize = 0;
-	dev_info->pci_dev = NULL;
 }
 
 static void
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 03/23] rte_device: make driver pointer const
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, shreyansh.jain, david.marchand
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

From: Stephen Hemminger <stephen@networkplumber.org>

The info in rte_device about driver is immutable and
shouldn't change.
Acked-by: Jan Blunck <jblunck@infradead.org>

Acked-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_eal/common/include/rte_dev.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 8840380..e5471a2 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -122,7 +122,7 @@ struct rte_driver;
  */
 struct rte_device {
 	TAILQ_ENTRY(rte_device) next; /**< Next device */
-	struct rte_driver *driver;    /**< Associated driver */
+	const struct rte_driver *driver;/**< Associated driver */
 	int numa_node;                /**< NUMA node connection */
 	struct rte_devargs *devargs;  /**< Device user arguments */
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 02/23] eal: Allow passing const rte_intr_handle
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: shreyansh.jain, david.marchand, stephen
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

Both register/unregister and enable/disable don't necessarily require the
rte_intr_handle to be modifiable. Therefore lets constify it.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_eal/common/include/rte_interrupts.h |  8 ++--
 lib/librte_eal/linuxapp/eal/eal_interrupts.c   | 62 ++++++++++++++++++--------
 2 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_interrupts.h b/lib/librte_eal/common/include/rte_interrupts.h
index fd3c6ef..6cade01 100644
--- a/lib/librte_eal/common/include/rte_interrupts.h
+++ b/lib/librte_eal/common/include/rte_interrupts.h
@@ -70,7 +70,7 @@ typedef void (*rte_intr_callback_fn)(struct rte_intr_handle *intr_handle,
  *  - On success, zero.
  *  - On failure, a negative value.
  */
-int rte_intr_callback_register(struct rte_intr_handle *intr_handle,
+int rte_intr_callback_register(const struct rte_intr_handle *intr_handle,
 				rte_intr_callback_fn cb, void *cb_arg);
 
 /**
@@ -88,7 +88,7 @@ int rte_intr_callback_register(struct rte_intr_handle *intr_handle,
  *  - On success, return the number of callback entities removed.
  *  - On failure, a negative value.
  */
-int rte_intr_callback_unregister(struct rte_intr_handle *intr_handle,
+int rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle,
 				rte_intr_callback_fn cb, void *cb_arg);
 
 /**
@@ -101,7 +101,7 @@ int rte_intr_callback_unregister(struct rte_intr_handle *intr_handle,
  *  - On success, zero.
  *  - On failure, a negative value.
  */
-int rte_intr_enable(struct rte_intr_handle *intr_handle);
+int rte_intr_enable(const struct rte_intr_handle *intr_handle);
 
 /**
  * It disables the interrupt for the specified handle.
@@ -113,7 +113,7 @@ int rte_intr_enable(struct rte_intr_handle *intr_handle);
  *  - On success, zero.
  *  - On failure, a negative value.
  */
-int rte_intr_disable(struct rte_intr_handle *intr_handle);
+int rte_intr_disable(const struct rte_intr_handle *intr_handle);
 
 #ifdef __cplusplus
 }
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 47a3b20..cb55751 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -136,7 +136,7 @@ static pthread_t intr_thread;
 
 /* enable legacy (INTx) interrupts */
 static int
-vfio_enable_intx(struct rte_intr_handle *intr_handle) {
+vfio_enable_intx(const struct rte_intr_handle *intr_handle) {
 	struct vfio_irq_set *irq_set;
 	char irq_set_buf[IRQ_SET_BUF_LEN];
 	int len, ret;
@@ -183,7 +183,7 @@ vfio_enable_intx(struct rte_intr_handle *intr_handle) {
 
 /* disable legacy (INTx) interrupts */
 static int
-vfio_disable_intx(struct rte_intr_handle *intr_handle) {
+vfio_disable_intx(const struct rte_intr_handle *intr_handle) {
 	struct vfio_irq_set *irq_set;
 	char irq_set_buf[IRQ_SET_BUF_LEN];
 	int len, ret;
@@ -226,7 +226,7 @@ vfio_disable_intx(struct rte_intr_handle *intr_handle) {
 
 /* enable MSI interrupts */
 static int
-vfio_enable_msi(struct rte_intr_handle *intr_handle) {
+vfio_enable_msi(const struct rte_intr_handle *intr_handle) {
 	int len, ret;
 	char irq_set_buf[IRQ_SET_BUF_LEN];
 	struct vfio_irq_set *irq_set;
@@ -255,7 +255,7 @@ vfio_enable_msi(struct rte_intr_handle *intr_handle) {
 
 /* disable MSI interrupts */
 static int
-vfio_disable_msi(struct rte_intr_handle *intr_handle) {
+vfio_disable_msi(const struct rte_intr_handle *intr_handle) {
 	struct vfio_irq_set *irq_set;
 	char irq_set_buf[IRQ_SET_BUF_LEN];
 	int len, ret;
@@ -278,9 +278,30 @@ vfio_disable_msi(struct rte_intr_handle *intr_handle) {
 	return ret;
 }
 
+static int
+get_max_intr(const struct rte_intr_handle *intr_handle)
+{
+	struct rte_intr_source *src;
+
+	TAILQ_FOREACH(src, &intr_sources, next) {
+		if (src->intr_handle.fd != intr_handle->fd)
+			continue;
+
+		if (!src->intr_handle.max_intr)
+			src->intr_handle.max_intr = 1;
+		else if (src->intr_handle.max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
+			src->intr_handle.max_intr
+				= RTE_MAX_RXTX_INTR_VEC_ID + 1;
+
+		return src->intr_handle.max_intr;
+	}
+
+	return -1;
+}
+
 /* enable MSI-X interrupts */
 static int
-vfio_enable_msix(struct rte_intr_handle *intr_handle) {
+vfio_enable_msix(const struct rte_intr_handle *intr_handle) {
 	int len, ret;
 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
 	struct vfio_irq_set *irq_set;
@@ -290,12 +311,15 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
 
 	irq_set = (struct vfio_irq_set *) irq_set_buf;
 	irq_set->argsz = len;
-	if (!intr_handle->max_intr)
-		intr_handle->max_intr = 1;
-	else if (intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
-		intr_handle->max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
 
-	irq_set->count = intr_handle->max_intr;
+	ret = get_max_intr(intr_handle);
+	if (ret < 0) {
+		RTE_LOG(ERR, EAL, "Invalid number of MSI-X irqs for fd %d\n",
+			intr_handle->fd);
+		return -1;
+	}
+
+	irq_set->count = ret;
 	irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
 	irq_set->start = 0;
@@ -318,7 +342,7 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
 
 /* disable MSI-X interrupts */
 static int
-vfio_disable_msix(struct rte_intr_handle *intr_handle) {
+vfio_disable_msix(const struct rte_intr_handle *intr_handle) {
 	struct vfio_irq_set *irq_set;
 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
 	int len, ret;
@@ -343,7 +367,7 @@ vfio_disable_msix(struct rte_intr_handle *intr_handle) {
 #endif
 
 static int
-uio_intx_intr_disable(struct rte_intr_handle *intr_handle)
+uio_intx_intr_disable(const struct rte_intr_handle *intr_handle)
 {
 	unsigned char command_high;
 
@@ -367,7 +391,7 @@ uio_intx_intr_disable(struct rte_intr_handle *intr_handle)
 }
 
 static int
-uio_intx_intr_enable(struct rte_intr_handle *intr_handle)
+uio_intx_intr_enable(const struct rte_intr_handle *intr_handle)
 {
 	unsigned char command_high;
 
@@ -391,7 +415,7 @@ uio_intx_intr_enable(struct rte_intr_handle *intr_handle)
 }
 
 static int
-uio_intr_disable(struct rte_intr_handle *intr_handle)
+uio_intr_disable(const struct rte_intr_handle *intr_handle)
 {
 	const int value = 0;
 
@@ -405,7 +429,7 @@ uio_intr_disable(struct rte_intr_handle *intr_handle)
 }
 
 static int
-uio_intr_enable(struct rte_intr_handle *intr_handle)
+uio_intr_enable(const struct rte_intr_handle *intr_handle)
 {
 	const int value = 1;
 
@@ -419,7 +443,7 @@ uio_intr_enable(struct rte_intr_handle *intr_handle)
 }
 
 int
-rte_intr_callback_register(struct rte_intr_handle *intr_handle,
+rte_intr_callback_register(const struct rte_intr_handle *intr_handle,
 			rte_intr_callback_fn cb, void *cb_arg)
 {
 	int ret, wake_thread;
@@ -491,7 +515,7 @@ rte_intr_callback_register(struct rte_intr_handle *intr_handle,
 }
 
 int
-rte_intr_callback_unregister(struct rte_intr_handle *intr_handle,
+rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle,
 			rte_intr_callback_fn cb_fn, void *cb_arg)
 {
 	int ret;
@@ -555,7 +579,7 @@ rte_intr_callback_unregister(struct rte_intr_handle *intr_handle,
 }
 
 int
-rte_intr_enable(struct rte_intr_handle *intr_handle)
+rte_intr_enable(const struct rte_intr_handle *intr_handle)
 {
 	if (!intr_handle || intr_handle->fd < 0 || intr_handle->uio_cfg_fd < 0)
 		return -1;
@@ -599,7 +623,7 @@ rte_intr_enable(struct rte_intr_handle *intr_handle)
 }
 
 int
-rte_intr_disable(struct rte_intr_handle *intr_handle)
+rte_intr_disable(const struct rte_intr_handle *intr_handle)
 {
 	if (!intr_handle || intr_handle->fd < 0 || intr_handle->uio_cfg_fd < 0)
 		return -1;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 01/23] eal: define container_of macro
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: shreyansh.jain, david.marchand, stephen, Jan Viktorin
In-Reply-To: <1482332986-7599-1-git-send-email-jblunck@infradead.org>

This macro is based on Jan Viktorin's original patch but also checks the
type of the passed pointer against the type of the member.

Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
[jblunck@infradead.org: add type checking and __extension__]
Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 lib/librte_eal/common/include/rte_common.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index db5ac91..8dda3e2 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -331,6 +331,26 @@ rte_bsf32(uint32_t v)
 #define offsetof(TYPE, MEMBER)  __builtin_offsetof (TYPE, MEMBER)
 #endif
 
+/**
+ * Return pointer to the wrapping struct instance.
+ *
+ * Example:
+ *
+ *  struct wrapper {
+ *      ...
+ *      struct child c;
+ *      ...
+ *  };
+ *
+ *  struct child *x = obtain(...);
+ *  struct wrapper *w = container_of(x, struct wrapper, c);
+ */
+#ifndef container_of
+#define container_of(ptr, type, member)	__extension__ ({		\
+			typeof(((type *)0)->member) *_ptr = (ptr);	\
+			(type *)(((char *)_ptr) - offsetof(type, member)); })
+#endif
+
 #define _RTE_STR(x) #x
 /** Take a macro value and get a string version of it */
 #define RTE_STR(x) _RTE_STR(x)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 00/23] Decouple ethdev from PCI device
From: Jan Blunck @ 2016-12-21 15:09 UTC (permalink / raw)
  To: dev; +Cc: shreyansh.jain, david.marchand, stephen

This is a partial merge of Stephens and my patches to make the rte_eth_dev
independent of the rte_pci_device.

Changes between v4 and v3:
 - broken out refactorings of drivers similar to Stephens example
 - use inline function instead of macro
 - fix build issues with bnx2x and mlx4/5

Changes between v3 and v2:
 - converted PCI device users I've missed in previous version

Jan Blunck (17):
  eal: define container_of macro
  eal: Allow passing const rte_intr_handle
  virtio: Don't fill dev_info->driver_name
  virtio: Add vtpci_intr_handle() helper to get rte_intr_handle
  virtio: Don't depend on struct rte_eth_dev's pci_dev
  bnx2x: localize mapping from eth_dev to pci
  fm10k: localize mapping from eth_dev to pci
  qede: localize mapping of eth_dev to pci
  szedata2: localize handling of pci resources
  nfp: localize rte_pci_device handling
  vmxnet3: use eth_dev->data->drv_name instead of pci_drv name
  ethdev: Helper to map to struct rte_pci_device
  drivers: Replace per-PMD macros with rte_eth_dev_to_pci() helper
  drivers: Use rte_eth_dev_to_pci() helper
  ethdev: Move filling of rte_eth_dev_info->pci_dev to dev_infos_get()
  ethdev: Decouple interrupt handling from PCI device
  ethdev: Decouple struct rte_eth_dev from struct rte_pci_device

Stephen Hemminger (6):
  rte_device: make driver pointer const
  pmd: remove useless reset of dev_info->dev_pci
  e1000: localize mapping from eth_dev to pci
  ixgbe: localize mapping from eth_dev to pci_device
  i40e: localize mapping of eth_dev to pci
  broadcom: localize mapping from eth_dev to pci

 app/test/virtual_pmd.c                         |   5 +-
 drivers/net/af_packet/rte_eth_af_packet.c      |   1 -
 drivers/net/bnx2x/bnx2x_ethdev.c               |  15 +--
 drivers/net/bnxt/bnxt_ethdev.c                 |  24 +++--
 drivers/net/bnxt/bnxt_ring.c                   |  16 ++--
 drivers/net/bonding/rte_eth_bond_args.c        |  12 ++-
 drivers/net/bonding/rte_eth_bond_pmd.c         |   1 -
 drivers/net/cxgbe/cxgbe_ethdev.c               |   4 +-
 drivers/net/cxgbe/cxgbe_main.c                 |   4 +-
 drivers/net/e1000/em_ethdev.c                  |  50 +++++-----
 drivers/net/e1000/igb_ethdev.c                 | 100 +++++++++++---------
 drivers/net/e1000/igb_pf.c                     |   4 +-
 drivers/net/ena/ena_ethdev.c                   |   4 +-
 drivers/net/enic/enic_ethdev.c                 |   3 +-
 drivers/net/fm10k/fm10k_ethdev.c               |  84 +++++++++--------
 drivers/net/i40e/i40e_ethdev.c                 |  78 ++++++++++------
 drivers/net/i40e/i40e_ethdev_vf.c              |  59 +++++++-----
 drivers/net/ixgbe/ixgbe_ethdev.c               | 122 ++++++++++++++-----------
 drivers/net/ixgbe/ixgbe_pf.c                   |   4 +-
 drivers/net/mlx4/mlx4.c                        |   4 +-
 drivers/net/mlx5/mlx5.c                        |   2 +-
 drivers/net/mlx5/mlx5_ethdev.c                 |   2 +
 drivers/net/nfp/nfp_net.c                      |  19 ++--
 drivers/net/null/rte_eth_null.c                |   1 -
 drivers/net/pcap/rte_eth_pcap.c                |   1 -
 drivers/net/qede/qede_ethdev.c                 |  19 ++--
 drivers/net/ring/rte_eth_ring.c                |   1 -
 drivers/net/szedata2/rte_eth_szedata2.c        |  73 +++++++++------
 drivers/net/szedata2/rte_eth_szedata2.h        |  58 +++++-------
 drivers/net/thunderx/nicvf_ethdev.c            |   7 +-
 drivers/net/virtio/virtio_ethdev.c             |  41 ++++-----
 drivers/net/virtio/virtio_pci.h                |   6 ++
 drivers/net/virtio/virtio_user_ethdev.c        |   1 -
 drivers/net/vmxnet3/vmxnet3_ethdev.c           |   8 +-
 drivers/net/xenvirt/rte_eth_xenvirt.c          |   1 -
 lib/librte_eal/common/include/rte_common.h     |  20 ++++
 lib/librte_eal/common/include/rte_dev.h        |   2 +-
 lib/librte_eal/common/include/rte_interrupts.h |   8 +-
 lib/librte_eal/common/include/rte_pci.h        |   6 ++
 lib/librte_eal/linuxapp/eal/eal_interrupts.c   |  62 +++++++++----
 lib/librte_ether/rte_ethdev.c                  |  25 +++--
 lib/librte_ether/rte_ethdev.h                  |  13 ++-
 42 files changed, 577 insertions(+), 393 deletions(-)

-- 
2.7.4

^ permalink raw reply

* Re: [PATCH v5 02/26] doc: add rte_flow prog guide
From: Mcnamara, John @ 2016-12-21 15:09 UTC (permalink / raw)
  To: Adrien Mazarguil, dev@dpdk.org
In-Reply-To: <e7d83f890bf2bd53c2333475b8d1213cfc796413.1482331076.git.adrien.mazarguil@6wind.com>



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Adrien Mazarguil
> Sent: Wednesday, December 21, 2016 2:51 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v5 02/26] doc: add rte_flow prog guide
> 
> This documentation is based on the latest RFC submission, subsequently
> updated according to feedback from the community.
> 
> Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> Acked-by: Olga Shern <olgas@mellanox.com>

Acked-by: John McNamara <john.mcnamara@intel.com>


^ permalink raw reply

* Re: Example(Load_balancer) Tx Flush Bug(This bug DPDK each version)
From: Thomas Monjalon @ 2016-12-21 15:08 UTC (permalink / raw)
  To: Maple; +Cc: dev, 李非, 施展
In-Reply-To: <2016122122394164225248@raisecom.com>

Hi,

Thanks for trying to send a patch.
Below are some comments to help you sending a proper patch.

2016-12-21 22:39, Maple:
> From 94f2eaed51e6e5402e8c03b80e0999a4fd420390 Mon Sep 17 00:00:00 2001
> From: root <root@liujian@raisecom.com>

Here we should have your real name, not "root".

> To: <dev@dpdk.org>
> Cc: <thomas.monjalon@6wind.com>, <lifei@raisecom.com>,<shizhan@raisecom.com>
> Date: Wed, 21 Dec 2016 22:31:29 +0800
> Subject: [PATCH] load_balancer Tx Flush Bug
> 
> We found a bug in use load_balancer example,and,This bug DPDK each version.
> In IO tx flush, only flush port 0.
> So,If I enable more than the Port,then,In addition to 0 port won't flush.
> 
> Signed-off-by: root <root@liujian@raisecom.com>

Here alse we should have your real name.
See ~/.gitconfig

> ---
>  a/examples/load_balancer/runtime.c | 667 ++++++++++++++++++++++++++++++++++++
>  b/examples/load_balancer/runtime.c | 669 +++++++++++++++++++++++++++++++++++++

You are sending the whole file instead of the diff.
Are you using git?
It should be as simple as "git clone git://dpdk.org/dpdk", then
modify the file, then "git commit -as", then send patch with
"git send-email -1 --to dev@dpdk.org".
As it will be your second version, you should add these options:
-v2 --in-reply-to '<2016122122394164225248@raisecom.com>'

Thanks

^ permalink raw reply

* [PATCH v4 3/3] doc: add required python versions to docs
From: John McNamara @ 2016-12-21 15:03 UTC (permalink / raw)
  To: dev; +Cc: mkletzan, nhorman, John McNamara
In-Reply-To: <1481212265-10229-1-git-send-email-john.mcnamara@intel.com>

Add a requirement to support both Python 2 and 3 to the
DPDK Python Coding Standards and Getting started Guide.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/contributing/coding_style.rst | 3 ++-
 doc/guides/linux_gsg/sys_reqs.rst        | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/doc/guides/contributing/coding_style.rst b/doc/guides/contributing/coding_style.rst
index 1eb67f3..4163960 100644
--- a/doc/guides/contributing/coding_style.rst
+++ b/doc/guides/contributing/coding_style.rst
@@ -690,6 +690,7 @@ Control Statements
 Python Code
 -----------
 
-All python code should be compliant with `PEP8 (Style Guide for Python Code) <https://www.python.org/dev/peps/pep-0008/>`_.
+All Python code should work with Python 2.7+ and 3.2+ and be compliant with
+`PEP8 (Style Guide for Python Code) <https://www.python.org/dev/peps/pep-0008/>`_.
 
 The ``pep8`` tool can be used for testing compliance with the guidelines.
diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 76d82e6..61222c6 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -84,7 +84,7 @@ Compilation of the DPDK
        x86_x32 ABI is currently supported with distribution packages only on Ubuntu
        higher than 13.10 or recent Debian distribution. The only supported  compiler is gcc 4.9+.
 
-*   Python, version 2.6 or 2.7, to use various helper scripts included in the DPDK package.
+*   Python, version 2.7+ or 3.2+, to use various helper scripts included in the DPDK package.
 
 
 **Optional Tools:**
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 2/3] app: make python apps python2/3 compliant
From: John McNamara @ 2016-12-21 15:03 UTC (permalink / raw)
  To: dev; +Cc: mkletzan, nhorman, John McNamara
In-Reply-To: <1481212265-10229-1-git-send-email-john.mcnamara@intel.com>

Make all the DPDK Python apps work with Python 2 or 3 to
allow them to work with whatever is the system default.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 app/cmdline_test/cmdline_test.py      | 26 ++++++++++++------------
 app/cmdline_test/cmdline_test_data.py |  2 --
 app/test/autotest.py                  | 10 ++++-----
 app/test/autotest_data.py             |  2 --
 app/test/autotest_runner.py           | 37 ++++++++++++++++------------------
 app/test/autotest_test_funcs.py       |  2 --
 tools/cpu_layout.py                   | 38 ++++++++++++++++++-----------------
 tools/dpdk-devbind.py                 |  2 +-
 tools/dpdk-pmdinfo.py                 | 14 +++++++------
 9 files changed, 64 insertions(+), 69 deletions(-)

diff --git a/app/cmdline_test/cmdline_test.py b/app/cmdline_test/cmdline_test.py
index 4729987..229f71f 100755
--- a/app/cmdline_test/cmdline_test.py
+++ b/app/cmdline_test/cmdline_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 #   BSD LICENSE
 #
@@ -32,7 +32,7 @@
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 # Script that runs cmdline_test app and feeds keystrokes into it.
-
+from __future__ import print_function
 import cmdline_test_data
 import os
 import pexpect
@@ -81,38 +81,38 @@ def runHistoryTest(child):
 
 # the path to cmdline_test executable is supplied via command-line.
 if len(sys.argv) < 2:
-    print "Error: please supply cmdline_test app path"
+    print("Error: please supply cmdline_test app path")
     sys.exit(1)
 
 test_app_path = sys.argv[1]
 
 if not os.path.exists(test_app_path):
-    print "Error: please supply cmdline_test app path"
+    print("Error: please supply cmdline_test app path")
     sys.exit(1)
 
 child = pexpect.spawn(test_app_path)
 
-print "Running command-line tests..."
+print("Running command-line tests...")
 for test in cmdline_test_data.tests:
-    print (test["Name"] + ":").ljust(30),
+    testname = (test["Name"] + ":").ljust(30)
     try:
         runTest(child, test)
-        print "PASS"
+        print(testname, "PASS")
     except:
-        print "FAIL"
-        print child
+        print(testname, "FAIL")
+        print(child)
         sys.exit(1)
 
 # since last test quits the app, run new instance
 child = pexpect.spawn(test_app_path)
 
-print ("History fill test:").ljust(30),
+testname = ("History fill test:").ljust(30)
 try:
     runHistoryTest(child)
-    print "PASS"
+    print(testname, "PASS")
 except:
-    print "FAIL"
-    print child
+    print(testname, "FAIL")
+    print(child)
     sys.exit(1)
 child.close()
 sys.exit(0)
diff --git a/app/cmdline_test/cmdline_test_data.py b/app/cmdline_test/cmdline_test_data.py
index 3ce6cbc..28dfefe 100644
--- a/app/cmdline_test/cmdline_test_data.py
+++ b/app/cmdline_test/cmdline_test_data.py
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-
 #   BSD LICENSE
 #
 #   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
diff --git a/app/test/autotest.py b/app/test/autotest.py
index 3a00538..5c19a02 100644
--- a/app/test/autotest.py
+++ b/app/test/autotest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 #   BSD LICENSE
 #
@@ -32,15 +32,15 @@
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 # Script that uses either test app or qemu controlled by python-pexpect
-
+from __future__ import print_function
 import autotest_data
 import autotest_runner
 import sys
 
 
 def usage():
-    print"Usage: autotest.py [test app|test iso image]",
-    print "[target] [whitelist|-blacklist]"
+    print("Usage: autotest.py [test app|test iso image] ",
+          "[target] [whitelist|-blacklist]")
 
 if len(sys.argv) < 3:
     usage()
@@ -63,7 +63,7 @@ def usage():
 
 cmdline = "%s -c f -n 4" % (sys.argv[1])
 
-print cmdline
+print(cmdline)
 
 runner = autotest_runner.AutotestRunner(cmdline, target, test_blacklist,
                                         test_whitelist)
diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
index 0cf4cfd..0cd598b 100644
--- a/app/test/autotest_data.py
+++ b/app/test/autotest_data.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
 #   BSD LICENSE
 #
 #   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
diff --git a/app/test/autotest_runner.py b/app/test/autotest_runner.py
index 55b63a8..fc882ec 100644
--- a/app/test/autotest_runner.py
+++ b/app/test/autotest_runner.py
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-
 #   BSD LICENSE
 #
 #   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
@@ -271,15 +269,16 @@ def __process_results(self, results):
             total_time = int(cur_time - self.start)
 
             # print results, test run time and total time since start
-            print ("%s:" % test_name).ljust(30),
-            print result_str.ljust(29),
-            print "[%02dm %02ds]" % (test_time / 60, test_time % 60),
+            result = ("%s:" % test_name).ljust(30)
+            result += result_str.ljust(29)
+            result += "[%02dm %02ds]" % (test_time / 60, test_time % 60)
 
             # don't print out total time every line, it's the same anyway
             if i == len(results) - 1:
-                print "[%02dm %02ds]" % (total_time / 60, total_time % 60)
+                print(result,
+                      "[%02dm %02ds]" % (total_time / 60, total_time % 60))
             else:
-                print ""
+                print(result)
 
             # if test failed and it wasn't a "start" test
             if test_result < 0 and not i == 0:
@@ -294,7 +293,7 @@ def __process_results(self, results):
                     f = open("%s_%s_report.rst" %
                              (self.target, test_name), "w")
                 except IOError:
-                    print "Report for %s could not be created!" % test_name
+                    print("Report for %s could not be created!" % test_name)
                 else:
                     with f:
                         f.write(report)
@@ -360,12 +359,10 @@ def run_all_tests(self):
         try:
 
             # create table header
-            print ""
-            print "Test name".ljust(30),
-            print "Test result".ljust(29),
-            print "Test".center(9),
-            print "Total".center(9)
-            print "=" * 80
+            print("")
+            print("Test name".ljust(30), "Test result".ljust(29),
+                  "Test".center(9), "Total".center(9))
+            print("=" * 80)
 
             # make a note of tests start time
             self.start = time.time()
@@ -407,11 +404,11 @@ def run_all_tests(self):
             total_time = int(cur_time - self.start)
 
             # print out summary
-            print "=" * 80
-            print "Total run time: %02dm %02ds" % (total_time / 60,
-                                                   total_time % 60)
+            print("=" * 80)
+            print("Total run time: %02dm %02ds" % (total_time / 60,
+                                                   total_time % 60))
             if self.fails != 0:
-                print "Number of failed tests: %s" % str(self.fails)
+                print("Number of failed tests: %s" % str(self.fails))
 
             # write summary to logfile
             self.logfile.write("Summary\n")
@@ -420,8 +417,8 @@ def run_all_tests(self):
             self.logfile.write("Failed tests: ".ljust(
                 15) + "%i\n" % self.fails)
         except:
-            print "Exception occurred"
-            print sys.exc_info()
+            print("Exception occurred")
+            print(sys.exc_info())
             self.fails = 1
 
         # drop logs from all executions to a logfile
diff --git a/app/test/autotest_test_funcs.py b/app/test/autotest_test_funcs.py
index c482ea8..1c5f390 100644
--- a/app/test/autotest_test_funcs.py
+++ b/app/test/autotest_test_funcs.py
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-
 #   BSD LICENSE
 #
 #   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
diff --git a/tools/cpu_layout.py b/tools/cpu_layout.py
index ccc22ec..0e049a6 100755
--- a/tools/cpu_layout.py
+++ b/tools/cpu_layout.py
@@ -1,4 +1,5 @@
-#! /usr/bin/python
+#!/usr/bin/env python
+
 #
 #   BSD LICENSE
 #
@@ -31,7 +32,7 @@
 #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
-
+from __future__ import print_function
 import sys
 
 sockets = []
@@ -55,7 +56,7 @@
 for core in core_details:
     for field in ["processor", "core id", "physical id"]:
         if field not in core:
-            print "Error getting '%s' value from /proc/cpuinfo" % field
+            print("Error getting '%s' value from /proc/cpuinfo" % field)
             sys.exit(1)
         core[field] = int(core[field])
 
@@ -68,29 +69,30 @@
         core_map[key] = []
     core_map[key].append(core["processor"])
 
-print "============================================================"
-print "Core and Socket Information (as reported by '/proc/cpuinfo')"
-print "============================================================\n"
-print "cores = ", cores
-print "sockets = ", sockets
-print ""
+print("============================================================")
+print("Core and Socket Information (as reported by '/proc/cpuinfo')")
+print("============================================================\n")
+print("cores = ", cores)
+print("sockets = ", sockets)
+print("")
 
 max_processor_len = len(str(len(cores) * len(sockets) * 2 - 1))
 max_core_map_len = max_processor_len * 2 + len('[, ]') + len('Socket ')
 max_core_id_len = len(str(max(cores)))
 
-print " ".ljust(max_core_id_len + len('Core ')),
+output = " ".ljust(max_core_id_len + len('Core '))
 for s in sockets:
-    print "Socket %s" % str(s).ljust(max_core_map_len - len('Socket ')),
-print ""
+    output += " Socket %s" % str(s).ljust(max_core_map_len - len('Socket '))
+print(output)
 
-print " ".ljust(max_core_id_len + len('Core ')),
+output = " ".ljust(max_core_id_len + len('Core '))
 for s in sockets:
-    print "--------".ljust(max_core_map_len),
-print ""
+    output += " --------".ljust(max_core_map_len)
+    output += " "
+print(output)
 
 for c in cores:
-    print "Core %s" % str(c).ljust(max_core_id_len),
+    output = "Core %s" % str(c).ljust(max_core_id_len)
     for s in sockets:
-        print str(core_map[(s, c)]).ljust(max_core_map_len),
-    print ""
+        output += " " + str(core_map[(s, c)]).ljust(max_core_map_len)
+    print(output)
diff --git a/tools/dpdk-devbind.py b/tools/dpdk-devbind.py
index 4f51a4b..e057b87 100755
--- a/tools/dpdk-devbind.py
+++ b/tools/dpdk-devbind.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 #   BSD LICENSE
 #
diff --git a/tools/dpdk-pmdinfo.py b/tools/dpdk-pmdinfo.py
index 3d3ad7d..d4e51aa 100755
--- a/tools/dpdk-pmdinfo.py
+++ b/tools/dpdk-pmdinfo.py
@@ -1,9 +1,11 @@
 #!/usr/bin/env python
+
 # -------------------------------------------------------------------------
 #
 # Utility to dump PMD_INFO_STRING support from an object file
 #
 # -------------------------------------------------------------------------
+from __future__ import print_function
 import json
 import os
 import platform
@@ -54,7 +56,7 @@ def addDevice(self, deviceStr):
             self.devices[devID] = Device(deviceStr)
 
     def report(self):
-        print self.ID, self.name
+        print(self.ID, self.name)
         for id, dev in self.devices.items():
             dev.report()
 
@@ -80,7 +82,7 @@ def __init__(self, deviceStr):
         self.subdevices = {}
 
     def report(self):
-        print "\t%s\t%s" % (self.ID, self.name)
+        print("\t%s\t%s" % (self.ID, self.name))
         for subID, subdev in self.subdevices.items():
             subdev.report()
 
@@ -126,7 +128,7 @@ def __init__(self, vendor, device, name):
         self.name = name
 
     def report(self):
-        print "\t\t%s\t%s\t%s" % (self.vendorID, self.deviceID, self.name)
+        print("\t\t%s\t%s\t%s" % (self.vendorID, self.deviceID, self.name))
 
 
 class PCIIds:
@@ -154,7 +156,7 @@ def reportVendors(self):
         """Reports the vendors
         """
         for vid, v in self.vendors.items():
-            print v.ID, v.name
+            print(v.ID, v.name)
 
     def report(self, vendor=None):
         """
@@ -185,7 +187,7 @@ def findDate(self, content):
 
     def parse(self):
         if len(self.contents) < 1:
-            print "data/%s-pci.ids not found" % self.date
+            print("data/%s-pci.ids not found" % self.date)
         else:
             vendorID = ""
             deviceID = ""
@@ -432,7 +434,7 @@ def process_dt_needed_entries(self):
 
         for tag in dynsec.iter_tags():
             if tag.entry.d_tag == 'DT_NEEDED':
-                rc = tag.needed.find("librte_pmd")
+                rc = tag.needed.find(b"librte_pmd")
                 if (rc != -1):
                     library = search_file(tag.needed,
                                           runpath + ":" + ldlibpath +
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 1/3] app: make python apps pep8 compliant
From: John McNamara @ 2016-12-21 15:03 UTC (permalink / raw)
  To: dev; +Cc: mkletzan, nhorman, John McNamara
In-Reply-To: <1481212265-10229-1-git-send-email-john.mcnamara@intel.com>

Make all DPDK python application compliant with the PEP8 standard
to allow for consistency checking of patches and to allow further
refactoring.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 app/cmdline_test/cmdline_test.py                   |  81 +-
 app/cmdline_test/cmdline_test_data.py              | 401 +++++-----
 app/test/autotest.py                               |  40 +-
 app/test/autotest_data.py                          | 831 +++++++++++----------
 app/test/autotest_runner.py                        | 739 +++++++++---------
 app/test/autotest_test_funcs.py                    | 479 ++++++------
 doc/guides/conf.py                                 |   9 +-
 examples/ip_pipeline/config/diagram-generator.py   |  13 +-
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  11 +-
 tools/cpu_layout.py                                |  55 +-
 tools/dpdk-devbind.py                              |  23 +-
 tools/dpdk-pmdinfo.py                              |  61 +-
 12 files changed, 1376 insertions(+), 1367 deletions(-)

diff --git a/app/cmdline_test/cmdline_test.py b/app/cmdline_test/cmdline_test.py
index 8efc5ea..4729987 100755
--- a/app/cmdline_test/cmdline_test.py
+++ b/app/cmdline_test/cmdline_test.py
@@ -33,16 +33,21 @@
 
 # Script that runs cmdline_test app and feeds keystrokes into it.
 
-import sys, pexpect, string, os, cmdline_test_data
+import cmdline_test_data
+import os
+import pexpect
+import sys
+
 
 #
 # function to run test
 #
-def runTest(child,test):
-	child.send(test["Sequence"])
-	if test["Result"] == None:
-		return 0
-	child.expect(test["Result"],1)
+def runTest(child, test):
+    child.send(test["Sequence"])
+    if test["Result"] is None:
+        return 0
+    child.expect(test["Result"], 1)
+
 
 #
 # history test is a special case
@@ -57,57 +62,57 @@ def runTest(child,test):
 # This is a self-contained test, it needs only a pexpect child
 #
 def runHistoryTest(child):
-	# find out history size
-	child.sendline(cmdline_test_data.CMD_GET_BUFSIZE)
-	child.expect("History buffer size: \\d+", timeout=1)
-	history_size = int(child.after[len(cmdline_test_data.BUFSIZE_TEMPLATE):])
-	i = 0
+    # find out history size
+    child.sendline(cmdline_test_data.CMD_GET_BUFSIZE)
+    child.expect("History buffer size: \\d+", timeout=1)
+    history_size = int(child.after[len(cmdline_test_data.BUFSIZE_TEMPLATE):])
+    i = 0
 
-	# fill the history with numbers
-	while i < history_size / 10:
-		# add 1 to prevent from parsing as octals
-		child.send("1" + str(i).zfill(8) + cmdline_test_data.ENTER)
-		# the app will simply print out the number
-		child.expect(str(i + 100000000), timeout=1)
-		i += 1
-	# scroll back history
-	child.send(cmdline_test_data.UP * (i + 2) + cmdline_test_data.ENTER)
-	child.expect("100000000", timeout=1)
+    # fill the history with numbers
+    while i < history_size / 10:
+        # add 1 to prevent from parsing as octals
+        child.send("1" + str(i).zfill(8) + cmdline_test_data.ENTER)
+        # the app will simply print out the number
+        child.expect(str(i + 100000000), timeout=1)
+        i += 1
+    # scroll back history
+    child.send(cmdline_test_data.UP * (i + 2) + cmdline_test_data.ENTER)
+    child.expect("100000000", timeout=1)
 
 # the path to cmdline_test executable is supplied via command-line.
 if len(sys.argv) < 2:
-	print "Error: please supply cmdline_test app path"
-	sys.exit(1)
+    print "Error: please supply cmdline_test app path"
+    sys.exit(1)
 
 test_app_path = sys.argv[1]
 
 if not os.path.exists(test_app_path):
-	print "Error: please supply cmdline_test app path"
-	sys.exit(1)
+    print "Error: please supply cmdline_test app path"
+    sys.exit(1)
 
 child = pexpect.spawn(test_app_path)
 
 print "Running command-line tests..."
 for test in cmdline_test_data.tests:
-	print (test["Name"] + ":").ljust(30),
-	try:
-		runTest(child,test)
-		print "PASS"
-	except:
-		print "FAIL"
-		print child
-		sys.exit(1)
+    print (test["Name"] + ":").ljust(30),
+    try:
+        runTest(child, test)
+        print "PASS"
+    except:
+        print "FAIL"
+        print child
+        sys.exit(1)
 
 # since last test quits the app, run new instance
 child = pexpect.spawn(test_app_path)
 
 print ("History fill test:").ljust(30),
 try:
-	runHistoryTest(child)
-	print "PASS"
+    runHistoryTest(child)
+    print "PASS"
 except:
-	print "FAIL"
-	print child
-	sys.exit(1)
+    print "FAIL"
+    print child
+    sys.exit(1)
 child.close()
 sys.exit(0)
diff --git a/app/cmdline_test/cmdline_test_data.py b/app/cmdline_test/cmdline_test_data.py
index b1945a5..3ce6cbc 100644
--- a/app/cmdline_test/cmdline_test_data.py
+++ b/app/cmdline_test/cmdline_test_data.py
@@ -33,8 +33,6 @@
 
 # collection of static data
 
-import sys
-
 # keycode constants
 CTRL_A = chr(1)
 CTRL_B = chr(2)
@@ -95,217 +93,220 @@
 # and expected output (if any).
 
 tests = [
-# test basic commands
-	{"Name" : "command test 1",
-	 "Sequence" : "ambiguous first" + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "command test 2",
-	 "Sequence" : "ambiguous second" + ENTER,
-	 "Result" : CMD2},
-	{"Name" : "command test 3",
-	 "Sequence" : "ambiguous ambiguous" + ENTER,
-	 "Result" : AMBIG},
-	{"Name" : "command test 4",
-	 "Sequence" : "ambiguous ambiguous2" + ENTER,
-	 "Result" : AMBIG},
+    # test basic commands
+    {"Name": "command test 1",
+     "Sequence": "ambiguous first" + ENTER,
+     "Result": CMD1},
+    {"Name": "command test 2",
+     "Sequence": "ambiguous second" + ENTER,
+     "Result": CMD2},
+    {"Name": "command test 3",
+     "Sequence": "ambiguous ambiguous" + ENTER,
+     "Result": AMBIG},
+    {"Name": "command test 4",
+     "Sequence": "ambiguous ambiguous2" + ENTER,
+     "Result": AMBIG},
 
-	{"Name" : "invalid command test 1",
-	 "Sequence" : "ambiguous invalid" + ENTER,
-	 "Result" : BAD_ARG},
-# test invalid commands
-	{"Name" : "invalid command test 2",
-	 "Sequence" : "invalid" + ENTER,
-	 "Result" : NOT_FOUND},
-	{"Name" : "invalid command test 3",
-	 "Sequence" : "ambiguousinvalid" + ENTER2,
-	 "Result" : NOT_FOUND},
+    {"Name": "invalid command test 1",
+     "Sequence": "ambiguous invalid" + ENTER,
+     "Result": BAD_ARG},
+    # test invalid commands
+    {"Name": "invalid command test 2",
+     "Sequence": "invalid" + ENTER,
+     "Result": NOT_FOUND},
+    {"Name": "invalid command test 3",
+     "Sequence": "ambiguousinvalid" + ENTER2,
+     "Result": NOT_FOUND},
 
-# test arrows and deletes
-	{"Name" : "arrows & delete test 1",
-	 "Sequence" : "singlebad" + LEFT*2 + CTRL_B + DEL*3 + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "arrows & delete test 2",
-	 "Sequence" : "singlebad" + LEFT*5 + RIGHT + CTRL_F + DEL*3 + ENTER,
-	 "Result" : SINGLE},
+    # test arrows and deletes
+    {"Name": "arrows & delete test 1",
+     "Sequence": "singlebad" + LEFT*2 + CTRL_B + DEL*3 + ENTER,
+     "Result": SINGLE},
+    {"Name": "arrows & delete test 2",
+     "Sequence": "singlebad" + LEFT*5 + RIGHT + CTRL_F + DEL*3 + ENTER,
+     "Result": SINGLE},
 
-# test backspace
-	{"Name" : "backspace test",
-	 "Sequence" : "singlebad" + BKSPACE*3 + ENTER,
-	 "Result" : SINGLE},
+    # test backspace
+    {"Name": "backspace test",
+     "Sequence": "singlebad" + BKSPACE*3 + ENTER,
+     "Result": SINGLE},
 
-# test goto left and goto right
-	{"Name" : "goto left test",
-	 "Sequence" : "biguous first" + CTRL_A + "am" + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "goto right test",
-	 "Sequence" : "biguous fir" + CTRL_A + "am" + CTRL_E + "st" + ENTER,
-	 "Result" : CMD1},
+    # test goto left and goto right
+    {"Name": "goto left test",
+     "Sequence": "biguous first" + CTRL_A + "am" + ENTER,
+     "Result": CMD1},
+    {"Name": "goto right test",
+     "Sequence": "biguous fir" + CTRL_A + "am" + CTRL_E + "st" + ENTER,
+     "Result": CMD1},
 
-# test goto words
-	{"Name" : "goto left word test",
-	 "Sequence" : "ambiguous st" + ALT_B + "fir" + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "goto right word test",
-	 "Sequence" : "ambig first" + CTRL_A + ALT_F + "uous" + ENTER,
-	 "Result" : CMD1},
+    # test goto words
+    {"Name": "goto left word test",
+     "Sequence": "ambiguous st" + ALT_B + "fir" + ENTER,
+     "Result": CMD1},
+    {"Name": "goto right word test",
+     "Sequence": "ambig first" + CTRL_A + ALT_F + "uous" + ENTER,
+     "Result": CMD1},
 
-# test removing words
-	{"Name" : "remove left word 1",
-	 "Sequence" : "single invalid" + CTRL_W + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "remove left word 2",
-	 "Sequence" : "single invalid" + ALT_BKSPACE + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "remove right word",
-	 "Sequence" : "single invalid" + ALT_B + ALT_D + ENTER,
-	 "Result" : SINGLE},
+    # test removing words
+    {"Name": "remove left word 1",
+     "Sequence": "single invalid" + CTRL_W + ENTER,
+     "Result": SINGLE},
+    {"Name": "remove left word 2",
+     "Sequence": "single invalid" + ALT_BKSPACE + ENTER,
+     "Result": SINGLE},
+    {"Name": "remove right word",
+     "Sequence": "single invalid" + ALT_B + ALT_D + ENTER,
+     "Result": SINGLE},
 
-# test kill buffer (copy and paste)
-	{"Name" : "killbuffer test 1",
-	 "Sequence" : "ambiguous" + CTRL_A + CTRL_K + " first" + CTRL_A + CTRL_Y + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "killbuffer test 2",
-	 "Sequence" : "ambiguous" + CTRL_A + CTRL_K + CTRL_Y*26 + ENTER,
-	 "Result" : NOT_FOUND},
+    # test kill buffer (copy and paste)
+    {"Name": "killbuffer test 1",
+     "Sequence": "ambiguous" + CTRL_A + CTRL_K + " first" + CTRL_A +
+                 CTRL_Y + ENTER,
+     "Result": CMD1},
+    {"Name": "killbuffer test 2",
+     "Sequence": "ambiguous" + CTRL_A + CTRL_K + CTRL_Y*26 + ENTER,
+     "Result": NOT_FOUND},
 
-# test newline
-	{"Name" : "newline test",
-	 "Sequence" : "invalid" + CTRL_C + "single" + ENTER,
-	 "Result" : SINGLE},
+    # test newline
+    {"Name": "newline test",
+     "Sequence": "invalid" + CTRL_C + "single" + ENTER,
+     "Result": SINGLE},
 
-# test redisplay (nothing should really happen)
-	{"Name" : "redisplay test",
-	 "Sequence" : "single" + CTRL_L + ENTER,
-	 "Result" : SINGLE},
+    # test redisplay (nothing should really happen)
+    {"Name": "redisplay test",
+     "Sequence": "single" + CTRL_L + ENTER,
+     "Result": SINGLE},
 
-# test autocomplete
-	{"Name" : "autocomplete test 1",
-	 "Sequence" : "si" + TAB + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "autocomplete test 2",
-	 "Sequence" : "si" + TAB + "_" + TAB + ENTER,
-	 "Result" : SINGLE_LONG},
-	{"Name" : "autocomplete test 3",
-	 "Sequence" : "in" + TAB + ENTER,
-	 "Result" : NOT_FOUND},
-	{"Name" : "autocomplete test 4",
-	 "Sequence" : "am" + TAB + ENTER,
-	 "Result" : BAD_ARG},
-	{"Name" : "autocomplete test 5",
-	 "Sequence" : "am" + TAB + "fir" + TAB + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "autocomplete test 6",
-	 "Sequence" : "am" + TAB + "fir" + TAB + TAB + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "autocomplete test 7",
-	 "Sequence" : "am" + TAB + "fir" + TAB + " " + TAB + ENTER,
-	 "Result" : CMD1},
-	{"Name" : "autocomplete test 8",
-	 "Sequence" : "am" + TAB + "     am" + TAB + "   " + ENTER,
-	 "Result" : AMBIG},
-	{"Name" : "autocomplete test 9",
-	 "Sequence" : "am" + TAB + "inv" + TAB + ENTER,
-	 "Result" : BAD_ARG},
-	{"Name" : "autocomplete test 10",
-	 "Sequence" : "au" + TAB + ENTER,
-	 "Result" : NOT_FOUND},
-	{"Name" : "autocomplete test 11",
-	 "Sequence" : "au" + TAB + "1" + ENTER,
-	 "Result" : AUTO1},
-	{"Name" : "autocomplete test 12",
-	 "Sequence" : "au" + TAB + "2" + ENTER,
-	 "Result" : AUTO2},
-	{"Name" : "autocomplete test 13",
-	 "Sequence" : "au" + TAB + "2" + TAB + ENTER,
-	 "Result" : AUTO2},
-	{"Name" : "autocomplete test 14",
-	 "Sequence" : "au" + TAB + "2   " + TAB + ENTER,
-	 "Result" : AUTO2},
-	{"Name" : "autocomplete test 15",
-	 "Sequence" : "24" + TAB + ENTER,
-	 "Result" : "24"},
+    # test autocomplete
+    {"Name": "autocomplete test 1",
+     "Sequence": "si" + TAB + ENTER,
+     "Result": SINGLE},
+    {"Name": "autocomplete test 2",
+     "Sequence": "si" + TAB + "_" + TAB + ENTER,
+     "Result": SINGLE_LONG},
+    {"Name": "autocomplete test 3",
+     "Sequence": "in" + TAB + ENTER,
+     "Result": NOT_FOUND},
+    {"Name": "autocomplete test 4",
+     "Sequence": "am" + TAB + ENTER,
+     "Result": BAD_ARG},
+    {"Name": "autocomplete test 5",
+     "Sequence": "am" + TAB + "fir" + TAB + ENTER,
+     "Result": CMD1},
+    {"Name": "autocomplete test 6",
+     "Sequence": "am" + TAB + "fir" + TAB + TAB + ENTER,
+     "Result": CMD1},
+    {"Name": "autocomplete test 7",
+     "Sequence": "am" + TAB + "fir" + TAB + " " + TAB + ENTER,
+     "Result": CMD1},
+    {"Name": "autocomplete test 8",
+     "Sequence": "am" + TAB + "     am" + TAB + "   " + ENTER,
+     "Result": AMBIG},
+    {"Name": "autocomplete test 9",
+     "Sequence": "am" + TAB + "inv" + TAB + ENTER,
+     "Result": BAD_ARG},
+    {"Name": "autocomplete test 10",
+     "Sequence": "au" + TAB + ENTER,
+     "Result": NOT_FOUND},
+    {"Name": "autocomplete test 11",
+     "Sequence": "au" + TAB + "1" + ENTER,
+     "Result": AUTO1},
+    {"Name": "autocomplete test 12",
+     "Sequence": "au" + TAB + "2" + ENTER,
+     "Result": AUTO2},
+    {"Name": "autocomplete test 13",
+     "Sequence": "au" + TAB + "2" + TAB + ENTER,
+     "Result": AUTO2},
+    {"Name": "autocomplete test 14",
+     "Sequence": "au" + TAB + "2   " + TAB + ENTER,
+     "Result": AUTO2},
+    {"Name": "autocomplete test 15",
+     "Sequence": "24" + TAB + ENTER,
+     "Result": "24"},
 
-# test history
-	{"Name" : "history test 1",
-	 "Sequence" : "invalid" + ENTER + "single" + ENTER + "invalid" + ENTER + UP + CTRL_P + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "history test 2",
-	 "Sequence" : "invalid" + ENTER + "ambiguous first" + ENTER + "invalid" + ENTER + "single" + ENTER + UP * 3 + CTRL_N + DOWN + ENTER,
-	 "Result" : SINGLE},
+    # test history
+    {"Name": "history test 1",
+     "Sequence": "invalid" + ENTER + "single" + ENTER + "invalid" +
+                 ENTER + UP + CTRL_P + ENTER,
+     "Result": SINGLE},
+    {"Name": "history test 2",
+     "Sequence": "invalid" + ENTER + "ambiguous first" + ENTER + "invalid" +
+                 ENTER + "single" + ENTER + UP * 3 + CTRL_N + DOWN + ENTER,
+     "Result": SINGLE},
 
-#
-# tests that improve coverage
-#
+    #
+    # tests that improve coverage
+    #
 
-# empty space tests
-	{"Name" : "empty space test 1",
-	 "Sequence" : RIGHT + LEFT + CTRL_B + CTRL_F + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 2",
-	 "Sequence" : BKSPACE + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 3",
-	 "Sequence" : CTRL_E*2 + CTRL_A*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 4",
-	 "Sequence" : ALT_F*2 + ALT_B*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 5",
-	 "Sequence" : " " + CTRL_E*2 + CTRL_A*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 6",
-	 "Sequence" : " " + CTRL_A + ALT_F*2 + ALT_B*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 7",
-	 "Sequence" : "  " + CTRL_A + CTRL_D + CTRL_E + CTRL_D + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 8",
-	 "Sequence" : " space" + CTRL_W*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 9",
-	 "Sequence" : " space" + ALT_BKSPACE*2 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "empty space test 10",
-	 "Sequence" : " space " + CTRL_A + ALT_D*3 + ENTER,
-	 "Result" : PROMPT},
+    # empty space tests
+    {"Name": "empty space test 1",
+     "Sequence": RIGHT + LEFT + CTRL_B + CTRL_F + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 2",
+     "Sequence": BKSPACE + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 3",
+     "Sequence": CTRL_E*2 + CTRL_A*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 4",
+     "Sequence": ALT_F*2 + ALT_B*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 5",
+     "Sequence": " " + CTRL_E*2 + CTRL_A*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 6",
+     "Sequence": " " + CTRL_A + ALT_F*2 + ALT_B*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 7",
+     "Sequence": "  " + CTRL_A + CTRL_D + CTRL_E + CTRL_D + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 8",
+     "Sequence": " space" + CTRL_W*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 9",
+     "Sequence": " space" + ALT_BKSPACE*2 + ENTER,
+     "Result": PROMPT},
+    {"Name": "empty space test 10",
+     "Sequence": " space " + CTRL_A + ALT_D*3 + ENTER,
+     "Result": PROMPT},
 
-# non-printable char tests
-	{"Name" : "non-printable test 1",
-	 "Sequence" : chr(27) + chr(47) + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "non-printable test 2",
-	 "Sequence" : chr(27) + chr(128) + ENTER*7,
-	 "Result" : PROMPT},
-	{"Name" : "non-printable test 3",
-	 "Sequence" : chr(27) + chr(91) + chr(127) + ENTER*6,
-	 "Result" : PROMPT},
+    # non-printable char tests
+    {"Name": "non-printable test 1",
+     "Sequence": chr(27) + chr(47) + ENTER,
+     "Result": PROMPT},
+    {"Name": "non-printable test 2",
+     "Sequence": chr(27) + chr(128) + ENTER*7,
+     "Result": PROMPT},
+    {"Name": "non-printable test 3",
+     "Sequence": chr(27) + chr(91) + chr(127) + ENTER*6,
+     "Result": PROMPT},
 
-# miscellaneous tests
-	{"Name" : "misc test 1",
-	 "Sequence" : ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "misc test 2",
-	 "Sequence" : "single #comment" + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "misc test 3",
-	 "Sequence" : "#empty line" + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "misc test 4",
-	 "Sequence" : "   single  " + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "misc test 5",
-	 "Sequence" : "single#" + ENTER,
-	 "Result" : SINGLE},
-	{"Name" : "misc test 6",
-	 "Sequence" : 'a' * 257 + ENTER,
-	 "Result" : NOT_FOUND},
-	{"Name" : "misc test 7",
-	 "Sequence" : "clear_history" + UP*5 + DOWN*5 + ENTER,
-	 "Result" : PROMPT},
-	{"Name" : "misc test 8",
-	 "Sequence" : "a" + HELP + CTRL_C,
-	 "Result" : PROMPT},
-	{"Name" : "misc test 9",
-	 "Sequence" : CTRL_D*3,
-	 "Result" : None},
+    # miscellaneous tests
+    {"Name": "misc test 1",
+     "Sequence": ENTER,
+     "Result": PROMPT},
+    {"Name": "misc test 2",
+     "Sequence": "single #comment" + ENTER,
+     "Result": SINGLE},
+    {"Name": "misc test 3",
+     "Sequence": "#empty line" + ENTER,
+     "Result": PROMPT},
+    {"Name": "misc test 4",
+     "Sequence": "   single  " + ENTER,
+     "Result": SINGLE},
+    {"Name": "misc test 5",
+     "Sequence": "single#" + ENTER,
+     "Result": SINGLE},
+    {"Name": "misc test 6",
+     "Sequence": 'a' * 257 + ENTER,
+     "Result": NOT_FOUND},
+    {"Name": "misc test 7",
+     "Sequence": "clear_history" + UP*5 + DOWN*5 + ENTER,
+     "Result": PROMPT},
+    {"Name": "misc test 8",
+     "Sequence": "a" + HELP + CTRL_C,
+     "Result": PROMPT},
+    {"Name": "misc test 9",
+     "Sequence": CTRL_D*3,
+     "Result": None},
 ]
diff --git a/app/test/autotest.py b/app/test/autotest.py
index b9fd6b6..3a00538 100644
--- a/app/test/autotest.py
+++ b/app/test/autotest.py
@@ -33,44 +33,46 @@
 
 # Script that uses either test app or qemu controlled by python-pexpect
 
-import sys, autotest_data, autotest_runner
-
+import autotest_data
+import autotest_runner
+import sys
 
 
 def usage():
-	print"Usage: autotest.py [test app|test iso image]",
-	print "[target] [whitelist|-blacklist]"
+    print"Usage: autotest.py [test app|test iso image]",
+    print "[target] [whitelist|-blacklist]"
 
 if len(sys.argv) < 3:
-	usage()
-	sys.exit(1)
+    usage()
+    sys.exit(1)
 
 target = sys.argv[2]
 
-test_whitelist=None
-test_blacklist=None
+test_whitelist = None
+test_blacklist = None
 
 # get blacklist/whitelist
 if len(sys.argv) > 3:
-	testlist = sys.argv[3].split(',')
-	testlist = [test.lower() for test in testlist]
-	if testlist[0].startswith('-'):
-		testlist[0] = testlist[0].lstrip('-')
-		test_blacklist = testlist
-	else:
-		test_whitelist = testlist
+    testlist = sys.argv[3].split(',')
+    testlist = [test.lower() for test in testlist]
+    if testlist[0].startswith('-'):
+        testlist[0] = testlist[0].lstrip('-')
+        test_blacklist = testlist
+    else:
+        test_whitelist = testlist
 
-cmdline  = "%s -c f -n 4"%(sys.argv[1])
+cmdline = "%s -c f -n 4" % (sys.argv[1])
 
 print cmdline
 
-runner = autotest_runner.AutotestRunner(cmdline, target, test_blacklist, test_whitelist)
+runner = autotest_runner.AutotestRunner(cmdline, target, test_blacklist,
+                                        test_whitelist)
 
 for test_group in autotest_data.parallel_test_group_list:
-	runner.add_parallel_test_group(test_group)
+    runner.add_parallel_test_group(test_group)
 
 for test_group in autotest_data.non_parallel_test_group_list:
-	runner.add_non_parallel_test_group(test_group)
+    runner.add_non_parallel_test_group(test_group)
 
 num_fails = runner.run_all_tests()
 
diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
index 9e8fd94..0cf4cfd 100644
--- a/app/test/autotest_data.py
+++ b/app/test/autotest_data.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 #   BSD LICENSE
 #
@@ -36,12 +36,14 @@
 from glob import glob
 from autotest_test_funcs import *
 
+
 # quick and dirty function to find out number of sockets
 def num_sockets():
-	result = len(glob("/sys/devices/system/node/node*"))
-	if result == 0:
-		return 1
-	return result
+    result = len(glob("/sys/devices/system/node/node*"))
+    if result == 0:
+        return 1
+    return result
+
 
 # Assign given number to each socket
 # e.g. 32 becomes 32,32 or 32,32,32,32
@@ -51,420 +53,419 @@ def per_sockets(num):
 # groups of tests that can be run in parallel
 # the grouping has been found largely empirically
 parallel_test_group_list = [
-
-{
-	"Prefix":	"group_1",
-	"Memory" :	per_sockets(8),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Cycles autotest",
-		 "Command" : 	"cycles_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Timer autotest",
-		 "Command" : 	"timer_autotest",
-		 "Func" :	timer_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Debug autotest",
-		 "Command" : 	"debug_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Errno autotest",
-		 "Command" : 	"errno_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Meter autotest",
-		 "Command" : 	"meter_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Common autotest",
-		 "Command" : 	"common_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Resource autotest",
-		 "Command" :	"resource_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"group_2",
-	"Memory" :	"16",
-	"Tests" :
-	[
-		{
-		 "Name" :	"Memory autotest",
-		 "Command" :	"memory_autotest",
-		 "Func" :	memory_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Read/write lock autotest",
-		 "Command" : 	"rwlock_autotest",
-		 "Func" :	rwlock_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Logs autotest",
-		 "Command" : 	"logs_autotest",
-		 "Func" :	logs_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"CPU flags autotest",
-		 "Command" : 	"cpuflags_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Version autotest",
-		 "Command" : 	"version_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"EAL filesystem autotest",
-		 "Command" : 	"eal_fs_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"EAL flags autotest",
-		 "Command" : 	"eal_flags_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Hash autotest",
-		 "Command" : 	"hash_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	],
-},
-{
-	"Prefix":	"group_3",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"LPM autotest",
-		 "Command" : 	"lpm_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-			"Name" :    "LPM6 autotest",
-			"Command" : "lpm6_autotest",
-			"Func" :    default_autotest,
-			"Report" :  None,
-		},
-		{
-		 "Name" :	"Memcpy autotest",
-		 "Command" : 	"memcpy_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Memzone autotest",
-		 "Command" : 	"memzone_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"String autotest",
-		 "Command" : 	"string_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Alarm autotest",
-		 "Command" :	"alarm_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"group_4",
-	"Memory" :	per_sockets(128),
-	"Tests" :
-	[
-		{
-		 "Name" :	"PCI autotest",
-		 "Command" :	"pci_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Malloc autotest",
-		 "Command" : 	"malloc_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Multi-process autotest",
-		 "Command" : 	"multiprocess_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Mbuf autotest",
-		 "Command" : 	"mbuf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Per-lcore autotest",
-		 "Command" : 	"per_lcore_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Ring autotest",
-		 "Command" : 	"ring_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"group_5",
-	"Memory" :	"32",
-	"Tests" :
-	[
-		{
-		 "Name" :	"Spinlock autotest",
-		 "Command" : 	"spinlock_autotest",
-		 "Func" :	spinlock_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Byte order autotest",
-		 "Command" : 	"byteorder_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"TAILQ autotest",
-		 "Command" : 	"tailq_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Command-line autotest",
-		 "Command" : 	"cmdline_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Interrupts autotest",
-		 "Command" : 	"interrupt_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"group_6",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Function reentrancy autotest",
-		 "Command" : 	"func_reentrancy_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Mempool autotest",
-		 "Command" : 	"mempool_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Atomics autotest",
-		 "Command" : 	"atomic_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Prefetch autotest",
-		 "Command" : 	"prefetch_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		 },
-		{
-		 "Name" :"Red autotest",
-		 "Command" : "red_autotest",
-		 "Func" :default_autotest,
-		 "Report" :None,
-		 },
-	]
-},
-{
-	"Prefix" :	"group_7",
-	"Memory" :	"64",
-	"Tests" :
-	[
-		{
-		 "Name" :	"PMD ring autotest",
-		 "Command" :	"ring_pmd_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		{
-		 "Name" :	"Access list control autotest",
-		 "Command" : 	"acl_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-		 {
-		 "Name" :"Sched autotest",
-		 "Command" : "sched_autotest",
-		 "Func" :default_autotest,
-		 "Report" :None,
-		 },
-	]
-},
+    {
+        "Prefix":    "group_1",
+        "Memory":    per_sockets(8),
+        "Tests":
+        [
+            {
+                "Name":    "Cycles autotest",
+                "Command": "cycles_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Timer autotest",
+                "Command": "timer_autotest",
+                "Func":    timer_autotest,
+                "Report":   None,
+            },
+            {
+                "Name":    "Debug autotest",
+                "Command": "debug_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Errno autotest",
+                "Command": "errno_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Meter autotest",
+                "Command": "meter_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Common autotest",
+                "Command": "common_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Resource autotest",
+                "Command": "resource_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "group_2",
+        "Memory":    "16",
+        "Tests":
+        [
+            {
+                "Name":    "Memory autotest",
+                "Command": "memory_autotest",
+                "Func":    memory_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Read/write lock autotest",
+                "Command": "rwlock_autotest",
+                "Func":    rwlock_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Logs autotest",
+                "Command": "logs_autotest",
+                "Func":    logs_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "CPU flags autotest",
+                "Command": "cpuflags_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Version autotest",
+                "Command": "version_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "EAL filesystem autotest",
+                "Command": "eal_fs_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "EAL flags autotest",
+                "Command": "eal_flags_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Hash autotest",
+                "Command": "hash_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ],
+    },
+    {
+        "Prefix":    "group_3",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "LPM autotest",
+                "Command": "lpm_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "LPM6 autotest",
+                "Command": "lpm6_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Memcpy autotest",
+                "Command": "memcpy_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Memzone autotest",
+                "Command": "memzone_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "String autotest",
+                "Command": "string_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Alarm autotest",
+                "Command": "alarm_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "group_4",
+        "Memory":    per_sockets(128),
+        "Tests":
+        [
+            {
+                "Name":    "PCI autotest",
+                "Command": "pci_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Malloc autotest",
+                "Command": "malloc_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Multi-process autotest",
+                "Command": "multiprocess_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Mbuf autotest",
+                "Command": "mbuf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Per-lcore autotest",
+                "Command": "per_lcore_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Ring autotest",
+                "Command": "ring_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "group_5",
+        "Memory":    "32",
+        "Tests":
+        [
+            {
+                "Name":    "Spinlock autotest",
+                "Command": "spinlock_autotest",
+                "Func":    spinlock_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Byte order autotest",
+                "Command": "byteorder_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "TAILQ autotest",
+                "Command": "tailq_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Command-line autotest",
+                "Command": "cmdline_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Interrupts autotest",
+                "Command": "interrupt_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "group_6",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "Function reentrancy autotest",
+                "Command": "func_reentrancy_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Mempool autotest",
+                "Command": "mempool_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Atomics autotest",
+                "Command": "atomic_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Prefetch autotest",
+                "Command": "prefetch_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Red autotest",
+                "Command": "red_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "group_7",
+        "Memory":    "64",
+        "Tests":
+        [
+            {
+                "Name":    "PMD ring autotest",
+                "Command": "ring_pmd_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Access list control autotest",
+                "Command": "acl_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+            {
+                "Name":    "Sched autotest",
+                "Command": "sched_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
 ]
 
 # tests that should not be run when any other tests are running
 non_parallel_test_group_list = [
 
-{
-	"Prefix" :	"kni",
-	"Memory" :	"512",
-	"Tests" :
-	[
-		{
-		 "Name" :	"KNI autotest",
-		 "Command" :	"kni_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"mempool_perf",
-	"Memory" :	per_sockets(256),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Mempool performance autotest",
-		 "Command" : 	"mempool_perf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"memcpy_perf",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Memcpy performance autotest",
-		 "Command" : 	"memcpy_perf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix":	"hash_perf",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Hash performance autotest",
-		 "Command" : 	"hash_perf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
-{
-	"Prefix" :      "power",
-	"Memory" :      "16",
-	"Tests" :
-	[
-		{
-		 "Name" :       "Power autotest",
-		 "Command" :    "power_autotest",
-		 "Func" :       default_autotest,
-		 "Report" :     None,
-		},
-	]
-},
-{
-	"Prefix" :      "power_acpi_cpufreq",
-	"Memory" :      "16",
-	"Tests" :
-	[
-		{
-		 "Name" :       "Power ACPI cpufreq autotest",
-		 "Command" :    "power_acpi_cpufreq_autotest",
-		 "Func" :       default_autotest,
-		 "Report" :     None,
-		},
-	]
-},
-{
-	"Prefix" :      "power_kvm_vm",
-	"Memory" :      "16",
-	"Tests" :
-	[
-		{
-		 "Name" :       "Power KVM VM  autotest",
-		 "Command" :    "power_kvm_vm_autotest",
-		 "Func" :       default_autotest,
-		 "Report" :     None,
-		},
-	]
-},
-{
-	"Prefix":	"timer_perf",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Timer performance autotest",
-		 "Command" : 	"timer_perf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
+    {
+        "Prefix":    "kni",
+        "Memory":    "512",
+        "Tests":
+        [
+            {
+                "Name":    "KNI autotest",
+                "Command": "kni_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "mempool_perf",
+        "Memory":    per_sockets(256),
+        "Tests":
+        [
+            {
+                "Name":    "Mempool performance autotest",
+                "Command": "mempool_perf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "memcpy_perf",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "Memcpy performance autotest",
+                "Command": "memcpy_perf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "hash_perf",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "Hash performance autotest",
+                "Command": "hash_perf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
+    {
+        "Prefix":      "power",
+        "Memory":      "16",
+        "Tests":
+        [
+            {
+                "Name":       "Power autotest",
+                "Command":    "power_autotest",
+                "Func":       default_autotest,
+                "Report":      None,
+            },
+        ]
+    },
+    {
+        "Prefix":      "power_acpi_cpufreq",
+        "Memory":      "16",
+        "Tests":
+        [
+            {
+                "Name":       "Power ACPI cpufreq autotest",
+                "Command":    "power_acpi_cpufreq_autotest",
+                "Func":       default_autotest,
+                "Report":     None,
+            },
+        ]
+    },
+    {
+        "Prefix":      "power_kvm_vm",
+        "Memory":      "16",
+        "Tests":
+        [
+            {
+                "Name":       "Power KVM VM  autotest",
+                "Command":    "power_kvm_vm_autotest",
+                "Func":       default_autotest,
+                "Report":     None,
+            },
+        ]
+    },
+    {
+        "Prefix":    "timer_perf",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "Timer performance autotest",
+                "Command": "timer_perf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
 
-#
-# Please always make sure that ring_perf is the last test!
-#
-{
-	"Prefix":	"ring_perf",
-	"Memory" :	per_sockets(512),
-	"Tests" :
-	[
-		{
-		 "Name" :	"Ring performance autotest",
-		 "Command" : 	"ring_perf_autotest",
-		 "Func" :	default_autotest,
-		 "Report" :	None,
-		},
-	]
-},
+    #
+    # Please always make sure that ring_perf is the last test!
+    #
+    {
+        "Prefix":    "ring_perf",
+        "Memory":    per_sockets(512),
+        "Tests":
+        [
+            {
+                "Name":    "Ring performance autotest",
+                "Command": "ring_perf_autotest",
+                "Func":    default_autotest,
+                "Report":  None,
+            },
+        ]
+    },
 ]
diff --git a/app/test/autotest_runner.py b/app/test/autotest_runner.py
index 21d3be2..55b63a8 100644
--- a/app/test/autotest_runner.py
+++ b/app/test/autotest_runner.py
@@ -33,20 +33,29 @@
 
 # The main logic behind running autotests in parallel
 
-import multiprocessing, subprocess, sys, pexpect, re, time, os, StringIO, csv
+import StringIO
+import csv
+import multiprocessing
+import pexpect
+import re
+import subprocess
+import sys
+import time
 
 # wait for prompt
+
+
 def wait_prompt(child):
-	try:
-		child.sendline()
-		result = child.expect(["RTE>>", pexpect.TIMEOUT, pexpect.EOF],
-			timeout = 120)
-	except:
-		return False
-	if result == 0:
-		return True
-	else:
-		return False
+    try:
+        child.sendline()
+        result = child.expect(["RTE>>", pexpect.TIMEOUT, pexpect.EOF],
+                              timeout=120)
+    except:
+        return False
+    if result == 0:
+        return True
+    else:
+        return False
 
 # run a test group
 # each result tuple in results list consists of:
@@ -60,363 +69,363 @@ def wait_prompt(child):
 # this function needs to be outside AutotestRunner class
 # because otherwise Pool won't work (or rather it will require
 # quite a bit of effort to make it work).
-def run_test_group(cmdline, test_group):
-	results = []
-	child = None
-	start_time = time.time()
-	startuplog = None
-
-	# run test app
-	try:
-		# prepare logging of init
-		startuplog = StringIO.StringIO()
-
-		print >>startuplog, "\n%s %s\n" % ("="*20, test_group["Prefix"])
-		print >>startuplog, "\ncmdline=%s" % cmdline
-
-		child = pexpect.spawn(cmdline, logfile=startuplog)
-
-		# wait for target to boot
-		if not wait_prompt(child):
-			child.close()
-
-			results.append((-1, "Fail [No prompt]", "Start %s" % test_group["Prefix"],
-				time.time() - start_time, startuplog.getvalue(), None))
-
-			# mark all tests as failed
-			for test in test_group["Tests"]:
-				results.append((-1, "Fail [No prompt]", test["Name"],
-				time.time() - start_time, "", None))
-			# exit test
-			return results
-
-	except:
-		results.append((-1, "Fail [Can't run]", "Start %s" % test_group["Prefix"],
-				time.time() - start_time, startuplog.getvalue(), None))
-
-		# mark all tests as failed
-		for t in test_group["Tests"]:
-			results.append((-1, "Fail [Can't run]", t["Name"],
-				time.time() - start_time, "", None))
-		# exit test
-		return results
-
-	# startup was successful
-	results.append((0, "Success", "Start %s" % test_group["Prefix"],
-		time.time() - start_time, startuplog.getvalue(), None))
-
-	# parse the binary for available test commands
-	binary = cmdline.split()[0]
-	stripped = 'not stripped' not in subprocess.check_output(['file', binary])
-	if not stripped:
-		symbols = subprocess.check_output(['nm', binary]).decode('utf-8')
-		avail_cmds = re.findall('test_register_(\w+)', symbols)
-
-	# run all tests in test group
-	for test in test_group["Tests"]:
-
-		# create log buffer for each test
-		# in multiprocessing environment, the logging would be
-		# interleaved and will create a mess, hence the buffering
-		logfile = StringIO.StringIO()
-		child.logfile = logfile
-
-		result = ()
-
-		# make a note when the test started
-		start_time = time.time()
-
-		try:
-			# print test name to log buffer
-			print >>logfile, "\n%s %s\n" % ("-"*20, test["Name"])
-
-			# run test function associated with the test
-			if stripped or test["Command"] in avail_cmds:
-				result = test["Func"](child, test["Command"])
-			else:
-				result = (0, "Skipped [Not Available]")
-
-			# make a note when the test was finished
-			end_time = time.time()
-
-			# append test data to the result tuple
-			result += (test["Name"], end_time - start_time,
-				logfile.getvalue())
-
-			# call report function, if any defined, and supply it with
-			# target and complete log for test run
-			if test["Report"]:
-				report = test["Report"](self.target, log)
-
-				# append report to results tuple
-				result += (report,)
-			else:
-				# report is None
-				result += (None,)
-		except:
-			# make a note when the test crashed
-			end_time = time.time()
-
-			# mark test as failed
-			result = (-1, "Fail [Crash]", test["Name"],
-				end_time - start_time, logfile.getvalue(), None)
-		finally:
-			# append the results to the results list
-			results.append(result)
-
-	# regardless of whether test has crashed, try quitting it
-	try:
-		child.sendline("quit")
-		child.close()
-	# if the test crashed, just do nothing instead
-	except:
-		# nop
-		pass
-
-	# return test results
-	return results
-
 
 
+def run_test_group(cmdline, test_group):
+    results = []
+    child = None
+    start_time = time.time()
+    startuplog = None
+
+    # run test app
+    try:
+        # prepare logging of init
+        startuplog = StringIO.StringIO()
+
+        print >>startuplog, "\n%s %s\n" % ("=" * 20, test_group["Prefix"])
+        print >>startuplog, "\ncmdline=%s" % cmdline
+
+        child = pexpect.spawn(cmdline, logfile=startuplog)
+
+        # wait for target to boot
+        if not wait_prompt(child):
+            child.close()
+
+            results.append((-1,
+                            "Fail [No prompt]",
+                            "Start %s" % test_group["Prefix"],
+                            time.time() - start_time,
+                            startuplog.getvalue(),
+                            None))
+
+            # mark all tests as failed
+            for test in test_group["Tests"]:
+                results.append((-1, "Fail [No prompt]", test["Name"],
+                                time.time() - start_time, "", None))
+            # exit test
+            return results
+
+    except:
+        results.append((-1,
+                        "Fail [Can't run]",
+                        "Start %s" % test_group["Prefix"],
+                        time.time() - start_time,
+                        startuplog.getvalue(),
+                        None))
+
+        # mark all tests as failed
+        for t in test_group["Tests"]:
+            results.append((-1, "Fail [Can't run]", t["Name"],
+                            time.time() - start_time, "", None))
+        # exit test
+        return results
+
+    # startup was successful
+    results.append((0, "Success", "Start %s" % test_group["Prefix"],
+                    time.time() - start_time, startuplog.getvalue(), None))
+
+    # parse the binary for available test commands
+    binary = cmdline.split()[0]
+    stripped = 'not stripped' not in subprocess.check_output(['file', binary])
+    if not stripped:
+        symbols = subprocess.check_output(['nm', binary]).decode('utf-8')
+        avail_cmds = re.findall('test_register_(\w+)', symbols)
+
+    # run all tests in test group
+    for test in test_group["Tests"]:
+
+        # create log buffer for each test
+        # in multiprocessing environment, the logging would be
+        # interleaved and will create a mess, hence the buffering
+        logfile = StringIO.StringIO()
+        child.logfile = logfile
+
+        result = ()
+
+        # make a note when the test started
+        start_time = time.time()
+
+        try:
+            # print test name to log buffer
+            print >>logfile, "\n%s %s\n" % ("-" * 20, test["Name"])
+
+            # run test function associated with the test
+            if stripped or test["Command"] in avail_cmds:
+                result = test["Func"](child, test["Command"])
+            else:
+                result = (0, "Skipped [Not Available]")
+
+            # make a note when the test was finished
+            end_time = time.time()
+
+            # append test data to the result tuple
+            result += (test["Name"], end_time - start_time,
+                       logfile.getvalue())
+
+            # call report function, if any defined, and supply it with
+            # target and complete log for test run
+            if test["Report"]:
+                report = test["Report"](self.target, log)
+
+                # append report to results tuple
+                result += (report,)
+            else:
+                # report is None
+                result += (None,)
+        except:
+            # make a note when the test crashed
+            end_time = time.time()
+
+            # mark test as failed
+            result = (-1, "Fail [Crash]", test["Name"],
+                      end_time - start_time, logfile.getvalue(), None)
+        finally:
+            # append the results to the results list
+            results.append(result)
+
+    # regardless of whether test has crashed, try quitting it
+    try:
+        child.sendline("quit")
+        child.close()
+    # if the test crashed, just do nothing instead
+    except:
+        # nop
+        pass
+
+    # return test results
+    return results
 
 
 # class representing an instance of autotests run
 class AutotestRunner:
-	cmdline = ""
-	parallel_test_groups = []
-	non_parallel_test_groups = []
-	logfile = None
-	csvwriter = None
-	target = ""
-	start = None
-	n_tests = 0
-	fails = 0
-	log_buffers = []
-	blacklist = []
-	whitelist = []
-
-
-	def __init__(self, cmdline, target, blacklist, whitelist):
-		self.cmdline = cmdline
-		self.target = target
-		self.blacklist = blacklist
-		self.whitelist = whitelist
-
-		# log file filename
-		logfile = "%s.log" % target
-		csvfile = "%s.csv" % target
-
-		self.logfile = open(logfile, "w")
-		csvfile = open(csvfile, "w")
-		self.csvwriter = csv.writer(csvfile)
-
-		# prepare results table
-		self.csvwriter.writerow(["test_name","test_result","result_str"])
-
-
-
-	# set up cmdline string
-	def __get_cmdline(self, test):
-		cmdline = self.cmdline
-
-		# append memory limitations for each test
-		# otherwise tests won't run in parallel
-		if not "i686" in self.target:
-			cmdline += " --socket-mem=%s"% test["Memory"]
-		else:
-			# affinitize startup so that tests don't fail on i686
-			cmdline = "taskset 1 " + cmdline
-			cmdline += " -m " + str(sum(map(int,test["Memory"].split(","))))
-
-		# set group prefix for autotest group
-		# otherwise they won't run in parallel
-		cmdline += " --file-prefix=%s"% test["Prefix"]
-
-		return cmdline
-
-
-
-	def add_parallel_test_group(self,test_group):
-		self.parallel_test_groups.append(test_group)
-
-	def add_non_parallel_test_group(self,test_group):
-		self.non_parallel_test_groups.append(test_group)
-
-
-	def __process_results(self, results):
-		# this iterates over individual test results
-		for i, result in enumerate(results):
-
-			# increase total number of tests that were run
-			# do not include "start" test
-			if i > 0:
-				self.n_tests += 1
-
-			# unpack result tuple
-			test_result, result_str, test_name, \
-				test_time, log, report = result
-
-			# get total run time
-			cur_time = time.time()
-			total_time = int(cur_time - self.start)
-
-			# print results, test run time and total time since start
-			print ("%s:" % test_name).ljust(30),
-			print result_str.ljust(29),
-			print "[%02dm %02ds]" % (test_time / 60, test_time % 60),
-
-			# don't print out total time every line, it's the same anyway
-			if i == len(results) - 1:
-				print "[%02dm %02ds]" % (total_time / 60, total_time % 60)
-			else:
-				print ""
-
-			# if test failed and it wasn't a "start" test
-			if test_result < 0 and not i == 0:
-				self.fails += 1
-
-			# collect logs
-			self.log_buffers.append(log)
-
-			# create report if it exists
-			if report:
-				try:
-					f = open("%s_%s_report.rst" % (self.target,test_name), "w")
-				except IOError:
-					print "Report for %s could not be created!" % test_name
-				else:
-					with f:
-						f.write(report)
-
-			# write test result to CSV file
-			if i != 0:
-				self.csvwriter.writerow([test_name, test_result, result_str])
-
-
-
-
-	# this function iterates over test groups and removes each
-	# test that is not in whitelist/blacklist
-	def __filter_groups(self, test_groups):
-		groups_to_remove = []
-
-		# filter out tests from parallel test groups
-		for i, test_group in enumerate(test_groups):
-
-			# iterate over a copy so that we could safely delete individual tests
-			for test in test_group["Tests"][:]:
-				test_id = test["Command"]
-
-				# dump tests are specified in full e.g. "Dump_mempool"
-				if "_autotest" in test_id:
-					test_id = test_id[:-len("_autotest")]
-
-				# filter out blacklisted/whitelisted tests
-				if self.blacklist and test_id in self.blacklist:
-					test_group["Tests"].remove(test)
-					continue
-				if self.whitelist and test_id not in self.whitelist:
-					test_group["Tests"].remove(test)
-					continue
-
-			# modify or remove original group
-			if len(test_group["Tests"]) > 0:
-				test_groups[i] = test_group
-			else:
-				# remember which groups should be deleted
-				# put the numbers backwards so that we start
-				# deleting from the end, not from the beginning
-				groups_to_remove.insert(0, i)
-
-		# remove test groups that need to be removed
-		for i in groups_to_remove:
-			del test_groups[i]
-
-		return test_groups
-
-
-
-	# iterate over test groups and run tests associated with them
-	def run_all_tests(self):
-		# filter groups
-		self.parallel_test_groups = \
-			self.__filter_groups(self.parallel_test_groups)
-		self.non_parallel_test_groups = \
-			self.__filter_groups(self.non_parallel_test_groups)
-
-		# create a pool of worker threads
-		pool = multiprocessing.Pool(processes=1)
-
-		results = []
-
-		# whatever happens, try to save as much logs as possible
-		try:
-
-			# create table header
-			print ""
-			print "Test name".ljust(30),
-			print "Test result".ljust(29),
-			print "Test".center(9),
-			print "Total".center(9)
-			print "=" * 80
-
-			# make a note of tests start time
-			self.start = time.time()
-
-			# assign worker threads to run test groups
-			for test_group in self.parallel_test_groups:
-				result = pool.apply_async(run_test_group,
-					[self.__get_cmdline(test_group), test_group])
-				results.append(result)
-
-			# iterate while we have group execution results to get
-			while len(results) > 0:
-
-				# iterate over a copy to be able to safely delete results
-				# this iterates over a list of group results
-				for group_result in results[:]:
-
-					# if the thread hasn't finished yet, continue
-					if not group_result.ready():
-						continue
-
-					res = group_result.get()
-
-					self.__process_results(res)
-
-					# remove result from results list once we're done with it
-					results.remove(group_result)
-
-			# run non_parallel tests. they are run one by one, synchronously
-			for test_group in self.non_parallel_test_groups:
-				group_result = run_test_group(self.__get_cmdline(test_group), test_group)
-
-				self.__process_results(group_result)
-
-			# get total run time
-			cur_time = time.time()
-			total_time = int(cur_time - self.start)
-
-			# print out summary
-			print "=" * 80
-			print "Total run time: %02dm %02ds" % (total_time / 60, total_time % 60)
-			if self.fails != 0:
-				print "Number of failed tests: %s" % str(self.fails)
-
-			# write summary to logfile
-			self.logfile.write("Summary\n")
-			self.logfile.write("Target: ".ljust(15) + "%s\n" % self.target)
-			self.logfile.write("Tests: ".ljust(15) + "%i\n" % self.n_tests)
-			self.logfile.write("Failed tests: ".ljust(15) + "%i\n" % self.fails)
-		except:
-			print "Exception occured"
-			print sys.exc_info()
-			self.fails = 1
-
-		# drop logs from all executions to a logfile
-		for buf in self.log_buffers:
-			self.logfile.write(buf.replace("\r",""))
-
-		log_buffers = []
-
-		return self.fails
+    cmdline = ""
+    parallel_test_groups = []
+    non_parallel_test_groups = []
+    logfile = None
+    csvwriter = None
+    target = ""
+    start = None
+    n_tests = 0
+    fails = 0
+    log_buffers = []
+    blacklist = []
+    whitelist = []
+
+    def __init__(self, cmdline, target, blacklist, whitelist):
+        self.cmdline = cmdline
+        self.target = target
+        self.blacklist = blacklist
+        self.whitelist = whitelist
+
+        # log file filename
+        logfile = "%s.log" % target
+        csvfile = "%s.csv" % target
+
+        self.logfile = open(logfile, "w")
+        csvfile = open(csvfile, "w")
+        self.csvwriter = csv.writer(csvfile)
+
+        # prepare results table
+        self.csvwriter.writerow(["test_name", "test_result", "result_str"])
+
+    # set up cmdline string
+    def __get_cmdline(self, test):
+        cmdline = self.cmdline
+
+        # append memory limitations for each test
+        # otherwise tests won't run in parallel
+        if "i686" not in self.target:
+            cmdline += " --socket-mem=%s" % test["Memory"]
+        else:
+            # affinitize startup so that tests don't fail on i686
+            cmdline = "taskset 1 " + cmdline
+            cmdline += " -m " + str(sum(map(int, test["Memory"].split(","))))
+
+        # set group prefix for autotest group
+        # otherwise they won't run in parallel
+        cmdline += " --file-prefix=%s" % test["Prefix"]
+
+        return cmdline
+
+    def add_parallel_test_group(self, test_group):
+        self.parallel_test_groups.append(test_group)
+
+    def add_non_parallel_test_group(self, test_group):
+        self.non_parallel_test_groups.append(test_group)
+
+    def __process_results(self, results):
+        # this iterates over individual test results
+        for i, result in enumerate(results):
+
+            # increase total number of tests that were run
+            # do not include "start" test
+            if i > 0:
+                self.n_tests += 1
+
+            # unpack result tuple
+            test_result, result_str, test_name, \
+                test_time, log, report = result
+
+            # get total run time
+            cur_time = time.time()
+            total_time = int(cur_time - self.start)
+
+            # print results, test run time and total time since start
+            print ("%s:" % test_name).ljust(30),
+            print result_str.ljust(29),
+            print "[%02dm %02ds]" % (test_time / 60, test_time % 60),
+
+            # don't print out total time every line, it's the same anyway
+            if i == len(results) - 1:
+                print "[%02dm %02ds]" % (total_time / 60, total_time % 60)
+            else:
+                print ""
+
+            # if test failed and it wasn't a "start" test
+            if test_result < 0 and not i == 0:
+                self.fails += 1
+
+            # collect logs
+            self.log_buffers.append(log)
+
+            # create report if it exists
+            if report:
+                try:
+                    f = open("%s_%s_report.rst" %
+                             (self.target, test_name), "w")
+                except IOError:
+                    print "Report for %s could not be created!" % test_name
+                else:
+                    with f:
+                        f.write(report)
+
+            # write test result to CSV file
+            if i != 0:
+                self.csvwriter.writerow([test_name, test_result, result_str])
+
+    # this function iterates over test groups and removes each
+    # test that is not in whitelist/blacklist
+    def __filter_groups(self, test_groups):
+        groups_to_remove = []
+
+        # filter out tests from parallel test groups
+        for i, test_group in enumerate(test_groups):
+
+            # iterate over a copy so that we could safely delete individual
+            # tests
+            for test in test_group["Tests"][:]:
+                test_id = test["Command"]
+
+                # dump tests are specified in full e.g. "Dump_mempool"
+                if "_autotest" in test_id:
+                    test_id = test_id[:-len("_autotest")]
+
+                # filter out blacklisted/whitelisted tests
+                if self.blacklist and test_id in self.blacklist:
+                    test_group["Tests"].remove(test)
+                    continue
+                if self.whitelist and test_id not in self.whitelist:
+                    test_group["Tests"].remove(test)
+                    continue
+
+            # modify or remove original group
+            if len(test_group["Tests"]) > 0:
+                test_groups[i] = test_group
+            else:
+                # remember which groups should be deleted
+                # put the numbers backwards so that we start
+                # deleting from the end, not from the beginning
+                groups_to_remove.insert(0, i)
+
+        # remove test groups that need to be removed
+        for i in groups_to_remove:
+            del test_groups[i]
+
+        return test_groups
+
+    # iterate over test groups and run tests associated with them
+    def run_all_tests(self):
+        # filter groups
+        self.parallel_test_groups = \
+            self.__filter_groups(self.parallel_test_groups)
+        self.non_parallel_test_groups = \
+            self.__filter_groups(self.non_parallel_test_groups)
+
+        # create a pool of worker threads
+        pool = multiprocessing.Pool(processes=1)
+
+        results = []
+
+        # whatever happens, try to save as much logs as possible
+        try:
+
+            # create table header
+            print ""
+            print "Test name".ljust(30),
+            print "Test result".ljust(29),
+            print "Test".center(9),
+            print "Total".center(9)
+            print "=" * 80
+
+            # make a note of tests start time
+            self.start = time.time()
+
+            # assign worker threads to run test groups
+            for test_group in self.parallel_test_groups:
+                result = pool.apply_async(run_test_group,
+                                          [self.__get_cmdline(test_group),
+                                           test_group])
+                results.append(result)
+
+            # iterate while we have group execution results to get
+            while len(results) > 0:
+
+                # iterate over a copy to be able to safely delete results
+                # this iterates over a list of group results
+                for group_result in results[:]:
+
+                    # if the thread hasn't finished yet, continue
+                    if not group_result.ready():
+                        continue
+
+                    res = group_result.get()
+
+                    self.__process_results(res)
+
+                    # remove result from results list once we're done with it
+                    results.remove(group_result)
+
+            # run non_parallel tests. they are run one by one, synchronously
+            for test_group in self.non_parallel_test_groups:
+                group_result = run_test_group(
+                    self.__get_cmdline(test_group), test_group)
+
+                self.__process_results(group_result)
+
+            # get total run time
+            cur_time = time.time()
+            total_time = int(cur_time - self.start)
+
+            # print out summary
+            print "=" * 80
+            print "Total run time: %02dm %02ds" % (total_time / 60,
+                                                   total_time % 60)
+            if self.fails != 0:
+                print "Number of failed tests: %s" % str(self.fails)
+
+            # write summary to logfile
+            self.logfile.write("Summary\n")
+            self.logfile.write("Target: ".ljust(15) + "%s\n" % self.target)
+            self.logfile.write("Tests: ".ljust(15) + "%i\n" % self.n_tests)
+            self.logfile.write("Failed tests: ".ljust(
+                15) + "%i\n" % self.fails)
+        except:
+            print "Exception occurred"
+            print sys.exc_info()
+            self.fails = 1
+
+        # drop logs from all executions to a logfile
+        for buf in self.log_buffers:
+            self.logfile.write(buf.replace("\r", ""))
+
+        return self.fails
diff --git a/app/test/autotest_test_funcs.py b/app/test/autotest_test_funcs.py
index 14cffd0..c482ea8 100644
--- a/app/test/autotest_test_funcs.py
+++ b/app/test/autotest_test_funcs.py
@@ -33,257 +33,272 @@
 
 # Test functions
 
-import sys, pexpect, time, os, re
+import pexpect
 
 # default autotest, used to run most tests
 # waits for "Test OK"
+
+
 def default_autotest(child, test_name):
-	child.sendline(test_name)
-	result = child.expect(["Test OK", "Test Failed",
-		"Command not found", pexpect.TIMEOUT], timeout = 900)
-	if result == 1:
-		return -1, "Fail"
-	elif result == 2:
-		return -1, "Fail [Not found]"
-	elif result == 3:
-		return -1, "Fail [Timeout]"
-	return 0, "Success"
+    child.sendline(test_name)
+    result = child.expect(["Test OK", "Test Failed",
+                           "Command not found", pexpect.TIMEOUT], timeout=900)
+    if result == 1:
+        return -1, "Fail"
+    elif result == 2:
+        return -1, "Fail [Not found]"
+    elif result == 3:
+        return -1, "Fail [Timeout]"
+    return 0, "Success"
 
 # autotest used to run dump commands
 # just fires the command
+
+
 def dump_autotest(child, test_name):
-	child.sendline(test_name)
-	return 0, "Success"
+    child.sendline(test_name)
+    return 0, "Success"
 
 # memory autotest
 # reads output and waits for Test OK
+
+
 def memory_autotest(child, test_name):
-	child.sendline(test_name)
-	regexp = "phys:0x[0-9a-f]*, len:([0-9]*), virt:0x[0-9a-f]*, socket_id:[0-9]*"
-	index = child.expect([regexp, pexpect.TIMEOUT], timeout = 180)
-	if index != 0:
-		return -1, "Fail [Timeout]"
-	size = int(child.match.groups()[0], 16)
-	if size <= 0:
-		return -1, "Fail [Bad size]"
-	index = child.expect(["Test OK", "Test Failed",
-		          pexpect.TIMEOUT], timeout = 10)
-	if index == 1:
-		return -1, "Fail"
-	elif index == 2:
-		return -1, "Fail [Timeout]"
-	return 0, "Success"
+    child.sendline(test_name)
+    regexp = "phys:0x[0-9a-f]*, len:([0-9]*), virt:0x[0-9a-f]*, " \
+             "socket_id:[0-9]*"
+    index = child.expect([regexp, pexpect.TIMEOUT], timeout=180)
+    if index != 0:
+        return -1, "Fail [Timeout]"
+    size = int(child.match.groups()[0], 16)
+    if size <= 0:
+        return -1, "Fail [Bad size]"
+    index = child.expect(["Test OK", "Test Failed",
+                          pexpect.TIMEOUT], timeout=10)
+    if index == 1:
+        return -1, "Fail"
+    elif index == 2:
+        return -1, "Fail [Timeout]"
+    return 0, "Success"
+
 
 def spinlock_autotest(child, test_name):
-	i = 0
-	ir = 0
-	child.sendline(test_name)
-	while True:
-		index = child.expect(["Test OK",
-			"Test Failed",
-			"Hello from core ([0-9]*) !",
-			"Hello from within recursive locks from ([0-9]*) !",
-		pexpect.TIMEOUT], timeout = 5)
-		# ok
-		if index == 0:
-			break
-
-		# message, check ordering
-		elif index == 2:
-			if int(child.match.groups()[0]) < i:
-				return -1, "Fail [Bad order]"
-			i = int(child.match.groups()[0])
-		elif index == 3:
-			if int(child.match.groups()[0]) < ir:
-				return -1, "Fail [Bad order]"
-			ir = int(child.match.groups()[0])
-
-		# fail
-		elif index == 4:
-			return -1, "Fail [Timeout]"
-		elif index == 1:
-			return -1, "Fail"
-
-	return 0, "Success"
+    i = 0
+    ir = 0
+    child.sendline(test_name)
+    while True:
+        index = child.expect(["Test OK",
+                              "Test Failed",
+                              "Hello from core ([0-9]*) !",
+                              "Hello from within recursive locks "
+                              "from ([0-9]*) !",
+                              pexpect.TIMEOUT], timeout=5)
+        # ok
+        if index == 0:
+            break
+
+        # message, check ordering
+        elif index == 2:
+            if int(child.match.groups()[0]) < i:
+                return -1, "Fail [Bad order]"
+            i = int(child.match.groups()[0])
+        elif index == 3:
+            if int(child.match.groups()[0]) < ir:
+                return -1, "Fail [Bad order]"
+            ir = int(child.match.groups()[0])
+
+        # fail
+        elif index == 4:
+            return -1, "Fail [Timeout]"
+        elif index == 1:
+            return -1, "Fail"
+
+    return 0, "Success"
+
 
 def rwlock_autotest(child, test_name):
-	i = 0
-	child.sendline(test_name)
-	while True:
-		index = child.expect(["Test OK",
-			"Test Failed",
-			"Hello from core ([0-9]*) !",
-			"Global write lock taken on master core ([0-9]*)",
-		pexpect.TIMEOUT], timeout = 10)
-		# ok
-		if index == 0:
-			if i != 0xffff:
-				return -1, "Fail [Message is missing]"
-			break
-
-		# message, check ordering
-		elif index == 2:
-			if int(child.match.groups()[0]) < i:
-				return -1, "Fail [Bad order]"
-			i = int(child.match.groups()[0])
-
-		# must be the last message, check ordering
-		elif index == 3:
-			i = 0xffff
-
-		elif index == 4:
-			return -1, "Fail [Timeout]"
-
-		# fail
-		else:
-			return -1, "Fail"
-
-	return 0, "Success"
+    i = 0
+    child.sendline(test_name)
+    while True:
+        index = child.expect(["Test OK",
+                              "Test Failed",
+                              "Hello from core ([0-9]*) !",
+                              "Global write lock taken on master "
+                              "core ([0-9]*)",
+                              pexpect.TIMEOUT], timeout=10)
+        # ok
+        if index == 0:
+            if i != 0xffff:
+                return -1, "Fail [Message is missing]"
+            break
+
+        # message, check ordering
+        elif index == 2:
+            if int(child.match.groups()[0]) < i:
+                return -1, "Fail [Bad order]"
+            i = int(child.match.groups()[0])
+
+        # must be the last message, check ordering
+        elif index == 3:
+            i = 0xffff
+
+        elif index == 4:
+            return -1, "Fail [Timeout]"
+
+        # fail
+        else:
+            return -1, "Fail"
+
+    return 0, "Success"
+
 
 def logs_autotest(child, test_name):
-	i = 0
-	child.sendline(test_name)
-
-	log_list = [
-		"TESTAPP1: error message",
-		"TESTAPP1: critical message",
-		"TESTAPP2: critical message",
-		"TESTAPP1: error message",
-	]
-
-	for log_msg in log_list:
-		index = child.expect([log_msg,
-				      "Test OK",
-				      "Test Failed",
-				      pexpect.TIMEOUT], timeout = 10)
-
-		if index == 3:
-			return -1, "Fail [Timeout]"
-		# not ok
-		elif index != 0:
-			return -1, "Fail"
-
-	index = child.expect(["Test OK",
-		"Test Failed",
-		pexpect.TIMEOUT], timeout = 10)
-
-	return 0, "Success"
+    child.sendline(test_name)
+
+    log_list = [
+        "TESTAPP1: error message",
+        "TESTAPP1: critical message",
+        "TESTAPP2: critical message",
+        "TESTAPP1: error message",
+    ]
+
+    for log_msg in log_list:
+        index = child.expect([log_msg,
+                              "Test OK",
+                              "Test Failed",
+                              pexpect.TIMEOUT], timeout=10)
+
+        if index == 3:
+            return -1, "Fail [Timeout]"
+        # not ok
+        elif index != 0:
+            return -1, "Fail"
+
+    index = child.expect(["Test OK",
+                          "Test Failed",
+                          pexpect.TIMEOUT], timeout=10)
+
+    return 0, "Success"
+
 
 def timer_autotest(child, test_name):
-	i = 0
-	child.sendline(test_name)
-
-	index = child.expect(["Start timer stress tests",
-		"Test Failed",
-		pexpect.TIMEOUT], timeout = 5)
-
-	if index == 1:
-		return -1, "Fail"
-	elif index == 2:
-		return -1, "Fail [Timeout]"
-
-	index = child.expect(["Start timer stress tests 2",
-		"Test Failed",
-		pexpect.TIMEOUT], timeout = 5)
-
-	if index == 1:
-		return -1, "Fail"
-	elif index == 2:
-		return -1, "Fail [Timeout]"
-
-	index = child.expect(["Start timer basic tests",
-		"Test Failed",
-		pexpect.TIMEOUT], timeout = 5)
-
-	if index == 1:
-		return -1, "Fail"
-	elif index == 2:
-		return -1, "Fail [Timeout]"
-
-	prev_lcore_timer1 = -1
-
-	lcore_tim0 = -1
-	lcore_tim1 = -1
-	lcore_tim2 = -1
-	lcore_tim3 = -1
-
-	while True:
-		index = child.expect(["TESTTIMER: ([0-9]*): callback id=([0-9]*) count=([0-9]*) on core ([0-9]*)",
-			"Test OK",
-			"Test Failed",
-			pexpect.TIMEOUT], timeout = 10)
-
-		if index == 1:
-			break
-
-		if index == 2:
-			return -1, "Fail"
-		elif index == 3:
-			return -1, "Fail [Timeout]"
-
-		try:
-			t = int(child.match.groups()[0])
-			id = int(child.match.groups()[1])
-			cnt = int(child.match.groups()[2])
-			lcore = int(child.match.groups()[3])
-		except:
-			return -1, "Fail [Cannot parse]"
-
-		# timer0 always expires on the same core when cnt < 20
-		if id == 0:
-			if lcore_tim0 == -1:
-				lcore_tim0 = lcore
-			elif lcore != lcore_tim0 and cnt < 20:
-				return -1, "Fail [lcore != lcore_tim0 (%d, %d)]"%(lcore, lcore_tim0)
-			if cnt > 21:
-				return -1, "Fail [tim0 cnt > 21]"
-
-		# timer1 each time expires on a different core
-		if id == 1:
-			if lcore == lcore_tim1:
-				return -1, "Fail [lcore == lcore_tim1 (%d, %d)]"%(lcore, lcore_tim1)
-			lcore_tim1 = lcore
-			if cnt > 10:
-				return -1, "Fail [tim1 cnt > 30]"
-
-		# timer0 always expires on the same core
-		if id == 2:
-			if lcore_tim2 == -1:
-				lcore_tim2 = lcore
-			elif lcore != lcore_tim2:
-				return -1, "Fail [lcore != lcore_tim2 (%d, %d)]"%(lcore, lcore_tim2)
-			if cnt > 30:
-				return -1, "Fail [tim2 cnt > 30]"
-
-		# timer0 always expires on the same core
-		if id == 3:
-			if lcore_tim3 == -1:
-				lcore_tim3 = lcore
-			elif lcore != lcore_tim3:
-				return -1, "Fail [lcore_tim3 changed (%d -> %d)]"%(lcore, lcore_tim3)
-			if cnt > 30:
-				return -1, "Fail [tim3 cnt > 30]"
-
-	# must be 2 different cores
-	if lcore_tim0 == lcore_tim3:
-		return -1, "Fail [lcore_tim0 (%d) == lcore_tim3 (%d)]"%(lcore_tim0, lcore_tim3)
-
-	return 0, "Success"
+    child.sendline(test_name)
+
+    index = child.expect(["Start timer stress tests",
+                          "Test Failed",
+                          pexpect.TIMEOUT], timeout=5)
+
+    if index == 1:
+        return -1, "Fail"
+    elif index == 2:
+        return -1, "Fail [Timeout]"
+
+    index = child.expect(["Start timer stress tests 2",
+                          "Test Failed",
+                          pexpect.TIMEOUT], timeout=5)
+
+    if index == 1:
+        return -1, "Fail"
+    elif index == 2:
+        return -1, "Fail [Timeout]"
+
+    index = child.expect(["Start timer basic tests",
+                          "Test Failed",
+                          pexpect.TIMEOUT], timeout=5)
+
+    if index == 1:
+        return -1, "Fail"
+    elif index == 2:
+        return -1, "Fail [Timeout]"
+
+    lcore_tim0 = -1
+    lcore_tim1 = -1
+    lcore_tim2 = -1
+    lcore_tim3 = -1
+
+    while True:
+        index = child.expect(["TESTTIMER: ([0-9]*): callback id=([0-9]*) "
+                              "count=([0-9]*) on core ([0-9]*)",
+                              "Test OK",
+                              "Test Failed",
+                              pexpect.TIMEOUT], timeout=10)
+
+        if index == 1:
+            break
+
+        if index == 2:
+            return -1, "Fail"
+        elif index == 3:
+            return -1, "Fail [Timeout]"
+
+        try:
+            id = int(child.match.groups()[1])
+            cnt = int(child.match.groups()[2])
+            lcore = int(child.match.groups()[3])
+        except:
+            return -1, "Fail [Cannot parse]"
+
+        # timer0 always expires on the same core when cnt < 20
+        if id == 0:
+            if lcore_tim0 == -1:
+                lcore_tim0 = lcore
+            elif lcore != lcore_tim0 and cnt < 20:
+                return -1, "Fail [lcore != lcore_tim0 (%d, %d)]" \
+                    % (lcore, lcore_tim0)
+            if cnt > 21:
+                return -1, "Fail [tim0 cnt > 21]"
+
+        # timer1 each time expires on a different core
+        if id == 1:
+            if lcore == lcore_tim1:
+                return -1, "Fail [lcore == lcore_tim1 (%d, %d)]" \
+                    % (lcore, lcore_tim1)
+            lcore_tim1 = lcore
+            if cnt > 10:
+                return -1, "Fail [tim1 cnt > 30]"
+
+        # timer0 always expires on the same core
+        if id == 2:
+            if lcore_tim2 == -1:
+                lcore_tim2 = lcore
+            elif lcore != lcore_tim2:
+                return -1, "Fail [lcore != lcore_tim2 (%d, %d)]" \
+                    % (lcore, lcore_tim2)
+            if cnt > 30:
+                return -1, "Fail [tim2 cnt > 30]"
+
+        # timer0 always expires on the same core
+        if id == 3:
+            if lcore_tim3 == -1:
+                lcore_tim3 = lcore
+            elif lcore != lcore_tim3:
+                return -1, "Fail [lcore_tim3 changed (%d -> %d)]" \
+                    % (lcore, lcore_tim3)
+            if cnt > 30:
+                return -1, "Fail [tim3 cnt > 30]"
+
+    # must be 2 different cores
+    if lcore_tim0 == lcore_tim3:
+        return -1, "Fail [lcore_tim0 (%d) == lcore_tim3 (%d)]" \
+            % (lcore_tim0, lcore_tim3)
+
+    return 0, "Success"
+
 
 def ring_autotest(child, test_name):
-	child.sendline(test_name)
-	index = child.expect(["Test OK", "Test Failed",
-		pexpect.TIMEOUT], timeout = 2)
-	if index == 1:
-		return -1, "Fail"
-	elif index == 2:
-		return -1, "Fail [Timeout]"
-
-	child.sendline("set_watermark test 100")
-	child.sendline("dump_ring test")
-	index = child.expect(["  watermark=100",
-		pexpect.TIMEOUT], timeout = 1)
-	if index != 0:
-		return -1, "Fail [Bad watermark]"
-
-	return 0, "Success"
+    child.sendline(test_name)
+    index = child.expect(["Test OK", "Test Failed",
+                          pexpect.TIMEOUT], timeout=2)
+    if index == 1:
+        return -1, "Fail"
+    elif index == 2:
+        return -1, "Fail [Timeout]"
+
+    child.sendline("set_watermark test 100")
+    child.sendline("dump_ring test")
+    index = child.expect(["  watermark=100",
+                          pexpect.TIMEOUT], timeout=1)
+    if index != 0:
+        return -1, "Fail [Bad watermark]"
+
+    return 0, "Success"
diff --git a/doc/guides/conf.py b/doc/guides/conf.py
index 29e8efb..34c62de 100644
--- a/doc/guides/conf.py
+++ b/doc/guides/conf.py
@@ -58,7 +58,8 @@
 html_show_copyright = False
 highlight_language = 'none'
 
-version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion']).decode('utf-8').rstrip()
+version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion'])
+version = version.decode('utf-8').rstrip()
 release = version
 
 master_doc = 'index'
@@ -94,6 +95,7 @@
     'preamble': latex_preamble
 }
 
+
 # Override the default Latex formatter in order to modify the
 # code/verbatim blocks.
 class CustomLatexFormatter(LatexFormatter):
@@ -117,12 +119,12 @@ def __init__(self, **options):
              ("tools/devbind", "dpdk-devbind",
               "check device status and bind/unbind them from drivers", "", 8)]
 
-######## :numref: fallback ########
+
+# ####### :numref: fallback ########
 # The following hook functions add some simple handling for the :numref:
 # directive for Sphinx versions prior to 1.3.1. The functions replace the
 # :numref: reference with a link to the target (for all Sphinx doc types).
 # It doesn't try to label figures/tables.
-
 def numref_role(reftype, rawtext, text, lineno, inliner):
     """
     Add a Sphinx role to handle numref references. Note, we can't convert
@@ -136,6 +138,7 @@ def numref_role(reftype, rawtext, text, lineno, inliner):
                               internal=True)
     return [newnode], []
 
+
 def process_numref(app, doctree, from_docname):
     """
     Process the numref nodes once the doctree has been built and prior to
diff --git a/examples/ip_pipeline/config/diagram-generator.py b/examples/ip_pipeline/config/diagram-generator.py
index 6b7170b..1748833 100755
--- a/examples/ip_pipeline/config/diagram-generator.py
+++ b/examples/ip_pipeline/config/diagram-generator.py
@@ -36,7 +36,8 @@
 # the DPDK ip_pipeline application.
 #
 # The input configuration file is translated to an output file in DOT syntax,
-# which is then used to create the image file using graphviz (www.graphviz.org).
+# which is then used to create the image file using graphviz
+# (www.graphviz.org).
 #
 
 from __future__ import print_function
@@ -94,6 +95,7 @@
 # SOURCEx | SOURCEx    | SOURCEx     | PIPELINEy     | SOURCEx
 # SINKx   | SINKx      | PIPELINEy   | SINKx         | SINKx
 
+
 #
 # Parse the input configuration file to detect the graph nodes and edges
 #
@@ -321,16 +323,17 @@ def process_config_file(cfgfile):
     #
     print('Creating image file "%s" ...' % imgfile)
     if os.system('which dot > /dev/null'):
-        print('Error: Unable to locate "dot" executable.' \
-            'Please install the "graphviz" package (www.graphviz.org).')
+        print('Error: Unable to locate "dot" executable.'
+              'Please install the "graphviz" package (www.graphviz.org).')
         return
 
     os.system(dot_cmd)
 
 
 if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description=\
-        'Create diagram for IP pipeline configuration file.')
+    parser = argparse.ArgumentParser(description='Create diagram for IP '
+                                                 'pipeline configuration '
+                                                 'file.')
 
     parser.add_argument(
         '-f',
diff --git a/examples/ip_pipeline/config/pipeline-to-core-mapping.py b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
index c2050b8..7a4eaa2 100755
--- a/examples/ip_pipeline/config/pipeline-to-core-mapping.py
+++ b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
@@ -39,15 +39,14 @@
 #
 
 from __future__ import print_function
-import sys
-import errno
-import os
-import re
+from collections import namedtuple
+import argparse
 import array
+import errno
 import itertools
+import os
 import re
-import argparse
-from collections import namedtuple
+import sys
 
 # default values
 enable_stage0_traceout = 1
diff --git a/tools/cpu_layout.py b/tools/cpu_layout.py
index d38d0b5..ccc22ec 100755
--- a/tools/cpu_layout.py
+++ b/tools/cpu_layout.py
@@ -38,40 +38,40 @@
 cores = []
 core_map = {}
 
-fd=open("/proc/cpuinfo")
+fd = open("/proc/cpuinfo")
 lines = fd.readlines()
 fd.close()
 
 core_details = []
 core_lines = {}
 for line in lines:
-	if len(line.strip()) != 0:
-		name, value = line.split(":", 1)
-		core_lines[name.strip()] = value.strip()
-	else:
-		core_details.append(core_lines)
-		core_lines = {}
+    if len(line.strip()) != 0:
+        name, value = line.split(":", 1)
+        core_lines[name.strip()] = value.strip()
+    else:
+        core_details.append(core_lines)
+        core_lines = {}
 
 for core in core_details:
-	for field in ["processor", "core id", "physical id"]:
-		if field not in core:
-			print "Error getting '%s' value from /proc/cpuinfo" % field
-			sys.exit(1)
-		core[field] = int(core[field])
+    for field in ["processor", "core id", "physical id"]:
+        if field not in core:
+            print "Error getting '%s' value from /proc/cpuinfo" % field
+            sys.exit(1)
+        core[field] = int(core[field])
 
-	if core["core id"] not in cores:
-		cores.append(core["core id"])
-	if core["physical id"] not in sockets:
-		sockets.append(core["physical id"])
-	key = (core["physical id"], core["core id"])
-	if key not in core_map:
-		core_map[key] = []
-	core_map[key].append(core["processor"])
+    if core["core id"] not in cores:
+        cores.append(core["core id"])
+    if core["physical id"] not in sockets:
+        sockets.append(core["physical id"])
+    key = (core["physical id"], core["core id"])
+    if key not in core_map:
+        core_map[key] = []
+    core_map[key].append(core["processor"])
 
 print "============================================================"
 print "Core and Socket Information (as reported by '/proc/cpuinfo')"
 print "============================================================\n"
-print "cores = ",cores
+print "cores = ", cores
 print "sockets = ", sockets
 print ""
 
@@ -81,15 +81,16 @@
 
 print " ".ljust(max_core_id_len + len('Core ')),
 for s in sockets:
-        print "Socket %s" % str(s).ljust(max_core_map_len - len('Socket ')),
+    print "Socket %s" % str(s).ljust(max_core_map_len - len('Socket ')),
 print ""
+
 print " ".ljust(max_core_id_len + len('Core ')),
 for s in sockets:
-        print "--------".ljust(max_core_map_len),
+    print "--------".ljust(max_core_map_len),
 print ""
 
 for c in cores:
-        print "Core %s" % str(c).ljust(max_core_id_len),
-        for s in sockets:
-                print str(core_map[(s,c)]).ljust(max_core_map_len),
-        print ""
+    print "Core %s" % str(c).ljust(max_core_id_len),
+    for s in sockets:
+        print str(core_map[(s, c)]).ljust(max_core_map_len),
+    print ""
diff --git a/tools/dpdk-devbind.py b/tools/dpdk-devbind.py
index f1d374d..4f51a4b 100755
--- a/tools/dpdk-devbind.py
+++ b/tools/dpdk-devbind.py
@@ -93,10 +93,10 @@ def usage():
         Unbind a device (Equivalent to \"-b none\")
 
     --force:
-        By default, network devices which are used by Linux - as indicated by having
-        routes in the routing table - cannot be modified. Using the --force
-        flag overrides this behavior, allowing active links to be forcibly
-        unbound.
+        By default, network devices which are used by Linux - as indicated by
+        having routes in the routing table - cannot be modified. Using the
+        --force flag overrides this behavior, allowing active links to be
+        forcibly unbound.
         WARNING: This can lead to loss of network connection and should be used
         with caution.
 
@@ -151,7 +151,7 @@ def find_module(mod):
 
     # check for a copy based off current path
     tools_dir = dirname(abspath(sys.argv[0]))
-    if (tools_dir.endswith("tools")):
+    if tools_dir.endswith("tools"):
         base_dir = dirname(tools_dir)
         find_out = check_output(["find", base_dir, "-name", mod + ".ko"])
         if len(find_out) > 0:  # something matched
@@ -249,7 +249,7 @@ def get_nic_details():
     dev = {}
     dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines()
     for dev_line in dev_lines:
-        if (len(dev_line) == 0):
+        if len(dev_line) == 0:
             if dev["Class"][0:2] == NETWORK_BASE_CLASS:
                 # convert device and vendor ids to numbers, then add to global
                 dev["Vendor"] = int(dev["Vendor"], 16)
@@ -315,8 +315,8 @@ def get_crypto_details():
     dev = {}
     dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines()
     for dev_line in dev_lines:
-        if (len(dev_line) == 0):
-            if (dev["Class"][0:2] == CRYPTO_BASE_CLASS):
+        if len(dev_line) == 0:
+            if dev["Class"][0:2] == CRYPTO_BASE_CLASS:
                 # convert device and vendor ids to numbers, then add to global
                 dev["Vendor"] = int(dev["Vendor"], 16)
                 dev["Device"] = int(dev["Device"], 16)
@@ -513,7 +513,8 @@ def display_devices(title, dev_list, extra_params=None):
         for dev in dev_list:
             if extra_params is not None:
                 strings.append("%s '%s' %s" % (dev["Slot"],
-                               dev["Device_str"], extra_params % dev))
+                                               dev["Device_str"],
+                                               extra_params % dev))
             else:
                 strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
     # sort before printing, so that the entries appear in PCI order
@@ -532,7 +533,7 @@ def show_status():
 
     # split our list of network devices into the three categories above
     for d in devices.keys():
-        if (NETWORK_BASE_CLASS in devices[d]["Class"]):
+        if NETWORK_BASE_CLASS in devices[d]["Class"]:
             if not has_driver(d):
                 no_drv.append(devices[d])
                 continue
@@ -555,7 +556,7 @@ def show_status():
     no_drv = []
 
     for d in devices.keys():
-        if (CRYPTO_BASE_CLASS in devices[d]["Class"]):
+        if CRYPTO_BASE_CLASS in devices[d]["Class"]:
             if not has_driver(d):
                 no_drv.append(devices[d])
                 continue
diff --git a/tools/dpdk-pmdinfo.py b/tools/dpdk-pmdinfo.py
index 3db9819..3d3ad7d 100755
--- a/tools/dpdk-pmdinfo.py
+++ b/tools/dpdk-pmdinfo.py
@@ -4,52 +4,20 @@
 # Utility to dump PMD_INFO_STRING support from an object file
 #
 # -------------------------------------------------------------------------
+import json
 import os
+import platform
+import string
 import sys
+from elftools.common.exceptions import ELFError
+from elftools.common.py3compat import (byte2int, bytes2str, str2bytes)
+from elftools.elf.elffile import ELFFile
 from optparse import OptionParser
-import string
-import json
-import platform
 
 # For running from development directory. It should take precedence over the
 # installed pyelftools.
 sys.path.insert(0, '.')
 
-
-from elftools import __version__
-from elftools.common.exceptions import ELFError
-from elftools.common.py3compat import (
-    ifilter, byte2int, bytes2str, itervalues, str2bytes)
-from elftools.elf.elffile import ELFFile
-from elftools.elf.dynamic import DynamicSection, DynamicSegment
-from elftools.elf.enums import ENUM_D_TAG
-from elftools.elf.segments import InterpSegment
-from elftools.elf.sections import SymbolTableSection
-from elftools.elf.gnuversions import (
-    GNUVerSymSection, GNUVerDefSection,
-    GNUVerNeedSection,
-)
-from elftools.elf.relocation import RelocationSection
-from elftools.elf.descriptions import (
-    describe_ei_class, describe_ei_data, describe_ei_version,
-    describe_ei_osabi, describe_e_type, describe_e_machine,
-    describe_e_version_numeric, describe_p_type, describe_p_flags,
-    describe_sh_type, describe_sh_flags,
-    describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
-    describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
-    describe_ver_flags,
-)
-from elftools.elf.constants import E_FLAGS
-from elftools.dwarf.dwarfinfo import DWARFInfo
-from elftools.dwarf.descriptions import (
-    describe_reg_name, describe_attr_value, set_global_machine_arch,
-    describe_CFI_instructions, describe_CFI_register_rule,
-    describe_CFI_CFA_rule,
-)
-from elftools.dwarf.constants import (
-    DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
-from elftools.dwarf.callframe import CIE, FDE
-
 raw_output = False
 pcidb = None
 
@@ -326,7 +294,7 @@ def parse_pmd_info_string(self, mystring):
         for i in optional_pmd_info:
             try:
                 print("%s: %s" % (i['tag'], pmdinfo[i['id']]))
-            except KeyError as e:
+            except KeyError:
                 continue
 
         if (len(pmdinfo["pci_ids"]) != 0):
@@ -475,7 +443,7 @@ def process_dt_needed_entries(self):
                         with open(library, 'rb') as file:
                             try:
                                 libelf = ReadElf(file, sys.stdout)
-                            except ELFError as e:
+                            except ELFError:
                                 print("%s is no an ELF file" % library)
                                 continue
                             libelf.process_dt_needed_entries()
@@ -491,7 +459,7 @@ def scan_autoload_path(autoload_path):
 
     try:
         dirs = os.listdir(autoload_path)
-    except OSError as e:
+    except OSError:
         # Couldn't read the directory, give up
         return
 
@@ -503,10 +471,10 @@ def scan_autoload_path(autoload_path):
             try:
                 file = open(dpath, 'rb')
                 readelf = ReadElf(file, sys.stdout)
-            except ELFError as e:
+            except ELFError:
                 # this is likely not an elf file, skip it
                 continue
-            except IOError as e:
+            except IOError:
                 # No permission to read the file, skip it
                 continue
 
@@ -531,7 +499,7 @@ def scan_for_autoload_pmds(dpdk_path):
     file = open(dpdk_path, 'rb')
     try:
         readelf = ReadElf(file, sys.stdout)
-    except ElfError as e:
+    except ElfError:
         if raw_output is False:
             print("Unable to parse %s" % file)
         return
@@ -557,7 +525,7 @@ def main(stream=None):
     global raw_output
     global pcidb
 
-    pcifile_default = "./pci.ids" # for unknown OS's assume local file
+    pcifile_default = "./pci.ids"  # For unknown OS's assume local file
     if platform.system() == 'Linux':
         pcifile_default = "/usr/share/hwdata/pci.ids"
     elif platform.system() == 'FreeBSD':
@@ -577,7 +545,8 @@ def main(stream=None):
                               "to get vendor names from",
                          default=pcifile_default, metavar="FILE")
     optparser.add_option("-t", "--table", dest="tblout",
-                         help="output information on hw support as a hex table",
+                         help="output information on hw support as a "
+                              "hex table",
                          action='store_true')
     optparser.add_option("-p", "--plugindir", dest="pdir",
                          help="scan dpdk for autoload plugins",
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 0/3] app: make python apps python2/3 compliant
From: John McNamara @ 2016-12-21 15:03 UTC (permalink / raw)
  To: dev; +Cc: mkletzan, nhorman, John McNamara
In-Reply-To: <1481212265-10229-1-git-send-email-john.mcnamara@intel.com>

These patches refactor the DPDK Python applications to make them Python 2/3
compatible.

In order to do this the patchset starts by making the apps PEP8 compliant in
accordance with the DPDK Coding guidelines:

    http://dpdk.org/doc/guides/contributing/coding_style.html#python-code

Implementing PEP8 and Python 2/3 compliance means that we can check all future
Python patches for consistency. Python 2/3 support also makes downstream
packaging easier as more distros move to Python 3 as the system python.

See the previous discussion about Python2/3 compatibilty here:

    http://dpdk.org/ml/archives/dev/2016-December/051683.html

V4: * Rebase to latest HEAD.

V3: * Squash shebang patch into Python 3 patch.
    * Only add /usr/bin/env shebang line to code that is executable.

V2: * Fix broken rebase.

John McNamara (3):
  app: make python apps pep8 compliant
  app: make python apps python2/3 compliant
  doc: add required python versions to docs

 app/cmdline_test/cmdline_test.py                   |  87 ++-
 app/cmdline_test/cmdline_test_data.py              | 403 +++++-----
 app/test/autotest.py                               |  46 +-
 app/test/autotest_data.py                          | 831 ++++++++++-----------
 app/test/autotest_runner.py                        | 740 +++++++++---------
 app/test/autotest_test_funcs.py                    | 481 ++++++------
 doc/guides/conf.py                                 |   9 +-
 doc/guides/contributing/coding_style.rst           |   3 +-
 doc/guides/linux_gsg/sys_reqs.rst                  |   2 +-
 examples/ip_pipeline/config/diagram-generator.py   |  13 +-
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  11 +-
 tools/cpu_layout.py                                |  79 +-
 tools/dpdk-devbind.py                              |  25 +-
 tools/dpdk-pmdinfo.py                              |  75 +-
 14 files changed, 1405 insertions(+), 1400 deletions(-)

-- 
2.7.4

^ permalink raw reply

* Re: [PATCH v2 08/12] mk/crypto/armv8: add PMD to the build system
From: De Lara Guarch, Pablo @ 2016-12-21 15:01 UTC (permalink / raw)
  To: zbigniew.bodek@caviumnetworks.com, jerin.jacob@caviumnetworks.com
  Cc: dev@dpdk.org
In-Reply-To: <1481077985-4224-9-git-send-email-zbigniew.bodek@caviumnetworks.com>



> -----Original Message-----
> From: zbigniew.bodek@caviumnetworks.com
> [mailto:zbigniew.bodek@caviumnetworks.com]
> Sent: Wednesday, December 07, 2016 2:33 AM
> To: De Lara Guarch, Pablo; jerin.jacob@caviumnetworks.com
> Cc: dev@dpdk.org; Zbigniew Bodek
> Subject: [PATCH v2 08/12] mk/crypto/armv8: add PMD to the build system
> 
> From: Zbigniew Bodek <zbigniew.bodek@caviumnetworks.com>
> 
> Build ARMv8 crypto PMD if compiling for ARM64
> and CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO option
> is enable in the configuration file.
> 
> Signed-off-by: Zbigniew Bodek <zbigniew.bodek@caviumnetworks.com>
> ---
>  drivers/crypto/Makefile | 3 +++
>  mk/rte.app.mk           | 3 +++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
> index 745c614..a5de944 100644
> --- a/drivers/crypto/Makefile
> +++ b/drivers/crypto/Makefile
> @@ -33,6 +33,9 @@ include $(RTE_SDK)/mk/rte.vars.mk
> 
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_GCM) += aesni_gcm
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
> +ifeq ($(CONFIG_RTE_ARCH_ARM64),y)
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO) += armv8
> +endif

Is this extra conditional necessary (ARM64)? I would think enabling ARMV8_CRYPTO would be sufficient.

^ permalink raw reply

* Re: [PATCH v2 06/12] crypto/armv8: add PMD optimized for ARMv8 processors
From: De Lara Guarch, Pablo @ 2016-12-21 14:55 UTC (permalink / raw)
  To: zbigniew.bodek@caviumnetworks.com, jerin.jacob@caviumnetworks.com
  Cc: dev@dpdk.org
In-Reply-To: <1481077985-4224-7-git-send-email-zbigniew.bodek@caviumnetworks.com>



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> zbigniew.bodek@caviumnetworks.com
> Sent: Wednesday, December 07, 2016 2:33 AM
> To: De Lara Guarch, Pablo; jerin.jacob@caviumnetworks.com
> Cc: dev@dpdk.org; Zbigniew Bodek
> Subject: [dpdk-dev] [PATCH v2 06/12] crypto/armv8: add PMD optimized
> for ARMv8 processors
> 
> From: Zbigniew Bodek <zbigniew.bodek@caviumnetworks.com>
> 
> This patch introduces crypto poll mode driver
> using ARMv8 cryptographic extensions.
> CPU compatibility with this driver is detected in
> run-time and virtual crypto device will not be
> created if CPU doesn't provide:
> AES, SHA1, SHA2 and NEON.
> 
> This PMD is optimized to provide performance boost
> for chained crypto operations processing,
> such as encryption + HMAC generation,
> decryption + HMAC validation. In particular,
> cipher only or hash only operations are
> not provided.
> 
> The driver currently supports AES-128-CBC
> in combination with:
> SHA256 MAC, SHA256 HMAC and SHA1 HMAC and relies
> on the low-level assembly code.
> 
> This patch adds driver's code only and does
> not include it in the build system.
> 
> Signed-off-by: Zbigniew Bodek <zbigniew.bodek@caviumnetworks.com>
> ---
>  drivers/crypto/armv8/Makefile                     |  72 ++
>  drivers/crypto/armv8/asm/include/rte_armv8_defs.h |  80 ++
>  drivers/crypto/armv8/rte_armv8_pmd.c              | 915
> ++++++++++++++++++++++
>  drivers/crypto/armv8/rte_armv8_pmd_ops.c          | 390 +++++++++
>  drivers/crypto/armv8/rte_armv8_pmd_private.h      | 210 +++++
>  drivers/crypto/armv8/rte_armv8_pmd_version.map    |   3 +
>  6 files changed, 1670 insertions(+)
>  create mode 100644 drivers/crypto/armv8/Makefile
>  create mode 100644
> drivers/crypto/armv8/asm/include/rte_armv8_defs.h
>  create mode 100644 drivers/crypto/armv8/rte_armv8_pmd.c
>  create mode 100644 drivers/crypto/armv8/rte_armv8_pmd_ops.c
>  create mode 100644 drivers/crypto/armv8/rte_armv8_pmd_private.h
>  create mode 100644 drivers/crypto/armv8/rte_armv8_pmd_version.map
> 
...

> diff --git a/drivers/crypto/armv8/asm/include/rte_armv8_defs.h
> b/drivers/crypto/armv8/asm/include/rte_armv8_defs.h
> new file mode 100644
> index 0000000..ea05495
> --- /dev/null
> +++ b/drivers/crypto/armv8/asm/include/rte_armv8_defs.h
> @@ -0,0 +1,80 @@
...

> +
> +#ifndef _RTE_ARMV8_DEFS_H_
> +#define _RTE_ARMV8_DEFS_H_
> +
> +struct crypto_arg {
> +	struct {
> +		uint8_t		*key;
> +		uint8_t		*iv;
> +	} cipher;

Remove unnecessary tab above.

> +	struct {
> +		struct {
> +			uint8_t	*key;
> +			uint8_t *i_key_pad;
> +			uint8_t *o_key_pad;
> +		} hmac;
> +	} digest;
> +};

...

> diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c
> b/drivers/crypto/armv8/rte_armv8_pmd.c
> new file mode 100644
> index 0000000..0410bb0
> --- /dev/null
> +++ b/drivers/crypto/armv8/rte_armv8_pmd.c


> + * 3D array type for ARM Combined Mode crypto functions pointers.
> + * CRYPTO_CIPHER_MAX:			max cipher ID number
> + * CRYPTO_AUTH_MAX:			max auth ID number
> + * CRYPTO_CIPHER_KEYLEN_MAX:		max key length ID number
> + */
> +typedef const crypto_func_t
> +crypto_func_tbl_t[CRYPTO_CIPHER_MAX][CRYPTO_AUTH_MAX][CRYPTO_
> CIPHER_KEYLEN_MAX];
> +
> +/* Evaluate to key length definition */
> +#define	KEYL(keyl)		(ARMV8_CRYPTO_CIPHER_KEYLEN_
> ## keyl)

I don't think a tab is necessary here after define (happens on other parts)

> +
> +/* Local aliases for supported ciphers */
> +#define	CIPH_AES_CBC		RTE_CRYPTO_CIPHER_AES_CBC
> +/* Local aliases for supported hashes */
> +#define	AUTH_SHA1_HMAC
> 	RTE_CRYPTO_AUTH_SHA1_HMAC
> +#define	AUTH_SHA256		RTE_CRYPTO_AUTH_SHA256
> +#define	AUTH_SHA256_HMAC	RTE_CRYPTO_AUTH_SHA256_HMAC

...

> diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
> b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
> new file mode 100644
> index 0000000..0f768f4
> --- /dev/null
> +++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c

...

> +	{	/* AES CBC */
> +		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
> +			{.sym = {
> +				.xform_type =
> RTE_CRYPTO_SYM_XFORM_CIPHER,
> +				{.cipher = {
> +					.algo =
> RTE_CRYPTO_CIPHER_AES_CBC,
> +					.block_size = 16,
> +					.key_size = {
> +						.min = 16,
> +						.max = 32,
> +						.increment = 8

>From what I read, this PMD only supports AES-128-CBC.
If that's right, then key_size should be .min = 16, .max = 16, .increment = 0.

^ permalink raw reply

* [PATCH v5 26/26] app/testpmd: add protocol fields to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev; +Cc: Xing, Beilei, Pei, Yulong, Nelio Laranjeiro
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

This commit exposes the following item fields through the flow command:

- VLAN priority code point, drop eligible indicator and VLAN identifier
  (all part of TCI).
- IPv4 type of service, time to live and protocol.
- IPv6 traffic class, flow label, next header and hop limit.
- SCTP tag and checksum.

Cc: Xing, Beilei <beilei.xing@intel.com>
Cc: Pei, Yulong <yulong.pei@intel.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 app/test-pmd/cmdline_flow.c                 | 127 +++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  12 +++
 2 files changed, 139 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index db680c6..7760c2d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -126,10 +126,20 @@ enum index {
 	ITEM_VLAN,
 	ITEM_VLAN_TPID,
 	ITEM_VLAN_TCI,
+	ITEM_VLAN_PCP,
+	ITEM_VLAN_DEI,
+	ITEM_VLAN_VID,
 	ITEM_IPV4,
+	ITEM_IPV4_TOS,
+	ITEM_IPV4_TTL,
+	ITEM_IPV4_PROTO,
 	ITEM_IPV4_SRC,
 	ITEM_IPV4_DST,
 	ITEM_IPV6,
+	ITEM_IPV6_TC,
+	ITEM_IPV6_FLOW,
+	ITEM_IPV6_PROTO,
+	ITEM_IPV6_HOP,
 	ITEM_IPV6_SRC,
 	ITEM_IPV6_DST,
 	ITEM_ICMP,
@@ -144,6 +154,8 @@ enum index {
 	ITEM_SCTP,
 	ITEM_SCTP_SRC,
 	ITEM_SCTP_DST,
+	ITEM_SCTP_TAG,
+	ITEM_SCTP_CKSUM,
 	ITEM_VXLAN,
 	ITEM_VXLAN_VNI,
 
@@ -281,6 +293,23 @@ struct token {
 		.mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
 	})
 
+/** Static initializer for ARGS() to target an arbitrary bit-mask. */
+#define ARGS_ENTRY_MASK(s, f, m) \
+	(&(const struct arg){ \
+		.offset = offsetof(s, f), \
+		.size = sizeof(((s *)0)->f), \
+		.mask = (const void *)(m), \
+	})
+
+/** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
+#define ARGS_ENTRY_MASK_HTON(s, f, m) \
+	(&(const struct arg){ \
+		.hton = 1, \
+		.offset = offsetof(s, f), \
+		.size = sizeof(((s *)0)->f), \
+		.mask = (const void *)(m), \
+	})
+
 /** Static initializer for ARGS() to target a pointer. */
 #define ARGS_ENTRY_PTR(s, f) \
 	(&(const struct arg){ \
@@ -444,11 +473,17 @@ static const enum index item_eth[] = {
 static const enum index item_vlan[] = {
 	ITEM_VLAN_TPID,
 	ITEM_VLAN_TCI,
+	ITEM_VLAN_PCP,
+	ITEM_VLAN_DEI,
+	ITEM_VLAN_VID,
 	ITEM_NEXT,
 	ZERO,
 };
 
 static const enum index item_ipv4[] = {
+	ITEM_IPV4_TOS,
+	ITEM_IPV4_TTL,
+	ITEM_IPV4_PROTO,
 	ITEM_IPV4_SRC,
 	ITEM_IPV4_DST,
 	ITEM_NEXT,
@@ -456,6 +491,10 @@ static const enum index item_ipv4[] = {
 };
 
 static const enum index item_ipv6[] = {
+	ITEM_IPV6_TC,
+	ITEM_IPV6_FLOW,
+	ITEM_IPV6_PROTO,
+	ITEM_IPV6_HOP,
 	ITEM_IPV6_SRC,
 	ITEM_IPV6_DST,
 	ITEM_NEXT,
@@ -486,6 +525,8 @@ static const enum index item_tcp[] = {
 static const enum index item_sctp[] = {
 	ITEM_SCTP_SRC,
 	ITEM_SCTP_DST,
+	ITEM_SCTP_TAG,
+	ITEM_SCTP_CKSUM,
 	ITEM_NEXT,
 	ZERO,
 };
@@ -1012,6 +1053,27 @@ static const struct token token_list[] = {
 		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
 		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
 	},
+	[ITEM_VLAN_PCP] = {
+		.name = "pcp",
+		.help = "priority code point",
+		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+						  tci, "\xe0\x00")),
+	},
+	[ITEM_VLAN_DEI] = {
+		.name = "dei",
+		.help = "drop eligible indicator",
+		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+						  tci, "\x10\x00")),
+	},
+	[ITEM_VLAN_VID] = {
+		.name = "vid",
+		.help = "VLAN identifier",
+		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+						  tci, "\x0f\xff")),
+	},
 	[ITEM_IPV4] = {
 		.name = "ipv4",
 		.help = "match IPv4 header",
@@ -1019,6 +1081,27 @@ static const struct token token_list[] = {
 		.next = NEXT(item_ipv4),
 		.call = parse_vc,
 	},
+	[ITEM_IPV4_TOS] = {
+		.name = "tos",
+		.help = "type of service",
+		.next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+					     hdr.type_of_service)),
+	},
+	[ITEM_IPV4_TTL] = {
+		.name = "ttl",
+		.help = "time to live",
+		.next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+					     hdr.time_to_live)),
+	},
+	[ITEM_IPV4_PROTO] = {
+		.name = "proto",
+		.help = "next protocol ID",
+		.next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+					     hdr.next_proto_id)),
+	},
 	[ITEM_IPV4_SRC] = {
 		.name = "src",
 		.help = "source address",
@@ -1040,6 +1123,36 @@ static const struct token token_list[] = {
 		.next = NEXT(item_ipv6),
 		.call = parse_vc,
 	},
+	[ITEM_IPV6_TC] = {
+		.name = "tc",
+		.help = "traffic class",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+						  hdr.vtc_flow,
+						  "\x0f\xf0\x00\x00")),
+	},
+	[ITEM_IPV6_FLOW] = {
+		.name = "flow",
+		.help = "flow label",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+						  hdr.vtc_flow,
+						  "\x00\x0f\xff\xff")),
+	},
+	[ITEM_IPV6_PROTO] = {
+		.name = "proto",
+		.help = "protocol (next header)",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+					     hdr.proto)),
+	},
+	[ITEM_IPV6_HOP] = {
+		.name = "hop",
+		.help = "hop limit",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+					     hdr.hop_limits)),
+	},
 	[ITEM_IPV6_SRC] = {
 		.name = "src",
 		.help = "source address",
@@ -1138,6 +1251,20 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
 					     hdr.dst_port)),
 	},
+	[ITEM_SCTP_TAG] = {
+		.name = "tag",
+		.help = "validation tag",
+		.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+					     hdr.tag)),
+	},
+	[ITEM_SCTP_CKSUM] = {
+		.name = "cksum",
+		.help = "checksum",
+		.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+					     hdr.cksum)),
+	},
 	[ITEM_VXLAN] = {
 		.name = "vxlan",
 		.help = "match VXLAN header",
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 03b6fa9..cacdef1 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2333,14 +2333,24 @@ This section lists supported pattern items and their attributes, if any.
 
   - ``tpid {unsigned}``: tag protocol identifier.
   - ``tci {unsigned}``: tag control information.
+  - ``pcp {unsigned}``: priority code point.
+  - ``dei {unsigned}``: drop eligible indicator.
+  - ``vid {unsigned}``: VLAN identifier.
 
 - ``ipv4``: match IPv4 header.
 
+  - ``tos {unsigned}``: type of service.
+  - ``ttl {unsigned}``: time to live.
+  - ``proto {unsigned}``: next protocol ID.
   - ``src {ipv4 address}``: source address.
   - ``dst {ipv4 address}``: destination address.
 
 - ``ipv6``: match IPv6 header.
 
+  - ``tc {unsigned}``: traffic class.
+  - ``flow {unsigned}``: flow label.
+  - ``proto {unsigned}``: protocol (next header).
+  - ``hop {unsigned}``: hop limit.
   - ``src {ipv6 address}``: source address.
   - ``dst {ipv6 address}``: destination address.
 
@@ -2363,6 +2373,8 @@ This section lists supported pattern items and their attributes, if any.
 
   - ``src {unsigned}``: SCTP source port.
   - ``dst {unsigned}``: SCTP destination port.
+  - ``tag {unsigned}``: validation tag.
+  - ``cksum {unsigned}``: checksum.
 
 - ``vxlan``: match VXLAN header.
 
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 25/26] doc: describe testpmd flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

Document syntax, interaction with rte_flow and provide usage examples.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++++++++++++++++++++
 1 file changed, 612 insertions(+)

diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index f1c269a..03b6fa9 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1631,6 +1631,9 @@ Filter Functions
 
 This section details the available filter functions that are available.
 
+Note these functions interface the deprecated legacy filtering framework,
+superseded by *rte_flow*. See `Flow rules management`_.
+
 ethertype_filter
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -2041,3 +2044,612 @@ Set different GRE key length for input set::
 For example to set GRE key length for input set to 4 bytes on port 0::
 
    testpmd> global_config 0 gre-key-len 4
+
+
+.. _testpmd_rte_flow:
+
+Flow rules management
+---------------------
+
+Control of the generic flow API (*rte_flow*) is fully exposed through the
+``flow`` command (validation, creation, destruction and queries).
+
+Considering *rte_flow* overlaps with all `Filter Functions`_, using both
+features simultaneously may cause undefined side-effects and is therefore
+not recommended.
+
+``flow`` syntax
+~~~~~~~~~~~~~~~
+
+Because the ``flow`` command uses dynamic tokens to handle the large number
+of possible flow rules combinations, its behavior differs slightly from
+other commands, in particular:
+
+- Pressing *?* or the *<tab>* key displays contextual help for the current
+  token, not that of the entire command.
+
+- Optional and repeated parameters are supported (provided they are listed
+  in the contextual help).
+
+The first parameter stands for the operation mode. Possible operations and
+their general syntax are described below. They are covered in detail in the
+following sections.
+
+- Check whether a flow rule can be created::
+
+   flow validate {port_id}
+       [group {group_id}] [priority {level}] [ingress] [egress]
+       pattern {item} [/ {item} [...]] / end
+       actions {action} [/ {action} [...]] / end
+
+- Create a flow rule::
+
+   flow create {port_id}
+       [group {group_id}] [priority {level}] [ingress] [egress]
+       pattern {item} [/ {item} [...]] / end
+       actions {action} [/ {action} [...]] / end
+
+- Destroy specific flow rules::
+
+   flow destroy {port_id} rule {rule_id} [...]
+
+- Destroy all flow rules::
+
+   flow flush {port_id}
+
+- Query an existing flow rule::
+
+   flow query {port_id} {rule_id} {action}
+
+- List existing flow rules sorted by priority, filtered by group
+  identifiers::
+
+   flow list {port_id} [group {group_id}] [...]
+
+Validating flow rules
+~~~~~~~~~~~~~~~~~~~~~
+
+``flow validate`` reports whether a flow rule would be accepted by the
+underlying device in its current state but stops short of creating it. It is
+bound to ``rte_flow_validate()``::
+
+   flow validate {port_id}
+      [group {group_id}] [priority {level}] [ingress] [egress]
+      pattern {item} [/ {item} [...]] / end
+      actions {action} [/ {action} [...]] / end
+
+If successful, it will show::
+
+   Flow rule validated
+
+Otherwise it will show an error message of the form::
+
+   Caught error type [...] ([...]): [...]
+
+This command uses the same parameters as ``flow create``, their format is
+described in `Creating flow rules`_.
+
+Check whether redirecting any Ethernet packet received on port 0 to RX queue
+index 6 is supported::
+
+   testpmd> flow validate 0 ingress pattern eth / end
+      actions queue index 6 / end
+   Flow rule validated
+   testpmd>
+
+Port 0 does not support TCPv6 rules::
+
+   testpmd> flow validate 0 ingress pattern eth / ipv6 / tcp / end
+      actions drop / end
+   Caught error type 9 (specific pattern item): Invalid argument
+   testpmd>
+
+Creating flow rules
+~~~~~~~~~~~~~~~~~~~
+
+``flow create`` validates and creates the specified flow rule. It is bound
+to ``rte_flow_create()``::
+
+   flow create {port_id}
+      [group {group_id}] [priority {level}] [ingress] [egress]
+      pattern {item} [/ {item} [...]] / end
+      actions {action} [/ {action} [...]] / end
+
+If successful, it will return a flow rule ID usable with other commands::
+
+   Flow rule #[...] created
+
+Otherwise it will show an error message of the form::
+
+   Caught error type [...] ([...]): [...]
+
+Parameters describe in the following order:
+
+- Attributes (*group*, *priority*, *ingress*, *egress* tokens).
+- A matching pattern, starting with the *pattern* token and terminated by an
+  *end* pattern item.
+- Actions, starting with the *actions* token and terminated by an *end*
+  action.
+
+These translate directly to *rte_flow* objects provided as-is to the
+underlying functions.
+
+The shortest valid definition only comprises mandatory tokens::
+
+   testpmd> flow create 0 pattern end actions end
+
+Note that PMDs may refuse rules that essentially do nothing such as this
+one.
+
+**All unspecified object values are automatically initialized to 0.**
+
+Attributes
+^^^^^^^^^^
+
+These tokens affect flow rule attributes (``struct rte_flow_attr``) and are
+specified before the ``pattern`` token.
+
+- ``group {group id}``: priority group.
+- ``priority {level}``: priority level within group.
+- ``ingress``: rule applies to ingress traffic.
+- ``egress``: rule applies to egress traffic.
+
+Each instance of an attribute specified several times overrides the previous
+value as shown below (group 4 is used)::
+
+   testpmd> flow create 0 group 42 group 24 group 4 [...]
+
+Note that once enabled, ``ingress`` and ``egress`` cannot be disabled.
+
+While not specifying a direction is an error, some rules may allow both
+simultaneously.
+
+Most rules affect RX therefore contain the ``ingress`` token::
+
+   testpmd> flow create 0 ingress pattern [...]
+
+Matching pattern
+^^^^^^^^^^^^^^^^
+
+A matching pattern starts after the ``pattern`` token. It is made of pattern
+items and is terminated by a mandatory ``end`` item.
+
+Items are named after their type (*RTE_FLOW_ITEM_TYPE_* from ``enum
+rte_flow_item_type``).
+
+The ``/`` token is used as a separator between pattern items as shown
+below::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end [...]
+
+Note that protocol items like these must be stacked from lowest to highest
+layer to make sense. For instance, the following rule is either invalid or
+unlikely to match any packet::
+
+   testpmd> flow create 0 ingress pattern eth / udp / ipv4 / end [...]
+
+More information on these restrictions can be found in the *rte_flow*
+documentation.
+
+Several items support additional specification structures, for example
+``ipv4`` allows specifying source and destination addresses as follows::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 src is 10.1.1.1
+      dst is 10.2.0.0 / end [...]
+
+This rule matches all IPv4 traffic with the specified properties.
+
+In this example, ``src`` and ``dst`` are field names of the underlying
+``struct rte_flow_item_ipv4`` object. All item properties can be specified
+in a similar fashion.
+
+The ``is`` token means that the subsequent value must be matched exactly,
+and assigns ``spec`` and ``mask`` fields in ``struct rte_flow_item``
+accordingly. Possible assignment tokens are:
+
+- ``is``: match value perfectly (with full bit-mask).
+- ``spec``: match value according to configured bit-mask.
+- ``last``: specify upper bound to establish a range.
+- ``mask``: specify bit-mask with relevant bits set to one.
+- ``prefix``: generate bit-mask from a prefix length.
+
+These yield identical results::
+
+   ipv4 src is 10.1.1.1
+
+::
+
+   ipv4 src spec 10.1.1.1 src mask 255.255.255.255
+
+::
+
+   ipv4 src spec 10.1.1.1 src prefix 32
+
+::
+
+   ipv4 src is 10.1.1.1 src last 10.1.1.1 # range with a single value
+
+::
+
+   ipv4 src is 10.1.1.1 src last 0 # 0 disables range
+
+Inclusive ranges can be defined with ``last``::
+
+   ipv4 src is 10.1.1.1 src last 10.2.3.4 # 10.1.1.1 to 10.2.3.4
+
+Note that ``mask`` affects both ``spec`` and ``last``::
+
+   ipv4 src is 10.1.1.1 src last 10.2.3.4 src mask 255.255.0.0
+      # matches 10.1.0.0 to 10.2.255.255
+
+Properties can be modified multiple times::
+
+   ipv4 src is 10.1.1.1 src is 10.1.2.3 src is 10.2.3.4 # matches 10.2.3.4
+
+::
+
+   ipv4 src is 10.1.1.1 src prefix 24 src prefix 16 # matches 10.1.0.0/16
+
+Pattern items
+^^^^^^^^^^^^^
+
+This section lists supported pattern items and their attributes, if any.
+
+- ``end``: end list of pattern items.
+
+- ``void``: no-op pattern item.
+
+- ``invert``: perform actions when pattern does not match.
+
+- ``any``: match any protocol for the current layer.
+
+  - ``num {unsigned}``: number of layers covered.
+
+- ``pf``: match packets addressed to the physical function.
+
+- ``vf``: match packets addressed to a virtual function ID.
+
+  - ``id {unsigned}``: destination VF ID.
+
+- ``port``: device-specific physical port index to use.
+
+  - ``index {unsigned}``: physical port index.
+
+- ``raw``: match an arbitrary byte string.
+
+  - ``relative {boolean}``: look for pattern after the previous item.
+  - ``search {boolean}``: search pattern from offset (see also limit).
+  - ``offset {integer}``: absolute or relative offset for pattern.
+  - ``limit {unsigned}``: search area limit for start of pattern.
+  - ``pattern {string}``: byte string to look for.
+
+- ``eth``: match Ethernet header.
+
+  - ``dst {MAC-48}``: destination MAC.
+  - ``src {MAC-48}``: source MAC.
+  - ``type {unsigned}``: EtherType.
+
+- ``vlan``: match 802.1Q/ad VLAN tag.
+
+  - ``tpid {unsigned}``: tag protocol identifier.
+  - ``tci {unsigned}``: tag control information.
+
+- ``ipv4``: match IPv4 header.
+
+  - ``src {ipv4 address}``: source address.
+  - ``dst {ipv4 address}``: destination address.
+
+- ``ipv6``: match IPv6 header.
+
+  - ``src {ipv6 address}``: source address.
+  - ``dst {ipv6 address}``: destination address.
+
+- ``icmp``: match ICMP header.
+
+  - ``type {unsigned}``: ICMP packet type.
+  - ``code {unsigned}``: ICMP packet code.
+
+- ``udp``: match UDP header.
+
+  - ``src {unsigned}``: UDP source port.
+  - ``dst {unsigned}``: UDP destination port.
+
+- ``tcp``: match TCP header.
+
+  - ``src {unsigned}``: TCP source port.
+  - ``dst {unsigned}``: TCP destination port.
+
+- ``sctp``: match SCTP header.
+
+  - ``src {unsigned}``: SCTP source port.
+  - ``dst {unsigned}``: SCTP destination port.
+
+- ``vxlan``: match VXLAN header.
+
+  - ``vni {unsigned}``: VXLAN identifier.
+
+Actions list
+^^^^^^^^^^^^
+
+A list of actions starts after the ``actions`` token in the same fashion as
+`Matching pattern`_; actions are separated by ``/`` tokens and the list is
+terminated by a mandatory ``end`` action.
+
+Actions are named after their type (*RTE_FLOW_ACTION_TYPE_* from ``enum
+rte_flow_action_type``).
+
+Dropping all incoming UDPv4 packets can be expressed as follows::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end
+      actions drop / end
+
+Several actions have configurable properties which must be specified when
+there is no valid default value. For example, ``queue`` requires a target
+queue index.
+
+This rule redirects incoming UDPv4 traffic to queue index 6::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end
+      actions queue index 6 / end
+
+While this one could be rejected by PMDs (unspecified queue index)::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end
+      actions queue / end
+
+As defined by *rte_flow*, the list is not ordered, all actions of a given
+rule are performed simultaneously. These are equivalent::
+
+   queue index 6 / void / mark id 42 / end
+
+::
+
+   void / mark id 42 / queue index 6 / end
+
+All actions in a list should have different types, otherwise only the last
+action of a given type is taken into account::
+
+   queue index 4 / queue index 5 / queue index 6 / end # will use queue 6
+
+::
+
+   drop / drop / drop / end # drop is performed only once
+
+::
+
+   mark id 42 / queue index 3 / mark id 24 / end # mark will be 24
+
+Considering they are performed simultaneously, opposite and overlapping
+actions can sometimes be combined when the end result is unambiguous::
+
+   drop / queue index 6 / end # drop has no effect
+
+::
+
+   drop / dup index 6 / end # same as above
+
+::
+
+   queue index 6 / rss queues 6 7 8 / end # queue has no effect
+
+::
+
+   drop / passthru / end # drop has no effect
+
+Note that PMDs may still refuse such combinations.
+
+Actions
+^^^^^^^
+
+This section lists supported actions and their attributes, if any.
+
+- ``end``: end list of actions.
+
+- ``void``: no-op action.
+
+- ``passthru``: let subsequent rule process matched packets.
+
+- ``mark``: attach 32 bit value to packets.
+
+  - ``id {unsigned}``: 32 bit value to return with packets.
+
+- ``flag``: flag packets.
+
+- ``queue``: assign packets to a given queue index.
+
+  - ``index {unsigned}``: queue index to use.
+
+- ``drop``: drop packets (note: passthru has priority).
+
+- ``count``: enable counters for this rule.
+
+- ``dup``: duplicate packets to a given queue index.
+
+  - ``index {unsigned}``: queue index to duplicate packets to.
+
+- ``rss``: spread packets among several queues.
+
+  - ``queues [{unsigned} [...]] end``: queue indices to use.
+
+- ``pf``: redirect packets to physical device function.
+
+- ``vf``: redirect packets to virtual device function.
+
+  - ``original {boolean}``: use original VF ID if possible.
+  - ``id {unsigned}``: VF ID to redirect packets to.
+
+Destroying flow rules
+~~~~~~~~~~~~~~~~~~~~~
+
+``flow destroy`` destroys one or more rules from their rule ID (as returned
+by ``flow create``), this command calls ``rte_flow_destroy()`` as many
+times as necessary::
+
+   flow destroy {port_id} rule {rule_id} [...]
+
+If successful, it will show::
+
+   Flow rule #[...] destroyed
+
+It does not report anything for rule IDs that do not exist. The usual error
+message is shown when a rule cannot be destroyed::
+
+   Caught error type [...] ([...]): [...]
+
+``flow flush`` destroys all rules on a device and does not take extra
+arguments. It is bound to ``rte_flow_flush()``::
+
+   flow flush {port_id}
+
+Any errors are reported as above.
+
+Creating several rules and destroying them::
+
+   testpmd> flow create 0 ingress pattern eth / ipv6 / end
+      actions queue index 2 / end
+   Flow rule #0 created
+   testpmd> flow create 0 ingress pattern eth / ipv4 / end
+      actions queue index 3 / end
+   Flow rule #1 created
+   testpmd> flow destroy 0 rule 0 rule 1
+   Flow rule #1 destroyed
+   Flow rule #0 destroyed
+   testpmd>
+
+The same result can be achieved using ``flow flush``::
+
+   testpmd> flow create 0 ingress pattern eth / ipv6 / end
+      actions queue index 2 / end
+   Flow rule #0 created
+   testpmd> flow create 0 ingress pattern eth / ipv4 / end
+      actions queue index 3 / end
+   Flow rule #1 created
+   testpmd> flow flush 0
+   testpmd>
+
+Non-existent rule IDs are ignored::
+
+   testpmd> flow create 0 ingress pattern eth / ipv6 / end
+      actions queue index 2 / end
+   Flow rule #0 created
+   testpmd> flow create 0 ingress pattern eth / ipv4 / end
+      actions queue index 3 / end
+   Flow rule #1 created
+   testpmd> flow destroy 0 rule 42 rule 10 rule 2
+   testpmd>
+   testpmd> flow destroy 0 rule 0
+   Flow rule #0 destroyed
+   testpmd>
+
+Querying flow rules
+~~~~~~~~~~~~~~~~~~~
+
+``flow query`` queries a specific action of a flow rule having that
+ability. Such actions collect information that can be reported using this
+command. It is bound to ``rte_flow_query()``::
+
+   flow query {port_id} {rule_id} {action}
+
+If successful, it will display either the retrieved data for known actions
+or the following message::
+
+   Cannot display result for action type [...] ([...])
+
+Otherwise, it will complain either that the rule does not exist or that some
+error occurred::
+
+   Flow rule #[...] not found
+
+::
+
+   Caught error type [...] ([...]): [...]
+
+Currently only the ``count`` action is supported. This action reports the
+number of packets that hit the flow rule and the total number of bytes. Its
+output has the following format::
+
+   count:
+    hits_set: [...] # whether "hits" contains a valid value
+    bytes_set: [...] # whether "bytes" contains a valid value
+    hits: [...] # number of packets
+    bytes: [...] # number of bytes
+
+Querying counters for TCPv6 packets redirected to queue 6::
+
+   testpmd> flow create 0 ingress pattern eth / ipv6 / tcp / end
+      actions queue index 6 / count / end
+   Flow rule #4 created
+   testpmd> flow query 0 4 count
+   count:
+    hits_set: 1
+    bytes_set: 0
+    hits: 386446
+    bytes: 0
+   testpmd>
+
+Listing flow rules
+~~~~~~~~~~~~~~~~~~
+
+``flow list`` lists existing flow rules sorted by priority and optionally
+filtered by group identifiers::
+
+   flow list {port_id} [group {group_id}] [...]
+
+This command only fails with the following message if the device does not
+exist::
+
+   Invalid port [...]
+
+Output consists of a header line followed by a short description of each
+flow rule, one per line. There is no output at all when no flow rules are
+configured on the device::
+
+   ID      Group   Prio    Attr    Rule
+   [...]   [...]   [...]   [...]   [...]
+
+``Attr`` column flags:
+
+- ``i`` for ``ingress``.
+- ``e`` for ``egress``.
+
+Creating several flow rules and listing them::
+
+   testpmd> flow create 0 ingress pattern eth / ipv4 / end
+      actions queue index 6 / end
+   Flow rule #0 created
+   testpmd> flow create 0 ingress pattern eth / ipv6 / end
+      actions queue index 2 / end
+   Flow rule #1 created
+   testpmd> flow create 0 priority 5 ingress pattern eth / ipv4 / udp / end
+      actions rss queues 6 7 8 end / end
+   Flow rule #2 created
+   testpmd> flow list 0
+   ID      Group   Prio    Attr    Rule
+   0       0       0       i-      ETH IPV4 => QUEUE
+   1       0       0       i-      ETH IPV6 => QUEUE
+   2       0       5       i-      ETH IPV4 UDP => RSS
+   testpmd>
+
+Rules are sorted by priority (i.e. group ID first, then priority level)::
+
+   testpmd> flow list 1
+   ID      Group   Prio    Attr    Rule
+   0       0       0       i-      ETH => COUNT
+   6       0       500     i-      ETH IPV6 TCP => DROP COUNT
+   5       0       1000    i-      ETH IPV6 ICMP => QUEUE
+   1       24      0       i-      ETH IPV4 UDP => QUEUE
+   4       24      10      i-      ETH IPV4 TCP => DROP
+   3       24      20      i-      ETH IPV4 => DROP
+   2       24      42      i-      ETH IPV4 UDP => QUEUE
+   7       63      0       i-      ETH IPV6 UDP VXLAN => MARK QUEUE
+   testpmd>
+
+Output can be limited to specific groups::
+
+   testpmd> flow list 1 group 0 group 63
+   ID      Group   Prio    Attr    Rule
+   0       0       0       i-      ETH => COUNT
+   6       0       500     i-      ETH IPV6 TCP => DROP COUNT
+   5       0       1000    i-      ETH IPV6 ICMP => QUEUE
+   7       63      0       i-      ETH IPV6 UDP VXLAN => MARK QUEUE
+   testpmd>
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 24/26] app/testpmd: add queue actions to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

- QUEUE: assign packets to a given queue index.
- DUP: duplicate packets to a given queue index.
- RSS: spread packets among several queues.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 152 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index a4e8ebe..db680c6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -156,8 +156,15 @@ enum index {
 	ACTION_MARK,
 	ACTION_MARK_ID,
 	ACTION_FLAG,
+	ACTION_QUEUE,
+	ACTION_QUEUE_INDEX,
 	ACTION_DROP,
 	ACTION_COUNT,
+	ACTION_DUP,
+	ACTION_DUP_INDEX,
+	ACTION_RSS,
+	ACTION_RSS_QUEUES,
+	ACTION_RSS_QUEUE,
 	ACTION_PF,
 	ACTION_VF,
 	ACTION_VF_ORIGINAL,
@@ -171,6 +178,14 @@ enum index {
 #define ITEM_RAW_SIZE \
 	(offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
 
+/** Number of queue[] entries in struct rte_flow_action_rss. */
+#define ACTION_RSS_NUM 32
+
+/** Storage size for struct rte_flow_action_rss including queues. */
+#define ACTION_RSS_SIZE \
+	(offsetof(struct rte_flow_action_rss, queue) + \
+	 sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM)
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -487,8 +502,11 @@ static const enum index next_action[] = {
 	ACTION_PASSTHRU,
 	ACTION_MARK,
 	ACTION_FLAG,
+	ACTION_QUEUE,
 	ACTION_DROP,
 	ACTION_COUNT,
+	ACTION_DUP,
+	ACTION_RSS,
 	ACTION_PF,
 	ACTION_VF,
 	ZERO,
@@ -500,6 +518,24 @@ static const enum index action_mark[] = {
 	ZERO,
 };
 
+static const enum index action_queue[] = {
+	ACTION_QUEUE_INDEX,
+	ACTION_NEXT,
+	ZERO,
+};
+
+static const enum index action_dup[] = {
+	ACTION_DUP_INDEX,
+	ACTION_NEXT,
+	ZERO,
+};
+
+static const enum index action_rss[] = {
+	ACTION_RSS_QUEUES,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static const enum index action_vf[] = {
 	ACTION_VF_ORIGINAL,
 	ACTION_VF_ID,
@@ -517,6 +553,9 @@ static int parse_vc_spec(struct context *, const struct token *,
 			 const char *, unsigned int, void *, unsigned int);
 static int parse_vc_conf(struct context *, const struct token *,
 			 const char *, unsigned int, void *, unsigned int);
+static int parse_vc_action_rss_queue(struct context *, const struct token *,
+				     const char *, unsigned int, void *,
+				     unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -566,6 +605,8 @@ static int comp_port(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_rule_id(struct context *, const struct token *,
 			unsigned int, char *, unsigned int);
+static int comp_vc_action_rss_queue(struct context *, const struct token *,
+				    unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -1163,6 +1204,21 @@ static const struct token token_list[] = {
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc,
 	},
+	[ACTION_QUEUE] = {
+		.name = "queue",
+		.help = "assign packets to a given queue index",
+		.priv = PRIV_ACTION(QUEUE,
+				    sizeof(struct rte_flow_action_queue)),
+		.next = NEXT(action_queue),
+		.call = parse_vc,
+	},
+	[ACTION_QUEUE_INDEX] = {
+		.name = "index",
+		.help = "queue index to use",
+		.next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
+		.call = parse_vc_conf,
+	},
 	[ACTION_DROP] = {
 		.name = "drop",
 		.help = "drop packets (note: passthru has priority)",
@@ -1177,6 +1233,39 @@ static const struct token token_list[] = {
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc,
 	},
+	[ACTION_DUP] = {
+		.name = "dup",
+		.help = "duplicate packets to a given queue index",
+		.priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)),
+		.next = NEXT(action_dup),
+		.call = parse_vc,
+	},
+	[ACTION_DUP_INDEX] = {
+		.name = "index",
+		.help = "queue index to duplicate packets to",
+		.next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_RSS] = {
+		.name = "rss",
+		.help = "spread packets among several queues",
+		.priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE),
+		.next = NEXT(action_rss),
+		.call = parse_vc,
+	},
+	[ACTION_RSS_QUEUES] = {
+		.name = "queues",
+		.help = "queue indices to use",
+		.next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_RSS_QUEUE] = {
+		.name = "{queue}",
+		.help = "queue index",
+		.call = parse_vc_action_rss_queue,
+		.comp = comp_vc_action_rss_queue,
+	},
 	[ACTION_PF] = {
 		.name = "pf",
 		.help = "redirect packets to physical device function",
@@ -1567,6 +1656,51 @@ parse_vc_conf(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/**
+ * Parse queue field for RSS action.
+ *
+ * Valid tokens are queue indices and the "end" token.
+ */
+static int
+parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
+			  const char *str, unsigned int len,
+			  void *buf, unsigned int size)
+{
+	static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
+	int ret;
+	int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_RSS_QUEUE)
+		return -1;
+	i = ctx->objdata >> 16;
+	if (!strncmp(str, "end", len)) {
+		ctx->objdata &= 0xffff;
+		return len;
+	}
+	if (i >= ACTION_RSS_NUM)
+		return -1;
+	if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i])))
+		return -1;
+	ret = parse_int(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+	++i;
+	ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
+	/* Repeat token. */
+	if (ctx->next_num == RTE_DIM(ctx->next))
+		return -1;
+	ctx->next[ctx->next_num++] = next;
+	if (!ctx->object)
+		return len;
+	((struct rte_flow_action_rss *)ctx->object)->num = i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -2141,6 +2275,24 @@ comp_rule_id(struct context *ctx, const struct token *token,
 	return i;
 }
 
+/** Complete queue field for RSS action. */
+static int
+comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
+			 unsigned int ent, char *buf, unsigned int size)
+{
+	static const char *const str[] = { "", "end", NULL };
+	unsigned int i;
+
+	(void)ctx;
+	(void)token;
+	for (i = 0; str[i] != NULL; ++i)
+		if (buf && i == ent)
+			return snprintf(buf, size, "%s", str[i]);
+	if (buf)
+		return -1;
+	return i;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 23/26] app/testpmd: add various actions to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

- MARK: attach 32 bit value to packets.
- FLAG: flag packets.
- DROP: drop packets.
- COUNT: enable counters for a rule.
- PF: redirect packets to physical device function.
- VF: redirect packets to virtual device function.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 121 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 259e9eb..a4e8ebe 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -153,6 +153,15 @@ enum index {
 	ACTION_END,
 	ACTION_VOID,
 	ACTION_PASSTHRU,
+	ACTION_MARK,
+	ACTION_MARK_ID,
+	ACTION_FLAG,
+	ACTION_DROP,
+	ACTION_COUNT,
+	ACTION_PF,
+	ACTION_VF,
+	ACTION_VF_ORIGINAL,
+	ACTION_VF_ID,
 };
 
 /** Size of pattern[] field in struct rte_flow_item_raw. */
@@ -476,6 +485,25 @@ static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
 	ACTION_PASSTHRU,
+	ACTION_MARK,
+	ACTION_FLAG,
+	ACTION_DROP,
+	ACTION_COUNT,
+	ACTION_PF,
+	ACTION_VF,
+	ZERO,
+};
+
+static const enum index action_mark[] = {
+	ACTION_MARK_ID,
+	ACTION_NEXT,
+	ZERO,
+};
+
+static const enum index action_vf[] = {
+	ACTION_VF_ORIGINAL,
+	ACTION_VF_ID,
+	ACTION_NEXT,
 	ZERO,
 };
 
@@ -487,6 +515,8 @@ static int parse_vc(struct context *, const struct token *,
 		    void *, unsigned int);
 static int parse_vc_spec(struct context *, const struct token *,
 			 const char *, unsigned int, void *, unsigned int);
+static int parse_vc_conf(struct context *, const struct token *,
+			 const char *, unsigned int, void *, unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1112,6 +1142,70 @@ static const struct token token_list[] = {
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc,
 	},
+	[ACTION_MARK] = {
+		.name = "mark",
+		.help = "attach 32 bit value to packets",
+		.priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
+		.next = NEXT(action_mark),
+		.call = parse_vc,
+	},
+	[ACTION_MARK_ID] = {
+		.name = "id",
+		.help = "32 bit value to return with packets",
+		.next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_FLAG] = {
+		.name = "flag",
+		.help = "flag packets",
+		.priv = PRIV_ACTION(FLAG, 0),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc,
+	},
+	[ACTION_DROP] = {
+		.name = "drop",
+		.help = "drop packets (note: passthru has priority)",
+		.priv = PRIV_ACTION(DROP, 0),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc,
+	},
+	[ACTION_COUNT] = {
+		.name = "count",
+		.help = "enable counters for this rule",
+		.priv = PRIV_ACTION(COUNT, 0),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc,
+	},
+	[ACTION_PF] = {
+		.name = "pf",
+		.help = "redirect packets to physical device function",
+		.priv = PRIV_ACTION(PF, 0),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc,
+	},
+	[ACTION_VF] = {
+		.name = "vf",
+		.help = "redirect packets to virtual device function",
+		.priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
+		.next = NEXT(action_vf),
+		.call = parse_vc,
+	},
+	[ACTION_VF_ORIGINAL] = {
+		.name = "original",
+		.help = "use original VF ID if possible",
+		.next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
+		.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
+					   original, 1)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_VF_ID] = {
+		.name = "id",
+		.help = "VF ID to redirect packets to",
+		.next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
+		.call = parse_vc_conf,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -1446,6 +1540,33 @@ parse_vc_spec(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse action configuration field. */
+static int
+parse_vc_conf(struct context *ctx, const struct token *token,
+	      const char *str, unsigned int len,
+	      void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+
+	(void)size;
+	/* Token name must match. */
+	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+		return -1;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return len;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Update configuration pointer. */
+	action->conf = ctx->object;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 22/26] app/testpmd: add L4 items to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

Add the ability to match a few properties of common L4[.5] protocol
headers:

- ICMP: type and code.
- UDP: source and destination ports.
- TCP: source and destination ports.
- SCTP: source and destination ports.
- VXLAN: network identifier.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 163 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 163 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 1f6a5a0..259e9eb 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -132,6 +132,20 @@ enum index {
 	ITEM_IPV6,
 	ITEM_IPV6_SRC,
 	ITEM_IPV6_DST,
+	ITEM_ICMP,
+	ITEM_ICMP_TYPE,
+	ITEM_ICMP_CODE,
+	ITEM_UDP,
+	ITEM_UDP_SRC,
+	ITEM_UDP_DST,
+	ITEM_TCP,
+	ITEM_TCP_SRC,
+	ITEM_TCP_DST,
+	ITEM_SCTP,
+	ITEM_SCTP_SRC,
+	ITEM_SCTP_DST,
+	ITEM_VXLAN,
+	ITEM_VXLAN_VNI,
 
 	/* Validate/create actions. */
 	ACTIONS,
@@ -359,6 +373,11 @@ static const enum index next_item[] = {
 	ITEM_VLAN,
 	ITEM_IPV4,
 	ITEM_IPV6,
+	ITEM_ICMP,
+	ITEM_UDP,
+	ITEM_TCP,
+	ITEM_SCTP,
+	ITEM_VXLAN,
 	ZERO,
 };
 
@@ -419,6 +438,40 @@ static const enum index item_ipv6[] = {
 	ZERO,
 };
 
+static const enum index item_icmp[] = {
+	ITEM_ICMP_TYPE,
+	ITEM_ICMP_CODE,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_udp[] = {
+	ITEM_UDP_SRC,
+	ITEM_UDP_DST,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_tcp[] = {
+	ITEM_TCP_SRC,
+	ITEM_TCP_DST,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_sctp[] = {
+	ITEM_SCTP_SRC,
+	ITEM_SCTP_DST,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_vxlan[] = {
+	ITEM_VXLAN_VNI,
+	ITEM_NEXT,
+	ZERO,
+};
+
 static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
@@ -930,6 +983,103 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
 					     hdr.dst_addr)),
 	},
+	[ITEM_ICMP] = {
+		.name = "icmp",
+		.help = "match ICMP header",
+		.priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
+		.next = NEXT(item_icmp),
+		.call = parse_vc,
+	},
+	[ITEM_ICMP_TYPE] = {
+		.name = "type",
+		.help = "ICMP packet type",
+		.next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
+					     hdr.icmp_type)),
+	},
+	[ITEM_ICMP_CODE] = {
+		.name = "code",
+		.help = "ICMP packet code",
+		.next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
+					     hdr.icmp_code)),
+	},
+	[ITEM_UDP] = {
+		.name = "udp",
+		.help = "match UDP header",
+		.priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
+		.next = NEXT(item_udp),
+		.call = parse_vc,
+	},
+	[ITEM_UDP_SRC] = {
+		.name = "src",
+		.help = "UDP source port",
+		.next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
+					     hdr.src_port)),
+	},
+	[ITEM_UDP_DST] = {
+		.name = "dst",
+		.help = "UDP destination port",
+		.next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
+					     hdr.dst_port)),
+	},
+	[ITEM_TCP] = {
+		.name = "tcp",
+		.help = "match TCP header",
+		.priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
+		.next = NEXT(item_tcp),
+		.call = parse_vc,
+	},
+	[ITEM_TCP_SRC] = {
+		.name = "src",
+		.help = "TCP source port",
+		.next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+					     hdr.src_port)),
+	},
+	[ITEM_TCP_DST] = {
+		.name = "dst",
+		.help = "TCP destination port",
+		.next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+					     hdr.dst_port)),
+	},
+	[ITEM_SCTP] = {
+		.name = "sctp",
+		.help = "match SCTP header",
+		.priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
+		.next = NEXT(item_sctp),
+		.call = parse_vc,
+	},
+	[ITEM_SCTP_SRC] = {
+		.name = "src",
+		.help = "SCTP source port",
+		.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+					     hdr.src_port)),
+	},
+	[ITEM_SCTP_DST] = {
+		.name = "dst",
+		.help = "SCTP destination port",
+		.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+					     hdr.dst_port)),
+	},
+	[ITEM_VXLAN] = {
+		.name = "vxlan",
+		.help = "match VXLAN header",
+		.priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
+		.next = NEXT(item_vxlan),
+		.call = parse_vc,
+	},
+	[ITEM_VXLAN_VNI] = {
+		.name = "vni",
+		.help = "VXLAN identifier",
+		.next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
+	},
 	/* Validate/create actions. */
 	[ACTIONS] = {
 		.name = "actions",
@@ -1502,6 +1652,19 @@ parse_int(struct context *ctx, const struct token *token,
 	case sizeof(uint16_t):
 		*(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
 		break;
+	case sizeof(uint8_t [3]):
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		if (!arg->hton) {
+			((uint8_t *)buf)[0] = u;
+			((uint8_t *)buf)[1] = u >> 8;
+			((uint8_t *)buf)[2] = u >> 16;
+			break;
+		}
+#endif
+		((uint8_t *)buf)[0] = u >> 16;
+		((uint8_t *)buf)[1] = u >> 8;
+		((uint8_t *)buf)[2] = u;
+		break;
 	case sizeof(uint32_t):
 		*(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
 		break;
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 21/26] app/testpmd: add items ipv4/ipv6 to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

Add the ability to match basic fields from IPv4 and IPv6 headers (source
and destination addresses only).

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index e22e0c2..1f6a5a0 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <string.h>
+#include <arpa/inet.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {
 	BOOLEAN,
 	STRING,
 	MAC_ADDR,
+	IPV4_ADDR,
+	IPV6_ADDR,
 	RULE_ID,
 	PORT_ID,
 	GROUP_ID,
@@ -123,6 +126,12 @@ enum index {
 	ITEM_VLAN,
 	ITEM_VLAN_TPID,
 	ITEM_VLAN_TCI,
+	ITEM_IPV4,
+	ITEM_IPV4_SRC,
+	ITEM_IPV4_DST,
+	ITEM_IPV6,
+	ITEM_IPV6_SRC,
+	ITEM_IPV6_DST,
 
 	/* Validate/create actions. */
 	ACTIONS,
@@ -348,6 +357,8 @@ static const enum index next_item[] = {
 	ITEM_RAW,
 	ITEM_ETH,
 	ITEM_VLAN,
+	ITEM_IPV4,
+	ITEM_IPV6,
 	ZERO,
 };
 
@@ -394,6 +405,20 @@ static const enum index item_vlan[] = {
 	ZERO,
 };
 
+static const enum index item_ipv4[] = {
+	ITEM_IPV4_SRC,
+	ITEM_IPV4_DST,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_ipv6[] = {
+	ITEM_IPV6_SRC,
+	ITEM_IPV6_DST,
+	ITEM_NEXT,
+	ZERO,
+};
+
 static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
@@ -439,6 +464,12 @@ static int parse_string(struct context *, const struct token *,
 static int parse_mac_addr(struct context *, const struct token *,
 			  const char *, unsigned int,
 			  void *, unsigned int);
+static int parse_ipv4_addr(struct context *, const struct token *,
+			   const char *, unsigned int,
+			   void *, unsigned int);
+static int parse_ipv6_addr(struct context *, const struct token *,
+			   const char *, unsigned int,
+			   void *, unsigned int);
 static int parse_port(struct context *, const struct token *,
 		      const char *, unsigned int,
 		      void *, unsigned int);
@@ -509,6 +540,20 @@ static const struct token token_list[] = {
 		.call = parse_mac_addr,
 		.comp = comp_none,
 	},
+	[IPV4_ADDR] = {
+		.name = "{IPv4 address}",
+		.type = "IPV4 ADDRESS",
+		.help = "standard IPv4 address notation",
+		.call = parse_ipv4_addr,
+		.comp = comp_none,
+	},
+	[IPV6_ADDR] = {
+		.name = "{IPv6 address}",
+		.type = "IPV6 ADDRESS",
+		.help = "standard IPv6 address notation",
+		.call = parse_ipv6_addr,
+		.comp = comp_none,
+	},
 	[RULE_ID] = {
 		.name = "{rule id}",
 		.type = "RULE ID",
@@ -843,6 +888,48 @@ static const struct token token_list[] = {
 		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
 		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
 	},
+	[ITEM_IPV4] = {
+		.name = "ipv4",
+		.help = "match IPv4 header",
+		.priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
+		.next = NEXT(item_ipv4),
+		.call = parse_vc,
+	},
+	[ITEM_IPV4_SRC] = {
+		.name = "src",
+		.help = "source address",
+		.next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+					     hdr.src_addr)),
+	},
+	[ITEM_IPV4_DST] = {
+		.name = "dst",
+		.help = "destination address",
+		.next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+					     hdr.dst_addr)),
+	},
+	[ITEM_IPV6] = {
+		.name = "ipv6",
+		.help = "match IPv6 header",
+		.priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
+		.next = NEXT(item_ipv6),
+		.call = parse_vc,
+	},
+	[ITEM_IPV6_SRC] = {
+		.name = "src",
+		.help = "source address",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+					     hdr.src_addr)),
+	},
+	[ITEM_IPV6_DST] = {
+		.name = "dst",
+		.help = "destination address",
+		.next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+					     hdr.dst_addr)),
+	},
 	/* Validate/create actions. */
 	[ACTIONS] = {
 		.name = "actions",
@@ -1525,6 +1612,96 @@ parse_mac_addr(struct context *ctx, const struct token *token,
 	return -1;
 }
 
+/**
+ * Parse an IPv4 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv4_addr(struct context *ctx, const struct token *token,
+		const char *str, unsigned int len,
+		void *buf, unsigned int size)
+{
+	const struct arg *arg = pop_args(ctx);
+	char str2[len + 1];
+	struct in_addr tmp;
+	int ret;
+
+	/* Argument is expected. */
+	if (!arg)
+		return -1;
+	size = arg->size;
+	/* Bit-mask fill is not supported. */
+	if (arg->mask || size != sizeof(tmp))
+		goto error;
+	/* Only network endian is supported. */
+	if (!arg->hton)
+		goto error;
+	memcpy(str2, str, len);
+	str2[len] = '\0';
+	ret = inet_pton(AF_INET, str2, &tmp);
+	if (ret != 1) {
+		/* Attempt integer parsing. */
+		push_args(ctx, arg);
+		return parse_int(ctx, token, str, len, buf, size);
+	}
+	if (!ctx->object)
+		return len;
+	buf = (uint8_t *)ctx->object + arg->offset;
+	memcpy(buf, &tmp, size);
+	if (ctx->objmask)
+		memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+	return len;
+error:
+	push_args(ctx, arg);
+	return -1;
+}
+
+/**
+ * Parse an IPv6 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv6_addr(struct context *ctx, const struct token *token,
+		const char *str, unsigned int len,
+		void *buf, unsigned int size)
+{
+	const struct arg *arg = pop_args(ctx);
+	char str2[len + 1];
+	struct in6_addr tmp;
+	int ret;
+
+	(void)token;
+	/* Argument is expected. */
+	if (!arg)
+		return -1;
+	size = arg->size;
+	/* Bit-mask fill is not supported. */
+	if (arg->mask || size != sizeof(tmp))
+		goto error;
+	/* Only network endian is supported. */
+	if (!arg->hton)
+		goto error;
+	memcpy(str2, str, len);
+	str2[len] = '\0';
+	ret = inet_pton(AF_INET6, str2, &tmp);
+	if (ret != 1)
+		goto error;
+	if (!ctx->object)
+		return len;
+	buf = (uint8_t *)ctx->object + arg->offset;
+	memcpy(buf, &tmp, size);
+	if (ctx->objmask)
+		memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+	return len;
+error:
+	push_args(ctx, arg);
+	return -1;
+}
+
 /** Boolean values (even indices stand for false). */
 static const char *const boolean_name[] = {
 	"0", "1",
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 20/26] app/testpmd: add items eth/vlan to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

These pattern items match basic Ethernet headers (source, destination and
type) and related 802.1Q/ad VLAN headers.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 126 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index c52a8f7..e22e0c2 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -43,6 +43,7 @@
 #include <rte_ethdev.h>
 #include <rte_byteorder.h>
 #include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
 #include <rte_flow.h>
 
 #include "testpmd.h"
@@ -59,6 +60,7 @@ enum index {
 	PREFIX,
 	BOOLEAN,
 	STRING,
+	MAC_ADDR,
 	RULE_ID,
 	PORT_ID,
 	GROUP_ID,
@@ -114,6 +116,13 @@ enum index {
 	ITEM_RAW_OFFSET,
 	ITEM_RAW_LIMIT,
 	ITEM_RAW_PATTERN,
+	ITEM_ETH,
+	ITEM_ETH_DST,
+	ITEM_ETH_SRC,
+	ITEM_ETH_TYPE,
+	ITEM_VLAN,
+	ITEM_VLAN_TPID,
+	ITEM_VLAN_TCI,
 
 	/* Validate/create actions. */
 	ACTIONS,
@@ -238,6 +247,14 @@ struct token {
 		.size = (sz), \
 	})
 
+/** Same as ARGS_ENTRY() using network byte ordering. */
+#define ARGS_ENTRY_HTON(s, f) \
+	(&(const struct arg){ \
+		.hton = 1, \
+		.offset = offsetof(s, f), \
+		.size = sizeof(((s *)0)->f), \
+	})
+
 /** Parser output buffer layout expected by cmd_flow_parsed(). */
 struct buffer {
 	enum index command; /**< Flow command. */
@@ -329,6 +346,8 @@ static const enum index next_item[] = {
 	ITEM_VF,
 	ITEM_PORT,
 	ITEM_RAW,
+	ITEM_ETH,
+	ITEM_VLAN,
 	ZERO,
 };
 
@@ -360,6 +379,21 @@ static const enum index item_raw[] = {
 	ZERO,
 };
 
+static const enum index item_eth[] = {
+	ITEM_ETH_DST,
+	ITEM_ETH_SRC,
+	ITEM_ETH_TYPE,
+	ITEM_NEXT,
+	ZERO,
+};
+
+static const enum index item_vlan[] = {
+	ITEM_VLAN_TPID,
+	ITEM_VLAN_TCI,
+	ITEM_NEXT,
+	ZERO,
+};
+
 static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
@@ -402,6 +436,9 @@ static int parse_boolean(struct context *, const struct token *,
 static int parse_string(struct context *, const struct token *,
 			const char *, unsigned int,
 			void *, unsigned int);
+static int parse_mac_addr(struct context *, const struct token *,
+			  const char *, unsigned int,
+			  void *, unsigned int);
 static int parse_port(struct context *, const struct token *,
 		      const char *, unsigned int,
 		      void *, unsigned int);
@@ -465,6 +502,13 @@ static const struct token token_list[] = {
 		.call = parse_string,
 		.comp = comp_none,
 	},
+	[MAC_ADDR] = {
+		.name = "{MAC address}",
+		.type = "MAC-48",
+		.help = "standard MAC address notation",
+		.call = parse_mac_addr,
+		.comp = comp_none,
+	},
 	[RULE_ID] = {
 		.name = "{rule id}",
 		.type = "RULE ID",
@@ -755,6 +799,50 @@ static const struct token token_list[] = {
 					    pattern,
 					    ITEM_RAW_PATTERN_SIZE)),
 	},
+	[ITEM_ETH] = {
+		.name = "eth",
+		.help = "match Ethernet header",
+		.priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
+		.next = NEXT(item_eth),
+		.call = parse_vc,
+	},
+	[ITEM_ETH_DST] = {
+		.name = "dst",
+		.help = "destination MAC",
+		.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, dst)),
+	},
+	[ITEM_ETH_SRC] = {
+		.name = "src",
+		.help = "source MAC",
+		.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, src)),
+	},
+	[ITEM_ETH_TYPE] = {
+		.name = "type",
+		.help = "EtherType",
+		.next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
+	},
+	[ITEM_VLAN] = {
+		.name = "vlan",
+		.help = "match 802.1Q/ad VLAN tag",
+		.priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
+		.next = NEXT(item_vlan),
+		.call = parse_vc,
+	},
+	[ITEM_VLAN_TPID] = {
+		.name = "tpid",
+		.help = "tag protocol identifier",
+		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)),
+	},
+	[ITEM_VLAN_TCI] = {
+		.name = "tci",
+		.help = "tag control information",
+		.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
+	},
 	/* Validate/create actions. */
 	[ACTIONS] = {
 		.name = "actions",
@@ -1399,6 +1487,44 @@ parse_string(struct context *ctx, const struct token *token,
 	return -1;
 }
 
+/**
+ * Parse a MAC address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_mac_addr(struct context *ctx, const struct token *token,
+	       const char *str, unsigned int len,
+	       void *buf, unsigned int size)
+{
+	const struct arg *arg = pop_args(ctx);
+	struct ether_addr tmp;
+	int ret;
+
+	(void)token;
+	/* Argument is expected. */
+	if (!arg)
+		return -1;
+	size = arg->size;
+	/* Bit-mask fill is not supported. */
+	if (arg->mask || size != sizeof(tmp))
+		goto error;
+	ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
+	if (ret < 0 || (unsigned int)ret != len)
+		goto error;
+	if (!ctx->object)
+		return len;
+	buf = (uint8_t *)ctx->object + arg->offset;
+	memcpy(buf, &tmp, size);
+	if (ctx->objmask)
+		memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+	return len;
+error:
+	push_args(ctx, arg);
+	return -1;
+}
+
 /** Boolean values (even indices stand for false). */
 static const char *const boolean_name[] = {
 	"0", "1",
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 19/26] app/testpmd: add item raw to flow command
From: Adrien Mazarguil @ 2016-12-21 14:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <cover.1482331076.git.adrien.mazarguil@6wind.com>

Matches arbitrary byte strings with properties:

- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 208 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 208 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 0592969..c52a8f7 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -57,6 +57,8 @@ enum index {
 	INTEGER,
 	UNSIGNED,
 	PREFIX,
+	BOOLEAN,
+	STRING,
 	RULE_ID,
 	PORT_ID,
 	GROUP_ID,
@@ -106,6 +108,12 @@ enum index {
 	ITEM_VF_ID,
 	ITEM_PORT,
 	ITEM_PORT_INDEX,
+	ITEM_RAW,
+	ITEM_RAW_RELATIVE,
+	ITEM_RAW_SEARCH,
+	ITEM_RAW_OFFSET,
+	ITEM_RAW_LIMIT,
+	ITEM_RAW_PATTERN,
 
 	/* Validate/create actions. */
 	ACTIONS,
@@ -115,6 +123,13 @@ enum index {
 	ACTION_PASSTHRU,
 };
 
+/** Size of pattern[] field in struct rte_flow_item_raw. */
+#define ITEM_RAW_PATTERN_SIZE 36
+
+/** Storage size for struct rte_flow_item_raw including pattern. */
+#define ITEM_RAW_SIZE \
+	(offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -216,6 +231,13 @@ struct token {
 		.size = sizeof(*((s *)0)->f), \
 	})
 
+/** Static initializer for ARGS() with arbitrary size. */
+#define ARGS_ENTRY_USZ(s, f, sz) \
+	(&(const struct arg){ \
+		.offset = offsetof(s, f), \
+		.size = (sz), \
+	})
+
 /** Parser output buffer layout expected by cmd_flow_parsed(). */
 struct buffer {
 	enum index command; /**< Flow command. */
@@ -306,6 +328,7 @@ static const enum index next_item[] = {
 	ITEM_PF,
 	ITEM_VF,
 	ITEM_PORT,
+	ITEM_RAW,
 	ZERO,
 };
 
@@ -327,6 +350,16 @@ static const enum index item_port[] = {
 	ZERO,
 };
 
+static const enum index item_raw[] = {
+	ITEM_RAW_RELATIVE,
+	ITEM_RAW_SEARCH,
+	ITEM_RAW_OFFSET,
+	ITEM_RAW_LIMIT,
+	ITEM_RAW_PATTERN,
+	ITEM_NEXT,
+	ZERO,
+};
+
 static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
@@ -363,11 +396,19 @@ static int parse_int(struct context *, const struct token *,
 static int parse_prefix(struct context *, const struct token *,
 			const char *, unsigned int,
 			void *, unsigned int);
+static int parse_boolean(struct context *, const struct token *,
+			 const char *, unsigned int,
+			 void *, unsigned int);
+static int parse_string(struct context *, const struct token *,
+			const char *, unsigned int,
+			void *, unsigned int);
 static int parse_port(struct context *, const struct token *,
 		      const char *, unsigned int,
 		      void *, unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
+static int comp_boolean(struct context *, const struct token *,
+			unsigned int, char *, unsigned int);
 static int comp_action(struct context *, const struct token *,
 		       unsigned int, char *, unsigned int);
 static int comp_port(struct context *, const struct token *,
@@ -410,6 +451,20 @@ static const struct token token_list[] = {
 		.call = parse_prefix,
 		.comp = comp_none,
 	},
+	[BOOLEAN] = {
+		.name = "{boolean}",
+		.type = "BOOLEAN",
+		.help = "any boolean value",
+		.call = parse_boolean,
+		.comp = comp_boolean,
+	},
+	[STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "fixed string",
+		.call = parse_string,
+		.comp = comp_none,
+	},
 	[RULE_ID] = {
 		.name = "{rule id}",
 		.type = "RULE ID",
@@ -654,6 +709,52 @@ static const struct token token_list[] = {
 		.next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param),
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)),
 	},
+	[ITEM_RAW] = {
+		.name = "raw",
+		.help = "match an arbitrary byte string",
+		.priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
+		.next = NEXT(item_raw),
+		.call = parse_vc,
+	},
+	[ITEM_RAW_RELATIVE] = {
+		.name = "relative",
+		.help = "look for pattern after the previous item",
+		.next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
+		.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
+					   relative, 1)),
+	},
+	[ITEM_RAW_SEARCH] = {
+		.name = "search",
+		.help = "search pattern from offset (see also limit)",
+		.next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
+		.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
+					   search, 1)),
+	},
+	[ITEM_RAW_OFFSET] = {
+		.name = "offset",
+		.help = "absolute or relative offset for pattern",
+		.next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
+	},
+	[ITEM_RAW_LIMIT] = {
+		.name = "limit",
+		.help = "search area limit for start of pattern",
+		.next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
+	},
+	[ITEM_RAW_PATTERN] = {
+		.name = "pattern",
+		.help = "byte string to look for",
+		.next = NEXT(item_raw,
+			     NEXT_ENTRY(STRING),
+			     NEXT_ENTRY(ITEM_PARAM_IS,
+					ITEM_PARAM_SPEC,
+					ITEM_PARAM_MASK)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length),
+			     ARGS_ENTRY_USZ(struct rte_flow_item_raw,
+					    pattern,
+					    ITEM_RAW_PATTERN_SIZE)),
+	},
 	/* Validate/create actions. */
 	[ACTIONS] = {
 		.name = "actions",
@@ -1246,6 +1347,96 @@ parse_int(struct context *ctx, const struct token *token,
 	return -1;
 }
 
+/**
+ * Parse a string.
+ *
+ * Two arguments (ctx->args) are retrieved from the stack to store data and
+ * its length (in that order).
+ */
+static int
+parse_string(struct context *ctx, const struct token *token,
+	     const char *str, unsigned int len,
+	     void *buf, unsigned int size)
+{
+	const struct arg *arg_data = pop_args(ctx);
+	const struct arg *arg_len = pop_args(ctx);
+	char tmp[16]; /* Ought to be enough. */
+	int ret;
+
+	/* Arguments are expected. */
+	if (!arg_data)
+		return -1;
+	if (!arg_len) {
+		push_args(ctx, arg_data);
+		return -1;
+	}
+	size = arg_data->size;
+	/* Bit-mask fill is not supported. */
+	if (arg_data->mask || size < len)
+		goto error;
+	if (!ctx->object)
+		return len;
+	/* Let parse_int() fill length information first. */
+	ret = snprintf(tmp, sizeof(tmp), "%u", len);
+	if (ret < 0)
+		goto error;
+	push_args(ctx, arg_len);
+	ret = parse_int(ctx, token, tmp, ret, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		goto error;
+	}
+	buf = (uint8_t *)ctx->object + arg_data->offset;
+	/* Output buffer is not necessarily NUL-terminated. */
+	memcpy(buf, str, len);
+	memset((uint8_t *)buf + len, 0x55, size - len);
+	if (ctx->objmask)
+		memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
+	return len;
+error:
+	push_args(ctx, arg_len);
+	push_args(ctx, arg_data);
+	return -1;
+}
+
+/** Boolean values (even indices stand for false). */
+static const char *const boolean_name[] = {
+	"0", "1",
+	"false", "true",
+	"no", "yes",
+	"N", "Y",
+	NULL,
+};
+
+/**
+ * Parse a boolean value.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_boolean(struct context *ctx, const struct token *token,
+	      const char *str, unsigned int len,
+	      void *buf, unsigned int size)
+{
+	const struct arg *arg = pop_args(ctx);
+	unsigned int i;
+	int ret;
+
+	/* Argument is expected. */
+	if (!arg)
+		return -1;
+	for (i = 0; boolean_name[i]; ++i)
+		if (!strncmp(str, boolean_name[i], len))
+			break;
+	/* Process token as integer. */
+	if (boolean_name[i])
+		str = i & 1 ? "1" : "0";
+	push_args(ctx, arg);
+	ret = parse_int(ctx, token, str, strlen(str), buf, size);
+	return ret > 0 ? (int)len : ret;
+}
+
 /** Parse port and update context. */
 static int
 parse_port(struct context *ctx, const struct token *token,
@@ -1284,6 +1475,23 @@ comp_none(struct context *ctx, const struct token *token,
 	return 0;
 }
 
+/** Complete boolean values. */
+static int
+comp_boolean(struct context *ctx, const struct token *token,
+	     unsigned int ent, char *buf, unsigned int size)
+{
+	unsigned int i;
+
+	(void)ctx;
+	(void)token;
+	for (i = 0; boolean_name[i]; ++i)
+		if (buf && i == ent)
+			return snprintf(buf, size, "%s", boolean_name[i]);
+	if (buf)
+		return -1;
+	return i;
+}
+
 /** Complete action names. */
 static int
 comp_action(struct context *ctx, const struct token *token,
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox