DPDK patches and discussions
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download: 
* Re: [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions
  @ 2017-08-30 20:07  4%     ` Bruce Richardson
  0 siblings, 0 replies; 200+ results
From: Bruce Richardson @ 2017-08-30 20:07 UTC (permalink / raw)
  To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski

I think the commit title needs rewording. This changes the internals not
the API.

On Mon, Jul 10, 2017 at 02:44:14PM +0200, Jacek Piasecki wrote:
> Change to flat arrays in cfgfile struct force slightly
> diffrent data access for most of cfgfile functions.
> This patch provides necessary changes in existing API.
> 
> Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
> ---

Some comments below. I believe the change in return value from -1 to
-EINVAL, though a more correct error, actually counts as an ABI change,
so I think that should be removed, i.e. keep errors at -1. Once done:

Acked-by: Bruce Richardon <bruce.richardson@intel.com>

>  lib/librte_cfgfile/rte_cfgfile.c | 120 +++++++++++++++++++--------------------
>  lib/librte_cfgfile/rte_cfgfile.h |   6 +-
>  2 files changed, 62 insertions(+), 64 deletions(-)
> 
> diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c
> index c6ae3e3..50fe37a 100644
> --- a/lib/librte_cfgfile/rte_cfgfile.c
> +++ b/lib/librte_cfgfile/rte_cfgfile.c
> @@ -35,6 +35,7 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <ctype.h>
> +#include <errno.h>
>  #include <rte_common.h>
>  
>  #include "rte_cfgfile.h"
> @@ -42,13 +43,15 @@
>  struct rte_cfgfile_section {
>  	char name[CFG_NAME_LEN];
>  	int num_entries;
> -	struct rte_cfgfile_entry *entries[0];
> +	int allocated_entries;
> +	struct rte_cfgfile_entry *entries;
>  };
>  
>  struct rte_cfgfile {
>  	int flags;
>  	int num_sections;
> -	struct rte_cfgfile_section *sections[0];
> +	int allocated_sections;
> +	struct rte_cfgfile_section *sections;
>  };
> 

These are good changes, allowing us to have the sections array and
entries arrays separate from the basic data structures.

<snip>
> @@ -409,7 +407,7 @@ rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg,
>  {
>  	const struct rte_cfgfile_section *s = _get_section(cfg, sectionname);
>  	if (s == NULL)
> -		return -1;
> +		return -EINVAL;
>  	return s->num_entries;
>  }

I think this change should be dropped for backward compatibility, or
else put in NEXT_ABI #ifdefs and an ABI notice added to the RN.

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH 6/6] eal: remove API rte_mem_phy2mch
    2017-08-30 18:10  1% ` [dpdk-dev] [PATCH 5/6] eal: remove xen dom0 support Jianfeng Tan
@ 2017-08-30 18:10  3% ` Jianfeng Tan
  1 sibling, 0 replies; 200+ results
From: Jianfeng Tan @ 2017-08-30 18:10 UTC (permalink / raw)
  To: dev
  Cc: xen-devel, thomas, john.mcnamara, oao.m.martins, jerin.jacob,
	shahafs, Jianfeng Tan

Previously, to get MFN address in dom0, this API is a wrapper to
obtain the "physical address".

As we removed xen dom0 support, this API is not necessary.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
 doc/guides/rel_notes/release_17_11.rst     | 2 ++
 drivers/net/e1000/em_rxtx.c                | 4 ++--
 drivers/net/e1000/igb_rxtx.c               | 4 ++--
 drivers/net/fm10k/fm10k_ethdev.c           | 4 ++--
 drivers/net/i40e/i40e_ethdev.c             | 2 +-
 drivers/net/i40e/i40e_fdir.c               | 2 +-
 drivers/net/i40e/i40e_rxtx.c               | 8 ++++----
 drivers/net/ixgbe/ixgbe_rxtx.c             | 4 ++--
 drivers/net/sfc/sfc.c                      | 2 +-
 lib/librte_eal/common/include/rte_memory.h | 5 -----
 lib/librte_mempool/rte_mempool.c           | 3 ---
 11 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index d211084..06c334b 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -110,6 +110,8 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+   * ``rte_mem_phy2mch`` was used in xen dom0 to obtain the physical address;
+     remove this API as xen dom0 support was removed.
 
 ABI Changes
 -----------
diff --git a/drivers/net/e1000/em_rxtx.c b/drivers/net/e1000/em_rxtx.c
index 31819c5..a0f63a7 100644
--- a/drivers/net/e1000/em_rxtx.c
+++ b/drivers/net/e1000/em_rxtx.c
@@ -1289,7 +1289,7 @@ eth_em_tx_queue_setup(struct rte_eth_dev *dev,
 	txq->port_id = dev->data->port_id;
 
 	txq->tdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_TDT(queue_idx));
-	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+	txq->tx_ring_phys_addr = tz->phys_addr;
 	txq->tx_ring = (struct e1000_data_desc *) tz->addr;
 
 	PMD_INIT_LOG(DEBUG, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
@@ -1416,7 +1416,7 @@ eth_em_rx_queue_setup(struct rte_eth_dev *dev,
 
 	rxq->rdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDT(queue_idx));
 	rxq->rdh_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDH(queue_idx));
-	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+	rxq->rx_ring_phys_addr = rz->phys_addr;
 	rxq->rx_ring = (struct e1000_rx_desc *) rz->addr;
 
 	PMD_INIT_LOG(DEBUG, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
diff --git a/drivers/net/e1000/igb_rxtx.c b/drivers/net/e1000/igb_rxtx.c
index 1c80a2a..0fccb5d 100644
--- a/drivers/net/e1000/igb_rxtx.c
+++ b/drivers/net/e1000/igb_rxtx.c
@@ -1530,7 +1530,7 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
 	txq->port_id = dev->data->port_id;
 
 	txq->tdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_TDT(txq->reg_idx));
-	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+	txq->tx_ring_phys_addr = tz->phys_addr;
 
 	txq->tx_ring = (union e1000_adv_tx_desc *) tz->addr;
 	/* Allocate software ring */
@@ -1667,7 +1667,7 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
 	}
 	rxq->rdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDT(rxq->reg_idx));
 	rxq->rdh_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDH(rxq->reg_idx));
-	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+	rxq->rx_ring_phys_addr = rz->phys_addr;
 	rxq->rx_ring = (union e1000_adv_rx_desc *) rz->addr;
 
 	/* Allocate software ring. */
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index e60d3a3..15ea2a5 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1887,7 +1887,7 @@ fm10k_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id,
 		return -ENOMEM;
 	}
 	q->hw_ring = mz->addr;
-	q->hw_ring_phys_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+	q->hw_ring_phys_addr = mz->phys_addr;
 
 	/* Check if number of descs satisfied Vector requirement */
 	if (!rte_is_power_of_2(nb_desc)) {
@@ -2047,7 +2047,7 @@ fm10k_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id,
 		return -ENOMEM;
 	}
 	q->hw_ring = mz->addr;
-	q->hw_ring_phys_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+	q->hw_ring_phys_addr = mz->phys_addr;
 
 	/*
 	 * allocate memory for the RS bit tracker. Enough slots to hold the
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 5f26e24..dc5458d 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -3741,7 +3741,7 @@ i40e_allocate_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,
 
 	mem->size = size;
 	mem->va = mz->addr;
-	mem->pa = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+	mem->pa = mz->phys_addr;
 	mem->zone = (const void *)mz;
 	PMD_DRV_LOG(DEBUG,
 		"memzone %s allocated with physical address: %"PRIu64,
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index 8013add..70dae92 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -249,7 +249,7 @@ i40e_fdir_setup(struct i40e_pf *pf)
 		goto fail_mem;
 	}
 	pf->fdir.prg_pkt = mz->addr;
-	pf->fdir.dma_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+	pf->fdir.dma_addr = mz->phys_addr;
 
 	pf->fdir.match_counter_index = I40E_COUNTER_INDEX_FDIR(hw->pf_id);
 	PMD_DRV_LOG(INFO, "FDIR setup successfully, with programming queue %u.",
diff --git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c
index f571e79..344c11c 100644
--- a/drivers/net/i40e/i40e_rxtx.c
+++ b/drivers/net/i40e/i40e_rxtx.c
@@ -1822,7 +1822,7 @@ i40e_dev_rx_queue_setup(struct rte_eth_dev *dev,
 	/* Zero all the descriptors in the ring. */
 	memset(rz->addr, 0, ring_size);
 
-	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+	rxq->rx_ring_phys_addr = rz->phys_addr;
 	rxq->rx_ring = (union i40e_rx_desc *)rz->addr;
 
 	len = (uint16_t)(nb_desc + RTE_PMD_I40E_RX_MAX_BURST);
@@ -2159,7 +2159,7 @@ i40e_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	txq->vsi = vsi;
 	txq->tx_deferred_start = tx_conf->tx_deferred_start;
 
-	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+	txq->tx_ring_phys_addr = tz->phys_addr;
 	txq->tx_ring = (struct i40e_tx_desc *)tz->addr;
 
 	/* Allocate software ring */
@@ -2671,7 +2671,7 @@ i40e_fdir_setup_tx_resources(struct i40e_pf *pf)
 	txq->reg_idx = pf->fdir.fdir_vsi->base_queue;
 	txq->vsi = pf->fdir.fdir_vsi;
 
-	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+	txq->tx_ring_phys_addr = tz->phys_addr;
 	txq->tx_ring = (struct i40e_tx_desc *)tz->addr;
 	/*
 	 * don't need to allocate software ring and reset for the fdir
@@ -2727,7 +2727,7 @@ i40e_fdir_setup_rx_resources(struct i40e_pf *pf)
 	rxq->reg_idx = pf->fdir.fdir_vsi->base_queue;
 	rxq->vsi = pf->fdir.fdir_vsi;
 
-	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+	rxq->rx_ring_phys_addr = rz->phys_addr;
 	rxq->rx_ring = (union i40e_rx_desc *)rz->addr;
 
 	/*
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 64bff25..ac1415b 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -2548,7 +2548,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	else
 		txq->tdt_reg_addr = IXGBE_PCI_REG_ADDR(hw, IXGBE_TDT(txq->reg_idx));
 
-	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+	txq->tx_ring_phys_addr = tz->phys_addr;
 	txq->tx_ring = (union ixgbe_adv_tx_desc *) tz->addr;
 
 	/* Allocate software ring */
@@ -2850,7 +2850,7 @@ ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
 			IXGBE_PCI_REG_ADDR(hw, IXGBE_RDH(rxq->reg_idx));
 	}
 
-	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+	rxq->rx_ring_phys_addr = rz->phys_addr;
 	rxq->rx_ring = (union ixgbe_adv_rx_desc *) rz->addr;
 
 	/*
diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c
index 6cecfc0..f9e9916 100644
--- a/drivers/net/sfc/sfc.c
+++ b/drivers/net/sfc/sfc.c
@@ -61,7 +61,7 @@ sfc_dma_alloc(const struct sfc_adapter *sa, const char *name, uint16_t id,
 		return ENOMEM;
 	}
 
-	esmp->esm_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+	esmp->esm_addr = mz->phys_addr;
 	if (esmp->esm_addr == RTE_BAD_PHYS_ADDR) {
 		(void)rte_memzone_free(mz);
 		return EFAULT;
diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index d8543c0..c545963 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -187,11 +187,6 @@ unsigned rte_memory_get_nchannel(void);
  */
 unsigned rte_memory_get_nrank(void);
 
-static inline phys_addr_t
-rte_mem_phy2mch(int32_t memseg_id __rte_unused, const phys_addr_t phy_addr)
-{
-	return phy_addr;
-}
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_mempool/rte_mempool.c b/lib/librte_mempool/rte_mempool.c
index 6d726ae..892a1ac 100644
--- a/lib/librte_mempool/rte_mempool.c
+++ b/lib/librte_mempool/rte_mempool.c
@@ -473,8 +473,6 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
 		     mp->populated_size < mp->size; off += phys_len) {
 
 		paddr = rte_mem_virt2phy(addr + off);
-		/* required for xen_dom0 to get the machine address */
-		paddr = rte_mem_phy2mch(-1, paddr);
 
 		if (paddr == RTE_BAD_PHYS_ADDR && rte_eal_has_hugepages()) {
 			ret = -EINVAL;
@@ -486,7 +484,6 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
 			phys_addr_t paddr_tmp;
 
 			paddr_tmp = rte_mem_virt2phy(addr + off + phys_len);
-			paddr_tmp = rte_mem_phy2mch(-1, paddr_tmp);
 
 			if (paddr_tmp != paddr + phys_len)
 				break;
-- 
2.7.4

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH 5/6] eal: remove xen dom0 support
  @ 2017-08-30 18:10  1% ` Jianfeng Tan
  2017-08-30 18:10  3% ` [dpdk-dev] [PATCH 6/6] eal: remove API rte_mem_phy2mch Jianfeng Tan
  1 sibling, 0 replies; 200+ results
From: Jianfeng Tan @ 2017-08-30 18:10 UTC (permalink / raw)
  To: dev
  Cc: xen-devel, thomas, john.mcnamara, oao.m.martins, jerin.jacob,
	shahafs, Jianfeng Tan

We remove xen-specific code in EAL, including the option --xen-dom0,
memory initialization code, compiling dependency, etc.

Besides, related documents are removed or updated.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
 MAINTAINERS                                        |   7 -
 config/common_base                                 |   5 -
 doc/guides/index.rst                               |   1 -
 doc/guides/linux_gsg/build_sample_apps.rst         |   5 +-
 doc/guides/linux_gsg/sys_reqs.rst                  |  53 --
 doc/guides/prog_guide/source_org.rst               |   1 -
 doc/guides/rel_notes/deprecation.rst               |   3 -
 doc/guides/rel_notes/release_17_11.rst             |  12 +
 doc/guides/testpmd_app_ug/run_app.rst              |   4 -
 doc/guides/xen/img/dpdk_xen_pkt_switch.png         | Bin 163842 -> 0 bytes
 doc/guides/xen/img/grant_refs.png                  | Bin 6405 -> 0 bytes
 doc/guides/xen/img/grant_table.png                 | Bin 96762 -> 0 bytes
 doc/guides/xen/index.rst                           |  38 -
 doc/guides/xen/pkt_switch.rst                      | 470 -------------
 .../bsdapp/eal/include/exec-env/rte_dom0_common.h  | 107 ---
 lib/librte_eal/common/eal_common_options.c         |   3 -
 lib/librte_eal/common/eal_internal_cfg.h           |   1 -
 lib/librte_eal/common/eal_options.h                |   2 -
 lib/librte_eal/common/include/rte_memory.h         |  66 --
 lib/librte_eal/linuxapp/Makefile                   |   2 -
 lib/librte_eal/linuxapp/eal/Makefile               |   5 +-
 lib/librte_eal/linuxapp/eal/eal.c                  |  24 -
 lib/librte_eal/linuxapp/eal/eal_memory.c           |  56 --
 lib/librte_eal/linuxapp/eal/eal_xen_memory.c       | 381 ----------
 .../eal/include/exec-env/rte_dom0_common.h         | 108 ---
 lib/librte_eal/linuxapp/igb_uio/igb_uio.c          |  54 --
 lib/librte_eal/linuxapp/xen_dom0/Makefile          |  53 --
 lib/librte_eal/linuxapp/xen_dom0/compat.h          |  15 -
 lib/librte_eal/linuxapp/xen_dom0/dom0_mm_dev.h     | 107 ---
 lib/librte_eal/linuxapp/xen_dom0/dom0_mm_misc.c    | 780 ---------------------
 pkg/dpdk.spec                                      |   3 -
 31 files changed, 14 insertions(+), 2352 deletions(-)
 delete mode 100644 doc/guides/xen/img/dpdk_xen_pkt_switch.png
 delete mode 100644 doc/guides/xen/img/grant_refs.png
 delete mode 100644 doc/guides/xen/img/grant_table.png
 delete mode 100644 doc/guides/xen/index.rst
 delete mode 100644 doc/guides/xen/pkt_switch.rst
 delete mode 100644 lib/librte_eal/bsdapp/eal/include/exec-env/rte_dom0_common.h
 delete mode 100644 lib/librte_eal/linuxapp/eal/eal_xen_memory.c
 delete mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_dom0_common.h
 delete mode 100644 lib/librte_eal/linuxapp/xen_dom0/Makefile
 delete mode 100644 lib/librte_eal/linuxapp/xen_dom0/compat.h
 delete mode 100644 lib/librte_eal/linuxapp/xen_dom0/dom0_mm_dev.h
 delete mode 100644 lib/librte_eal/linuxapp/xen_dom0/dom0_mm_misc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 003e72e..2af32ff 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -189,13 +189,6 @@ Linux VFIO
 M: Anatoly Burakov <anatoly.burakov@intel.com>
 F: lib/librte_eal/linuxapp/eal/*vfio*
 
-Linux Xen
-M: Jianfeng Tan <jianfeng.tan@intel.com>
-F: lib/librte_eal/linuxapp/xen_dom0/
-F: lib/librte_eal/linuxapp/eal/*xen*
-F: lib/librte_eal/linuxapp/eal/include/exec-env/rte_dom0_common.h
-F: doc/guides/xen/
-
 FreeBSD EAL (with overlaps)
 M: Bruce Richardson <bruce.richardson@intel.com>
 M: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
diff --git a/config/common_base b/config/common_base
index 93928b6..17d3dae 100644
--- a/config/common_base
+++ b/config/common_base
@@ -719,11 +719,6 @@ CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_VHOST=n
 
 #
-#Compile Xen domain0 support
-#
-CONFIG_RTE_LIBRTE_XEN_DOM0=n
-
-#
 # Compile the test application
 #
 CONFIG_RTE_APP_TEST=y
diff --git a/doc/guides/index.rst b/doc/guides/index.rst
index 63716b0..5b6eb7e 100644
--- a/doc/guides/index.rst
+++ b/doc/guides/index.rst
@@ -44,7 +44,6 @@ DPDK documentation
    nics/index
    cryptodevs/index
    eventdevs/index
-   xen/index
    contributing/index
    rel_notes/index
    faq/index
diff --git a/doc/guides/linux_gsg/build_sample_apps.rst b/doc/guides/linux_gsg/build_sample_apps.rst
index 0cc5fd1..582984d 100644
--- a/doc/guides/linux_gsg/build_sample_apps.rst
+++ b/doc/guides/linux_gsg/build_sample_apps.rst
@@ -116,7 +116,7 @@ The following is the list of options that can be given to the EAL:
 
     ./rte-app [-c COREMASK | -l CORELIST] [-n NUM] [-b <domain:bus:devid.func>] \
               [--socket-mem=MB,...] [-d LIB.so|DIR] [-m MB] [-r NUM] [-v] [--file-prefix] \
-	      [--proc-type <primary|secondary|auto>] [-- xen-dom0]
+	      [--proc-type <primary|secondary|auto>]
 
 The EAL options are as follows:
 
@@ -163,9 +163,6 @@ The EAL options are as follows:
 * ``--proc-type``:
   The type of process instance.
 
-* ``--xen-dom0``:
-  Support application running on Xen Domain0 without hugetlbfs.
-
 * ``--vmware-tsc-map``:
   Use VMware TSC map instead of native RDTSC.
 
diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index eb8442c..3e7fe63 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -228,56 +228,3 @@ The mount point can be made permanent across reboots, by adding the following li
 For 1GB pages, the page size must be specified as a mount option::
 
     nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
-
-Xen Domain0 Support in the Linux Environment
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The existing memory management implementation is based on the Linux kernel hugepage mechanism.
-On the Xen hypervisor, hugepage support for DomainU (DomU) Guests means that DPDK applications work as normal for guests.
-
-However, Domain0 (Dom0) does not support hugepages.
-To work around this limitation, a new kernel module rte_dom0_mm is added to facilitate the allocation and mapping of memory via
-**IOCTL** (allocation) and **MMAP** (mapping).
-
-Enabling Xen Dom0 Mode in the DPDK
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-By default, Xen Dom0 mode is disabled in the DPDK build configuration files.
-To support Xen Dom0, the CONFIG_RTE_LIBRTE_XEN_DOM0 setting should be changed to “y”, which enables the Xen Dom0 mode at compile time.
-
-Furthermore, the CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID setting should also be changed to “y” in the case of the wrong socket ID being received.
-
-Loading the DPDK rte_dom0_mm Module
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To run any DPDK application on Xen Dom0, the ``rte_dom0_mm`` module must be loaded into the running kernel with rsv_memsize option.
-The module is found in the kmod sub-directory of the DPDK target directory.
-This module should be loaded using the insmod command as shown below (assuming that the current directory is the DPDK target directory)::
-
-    sudo insmod kmod/rte_dom0_mm.ko rsv_memsize=X
-
-The value X cannot be greater than 4096(MB).
-
-Configuring Memory for DPDK Use
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-After the rte_dom0_mm.ko kernel module has been loaded, the user must configure the memory size for DPDK usage.
-This is done by echoing the memory size to a memsize file in the /sys/devices/ directory.
-Use the following command (assuming that 2048 MB is required)::
-
-    echo 2048 > /sys/kernel/mm/dom0-mm/memsize-mB/memsize
-
-The user can also check how much memory has already been used::
-
-    cat /sys/kernel/mm/dom0-mm/memsize-mB/memsize_rsvd
-
-Xen Domain0 does not support NUMA configuration, as a result the ``--socket-mem`` command line option is invalid for Xen Domain0.
-
-.. note::
-
-    The memsize value cannot be greater than the rsv_memsize value.
-
-Running the DPDK Application on Xen Domain0
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To run the DPDK application on Xen Domain0, an extra command line option ``--xen-dom0`` is required.
diff --git a/doc/guides/prog_guide/source_org.rst b/doc/guides/prog_guide/source_org.rst
index d5d01f3..7aab4b4 100644
--- a/doc/guides/prog_guide/source_org.rst
+++ b/doc/guides/prog_guide/source_org.rst
@@ -108,7 +108,6 @@ The drivers directory has a *net* subdirectory which contains::
     +-- szedata2           # SZEDATA2 poll mode driver
     +-- virtio             # Virtio poll mode driver
     +-- vmxnet3            # VMXNET3 poll mode driver
-    +-- xenvirt            # Xen virtio poll mode driver
 
 .. note::
 
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 3362f33..7a2d2f2 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -29,9 +29,6 @@ Deprecation Notices
   - ``rte_eal_devargs_type_count``
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
 
-* eal: the support of Xen dom0 will be removed from EAL in 17.11; and with
-  that, drivers/net/xenvirt and examples/vhost_xen will also be removed.
-
 * eal: An ABI change is planned for 17.11 to make DPDK aware of IOVA address
   translation scheme.
   Reference to phys address in EAL data-structure or functions may change to
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..d211084 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,7 +124,19 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+Removed Items
+-------------
 
+.. This section should contain removed items in this release. Sample format:
+
+   * Add a short 1-2 sentence description of the removed item in the past
+     tense.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+   * Xen dom0 in EAL was removed, as well as xenvirt PMD and vhost_xen.
 
 Shared Library Versions
 -----------------------
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index e8303f3..bd5ebe6 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -94,10 +94,6 @@ See the DPDK Getting Started Guides for more information on these options.
 
     Display the version information on startup.
 
-*   ``--xen-dom0``
-
-    Support application running on Xen Domain0 without hugetlbfs.
-
 *   ``--syslog``
 
     Set the syslog facility.
diff --git a/doc/guides/xen/img/dpdk_xen_pkt_switch.png b/doc/guides/xen/img/dpdk_xen_pkt_switch.png
deleted file mode 100644
index 32a6d1618820e930b17231f8fe38aab5d5c5d370..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 163842
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

diff --git a/doc/guides/xen/img/grant_refs.png b/doc/guides/xen/img/grant_refs.png
deleted file mode 100644
index baa34e1e3f5e8975ae0516a09f906933b1ac688d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6405
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
R9${aAy7JpMP(_Qd{{c{~dJX^p

diff --git a/doc/guides/xen/img/grant_table.png b/doc/guides/xen/img/grant_table.png
deleted file mode 100644
index c23e5fa73e660c5be9c7cd01f55ff34e2917632b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 96762
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
Z{{xM~vTICa&vpO+002ovPDHLkV1nHvhjah{

diff --git a/doc/guides/xen/index.rst b/doc/guides/xen/index.rst
deleted file mode 100644
index cb43cd2..0000000
--- a/doc/guides/xen/index.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
-    All rights reserved.
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-
-    * Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in
-    the documentation and/or other materials provided with the
-    distribution.
-    * Neither the name of Intel Corporation nor the names of its
-    contributors may be used to endorse or promote products derived
-    from this software without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Xen Guide
-=========
-
-.. toctree::
-    :maxdepth: 2
-    :numbered:
-
-    pkt_switch
diff --git a/doc/guides/xen/pkt_switch.rst b/doc/guides/xen/pkt_switch.rst
deleted file mode 100644
index 717a04b..0000000
--- a/doc/guides/xen/pkt_switch.rst
+++ /dev/null
@@ -1,470 +0,0 @@
-..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
-    All rights reserved.
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions
-    are met:
-
-    * Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in
-    the documentation and/or other materials provided with the
-    distribution.
-    * Neither the name of Intel Corporation nor the names of its
-    contributors may be used to endorse or promote products derived
-    from this software without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-DPDK Xen Based Packet-Switching Solution
-========================================
-
-Introduction
-------------
-
-DPDK provides a para-virtualization packet switching solution, based on the Xen hypervisor's Grant Table, Note 1,
-which provides simple and fast packet switching capability between guest domains and host domain based on MAC address or VLAN tag.
-
-This solution is comprised of two components;
-a Poll Mode Driver (PMD) as the front end in the guest domain and a switching back end in the host domain.
-XenStore is used to exchange configure information between the PMD front end and switching back end,
-including grant reference IDs for shared Virtio RX/TX rings,
-MAC address, device state, and so on. XenStore is an information storage space shared between domains,
-see further information on XenStore below.
-
-The front end PMD can be found in the DPDK directory lib/ librte_pmd_xenvirt and back end example in examples/vhost_xen.
-
-The PMD front end and switching back end use shared Virtio RX/TX rings as para- virtualized interface.
-The Virtio ring is created by the front end, and Grant table references for the ring are passed to host.
-The switching back end maps those grant table references and creates shared rings in a mapped address space.
-
-The following diagram describes the functionality of the DPDK Xen Packet- Switching Solution.
-
-
-.. _figure_dpdk_xen_pkt_switch:
-
-.. figure:: img/dpdk_xen_pkt_switch.*
-
-   Functionality of the DPDK Xen Packet Switching Solution.
-
-
-Note 1 The Xen hypervisor uses a mechanism called a Grant Table to share memory between domains
-(`http://wiki.xen.org/wiki/Grant Table <http://wiki.xen.org/wiki/Grant%20Table>`_).
-
-A diagram of the design is shown below, where "gva" is the Guest Virtual Address,
-which is the data pointer of the mbuf, and "hva" is the Host Virtual Address:
-
-
-.. _figure_grant_table:
-
-.. figure:: img/grant_table.*
-
-   DPDK Xen Layout
-
-
-In this design, a Virtio ring is used as a para-virtualized interface for better performance over a Xen private ring
-when packet switching to and from a VM.
-The additional performance is gained by avoiding a system call and memory map in each memory copy with a XEN private ring.
-
-Device Creation
----------------
-
-Poll Mode Driver Front End
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-*   Mbuf pool allocation:
-
-    To use a Xen switching solution, the DPDK application should use rte_mempool_gntalloc_create()
-    to reserve mbuf pools during initialization.
-    rte_mempool_gntalloc_create() creates a mempool with objects from memory allocated and managed via gntalloc/gntdev.
-
-    The DPDK now supports construction of mempools from allocated virtual memory through the rte_mempool_xmem_create() API.
-
-    This front end constructs mempools based on memory allocated through the xen_gntalloc driver.
-    rte_mempool_gntalloc_create() allocates Grant pages, maps them to continuous virtual address space,
-    and calls rte_mempool_xmem_create() to build mempools.
-    The Grant IDs for all Grant pages are passed to the host through XenStore.
-
-*   Virtio Ring Creation:
-
-    The Virtio queue size is defined as 256 by default in the VQ_DESC_NUM macro.
-    Using the queue setup function,
-    Grant pages are allocated based on ring size and are mapped to continuous virtual address space to form the Virtio ring.
-    Normally, one ring is comprised of several pages.
-    Their Grant IDs are passed to the host through XenStore.
-
-    There is no requirement that this memory be physically continuous.
-
-*   Interrupt and Kick:
-
-    There are no interrupts in DPDK Xen Switching as both front and back ends work in polling mode.
-    There is no requirement for notification.
-
-*   Feature Negotiation:
-
-    Currently, feature negotiation through XenStore is not supported.
-
-*   Packet Reception & Transmission:
-
-    With mempools and Virtio rings created, the front end can operate Virtio devices,
-    as it does in Virtio PMD for KVM Virtio devices with the exception that the host
-    does not require notifications or deal with interrupts.
-
-XenStore is a database that stores guest and host information in the form of (key, value) pairs.
-The following is an example of the information generated during the startup of the front end PMD in a guest VM (domain ID 1):
-
-.. code-block:: console
-
-        xenstore -ls /local/domain/1/control/dpdk
-        0_mempool_gref="3042,3043,3044,3045"
-        0_mempool_va="0x7fcbc6881000"
-        0_tx_vring_gref="3049"
-        0_rx_vring_gref="3053"
-        0_ether_addr="4e:0b:d0:4e:aa:f1"
-        0_vring_flag="3054"
-        ...
-
-Multiple mempools and multiple Virtios may exist in the guest domain, the first number is the index, starting from zero.
-
-The idx#_mempool_va stores the guest virtual address for mempool idx#.
-
-The idx#_ether_adder stores the MAC address of the guest Virtio device.
-
-For idx#_rx_ring_gref, idx#_tx_ring_gref, and idx#_mempool_gref, the value is a list of Grant references.
-Take idx#_mempool_gref node for example, the host maps those Grant references to a continuous virtual address space.
-The real Grant reference information is stored in this virtual address space,
-where (gref, pfn) pairs follow each other with -1 as the terminator.
-
-
-.. _figure_grant_refs:
-
-.. figure:: img/grant_refs.*
-
-   Mapping Grant references to a continuous virtual address space
-
-
-After all gref# IDs are retrieved, the host maps them to a continuous virtual address space.
-With the guest mempool virtual address, the host establishes 1:1 address mapping.
-With multiple guest mempools, the host establishes multiple address translation regions.
-
-Switching Back End
-~~~~~~~~~~~~~~~~~~
-
-The switching back end monitors changes in XenStore.
-When the back end detects that a new Virtio device has been created in a guest domain, it will:
-
-#.  Retrieve Grant and configuration information from XenStore.
-
-#.  Map and create a Virtio ring.
-
-#.  Map mempools in the host and establish address translation between the guest address and host address.
-
-#.  Select a free VMDQ pool, set its affinity with the Virtio device, and set the MAC/ VLAN filter.
-
-Packet Reception
-~~~~~~~~~~~~~~~~
-
-When packets arrive from an external network, the MAC?VLAN filter classifies packets into queues in one VMDQ pool.
-As each pool is bonded to a Virtio device in some guest domain, the switching back end will:
-
-#.  Fetch an available entry from the Virtio RX ring.
-
-#.  Get gva, and translate it to hva.
-
-#.  Copy the contents of the packet to the memory buffer pointed to by gva.
-
-The DPDK application in the guest domain, based on the PMD front end,
-is polling the shared Virtio RX ring for available packets and receives them on arrival.
-
-Packet Transmission
-~~~~~~~~~~~~~~~~~~~
-
-When a Virtio device in one guest domain is to transmit a packet,
-it puts the virtual address of the packet's data area into the shared Virtio TX ring.
-
-The packet switching back end is continuously polling the Virtio TX ring.
-When new packets are available for transmission from a guest, it will:
-
-#.  Fetch an available entry from the Virtio TX ring.
-
-#.  Get gva, and translate it to hva.
-
-#.  Copy the packet from hva to the host mbuf's data area.
-
-#.  Compare the destination MAC address with all the MAC addresses of the Virtio devices it manages.
-    If a match exists, it directly copies the packet to the matched VIrtio RX ring.
-    Otherwise, it sends the packet out through hardware.
-
-.. note::
-
-    The packet switching back end is for demonstration purposes only.
-    The user could implement their switching logic based on this example.
-    In this example, only one physical port on the host is supported.
-    Multiple segments are not supported. The biggest mbuf supported is 4KB.
-    When the back end is restarted, all front ends must also be restarted.
-
-Running the Application
------------------------
-
-The following describes the steps required to run the application.
-
-Validated Environment
-~~~~~~~~~~~~~~~~~~~~~
-
-Host:
-
-    Xen-hypervisor: 4.2.2
-
-    Distribution: Fedora release 18
-
-    Kernel: 3.10.0
-
-    Xen development package (including Xen, Xen-libs, xen-devel): 4.2.3
-
-Guest:
-
-    Distribution: Fedora 16 and 18
-
-    Kernel: 3.6.11
-
-Xen Host Prerequisites
-~~~~~~~~~~~~~~~~~~~~~~
-
-Note that the following commands might not be the same on different Linux* distributions.
-
-*   Install xen-devel package:
-
-    .. code-block:: console
-
-        yum install xen-devel.x86_64
-
-*   Start xend if not already started:
-
-    .. code-block:: console
-
-        /etc/init.d/xend start
-
-*   Mount xenfs if not already mounted:
-
-    .. code-block:: console
-
-        mount -t xenfs none /proc/xen
-
-*   Enlarge the limit for xen_gntdev driver:
-
-    .. code-block:: console
-
-        modprobe -r xen_gntdev
-        modprobe xen_gntdev limit=1000000
-
-.. note::
-
-    The default limit for earlier versions of the xen_gntdev driver is 1024.
-    That is insufficient to support the mapping of multiple Virtio devices into multiple VMs,
-    so it is necessary to enlarge the limit by reloading this module.
-    The default limit of recent versions of xen_gntdev is 1048576.
-    The rough calculation of this limit is:
-
-        limit=nb_mbuf# * VM#.
-
-        In DPDK examples, nb_mbuf# is normally 8192.
-
-Building and Running the Switching Backend
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-#.  Edit config/common_linuxapp, and change the default configuration value for the following two items:
-
-    .. code-block:: console
-
-        CONFIG_RTE_LIBRTE_XEN_DOM0=y
-        CONFIG RTE_LIBRTE_PMD_XENVIRT=n
-
-#.  Build the target:
-
-    .. code-block:: console
-
-        make install T=x86_64-native-linuxapp-gcc
-
-#.  Ensure that RTE_SDK and RTE_TARGET are correctly set. Build the switching example:
-
-    .. code-block:: console
-
-        make -C examples/vhost_xen/
-
-#.  Load the Xen DPDK memory management module and preallocate memory:
-
-    .. code-block:: console
-
-        insmod ./x86_64-native-linuxapp-gcc/build/lib/librte_eal/linuxapp/xen_dom0/rte_dom0_mm.ko
-        echo 2048> /sys/kernel/mm/dom0-mm/memsize-mB/memsize
-
-    .. note::
-
-        On Xen Dom0, there is no hugepage support.
-        Under Xen Dom0, the DPDK uses a special memory management kernel module
-        to allocate chunks of physically continuous memory.
-        Refer to the *DPDK Getting Started Guide* for more information on memory management in the DPDK.
-        In the above command, 4 GB memory is reserved (2048 of 2 MB pages) for DPDK.
-
-#.  Load uio_pci_generic and bind one Intel NIC controller to it:
-
-    .. code-block:: console
-
-        modprobe uio_pci_generic
-        python usertools/dpdk-devbind.py -b uio_pci_generic 0000:09:00:00.0
-
-    In this case, 0000:09:00.0 is the PCI address for the NIC controller.
-
-#.  Run the switching back end example:
-
-    .. code-block:: console
-
-        examples/vhost_xen/build/vhost-switch -l 0-3 -n 3 --xen-dom0 -- -p1
-
-.. note::
-
-    The -xen-dom0 option instructs the DPDK to use the Xen kernel module to allocate memory.
-
-Other Parameters:
-
-*   -vm2vm
-
-    The vm2vm parameter enables/disables packet switching in software.
-    Disabling vm2vm implies that on a VM packet transmission will always go to the Ethernet port
-    and will not be switched to another VM
-
-*   -Stats
-
-    The Stats parameter controls the printing of Virtio-net device statistics.
-    The parameter specifies the interval (in seconds) at which to print statistics,
-    an interval of 0 seconds will disable printing statistics.
-
-Xen PMD Frontend Prerequisites
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-#.  Install xen-devel package for accessing XenStore:
-
-    .. code-block:: console
-
-        yum install xen-devel.x86_64
-
-#.  Mount xenfs, if it is not already mounted:
-
-    .. code-block:: console
-
-        mount -t xenfs none /proc/xen
-
-#.  Enlarge the default limit for xen_gntalloc driver:
-
-    .. code-block:: console
-
-        modprobe -r xen_gntalloc
-        modprobe xen_gntalloc limit=6000
-
-.. note::
-
-    Before the Linux kernel version 3.8-rc5, Jan 15th 2013,
-    a critical defect occurs when a guest is heavily allocating Grant pages.
-    The Grant driver allocates fewer pages than expected which causes kernel memory corruption.
-    This happens, for example, when a guest uses the v1 format of a Grant table entry and allocates
-    more than 8192 Grant pages (this number might be different on different hypervisor versions).
-    To work around this issue, set the limit for gntalloc driver to 6000.
-    (The kernel normally allocates hundreds of Grant pages with one Xen front end per virtualized device).
-    If the kernel allocates a lot of Grant pages, for example, if the user uses multiple net front devices,
-    it is best to upgrade the Grant alloc driver.
-    This defect has been fixed in kernel version 3.8-rc5 and later.
-
-Building and Running the Front End
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-#.  Edit config/common_linuxapp, and change the default configuration value:
-
-    .. code-block:: console
-
-        CONFIG_RTE_LIBRTE_XEN_DOM0=n
-        CONFIG_RTE_LIBRTE_PMD_XENVIRT=y
-
-#.  Build the package:
-
-    .. code-block:: console
-
-        make install T=x86_64-native-linuxapp-gcc
-
-#.  Enable hugepages. Refer to the  *DPDK Getting Started Guide* for instructions on
-    how to use hugepages in the DPDK.
-
-#.  Run TestPMD. Refer to *DPDK TestPMD Application User Guide* for detailed parameter usage.
-
-    .. code-block:: console
-
-        ./x86_64-native-linuxapp-gcc/app/testpmd -l 0-3 -n 4 --vdev="net_xenvirt0,mac=00:00:00:00:00:11"
-        testpmd>set fwd mac
-        testpmd>start
-
-    As an example to run two TestPMD instances over 2 Xen Virtio devices:
-
-    .. code-block:: console
-
-        --vdev="net_xenvirt0,mac=00:00:00:00:00:11" --vdev="net_xenvirt1;mac=00:00:00:00:00:22"
-
-
-Usage Examples: Injecting a Packet Stream Using a Packet Generator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Loopback Mode
-^^^^^^^^^^^^^
-
-Run TestPMD in a guest VM:
-
-.. code-block:: console
-
-    ./x86_64-native-linuxapp-gcc/app/testpmd -l 0-3 -n 4 --vdev="net_xenvirt0,mac=00:00:00:00:00:11" -- -i --eth-peer=0,00:00:00:00:00:22
-    testpmd> set fwd mac
-    testpmd> start
-
-Example output of the vhost_switch would be:
-
-.. code-block:: console
-
-    DATA:(0) MAC_ADDRESS 00:00:00:00:00:11 and VLAN_TAG 1000 registered.
-
-The above message indicates that device 0 has been registered with MAC address 00:00:00:00:00:11 and VLAN tag 1000.
-Any packets received on the NIC with these values is placed on the device's receive queue.
-
-Configure a packet stream in the packet generator, set the destination MAC address to 00:00:00:00:00:11, and VLAN to 1000,
-the guest Virtio receives these packets and sends them out with destination MAC address 00:00:00:00:00:22.
-
-Inter-VM Mode
-^^^^^^^^^^^^^
-
-Run TestPMD in guest VM1:
-
-.. code-block:: console
-
-    ./x86_64-native-linuxapp-gcc/app/testpmd -l 0-3 -n 4 --vdev="net_xenvirt0,mac=00:00:00:00:00:11" -- -i --eth-peer=0,00:00:00:00:00:22 -- -i
-
-Run TestPMD in guest VM2:
-
-.. code-block:: console
-
-    ./x86_64-native-linuxapp-gcc/app/testpmd -l 0-3 -n 4 --vdev="net_xenvirt0,mac=00:00:00:00:00:22" -- -i --eth-peer=0,00:00:00:00:00:33
-
-Configure a packet stream in the packet generator, and set the destination MAC address to 00:00:00:00:00:11 and VLAN to 1000.
-The packets received in Virtio in guest VM1 will be forwarded to Virtio in guest VM2 and
-then sent out through hardware with destination MAC address 00:00:00:00:00:33.
-
-The packet flow is:
-
-packet generator->Virtio in guest VM1->switching backend->Virtio in guest VM2->switching backend->wire
diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_dom0_common.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_dom0_common.h
deleted file mode 100644
index 99a3343..0000000
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_dom0_common.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-
- *   This file is provided under a dual BSD/LGPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GNU LESSER GENERAL PUBLIC LICENSE
- *
- *   Copyright(c) 2007-2014 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2.1 of the GNU Lesser General Public License
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *   Contact Information:
- *   Intel Corporation
- *
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *   * Neither the name of Intel Corporation nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _RTE_DOM0_COMMON_H_
-#define _RTE_DOM0_COMMON_H_
-
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
-
-#define DOM0_NAME_MAX   256
-#define DOM0_MM_DEV   "/dev/dom0_mm"
-
-#define DOM0_CONTIG_NUM_ORDER       9       /**< 2M order */
-#define DOM0_NUM_MEMSEG             512     /**< Maximum nb. of memory segment. */
-#define DOM0_MEMBLOCK_SIZE          0x200000 /**< Maximum nb. of memory block(2M). */
-#define DOM0_CONFIG_MEMSIZE         4096     /**< Maximum config memory size(4G). */
-#define DOM0_NUM_MEMBLOCK (DOM0_CONFIG_MEMSIZE / 2) /**< Maximum nb. of 2M memory block. */
-
-#define RTE_DOM0_IOCTL_PREPARE_MEMSEG    _IOWR(0, 1 , struct memory_info)
-#define RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG  _IOWR(0, 2 , char *)
-#define RTE_DOM0_IOCTL_GET_NUM_MEMSEG    _IOWR(0, 3, int)
-#define RTE_DOM0_IOCTL_GET_MEMSEG_INFO   _IOWR(0, 4, void *)
-
-/**
- * A structure used to store memory information.
- */
-struct memory_info {
-	char name[DOM0_NAME_MAX];
-	uint64_t size;
-};
-
-/**
- * A structure used to store memory segment information.
- */
-struct memseg_info {
-	uint32_t idx;
-	uint64_t pfn;
-	uint64_t size;
-	uint64_t mfn[DOM0_NUM_MEMBLOCK];
-};
-
-/**
- * A structure used to store memory block information.
- */
-struct memblock_info {
-	uint8_t  exchange_flag;
-	uint64_t vir_addr;
-	uint64_t pfn;
-	uint64_t mfn;
-};
-#endif /* _RTE_DOM0_COMMON_H_ */
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 1da185e..354cded 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -97,7 +97,6 @@ eal_long_options[] = {
 	{OPT_VDEV,              1, NULL, OPT_VDEV_NUM             },
 	{OPT_VFIO_INTR,         1, NULL, OPT_VFIO_INTR_NUM        },
 	{OPT_VMWARE_TSC_MAP,    0, NULL, OPT_VMWARE_TSC_MAP_NUM   },
-	{OPT_XEN_DOM0,          0, NULL, OPT_XEN_DOM0_NUM         },
 	{0,                     0, NULL, 0                        }
 };
 
@@ -208,8 +207,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg)
 
 	internal_cfg->syslog_facility = LOG_DAEMON;
 
-	internal_cfg->xen_dom0_support = 0;
-
 	/* if set to NONE, interrupt mode is determined automatically */
 	internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE;
 
diff --git a/lib/librte_eal/common/eal_internal_cfg.h b/lib/librte_eal/common/eal_internal_cfg.h
index 7b7e8c8..f7c885f 100644
--- a/lib/librte_eal/common/eal_internal_cfg.h
+++ b/lib/librte_eal/common/eal_internal_cfg.h
@@ -65,7 +65,6 @@ struct internal_config {
 	volatile unsigned force_nrank;    /**< force number of ranks */
 	volatile unsigned no_hugetlbfs;   /**< true to disable hugetlbfs */
 	unsigned hugepage_unlink;         /**< true to unlink backing files */
-	volatile unsigned xen_dom0_support; /**< support app running on Xen Dom0*/
 	volatile unsigned no_pci;         /**< true to disable PCI */
 	volatile unsigned no_hpet;        /**< true to disable HPET */
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
index 439a261..8770b85 100644
--- a/lib/librte_eal/common/eal_options.h
+++ b/lib/librte_eal/common/eal_options.h
@@ -81,8 +81,6 @@ enum {
 	OPT_VFIO_INTR_NUM,
 #define OPT_VMWARE_TSC_MAP    "vmware-tsc-map"
 	OPT_VMWARE_TSC_MAP_NUM,
-#define OPT_XEN_DOM0          "xen-dom0"
-	OPT_XEN_DOM0_NUM,
 	OPT_LONG_MAX_NUM
 };
 
diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index 4aa5d1f..d8543c0 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -46,10 +46,6 @@
 
 #include <rte_config.h>
 
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <exec-env/rte_dom0_common.h>
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -116,10 +112,6 @@ struct rte_memseg {
 	int32_t socket_id;          /**< NUMA socket ID. */
 	uint32_t nchannel;          /**< Number of channels. */
 	uint32_t nrank;             /**< Number of ranks. */
-#ifdef RTE_LIBRTE_XEN_DOM0
-	 /**< store segment MFNs */
-	uint64_t mfn[DOM0_NUM_MEMBLOCK];
-#endif
 } __rte_packed;
 
 /**
@@ -195,69 +187,11 @@ unsigned rte_memory_get_nchannel(void);
  */
 unsigned rte_memory_get_nrank(void);
 
-#ifdef RTE_LIBRTE_XEN_DOM0
-
-/**< Internal use only - should DOM0 memory mapping be used */
-int rte_xen_dom0_supported(void);
-
-/**< Internal use only - phys to virt mapping for xen */
-phys_addr_t rte_xen_mem_phy2mch(int32_t, const phys_addr_t);
-
-/**
- * Return the physical address of elt, which is an element of the pool mp.
- *
- * @param memseg_id
- *   Identifier of the memory segment owning the physical address. If
- *   set to -1, find it automatically.
- * @param phy_addr
- *   physical address of elt.
- *
- * @return
- *   The physical address or RTE_BAD_PHYS_ADDR on error.
- */
-static inline phys_addr_t
-rte_mem_phy2mch(int32_t memseg_id, const phys_addr_t phy_addr)
-{
-	if (rte_xen_dom0_supported())
-		return rte_xen_mem_phy2mch(memseg_id, phy_addr);
-	else
-		return phy_addr;
-}
-
-/**
- * Memory init for supporting application running on Xen domain0.
- *
- * @param void
- *
- * @return
- *       0: successfully
- *	 negative: error
- */
-int rte_xen_dom0_memory_init(void);
-
-/**
- * Attach to memory setments of primary process on Xen domain0.
- *
- * @param void
- *
- * @return
- *       0: successfully
- *       negative: error
- */
-int rte_xen_dom0_memory_attach(void);
-#else
-static inline int rte_xen_dom0_supported(void)
-{
-	return 0;
-}
-
 static inline phys_addr_t
 rte_mem_phy2mch(int32_t memseg_id __rte_unused, const phys_addr_t phy_addr)
 {
 	return phy_addr;
 }
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index 4794696..2ebdf31 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -35,7 +35,5 @@ DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal
 DIRS-$(CONFIG_RTE_EAL_IGB_UIO) += igb_uio
 DIRS-$(CONFIG_RTE_KNI_KMOD) += kni
 DEPDIRS-kni := eal
-DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += xen_dom0
-DEPDIRS-xen_dom0 := eal
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 90bca4d..d9f9985 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -58,9 +58,6 @@ endif
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) := eal.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_hugepage_info.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_memory.c
-ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_xen_memory.c
-endif
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_thread.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_log.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_vfio.c
@@ -130,7 +127,7 @@ ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
 CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
-INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC := rte_interrupts.h rte_kni_common.h
 
 SYMLINK-$(CONFIG_RTE_EXEC_ENV_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 48f12f4..d995d03 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -354,7 +354,6 @@ eal_usage(const char *prgname)
 	       "  --"OPT_BASE_VIRTADDR"     Base virtual address\n"
 	       "  --"OPT_CREATE_UIO_DEV"    Create /dev/uioX (usually done by hotplug)\n"
 	       "  --"OPT_VFIO_INTR"         Interrupt mode for VFIO (legacy|msi|msix)\n"
-	       "  --"OPT_XEN_DOM0"          Support running on Xen dom0 without hugetlbfs\n"
 	       "\n");
 	/* Allow the application to print its usage message too if hook is set */
 	if ( rte_application_usage_hook ) {
@@ -555,19 +554,6 @@ eal_parse_args(int argc, char **argv)
 			eal_usage(prgname);
 			exit(EXIT_SUCCESS);
 
-		/* long options */
-		case OPT_XEN_DOM0_NUM:
-#ifdef RTE_LIBRTE_XEN_DOM0
-			internal_config.xen_dom0_support = 1;
-#else
-			RTE_LOG(ERR, EAL, "Can't support DPDK app "
-				"running on Dom0, please configure"
-				" RTE_LIBRTE_XEN_DOM0=y\n");
-			ret = -1;
-			goto out;
-#endif
-			break;
-
 		case OPT_HUGE_DIR_NUM:
 			internal_config.hugepage_dir = optarg;
 			break;
@@ -641,15 +627,6 @@ eal_parse_args(int argc, char **argv)
 		goto out;
 	}
 
-	/* --xen-dom0 doesn't make sense with --socket-mem */
-	if (internal_config.xen_dom0_support && internal_config.force_sockets == 1) {
-		RTE_LOG(ERR, EAL, "Options --"OPT_SOCKET_MEM" cannot be specified "
-			"together with --"OPT_XEN_DOM0"\n");
-		eal_usage(prgname);
-		ret = -1;
-		goto out;
-	}
-
 	if (optind >= 0)
 		argv[optind-1] = prgname;
 	ret = optind-1;
@@ -794,7 +771,6 @@ rte_eal_init(int argc, char **argv)
 
 	if (internal_config.no_hugetlbfs == 0 &&
 			internal_config.process_type != RTE_PROC_SECONDARY &&
-			internal_config.xen_dom0_support == 0 &&
 			eal_hugepage_info_init() < 0) {
 		rte_eal_init_alert("Cannot get hugepage information.");
 		rte_errno = EACCES;
diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c
index 5279128..087fad4 100644
--- a/lib/librte_eal/linuxapp/eal/eal_memory.c
+++ b/lib/librte_eal/linuxapp/eal/eal_memory.c
@@ -75,13 +75,6 @@
 
 #define PFN_MASK_SIZE	8
 
-#ifdef RTE_LIBRTE_XEN_DOM0
-int rte_xen_dom0_supported(void)
-{
-	return internal_config.xen_dom0_support;
-}
-#endif
-
 /**
  * @file
  * Huge page mapping under linux
@@ -106,10 +99,6 @@ test_phys_addrs_available(void)
 	uint64_t tmp;
 	phys_addr_t physaddr;
 
-	/* For dom0, phys addresses can always be available */
-	if (rte_xen_dom0_supported())
-		return;
-
 	if (!rte_eal_has_hugepages()) {
 		RTE_LOG(ERR, EAL,
 			"Started without hugepages support, physical addresses not available\n");
@@ -139,29 +128,6 @@ rte_mem_virt2phy(const void *virtaddr)
 	int page_size;
 	off_t offset;
 
-	/* when using dom0, /proc/self/pagemap always returns 0, check in
-	 * dpdk memory by browsing the memsegs */
-	if (rte_xen_dom0_supported()) {
-		struct rte_mem_config *mcfg;
-		struct rte_memseg *memseg;
-		unsigned i;
-
-		mcfg = rte_eal_get_configuration()->mem_config;
-		for (i = 0; i < RTE_MAX_MEMSEG; i++) {
-			memseg = &mcfg->memseg[i];
-			if (memseg->addr == NULL)
-				break;
-			if (virtaddr > memseg->addr &&
-					virtaddr < RTE_PTR_ADD(memseg->addr,
-						memseg->len)) {
-				return memseg->phys_addr +
-					RTE_PTR_DIFF(virtaddr, memseg->addr);
-			}
-		}
-
-		return RTE_BAD_PHYS_ADDR;
-	}
-
 	/* Cannot parse /proc/self/pagemap, no need to log errors everywhere */
 	if (!phys_addrs_available)
 		return RTE_BAD_PHYS_ADDR;
@@ -1067,17 +1033,6 @@ rte_eal_hugepage_init(void)
 		return 0;
 	}
 
-/* check if app runs on Xen Dom0 */
-	if (internal_config.xen_dom0_support) {
-#ifdef RTE_LIBRTE_XEN_DOM0
-		/* use dom0_mm kernel driver to init memory */
-		if (rte_xen_dom0_memory_init() < 0)
-			return -1;
-		else
-			return 0;
-#endif
-	}
-
 	/* calculate total number of hugepages available. at this point we haven't
 	 * yet started sorting them so they all are on socket 0 */
 	for (i = 0; i < (int) internal_config.num_hugepage_sizes; i++) {
@@ -1400,17 +1355,6 @@ rte_eal_hugepage_attach(void)
 
 	test_phys_addrs_available();
 
-	if (internal_config.xen_dom0_support) {
-#ifdef RTE_LIBRTE_XEN_DOM0
-		if (rte_xen_dom0_memory_attach() < 0) {
-			RTE_LOG(ERR, EAL, "Failed to attach memory segments of primary "
-					"process\n");
-			return -1;
-		}
-		return 0;
-#endif
-	}
-
 	fd_zero = open("/dev/zero", O_RDONLY);
 	if (fd_zero < 0) {
 		RTE_LOG(ERR, EAL, "Could not open /dev/zero\n");
diff --git a/lib/librte_eal/linuxapp/eal/eal_xen_memory.c b/lib/librte_eal/linuxapp/eal/eal_xen_memory.c
deleted file mode 100644
index 19db1cb..0000000
--- a/lib/librte_eal/linuxapp/eal/eal_xen_memory.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/queue.h>
-#include <sys/file.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memzone.h>
-#include <rte_launch.h>
-#include <rte_eal.h>
-#include <rte_eal_memconfig.h>
-#include <rte_per_lcore.h>
-#include <rte_lcore.h>
-#include <rte_common.h>
-#include <rte_string_fns.h>
-
-#include "eal_private.h"
-#include "eal_internal_cfg.h"
-#include "eal_filesystem.h"
-#include <exec-env/rte_dom0_common.h>
-
-#define PAGE_SIZE RTE_PGSIZE_4K
-#define DEFAUL_DOM0_NAME "dom0-mem"
-
-static int xen_fd = -1;
-static const char sys_dir_path[] = "/sys/kernel/mm/dom0-mm/memsize-mB";
-
-/*
- * Try to mmap *size bytes in /dev/zero. If it is successful, return the
- * pointer to the mmap'd area and keep *size unmodified. Else, retry
- * with a smaller zone: decrease *size by mem_size until it reaches
- * 0. In this case, return NULL. Note: this function returns an address
- * which is a multiple of mem_size size.
- */
-static void *
-xen_get_virtual_area(size_t *size, size_t mem_size)
-{
-	void *addr;
-	int fd;
-	long aligned_addr;
-
-	RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zu bytes\n", *size);
-
-	fd = open("/dev/zero", O_RDONLY);
-	if (fd < 0){
-		RTE_LOG(ERR, EAL, "Cannot open /dev/zero\n");
-		return NULL;
-	}
-	do {
-		addr = mmap(NULL, (*size) + mem_size, PROT_READ,
-			MAP_PRIVATE, fd, 0);
-		if (addr == MAP_FAILED)
-			*size -= mem_size;
-	} while (addr == MAP_FAILED && *size > 0);
-
-	if (addr == MAP_FAILED) {
-		close(fd);
-		RTE_LOG(ERR, EAL, "Cannot get a virtual area\n");
-		return NULL;
-	}
-
-	munmap(addr, (*size) + mem_size);
-	close(fd);
-
-	/* align addr to a mem_size boundary */
-	aligned_addr = (uintptr_t)addr;
-	aligned_addr = RTE_ALIGN_CEIL(aligned_addr, mem_size);
-        addr = (void *)(aligned_addr);
-
-	RTE_LOG(DEBUG, EAL, "Virtual area found at %p (size = 0x%zx)\n",
-		addr, *size);
-
-	return addr;
-}
-
-/**
- * Get memory size configuration from /sys/devices/virtual/misc/dom0_mm
- * /memsize-mB/memsize file, and the size unit is mB.
- */
-static int
-get_xen_memory_size(void)
-{
-	char path[PATH_MAX];
-	unsigned long mem_size = 0;
-	static const char *file_name;
-
-	file_name = "memsize";
-	snprintf(path, sizeof(path), "%s/%s",
-			sys_dir_path, file_name);
-
-	if (eal_parse_sysfs_value(path, &mem_size) < 0)
-		return -1;
-
-	if (mem_size == 0)
-		rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s was not"
-			" configured.\n",sys_dir_path, file_name);
-	if (mem_size % 2)
-		rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s must be"
-			" even number.\n",sys_dir_path, file_name);
-
-	if (mem_size > DOM0_CONFIG_MEMSIZE)
-		rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s should not be larger"
-			" than %d mB\n",sys_dir_path, file_name, DOM0_CONFIG_MEMSIZE);
-
-	return mem_size;
-}
-
-/**
- * Based on physical address to caculate MFN in Xen Dom0.
- */
-phys_addr_t
-rte_xen_mem_phy2mch(int32_t memseg_id, const phys_addr_t phy_addr)
-{
-	int mfn_id, i;
-	uint64_t mfn, mfn_offset;
-	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
-	struct rte_memseg *memseg = mcfg->memseg;
-
-	/* find the memory segment owning the physical address */
-	if (memseg_id == -1) {
-		for (i = 0; i < RTE_MAX_MEMSEG; i++) {
-			if ((phy_addr >= memseg[i].phys_addr) &&
-					(phy_addr < memseg[i].phys_addr +
-						memseg[i].len)) {
-				memseg_id = i;
-				break;
-			}
-		}
-		if (memseg_id == -1)
-			return RTE_BAD_PHYS_ADDR;
-	}
-
-	mfn_id = (phy_addr - memseg[memseg_id].phys_addr) / RTE_PGSIZE_2M;
-
-	/*the MFN is contiguous in 2M */
-	mfn_offset = (phy_addr - memseg[memseg_id].phys_addr) %
-					RTE_PGSIZE_2M / PAGE_SIZE;
-	mfn = mfn_offset + memseg[memseg_id].mfn[mfn_id];
-
-	/** return mechine address */
-	return mfn * PAGE_SIZE + phy_addr % PAGE_SIZE;
-}
-
-int
-rte_xen_dom0_memory_init(void)
-{
-	void *vir_addr, *vma_addr = NULL;
-	int err, ret = 0;
-	uint32_t i, requested, mem_size, memseg_idx, num_memseg = 0;
-	size_t vma_len = 0;
-	struct memory_info meminfo;
-	struct memseg_info seginfo[RTE_MAX_MEMSEG];
-	int flags, page_size = getpagesize();
-	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
-	struct rte_memseg *memseg = mcfg->memseg;
-	uint64_t total_mem = internal_config.memory;
-
-	memset(seginfo, 0, sizeof(seginfo));
-	memset(&meminfo, 0, sizeof(struct memory_info));
-
-	mem_size = get_xen_memory_size();
-	requested = (unsigned) (total_mem / 0x100000);
-	if (requested > mem_size)
-		/* if we didn't satisfy total memory requirements */
-		rte_exit(EXIT_FAILURE,"Not enough memory available! Requested: %uMB,"
-				" available: %uMB\n", requested, mem_size);
-	else if (total_mem != 0)
-		mem_size = requested;
-
-	/* Check FD and open once */
-	if (xen_fd < 0) {
-		xen_fd = open(DOM0_MM_DEV, O_RDWR);
-		if (xen_fd < 0) {
-			RTE_LOG(ERR, EAL, "Can not open %s\n",DOM0_MM_DEV);
-			return -1;
-		}
-	}
-
-	meminfo.size = mem_size;
-
-	/* construct memory mangement name for Dom0 */
-	snprintf(meminfo.name, DOM0_NAME_MAX, "%s-%s",
-		internal_config.hugefile_prefix, DEFAUL_DOM0_NAME);
-
-	/* Notify kernel driver to allocate memory */
-	ret = ioctl(xen_fd, RTE_DOM0_IOCTL_PREPARE_MEMSEG, &meminfo);
-	if (ret < 0) {
-		RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memory\n");
-		err = -EIO;
-		goto fail;
-	}
-
-	/* Get number of memory segment from driver */
-	ret = ioctl(xen_fd, RTE_DOM0_IOCTL_GET_NUM_MEMSEG, &num_memseg);
-	if (ret < 0) {
-		RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memseg count.\n");
-		err = -EIO;
-		goto fail;
-	}
-
-	if(num_memseg > RTE_MAX_MEMSEG){
-		RTE_LOG(ERR, EAL, "XEN DOM0: the memseg count %d is greater"
-			" than max memseg %d.\n",num_memseg, RTE_MAX_MEMSEG);
-		err = -EIO;
-		goto fail;
-	}
-
-	/* get all memory segements information */
-	ret = ioctl(xen_fd, RTE_DOM0_IOCTL_GET_MEMSEG_INFO, seginfo);
-	if (ret < 0) {
-		RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memseg info.\n");
-		err = -EIO;
-		goto fail;
-	}
-
-	/* map all memory segments to contiguous user space */
-	for (memseg_idx = 0; memseg_idx < num_memseg; memseg_idx++)
-	{
-		vma_len = seginfo[memseg_idx].size;
-
-		/**
-		 * get the biggest virtual memory area up to vma_len. If it fails,
-		 * vma_addr is NULL, so let the kernel provide the address.
-		 */
-		vma_addr = xen_get_virtual_area(&vma_len, RTE_PGSIZE_2M);
-		if (vma_addr == NULL) {
-			flags = MAP_SHARED;
-			vma_len = RTE_PGSIZE_2M;
-		} else
-			flags = MAP_SHARED | MAP_FIXED;
-
-		seginfo[memseg_idx].size = vma_len;
-		vir_addr = mmap(vma_addr, seginfo[memseg_idx].size,
-			PROT_READ|PROT_WRITE, flags, xen_fd,
-			memseg_idx * page_size);
-		if (vir_addr == MAP_FAILED) {
-			RTE_LOG(ERR, EAL, "XEN DOM0:Could not mmap %s\n",
-				DOM0_MM_DEV);
-			err = -EIO;
-			goto fail;
-		}
-
-		memseg[memseg_idx].addr = vir_addr;
-		memseg[memseg_idx].phys_addr = page_size *
-			seginfo[memseg_idx].pfn ;
-		memseg[memseg_idx].len = seginfo[memseg_idx].size;
-		for ( i = 0; i < seginfo[memseg_idx].size / RTE_PGSIZE_2M; i++)
-			memseg[memseg_idx].mfn[i] = seginfo[memseg_idx].mfn[i];
-
-		/* MFNs are continuous in 2M, so assume that page size is 2M */
-		memseg[memseg_idx].hugepage_sz = RTE_PGSIZE_2M;
-
-		memseg[memseg_idx].nchannel = mcfg->nchannel;
-		memseg[memseg_idx].nrank = mcfg->nrank;
-
-		/* NUMA is not suppoted in Xen Dom0, so only set socket 0*/
-		memseg[memseg_idx].socket_id = 0;
-	}
-
-	return 0;
-fail:
-	if (xen_fd > 0) {
-		close(xen_fd);
-		xen_fd = -1;
-	}
-	return err;
-}
-
-/*
- * This creates the memory mappings in the secondary process to match that of
- * the server process. It goes through each memory segment in the DPDK runtime
- * configuration, mapping them in order to form a contiguous block in the
- * virtual memory space
- */
-int
-rte_xen_dom0_memory_attach(void)
-{
-	const struct rte_mem_config *mcfg;
-	unsigned s = 0; /* s used to track the segment number */
-	int xen_fd = -1;
-	int ret = -1;
-	void *vir_addr;
-	char name[DOM0_NAME_MAX] = {0};
-	int page_size = getpagesize();
-
-	mcfg = rte_eal_get_configuration()->mem_config;
-
-	/* Check FD and open once */
-	if (xen_fd < 0) {
-		xen_fd = open(DOM0_MM_DEV, O_RDWR);
-		if (xen_fd < 0) {
-			RTE_LOG(ERR, EAL, "Can not open %s\n",DOM0_MM_DEV);
-			goto error;
-		}
-	}
-
-	/* construct memory mangement name for Dom0 */
-	snprintf(name, DOM0_NAME_MAX, "%s-%s",
-		internal_config.hugefile_prefix, DEFAUL_DOM0_NAME);
-	/* attach to memory segments of primary process */
-	ret = ioctl(xen_fd, RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG, name);
-	if (ret) {
-		RTE_LOG(ERR, EAL,"attach memory segments fail.\n");
-		goto error;
-	}
-
-	/* map all segments into memory to make sure we get the addrs */
-	for (s = 0; s < RTE_MAX_MEMSEG; ++s) {
-
-		/*
-		 * the first memory segment with len==0 is the one that
-		 * follows the last valid segment.
-		 */
-		if (mcfg->memseg[s].len == 0)
-			break;
-
-		vir_addr = mmap(mcfg->memseg[s].addr, mcfg->memseg[s].len,
-				PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, xen_fd,
-				s * page_size);
-		if (vir_addr == MAP_FAILED) {
-			RTE_LOG(ERR, EAL, "Could not mmap %llu bytes "
-				"in %s to requested address [%p]\n",
-				(unsigned long long)mcfg->memseg[s].len, DOM0_MM_DEV,
-				mcfg->memseg[s].addr);
-			goto error;
-		}
-	}
-	return 0;
-
-error:
-	if (xen_fd >= 0) {
-		close(xen_fd);
-		xen_fd = -1;
-	}
-	return -1;
-}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_dom0_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_dom0_common.h
deleted file mode 100644
index d970778..0000000
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_dom0_common.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*-
- *   This file is provided under a dual BSD/LGPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GNU LESSER GENERAL PUBLIC LICENSE
- *
- *   Copyright(c) 2007-2014 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2.1 of the GNU Lesser General Public License
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *   Contact Information:
- *   Intel Corporation
- *
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *   * Neither the name of Intel Corporation nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _RTE_DOM0_COMMON_H_
-#define _RTE_DOM0_COMMON_H_
-
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
-
-#define DOM0_NAME_MAX   256
-#define DOM0_MM_DEV   "/dev/dom0_mm"
-
-#define DOM0_CONTIG_NUM_ORDER       9       /**< order of 2M */
-#define DOM0_NUM_MEMSEG             512     /**< Maximum nb. of memory segment. */
-#define DOM0_MEMBLOCK_SIZE          0x200000 /**< size of memory block(2M). */
-#define DOM0_CONFIG_MEMSIZE         4096     /**< Maximum config memory size(4G). */
-#define DOM0_NUM_MEMBLOCK (DOM0_CONFIG_MEMSIZE / 2) /**< Maximum nb. of 2M memory block. */
-
-#define RTE_DOM0_IOCTL_PREPARE_MEMSEG    _IOWR(0, 1 , struct memory_info)
-#define RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG  _IOWR(0, 2 , char *)
-#define RTE_DOM0_IOCTL_GET_NUM_MEMSEG    _IOWR(0, 3, int)
-#define RTE_DOM0_IOCTL_GET_MEMSEG_INFO   _IOWR(0, 4, void *)
-
-/**
- * A structure used to store memory information.
- */
-struct memory_info {
-	char name[DOM0_NAME_MAX];
-	uint64_t size;
-};
-
-/**
- * A structure used to store memory segment information.
- */
-struct memseg_info {
-	uint32_t idx;
-	uint64_t pfn;
-	uint64_t size;
-	uint64_t mfn[DOM0_NUM_MEMBLOCK];
-};
-
-/**
- * A structure used to store memory block information.
- */
-struct memblock_info {
-	uint8_t exchange_flag;
-	uint8_t used;
-	uint64_t vir_addr;
-	uint64_t pfn;
-	uint64_t mfn;
-};
-#endif /* _RTE_DOM0_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
index 07a19a3..3d5c2f3 100644
--- a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
+++ b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
@@ -33,9 +33,6 @@
 #include <linux/version.h>
 #include <linux/slab.h>
 
-#ifdef CONFIG_XEN_DOM0
-#include <xen/xen.h>
-#endif
 #include <rte_pci_dev_features.h>
 
 #include "compat.h"
@@ -201,52 +198,6 @@ igbuio_pci_release(struct uio_info *info, struct inode *inode)
 	return 0;
 }
 
-#ifdef CONFIG_XEN_DOM0
-static int
-igbuio_dom0_mmap_phys(struct uio_info *info, struct vm_area_struct *vma)
-{
-	int idx;
-
-	idx = (int)vma->vm_pgoff;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#ifdef HAVE_PTE_MASK_PAGE_IOMAP
-	vma->vm_page_prot.pgprot |= _PAGE_IOMAP;
-#endif
-
-	return remap_pfn_range(vma,
-			vma->vm_start,
-			info->mem[idx].addr >> PAGE_SHIFT,
-			vma->vm_end - vma->vm_start,
-			vma->vm_page_prot);
-}
-
-/**
- * This is uio device mmap method which will use igbuio mmap for Xen
- * Dom0 environment.
- */
-static int
-igbuio_dom0_pci_mmap(struct uio_info *info, struct vm_area_struct *vma)
-{
-	int idx;
-
-	if (vma->vm_pgoff >= MAX_UIO_MAPS)
-		return -EINVAL;
-
-	if (info->mem[vma->vm_pgoff].size == 0)
-		return -EINVAL;
-
-	idx = (int)vma->vm_pgoff;
-	switch (info->mem[idx].memtype) {
-	case UIO_MEM_PHYS:
-		return igbuio_dom0_mmap_phys(info, vma);
-	case UIO_MEM_LOGICAL:
-	case UIO_MEM_VIRTUAL:
-	default:
-		return -EINVAL;
-	}
-}
-#endif
-
 /* Remap pci resources described by bar #pci_bar in uio resource n. */
 static int
 igbuio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info,
@@ -405,11 +356,6 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	udev->info.irqcontrol = igbuio_pci_irqcontrol;
 	udev->info.open = igbuio_pci_open;
 	udev->info.release = igbuio_pci_release;
-#ifdef CONFIG_XEN_DOM0
-	/* check if the driver run on Xen Dom0 */
-	if (xen_initial_domain())
-		udev->info.mmap = igbuio_dom0_pci_mmap;
-#endif
 	udev->info.priv = udev;
 	udev->pdev = dev;
 
diff --git a/lib/librte_eal/linuxapp/xen_dom0/Makefile b/lib/librte_eal/linuxapp/xen_dom0/Makefile
deleted file mode 100644
index be51a82..0000000
--- a/lib/librte_eal/linuxapp/xen_dom0/Makefile
+++ /dev/null
@@ -1,53 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
-#   All rights reserved.
-#
-#   Redistribution and use in source and binary forms, with or without
-#   modification, are permitted provided that the following conditions
-#   are met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in
-#       the documentation and/or other materials provided with the
-#       distribution.
-#     * Neither the name of Intel Corporation nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-#
-# module name and path
-#
-MODULE = rte_dom0_mm
-
-#
-# CFLAGS
-#
-MODULE_CFLAGS += -I$(SRCDIR) --param max-inline-insns-single=50
-MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
-MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
-MODULE_CFLAGS += -Wall -Werror
-
-#
-# all source are stored in SRCS-y
-#
-
-SRCS-y += dom0_mm_misc.c
-
-include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/xen_dom0/compat.h b/lib/librte_eal/linuxapp/xen_dom0/compat.h
deleted file mode 100644
index e6eb97f..0000000
--- a/lib/librte_eal/linuxapp/xen_dom0/compat.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Minimal wrappers to allow compiling xen_dom0 on older kernels.
- */
-
-#ifndef RHEL_RELEASE_VERSION
-#define RHEL_RELEASE_VERSION(a, b) (((a) << 8) + (b))
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
-	(!(defined(RHEL_RELEASE_CODE) && \
-	 RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 4)))
-
-#define kstrtoul strict_strtoul
-
-#endif /* < 2.6.39 */
diff --git a/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_dev.h b/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_dev.h
deleted file mode 100644
index 9d5ffb2..0000000
--- a/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_dev.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *   The full GNU General Public License is included in this distribution
- *   in the file called LICENSE.GPL.
- *
- *   Contact Information:
- *   Intel Corporation
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-#ifndef _DOM0_MM_DEV_H_
-#define _DOM0_MM_DEV_H_
-
-#include <linux/wait.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <exec-env/rte_dom0_common.h>
-
-#define NUM_MEM_CTX     256  /**< Maximum number of memory context*/
-#define MAX_EXCHANGE_FAIL_TIME 5  /**< Maximum times of allowing exchange fail .*/
-#define MAX_MEMBLOCK_SIZE (2 * DOM0_MEMBLOCK_SIZE)
-#define MAX_NUM_ORDER     (DOM0_CONTIG_NUM_ORDER + 1)
-#define SIZE_PER_BLOCK    2       /**< Size of memory block (2MB).*/
-
-/**
- * A structure describing the private information for a dom0 device.
- */
-struct dom0_mm_dev {
-	struct miscdevice miscdev;
-	uint8_t fail_times;
-	uint32_t used_memsize;
-	uint32_t num_mem_ctx;
-	uint32_t config_memsize;
-	uint32_t num_bigblock;
-	struct  dom0_mm_data *mm_data[NUM_MEM_CTX];
-	struct mutex data_lock;
-};
-
-struct dom0_mm_data{
-	uint32_t refcnt;
-	uint32_t num_memseg; /**< Number of memory segment. */
-	uint32_t mem_size;   /**< Size of requesting memory. */
-
-	char name[DOM0_NAME_MAX];
-
-	/** Store global memory block IDs used by an instance */
-	uint32_t block_num[DOM0_NUM_MEMBLOCK];
-
-	/** Store memory block information.*/
-	struct memblock_info block_info[DOM0_NUM_MEMBLOCK];
-
-	/** Store memory segment information.*/
-	struct memseg_info  seg_info[DOM0_NUM_MEMSEG];
-};
-
-#define XEN_ERR(args...) printk(KERN_DEBUG "XEN_DOM0: Error: " args)
-#define XEN_PRINT(args...) printk(KERN_DEBUG "XEN_DOM0: " args)
-#endif
diff --git a/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_misc.c b/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_misc.c
deleted file mode 100644
index 79630ba..0000000
--- a/lib/librte_eal/linuxapp/xen_dom0/dom0_mm_misc.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/*-
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *   The full GNU General Public License is included in this distribution
- *   in the file called LICENSE.GPL.
- *
- *   Contact Information:
- *   Intel Corporation
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/version.h>
-
-#include <xen/xen.h>
-#include <xen/page.h>
-#include <xen/xen-ops.h>
-#include <xen/interface/memory.h>
-
-#include <exec-env/rte_dom0_common.h>
-
-#include "compat.h"
-#include "dom0_mm_dev.h"
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Kernel Module for supporting DPDK running on Xen Dom0");
-
-static struct dom0_mm_dev dom0_dev;
-static struct kobject *dom0_kobj = NULL;
-
-static struct memblock_info *rsv_mm_info;
-
-/* Default configuration for reserved memory size(2048 MB). */
-static uint32_t rsv_memsize = 2048;
-
-static int dom0_open(struct inode *inode, struct file *file);
-static int dom0_release(struct inode *inode, struct file *file);
-static int dom0_ioctl(struct file *file, unsigned int ioctl_num,
-		unsigned long ioctl_param);
-static int dom0_mmap(struct file *file, struct vm_area_struct *vma);
-static int dom0_memory_free(uint32_t size);
-static int dom0_memory_release(struct dom0_mm_data *mm_data);
-
-static const struct file_operations data_fops = {
-	.owner = THIS_MODULE,
-	.open = dom0_open,
-	.release = dom0_release,
-	.mmap = dom0_mmap,
-	.unlocked_ioctl = (void *)dom0_ioctl,
-};
-
-static ssize_t
-show_memsize_rsvd(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, 10, "%u\n", dom0_dev.used_memsize);
-}
-
-static ssize_t
-show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, 10, "%u\n", dom0_dev.config_memsize);
-}
-
-static ssize_t
-store_memsize(struct device *dev, struct device_attribute *attr,
-            const char *buf, size_t count)
-{
-	int err = 0;
-	unsigned long mem_size;
-
-	if (0 != kstrtoul(buf, 0, &mem_size))
-		return  -EINVAL;
-
-	mutex_lock(&dom0_dev.data_lock);
-	if (0 == mem_size) {
-		err = -EINVAL;
-		goto fail;
-	} else if (mem_size > (rsv_memsize - dom0_dev.used_memsize)) {
-		XEN_ERR("configure memory size fail\n");
-		err = -EINVAL;
-		goto fail;
-	} else
-		dom0_dev.config_memsize = mem_size;
-
-fail:
-	mutex_unlock(&dom0_dev.data_lock);
-	return err ? err : count;
-}
-
-static DEVICE_ATTR(memsize, S_IRUGO | S_IWUSR, show_memsize, store_memsize);
-static DEVICE_ATTR(memsize_rsvd, S_IRUGO, show_memsize_rsvd, NULL);
-
-static struct attribute *dev_attrs[] = {
-	&dev_attr_memsize.attr,
-	&dev_attr_memsize_rsvd.attr,
-	NULL,
-};
-
-/* the memory size unit is MB */
-static const struct attribute_group dev_attr_grp = {
-	.name = "memsize-mB",
-	.attrs = dev_attrs,
-};
-
-
-static void
-sort_viraddr(struct memblock_info *mb, int cnt)
-{
-	int i,j;
-	uint64_t tmp_pfn;
-	uint64_t tmp_viraddr;
-
-	/*sort virtual address and pfn */
-	for(i = 0; i < cnt; i ++) {
-		for(j = cnt - 1; j > i; j--) {
-			if(mb[j].pfn < mb[j - 1].pfn) {
-				tmp_pfn = mb[j - 1].pfn;
-				mb[j - 1].pfn = mb[j].pfn;
-				mb[j].pfn = tmp_pfn;
-
-				tmp_viraddr = mb[j - 1].vir_addr;
-				mb[j - 1].vir_addr = mb[j].vir_addr;
-				mb[j].vir_addr = tmp_viraddr;
-			}
-		}
-	}
-}
-
-static int
-dom0_find_memdata(const char * mem_name)
-{
-	unsigned i;
-	int idx = -1;
-	for(i = 0; i< NUM_MEM_CTX; i++) {
-		if(dom0_dev.mm_data[i] == NULL)
-			continue;
-		if (!strncmp(dom0_dev.mm_data[i]->name, mem_name,
-			sizeof(char) * DOM0_NAME_MAX)) {
-			idx = i;
-			break;
-		}
-	}
-
-	return idx;
-}
-
-static int
-dom0_find_mempos(void)
-{
-	unsigned i;
-	int idx = -1;
-
-	for(i = 0; i< NUM_MEM_CTX; i++) {
-		if(dom0_dev.mm_data[i] == NULL){
-			idx = i;
-			break;
-		}
-	}
-
-	return idx;
-}
-
-static int
-dom0_memory_release(struct dom0_mm_data *mm_data)
-{
-	int idx;
-	uint32_t  num_block, block_id;
-
-	/* each memory block is 2M */
-	num_block = mm_data->mem_size / SIZE_PER_BLOCK;
-	if (num_block == 0)
-		return -EINVAL;
-
-	/* reset global memory data */
-	idx = dom0_find_memdata(mm_data->name);
-	if (idx >= 0) {
-		dom0_dev.used_memsize -= mm_data->mem_size;
-		dom0_dev.mm_data[idx] = NULL;
-		dom0_dev.num_mem_ctx--;
-	}
-
-	/* reset these memory blocks status as free */
-	for (idx = 0; idx < num_block; idx++) {
-		block_id = mm_data->block_num[idx];
-		rsv_mm_info[block_id].used = 0;
-	}
-
-	memset(mm_data, 0, sizeof(struct dom0_mm_data));
-	vfree(mm_data);
-	return 0;
-}
-
-static int
-dom0_memory_free(uint32_t rsv_size)
-{
-	uint64_t vstart, vaddr;
-	uint32_t i, num_block, size;
-
-	if (!xen_pv_domain())
-		return -1;
-
-	/* each memory block is 2M */
-	num_block = rsv_size / SIZE_PER_BLOCK;
-	if (num_block == 0)
-		return -EINVAL;
-
-	/* free all memory blocks of size of 4M and destroy contiguous region */
-	for (i = 0; i < dom0_dev.num_bigblock * 2; i += 2) {
-		vstart = rsv_mm_info[i].vir_addr;
-		if (vstart) {
-		#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
-			if (rsv_mm_info[i].exchange_flag)
-				xen_destroy_contiguous_region(vstart,
-						DOM0_CONTIG_NUM_ORDER);
-			if (rsv_mm_info[i + 1].exchange_flag)
-				xen_destroy_contiguous_region(vstart +
-						DOM0_MEMBLOCK_SIZE,
-						DOM0_CONTIG_NUM_ORDER);
-		#else
-			if (rsv_mm_info[i].exchange_flag)
-				xen_destroy_contiguous_region(rsv_mm_info[i].pfn
-					* PAGE_SIZE,
-					DOM0_CONTIG_NUM_ORDER);
-			if (rsv_mm_info[i + 1].exchange_flag)
-				xen_destroy_contiguous_region(rsv_mm_info[i].pfn
-					* PAGE_SIZE + DOM0_MEMBLOCK_SIZE,
-					DOM0_CONTIG_NUM_ORDER);
-		#endif
-
-			size = DOM0_MEMBLOCK_SIZE * 2;
-			vaddr = vstart;
-			while (size > 0) {
-				ClearPageReserved(virt_to_page(vaddr));
-				vaddr += PAGE_SIZE;
-				size -= PAGE_SIZE;
-			}
-			free_pages(vstart, MAX_NUM_ORDER);
-		}
-	}
-
-	/* free all memory blocks size of 2M and destroy contiguous region */
-	for (; i < num_block; i++) {
-		vstart = rsv_mm_info[i].vir_addr;
-		if (vstart) {
-			if (rsv_mm_info[i].exchange_flag)
-				xen_destroy_contiguous_region(vstart,
-					DOM0_CONTIG_NUM_ORDER);
-
-			size = DOM0_MEMBLOCK_SIZE;
-			vaddr = vstart;
-			while (size > 0) {
-				ClearPageReserved(virt_to_page(vaddr));
-				vaddr += PAGE_SIZE;
-				size -= PAGE_SIZE;
-			}
-			free_pages(vstart, DOM0_CONTIG_NUM_ORDER);
-		}
-	}
-
-	memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
-	vfree(rsv_mm_info);
-	rsv_mm_info = NULL;
-
-	return 0;
-}
-
-static void
-find_free_memory(uint32_t count, struct dom0_mm_data *mm_data)
-{
-	uint32_t i = 0;
-	uint32_t j = 0;
-
-	while ((i < count) && (j < rsv_memsize / SIZE_PER_BLOCK)) {
-		if (rsv_mm_info[j].used == 0) {
-			mm_data->block_info[i].pfn = rsv_mm_info[j].pfn;
-			mm_data->block_info[i].vir_addr =
-				rsv_mm_info[j].vir_addr;
-			mm_data->block_info[i].mfn = rsv_mm_info[j].mfn;
-			mm_data->block_info[i].exchange_flag =
-				rsv_mm_info[j].exchange_flag;
-			mm_data->block_num[i] = j;
-			rsv_mm_info[j].used = 1;
-			i++;
-		}
-		j++;
-	}
-}
-
-/**
- * Find all memory segments in which physical addresses are contiguous.
- */
-static void
-find_memseg(int count, struct dom0_mm_data * mm_data)
-{
-	int i = 0;
-	int j, k, idx = 0;
-	uint64_t zone_len, pfn, num_block;
-
-	while(i < count) {
-		if (mm_data->block_info[i].exchange_flag == 0) {
-			i++;
-			continue;
-		}
-		k = 0;
-		pfn = mm_data->block_info[i].pfn;
-		mm_data->seg_info[idx].pfn = pfn;
-		mm_data->seg_info[idx].mfn[k] = mm_data->block_info[i].mfn;
-
-		for (j = i + 1; j < count; j++) {
-
-			/* ignore exchange fail memory block */
-			if (mm_data->block_info[j].exchange_flag == 0)
-				break;
-
-			if (mm_data->block_info[j].pfn !=
-				(mm_data->block_info[j - 1].pfn +
-					 DOM0_MEMBLOCK_SIZE / PAGE_SIZE))
-			    break;
-			++k;
-			mm_data->seg_info[idx].mfn[k] = mm_data->block_info[j].mfn;
-		}
-
-		num_block = j - i;
-		zone_len = num_block * DOM0_MEMBLOCK_SIZE;
-		mm_data->seg_info[idx].size = zone_len;
-
-		XEN_PRINT("memseg id=%d, size=0x%llx\n", idx, zone_len);
-		i = i+ num_block;
-		idx++;
-		if (idx == DOM0_NUM_MEMSEG)
-			break;
-	}
-	mm_data->num_memseg = idx;
-}
-
-static int
-dom0_memory_reserve(uint32_t rsv_size)
-{
-	uint64_t pfn, vstart, vaddr;
-	uint32_t i, num_block, size, allocated_size = 0;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
-	dma_addr_t dma_handle;
-#endif
-
-	/* 2M as memory block */
-	num_block = rsv_size / SIZE_PER_BLOCK;
-
-	rsv_mm_info = vmalloc(sizeof(struct memblock_info) * num_block);
-	if (!rsv_mm_info) {
-		XEN_ERR("Unable to allocate device memory information\n");
-		return -ENOMEM;
-	}
-	memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
-
-	/* try alloc size of 4M once */
-	for (i = 0; i < num_block; i += 2) {
-		vstart = (unsigned long)
-			__get_free_pages(GFP_ATOMIC, MAX_NUM_ORDER);
-		if (vstart == 0)
-			break;
-
-		dom0_dev.num_bigblock = i / 2 + 1;
-		allocated_size =  SIZE_PER_BLOCK * (i + 2);
-
-		/* size of 4M */
-		size = DOM0_MEMBLOCK_SIZE * 2;
-
-		vaddr = vstart;
-		while (size > 0) {
-			SetPageReserved(virt_to_page(vaddr));
-			vaddr += PAGE_SIZE;
-			size -= PAGE_SIZE;
-		}
-
-		pfn = virt_to_pfn(vstart);
-		rsv_mm_info[i].pfn = pfn;
-		rsv_mm_info[i].vir_addr = vstart;
-		rsv_mm_info[i + 1].pfn =
-				pfn + DOM0_MEMBLOCK_SIZE / PAGE_SIZE;
-		rsv_mm_info[i + 1].vir_addr =
-				vstart + DOM0_MEMBLOCK_SIZE;
-	}
-
-	/*if it failed to alloc 4M, and continue to alloc 2M once */
-	for (; i < num_block; i++) {
-		vstart = (unsigned long)
-			__get_free_pages(GFP_ATOMIC, DOM0_CONTIG_NUM_ORDER);
-		if (vstart == 0) {
-			XEN_ERR("allocate memory fail.\n");
-			dom0_memory_free(allocated_size);
-			return -ENOMEM;
-		}
-
-		allocated_size += SIZE_PER_BLOCK;
-
-		size = DOM0_MEMBLOCK_SIZE;
-		vaddr = vstart;
-		while (size > 0) {
-			SetPageReserved(virt_to_page(vaddr));
-			vaddr += PAGE_SIZE;
-			size -= PAGE_SIZE;
-		}
-		pfn = virt_to_pfn(vstart);
-		rsv_mm_info[i].pfn = pfn;
-		rsv_mm_info[i].vir_addr = vstart;
-	}
-
-	sort_viraddr(rsv_mm_info, num_block);
-
-	for (i = 0; i< num_block; i++) {
-
-		/*
-		 * This API is used to exchage MFN for getting a block of
-		 * contiguous physical addresses, its maximum size is 2M.
-		 */
-	#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
-		if (xen_create_contiguous_region(rsv_mm_info[i].vir_addr,
-				DOM0_CONTIG_NUM_ORDER, 0) == 0) {
-	#else
-		if (xen_create_contiguous_region(rsv_mm_info[i].pfn * PAGE_SIZE,
-				DOM0_CONTIG_NUM_ORDER, 0, &dma_handle) == 0) {
-	#endif
-			rsv_mm_info[i].exchange_flag = 1;
-			rsv_mm_info[i].mfn =
-				pfn_to_mfn(rsv_mm_info[i].pfn);
-			rsv_mm_info[i].used = 0;
-		} else {
-			XEN_ERR("exchange memeory fail\n");
-			rsv_mm_info[i].exchange_flag = 0;
-			dom0_dev.fail_times++;
-			if (dom0_dev.fail_times > MAX_EXCHANGE_FAIL_TIME) {
-				dom0_memory_free(rsv_size);
-				return  -EFAULT;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int
-dom0_prepare_memsegs(struct memory_info *meminfo, struct dom0_mm_data *mm_data)
-{
-	uint32_t num_block;
-	int idx;
-
-	/* check if there is a free name buffer */
-	memcpy(mm_data->name, meminfo->name, DOM0_NAME_MAX);
-	mm_data->name[DOM0_NAME_MAX - 1] = '\0';
-	idx = dom0_find_mempos();
-	if (idx < 0)
-		return -1;
-
-	num_block = meminfo->size / SIZE_PER_BLOCK;
-	/* find free memory and new memory segments*/
-	find_free_memory(num_block, mm_data);
-	find_memseg(num_block, mm_data);
-
-	/* update private memory data */
-	mm_data->refcnt++;
-	mm_data->mem_size = meminfo->size;
-
-	/* update global memory data */
-	dom0_dev.mm_data[idx] = mm_data;
-	dom0_dev.num_mem_ctx++;
-	dom0_dev.used_memsize += mm_data->mem_size;
-
-	return 0;
-}
-
-static int
-dom0_check_memory (struct memory_info *meminfo)
-{
-	int idx;
-	uint64_t mem_size;
-
-	/* round memory size to the next even number. */
-	if (meminfo->size % 2)
-		++meminfo->size;
-
-	mem_size = meminfo->size;
-	if (dom0_dev.num_mem_ctx > NUM_MEM_CTX) {
-		XEN_ERR("Memory data space is full in Dom0 driver\n");
-		return -1;
-	}
-	idx = dom0_find_memdata(meminfo->name);
-	if (idx >= 0) {
-		XEN_ERR("Memory data name %s has already exsited in Dom0 driver.\n",
-			meminfo->name);
-		return -1;
-	}
-	if ((dom0_dev.used_memsize + mem_size) > rsv_memsize) {
-		XEN_ERR("Total size can't be larger than reserved size.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int __init
-dom0_init(void)
-{
-	if (!xen_domain())
-		return -ENODEV;
-
-	if (rsv_memsize > DOM0_CONFIG_MEMSIZE) {
-		XEN_ERR("The reserved memory size cannot be greater than %d\n",
-			DOM0_CONFIG_MEMSIZE);
-		return -EINVAL;
-	}
-
-	/* Setup the misc device */
-	dom0_dev.miscdev.minor = MISC_DYNAMIC_MINOR;
-	dom0_dev.miscdev.name = "dom0_mm";
-	dom0_dev.miscdev.fops = &data_fops;
-
-	/* register misc char device */
-	if (misc_register(&dom0_dev.miscdev) != 0) {
-		XEN_ERR("Misc device registration failed\n");
-		return -EPERM;
-	}
-
-	mutex_init(&dom0_dev.data_lock);
-	dom0_kobj = kobject_create_and_add("dom0-mm", mm_kobj);
-
-	if (!dom0_kobj) {
-		XEN_ERR("dom0-mm object creation failed\n");
-		misc_deregister(&dom0_dev.miscdev);
-		return -ENOMEM;
-	}
-
-	if (sysfs_create_group(dom0_kobj, &dev_attr_grp)) {
-		kobject_put(dom0_kobj);
-		misc_deregister(&dom0_dev.miscdev);
-		return -EPERM;
-	}
-
-	if (dom0_memory_reserve(rsv_memsize) < 0) {
-		sysfs_remove_group(dom0_kobj, &dev_attr_grp);
-		kobject_put(dom0_kobj);
-		misc_deregister(&dom0_dev.miscdev);
-		return -ENOMEM;
-	}
-
-	XEN_PRINT("####### DPDK Xen Dom0 module loaded  #######\n");
-
-	return 0;
-}
-
-static void __exit
-dom0_exit(void)
-{
-	if (rsv_mm_info != NULL)
-		dom0_memory_free(rsv_memsize);
-
-	sysfs_remove_group(dom0_kobj, &dev_attr_grp);
-	kobject_put(dom0_kobj);
-	misc_deregister(&dom0_dev.miscdev);
-
-	XEN_PRINT("####### DPDK Xen Dom0 module unloaded  #######\n");
-}
-
-static int
-dom0_open(struct inode *inode, struct file *file)
-{
-	file->private_data = NULL;
-
-	XEN_PRINT(KERN_INFO "/dev/dom0_mm opened\n");
-	return 0;
-}
-
-static int
-dom0_release(struct inode *inode, struct file *file)
-{
-	int ret = 0;
-	struct dom0_mm_data *mm_data = file->private_data;
-
-	if (mm_data == NULL)
-		return ret;
-
-	mutex_lock(&dom0_dev.data_lock);
-	if (--mm_data->refcnt == 0)
-		ret = dom0_memory_release(mm_data);
-	mutex_unlock(&dom0_dev.data_lock);
-
-	file->private_data = NULL;
-	XEN_PRINT(KERN_INFO "/dev/dom0_mm closed\n");
-	return ret;
-}
-
-static int
-dom0_mmap(struct file *file, struct vm_area_struct *vm)
-{
-	int status = 0;
-	uint32_t idx = vm->vm_pgoff;
-	uint64_t pfn, size = vm->vm_end - vm->vm_start;
-	struct dom0_mm_data *mm_data = file->private_data;
-
-	if(mm_data == NULL)
-		return -EINVAL;
-
-	mutex_lock(&dom0_dev.data_lock);
-	if (idx >= mm_data->num_memseg) {
-		mutex_unlock(&dom0_dev.data_lock);
-		return -EINVAL;
-	}
-
-	if (size > mm_data->seg_info[idx].size){
-		mutex_unlock(&dom0_dev.data_lock);
-		return -EINVAL;
-	}
-
-	XEN_PRINT("mmap memseg idx =%d,size = 0x%llx\n", idx, size);
-
-	pfn = mm_data->seg_info[idx].pfn;
-	mutex_unlock(&dom0_dev.data_lock);
-
-	status = remap_pfn_range(vm, vm->vm_start, pfn, size, PAGE_SHARED);
-
-	return status;
-}
-static int
-dom0_ioctl(struct file *file,
-	unsigned int ioctl_num,
-	unsigned long ioctl_param)
-{
-	int idx, ret;
-	char name[DOM0_NAME_MAX] = {0};
-	struct memory_info meminfo;
-	struct dom0_mm_data *mm_data = file->private_data;
-
-	XEN_PRINT("IOCTL num=0x%0x param=0x%0lx \n", ioctl_num, ioctl_param);
-
-	/**
-	 * Switch according to the ioctl called
-	 */
-	switch _IOC_NR(ioctl_num) {
-	case _IOC_NR(RTE_DOM0_IOCTL_PREPARE_MEMSEG):
-		ret = copy_from_user(&meminfo, (void *)ioctl_param,
-			sizeof(struct memory_info));
-		if (ret)
-			return  -EFAULT;
-
-		if (mm_data != NULL) {
-			XEN_ERR("Cannot create memory segment for the same"
-				" file descriptor\n");
-			return -EINVAL;
-		}
-
-		/* Allocate private data */
-		mm_data = vmalloc(sizeof(struct dom0_mm_data));
-		if (!mm_data) {
-			XEN_ERR("Unable to allocate device private data\n");
-			return -ENOMEM;
-		}
-		memset(mm_data, 0, sizeof(struct dom0_mm_data));
-
-		mutex_lock(&dom0_dev.data_lock);
-		/* check if we can allocate memory*/
-		if (dom0_check_memory(&meminfo) < 0) {
-			mutex_unlock(&dom0_dev.data_lock);
-			vfree(mm_data);
-			return -EINVAL;
-		}
-
-		/* allocate memory and created memory segments*/
-		if (dom0_prepare_memsegs(&meminfo, mm_data) < 0) {
-			XEN_ERR("create memory segment fail.\n");
-			mutex_unlock(&dom0_dev.data_lock);
-			return -EIO;
-		}
-
-		file->private_data = mm_data;
-		mutex_unlock(&dom0_dev.data_lock);
-		break;
-
-	/* support multiple process in term of memory mapping*/
-	case _IOC_NR(RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG):
-		ret = copy_from_user(name, (void *)ioctl_param,
-				sizeof(char) * DOM0_NAME_MAX);
-		if (ret)
-			return -EFAULT;
-
-		mutex_lock(&dom0_dev.data_lock);
-		idx = dom0_find_memdata(name);
-		if (idx < 0) {
-			mutex_unlock(&dom0_dev.data_lock);
-			return -EINVAL;
-		}
-
-		mm_data = dom0_dev.mm_data[idx];
-		mm_data->refcnt++;
-		file->private_data = mm_data;
-		mutex_unlock(&dom0_dev.data_lock);
-		break;
-
-	case _IOC_NR(RTE_DOM0_IOCTL_GET_NUM_MEMSEG):
-		ret = copy_to_user((void *)ioctl_param, &mm_data->num_memseg,
-				sizeof(int));
-		if (ret)
-			return -EFAULT;
-		break;
-
-	case _IOC_NR(RTE_DOM0_IOCTL_GET_MEMSEG_INFO):
-		ret = copy_to_user((void *)ioctl_param,
-				&mm_data->seg_info[0],
-				sizeof(struct memseg_info) *
-				mm_data->num_memseg);
-		if (ret)
-			return -EFAULT;
-		break;
-	default:
-		XEN_PRINT("IOCTL default \n");
-		break;
-	}
-
-	return 0;
-}
-
-module_init(dom0_init);
-module_exit(dom0_exit);
-
-module_param(rsv_memsize, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(rsv_memsize, "Xen-dom0 reserved memory size(MB).\n");
diff --git a/pkg/dpdk.spec b/pkg/dpdk.spec
index 95c3335..fd1b5ef 100644
--- a/pkg/dpdk.spec
+++ b/pkg/dpdk.spec
@@ -52,9 +52,6 @@ ExclusiveArch: i686 x86_64 aarch64
 %endif
 
 BuildRequires: kernel-devel, kernel-headers, libpcap-devel
-%ifarch i686 x86_64
-BuildRequires: xen-devel
-%endif
 BuildRequires: doxygen, python-sphinx, inkscape
 BuildRequires: texlive-collection-latexextra
 
-- 
2.7.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH] devtools: rework abi checker script
@ 2017-08-30 13:51 27% Olivier Matz
  0 siblings, 0 replies; 200+ results
From: Olivier Matz @ 2017-08-30 13:51 UTC (permalink / raw)
  To: dev, nhorman

The intiatial version of the script had some limitations:
- cannot work on a non-clean workspace
- environment variables are not documented
- no compilation log in case of failure
- return success even it abi is incompatible

This patch addresses these issues and rework the code.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 devtools/validate-abi.sh | 387 ++++++++++++++++++++++++-----------------------
 1 file changed, 195 insertions(+), 192 deletions(-)

diff --git a/devtools/validate-abi.sh b/devtools/validate-abi.sh
index 0accc99b1..5efcccc90 100755
--- a/devtools/validate-abi.sh
+++ b/devtools/validate-abi.sh
@@ -1,7 +1,8 @@
-#!/bin/sh
+#!/bin/bash -e
 #   BSD LICENSE
 #
 #   Copyright(c) 2015 Neil Horman. All rights reserved.
+#   Copyright(c) 2017 6WIND S.A.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -27,236 +28,238 @@
 #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-TAG1=$1
-TAG2=$2
-TARGET=$3
-ABI_DIR=`mktemp -d -p /tmp ABI.XXXXXX`
+abicheck=abi-compliance-checker
+abidump=abi-dumper
+default_dst=abi-check
+default_target=x86_64-native-linuxapp-gcc
 
-usage() {
-	echo "$0 <REV1> <REV2> <TARGET>"
+# trap on error
+err_report() {
+    echo "$0: error at line $1"
 }
+trap 'err_report $LINENO' ERR
 
-log() {
-	local level=$1
-	shift
-	echo "$*"
-}
+print_usage () {
+	cat <<- END_OF_HELP
+	$(basename $0) [options] <rev1> <rev2>
 
-validate_tags() {
+	This script compares the ABI of 2 git revisions of the current
+	workspace. The output is a html report and a compilation log.
 
-	if [ -z "$HASH1" ]
-	then
-		echo "invalid revision: $TAG1"
-		return
-	fi
-	if [ -z "$HASH2" ]
-	then
-		echo "invalid revision: $TAG2"
-		return
-	fi
+	The objective is to make sure that applications built against
+	DSOs from the first revision can still run when executed using
+	the DSOs built from the second revision.
+
+	<rev1> and <rev2> are git commit id or tags.
+
+	Options:
+	  -h		show this help
+	  -j <num>	enable parallel compilation with <num> threads
+	  -v		show compilation logs on the console
+	  -d <dir>	change working directory (default is ${default_dst})
+	  -t <target>	the dpdk target to use (default is ${default_target})
+	  -f		override existing destination directory
+
+	The script returns 0 on success, or the value of last failing
+	call of ${abicheck} (incompatible abi or the tool has run with errors).
+	The errors returned by ${abidump} are ignored.
+
+	END_OF_HELP
 }
 
-validate_args() {
-	if [ -z "$TAG1" ]
-	then
-		echo "Must Specify REV1"
-		return
-	fi
-	if [ -z "$TAG2" ]
-	then
-		echo "Must Specify REV2"
-		return
-	fi
-	if [ -z "$TARGET" ]
-	then
-		echo "Must Specify a build target"
+# log in the file, and on stdout if verbose
+# $1: level string
+# $2: string to be logged
+log() {
+	echo "$1: $2"
+	if [ "${verbose}" != "true" ]; then
+		echo "$1: $2" >&3
 	fi
 }
 
+# launch a command and log it, taking care of surrounding spaces with quotes
+cmd() {
+	local i s whitespace
+	s=""
+	whitespace="[[:space:]]"
+	for i in "$@"; do
+		if [[ $i =~ $whitespace ]]; then
+			i=\"$i\"
+		fi
+		if [ -z "$s" ]; then
+			s="$i"
+		else
+			s="$s $i"
+		fi
+	done
+
+	log "CMD" "$s"
+	"$@"
+}
 
-cleanup_and_exit() {
-	rm -rf $ABI_DIR
-	git checkout $CURRENT_BRANCH
-	exit $1
+# redirect or copy stderr/stdout to a file
+# the syntax is unfamiliar, but it makes the rest of the
+# code easier to read, avoiding the use of pipes
+set_log_file() {
+	# save original stdout and stderr in fd 3 and 4
+	exec 3>&1
+	exec 4>&2
+	# create a new fd 5 that send to a file
+	exec 5> >(cat > $1)
+	# send stdout and stderr to fd 5
+	if [ "${verbose}" = "true" ]; then
+		exec 1> >(tee /dev/fd/5 >&3)
+		exec 2> >(tee /dev/fd/5 >&4)
+	else
+		exec 1>&5
+		exec 2>&5
+	fi
 }
 
 # Make sure we configure SHARED libraries
 # Also turn off IGB and KNI as those require kernel headers to build
 fixup_config() {
-	sed -i -e"$ a\CONFIG_RTE_BUILD_SHARED_LIB=y" config/defconfig_$TARGET
-	sed -i -e"$ a\CONFIG_RTE_NEXT_ABI=n" config/defconfig_$TARGET
-	sed -i -e"$ a\CONFIG_RTE_EAL_IGB_UIO=n" config/defconfig_$TARGET
-	sed -i -e"$ a\CONFIG_RTE_LIBRTE_KNI=n" config/defconfig_$TARGET
-	sed -i -e"$ a\CONFIG_RTE_KNI_KMOD=n" config/defconfig_$TARGET
+	local conf=config/defconfig_$target
+	cmd sed -i -e"$ a\CONFIG_RTE_BUILD_SHARED_LIB=y" $conf
+	cmd sed -i -e"$ a\CONFIG_RTE_NEXT_ABI=n" $conf
+	cmd sed -i -e"$ a\CONFIG_RTE_EAL_IGB_UIO=n" $conf
+	cmd sed -i -e"$ a\CONFIG_RTE_LIBRTE_KNI=n" $conf
+	cmd sed -i -e"$ a\CONFIG_RTE_KNI_KMOD=n" $conf
 }
 
-###########################################
-#START
-############################################
+# build dpdk for the given tag and dump abi
+# $1: hash of the revision
+gen_abi() {
+	cmd git clone $(dirname $0)/.. ${dst}/${1}
+	cmd cd ${dst}/${1}
+
+	log "INFO" "Checking out version ${1} of the dpdk"
+	# Move to the old version of the tree
+	cmd git checkout ${1}
+
+	fixup_config
+
+	# Now configure the build
+	log "INFO" "Configuring DPDK ${1}"
+	cmd make config T=$target O=$target > ${dst}/log 2>&1
+
+	# Checking abi compliance relies on using the dwarf information in
+	# the shared objects. Build with -g to include them.
+	log "INFO" "Building DPDK ${1}. This might take a moment"
+	cmd make -j$parallel O=$target V=1 EXTRA_CFLAGS="-g -O0" \
+	    EXTRA_LDFLAGS="-g" || log "INFO" "The build failed"
+
+	# Move to the lib directory
+	cmd cd ${PWD}/$target/lib
+	log "INFO" "Collecting ABI information for ${1}"
+	for i in *.so; do
+		[ -e "$i" ] || break
+		cmd $abidump ${i} -o $dst/${1}/${i}.dump -lver ${1} || true
+		# hack to ignore empty SymbolsInfo section (no public ABI)
+		if grep -q "'SymbolInfo' => {}," $dst/${1}/${i}.dump \
+				2> /dev/null; then
+			log "INFO" "${i} has no public ABI, remove dump file"
+			cmd rm -f $dst/${1}/${i}.dump
+		fi
+	done
+	cmd cd ../..
+}
 
-#trap on ctrl-c to clean up
-trap cleanup_and_exit SIGINT
+verbose=false
+parallel=1
+dst=${default_dst}
+target=${default_target}
+force=0
+while getopts j:vd:t:fh ARG ; do
+	case $ARG in
+		j ) parallel=$OPTARG ;;
+		v ) verbose=true ;;
+		d ) dst=$OPTARG ;;
+		t ) target=$OPTARG ;;
+		f ) force=1 ;;
+		h ) print_usage ; exit 0 ;;
+		? ) print_usage ; exit 1 ;;
+	esac
+done
+shift $(($OPTIND - 1))
 
-if [ -z "$DPDK_MAKE_JOBS" ]
-then
-	# This counts the number of cpus on the system
-	if [ -e /usr/bin/lscpu ]
-	then
-		DPDK_MAKE_JOBS=`lscpu -p=cpu | grep -v "#" | wc -l`
-	else
-		DPDK_MAKE_JOBS=1
-	fi
+if [ $# != 2 ]; then
+	print_usage
+	exit 1
 fi
 
-#Save the current branch
-CURRENT_BRANCH=`git branch | grep \* | cut -d' ' -f2`
+tag1=$1
+tag2=$2
 
-if [ -z "$CURRENT_BRANCH" ]
-then
-	CURRENT_BRANCH=`git log --pretty=format:%H HEAD~1..HEAD`
-fi
+# convert path to absolute
+case "${dst}" in
+	/*) ;;
+	*) dst=${PWD}/${dst} ;;
+esac
 
-if [ -n "$VERBOSE" ]
-then
-	export VERBOSE=/dev/stdout
-else
-	export VERBOSE=/dev/null
+if [ -e "${dst}" -a "$force" = 0 ]; then
+	echo "The ${dst} directory is not empty. Remove it, use another"
+	echo "one (-d <dir>), or force overriding (-f)"
+	exit 1
 fi
 
-# Validate that we have all the arguments we need
-res=$(validate_args)
-if [ -n "$res" ]
-then
-	echo $res
-	usage
-	cleanup_and_exit 1
-fi
+rm -rf ${dst}
+mkdir -p ${dst}
+set_log_file ${dst}/abi-check.log
+log "INFO" "Logs available in ${dst}/abi-check.log"
 
-HASH1=$(git show -s --format=%H "$TAG1" -- 2> /dev/null | tail -1)
-HASH2=$(git show -s --format=%H "$TAG2" -- 2> /dev/null | tail -1)
+command -v ${abicheck} || log "INFO" "Can't find ${abicheck} utility"
+command -v ${abidump} || log "INFO" "Can't find ${abidump} utility"
 
-# Make sure our tags exist
-res=$(validate_tags)
-if [ -n "$res" ]
-then
-	echo $res
-	cleanup_and_exit 1
-fi
+hash1=$(git show -s --format=%h "$tag1" -- 2> /dev/null | tail -1)
+hash2=$(git show -s --format=%h "$tag2" -- 2> /dev/null | tail -1)
 
 # Make hashes available in output for non-local reference
-TAG1="$TAG1 ($HASH1)"
-TAG2="$TAG2 ($HASH2)"
-
-ABICHECK=`which abi-compliance-checker 2>/dev/null`
-if [ $? -ne 0 ]
-then
-	log "INFO" "Can't find abi-compliance-checker utility"
-	cleanup_and_exit 1
-fi
-
-ABIDUMP=`which abi-dumper 2>/dev/null`
-if [ $? -ne 0 ]
-then
-	log "INFO" "Can't find abi-dumper utility"
-	cleanup_and_exit 1
-fi
+tag1="$tag1 ($hash1)"
+tag2="$tag2 ($hash2)"
 
-log "INFO" "We're going to check and make sure that applications built"
-log "INFO" "against DPDK DSOs from version $TAG1 will still run when executed"
-log "INFO" "against DPDK DSOs built from version $TAG2."
-log "INFO" ""
-
-# Check to make sure we have a clean tree
-git status | grep -q clean
-if [ $? -ne 0 ]
-then
-	log "WARN" "Working directory not clean, aborting"
-	cleanup_and_exit 1
+if [ "$hash1" = "$hash2" ]; then
+	log "ERROR" "$tag1 and $tag2 are the same revisions"
+	exit 1
 fi
 
-# Move to the root of the git tree
-cd $(dirname $0)/..
+cmd mkdir -p ${dst}
 
-log "INFO" "Checking out version $TAG1 of the dpdk"
-# Move to the old version of the tree
-git checkout $HASH1
+# dump abi for each revision
+gen_abi ${hash1}
+gen_abi ${hash2}
 
-fixup_config
+# compare the abi dumps
+ret=0
+list=""
+for i in ${dst}/${hash2}/*.dump; do
+	name=`basename $i`
+	libname=${name%.dump}
 
-# Checking abi compliance relies on using the dwarf information in
-# The shared objects.  Thats only included in the DSO's if we build
-# with -g
-export EXTRA_CFLAGS="$EXTRA_CFLAGS -g -O0"
-export EXTRA_LDFLAGS="$EXTRA_LDFLAGS -g"
-
-# Now configure the build
-log "INFO" "Configuring DPDK $TAG1"
-make config T=$TARGET O=$TARGET > $VERBOSE 2>&1
-
-log "INFO" "Building DPDK $TAG1. This might take a moment"
-make -j$DPDK_MAKE_JOBS O=$TARGET > $VERBOSE 2>&1
-
-if [ $? -ne 0 ]
-then
-	log "INFO" "THE BUILD FAILED.  ABORTING"
-	cleanup_and_exit 1
-fi
+	if [ ! -f $dst/${hash1}/$name ]; then
+		log "INFO" "$NAME does not exist in $tag1. skipping..."
+		continue
+	fi
 
-# Move to the lib directory
-cd $TARGET/lib
-log "INFO" "COLLECTING ABI INFORMATION FOR $TAG1"
-for i in `ls *.so`
-do
-	$ABIDUMP $i -o $ABI_DIR/$i-ABI-0.dump -lver $HASH1
+	local_ret=0
+	cmd $abicheck -l $libname \
+	    -old $dst/${hash1}/$name -new $dst/${hash2}/$name || local_ret=$?
+	if [ $local_ret != 0 ]; then
+		log "NOTICE" "$abicheck returned $local_ret"
+		ret=$local_ret
+		list="$list $libname"
+	fi
 done
-cd ../..
-
-# Now clean the tree, checkout the second tag, and rebuild
-git clean -f -d
-git reset --hard
-# Move to the new version of the tree
-log "INFO" "Checking out version $TAG2 of the dpdk"
-git checkout $HASH2
-
-fixup_config
-
-# Now configure the build
-log "INFO" "Configuring DPDK $TAG2"
-make config T=$TARGET O=$TARGET > $VERBOSE 2>&1
-
-log "INFO" "Building DPDK $TAG2. This might take a moment"
-make -j$DPDK_MAKE_JOBS O=$TARGET > $VERBOSE 2>&1
 
-if [ $? -ne 0 ]
-then
-	log "INFO" "THE BUILD FAILED.  ABORTING"
-	cleanup_and_exit 1
+if [ $ret != 0 ]; then
+	log "NOTICE" "At least one call to $abicheck returned an error."
+	log "NOTICE" "ABI may be incompatible, please check logs for details."
+	log "NOTICE" "Incompatible list: $list"
+else
+	log "NOTICE" "No error detected, ABI is compatible."
 fi
 
-cd $TARGET/lib
-log "INFO" "COLLECTING ABI INFORMATION FOR $TAG2"
-for i in `ls *.so`
-do
-	$ABIDUMP $i -o $ABI_DIR/$i-ABI-1.dump -lver $HASH2
-done
-cd ../..
-
-# Start comparison of ABI dumps
-for i in `ls $ABI_DIR/*-1.dump`
-do
-	NEWNAME=`basename $i`
-	OLDNAME=`basename $i | sed -e"s/1.dump/0.dump/"`
-	LIBNAME=`basename $i | sed -e"s/-ABI-1.dump//"`
-
-	if [ ! -f $ABI_DIR/$OLDNAME ]
-	then
-		log "INFO" "$OLDNAME DOES NOT EXIST IN $TAG1. SKIPPING..."
-	fi
-
-	#compare the abi dumps
-	$ABICHECK -l $LIBNAME -old $ABI_DIR/$OLDNAME -new $ABI_DIR/$NEWNAME
-done
+log "INFO" "Logs are in ${dst}/abi-check.log"
+log "INFO" "HTML reports are in ${dst}/compat_reports directory"
 
-git reset --hard
-log "INFO" "ABI CHECK COMPLETE.  REPORTS ARE IN compat_report directory"
-cleanup_and_exit 0
+exit $ret
-- 
2.11.0

^ permalink raw reply	[relevance 27%]

* [dpdk-dev] [PATCH v3] rte_vhost: added user callbacks for socket open/close
  2017-08-22 16:24  3% ` [dpdk-dev] [PATCH v2] " Dariusz Stojaczyk
  2017-08-25  9:22  0%   ` Jens Freimann
@ 2017-08-30 10:50  3%   ` Dariusz Stojaczyk
  1 sibling, 0 replies; 200+ results
From: Dariusz Stojaczyk @ 2017-08-30 10:50 UTC (permalink / raw)
  To: dev; +Cc: Pawel Wodkowski, jfreimann, maxime.coquelin, yliu, Dariusz Stojaczyk

Added new callbacks to notify about socket connection status.
As destroy_device is used for virtqueue processing *pause* as well as
connection close, the user has no distinction between those.

Consider the following scenario:
rte_vhost: received SET_VRING_BASE message,
           calling destroy_device() as usual

user:  end-user asks to remove the device (together with socket file),
       OK, device is not *in use* - that's NOT the behavior we want
       calling rte_vhost_driver_unregister() etc.

Instead of changing new_device/destroy_device callbacks and breaking
the ABI, a set of new functions new_connection/destroy_connection
has been added.

Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
---
v3: improved err-handling path and updated commit msg
v2: also updated vhost_lib.rst
 lib/librte_vhost/rte_vhost.h |  5 ++++-
 lib/librte_vhost/socket.c    | 31 ++++++++++++++++++++++++-------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
index 8c974eb..fe5c94c 100644
--- a/lib/librte_vhost/rte_vhost.h
+++ b/lib/librte_vhost/rte_vhost.h
@@ -107,7 +107,10 @@ struct vhost_device_ops {
 	 */
 	int (*features_changed)(int vid, uint64_t features);
 
-	void *reserved[4]; /**< Reserved for future extension */
+	int (*new_connection)(int vid);
+	void (*destroy_connection)(int vid);
+
+	void *reserved[2]; /**< Reserved for future extension */
 };
 
 /**
diff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c
index 41aa3f9..7018150 100644
--- a/lib/librte_vhost/socket.c
+++ b/lib/librte_vhost/socket.c
@@ -217,9 +217,7 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
 
 	vid = vhost_new_device();
 	if (vid == -1) {
-		close(fd);
-		free(conn);
-		return;
+		goto err;
 	}
 
 	size = strnlen(vsocket->path, PATH_MAX);
@@ -230,24 +228,40 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
 
 	RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
 
+	if (vsocket->notify_ops->new_connection) {
+		ret = vsocket->notify_ops->new_connection(vid);
+		if (ret < 0) {
+			RTE_LOG(ERR, VHOST_CONFIG,
+				"failed to add vhost user connection with fd %d\n",
+				fd);
+			goto err;
+		}
+	}
+
 	conn->connfd = fd;
 	conn->vsocket = vsocket;
 	conn->vid = vid;
 	ret = fdset_add(&vhost_user.fdset, fd, vhost_user_read_cb,
 			NULL, conn);
 	if (ret < 0) {
-		conn->connfd = -1;
-		free(conn);
-		close(fd);
 		RTE_LOG(ERR, VHOST_CONFIG,
 			"failed to add fd %d into vhost server fdset\n",
 			fd);
-		return;
+
+		if (vsocket->notify_ops->destroy_connection)
+			vsocket->notify_ops->destroy_connection(conn->vid);
+
+		goto err;
 	}
 
 	pthread_mutex_lock(&vsocket->conn_mutex);
 	TAILQ_INSERT_TAIL(&vsocket->conn_list, conn, next);
 	pthread_mutex_unlock(&vsocket->conn_mutex);
+	return;
+
+err:
+	free(conn);
+	close(fd);
 }
 
 /* call back when there is new vhost-user connection from client  */
@@ -277,6 +291,9 @@ vhost_user_read_cb(int connfd, void *dat, int *remove)
 		*remove = 1;
 		vhost_destroy_device(conn->vid);
 
+		if (vsocket->notify_ops->destroy_connection)
+			vsocket->notify_ops->destroy_connection(conn->vid);
+
 		pthread_mutex_lock(&vsocket->conn_mutex);
 		TAILQ_REMOVE(&vsocket->conn_list, conn, next);
 		pthread_mutex_unlock(&vsocket->conn_mutex);
-- 
2.7.4

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] vhost: added user callbacks for socket open/close
  2017-08-29  6:08  3%     ` Stojaczyk, DariuszX
@ 2017-08-30  6:33  0%       ` Jens Freimann
  0 siblings, 0 replies; 200+ results
From: Jens Freimann @ 2017-08-30  6:33 UTC (permalink / raw)
  To: Stojaczyk, DariuszX; +Cc: dev, Wodkowski, PawelX, maxime.coquelin, yliu

On Tue, Aug 29, 2017 at 06:08:45AM +0000, Stojaczyk, DariuszX wrote:
>Hi Jens,
>
>> I'm still not sure I understand the use case. So just for my
>> understanding: users need to distinct between "the device is going away
>> temporarily, keep the connection" and "we're shutting down for good", is
>> that it?
>
>Yes, exactly.
>
>> Maybe it's just me or maybe it means you could explain your example in the
>> commit message a bit more.
>
>Ok. How about the following commit message instead:
>```
>rte_vhost: added user callbacks for socket open/close
>
>Added new callbacks to notify about socket connection status.
>As destroy_device is used for virtqueue processing *pause* as
>well as connection close, the user has no distinction between those.
>
>Consider the following scenario:
>rte_vhost: received SET_VRING_BASE message,
>                  calling destroy_device() as usual
>
>user:  end-user asks to remove the device (together with socket file),
>          OK, device is not *in use* - that's NOT the behavior we want
>          calling rte_vhost_driver_unregister() etc.
>
>Instead of changing new_device/destroy_device callbacks and breaking
>the ABI, a set of new functions new_connection/destroy_connection
>has been added.
>```

Sounds good to me. Thanks!

regards,
Jens 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-29 12:50  0%   ` Ferruh Yigit
@ 2017-08-30  6:22  0%     ` Shahaf Shuler
  0 siblings, 0 replies; 200+ results
From: Shahaf Shuler @ 2017-08-30  6:22 UTC (permalink / raw)
  To: Ferruh Yigit, dev

Tuesday, August 29, 2017 3:50 PM, Ferruh Yigit:
> On 8/7/2017 11:54 AM, Shahaf Shuler wrote:
> > Introduce a new API to configure Rx offloads.
> >
> > The new API will re-use existing DEV_RX_OFFLOAD_* flags to enable the
> > different offloads. This will ease the process of adding a new Rx
> > offloads, as no ABI breakage is involved.
> > In addition, the offload configuration can be done per queue, instead
> > of per port.
> 
> If a device doesn't have capability to set the offload per queue how should it
> behave, I think it is good to define this.

Yes, will add documentation. 
How about If device cannot set offloads per queue, then the queue_setup function should return with ENOTSUP ?

> 
> >
> > The Rx queue offload API can be used only with devices which advertize
> > the RTE_ETH_DEV_RXQ_OFFLOAD capability.
> >
> > The old Rx offloads API is kept for the meanwhile, in order to enable
> > a smooth transition for PMDs and application to the new API.
> >
> > Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
> 
> <...>
> 
> > @@ -357,7 +357,14 @@ struct rte_eth_rxmode {
> >  		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
> >  		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
> >  		enable_scatter   : 1, /**< Enable scatter packets rx handler */
> > -		enable_lro       : 1; /**< Enable LRO */
> > +		enable_lro       : 1, /**< Enable LRO */
> > +		ignore		 : 1;
> 
> what do you think making this variable more verbose, like
> "ignore_rx_offloads"
> 
> "dev_conf.rxmode.ignore" doesn't say on its own what is ignored.

Maybe ignore_offloads ? Rx is quite explicit from rxomde.

> 
> > +		/**
> > +		 * When set the rxmode offloads should be ignored,
> > +		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
> > +		 * This bit is temporary till rxmode Rx offloads API will
> > +		 * be deprecated.
> > +		 */
> >  };
> 
> <...>
> 
> > +/** Device supports the rte_eth_rxq_conf offloads API */ #define
> > +RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
> Since this is temporary flag and with current implementation this is local to
> library, should we put this into public header?
> 
> Later when all PMDs implemented this new method and we want to remove
> the flag, can we remove them or do we have to keep them reserved for any
> conflict for further new values?
> 
> I guess this should be part of missing pmd-ethdev interface file
> (rte_ethdev_pmd.h ?).

Yes it is better fits to inner interface between ethdev and PMDs.
Wondering, do we have other motivation to have such header? 

> 
> >
> >  /**
> >   * @internal
> >


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 04/12] vdev: move to drivers/bus
  2017-08-29 13:04  3%   ` Gaëtan Rivet
@ 2017-08-29 22:47  0%     ` Tan, Jianfeng
  0 siblings, 0 replies; 200+ results
From: Tan, Jianfeng @ 2017-08-29 22:47 UTC (permalink / raw)
  To: Gaëtan Rivet
  Cc: dev, bruce.richardson, konstantin.ananyev, pablo.de.lara.guarch,
	thomas, yliu, maxime.coquelin, mtetsuyah, ferruh.yigit

Hi Gaetan,


On 8/29/2017 6:04 AM, Gaëtan Rivet wrote:
> On Fri, Aug 25, 2017 at 09:40:44AM +0000, Jianfeng Tan wrote:
>> Move the vdev bus from lib/librte_eal to drivers/bus.
>>
>> As the crypto vdev helper function refers to data structure
>> in rte_vdev.h, so we move those helper function into drivers/bus
>> too.
>>
>> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
>> ---
>>   config/common_base                        |   5 +
>>   drivers/bus/Makefile                      |   2 +
>>   drivers/bus/vdev/Makefile                 |  57 +++++
>>   drivers/bus/vdev/rte_bus_vdev_version.map |  10 +
>>   drivers/bus/vdev/rte_cryptodev_vdev.c     | 154 ++++++++++++++
>>   drivers/bus/vdev/rte_cryptodev_vdev.h     | 100 +++++++++
>>   drivers/bus/vdev/rte_vdev.h               | 153 +++++++++++++
>>   drivers/bus/vdev/vdev.c                   | 342 ++++++++++++++++++++++++++++++
>>   lib/librte_cryptodev/Makefile             |   2 -
>>   lib/librte_cryptodev/rte_cryptodev_vdev.c | 154 --------------
>>   lib/librte_cryptodev/rte_cryptodev_vdev.h | 100 ---------
>>   lib/librte_eal/bsdapp/eal/Makefile        |   1 -
>>   lib/librte_eal/common/Makefile            |   2 +-
>>   lib/librte_eal/common/eal_common_vdev.c   | 342 ------------------------------
>>   lib/librte_eal/common/include/rte_dev.h   |  24 +--
>>   lib/librte_eal/common/include/rte_vdev.h  | 131 ------------
>>   lib/librte_eal/linuxapp/eal/Makefile      |   1 -
>>   mk/rte.app.mk                             |   1 +
>>   18 files changed, 826 insertions(+), 755 deletions(-)
>>   create mode 100644 drivers/bus/vdev/Makefile
>>   create mode 100644 drivers/bus/vdev/rte_bus_vdev_version.map
>>   create mode 100644 drivers/bus/vdev/rte_cryptodev_vdev.c
>>   create mode 100644 drivers/bus/vdev/rte_cryptodev_vdev.h
>>   create mode 100644 drivers/bus/vdev/rte_vdev.h
>>   create mode 100644 drivers/bus/vdev/vdev.c
>>   delete mode 100644 lib/librte_cryptodev/rte_cryptodev_vdev.c
>>   delete mode 100644 lib/librte_cryptodev/rte_cryptodev_vdev.h
>>   delete mode 100644 lib/librte_eal/common/eal_common_vdev.c
>>   delete mode 100644 lib/librte_eal/common/include/rte_vdev.h
>>
>> diff --git a/config/common_base b/config/common_base
>> index 5e97a08..aca0994 100644
>> --- a/config/common_base
>> +++ b/config/common_base
>> @@ -750,3 +750,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y
>>   # Compile the eventdev application
>>   #
>>   CONFIG_RTE_APP_EVENTDEV=y
>> +
>> +#
>> +# Compile the vdev bus
>> +#
>> +CONFIG_RTE_LIBRTE_VDEV=y
> Why not CONFIG_RTE_LIBRTE_VDEV_BUS?
> It would seem more consistent.

Was trying to be consistent with the directory name, drivers/bus/vdev. 
Do you think that directory should also be renamed?

>
>> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
>> index 0224214..9b6d45e 100644
>> --- a/drivers/bus/Makefile
>> +++ b/drivers/bus/Makefile
>> @@ -35,4 +35,6 @@ core-libs := librte_eal librte_mbuf librte_mempool librte_ring librte_ether
>>   DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc
>>   DEPDIRS-fslmc = $(core-libs)
>>   
>> +DIRS-$(CONFIG_RTE_LIBRTE_VDEV) += vdev
>> +
>>   include $(RTE_SDK)/mk/rte.subdir.mk
>> diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
>> new file mode 100644
>> index 0000000..30c4813
>> --- /dev/null
>> +++ b/drivers/bus/vdev/Makefile
>> @@ -0,0 +1,57 @@
>> +#   BSD LICENSE
>> +#
>> +#   Copyright(c) 2017 Intel Corporation. All rights reserved.
>> +#   All rights reserved.
>> +#
>> +#   Redistribution and use in source and binary forms, with or without
>> +#   modification, are permitted provided that the following conditions
>> +#   are met:
>> +#
>> +#     * Redistributions of source code must retain the above copyright
>> +#       notice, this list of conditions and the following disclaimer.
>> +#     * Redistributions in binary form must reproduce the above copyright
>> +#       notice, this list of conditions and the following disclaimer in
>> +#       the documentation and/or other materials provided with the
>> +#       distribution.
>> +#     * Neither the name of Intel Corporation nor the names of its
>> +#       contributors may be used to endorse or promote products derived
>> +#       from this software without specific prior written permission.
>> +#
>> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> +
>> +include $(RTE_SDK)/mk/rte.vars.mk
>> +
>> +#
>> +# library name
>> +#
>> +LIB = librte_bus_vdev.a
>> +
>> +CFLAGS += -O3
>> +CFLAGS += $(WERROR_FLAGS)
>> +
>> +# versioning export map
>> +EXPORT_MAP := rte_bus_vdev_version.map
>> +
>> +# library version
>> +LIBABIVER := 1
>> +
>> +SRCS-y += vdev.c
>> +SRCS-y += rte_cryptodev_vdev.c
>> +
>> +#
>> +# Export include files
>> +#
>> +SYMLINK-y-include += rte_vdev.h
>> +SYMLINK-y-include += rte_cryptodev_vdev.h
>> +
> Let's say the cryptodev lib must be updated.
> I understand the need to move rte_cryptodev_vdev.h outside
> librte_cryptodev, but I guess this exposes the vdev bus to ABI / API
> instability due to a third-party subsystem?

Thank you for bringing up this question. I really don't want to move 
these crypto-specific files into bus/vdev/. It's just some helper 
functions to be called by crypto vdev drivers. And what's more, the only 
dependence on vdev is that the API rte_cryptodev_vdev_pmd_init() has a 
parameter of struct rte_vdev_device, which is totally not necessary, as 
it only needs a struct rte_device parameter.

In all, I'd prefer to change this specific API and move those 
crypto-specific files back to lib/librte_crypto (just like ether dev and 
eventdev); but it needs API change announcement.

Any thoughts?

>
> I did something somewhat similar for PCI:
> http://dpdk.org/ml/archives/dev/2017-August/073525.html

I prefer your way to move those things to specific dev folder.

>
> I don't know which solution is best, but something certainly needs to be
> done.
>
> ---
>
> Beside the `why`, about the `how`: shouldn't this file compilation and
> symlink be conditioned to CONFIG_RTE_LIBRTE_CRYPTODEV=y?
>
> i.e.: SYMLINK-$(CONFIG_RTE_LIBRTE_CRYPTODEV)-include += rte_cryptodev_vdev.h

Yes, make sense.

Thanks,
Jianfeng


>
>> +include $(RTE_SDK)/mk/rte.lib.mk
>> diff --git a/drivers/bus/vdev/rte_bus_vdev_version.map b/drivers/bus/vdev/rte_bus_vdev_version.map
>> new file mode 100644
>> index 0000000..69740c3
>> --- /dev/null
>> +++ b/drivers/bus/vdev/rte_bus_vdev_version.map
>> @@ -0,0 +1,10 @@
>> +DPDK_17.11 {
>> +	global:
>> +
>> +	rte_vdev_init;
>> +	rte_vdev_register;
>> +	rte_vdev_uninit;
>> +	rte_vdev_unregister;
>> +	rte_cryptodev_vdev_pmd_init
>> +	rte_cryptodev_vdev_parse_init_params
>> +};
>> diff --git a/drivers/bus/vdev/rte_cryptodev_vdev.c b/drivers/bus/vdev/rte_cryptodev_vdev.c
>> new file mode 100644
>> index 0000000..fd308b4
>> --- /dev/null
>> +++ b/drivers/bus/vdev/rte_cryptodev_vdev.c
>> @@ -0,0 +1,154 @@
>> +/*-
>> + *   BSD LICENSE
>> + *
>> + *   Copyright(c) 2017 Intel Corporation. All rights reserved.
>> + *
>> + *   Redistribution and use in source and binary forms, with or without
>> + *   modification, are permitted provided that the following conditions
>> + *   are met:
>> + *
>> + *     * Redistributions of source code must retain the above copyright
>> + *       notice, this list of conditions and the following disclaimer.
>> + *     * Redistributions in binary form must reproduce the above copyright
>> + *       notice, this list of conditions and the following disclaimer in
>> + *       the documentation and/or other materials provided with the
>> + *       distribution.
>> + *     * Neither the name of the copyright holder nor the names of its
>> + *       contributors may be used to endorse or promote products derived
>> + *       from this software without specific prior written permission.
>> + *
>> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> + */
>> +
>> +#include "rte_cryptodev_vdev.h"
>> +#include "rte_cryptodev_pci.h"
>> +#include "rte_cryptodev_pmd.h"
>> +
>> +/**
>> + * Parse name from argument
>> + */
>> +static int
>> +rte_cryptodev_vdev_parse_name_arg(const char *key __rte_unused,
>> +		const char *value, void *extra_args)
>> +{
>> +	struct rte_crypto_vdev_init_params *params = extra_args;
>> +
>> +	if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
>> +		CDEV_LOG_ERR("Invalid name %s, should be less than "
>> +				"%u bytes", value,
>> +				RTE_CRYPTODEV_NAME_MAX_LEN - 1);
>> +		return -1;
>> +	}
>> +
>> +	strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * Parse integer from argument
>> + */
>> +static int
>> +rte_cryptodev_vdev_parse_integer_arg(const char *key __rte_unused,
>> +		const char *value, void *extra_args)
>> +{
>> +	int *i = extra_args;
>> +
>> +	*i = atoi(value);
>> +	if (*i < 0) {
>> +		CDEV_LOG_ERR("Argument has to be positive.");
>> +		return -1;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +struct rte_cryptodev *
>> +rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
>> +		int socket_id, struct rte_vdev_device *vdev)
>> +{
>> +	struct rte_cryptodev *cryptodev;
>> +
>> +	/* allocate device structure */
>> +	cryptodev = rte_cryptodev_pmd_allocate(name, socket_id);
>> +	if (cryptodev == NULL)
>> +		return NULL;
>> +
>> +	/* allocate private device structure */
>> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>> +		cryptodev->data->dev_private =
>> +				rte_zmalloc_socket("cryptodev device private",
>> +						dev_private_size,
>> +						RTE_CACHE_LINE_SIZE,
>> +						socket_id);
>> +
>> +		if (cryptodev->data->dev_private == NULL)
>> +			rte_panic("Cannot allocate memzone for private device"
>> +					" data");
>> +	}
>> +
>> +	cryptodev->device = &vdev->device;
>> +
>> +	/* initialise user call-back tail queue */
>> +	TAILQ_INIT(&(cryptodev->link_intr_cbs));
>> +
>> +	return cryptodev;
>> +}
>> +
>> +int
>> +rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
>> +		const char *input_args)
>> +{
>> +	struct rte_kvargs *kvlist = NULL;
>> +	int ret = 0;
>> +
>> +	if (params == NULL)
>> +		return -EINVAL;
>> +
>> +	if (input_args) {
>> +		kvlist = rte_kvargs_parse(input_args,
>> +				cryptodev_vdev_valid_params);
>> +		if (kvlist == NULL)
>> +			return -1;
>> +
>> +		ret = rte_kvargs_process(kvlist,
>> +					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
>> +					&rte_cryptodev_vdev_parse_integer_arg,
>> +					&params->max_nb_queue_pairs);
>> +		if (ret < 0)
>> +			goto free_kvlist;
>> +
>> +		ret = rte_kvargs_process(kvlist,
>> +					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
>> +					&rte_cryptodev_vdev_parse_integer_arg,
>> +					&params->max_nb_sessions);
>> +		if (ret < 0)
>> +			goto free_kvlist;
>> +
>> +		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
>> +					&rte_cryptodev_vdev_parse_integer_arg,
>> +					&params->socket_id);
>> +		if (ret < 0)
>> +			goto free_kvlist;
>> +
>> +		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
>> +					&rte_cryptodev_vdev_parse_name_arg,
>> +					params);
>> +		if (ret < 0)
>> +			goto free_kvlist;
>> +	}
>> +
>> +free_kvlist:
>> +	rte_kvargs_free(kvlist);
>> +	return ret;
>> +}
>> diff --git a/drivers/bus/vdev/rte_cryptodev_vdev.h b/drivers/bus/vdev/rte_cryptodev_vdev.h
>> new file mode 100644
>> index 0000000..94ab9d3
>> --- /dev/null
>> +++ b/drivers/bus/vdev/rte_cryptodev_vdev.h
>> @@ -0,0 +1,100 @@
>> +/*-
>> + *   BSD LICENSE
>> + *
>> + *   Copyright(c) 2017 Intel Corporation. All rights reserved.
>> + *
>> + *   Redistribution and use in source and binary forms, with or without
>> + *   modification, are permitted provided that the following conditions
>> + *   are met:
>> + *
>> + *     * Redistributions of source code must retain the above copyright
>> + *       notice, this list of conditions and the following disclaimer.
>> + *     * Redistributions in binary form must reproduce the above copyright
>> + *       notice, this list of conditions and the following disclaimer in
>> + *       the documentation and/or other materials provided with the
>> + *       distribution.
>> + *     * Neither the name of the copyright holder nor the names of its
>> + *       contributors may be used to endorse or promote products derived
>> + *       from this software without specific prior written permission.
>> + *
>> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> + */
>> +
>> +#ifndef _RTE_CRYPTODEV_VDEV_H_
>> +#define _RTE_CRYPTODEV_VDEV_H_
>> +
>> +#include <rte_vdev.h>
>> +#include <inttypes.h>
>> +
>> +#include "rte_cryptodev.h"
>> +
>> +#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
>> +#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
>> +
>> +#define RTE_CRYPTODEV_VDEV_NAME				("name")
>> +#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
>> +#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
>> +#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
>> +
>> +static const char * const cryptodev_vdev_valid_params[] = {
>> +	RTE_CRYPTODEV_VDEV_NAME,
>> +	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
>> +	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
>> +	RTE_CRYPTODEV_VDEV_SOCKET_ID
>> +};
>> +
>> +/**
>> + * @internal
>> + * Initialisation parameters for virtual crypto devices
>> + */
>> +struct rte_crypto_vdev_init_params {
>> +	unsigned int max_nb_queue_pairs;
>> +	unsigned int max_nb_sessions;
>> +	uint8_t socket_id;
>> +	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
>> +};
>> +
>> +/**
>> + * @internal
>> + * Creates a new virtual crypto device and returns the pointer
>> + * to that device.
>> + *
>> + * @param	name			PMD type name
>> + * @param	dev_private_size	Size of crypto PMDs private data
>> + * @param	socket_id		Socket to allocate resources on.
>> + * @param	vdev			Pointer to virtual device structure.
>> + *
>> + * @return
>> + *   - Cryptodev pointer if device is successfully created.
>> + *   - NULL if device cannot be created.
>> + */
>> +struct rte_cryptodev *
>> +rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
>> +		int socket_id, struct rte_vdev_device *vdev);
>> +
>> +/**
>> + * @internal
>> + * Parse virtual device initialisation parameters input arguments
>> + *
>> + * @params	params		Initialisation parameters with defaults set.
>> + * @params	input_args	Command line arguments
>> + *
>> + * @return
>> + * 0 on successful parse
>> + * <0 on failure to parse
>> + */
>> +int
>> +rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
>> +		const char *input_args);
>> +
>> +#endif /* _RTE_CRYPTODEV_VDEV_H_ */
>> diff --git a/drivers/bus/vdev/rte_vdev.h b/drivers/bus/vdev/rte_vdev.h
>> new file mode 100644
>> index 0000000..41762b8
>> --- /dev/null
>> +++ b/drivers/bus/vdev/rte_vdev.h
>> @@ -0,0 +1,153 @@
>> +/*-
>> + *   BSD LICENSE
>> + *
>> + *   Copyright(c) 2016 RehiveTech. All rights reserved.
>> + *
>> + *   Redistribution and use in source and binary forms, with or without
>> + *   modification, are permitted provided that the following conditions
>> + *   are met:
>> + *
>> + *     * Redistributions of source code must retain the above copyright
>> + *       notice, this list of conditions and the following disclaimer.
>> + *     * Redistributions in binary form must reproduce the above copyright
>> + *       notice, this list of conditions and the following disclaimer in
>> + *       the documentation and/or other materials provided with the
>> + *       distribution.
>> + *     * Neither the name of RehiveTech nor the names of its
>> + *       contributors may be used to endorse or promote products derived
>> + *       from this software without specific prior written permission.
>> + *
>> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> + */
>> +
>> +#ifndef RTE_VDEV_H
>> +#define RTE_VDEV_H
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +#include <sys/queue.h>
>> +#include <rte_dev.h>
>> +#include <rte_devargs.h>
>> +
>> +struct rte_vdev_device {
>> +	TAILQ_ENTRY(rte_vdev_device) next;      /**< Next attached vdev */
>> +	struct rte_device device;               /**< Inherit core device */
>> +};
>> +
>> +/**
>> + * @internal
>> + * Helper macro for drivers that need to convert to struct rte_vdev_device.
>> + */
>> +#define RTE_DEV_TO_VDEV(ptr) \
>> +	container_of(ptr, struct rte_vdev_device, device)
>> +
>> +static inline const char *
>> +rte_vdev_device_name(const struct rte_vdev_device *dev)
>> +{
>> +	if (dev && dev->device.name)
>> +		return dev->device.name;
>> +	return NULL;
>> +}
>> +
>> +static inline const char *
>> +rte_vdev_device_args(const struct rte_vdev_device *dev)
>> +{
>> +	if (dev && dev->device.devargs)
>> +		return dev->device.devargs->args;
>> +	return "";
>> +}
>> +
>> +/** Double linked list of virtual device drivers. */
>> +TAILQ_HEAD(vdev_driver_list, rte_vdev_driver);
>> +
>> +/**
>> + * Probe function called for each virtual device driver once.
>> + */
>> +typedef int (rte_vdev_probe_t)(struct rte_vdev_device *dev);
>> +
>> +/**
>> + * Remove function called for each virtual device driver once.
>> + */
>> +typedef int (rte_vdev_remove_t)(struct rte_vdev_device *dev);
>> +
>> +/**
>> + * A virtual device driver abstraction.
>> + */
>> +struct rte_vdev_driver {
>> +	TAILQ_ENTRY(rte_vdev_driver) next; /**< Next in list. */
>> +	struct rte_driver driver;      /**< Inherited general driver. */
>> +	rte_vdev_probe_t *probe;       /**< Virtual device probe function. */
>> +	rte_vdev_remove_t *remove;     /**< Virtual device remove function. */
>> +};
>> +
>> +/**
>> + * Register a virtual device driver.
>> + *
>> + * @param driver
>> + *   A pointer to a rte_vdev_driver structure describing the driver
>> + *   to be registered.
>> + */
>> +void rte_vdev_register(struct rte_vdev_driver *driver);
>> +
>> +/**
>> + * Unregister a virtual device driver.
>> + *
>> + * @param driver
>> + *   A pointer to a rte_vdev_driver structure describing the driver
>> + *   to be unregistered.
>> + */
>> +void rte_vdev_unregister(struct rte_vdev_driver *driver);
>> +
>> +#define RTE_PMD_REGISTER_VDEV(nm, vdrv)\
>> +RTE_INIT(vdrvinitfn_ ##vdrv);\
>> +static const char *vdrvinit_ ## nm ## _alias;\
>> +static void vdrvinitfn_ ##vdrv(void)\
>> +{\
>> +	(vdrv).driver.name = RTE_STR(nm);\
>> +	(vdrv).driver.alias = vdrvinit_ ## nm ## _alias;\
>> +	rte_vdev_register(&vdrv);\
>> +} \
>> +RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
>> +
>> +#define RTE_PMD_REGISTER_ALIAS(nm, alias)\
>> +static const char *vdrvinit_ ## nm ## _alias = RTE_STR(alias)
>> +
>> +/**
>> + * Initialize a driver specified by name.
>> + *
>> + * @param name
>> + *   The pointer to a driver name to be initialized.
>> + * @param args
>> + *   The pointer to arguments used by driver initialization.
>> + * @return
>> + *  0 on success, negative on error
>> + */
>> +int rte_vdev_init(const char *name, const char *args);
>> +
>> +/**
>> + * Uninitalize a driver specified by name.
>> + *
>> + * @param name
>> + *   The pointer to a driver name to be initialized.
>> + * @return
>> + *  0 on success, negative on error
>> + */
>> +int rte_vdev_uninit(const char *name);
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> +
>> +#endif
>> diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
>> new file mode 100644
>> index 0000000..f7e547a
>> --- /dev/null
>> +++ b/drivers/bus/vdev/vdev.c
>> @@ -0,0 +1,342 @@
>> +/*-
>> + *   BSD LICENSE
>> + *
>> + *   Copyright(c) 2016 RehiveTech. All rights reserved.
>> + *
>> + *   Redistribution and use in source and binary forms, with or without
>> + *   modification, are permitted provided that the following conditions
>> + *   are met:
>> + *
>> + *     * Redistributions of source code must retain the above copyright
>> + *       notice, this list of conditions and the following disclaimer.
>> + *     * Redistributions in binary form must reproduce the above copyright
>> + *       notice, this list of conditions and the following disclaimer in
>> + *       the documentation and/or other materials provided with the
>> + *       distribution.
>> + *     * Neither the name of RehiveTech nor the names of its
>> + *       contributors may be used to endorse or promote products derived
>> + *       from this software without specific prior written permission.
>> + *
>> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> + */
>> +
>> +#include <string.h>
>> +#include <inttypes.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdint.h>
>> +#include <stdbool.h>
>> +#include <sys/queue.h>
>> +
>> +#include <rte_eal.h>
>> +#include <rte_dev.h>
>> +#include <rte_bus.h>
>> +#include <rte_vdev.h>
>> +#include <rte_common.h>
>> +#include <rte_devargs.h>
>> +#include <rte_memory.h>
>> +#include <rte_errno.h>
>> +
>> +/* Forward declare to access virtual bus name */
>> +static struct rte_bus rte_vdev_bus;
>> +
>> +/** Double linked list of virtual device drivers. */
>> +TAILQ_HEAD(vdev_device_list, rte_vdev_device);
>> +
>> +static struct vdev_device_list vdev_device_list =
>> +	TAILQ_HEAD_INITIALIZER(vdev_device_list);
>> +struct vdev_driver_list vdev_driver_list =
>> +	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
>> +
>> +/* register a driver */
>> +void
>> +rte_vdev_register(struct rte_vdev_driver *driver)
>> +{
>> +	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
>> +}
>> +
>> +/* unregister a driver */
>> +void
>> +rte_vdev_unregister(struct rte_vdev_driver *driver)
>> +{
>> +	TAILQ_REMOVE(&vdev_driver_list, driver, next);
>> +}
>> +
>> +static int
>> +vdev_parse(const char *name, void *addr)
>> +{
>> +	struct rte_vdev_driver **out = addr;
>> +	struct rte_vdev_driver *driver = NULL;
>> +
>> +	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
>> +		if (strncmp(driver->driver.name, name,
>> +			    strlen(driver->driver.name)) == 0)
>> +			break;
>> +		if (driver->driver.alias &&
>> +		    strncmp(driver->driver.alias, name,
>> +			    strlen(driver->driver.alias)) == 0)
>> +			break;
>> +	}
>> +	if (driver != NULL &&
>> +	    addr != NULL)
>> +		*out = driver;
>> +	return driver == NULL;
>> +}
>> +
>> +static int
>> +vdev_probe_all_drivers(struct rte_vdev_device *dev)
>> +{
>> +	const char *name;
>> +	struct rte_vdev_driver *driver;
>> +	int ret;
>> +
>> +	name = rte_vdev_device_name(dev);
>> +
>> +	RTE_LOG(DEBUG, EAL, "Search driver %s to probe device %s\n", name,
>> +		rte_vdev_device_name(dev));
>> +
>> +	if (vdev_parse(name, &driver))
>> +		return -1;
>> +	dev->device.driver = &driver->driver;
>> +	ret = driver->probe(dev);
>> +	if (ret)
>> +		dev->device.driver = NULL;
>> +	return ret;
>> +}
>> +
>> +static struct rte_vdev_device *
>> +find_vdev(const char *name)
>> +{
>> +	struct rte_vdev_device *dev;
>> +
>> +	if (!name)
>> +		return NULL;
>> +
>> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> +		const char *devname = rte_vdev_device_name(dev);
>> +		if (!strncmp(devname, name, strlen(name)))
>> +			return dev;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct rte_devargs *
>> +alloc_devargs(const char *name, const char *args)
>> +{
>> +	struct rte_devargs *devargs;
>> +	int ret;
>> +
>> +	devargs = calloc(1, sizeof(*devargs));
>> +	if (!devargs)
>> +		return NULL;
>> +
>> +	devargs->bus = &rte_vdev_bus;
>> +	if (args)
>> +		devargs->args = strdup(args);
>> +	else
>> +		devargs->args = strdup("");
>> +
>> +	ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
>> +	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
>> +		free(devargs->args);
>> +		free(devargs);
>> +		return NULL;
>> +	}
>> +
>> +	return devargs;
>> +}
>> +
>> +int
>> +rte_vdev_init(const char *name, const char *args)
>> +{
>> +	struct rte_vdev_device *dev;
>> +	struct rte_devargs *devargs;
>> +	int ret;
>> +
>> +	if (name == NULL)
>> +		return -EINVAL;
>> +
>> +	dev = find_vdev(name);
>> +	if (dev)
>> +		return -EEXIST;
>> +
>> +	devargs = alloc_devargs(name, args);
>> +	if (!devargs)
>> +		return -ENOMEM;
>> +
>> +	dev = calloc(1, sizeof(*dev));
>> +	if (!dev) {
>> +		ret = -ENOMEM;
>> +		goto fail;
>> +	}
>> +
>> +	dev->device.devargs = devargs;
>> +	dev->device.numa_node = SOCKET_ID_ANY;
>> +	dev->device.name = devargs->name;
>> +
>> +	ret = vdev_probe_all_drivers(dev);
>> +	if (ret) {
>> +		if (ret > 0)
>> +			RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
>> +		goto fail;
>> +	}
>> +
>> +	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
>> +
>> +	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
>> +	return 0;
>> +
>> +fail:
>> +	free(devargs->args);
>> +	free(devargs);
>> +	free(dev);
>> +	return ret;
>> +}
>> +
>> +static int
>> +vdev_remove_driver(struct rte_vdev_device *dev)
>> +{
>> +	const char *name = rte_vdev_device_name(dev);
>> +	const struct rte_vdev_driver *driver;
>> +
>> +	if (!dev->device.driver) {
>> +		RTE_LOG(DEBUG, EAL, "no driver attach to device %s\n", name);
>> +		return 1;
>> +	}
>> +
>> +	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
>> +		driver);
>> +	return driver->remove(dev);
>> +}
>> +
>> +int
>> +rte_vdev_uninit(const char *name)
>> +{
>> +	struct rte_vdev_device *dev;
>> +	struct rte_devargs *devargs;
>> +	int ret;
>> +
>> +	if (name == NULL)
>> +		return -EINVAL;
>> +
>> +	dev = find_vdev(name);
>> +	if (!dev)
>> +		return -ENOENT;
>> +
>> +	devargs = dev->device.devargs;
>> +
>> +	ret = vdev_remove_driver(dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	TAILQ_REMOVE(&vdev_device_list, dev, next);
>> +
>> +	TAILQ_REMOVE(&devargs_list, devargs, next);
>> +
>> +	free(devargs->args);
>> +	free(devargs);
>> +	free(dev);
>> +	return 0;
>> +}
>> +
>> +static int
>> +vdev_scan(void)
>> +{
>> +	struct rte_vdev_device *dev;
>> +	struct rte_devargs *devargs;
>> +
>> +	/* for virtual devices we scan the devargs_list populated via cmdline */
>> +	TAILQ_FOREACH(devargs, &devargs_list, next) {
>> +
>> +		if (devargs->bus != &rte_vdev_bus)
>> +			continue;
>> +
>> +		dev = find_vdev(devargs->name);
>> +		if (dev)
>> +			continue;
>> +
>> +		dev = calloc(1, sizeof(*dev));
>> +		if (!dev)
>> +			return -1;
>> +
>> +		dev->device.devargs = devargs;
>> +		dev->device.numa_node = SOCKET_ID_ANY;
>> +		dev->device.name = devargs->name;
>> +
>> +		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +vdev_probe(void)
>> +{
>> +	struct rte_vdev_device *dev;
>> +
>> +	/* call the init function for each virtual device */
>> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> +
>> +		if (dev->device.driver)
>> +			continue;
>> +
>> +		if (vdev_probe_all_drivers(dev)) {
>> +			RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
>> +				rte_vdev_device_name(dev));
>> +			return -1;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct rte_device *
>> +vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
>> +		 const void *data)
>> +{
>> +	struct rte_vdev_device *dev;
>> +
>> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> +		if (start && &dev->device == start) {
>> +			start = NULL;
>> +			continue;
>> +		}
>> +		if (cmp(&dev->device, data) == 0)
>> +			return &dev->device;
>> +	}
>> +	return NULL;
>> +}
>> +
>> +static int
>> +vdev_plug(struct rte_device *dev)
>> +{
>> +	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
>> +}
>> +
>> +static int
>> +vdev_unplug(struct rte_device *dev)
>> +{
>> +	return rte_vdev_uninit(dev->name);
>> +}
>> +
>> +static struct rte_bus rte_vdev_bus = {
>> +	.scan = vdev_scan,
>> +	.probe = vdev_probe,
>> +	.find_device = vdev_find_device,
>> +	.plug = vdev_plug,
>> +	.unplug = vdev_unplug,
>> +	.parse = vdev_parse,
>> +};
>> +
>> +RTE_REGISTER_BUS(vdev, rte_vdev_bus);
>> diff --git a/lib/librte_cryptodev/Makefile b/lib/librte_cryptodev/Makefile
>> index 301c78d..4f70719 100644
>> --- a/lib/librte_cryptodev/Makefile
>> +++ b/lib/librte_cryptodev/Makefile
>> @@ -42,14 +42,12 @@ CFLAGS += $(WERROR_FLAGS)
>>   
>>   # library source files
>>   SRCS-y += rte_cryptodev.c rte_cryptodev_pmd.c
>> -SRCS-y += rte_cryptodev_vdev.c
>>   
>>   # export include files
>>   SYMLINK-y-include += rte_crypto.h
>>   SYMLINK-y-include += rte_crypto_sym.h
>>   SYMLINK-y-include += rte_cryptodev.h
>>   SYMLINK-y-include += rte_cryptodev_pmd.h
>> -SYMLINK-y-include += rte_cryptodev_vdev.h
>>   SYMLINK-y-include += rte_cryptodev_pci.h
>>   
>>   # versioning export map
>> diff --git a/lib/librte_cryptodev/rte_cryptodev_vdev.c b/lib/librte_cryptodev/rte_cryptodev_vdev.c
>> deleted file mode 100644
>> index fd308b4..0000000
>> --- a/lib/librte_cryptodev/rte_cryptodev_vdev.c
>> +++ /dev/null
>> @@ -1,154 +0,0 @@
>> -/*-
>> - *   BSD LICENSE
>> - *
>> - *   Copyright(c) 2017 Intel Corporation. All rights reserved.
>> - *
>> - *   Redistribution and use in source and binary forms, with or without
>> - *   modification, are permitted provided that the following conditions
>> - *   are met:
>> - *
>> - *     * Redistributions of source code must retain the above copyright
>> - *       notice, this list of conditions and the following disclaimer.
>> - *     * Redistributions in binary form must reproduce the above copyright
>> - *       notice, this list of conditions and the following disclaimer in
>> - *       the documentation and/or other materials provided with the
>> - *       distribution.
>> - *     * Neither the name of the copyright holder nor the names of its
>> - *       contributors may be used to endorse or promote products derived
>> - *       from this software without specific prior written permission.
>> - *
>> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> - */
>> -
>> -#include "rte_cryptodev_vdev.h"
>> -#include "rte_cryptodev_pci.h"
>> -#include "rte_cryptodev_pmd.h"
>> -
>> -/**
>> - * Parse name from argument
>> - */
>> -static int
>> -rte_cryptodev_vdev_parse_name_arg(const char *key __rte_unused,
>> -		const char *value, void *extra_args)
>> -{
>> -	struct rte_crypto_vdev_init_params *params = extra_args;
>> -
>> -	if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
>> -		CDEV_LOG_ERR("Invalid name %s, should be less than "
>> -				"%u bytes", value,
>> -				RTE_CRYPTODEV_NAME_MAX_LEN - 1);
>> -		return -1;
>> -	}
>> -
>> -	strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
>> -
>> -	return 0;
>> -}
>> -
>> -/**
>> - * Parse integer from argument
>> - */
>> -static int
>> -rte_cryptodev_vdev_parse_integer_arg(const char *key __rte_unused,
>> -		const char *value, void *extra_args)
>> -{
>> -	int *i = extra_args;
>> -
>> -	*i = atoi(value);
>> -	if (*i < 0) {
>> -		CDEV_LOG_ERR("Argument has to be positive.");
>> -		return -1;
>> -	}
>> -
>> -	return 0;
>> -}
>> -
>> -struct rte_cryptodev *
>> -rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
>> -		int socket_id, struct rte_vdev_device *vdev)
>> -{
>> -	struct rte_cryptodev *cryptodev;
>> -
>> -	/* allocate device structure */
>> -	cryptodev = rte_cryptodev_pmd_allocate(name, socket_id);
>> -	if (cryptodev == NULL)
>> -		return NULL;
>> -
>> -	/* allocate private device structure */
>> -	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>> -		cryptodev->data->dev_private =
>> -				rte_zmalloc_socket("cryptodev device private",
>> -						dev_private_size,
>> -						RTE_CACHE_LINE_SIZE,
>> -						socket_id);
>> -
>> -		if (cryptodev->data->dev_private == NULL)
>> -			rte_panic("Cannot allocate memzone for private device"
>> -					" data");
>> -	}
>> -
>> -	cryptodev->device = &vdev->device;
>> -
>> -	/* initialise user call-back tail queue */
>> -	TAILQ_INIT(&(cryptodev->link_intr_cbs));
>> -
>> -	return cryptodev;
>> -}
>> -
>> -int
>> -rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
>> -		const char *input_args)
>> -{
>> -	struct rte_kvargs *kvlist = NULL;
>> -	int ret = 0;
>> -
>> -	if (params == NULL)
>> -		return -EINVAL;
>> -
>> -	if (input_args) {
>> -		kvlist = rte_kvargs_parse(input_args,
>> -				cryptodev_vdev_valid_params);
>> -		if (kvlist == NULL)
>> -			return -1;
>> -
>> -		ret = rte_kvargs_process(kvlist,
>> -					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
>> -					&rte_cryptodev_vdev_parse_integer_arg,
>> -					&params->max_nb_queue_pairs);
>> -		if (ret < 0)
>> -			goto free_kvlist;
>> -
>> -		ret = rte_kvargs_process(kvlist,
>> -					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
>> -					&rte_cryptodev_vdev_parse_integer_arg,
>> -					&params->max_nb_sessions);
>> -		if (ret < 0)
>> -			goto free_kvlist;
>> -
>> -		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
>> -					&rte_cryptodev_vdev_parse_integer_arg,
>> -					&params->socket_id);
>> -		if (ret < 0)
>> -			goto free_kvlist;
>> -
>> -		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
>> -					&rte_cryptodev_vdev_parse_name_arg,
>> -					params);
>> -		if (ret < 0)
>> -			goto free_kvlist;
>> -	}
>> -
>> -free_kvlist:
>> -	rte_kvargs_free(kvlist);
>> -	return ret;
>> -}
>> diff --git a/lib/librte_cryptodev/rte_cryptodev_vdev.h b/lib/librte_cryptodev/rte_cryptodev_vdev.h
>> deleted file mode 100644
>> index 94ab9d3..0000000
>> --- a/lib/librte_cryptodev/rte_cryptodev_vdev.h
>> +++ /dev/null
>> @@ -1,100 +0,0 @@
>> -/*-
>> - *   BSD LICENSE
>> - *
>> - *   Copyright(c) 2017 Intel Corporation. All rights reserved.
>> - *
>> - *   Redistribution and use in source and binary forms, with or without
>> - *   modification, are permitted provided that the following conditions
>> - *   are met:
>> - *
>> - *     * Redistributions of source code must retain the above copyright
>> - *       notice, this list of conditions and the following disclaimer.
>> - *     * Redistributions in binary form must reproduce the above copyright
>> - *       notice, this list of conditions and the following disclaimer in
>> - *       the documentation and/or other materials provided with the
>> - *       distribution.
>> - *     * Neither the name of the copyright holder nor the names of its
>> - *       contributors may be used to endorse or promote products derived
>> - *       from this software without specific prior written permission.
>> - *
>> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> - */
>> -
>> -#ifndef _RTE_CRYPTODEV_VDEV_H_
>> -#define _RTE_CRYPTODEV_VDEV_H_
>> -
>> -#include <rte_vdev.h>
>> -#include <inttypes.h>
>> -
>> -#include "rte_cryptodev.h"
>> -
>> -#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
>> -#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
>> -
>> -#define RTE_CRYPTODEV_VDEV_NAME				("name")
>> -#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
>> -#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
>> -#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
>> -
>> -static const char * const cryptodev_vdev_valid_params[] = {
>> -	RTE_CRYPTODEV_VDEV_NAME,
>> -	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
>> -	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
>> -	RTE_CRYPTODEV_VDEV_SOCKET_ID
>> -};
>> -
>> -/**
>> - * @internal
>> - * Initialisation parameters for virtual crypto devices
>> - */
>> -struct rte_crypto_vdev_init_params {
>> -	unsigned int max_nb_queue_pairs;
>> -	unsigned int max_nb_sessions;
>> -	uint8_t socket_id;
>> -	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
>> -};
>> -
>> -/**
>> - * @internal
>> - * Creates a new virtual crypto device and returns the pointer
>> - * to that device.
>> - *
>> - * @param	name			PMD type name
>> - * @param	dev_private_size	Size of crypto PMDs private data
>> - * @param	socket_id		Socket to allocate resources on.
>> - * @param	vdev			Pointer to virtual device structure.
>> - *
>> - * @return
>> - *   - Cryptodev pointer if device is successfully created.
>> - *   - NULL if device cannot be created.
>> - */
>> -struct rte_cryptodev *
>> -rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
>> -		int socket_id, struct rte_vdev_device *vdev);
>> -
>> -/**
>> - * @internal
>> - * Parse virtual device initialisation parameters input arguments
>> - *
>> - * @params	params		Initialisation parameters with defaults set.
>> - * @params	input_args	Command line arguments
>> - *
>> - * @return
>> - * 0 on successful parse
>> - * <0 on failure to parse
>> - */
>> -int
>> -rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
>> -		const char *input_args);
>> -
>> -#endif /* _RTE_CRYPTODEV_VDEV_H_ */
>> diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
>> index 005019e..6fee587 100644
>> --- a/lib/librte_eal/bsdapp/eal/Makefile
>> +++ b/lib/librte_eal/bsdapp/eal/Makefile
>> @@ -68,7 +68,6 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_timer.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memzone.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_log.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_launch.c
>> -SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_vdev.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_pci.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_pci_uio.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memory.c
>> diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
>> index e8fd67a..7eeb06a 100644
>> --- a/lib/librte_eal/common/Makefile
>> +++ b/lib/librte_eal/common/Makefile
>> @@ -38,7 +38,7 @@ INC += rte_per_lcore.h rte_random.h
>>   INC += rte_tailq.h rte_interrupts.h rte_alarm.h
>>   INC += rte_string_fns.h rte_version.h
>>   INC += rte_eal_memconfig.h rte_malloc_heap.h
>> -INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
>> +INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
>>   INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
>>   INC += rte_malloc.h rte_keepalive.h rte_time.h
>>   INC += rte_service.h rte_service_component.h
>> diff --git a/lib/librte_eal/common/eal_common_vdev.c b/lib/librte_eal/common/eal_common_vdev.c
>> deleted file mode 100644
>> index f7e547a..0000000
>> --- a/lib/librte_eal/common/eal_common_vdev.c
>> +++ /dev/null
>> @@ -1,342 +0,0 @@
>> -/*-
>> - *   BSD LICENSE
>> - *
>> - *   Copyright(c) 2016 RehiveTech. All rights reserved.
>> - *
>> - *   Redistribution and use in source and binary forms, with or without
>> - *   modification, are permitted provided that the following conditions
>> - *   are met:
>> - *
>> - *     * Redistributions of source code must retain the above copyright
>> - *       notice, this list of conditions and the following disclaimer.
>> - *     * Redistributions in binary form must reproduce the above copyright
>> - *       notice, this list of conditions and the following disclaimer in
>> - *       the documentation and/or other materials provided with the
>> - *       distribution.
>> - *     * Neither the name of RehiveTech nor the names of its
>> - *       contributors may be used to endorse or promote products derived
>> - *       from this software without specific prior written permission.
>> - *
>> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> - */
>> -
>> -#include <string.h>
>> -#include <inttypes.h>
>> -#include <stdio.h>
>> -#include <stdlib.h>
>> -#include <stdint.h>
>> -#include <stdbool.h>
>> -#include <sys/queue.h>
>> -
>> -#include <rte_eal.h>
>> -#include <rte_dev.h>
>> -#include <rte_bus.h>
>> -#include <rte_vdev.h>
>> -#include <rte_common.h>
>> -#include <rte_devargs.h>
>> -#include <rte_memory.h>
>> -#include <rte_errno.h>
>> -
>> -/* Forward declare to access virtual bus name */
>> -static struct rte_bus rte_vdev_bus;
>> -
>> -/** Double linked list of virtual device drivers. */
>> -TAILQ_HEAD(vdev_device_list, rte_vdev_device);
>> -
>> -static struct vdev_device_list vdev_device_list =
>> -	TAILQ_HEAD_INITIALIZER(vdev_device_list);
>> -struct vdev_driver_list vdev_driver_list =
>> -	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
>> -
>> -/* register a driver */
>> -void
>> -rte_vdev_register(struct rte_vdev_driver *driver)
>> -{
>> -	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
>> -}
>> -
>> -/* unregister a driver */
>> -void
>> -rte_vdev_unregister(struct rte_vdev_driver *driver)
>> -{
>> -	TAILQ_REMOVE(&vdev_driver_list, driver, next);
>> -}
>> -
>> -static int
>> -vdev_parse(const char *name, void *addr)
>> -{
>> -	struct rte_vdev_driver **out = addr;
>> -	struct rte_vdev_driver *driver = NULL;
>> -
>> -	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
>> -		if (strncmp(driver->driver.name, name,
>> -			    strlen(driver->driver.name)) == 0)
>> -			break;
>> -		if (driver->driver.alias &&
>> -		    strncmp(driver->driver.alias, name,
>> -			    strlen(driver->driver.alias)) == 0)
>> -			break;
>> -	}
>> -	if (driver != NULL &&
>> -	    addr != NULL)
>> -		*out = driver;
>> -	return driver == NULL;
>> -}
>> -
>> -static int
>> -vdev_probe_all_drivers(struct rte_vdev_device *dev)
>> -{
>> -	const char *name;
>> -	struct rte_vdev_driver *driver;
>> -	int ret;
>> -
>> -	name = rte_vdev_device_name(dev);
>> -
>> -	RTE_LOG(DEBUG, EAL, "Search driver %s to probe device %s\n", name,
>> -		rte_vdev_device_name(dev));
>> -
>> -	if (vdev_parse(name, &driver))
>> -		return -1;
>> -	dev->device.driver = &driver->driver;
>> -	ret = driver->probe(dev);
>> -	if (ret)
>> -		dev->device.driver = NULL;
>> -	return ret;
>> -}
>> -
>> -static struct rte_vdev_device *
>> -find_vdev(const char *name)
>> -{
>> -	struct rte_vdev_device *dev;
>> -
>> -	if (!name)
>> -		return NULL;
>> -
>> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> -		const char *devname = rte_vdev_device_name(dev);
>> -		if (!strncmp(devname, name, strlen(name)))
>> -			return dev;
>> -	}
>> -
>> -	return NULL;
>> -}
>> -
>> -static struct rte_devargs *
>> -alloc_devargs(const char *name, const char *args)
>> -{
>> -	struct rte_devargs *devargs;
>> -	int ret;
>> -
>> -	devargs = calloc(1, sizeof(*devargs));
>> -	if (!devargs)
>> -		return NULL;
>> -
>> -	devargs->bus = &rte_vdev_bus;
>> -	if (args)
>> -		devargs->args = strdup(args);
>> -	else
>> -		devargs->args = strdup("");
>> -
>> -	ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
>> -	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
>> -		free(devargs->args);
>> -		free(devargs);
>> -		return NULL;
>> -	}
>> -
>> -	return devargs;
>> -}
>> -
>> -int
>> -rte_vdev_init(const char *name, const char *args)
>> -{
>> -	struct rte_vdev_device *dev;
>> -	struct rte_devargs *devargs;
>> -	int ret;
>> -
>> -	if (name == NULL)
>> -		return -EINVAL;
>> -
>> -	dev = find_vdev(name);
>> -	if (dev)
>> -		return -EEXIST;
>> -
>> -	devargs = alloc_devargs(name, args);
>> -	if (!devargs)
>> -		return -ENOMEM;
>> -
>> -	dev = calloc(1, sizeof(*dev));
>> -	if (!dev) {
>> -		ret = -ENOMEM;
>> -		goto fail;
>> -	}
>> -
>> -	dev->device.devargs = devargs;
>> -	dev->device.numa_node = SOCKET_ID_ANY;
>> -	dev->device.name = devargs->name;
>> -
>> -	ret = vdev_probe_all_drivers(dev);
>> -	if (ret) {
>> -		if (ret > 0)
>> -			RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
>> -		goto fail;
>> -	}
>> -
>> -	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
>> -
>> -	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
>> -	return 0;
>> -
>> -fail:
>> -	free(devargs->args);
>> -	free(devargs);
>> -	free(dev);
>> -	return ret;
>> -}
>> -
>> -static int
>> -vdev_remove_driver(struct rte_vdev_device *dev)
>> -{
>> -	const char *name = rte_vdev_device_name(dev);
>> -	const struct rte_vdev_driver *driver;
>> -
>> -	if (!dev->device.driver) {
>> -		RTE_LOG(DEBUG, EAL, "no driver attach to device %s\n", name);
>> -		return 1;
>> -	}
>> -
>> -	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
>> -		driver);
>> -	return driver->remove(dev);
>> -}
>> -
>> -int
>> -rte_vdev_uninit(const char *name)
>> -{
>> -	struct rte_vdev_device *dev;
>> -	struct rte_devargs *devargs;
>> -	int ret;
>> -
>> -	if (name == NULL)
>> -		return -EINVAL;
>> -
>> -	dev = find_vdev(name);
>> -	if (!dev)
>> -		return -ENOENT;
>> -
>> -	devargs = dev->device.devargs;
>> -
>> -	ret = vdev_remove_driver(dev);
>> -	if (ret)
>> -		return ret;
>> -
>> -	TAILQ_REMOVE(&vdev_device_list, dev, next);
>> -
>> -	TAILQ_REMOVE(&devargs_list, devargs, next);
>> -
>> -	free(devargs->args);
>> -	free(devargs);
>> -	free(dev);
>> -	return 0;
>> -}
>> -
>> -static int
>> -vdev_scan(void)
>> -{
>> -	struct rte_vdev_device *dev;
>> -	struct rte_devargs *devargs;
>> -
>> -	/* for virtual devices we scan the devargs_list populated via cmdline */
>> -	TAILQ_FOREACH(devargs, &devargs_list, next) {
>> -
>> -		if (devargs->bus != &rte_vdev_bus)
>> -			continue;
>> -
>> -		dev = find_vdev(devargs->name);
>> -		if (dev)
>> -			continue;
>> -
>> -		dev = calloc(1, sizeof(*dev));
>> -		if (!dev)
>> -			return -1;
>> -
>> -		dev->device.devargs = devargs;
>> -		dev->device.numa_node = SOCKET_ID_ANY;
>> -		dev->device.name = devargs->name;
>> -
>> -		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
>> -	}
>> -
>> -	return 0;
>> -}
>> -
>> -static int
>> -vdev_probe(void)
>> -{
>> -	struct rte_vdev_device *dev;
>> -
>> -	/* call the init function for each virtual device */
>> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> -
>> -		if (dev->device.driver)
>> -			continue;
>> -
>> -		if (vdev_probe_all_drivers(dev)) {
>> -			RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
>> -				rte_vdev_device_name(dev));
>> -			return -1;
>> -		}
>> -	}
>> -
>> -	return 0;
>> -}
>> -
>> -static struct rte_device *
>> -vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
>> -		 const void *data)
>> -{
>> -	struct rte_vdev_device *dev;
>> -
>> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
>> -		if (start && &dev->device == start) {
>> -			start = NULL;
>> -			continue;
>> -		}
>> -		if (cmp(&dev->device, data) == 0)
>> -			return &dev->device;
>> -	}
>> -	return NULL;
>> -}
>> -
>> -static int
>> -vdev_plug(struct rte_device *dev)
>> -{
>> -	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
>> -}
>> -
>> -static int
>> -vdev_unplug(struct rte_device *dev)
>> -{
>> -	return rte_vdev_uninit(dev->name);
>> -}
>> -
>> -static struct rte_bus rte_vdev_bus = {
>> -	.scan = vdev_scan,
>> -	.probe = vdev_probe,
>> -	.find_device = vdev_find_device,
>> -	.plug = vdev_plug,
>> -	.unplug = vdev_unplug,
>> -	.parse = vdev_parse,
>> -};
>> -
>> -RTE_REGISTER_BUS(vdev, rte_vdev_bus);
>> diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
>> index 5386d3a..8bfc343 100644
>> --- a/lib/librte_eal/common/include/rte_dev.h
>> +++ b/lib/librte_eal/common/include/rte_dev.h
>> @@ -166,28 +166,6 @@ struct rte_device {
>>   };
>>   
>>   /**
>> - * Initialize a driver specified by name.
>> - *
>> - * @param name
>> - *   The pointer to a driver name to be initialized.
>> - * @param args
>> - *   The pointer to arguments used by driver initialization.
>> - * @return
>> - *  0 on success, negative on error
>> - */
>> -int rte_vdev_init(const char *name, const char *args);
>> -
>> -/**
>> - * Uninitalize a driver specified by name.
>> - *
>> - * @param name
>> - *   The pointer to a driver name to be initialized.
>> - * @return
>> - *  0 on success, negative on error
>> - */
>> -int rte_vdev_uninit(const char *name);
>> -
>> -/**
>>    * Attach a device to a registered driver.
>>    *
>>    * @param name
>> @@ -312,4 +290,4 @@ __attribute__((used)) = str
>>   }
>>   #endif
>>   
>> -#endif /* _RTE_VDEV_H_ */
>> +#endif /* _RTE_DEV_H_ */
>> diff --git a/lib/librte_eal/common/include/rte_vdev.h b/lib/librte_eal/common/include/rte_vdev.h
>> deleted file mode 100644
>> index 29f5a52..0000000
>> --- a/lib/librte_eal/common/include/rte_vdev.h
>> +++ /dev/null
>> @@ -1,131 +0,0 @@
>> -/*-
>> - *   BSD LICENSE
>> - *
>> - *   Copyright(c) 2016 RehiveTech. All rights reserved.
>> - *
>> - *   Redistribution and use in source and binary forms, with or without
>> - *   modification, are permitted provided that the following conditions
>> - *   are met:
>> - *
>> - *     * Redistributions of source code must retain the above copyright
>> - *       notice, this list of conditions and the following disclaimer.
>> - *     * Redistributions in binary form must reproduce the above copyright
>> - *       notice, this list of conditions and the following disclaimer in
>> - *       the documentation and/or other materials provided with the
>> - *       distribution.
>> - *     * Neither the name of RehiveTech nor the names of its
>> - *       contributors may be used to endorse or promote products derived
>> - *       from this software without specific prior written permission.
>> - *
>> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
>> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
>> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
>> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
>> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
>> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>> - */
>> -
>> -#ifndef RTE_VDEV_H
>> -#define RTE_VDEV_H
>> -
>> -#ifdef __cplusplus
>> -extern "C" {
>> -#endif
>> -
>> -#include <sys/queue.h>
>> -#include <rte_dev.h>
>> -#include <rte_devargs.h>
>> -
>> -struct rte_vdev_device {
>> -	TAILQ_ENTRY(rte_vdev_device) next;      /**< Next attached vdev */
>> -	struct rte_device device;               /**< Inherit core device */
>> -};
>> -
>> -/**
>> - * @internal
>> - * Helper macro for drivers that need to convert to struct rte_vdev_device.
>> - */
>> -#define RTE_DEV_TO_VDEV(ptr) \
>> -	container_of(ptr, struct rte_vdev_device, device)
>> -
>> -static inline const char *
>> -rte_vdev_device_name(const struct rte_vdev_device *dev)
>> -{
>> -	if (dev && dev->device.name)
>> -		return dev->device.name;
>> -	return NULL;
>> -}
>> -
>> -static inline const char *
>> -rte_vdev_device_args(const struct rte_vdev_device *dev)
>> -{
>> -	if (dev && dev->device.devargs)
>> -		return dev->device.devargs->args;
>> -	return "";
>> -}
>> -
>> -/** Double linked list of virtual device drivers. */
>> -TAILQ_HEAD(vdev_driver_list, rte_vdev_driver);
>> -
>> -/**
>> - * Probe function called for each virtual device driver once.
>> - */
>> -typedef int (rte_vdev_probe_t)(struct rte_vdev_device *dev);
>> -
>> -/**
>> - * Remove function called for each virtual device driver once.
>> - */
>> -typedef int (rte_vdev_remove_t)(struct rte_vdev_device *dev);
>> -
>> -/**
>> - * A virtual device driver abstraction.
>> - */
>> -struct rte_vdev_driver {
>> -	TAILQ_ENTRY(rte_vdev_driver) next; /**< Next in list. */
>> -	struct rte_driver driver;      /**< Inherited general driver. */
>> -	rte_vdev_probe_t *probe;       /**< Virtual device probe function. */
>> -	rte_vdev_remove_t *remove;     /**< Virtual device remove function. */
>> -};
>> -
>> -/**
>> - * Register a virtual device driver.
>> - *
>> - * @param driver
>> - *   A pointer to a rte_vdev_driver structure describing the driver
>> - *   to be registered.
>> - */
>> -void rte_vdev_register(struct rte_vdev_driver *driver);
>> -
>> -/**
>> - * Unregister a virtual device driver.
>> - *
>> - * @param driver
>> - *   A pointer to a rte_vdev_driver structure describing the driver
>> - *   to be unregistered.
>> - */
>> -void rte_vdev_unregister(struct rte_vdev_driver *driver);
>> -
>> -#define RTE_PMD_REGISTER_VDEV(nm, vdrv)\
>> -RTE_INIT(vdrvinitfn_ ##vdrv);\
>> -static const char *vdrvinit_ ## nm ## _alias;\
>> -static void vdrvinitfn_ ##vdrv(void)\
>> -{\
>> -	(vdrv).driver.name = RTE_STR(nm);\
>> -	(vdrv).driver.alias = vdrvinit_ ## nm ## _alias;\
>> -	rte_vdev_register(&vdrv);\
>> -} \
>> -RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
>> -
>> -#define RTE_PMD_REGISTER_ALIAS(nm, alias)\
>> -static const char *vdrvinit_ ## nm ## _alias = RTE_STR(alias)
>> -
>> -#ifdef __cplusplus
>> -}
>> -#endif
>> -
>> -#endif
>> diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
>> index 90bca4d..33faa18 100644
>> --- a/lib/librte_eal/linuxapp/eal/Makefile
>> +++ b/lib/librte_eal/linuxapp/eal/Makefile
>> @@ -80,7 +80,6 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_timer.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memzone.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_log.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_launch.c
>> -SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_vdev.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci_uio.c
>>   SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memory.c
>> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
>> index c25fdd9..c423bf8 100644
>> --- a/mk/rte.app.mk
>> +++ b/mk/rte.app.mk
>> @@ -97,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>>   _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>>   _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
>>   _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
>> +_LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV)           += -lrte_bus_vdev
>>   _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
>>   _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
>>   
>> -- 
>> 2.7.4
>>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-techboard]  next techboard meeting (29th, August)
  2017-08-28 15:04  3% ` Bruce Richardson
@ 2017-08-29 15:30  0%   ` Jerin Jacob
  0 siblings, 0 replies; 200+ results
From: Jerin Jacob @ 2017-08-29 15:30 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: techboard, dev

-----Original Message-----
> Date: Mon, 28 Aug 2017 16:04:10 +0100
> From: Bruce Richardson <bruce.richardson@intel.com>
> To: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> CC: techboard@dpdk.org, dev@dpdk.org
> Subject: Re: [dpdk-techboard]  next techboard meeting (29th, August)
> User-Agent: Mutt/1.8.3 (2017-05-23)
> 
> On Sun, Aug 27, 2017 at 06:54:35PM +0530, Jerin Jacob wrote:
> > Hi All,
> > 
> > The next meeting of the tech board will happen on IRC #dpdk-board, at 3pm UTC, on 29th of August(Tuesday)
> > 
> > Agenda:
> > 
> > 1) Discussion on next tree requests
> > a) Next tree for IPSec offload and maintainership
> > http://dpdk.org/ml/archives/dev/2017-August/072995.html
> > b) Next tree for cli
> > http://dpdk.org/ml/archives/dev/2017-August/073343.html
> > 
> > 2) Approval of a policy for changes to the minimum DPDK requirements.
> > e.g. like what was done with bumping IA min to SSE4.2 in last release.
> > 
> 
> Proposal for a policy for this item, so as to hopefully speed up the
> discussion at the meeting:
> 
> * Updates to the minimum HW requirements, i.e. those dropping support for
>   hardware which was previously supported, should be treated as an ABI
>   change, and follow that deprecation policy. Specifically:
>   - change announced at least one release in advance
>   - patches removing support for the older hardware should have at least
>     three ACKs before being applied.


The meeting got canceled due to lack of quorum. Scheduled Again for
tomorrow at the same time.

/Jerin

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
                     ` (2 preceding siblings ...)
  2017-08-29 12:50  0%   ` Ferruh Yigit
@ 2017-08-29 13:11  0%   ` Ferruh Yigit
  3 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2017-08-29 13:11 UTC (permalink / raw)
  To: Shahaf Shuler, dev

On 8/7/2017 11:54 AM, Shahaf Shuler wrote:
> Introduce a new API to configure Rx offloads.
> 
> The new API will re-use existing DEV_RX_OFFLOAD_* flags
> to enable the different offloads. This will ease the process
> of adding a new Rx offloads, as no ABI breakage is involved.
> In addition, the offload configuration can be done per queue,
> instead of per port.
> 
> The Rx queue offload API can be used only with devices which advertize
> the RTE_ETH_DEV_RXQ_OFFLOAD capability.
> 
> The old Rx offloads API is kept for the meanwhile, in order to enable a
> smooth transition for PMDs and application to the new API.
> 
> Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>

<...>

>  /**
> @@ -691,6 +698,12 @@ struct rte_eth_rxq_conf {
>  	uint16_t rx_free_thresh; /**< Drives the freeing of RX descriptors. */
>  	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
>  	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
> +	uint64_t offloads;

Also there is a documentation aims to help PMDs on developing features
[1], currently for Rx offload features it documents rxmode fields as to
be used.

Can you please update that document too, according new API, new field to
use, both for Rx and Tx.

[1]
doc/guides/nics/features.rst

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 04/12] vdev: move to drivers/bus
  @ 2017-08-29 13:04  3%   ` Gaëtan Rivet
  2017-08-29 22:47  0%     ` Tan, Jianfeng
  0 siblings, 1 reply; 200+ results
From: Gaëtan Rivet @ 2017-08-29 13:04 UTC (permalink / raw)
  To: Jianfeng Tan
  Cc: dev, bruce.richardson, konstantin.ananyev, pablo.de.lara.guarch,
	thomas, yliu, maxime.coquelin, mtetsuyah, ferruh.yigit

On Fri, Aug 25, 2017 at 09:40:44AM +0000, Jianfeng Tan wrote:
> Move the vdev bus from lib/librte_eal to drivers/bus.
> 
> As the crypto vdev helper function refers to data structure
> in rte_vdev.h, so we move those helper function into drivers/bus
> too.
> 
> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
> ---
>  config/common_base                        |   5 +
>  drivers/bus/Makefile                      |   2 +
>  drivers/bus/vdev/Makefile                 |  57 +++++
>  drivers/bus/vdev/rte_bus_vdev_version.map |  10 +
>  drivers/bus/vdev/rte_cryptodev_vdev.c     | 154 ++++++++++++++
>  drivers/bus/vdev/rte_cryptodev_vdev.h     | 100 +++++++++
>  drivers/bus/vdev/rte_vdev.h               | 153 +++++++++++++
>  drivers/bus/vdev/vdev.c                   | 342 ++++++++++++++++++++++++++++++
>  lib/librte_cryptodev/Makefile             |   2 -
>  lib/librte_cryptodev/rte_cryptodev_vdev.c | 154 --------------
>  lib/librte_cryptodev/rte_cryptodev_vdev.h | 100 ---------
>  lib/librte_eal/bsdapp/eal/Makefile        |   1 -
>  lib/librte_eal/common/Makefile            |   2 +-
>  lib/librte_eal/common/eal_common_vdev.c   | 342 ------------------------------
>  lib/librte_eal/common/include/rte_dev.h   |  24 +--
>  lib/librte_eal/common/include/rte_vdev.h  | 131 ------------
>  lib/librte_eal/linuxapp/eal/Makefile      |   1 -
>  mk/rte.app.mk                             |   1 +
>  18 files changed, 826 insertions(+), 755 deletions(-)
>  create mode 100644 drivers/bus/vdev/Makefile
>  create mode 100644 drivers/bus/vdev/rte_bus_vdev_version.map
>  create mode 100644 drivers/bus/vdev/rte_cryptodev_vdev.c
>  create mode 100644 drivers/bus/vdev/rte_cryptodev_vdev.h
>  create mode 100644 drivers/bus/vdev/rte_vdev.h
>  create mode 100644 drivers/bus/vdev/vdev.c
>  delete mode 100644 lib/librte_cryptodev/rte_cryptodev_vdev.c
>  delete mode 100644 lib/librte_cryptodev/rte_cryptodev_vdev.h
>  delete mode 100644 lib/librte_eal/common/eal_common_vdev.c
>  delete mode 100644 lib/librte_eal/common/include/rte_vdev.h
> 
> diff --git a/config/common_base b/config/common_base
> index 5e97a08..aca0994 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -750,3 +750,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y
>  # Compile the eventdev application
>  #
>  CONFIG_RTE_APP_EVENTDEV=y
> +
> +#
> +# Compile the vdev bus
> +#
> +CONFIG_RTE_LIBRTE_VDEV=y

Why not CONFIG_RTE_LIBRTE_VDEV_BUS?
It would seem more consistent.

> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
> index 0224214..9b6d45e 100644
> --- a/drivers/bus/Makefile
> +++ b/drivers/bus/Makefile
> @@ -35,4 +35,6 @@ core-libs := librte_eal librte_mbuf librte_mempool librte_ring librte_ether
>  DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc
>  DEPDIRS-fslmc = $(core-libs)
>  
> +DIRS-$(CONFIG_RTE_LIBRTE_VDEV) += vdev
> +
>  include $(RTE_SDK)/mk/rte.subdir.mk
> diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
> new file mode 100644
> index 0000000..30c4813
> --- /dev/null
> +++ b/drivers/bus/vdev/Makefile
> @@ -0,0 +1,57 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2017 Intel Corporation. All rights reserved.
> +#   All rights reserved.
> +#
> +#   Redistribution and use in source and binary forms, with or without
> +#   modification, are permitted provided that the following conditions
> +#   are met:
> +#
> +#     * Redistributions of source code must retain the above copyright
> +#       notice, this list of conditions and the following disclaimer.
> +#     * Redistributions in binary form must reproduce the above copyright
> +#       notice, this list of conditions and the following disclaimer in
> +#       the documentation and/or other materials provided with the
> +#       distribution.
> +#     * Neither the name of Intel Corporation nor the names of its
> +#       contributors may be used to endorse or promote products derived
> +#       from this software without specific prior written permission.
> +#
> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_bus_vdev.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +# versioning export map
> +EXPORT_MAP := rte_bus_vdev_version.map
> +
> +# library version
> +LIBABIVER := 1
> +
> +SRCS-y += vdev.c
> +SRCS-y += rte_cryptodev_vdev.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include += rte_vdev.h
> +SYMLINK-y-include += rte_cryptodev_vdev.h
> +

Let's say the cryptodev lib must be updated.
I understand the need to move rte_cryptodev_vdev.h outside
librte_cryptodev, but I guess this exposes the vdev bus to ABI / API
instability due to a third-party subsystem?

I did something somewhat similar for PCI:
http://dpdk.org/ml/archives/dev/2017-August/073525.html

I don't know which solution is best, but something certainly needs to be
done.

---

Beside the `why`, about the `how`: shouldn't this file compilation and
symlink be conditioned to CONFIG_RTE_LIBRTE_CRYPTODEV=y?

i.e.: SYMLINK-$(CONFIG_RTE_LIBRTE_CRYPTODEV)-include += rte_cryptodev_vdev.h

> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/bus/vdev/rte_bus_vdev_version.map b/drivers/bus/vdev/rte_bus_vdev_version.map
> new file mode 100644
> index 0000000..69740c3
> --- /dev/null
> +++ b/drivers/bus/vdev/rte_bus_vdev_version.map
> @@ -0,0 +1,10 @@
> +DPDK_17.11 {
> +	global:
> +
> +	rte_vdev_init;
> +	rte_vdev_register;
> +	rte_vdev_uninit;
> +	rte_vdev_unregister;
> +	rte_cryptodev_vdev_pmd_init
> +	rte_cryptodev_vdev_parse_init_params
> +};
> diff --git a/drivers/bus/vdev/rte_cryptodev_vdev.c b/drivers/bus/vdev/rte_cryptodev_vdev.c
> new file mode 100644
> index 0000000..fd308b4
> --- /dev/null
> +++ b/drivers/bus/vdev/rte_cryptodev_vdev.c
> @@ -0,0 +1,154 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2017 Intel Corporation. All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of the copyright holder nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "rte_cryptodev_vdev.h"
> +#include "rte_cryptodev_pci.h"
> +#include "rte_cryptodev_pmd.h"
> +
> +/**
> + * Parse name from argument
> + */
> +static int
> +rte_cryptodev_vdev_parse_name_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	struct rte_crypto_vdev_init_params *params = extra_args;
> +
> +	if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
> +		CDEV_LOG_ERR("Invalid name %s, should be less than "
> +				"%u bytes", value,
> +				RTE_CRYPTODEV_NAME_MAX_LEN - 1);
> +		return -1;
> +	}
> +
> +	strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
> +
> +	return 0;
> +}
> +
> +/**
> + * Parse integer from argument
> + */
> +static int
> +rte_cryptodev_vdev_parse_integer_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	int *i = extra_args;
> +
> +	*i = atoi(value);
> +	if (*i < 0) {
> +		CDEV_LOG_ERR("Argument has to be positive.");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +struct rte_cryptodev *
> +rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
> +		int socket_id, struct rte_vdev_device *vdev)
> +{
> +	struct rte_cryptodev *cryptodev;
> +
> +	/* allocate device structure */
> +	cryptodev = rte_cryptodev_pmd_allocate(name, socket_id);
> +	if (cryptodev == NULL)
> +		return NULL;
> +
> +	/* allocate private device structure */
> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> +		cryptodev->data->dev_private =
> +				rte_zmalloc_socket("cryptodev device private",
> +						dev_private_size,
> +						RTE_CACHE_LINE_SIZE,
> +						socket_id);
> +
> +		if (cryptodev->data->dev_private == NULL)
> +			rte_panic("Cannot allocate memzone for private device"
> +					" data");
> +	}
> +
> +	cryptodev->device = &vdev->device;
> +
> +	/* initialise user call-back tail queue */
> +	TAILQ_INIT(&(cryptodev->link_intr_cbs));
> +
> +	return cryptodev;
> +}
> +
> +int
> +rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
> +		const char *input_args)
> +{
> +	struct rte_kvargs *kvlist = NULL;
> +	int ret = 0;
> +
> +	if (params == NULL)
> +		return -EINVAL;
> +
> +	if (input_args) {
> +		kvlist = rte_kvargs_parse(input_args,
> +				cryptodev_vdev_valid_params);
> +		if (kvlist == NULL)
> +			return -1;
> +
> +		ret = rte_kvargs_process(kvlist,
> +					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
> +					&rte_cryptodev_vdev_parse_integer_arg,
> +					&params->max_nb_queue_pairs);
> +		if (ret < 0)
> +			goto free_kvlist;
> +
> +		ret = rte_kvargs_process(kvlist,
> +					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
> +					&rte_cryptodev_vdev_parse_integer_arg,
> +					&params->max_nb_sessions);
> +		if (ret < 0)
> +			goto free_kvlist;
> +
> +		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
> +					&rte_cryptodev_vdev_parse_integer_arg,
> +					&params->socket_id);
> +		if (ret < 0)
> +			goto free_kvlist;
> +
> +		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
> +					&rte_cryptodev_vdev_parse_name_arg,
> +					params);
> +		if (ret < 0)
> +			goto free_kvlist;
> +	}
> +
> +free_kvlist:
> +	rte_kvargs_free(kvlist);
> +	return ret;
> +}
> diff --git a/drivers/bus/vdev/rte_cryptodev_vdev.h b/drivers/bus/vdev/rte_cryptodev_vdev.h
> new file mode 100644
> index 0000000..94ab9d3
> --- /dev/null
> +++ b/drivers/bus/vdev/rte_cryptodev_vdev.h
> @@ -0,0 +1,100 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2017 Intel Corporation. All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of the copyright holder nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef _RTE_CRYPTODEV_VDEV_H_
> +#define _RTE_CRYPTODEV_VDEV_H_
> +
> +#include <rte_vdev.h>
> +#include <inttypes.h>
> +
> +#include "rte_cryptodev.h"
> +
> +#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
> +#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
> +
> +#define RTE_CRYPTODEV_VDEV_NAME				("name")
> +#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
> +#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
> +#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
> +
> +static const char * const cryptodev_vdev_valid_params[] = {
> +	RTE_CRYPTODEV_VDEV_NAME,
> +	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
> +	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
> +	RTE_CRYPTODEV_VDEV_SOCKET_ID
> +};
> +
> +/**
> + * @internal
> + * Initialisation parameters for virtual crypto devices
> + */
> +struct rte_crypto_vdev_init_params {
> +	unsigned int max_nb_queue_pairs;
> +	unsigned int max_nb_sessions;
> +	uint8_t socket_id;
> +	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
> +};
> +
> +/**
> + * @internal
> + * Creates a new virtual crypto device and returns the pointer
> + * to that device.
> + *
> + * @param	name			PMD type name
> + * @param	dev_private_size	Size of crypto PMDs private data
> + * @param	socket_id		Socket to allocate resources on.
> + * @param	vdev			Pointer to virtual device structure.
> + *
> + * @return
> + *   - Cryptodev pointer if device is successfully created.
> + *   - NULL if device cannot be created.
> + */
> +struct rte_cryptodev *
> +rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
> +		int socket_id, struct rte_vdev_device *vdev);
> +
> +/**
> + * @internal
> + * Parse virtual device initialisation parameters input arguments
> + *
> + * @params	params		Initialisation parameters with defaults set.
> + * @params	input_args	Command line arguments
> + *
> + * @return
> + * 0 on successful parse
> + * <0 on failure to parse
> + */
> +int
> +rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
> +		const char *input_args);
> +
> +#endif /* _RTE_CRYPTODEV_VDEV_H_ */
> diff --git a/drivers/bus/vdev/rte_vdev.h b/drivers/bus/vdev/rte_vdev.h
> new file mode 100644
> index 0000000..41762b8
> --- /dev/null
> +++ b/drivers/bus/vdev/rte_vdev.h
> @@ -0,0 +1,153 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 RehiveTech. All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of RehiveTech nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef RTE_VDEV_H
> +#define RTE_VDEV_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <sys/queue.h>
> +#include <rte_dev.h>
> +#include <rte_devargs.h>
> +
> +struct rte_vdev_device {
> +	TAILQ_ENTRY(rte_vdev_device) next;      /**< Next attached vdev */
> +	struct rte_device device;               /**< Inherit core device */
> +};
> +
> +/**
> + * @internal
> + * Helper macro for drivers that need to convert to struct rte_vdev_device.
> + */
> +#define RTE_DEV_TO_VDEV(ptr) \
> +	container_of(ptr, struct rte_vdev_device, device)
> +
> +static inline const char *
> +rte_vdev_device_name(const struct rte_vdev_device *dev)
> +{
> +	if (dev && dev->device.name)
> +		return dev->device.name;
> +	return NULL;
> +}
> +
> +static inline const char *
> +rte_vdev_device_args(const struct rte_vdev_device *dev)
> +{
> +	if (dev && dev->device.devargs)
> +		return dev->device.devargs->args;
> +	return "";
> +}
> +
> +/** Double linked list of virtual device drivers. */
> +TAILQ_HEAD(vdev_driver_list, rte_vdev_driver);
> +
> +/**
> + * Probe function called for each virtual device driver once.
> + */
> +typedef int (rte_vdev_probe_t)(struct rte_vdev_device *dev);
> +
> +/**
> + * Remove function called for each virtual device driver once.
> + */
> +typedef int (rte_vdev_remove_t)(struct rte_vdev_device *dev);
> +
> +/**
> + * A virtual device driver abstraction.
> + */
> +struct rte_vdev_driver {
> +	TAILQ_ENTRY(rte_vdev_driver) next; /**< Next in list. */
> +	struct rte_driver driver;      /**< Inherited general driver. */
> +	rte_vdev_probe_t *probe;       /**< Virtual device probe function. */
> +	rte_vdev_remove_t *remove;     /**< Virtual device remove function. */
> +};
> +
> +/**
> + * Register a virtual device driver.
> + *
> + * @param driver
> + *   A pointer to a rte_vdev_driver structure describing the driver
> + *   to be registered.
> + */
> +void rte_vdev_register(struct rte_vdev_driver *driver);
> +
> +/**
> + * Unregister a virtual device driver.
> + *
> + * @param driver
> + *   A pointer to a rte_vdev_driver structure describing the driver
> + *   to be unregistered.
> + */
> +void rte_vdev_unregister(struct rte_vdev_driver *driver);
> +
> +#define RTE_PMD_REGISTER_VDEV(nm, vdrv)\
> +RTE_INIT(vdrvinitfn_ ##vdrv);\
> +static const char *vdrvinit_ ## nm ## _alias;\
> +static void vdrvinitfn_ ##vdrv(void)\
> +{\
> +	(vdrv).driver.name = RTE_STR(nm);\
> +	(vdrv).driver.alias = vdrvinit_ ## nm ## _alias;\
> +	rte_vdev_register(&vdrv);\
> +} \
> +RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
> +
> +#define RTE_PMD_REGISTER_ALIAS(nm, alias)\
> +static const char *vdrvinit_ ## nm ## _alias = RTE_STR(alias)
> +
> +/**
> + * Initialize a driver specified by name.
> + *
> + * @param name
> + *   The pointer to a driver name to be initialized.
> + * @param args
> + *   The pointer to arguments used by driver initialization.
> + * @return
> + *  0 on success, negative on error
> + */
> +int rte_vdev_init(const char *name, const char *args);
> +
> +/**
> + * Uninitalize a driver specified by name.
> + *
> + * @param name
> + *   The pointer to a driver name to be initialized.
> + * @return
> + *  0 on success, negative on error
> + */
> +int rte_vdev_uninit(const char *name);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
> new file mode 100644
> index 0000000..f7e547a
> --- /dev/null
> +++ b/drivers/bus/vdev/vdev.c
> @@ -0,0 +1,342 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 RehiveTech. All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of RehiveTech nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <string.h>
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdbool.h>
> +#include <sys/queue.h>
> +
> +#include <rte_eal.h>
> +#include <rte_dev.h>
> +#include <rte_bus.h>
> +#include <rte_vdev.h>
> +#include <rte_common.h>
> +#include <rte_devargs.h>
> +#include <rte_memory.h>
> +#include <rte_errno.h>
> +
> +/* Forward declare to access virtual bus name */
> +static struct rte_bus rte_vdev_bus;
> +
> +/** Double linked list of virtual device drivers. */
> +TAILQ_HEAD(vdev_device_list, rte_vdev_device);
> +
> +static struct vdev_device_list vdev_device_list =
> +	TAILQ_HEAD_INITIALIZER(vdev_device_list);
> +struct vdev_driver_list vdev_driver_list =
> +	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
> +
> +/* register a driver */
> +void
> +rte_vdev_register(struct rte_vdev_driver *driver)
> +{
> +	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
> +}
> +
> +/* unregister a driver */
> +void
> +rte_vdev_unregister(struct rte_vdev_driver *driver)
> +{
> +	TAILQ_REMOVE(&vdev_driver_list, driver, next);
> +}
> +
> +static int
> +vdev_parse(const char *name, void *addr)
> +{
> +	struct rte_vdev_driver **out = addr;
> +	struct rte_vdev_driver *driver = NULL;
> +
> +	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
> +		if (strncmp(driver->driver.name, name,
> +			    strlen(driver->driver.name)) == 0)
> +			break;
> +		if (driver->driver.alias &&
> +		    strncmp(driver->driver.alias, name,
> +			    strlen(driver->driver.alias)) == 0)
> +			break;
> +	}
> +	if (driver != NULL &&
> +	    addr != NULL)
> +		*out = driver;
> +	return driver == NULL;
> +}
> +
> +static int
> +vdev_probe_all_drivers(struct rte_vdev_device *dev)
> +{
> +	const char *name;
> +	struct rte_vdev_driver *driver;
> +	int ret;
> +
> +	name = rte_vdev_device_name(dev);
> +
> +	RTE_LOG(DEBUG, EAL, "Search driver %s to probe device %s\n", name,
> +		rte_vdev_device_name(dev));
> +
> +	if (vdev_parse(name, &driver))
> +		return -1;
> +	dev->device.driver = &driver->driver;
> +	ret = driver->probe(dev);
> +	if (ret)
> +		dev->device.driver = NULL;
> +	return ret;
> +}
> +
> +static struct rte_vdev_device *
> +find_vdev(const char *name)
> +{
> +	struct rte_vdev_device *dev;
> +
> +	if (!name)
> +		return NULL;
> +
> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> +		const char *devname = rte_vdev_device_name(dev);
> +		if (!strncmp(devname, name, strlen(name)))
> +			return dev;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct rte_devargs *
> +alloc_devargs(const char *name, const char *args)
> +{
> +	struct rte_devargs *devargs;
> +	int ret;
> +
> +	devargs = calloc(1, sizeof(*devargs));
> +	if (!devargs)
> +		return NULL;
> +
> +	devargs->bus = &rte_vdev_bus;
> +	if (args)
> +		devargs->args = strdup(args);
> +	else
> +		devargs->args = strdup("");
> +
> +	ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
> +	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
> +		free(devargs->args);
> +		free(devargs);
> +		return NULL;
> +	}
> +
> +	return devargs;
> +}
> +
> +int
> +rte_vdev_init(const char *name, const char *args)
> +{
> +	struct rte_vdev_device *dev;
> +	struct rte_devargs *devargs;
> +	int ret;
> +
> +	if (name == NULL)
> +		return -EINVAL;
> +
> +	dev = find_vdev(name);
> +	if (dev)
> +		return -EEXIST;
> +
> +	devargs = alloc_devargs(name, args);
> +	if (!devargs)
> +		return -ENOMEM;
> +
> +	dev = calloc(1, sizeof(*dev));
> +	if (!dev) {
> +		ret = -ENOMEM;
> +		goto fail;
> +	}
> +
> +	dev->device.devargs = devargs;
> +	dev->device.numa_node = SOCKET_ID_ANY;
> +	dev->device.name = devargs->name;
> +
> +	ret = vdev_probe_all_drivers(dev);
> +	if (ret) {
> +		if (ret > 0)
> +			RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
> +		goto fail;
> +	}
> +
> +	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
> +
> +	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
> +	return 0;
> +
> +fail:
> +	free(devargs->args);
> +	free(devargs);
> +	free(dev);
> +	return ret;
> +}
> +
> +static int
> +vdev_remove_driver(struct rte_vdev_device *dev)
> +{
> +	const char *name = rte_vdev_device_name(dev);
> +	const struct rte_vdev_driver *driver;
> +
> +	if (!dev->device.driver) {
> +		RTE_LOG(DEBUG, EAL, "no driver attach to device %s\n", name);
> +		return 1;
> +	}
> +
> +	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
> +		driver);
> +	return driver->remove(dev);
> +}
> +
> +int
> +rte_vdev_uninit(const char *name)
> +{
> +	struct rte_vdev_device *dev;
> +	struct rte_devargs *devargs;
> +	int ret;
> +
> +	if (name == NULL)
> +		return -EINVAL;
> +
> +	dev = find_vdev(name);
> +	if (!dev)
> +		return -ENOENT;
> +
> +	devargs = dev->device.devargs;
> +
> +	ret = vdev_remove_driver(dev);
> +	if (ret)
> +		return ret;
> +
> +	TAILQ_REMOVE(&vdev_device_list, dev, next);
> +
> +	TAILQ_REMOVE(&devargs_list, devargs, next);
> +
> +	free(devargs->args);
> +	free(devargs);
> +	free(dev);
> +	return 0;
> +}
> +
> +static int
> +vdev_scan(void)
> +{
> +	struct rte_vdev_device *dev;
> +	struct rte_devargs *devargs;
> +
> +	/* for virtual devices we scan the devargs_list populated via cmdline */
> +	TAILQ_FOREACH(devargs, &devargs_list, next) {
> +
> +		if (devargs->bus != &rte_vdev_bus)
> +			continue;
> +
> +		dev = find_vdev(devargs->name);
> +		if (dev)
> +			continue;
> +
> +		dev = calloc(1, sizeof(*dev));
> +		if (!dev)
> +			return -1;
> +
> +		dev->device.devargs = devargs;
> +		dev->device.numa_node = SOCKET_ID_ANY;
> +		dev->device.name = devargs->name;
> +
> +		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +vdev_probe(void)
> +{
> +	struct rte_vdev_device *dev;
> +
> +	/* call the init function for each virtual device */
> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> +
> +		if (dev->device.driver)
> +			continue;
> +
> +		if (vdev_probe_all_drivers(dev)) {
> +			RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
> +				rte_vdev_device_name(dev));
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static struct rte_device *
> +vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
> +		 const void *data)
> +{
> +	struct rte_vdev_device *dev;
> +
> +	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> +		if (start && &dev->device == start) {
> +			start = NULL;
> +			continue;
> +		}
> +		if (cmp(&dev->device, data) == 0)
> +			return &dev->device;
> +	}
> +	return NULL;
> +}
> +
> +static int
> +vdev_plug(struct rte_device *dev)
> +{
> +	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
> +}
> +
> +static int
> +vdev_unplug(struct rte_device *dev)
> +{
> +	return rte_vdev_uninit(dev->name);
> +}
> +
> +static struct rte_bus rte_vdev_bus = {
> +	.scan = vdev_scan,
> +	.probe = vdev_probe,
> +	.find_device = vdev_find_device,
> +	.plug = vdev_plug,
> +	.unplug = vdev_unplug,
> +	.parse = vdev_parse,
> +};
> +
> +RTE_REGISTER_BUS(vdev, rte_vdev_bus);
> diff --git a/lib/librte_cryptodev/Makefile b/lib/librte_cryptodev/Makefile
> index 301c78d..4f70719 100644
> --- a/lib/librte_cryptodev/Makefile
> +++ b/lib/librte_cryptodev/Makefile
> @@ -42,14 +42,12 @@ CFLAGS += $(WERROR_FLAGS)
>  
>  # library source files
>  SRCS-y += rte_cryptodev.c rte_cryptodev_pmd.c
> -SRCS-y += rte_cryptodev_vdev.c
>  
>  # export include files
>  SYMLINK-y-include += rte_crypto.h
>  SYMLINK-y-include += rte_crypto_sym.h
>  SYMLINK-y-include += rte_cryptodev.h
>  SYMLINK-y-include += rte_cryptodev_pmd.h
> -SYMLINK-y-include += rte_cryptodev_vdev.h
>  SYMLINK-y-include += rte_cryptodev_pci.h
>  
>  # versioning export map
> diff --git a/lib/librte_cryptodev/rte_cryptodev_vdev.c b/lib/librte_cryptodev/rte_cryptodev_vdev.c
> deleted file mode 100644
> index fd308b4..0000000
> --- a/lib/librte_cryptodev/rte_cryptodev_vdev.c
> +++ /dev/null
> @@ -1,154 +0,0 @@
> -/*-
> - *   BSD LICENSE
> - *
> - *   Copyright(c) 2017 Intel Corporation. All rights reserved.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of the copyright holder nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> - */
> -
> -#include "rte_cryptodev_vdev.h"
> -#include "rte_cryptodev_pci.h"
> -#include "rte_cryptodev_pmd.h"
> -
> -/**
> - * Parse name from argument
> - */
> -static int
> -rte_cryptodev_vdev_parse_name_arg(const char *key __rte_unused,
> -		const char *value, void *extra_args)
> -{
> -	struct rte_crypto_vdev_init_params *params = extra_args;
> -
> -	if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
> -		CDEV_LOG_ERR("Invalid name %s, should be less than "
> -				"%u bytes", value,
> -				RTE_CRYPTODEV_NAME_MAX_LEN - 1);
> -		return -1;
> -	}
> -
> -	strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
> -
> -	return 0;
> -}
> -
> -/**
> - * Parse integer from argument
> - */
> -static int
> -rte_cryptodev_vdev_parse_integer_arg(const char *key __rte_unused,
> -		const char *value, void *extra_args)
> -{
> -	int *i = extra_args;
> -
> -	*i = atoi(value);
> -	if (*i < 0) {
> -		CDEV_LOG_ERR("Argument has to be positive.");
> -		return -1;
> -	}
> -
> -	return 0;
> -}
> -
> -struct rte_cryptodev *
> -rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
> -		int socket_id, struct rte_vdev_device *vdev)
> -{
> -	struct rte_cryptodev *cryptodev;
> -
> -	/* allocate device structure */
> -	cryptodev = rte_cryptodev_pmd_allocate(name, socket_id);
> -	if (cryptodev == NULL)
> -		return NULL;
> -
> -	/* allocate private device structure */
> -	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> -		cryptodev->data->dev_private =
> -				rte_zmalloc_socket("cryptodev device private",
> -						dev_private_size,
> -						RTE_CACHE_LINE_SIZE,
> -						socket_id);
> -
> -		if (cryptodev->data->dev_private == NULL)
> -			rte_panic("Cannot allocate memzone for private device"
> -					" data");
> -	}
> -
> -	cryptodev->device = &vdev->device;
> -
> -	/* initialise user call-back tail queue */
> -	TAILQ_INIT(&(cryptodev->link_intr_cbs));
> -
> -	return cryptodev;
> -}
> -
> -int
> -rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
> -		const char *input_args)
> -{
> -	struct rte_kvargs *kvlist = NULL;
> -	int ret = 0;
> -
> -	if (params == NULL)
> -		return -EINVAL;
> -
> -	if (input_args) {
> -		kvlist = rte_kvargs_parse(input_args,
> -				cryptodev_vdev_valid_params);
> -		if (kvlist == NULL)
> -			return -1;
> -
> -		ret = rte_kvargs_process(kvlist,
> -					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
> -					&rte_cryptodev_vdev_parse_integer_arg,
> -					&params->max_nb_queue_pairs);
> -		if (ret < 0)
> -			goto free_kvlist;
> -
> -		ret = rte_kvargs_process(kvlist,
> -					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
> -					&rte_cryptodev_vdev_parse_integer_arg,
> -					&params->max_nb_sessions);
> -		if (ret < 0)
> -			goto free_kvlist;
> -
> -		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
> -					&rte_cryptodev_vdev_parse_integer_arg,
> -					&params->socket_id);
> -		if (ret < 0)
> -			goto free_kvlist;
> -
> -		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
> -					&rte_cryptodev_vdev_parse_name_arg,
> -					params);
> -		if (ret < 0)
> -			goto free_kvlist;
> -	}
> -
> -free_kvlist:
> -	rte_kvargs_free(kvlist);
> -	return ret;
> -}
> diff --git a/lib/librte_cryptodev/rte_cryptodev_vdev.h b/lib/librte_cryptodev/rte_cryptodev_vdev.h
> deleted file mode 100644
> index 94ab9d3..0000000
> --- a/lib/librte_cryptodev/rte_cryptodev_vdev.h
> +++ /dev/null
> @@ -1,100 +0,0 @@
> -/*-
> - *   BSD LICENSE
> - *
> - *   Copyright(c) 2017 Intel Corporation. All rights reserved.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of the copyright holder nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> - */
> -
> -#ifndef _RTE_CRYPTODEV_VDEV_H_
> -#define _RTE_CRYPTODEV_VDEV_H_
> -
> -#include <rte_vdev.h>
> -#include <inttypes.h>
> -
> -#include "rte_cryptodev.h"
> -
> -#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
> -#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
> -
> -#define RTE_CRYPTODEV_VDEV_NAME				("name")
> -#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
> -#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
> -#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
> -
> -static const char * const cryptodev_vdev_valid_params[] = {
> -	RTE_CRYPTODEV_VDEV_NAME,
> -	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
> -	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
> -	RTE_CRYPTODEV_VDEV_SOCKET_ID
> -};
> -
> -/**
> - * @internal
> - * Initialisation parameters for virtual crypto devices
> - */
> -struct rte_crypto_vdev_init_params {
> -	unsigned int max_nb_queue_pairs;
> -	unsigned int max_nb_sessions;
> -	uint8_t socket_id;
> -	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
> -};
> -
> -/**
> - * @internal
> - * Creates a new virtual crypto device and returns the pointer
> - * to that device.
> - *
> - * @param	name			PMD type name
> - * @param	dev_private_size	Size of crypto PMDs private data
> - * @param	socket_id		Socket to allocate resources on.
> - * @param	vdev			Pointer to virtual device structure.
> - *
> - * @return
> - *   - Cryptodev pointer if device is successfully created.
> - *   - NULL if device cannot be created.
> - */
> -struct rte_cryptodev *
> -rte_cryptodev_vdev_pmd_init(const char *name, size_t dev_private_size,
> -		int socket_id, struct rte_vdev_device *vdev);
> -
> -/**
> - * @internal
> - * Parse virtual device initialisation parameters input arguments
> - *
> - * @params	params		Initialisation parameters with defaults set.
> - * @params	input_args	Command line arguments
> - *
> - * @return
> - * 0 on successful parse
> - * <0 on failure to parse
> - */
> -int
> -rte_cryptodev_vdev_parse_init_params(struct rte_crypto_vdev_init_params *params,
> -		const char *input_args);
> -
> -#endif /* _RTE_CRYPTODEV_VDEV_H_ */
> diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
> index 005019e..6fee587 100644
> --- a/lib/librte_eal/bsdapp/eal/Makefile
> +++ b/lib/librte_eal/bsdapp/eal/Makefile
> @@ -68,7 +68,6 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_timer.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memzone.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_log.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_launch.c
> -SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_vdev.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_pci.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_pci_uio.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memory.c
> diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
> index e8fd67a..7eeb06a 100644
> --- a/lib/librte_eal/common/Makefile
> +++ b/lib/librte_eal/common/Makefile
> @@ -38,7 +38,7 @@ INC += rte_per_lcore.h rte_random.h
>  INC += rte_tailq.h rte_interrupts.h rte_alarm.h
>  INC += rte_string_fns.h rte_version.h
>  INC += rte_eal_memconfig.h rte_malloc_heap.h
> -INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
> +INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
>  INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
>  INC += rte_malloc.h rte_keepalive.h rte_time.h
>  INC += rte_service.h rte_service_component.h
> diff --git a/lib/librte_eal/common/eal_common_vdev.c b/lib/librte_eal/common/eal_common_vdev.c
> deleted file mode 100644
> index f7e547a..0000000
> --- a/lib/librte_eal/common/eal_common_vdev.c
> +++ /dev/null
> @@ -1,342 +0,0 @@
> -/*-
> - *   BSD LICENSE
> - *
> - *   Copyright(c) 2016 RehiveTech. All rights reserved.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of RehiveTech nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> - */
> -
> -#include <string.h>
> -#include <inttypes.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <stdint.h>
> -#include <stdbool.h>
> -#include <sys/queue.h>
> -
> -#include <rte_eal.h>
> -#include <rte_dev.h>
> -#include <rte_bus.h>
> -#include <rte_vdev.h>
> -#include <rte_common.h>
> -#include <rte_devargs.h>
> -#include <rte_memory.h>
> -#include <rte_errno.h>
> -
> -/* Forward declare to access virtual bus name */
> -static struct rte_bus rte_vdev_bus;
> -
> -/** Double linked list of virtual device drivers. */
> -TAILQ_HEAD(vdev_device_list, rte_vdev_device);
> -
> -static struct vdev_device_list vdev_device_list =
> -	TAILQ_HEAD_INITIALIZER(vdev_device_list);
> -struct vdev_driver_list vdev_driver_list =
> -	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
> -
> -/* register a driver */
> -void
> -rte_vdev_register(struct rte_vdev_driver *driver)
> -{
> -	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
> -}
> -
> -/* unregister a driver */
> -void
> -rte_vdev_unregister(struct rte_vdev_driver *driver)
> -{
> -	TAILQ_REMOVE(&vdev_driver_list, driver, next);
> -}
> -
> -static int
> -vdev_parse(const char *name, void *addr)
> -{
> -	struct rte_vdev_driver **out = addr;
> -	struct rte_vdev_driver *driver = NULL;
> -
> -	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
> -		if (strncmp(driver->driver.name, name,
> -			    strlen(driver->driver.name)) == 0)
> -			break;
> -		if (driver->driver.alias &&
> -		    strncmp(driver->driver.alias, name,
> -			    strlen(driver->driver.alias)) == 0)
> -			break;
> -	}
> -	if (driver != NULL &&
> -	    addr != NULL)
> -		*out = driver;
> -	return driver == NULL;
> -}
> -
> -static int
> -vdev_probe_all_drivers(struct rte_vdev_device *dev)
> -{
> -	const char *name;
> -	struct rte_vdev_driver *driver;
> -	int ret;
> -
> -	name = rte_vdev_device_name(dev);
> -
> -	RTE_LOG(DEBUG, EAL, "Search driver %s to probe device %s\n", name,
> -		rte_vdev_device_name(dev));
> -
> -	if (vdev_parse(name, &driver))
> -		return -1;
> -	dev->device.driver = &driver->driver;
> -	ret = driver->probe(dev);
> -	if (ret)
> -		dev->device.driver = NULL;
> -	return ret;
> -}
> -
> -static struct rte_vdev_device *
> -find_vdev(const char *name)
> -{
> -	struct rte_vdev_device *dev;
> -
> -	if (!name)
> -		return NULL;
> -
> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> -		const char *devname = rte_vdev_device_name(dev);
> -		if (!strncmp(devname, name, strlen(name)))
> -			return dev;
> -	}
> -
> -	return NULL;
> -}
> -
> -static struct rte_devargs *
> -alloc_devargs(const char *name, const char *args)
> -{
> -	struct rte_devargs *devargs;
> -	int ret;
> -
> -	devargs = calloc(1, sizeof(*devargs));
> -	if (!devargs)
> -		return NULL;
> -
> -	devargs->bus = &rte_vdev_bus;
> -	if (args)
> -		devargs->args = strdup(args);
> -	else
> -		devargs->args = strdup("");
> -
> -	ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
> -	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
> -		free(devargs->args);
> -		free(devargs);
> -		return NULL;
> -	}
> -
> -	return devargs;
> -}
> -
> -int
> -rte_vdev_init(const char *name, const char *args)
> -{
> -	struct rte_vdev_device *dev;
> -	struct rte_devargs *devargs;
> -	int ret;
> -
> -	if (name == NULL)
> -		return -EINVAL;
> -
> -	dev = find_vdev(name);
> -	if (dev)
> -		return -EEXIST;
> -
> -	devargs = alloc_devargs(name, args);
> -	if (!devargs)
> -		return -ENOMEM;
> -
> -	dev = calloc(1, sizeof(*dev));
> -	if (!dev) {
> -		ret = -ENOMEM;
> -		goto fail;
> -	}
> -
> -	dev->device.devargs = devargs;
> -	dev->device.numa_node = SOCKET_ID_ANY;
> -	dev->device.name = devargs->name;
> -
> -	ret = vdev_probe_all_drivers(dev);
> -	if (ret) {
> -		if (ret > 0)
> -			RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
> -		goto fail;
> -	}
> -
> -	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
> -
> -	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
> -	return 0;
> -
> -fail:
> -	free(devargs->args);
> -	free(devargs);
> -	free(dev);
> -	return ret;
> -}
> -
> -static int
> -vdev_remove_driver(struct rte_vdev_device *dev)
> -{
> -	const char *name = rte_vdev_device_name(dev);
> -	const struct rte_vdev_driver *driver;
> -
> -	if (!dev->device.driver) {
> -		RTE_LOG(DEBUG, EAL, "no driver attach to device %s\n", name);
> -		return 1;
> -	}
> -
> -	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
> -		driver);
> -	return driver->remove(dev);
> -}
> -
> -int
> -rte_vdev_uninit(const char *name)
> -{
> -	struct rte_vdev_device *dev;
> -	struct rte_devargs *devargs;
> -	int ret;
> -
> -	if (name == NULL)
> -		return -EINVAL;
> -
> -	dev = find_vdev(name);
> -	if (!dev)
> -		return -ENOENT;
> -
> -	devargs = dev->device.devargs;
> -
> -	ret = vdev_remove_driver(dev);
> -	if (ret)
> -		return ret;
> -
> -	TAILQ_REMOVE(&vdev_device_list, dev, next);
> -
> -	TAILQ_REMOVE(&devargs_list, devargs, next);
> -
> -	free(devargs->args);
> -	free(devargs);
> -	free(dev);
> -	return 0;
> -}
> -
> -static int
> -vdev_scan(void)
> -{
> -	struct rte_vdev_device *dev;
> -	struct rte_devargs *devargs;
> -
> -	/* for virtual devices we scan the devargs_list populated via cmdline */
> -	TAILQ_FOREACH(devargs, &devargs_list, next) {
> -
> -		if (devargs->bus != &rte_vdev_bus)
> -			continue;
> -
> -		dev = find_vdev(devargs->name);
> -		if (dev)
> -			continue;
> -
> -		dev = calloc(1, sizeof(*dev));
> -		if (!dev)
> -			return -1;
> -
> -		dev->device.devargs = devargs;
> -		dev->device.numa_node = SOCKET_ID_ANY;
> -		dev->device.name = devargs->name;
> -
> -		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
> -	}
> -
> -	return 0;
> -}
> -
> -static int
> -vdev_probe(void)
> -{
> -	struct rte_vdev_device *dev;
> -
> -	/* call the init function for each virtual device */
> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> -
> -		if (dev->device.driver)
> -			continue;
> -
> -		if (vdev_probe_all_drivers(dev)) {
> -			RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
> -				rte_vdev_device_name(dev));
> -			return -1;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
> -static struct rte_device *
> -vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
> -		 const void *data)
> -{
> -	struct rte_vdev_device *dev;
> -
> -	TAILQ_FOREACH(dev, &vdev_device_list, next) {
> -		if (start && &dev->device == start) {
> -			start = NULL;
> -			continue;
> -		}
> -		if (cmp(&dev->device, data) == 0)
> -			return &dev->device;
> -	}
> -	return NULL;
> -}
> -
> -static int
> -vdev_plug(struct rte_device *dev)
> -{
> -	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
> -}
> -
> -static int
> -vdev_unplug(struct rte_device *dev)
> -{
> -	return rte_vdev_uninit(dev->name);
> -}
> -
> -static struct rte_bus rte_vdev_bus = {
> -	.scan = vdev_scan,
> -	.probe = vdev_probe,
> -	.find_device = vdev_find_device,
> -	.plug = vdev_plug,
> -	.unplug = vdev_unplug,
> -	.parse = vdev_parse,
> -};
> -
> -RTE_REGISTER_BUS(vdev, rte_vdev_bus);
> diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
> index 5386d3a..8bfc343 100644
> --- a/lib/librte_eal/common/include/rte_dev.h
> +++ b/lib/librte_eal/common/include/rte_dev.h
> @@ -166,28 +166,6 @@ struct rte_device {
>  };
>  
>  /**
> - * Initialize a driver specified by name.
> - *
> - * @param name
> - *   The pointer to a driver name to be initialized.
> - * @param args
> - *   The pointer to arguments used by driver initialization.
> - * @return
> - *  0 on success, negative on error
> - */
> -int rte_vdev_init(const char *name, const char *args);
> -
> -/**
> - * Uninitalize a driver specified by name.
> - *
> - * @param name
> - *   The pointer to a driver name to be initialized.
> - * @return
> - *  0 on success, negative on error
> - */
> -int rte_vdev_uninit(const char *name);
> -
> -/**
>   * Attach a device to a registered driver.
>   *
>   * @param name
> @@ -312,4 +290,4 @@ __attribute__((used)) = str
>  }
>  #endif
>  
> -#endif /* _RTE_VDEV_H_ */
> +#endif /* _RTE_DEV_H_ */
> diff --git a/lib/librte_eal/common/include/rte_vdev.h b/lib/librte_eal/common/include/rte_vdev.h
> deleted file mode 100644
> index 29f5a52..0000000
> --- a/lib/librte_eal/common/include/rte_vdev.h
> +++ /dev/null
> @@ -1,131 +0,0 @@
> -/*-
> - *   BSD LICENSE
> - *
> - *   Copyright(c) 2016 RehiveTech. All rights reserved.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of RehiveTech nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> - */
> -
> -#ifndef RTE_VDEV_H
> -#define RTE_VDEV_H
> -
> -#ifdef __cplusplus
> -extern "C" {
> -#endif
> -
> -#include <sys/queue.h>
> -#include <rte_dev.h>
> -#include <rte_devargs.h>
> -
> -struct rte_vdev_device {
> -	TAILQ_ENTRY(rte_vdev_device) next;      /**< Next attached vdev */
> -	struct rte_device device;               /**< Inherit core device */
> -};
> -
> -/**
> - * @internal
> - * Helper macro for drivers that need to convert to struct rte_vdev_device.
> - */
> -#define RTE_DEV_TO_VDEV(ptr) \
> -	container_of(ptr, struct rte_vdev_device, device)
> -
> -static inline const char *
> -rte_vdev_device_name(const struct rte_vdev_device *dev)
> -{
> -	if (dev && dev->device.name)
> -		return dev->device.name;
> -	return NULL;
> -}
> -
> -static inline const char *
> -rte_vdev_device_args(const struct rte_vdev_device *dev)
> -{
> -	if (dev && dev->device.devargs)
> -		return dev->device.devargs->args;
> -	return "";
> -}
> -
> -/** Double linked list of virtual device drivers. */
> -TAILQ_HEAD(vdev_driver_list, rte_vdev_driver);
> -
> -/**
> - * Probe function called for each virtual device driver once.
> - */
> -typedef int (rte_vdev_probe_t)(struct rte_vdev_device *dev);
> -
> -/**
> - * Remove function called for each virtual device driver once.
> - */
> -typedef int (rte_vdev_remove_t)(struct rte_vdev_device *dev);
> -
> -/**
> - * A virtual device driver abstraction.
> - */
> -struct rte_vdev_driver {
> -	TAILQ_ENTRY(rte_vdev_driver) next; /**< Next in list. */
> -	struct rte_driver driver;      /**< Inherited general driver. */
> -	rte_vdev_probe_t *probe;       /**< Virtual device probe function. */
> -	rte_vdev_remove_t *remove;     /**< Virtual device remove function. */
> -};
> -
> -/**
> - * Register a virtual device driver.
> - *
> - * @param driver
> - *   A pointer to a rte_vdev_driver structure describing the driver
> - *   to be registered.
> - */
> -void rte_vdev_register(struct rte_vdev_driver *driver);
> -
> -/**
> - * Unregister a virtual device driver.
> - *
> - * @param driver
> - *   A pointer to a rte_vdev_driver structure describing the driver
> - *   to be unregistered.
> - */
> -void rte_vdev_unregister(struct rte_vdev_driver *driver);
> -
> -#define RTE_PMD_REGISTER_VDEV(nm, vdrv)\
> -RTE_INIT(vdrvinitfn_ ##vdrv);\
> -static const char *vdrvinit_ ## nm ## _alias;\
> -static void vdrvinitfn_ ##vdrv(void)\
> -{\
> -	(vdrv).driver.name = RTE_STR(nm);\
> -	(vdrv).driver.alias = vdrvinit_ ## nm ## _alias;\
> -	rte_vdev_register(&vdrv);\
> -} \
> -RTE_PMD_EXPORT_NAME(nm, __COUNTER__)
> -
> -#define RTE_PMD_REGISTER_ALIAS(nm, alias)\
> -static const char *vdrvinit_ ## nm ## _alias = RTE_STR(alias)
> -
> -#ifdef __cplusplus
> -}
> -#endif
> -
> -#endif
> diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
> index 90bca4d..33faa18 100644
> --- a/lib/librte_eal/linuxapp/eal/Makefile
> +++ b/lib/librte_eal/linuxapp/eal/Makefile
> @@ -80,7 +80,6 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_timer.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memzone.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_log.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_launch.c
> -SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_vdev.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci_uio.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memory.c
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index c25fdd9..c423bf8 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -97,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV)           += -lrte_bus_vdev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
>  
> -- 
> 2.7.4
> 

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
  2017-08-23 12:21  0%   ` Ananyev, Konstantin
  2017-08-23 21:48  0%   ` Thomas Monjalon
@ 2017-08-29 12:50  0%   ` Ferruh Yigit
  2017-08-30  6:22  0%     ` Shahaf Shuler
  2017-08-29 13:11  0%   ` Ferruh Yigit
  3 siblings, 1 reply; 200+ results
From: Ferruh Yigit @ 2017-08-29 12:50 UTC (permalink / raw)
  To: Shahaf Shuler, dev

On 8/7/2017 11:54 AM, Shahaf Shuler wrote:
> Introduce a new API to configure Rx offloads.
> 
> The new API will re-use existing DEV_RX_OFFLOAD_* flags
> to enable the different offloads. This will ease the process
> of adding a new Rx offloads, as no ABI breakage is involved.
> In addition, the offload configuration can be done per queue,
> instead of per port.

If a device doesn't have capability to set the offload per queue how
should it behave, I think it is good to define this.

> 
> The Rx queue offload API can be used only with devices which advertize
> the RTE_ETH_DEV_RXQ_OFFLOAD capability.
> 
> The old Rx offloads API is kept for the meanwhile, in order to enable a
> smooth transition for PMDs and application to the new API.
> 
> Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>

<...>

> @@ -357,7 +357,14 @@ struct rte_eth_rxmode {
>  		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
>  		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
>  		enable_scatter   : 1, /**< Enable scatter packets rx handler */
> -		enable_lro       : 1; /**< Enable LRO */
> +		enable_lro       : 1, /**< Enable LRO */
> +		ignore		 : 1;

what do you think making this variable more verbose, like
"ignore_rx_offloads"

"dev_conf.rxmode.ignore" doesn't say on its own what is ignored.

> +		/**
> +		 * When set the rxmode offloads should be ignored,
> +		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
> +		 * This bit is temporary till rxmode Rx offloads API will
> +		 * be deprecated.
> +		 */
>  };

<...>

> +/** Device supports the rte_eth_rxq_conf offloads API */
> +#define RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
Since this is temporary flag and with current implementation this is
local to library, should we put this into public header?

Later when all PMDs implemented this new method and we want to remove
the flag, can we remove them or do we have to keep them reserved for any
conflict for further new values?

I guess this should be part of missing pmd-ethdev interface file
(rte_ethdev_pmd.h ?).

>  
>  /**
>   * @internal
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] vhost: added user callbacks for socket open/close
  2017-08-25  9:22  0%   ` Jens Freimann
@ 2017-08-29  6:08  3%     ` Stojaczyk, DariuszX
  2017-08-30  6:33  0%       ` Jens Freimann
  0 siblings, 1 reply; 200+ results
From: Stojaczyk, DariuszX @ 2017-08-29  6:08 UTC (permalink / raw)
  To: 'Jens Freimann'; +Cc: dev, Wodkowski, PawelX, maxime.coquelin, yliu

Hi Jens,

> I'm still not sure I understand the use case. So just for my
> understanding: users need to distinct between "the device is going away
> temporarily, keep the connection" and "we're shutting down for good", is
> that it?

Yes, exactly.

> Maybe it's just me or maybe it means you could explain your example in the
> commit message a bit more.

Ok. How about the following commit message instead:
```
rte_vhost: added user callbacks for socket open/close

Added new callbacks to notify about socket connection status.
As destroy_device is used for virtqueue processing *pause* as
well as connection close, the user has no distinction between those.

Consider the following scenario:
rte_vhost: received SET_VRING_BASE message,
                  calling destroy_device() as usual

user:  end-user asks to remove the device (together with socket file),
          OK, device is not *in use* - that's NOT the behavior we want
          calling rte_vhost_driver_unregister() etc.

Instead of changing new_device/destroy_device callbacks and breaking
the ABI, a set of new functions new_connection/destroy_connection
has been added.
```

> Oh, and you should put the maintainers on Cc to get a faster review.

Thanks, I will!
Regards,
D. 

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 02/16] nfp: add specific pf probe function
  2017-08-24 16:20 10% ` [dpdk-dev] [PATCH 02/16] nfp: add specific pf probe function Alejandro Lucero
@ 2017-08-28 16:42  0%   ` Ferruh Yigit
  0 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2017-08-28 16:42 UTC (permalink / raw)
  To: Alejandro Lucero, dev

On 8/24/2017 5:20 PM, Alejandro Lucero wrote:
> Configuring the NFP PMD for using the PF requires access through the
> NSPU interface for device configuration. This patch adds a specific probe
> function for the PF which uses the NSPU interface. Just basic NSPU access
> is done by now reading the NSPU ABI version.
> 
> No ethernet port is created yet.
> 
> Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>

<...>

> +	/* Check NSP ABI version */
> +	if (nfp_nsp_get_abi_version(nspu_desc, &major, &minor) < 0) {
> +		RTE_LOG(INFO, PMD, "NFP NSP not present\n");
> +		goto no_abi;
> +	}
> +	PMD_INIT_LOG(INFO, "nspu ABI version: %d.%d\n", major, minor);
> +
> +	if (minor < 20) {
> +		RTE_LOG(INFO, PMD, "NFP NSP ABI version too old. Required 0.20 or higher\n");

I believe it worth documenting this detail in commit log and documentation.

<...>

>  
> -RTE_PMD_REGISTER_PCI(net_nfp, rte_nfp_net_pmd);
> -RTE_PMD_REGISTER_PCI_TABLE(net_nfp, pci_id_nfp_net_map);
> -RTE_PMD_REGISTER_KMOD_DEP(net_nfp, "* igb_uio | uio_pci_generic | vfio-pci");
> +RTE_PMD_REGISTER_PCI(net_nfp_pf, rte_nfp_net_pf_pmd);
> +RTE_PMD_REGISTER_PCI(net_nfp_vf, rte_nfp_net_vf_pmd);

Now pf and vf drivers are separated. For existing drivers this has been
documented in features file as another file (another column in table),
but we are looking for better representation for this.

What do you think, does two drivers has significant enough differences
to be documented as two different drivers?

> +RTE_PMD_REGISTER_PCI_TABLE(net_nfp_pf, pci_id_nfp_pf_net_map);
> +RTE_PMD_REGISTER_PCI_TABLE(net_nfp_vf, pci_id_nfp_vf_net_map);
> +RTE_PMD_REGISTER_KMOD_DEP(net_nfp_pf, "* igb_uio | uio_pci_generic | vfio");
> +RTE_PMD_REGISTER_KMOD_DEP(net_nfp_vf, "* igb_uio | uio_pci_generic | vfio");
>  
>  /*
>   * Local variables:
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-techboard]  next techboard meeting (29th, August)
  @ 2017-08-28 15:04  3% ` Bruce Richardson
  2017-08-29 15:30  0%   ` Jerin Jacob
  0 siblings, 1 reply; 200+ results
From: Bruce Richardson @ 2017-08-28 15:04 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: techboard, dev

On Sun, Aug 27, 2017 at 06:54:35PM +0530, Jerin Jacob wrote:
> Hi All,
> 
> The next meeting of the tech board will happen on IRC #dpdk-board, at 3pm UTC, on 29th of August(Tuesday)
> 
> Agenda:
> 
> 1) Discussion on next tree requests
> a) Next tree for IPSec offload and maintainership
> http://dpdk.org/ml/archives/dev/2017-August/072995.html
> b) Next tree for cli
> http://dpdk.org/ml/archives/dev/2017-August/073343.html
> 
> 2) Approval of a policy for changes to the minimum DPDK requirements.
> e.g. like what was done with bumping IA min to SSE4.2 in last release.
> 

Proposal for a policy for this item, so as to hopefully speed up the
discussion at the meeting:

* Updates to the minimum HW requirements, i.e. those dropping support for
  hardware which was previously supported, should be treated as an ABI
  change, and follow that deprecation policy. Specifically:
  - change announced at least one release in advance
  - patches removing support for the older hardware should have at least
    three ACKs before being applied.

Regards,
/Bruce

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH 2/3] ethdev: add new rte_mtr API for traffic metering and policing
  @ 2017-08-26  0:06  2%   ` Cristian Dumitrescu
  0 siblings, 0 replies; 200+ results
From: Cristian Dumitrescu @ 2017-08-26  0:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, adrien.mazarguil, jerin.jacob, hemant.agrawal

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
Changes in v1 (from RFC [1]):
- Added EXPERIMENTAL tag in rte_mtr.h and MANTAINERS for this new API
  (input from Thomas)
- Added more Doxygen comments to re-inforce relationship between MTR and
  flow (input from Adrien)
- Added Doxygen hook in doxy-api-index.md

[1] RFC: http://www.dpdk.org/ml/archives/dev/2017-May/066888.html

 MAINTAINERS                            |   4 +
 doc/api/doxy-api-index.md              |   1 +
 lib/librte_ether/Makefile              |   5 +-
 lib/librte_ether/rte_ether_version.map |  15 ++
 lib/librte_ether/rte_mtr.c             | 184 +++++++++++++
 lib/librte_ether/rte_mtr.h             | 471 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_mtr_driver.h      | 188 +++++++++++++
 7 files changed, 867 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ether/rte_mtr.c
 create mode 100644 lib/librte_ether/rte_mtr.h
 create mode 100644 lib/librte_ether/rte_mtr_driver.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a0cd75e..5491906 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -257,6 +257,10 @@ M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
 T: git://dpdk.org/next/dpdk-next-tm
 F: lib/librte_ether/rte_tm*
 
+Traffic Metering and Policing API - EXPERIMENTAL
+M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
+F: lib/librte_ether/rte_mtr*
+
 Crypto API
 M: Declan Doherty <declan.doherty@intel.com>
 F: lib/librte_cryptodev/
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 19e0d4f..b2342a9 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -41,6 +41,7 @@ The public API headers are grouped by topics:
   [ethctrl]            (@ref rte_eth_ctrl.h),
   [rte_flow]           (@ref rte_flow.h),
   [rte_tm]             (@ref rte_tm.h),
+  [rte_mtr]            (@ref rte_mtr.h),
   [cryptodev]          (@ref rte_cryptodev.h),
   [eventdev]           (@ref rte_eventdev.h),
   [metrics]            (@ref rte_metrics.h),
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index db692ae..e4e339d 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -41,11 +41,12 @@ CFLAGS += $(WERROR_FLAGS)
 
 EXPORT_MAP := rte_ether_version.map
 
-LIBABIVER := 6
+LIBABIVER := 7
 
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
+SRCS-y += rte_mtr.c
 
 #
 # Export include files
@@ -59,5 +60,7 @@ SYMLINK-y-include += rte_flow.h
 SYMLINK-y-include += rte_flow_driver.h
 SYMLINK-y-include += rte_tm.h
 SYMLINK-y-include += rte_tm_driver.h
+SYMLINK-y-include += rte_mtr.h
+SYMLINK-y-include += rte_mtr_driver.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 4283728..7192664 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -187,3 +187,18 @@ DPDK_17.08 {
 	rte_tm_wred_profile_delete;
 
 } DPDK_17.05;
+
+DPDK_17.11 {
+	global:
+
+	rte_eth_dev_mtr_ops_get;
+	rte_mtr_meter_profile_add;
+	rte_mtr_meter_profile_delete;
+	rte_mtr_create;
+	rte_mtr_destroy;
+	rte_mtr_meter_profile_update;
+	rte_mtr_policer_action_update;
+	rte_mtr_stats_update;
+	rte_mtr_stats_read;
+
+} DPDK_17.08;
diff --git a/lib/librte_ether/rte_mtr.c b/lib/librte_ether/rte_mtr.c
new file mode 100644
index 0000000..efbe7fb
--- /dev/null
+++ b/lib/librte_ether/rte_mtr.c
@@ -0,0 +1,184 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include <rte_errno.h>
+#include "rte_ethdev.h"
+#include "rte_mtr_driver.h"
+#include "rte_mtr.h"
+
+/* Get generic traffic metering and policing operations structure from a port. */
+const struct rte_mtr_ops *
+rte_mtr_ops_get(uint8_t port_id, struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	const struct rte_mtr_ops *ops;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		rte_mtr_error_set(error,
+			ENODEV,
+			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(ENODEV));
+		return NULL;
+	}
+
+	if ((dev->dev_ops->mtr_ops_get == NULL) ||
+		(dev->dev_ops->mtr_ops_get(dev, &ops) != 0) ||
+		(ops == NULL)) {
+		rte_mtr_error_set(error,
+			ENOSYS,
+			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(ENOSYS));
+		return NULL;
+	}
+
+	return ops;
+}
+
+#define RTE_MTR_FUNC(port_id, func)			\
+({							\
+	const struct rte_mtr_ops *ops =			\
+		rte_mtr_ops_get(port_id, error);		\
+	if (ops == NULL)					\
+		return -rte_errno;			\
+							\
+	if (ops->func == NULL)				\
+		return -rte_mtr_error_set(error,		\
+			ENOSYS,				\
+			RTE_MTR_ERROR_TYPE_UNSPECIFIED,	\
+			NULL,				\
+			rte_strerror(ENOSYS));		\
+							\
+	ops->func;					\
+})
+
+/* MTR meter profile add */
+int
+rte_mtr_meter_profile_add(uint8_t port_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_meter_profile *profile,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_profile_add)(dev,
+		meter_profile_id, profile, error);
+}
+
+/** MTR meter profile delete */
+int
+rte_mtr_meter_profile_delete(uint8_t port_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_profile_delete)(dev,
+		meter_profile_id, error);
+}
+
+/** MTR object create */
+int
+rte_mtr_create(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_params *params,
+	int shared,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, create)(dev,
+		mtr_id, params, shared, error);
+}
+
+/** MTR object destroy */
+int
+rte_mtr_destroy(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, destroy)(dev,
+		mtr_id, error);
+}
+
+/** MTR object meter profile update */
+int
+rte_mtr_meter_profile_update(uint8_t port_id,
+	uint32_t mtr_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_profile_update)(dev,
+		mtr_id, meter_profile_id, error);
+}
+
+/** MTR object policer action update */
+int
+rte_mtr_policer_action_update(uint8_t port_id,
+	uint32_t mtr_id,
+	enum rte_mtr_color color,
+	enum rte_mtr_policer_action action,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, policer_action_update)(dev,
+		mtr_id, color, action, error);
+}
+
+/** MTR object enabled stats update */
+int
+rte_mtr_stats_update(uint8_t port_id,
+	uint32_t mtr_id,
+	uint64_t stats_mask,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, stats_update)(dev,
+		mtr_id, stats_mask, error);
+}
+
+/** MTR object stats read */
+int
+rte_mtr_stats_read(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_stats *stats,
+	uint64_t *stats_mask,
+	int clear,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, stats_read)(dev,
+		mtr_id, stats, stats_mask, clear, error);
+}
diff --git a/lib/librte_ether/rte_mtr.h b/lib/librte_ether/rte_mtr.h
new file mode 100644
index 0000000..d15cb9f
--- /dev/null
+++ b/lib/librte_ether/rte_mtr.h
@@ -0,0 +1,471 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_RTE_MTR_H__
+#define __INCLUDE_RTE_MTR_H__
+
+/**
+ * @file
+ * RTE Generic Traffic Metering and Policing API
+ *
+ * This interface provides the ability to configure the traffic metering and
+ * policing (MTR) in a generic way.
+ *
+ * The processing done for each input packet hitting a MTR object is:
+ *    A) Traffic metering: The packet is assigned a color (the meter output
+ *       color), based on the previous history of the flow reflected in the
+ *       current state of the MTR object, according to the specific traffic
+ *       metering algorithm. The traffic metering algorithm can typically work
+ *       in color aware mode, in which case the input packet already has an
+ *       initial color (the input color), or in color blind mode, which is
+ *       equivalent to considering all input packets initially colored as green.
+ *    B) Policing: There is a separate policer action configured for each meter
+ *       output color, which can:
+ *          a) Drop the packet.
+ *          b) Keep the same packet color: the policer output color matches the
+ *             meter output color (essentially a no-op action).
+ *          c) Recolor the packet: the policer output color is different than
+ *             the meter output color.
+ *       The policer output color is the output color of the packet, which is
+ *       set in the packet meta-data (i.e. struct rte_mbuf::sched::color).
+ *    C) Statistics: The set of counters maintained for each MTR object is
+ *       configurable and subject to the implementation support. This set
+ *       includes the number of packets and bytes dropped or passed for each
+ *       output color.
+ *
+ * Once successfully created, an MTR object is linked to one or several flows
+ * through the meter action of the flow API.
+ *    A) Whether an MTR object is private to a flow or potentially shared by
+ *       several flows has to be specified at creation time.
+ *    B) Several meter actions can be potentially registered for the same flow.
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Color
+ */
+enum rte_mtr_color {
+	RTE_MTR_GREEN = 0, /**< Green */
+	RTE_MTR_YELLOW, /**< Yellow */
+	RTE_MTR_RED, /**< Red */
+	RTE_MTR_COLORS /**< Number of colors */
+};
+
+/**
+ * Statistics counter type
+ */
+enum rte_mtr_stats_type {
+	/**< Number of packets passed as green by the policer.  */
+	RTE_MTR_STATS_N_PKTS_GREEN = 1 << 0,
+
+	/**< Number of bytes passed as green by the policer.  */
+	RTE_MTR_STATS_N_BYTES_GREEN = 1 << 1,
+
+	/**< Number of packets passed as yellow by the policer.  */
+	RTE_MTR_STATS_N_PKTS_YELLOW = 1 << 2,
+
+	/**< Number of bytes passed as yellow by the policer.  */
+	RTE_MTR_STATS_N_BYTES_YELLOW = 1 << 3,
+
+	/**< Number of packets passed as red by the policer.  */
+	RTE_MTR_STATS_N_PKTS_RED = 1 << 4,
+
+	/**< Number of bytes passed as red by the policer.  */
+	RTE_MTR_STATS_N_BYTES_RED = 1 << 5,
+
+	/**< Number of packets dropped by the policer.  */
+	RTE_MTR_STATS_N_PKTS_DROPPED = 1 << 6,
+
+	/**< Number of bytes dropped by the policer.  */
+	RTE_MTR_STATS_N_BYTES_DROPPED = 1 << 7,
+};
+
+/**
+ * Statistics counters
+ */
+struct rte_mtr_stats {
+	/**< Number of packets passed by the policer (per color). */
+	uint64_t n_pkts[RTE_MTR_COLORS];
+
+	/**< Number of bytes passed by the policer (per color). */
+	uint64_t n_bytes[RTE_MTR_COLORS];
+
+	/**< Number of packets dropped by the policer. */
+	uint64_t n_pkts_dropped;
+
+	/**< Number of bytes passed by the policer. */
+	uint64_t n_bytes_dropped;
+};
+
+/**
+ * Traffic metering algorithms
+ */
+enum rte_mtr_algorithm {
+	/**< Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
+	RTE_MTR_SRTCM_RFC2697 = 0,
+
+	/**< Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
+	RTE_MTR_TRTCM_RFC2698,
+};
+
+/**
+ * Meter profile
+ */
+struct rte_mtr_meter_profile {
+	/**<  Traffic metering algorithm. */
+	enum rte_mtr_algorithm alg;
+
+	union {
+		/**< Items only valid when *alg* is set to srTCM - RFC2697. */
+		struct {
+			/**< Committed Information Rate (CIR) (bytes/second). */
+			uint64_t cir;
+
+			/**< Committed Burst Size (CBS) (bytes). */
+			uint64_t cbs;
+
+			/**< Excess Burst Size (EBS) (bytes). */
+			uint64_t ebs;
+
+			/**< Non-zero for color aware mode, zero for color blind
+			 * mode. In color aware mode, the packet input color is
+			 * read from the IPv4/IPv6 DSCP field, as defined by
+			 * IETF RFC 2597 (low/medium/high drop precedence
+			 * translates to green/yellow/red color respectively).
+			 */
+			int color_aware;
+		} srtcm_rfc2697;
+
+		/**< Items only valid when *alg* is set to trTCM - RFC2698. */
+		struct {
+			/**< Committed Information Rate (CIR) (bytes/second). */
+			uint64_t cir;
+
+			/**< Peak Information Rate (PIR) (bytes/second). */
+			uint64_t pir;
+
+			/**< Committed Burst Size (CBS) (byes). */
+			uint64_t cbs;
+
+			/**< Peak Burst Size (PBS) (bytes). */
+			uint64_t pbs;
+
+			/**< Non-zero for color aware mode, zero for color blind
+			 * mode. In color aware mode, the packet input color is
+			 * read from the IPv4/IPv6 DSCP field, as defined by
+			 * IETF RFC 2597 (low/medium/high drop precedence
+			 * translates to green/yellow/red color respectively).
+			 */
+			int color_aware;
+		} trtcm_rfc2698;
+	};
+};
+
+/**
+ * Policer actions
+ */
+enum rte_mtr_policer_action {
+	/**< Recolor the packet as green. */
+	e_MTR_POLICER_ACTION_COLOR_GREEN = 0,
+
+	/**< Recolor the packet as yellow. */
+	e_MTR_POLICER_ACTION_COLOR_YELLOW,
+
+	/**< Recolor the packet as red. */
+	e_MTR_POLICER_ACTION_COLOR_RED,
+
+	/**< Drop the packet. */
+	e_MTR_POLICER_ACTION_DROP,
+};
+
+/**
+ * Parameters for each traffic metering & policing object
+ *
+ * @see enum rte_mtr_stats_type
+ */
+struct rte_mtr_params {
+	/**< Meter profile ID. */
+	uint32_t meter_profile_id;
+
+	/**< Policer actions (per meter output color). */
+	enum rte_mtr_policer_action action[RTE_MTR_COLORS];
+
+	/**< Set of stats counters to be enabled. */
+	uint64_t stats_mask;
+};
+
+/**
+ * Verbose error types.
+ *
+ * Most of them provide the type of the object referenced by struct
+ * rte_mtr_error::cause.
+ */
+enum rte_mtr_error_type {
+	RTE_MTR_ERROR_TYPE_NONE, /**< No error. */
+	RTE_MTR_ERROR_TYPE_UNSPECIFIED, /**< Cause unspecified. */
+	RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+	RTE_MTR_ERROR_TYPE_METER_PROFILE,
+	RTE_MTR_ERROR_TYPE_MTR_ID,
+	RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+	RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
+	RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW,
+	RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED,
+	RTE_MTR_ERROR_TYPE_STATS_MASK,
+	RTE_MTR_ERROR_TYPE_STATS,
+	RTE_MTR_ERROR_TYPE_SHARED,
+};
+
+/**
+ * Verbose error structure definition.
+ *
+ * This object is normally allocated by applications and set by PMDs, the
+ * message points to a constant string which does not need to be freed by
+ * the application, however its pointer can be considered valid only as long
+ * as its associated DPDK port remains configured. Closing the underlying
+ * device or unloading the PMD invalidates it.
+ *
+ * Both cause and message may be NULL regardless of the error type.
+ */
+struct rte_mtr_error {
+	enum rte_mtr_error_type type; /**< Cause field and error type. */
+	const void *cause; /**< Object responsible for the error. */
+	const char *message; /**< Human-readable error message. */
+};
+
+/**
+ * Meter profile add
+ *
+ * Create a new meter profile with ID set to *meter_profile_id*. The new profile
+ * is used to create one or several MTR objects.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] meter_profile_id
+ *   ID for the new meter profile. Needs to be unused by any of the existing
+ *   meter profiles added for the current port.
+ * @param[in] profile
+ *   Meter profile parameters. Needs to be pre-allocated and valid.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+int
+rte_mtr_meter_profile_add(uint8_t port_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_meter_profile *profile,
+	struct rte_mtr_error *error);
+
+/**
+ * Meter profile delete
+ *
+ * Delete an existing meter profile. This operation fails when there is
+ * currently at least one user (i.e. MTR object) of this profile.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile ID. Needs to be the valid.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+int
+rte_mtr_meter_profile_delete(uint8_t port_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object create
+ *
+ * Create a new MTR object for the current port. This object is run as part of
+ * associated flow action for traffic metering and policing.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be unused by any of the existing MTR objects
+ *   created for the current port.
+ * @param[in] params
+ *   MTR object params. Needs to be pre-allocated and valid.
+ * @param[in] shared
+ *   Non-zero when this MTR object can be shared by multiple flows, zero when
+ *   this MTR object can be used by a single flow.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ *
+ * @see enum rte_flow_action_type::RTE_FLOW_ACTION_TYPE_METER
+ */
+int
+rte_mtr_create(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_params *params,
+	int shared,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object destroy
+ *
+ * Delete an existing MTR object. This operation fails when there is currently
+ * at least one user (i.e. flow) of this MTR object.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be unused by any of the existing MTR objects
+ *   created for the current port.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+int
+rte_mtr_destroy(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object meter profile update
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be valid.
+ * @param[in] meter_profile_id
+ *   Meter profile ID for the current MTR object. Needs to be valid.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+int
+rte_mtr_meter_profile_update(uint8_t port_id,
+	uint32_t mtr_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object policer action update for given color
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be valid.
+ * @param[in] color
+ *   Color for which the policer action is updated.
+ * @param[in] action
+ *   Policer action for specified color.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+int
+rte_mtr_policer_action_update(uint8_t port_id,
+	uint32_t mtr_id,
+	enum rte_mtr_color color,
+	enum rte_mtr_policer_action action,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object enabled statistics counters update
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be valid.
+ * @param[in] stats_mask
+ *   Mask of statistics counter types to be enabled for the current MTR object.
+ *   Any statistics counter type not included in this set is to be disabled for
+ *   the current MTR object.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ *
+ * @see enum rte_mtr_stats_type
+ */
+int
+rte_mtr_stats_update(uint8_t port_id,
+	uint32_t mtr_id,
+	uint64_t stats_mask,
+	struct rte_mtr_error *error);
+
+/**
+ * MTR object statistics counters read
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] mtr_id
+ *   MTR object ID. Needs to be valid.
+ * @param[out] stats
+ *   When non-NULL, it contains the current value for the statistics counters
+ *   enabled for the current MTR object.
+ * @param[out] stats_mask
+ *   When non-NULL, it contains the mask of statistics counter types that are
+ *   currently enabled for this MTR object, indicating which of the counters
+ *   retrieved with the *stats* structure are valid.
+ * @param[in] clear
+ *   When this parameter has a non-zero value, the statistics counters are
+ *   cleared (i.e. set to zero) immediately after they have been read,
+ *   otherwise the statistics counters are left untouched.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ *
+ * @see enum rte_mtr_stats_type
+ */
+int
+rte_mtr_stats_read(uint8_t port_id,
+	uint32_t mtr_id,
+	struct rte_mtr_stats *stats,
+	uint64_t *stats_mask,
+	int clear,
+	struct rte_mtr_error *error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_MTR_H__ */
diff --git a/lib/librte_ether/rte_mtr_driver.h b/lib/librte_ether/rte_mtr_driver.h
new file mode 100644
index 0000000..3798cf6
--- /dev/null
+++ b/lib/librte_ether/rte_mtr_driver.h
@@ -0,0 +1,188 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_RTE_MTR_DRIVER_H__
+#define __INCLUDE_RTE_MTR_DRIVER_H__
+
+/**
+ * @file
+ * RTE Generic Traffic Metering and Policing API (Driver Side)
+ *
+ * This file provides implementation helpers for internal use by PMDs, they
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ */
+
+#include <stdint.h>
+
+#include <rte_errno.h>
+#include "rte_ethdev.h"
+#include "rte_mtr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*rte_mtr_meter_profile_add_t)(struct rte_eth_dev *dev,
+	uint32_t meter_profile_id,
+	struct rte_mtr_meter_profile *profile,
+	struct rte_mtr_error *error);
+/**< @internal MTR meter profile add */
+
+typedef int (*rte_mtr_meter_profile_delete_t)(struct rte_eth_dev *dev,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error);
+/**< @internal MTR meter profile delete */
+
+typedef int (*rte_mtr_create_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	struct rte_mtr_params *params,
+	int shared,
+	struct rte_mtr_error *error);
+/**< @internal MTR object create */
+
+typedef int (*rte_mtr_destroy_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	struct rte_mtr_error *error);
+/**< @internal MTR object destroy */
+
+typedef int (*rte_mtr_meter_profile_update_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	uint32_t meter_profile_id,
+	struct rte_mtr_error *error);
+/**< @internal MTR object meter profile update */
+
+typedef int (*rte_mtr_policer_action_update_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	enum rte_mtr_color color,
+	enum rte_mtr_policer_action action,
+	struct rte_mtr_error *error);
+/**< @internal MTR object policer action update*/
+
+typedef int (*rte_mtr_stats_update_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	uint64_t stats_mask,
+	struct rte_mtr_error *error);
+/**< @internal MTR object enabled stats update */
+
+typedef int (*rte_mtr_stats_read_t)(struct rte_eth_dev *dev,
+	uint32_t mtr_id,
+	struct rte_mtr_stats *stats,
+	uint64_t *stats_mask,
+	int clear,
+	struct rte_mtr_error *error);
+/**< @internal MTR object stats read */
+
+struct rte_mtr_ops {
+	/** MTR meter profile add */
+	rte_mtr_meter_profile_add_t meter_profile_add;
+
+	/** MTR meter profile delete */
+	rte_mtr_meter_profile_delete_t meter_profile_delete;
+
+	/** MTR object create */
+	rte_mtr_create_t create;
+
+	/** MTR object destroy */
+	rte_mtr_destroy_t destroy;
+
+	/** MTR object meter profile update */
+	rte_mtr_meter_profile_update_t meter_profile_update;
+
+	/** MTR object policer action update */
+	rte_mtr_policer_action_update_t policer_action_update;
+
+	/** MTR object enabled stats update */
+	rte_mtr_stats_update_t stats_update;
+
+	/** MTR object stats read */
+	rte_mtr_stats_read_t stats_read;
+};
+
+/**
+ * Initialize generic error structure.
+ *
+ * This function also sets rte_errno to a given value.
+ *
+ * @param[out] error
+ *   Pointer to error structure (may be NULL).
+ * @param[in] code
+ *   Related error code (rte_errno).
+ * @param[in] type
+ *   Cause field and error type.
+ * @param[in] cause
+ *   Object responsible for the error.
+ * @param[in] message
+ *   Human-readable error message.
+ *
+ * @return
+ *   Error code.
+ */
+static inline int
+rte_mtr_error_set(struct rte_mtr_error *error,
+		   int code,
+		   enum rte_mtr_error_type type,
+		   const void *cause,
+		   const char *message)
+{
+	if (error) {
+		*error = (struct rte_mtr_error){
+			.type = type,
+			.cause = cause,
+			.message = message,
+		};
+	}
+	rte_errno = code;
+	return code;
+}
+
+/**
+ * Get generic traffic metering and policing operations structure from a port
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[out] error
+ *   Error details
+ *
+ * @return
+ *   The traffic metering and policing operations structure associated with
+ *   port_id on success, NULL otherwise.
+ */
+const struct rte_mtr_ops *
+rte_mtr_ops_get(uint8_t port_id, struct rte_mtr_error *error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_MTR_DRIVER_H__ */
-- 
2.7.4

^ permalink raw reply	[relevance 2%]

* [dpdk-dev] [PATCH v3] ethdev: modifiy vlan_offload_set_t to return int
  2017-08-25 13:33  4% ` [dpdk-dev] [PATCH v2] " David Harton
@ 2017-08-25 13:47  4%   ` David Harton
  0 siblings, 0 replies; 200+ results
From: David Harton @ 2017-08-25 13:47 UTC (permalink / raw)
  To: thomas, ferruh.yigit, ajit.khaparde, johndale,
	konstantin.ananyev, jingjing.wu, beilei.xing, jing.d.chen,
	adrien.mazarguil, nelio.laranjeiro, alejandro.lucero,
	hemant.agrawal, rasesh.mody, harish.patil, skhare, yliu,
	maxime.coquelin, allain.legacy
  Cc: dev, David Harton

Some devices may not support or fail setting VLAN offload
configuration based on dynamic circurmstances so the
vlan_offload_set_t vector is modified to return an int so
the caller can determine success or not.

rte_eth_dev_set_vlan_offload is updated to return the
value provided by the vector when called along with restoring
the original offload configs on failure.

Existing vlan_offload_set_t vectors are modified to return
an int.  Majority of cases return 0 but a few that actually
can fail now return their failure codes.

Finally, a vlan_offload_set_t vector is added to virtio
to facilitate dynamically turning VLAN strip on or off.

Signed-off-by: David Harton <dharton@cisco.com>
---

*v3
Fixed a format error.
Apologies...need to figure out why checkpatches.pl keeps saying
valid patch when I've got soft tabs.

*v2
Fixed a missed format error.
Removed vlan offload vector call casts and replaced with checks 
for return values.

*v1
This is an ABI breakage that has been previously negotiated
with Thomas and the proposed rel note change is included as well.

 doc/guides/rel_notes/release_17_11.rst |  2 +-
 drivers/net/avp/avp_ethdev.c           | 12 +++++++++---
 drivers/net/bnxt/bnxt_ethdev.c         |  9 ++++++---
 drivers/net/dpaa2/dpaa2_ethdev.c       | 13 ++++++++++---
 drivers/net/e1000/em_ethdev.c          | 12 +++++++++---
 drivers/net/e1000/igb_ethdev.c         | 12 +++++++++---
 drivers/net/enic/enic_ethdev.c         |  8 +++++---
 drivers/net/fm10k/fm10k_ethdev.c       |  3 ++-
 drivers/net/i40e/i40e_ethdev.c         | 11 ++++++++---
 drivers/net/i40e/i40e_ethdev_vf.c      |  9 ++++++---
 drivers/net/ixgbe/ixgbe_ethdev.c       | 25 ++++++++++++++++++-------
 drivers/net/mlx5/mlx5.h                |  2 +-
 drivers/net/mlx5/mlx5_vlan.c           |  3 ++-
 drivers/net/nfp/nfp_net.c              | 13 +++++++------
 drivers/net/qede/qede_ethdev.c         |  9 +++++++--
 drivers/net/virtio/virtio_ethdev.c     | 21 +++++++++++++++++++++
 drivers/net/vmxnet3/vmxnet3_ethdev.c   | 10 +++++++---
 lib/librte_ether/rte_ethdev.c          | 14 +++++++++++++-
 lib/librte_ether/rte_ethdev.h          |  2 +-
 19 files changed, 142 insertions(+), 48 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..e74f70c 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,7 +124,7 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
-
+* Changed return type of ``vlan_offload_set_t`` from ``void`` to ``int``.
 
 Shared Library Versions
 -----------------------
diff --git a/drivers/net/avp/avp_ethdev.c b/drivers/net/avp/avp_ethdev.c
index c746a0e..4011dfa 100644
--- a/drivers/net/avp/avp_ethdev.c
+++ b/drivers/net/avp/avp_ethdev.c
@@ -70,7 +70,7 @@ static int avp_dev_create(struct rte_pci_device *pci_dev,
 static void avp_dev_close(struct rte_eth_dev *dev);
 static void avp_dev_info_get(struct rte_eth_dev *dev,
 			     struct rte_eth_dev_info *dev_info);
-static void avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int avp_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 static void avp_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static void avp_dev_promiscuous_disable(struct rte_eth_dev *dev);
@@ -2031,7 +2031,12 @@ struct avp_queue {
 	mask = (ETH_VLAN_STRIP_MASK |
 		ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK);
-	avp_vlan_offload_set(eth_dev, mask);
+	ret = avp_vlan_offload_set(eth_dev, mask);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "VLAN offload set failed by host, ret=%d\n",
+			    ret);
+		goto unlock;
+	}
 
 	/* update device config */
 	memset(&config, 0, sizeof(config));
@@ -2214,7 +2219,7 @@ struct avp_queue {
 	}
 }
 
-static void
+static int
 avp_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
@@ -2239,6 +2244,7 @@ struct avp_queue {
 		if (eth_dev->data->dev_conf.rxmode.hw_vlan_extend)
 			PMD_DRV_LOG(ERR, "VLAN extend offload not supported\n");
 	}
+	return 0;
 }
 
 static void
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index c9d1122..547bd55 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -144,7 +144,7 @@
 	ETH_RSS_NONFRAG_IPV6_TCP |	\
 	ETH_RSS_NONFRAG_IPV6_UDP)
 
-static void bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
+static int bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
 
 /***********************/
 
@@ -522,7 +522,9 @@ static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev)
 		vlan_mask |= ETH_VLAN_FILTER_MASK;
 	if (eth_dev->data->dev_conf.rxmode.hw_vlan_strip)
 		vlan_mask |= ETH_VLAN_STRIP_MASK;
-	bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	rc = bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	if (rc)
+		goto error;
 
 	return 0;
 
@@ -1275,7 +1277,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 		return bnxt_del_vlan_filter(bp, vlan_id);
 }
 
-static void
+static int
 bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask)
 {
 	struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
@@ -1307,6 +1309,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 
 	if (mask & ETH_VLAN_EXTEND_MASK)
 		RTE_LOG(ERR, PMD, "Extend VLAN Not supported\n");
+	return 0;
 }
 
 static void
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 429b3a0..3390cb3 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -138,7 +138,7 @@
 	return ret;
 }
 
-static void
+static int
 dpaa2_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct dpaa2_dev_priv *priv = dev->data->dev_private;
@@ -158,6 +158,7 @@
 			RTE_LOG(ERR, PMD, "Unable to set vlan filter = %d\n",
 				ret);
 	}
+	return 0;
 }
 
 static int
@@ -643,8 +644,14 @@
 		return ret;
 	}
 	/* VLAN Offload Settings */
-	if (priv->max_vlan_filters)
-		dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+	if (priv->max_vlan_filters) {
+		ret = dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+		if (ret) {
+			PMD_INIT_LOG(ERR, "Error to dpaa2_vlan_offload_set:"
+				     "code = %d\n", ret);
+			return ret;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index 3d4ab93..51f49d8 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -99,7 +99,7 @@ static int eth_em_interrupt_action(struct rte_eth_dev *dev,
 
 static int eth_em_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
-static void eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void em_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void em_vlan_hw_filter_disable(struct rte_eth_dev *dev);
 static void em_vlan_hw_strip_enable(struct rte_eth_dev *dev);
@@ -668,7 +668,12 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_em_vlan_offload_set(dev, mask);
+	ret = eth_em_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to update vlan offload");
+		em_dev_clear_queues(dev);
+		return ret;
+	}
 
 	/* Set Interrupt Throttling Rate to maximum allowed value. */
 	E1000_WRITE_REG(hw, E1000_ITR, UINT16_MAX);
@@ -1447,7 +1452,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
 }
 
-static void
+static int
 eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -1463,6 +1468,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			em_vlan_hw_filter_disable(dev);
 	}
+	return 0;
 }
 
 /*
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index e4f7a9f..fa15ee9 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -157,7 +157,7 @@ static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
 				 enum rte_vlan_type vlan_type,
 				 uint16_t tpid_id);
-static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev);
@@ -1400,7 +1400,12 @@ static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_igb_vlan_offload_set(dev, mask);
+	ret = eth_igb_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to set vlan offload");
+		igb_dev_clear_queues(dev);
+		return ret;
+	}
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable VLAN filter since VMDq always use VLAN filter */
@@ -2715,7 +2720,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 						2 * VLAN_TAG_SIZE);
 }
 
-static void
+static int
 eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -2738,6 +2743,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			igb_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index da8fec2..fc1eac2 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -347,7 +347,7 @@ static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return err;
 }
 
-static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
 
@@ -371,6 +371,8 @@ static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
+
+	return 0;
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -392,9 +394,9 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 			eth_dev->data->dev_conf.rxmode.split_hdr_size);
 	}
 
-	enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
 	enic->hw_ip_checksum = eth_dev->data->dev_conf.rxmode.hw_ip_checksum;
-	return 0;
+	return ret;
 }
 
 /* Start the device.
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index e60d3a3..f4626f7 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1590,7 +1590,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return 0;
 }
 
-static void
+static int
 fm10k_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -1609,6 +1609,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		if (!dev->data->dev_conf.rxmode.hw_vlan_filter)
 			PMD_INIT_LOG(ERR, "VLAN filter is always on in fm10k");
 	}
+	return 0;
 }
 
 /* Add/Remove a MAC address, and update filters to main VSI */
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 00b6082..d03a44b 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -278,7 +278,7 @@ static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
 static int i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			      enum rte_vlan_type vlan_type,
 			      uint16_t tpid);
-static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
 				      uint16_t queue,
 				      int on);
@@ -3130,7 +3130,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return ret;
 }
 
-static void
+static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -3163,6 +3163,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 	}
+	return 0;
 }
 
 static void
@@ -5216,7 +5217,11 @@ struct i40e_vsi *
 
 	/* Apply vlan offload setting */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
-	i40e_vlan_offload_set(dev, mask);
+	ret = i40e_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_DRV_LOG(INFO, "Failed to update vlan offload");
+		return ret;
+	}
 
 	/* Apply double-vlan setting, not implemented yet */
 
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index f6d8293..f7fffc2 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -118,7 +118,7 @@ static int i40evf_dev_xstats_get_names(struct rte_eth_dev *dev,
 static void i40evf_dev_xstats_reset(struct rte_eth_dev *dev);
 static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
 				  uint16_t vlan_id, int on);
-static void i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int i40evf_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid,
 				int on);
 static void i40evf_dev_close(struct rte_eth_dev *dev);
@@ -1634,7 +1634,9 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	int ret;
 
 	/* Apply vlan offload setting */
-	i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	ret = i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	if (ret)
+		return ret;
 
 	/* Apply pvid setting */
 	ret = i40evf_vlan_pvid_set(dev, data->dev_conf.txmode.pvid,
@@ -1642,7 +1644,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	return ret;
 }
 
-static void
+static int
 i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
@@ -1655,6 +1657,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			i40evf_disable_vlan_strip(dev);
 	}
+	return 0;
 }
 
 static int
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 22171d8..1ec5aaf 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -218,7 +218,7 @@ static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
 		uint16_t queue, bool on);
 static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
 		int on);
-static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev);
@@ -274,7 +274,7 @@ static int ixgbevf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev,
 		uint16_t queue, int on);
-static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on);
 static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
 					    uint16_t queue_id);
@@ -2125,7 +2125,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 }
 
-static void
+static int
 ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -2148,6 +2148,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			ixgbe_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 static void
@@ -2568,9 +2569,13 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 		goto error;
 	}
 
-    mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
+	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbe_vlan_offload_set(dev, mask);
+	err = ixgbe_vlan_offload_set(dev, mask);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Unable to set VLAN offload");
+		goto error;
+	}
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable vlan filtering for VMDq */
@@ -4993,7 +4998,12 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	/* Set HW strip */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbevf_vlan_offload_set(dev, mask);
+	err = ixgbevf_vlan_offload_set(dev, mask);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Unable to set VLAN offload (%d)", err);
+		ixgbe_dev_clear_queues(dev);
+		return err;
+	}
 
 	ixgbevf_dev_rxtx_start(dev);
 
@@ -5153,7 +5163,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 	ixgbe_vlan_hw_strip_bitmap_set(dev, queue, on);
 }
 
-static void
+static int
 ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct ixgbe_hw *hw =
@@ -5168,6 +5178,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 		for (i = 0; i < hw->mac.max_rx_queues; i++)
 			ixgbevf_vlan_strip_queue_set(dev, i, on);
 	}
+	return 0;
 }
 
 int
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 43c5384..93e71be 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -283,7 +283,7 @@ int mlx5_xstats_get_names(struct rte_eth_dev *,
 /* mlx5_vlan.c */
 
 int mlx5_vlan_filter_set(struct rte_eth_dev *, uint16_t, int);
-void mlx5_vlan_offload_set(struct rte_eth_dev *, int);
+int mlx5_vlan_offload_set(struct rte_eth_dev *, int);
 void mlx5_vlan_strip_queue_set(struct rte_eth_dev *, uint16_t, int);
 
 /* mlx5_trigger.c */
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index 1b0fa40..7215909 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -210,7 +210,7 @@
  * @param mask
  *   VLAN offload bit mask.
  */
-void
+int
 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct priv *priv = dev->data->dev_private;
@@ -230,4 +230,5 @@
 			priv_vlan_strip_queue_set(priv, i, hw_vlan_strip);
 		priv_unlock(priv);
 	}
+	return 0;
 }
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 92b03c4..6473edc 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2149,11 +2149,12 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 	return i;
 }
 
-static void
+static int
 nfp_net_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	uint32_t new_ctrl, update;
 	struct nfp_net_hw *hw;
+	int ret;
 
 	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	new_ctrl = 0;
@@ -2174,14 +2175,14 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 		new_ctrl = hw->ctrl & ~NFP_NET_CFG_CTRL_RXVLAN;
 
 	if (new_ctrl == 0)
-		return;
+		return 0;
 
 	update = NFP_NET_CFG_UPDATE_GEN;
 
-	if (nfp_net_reconfig(hw, new_ctrl, update) < 0)
-		return;
-
-	hw->ctrl = new_ctrl;
+	ret = nfp_net_reconfig(hw, new_ctrl, update);
+	if (!ret)
+		hw->ctrl = new_ctrl;
+	return ret;
 }
 
 /* Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device */
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 0e05989..644f69d 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -975,7 +975,7 @@ static int qede_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return rc;
 }
 
-static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
 	struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
@@ -1013,6 +1013,8 @@ static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 
 	DP_INFO(edev, "vlan offload mask %d vlan-strip %d vlan-filter %d\n",
 		mask, rxmode->hw_vlan_strip, rxmode->hw_vlan_filter);
+
+	return 0;
 }
 
 static void qede_prandom_bytes(uint32_t *buff)
@@ -1157,6 +1159,7 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
 	struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
 	struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
 	struct rte_eth_rxmode *rxmode = &eth_dev->data->dev_conf.rxmode;
+	int ret;
 
 	PMD_INIT_FUNC_TRACE(edev);
 
@@ -1237,9 +1240,11 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
 	qdev->enable_lro = rxmode->enable_lro;
 
 	/* Enable VLAN offloads by default */
-	qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
+	ret = qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
 			ETH_VLAN_FILTER_MASK |
 			ETH_VLAN_EXTEND_MASK);
+	if (ret)
+		return ret;
 
 	DP_INFO(edev, "Device configured with RSS=%d TSS=%d\n",
 			QEDE_RSS_COUNT(qdev), QEDE_TSS_COUNT(qdev));
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index e320811..72b4248 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -72,6 +72,7 @@ static void virtio_dev_info_get(struct rte_eth_dev *dev,
 				struct rte_eth_dev_info *dev_info);
 static int virtio_dev_link_update(struct rte_eth_dev *dev,
 	int wait_to_complete);
+static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void virtio_set_hwaddr(struct virtio_hw *hw);
 static void virtio_get_hwaddr(struct virtio_hw *hw);
@@ -779,6 +780,7 @@ struct rte_virtio_xstats_name_off {
 	.stats_reset             = virtio_dev_stats_reset,
 	.xstats_reset            = virtio_dev_stats_reset,
 	.link_update             = virtio_dev_link_update,
+	.vlan_offload_set        = virtio_dev_vlan_offload_set,
 	.rx_queue_setup          = virtio_dev_rx_queue_setup,
 	.rx_queue_intr_enable    = virtio_dev_rx_queue_intr_enable,
 	.rx_queue_intr_disable   = virtio_dev_rx_queue_intr_disable,
@@ -1875,6 +1877,25 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev)
 	return (old.link_status == link.link_status) ? -1 : 0;
 }
 
+static int
+virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+	const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	if (rxmode->hw_vlan_filter &&
+	    !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) {
+		PMD_DRV_LOG(NOTICE,
+			    "vlan filtering not available on this host");
+		return -ENOTSUP;
+	}
+
+	if (mask & ETH_VLAN_STRIP_MASK)
+		hw->vlan_strip = rxmode->hw_vlan_strip;
+
+	return 0;
+}
+
 static void
 virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 3910991..06735dd 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -100,7 +100,7 @@ static void vmxnet3_dev_info_get(struct rte_eth_dev *dev,
 vmxnet3_dev_supported_ptypes_get(struct rte_eth_dev *dev);
 static int vmxnet3_dev_vlan_filter_set(struct rte_eth_dev *dev,
 				       uint16_t vid, int on);
-static void vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void vmxnet3_mac_addr_set(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr);
 static void vmxnet3_interrupt_handler(void *param);
@@ -730,8 +730,10 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		devRead->rssConfDesc.confPA  = hw->rss_confPA;
 	}
 
-	vmxnet3_dev_vlan_offload_set(dev,
+	ret = vmxnet3_dev_vlan_offload_set(dev,
 				     ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK);
+	if (ret)
+		return ret;
 
 	vmxnet3_write_mac(hw, dev->data->mac_addrs->addr_bytes);
 
@@ -1275,7 +1277,7 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 	return 0;
 }
 
-static void
+static int
 vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct vmxnet3_hw *hw = dev->data->dev_private;
@@ -1301,6 +1303,8 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD,
 				       VMXNET3_CMD_UPDATE_VLAN_FILTERS);
 	}
+
+	return 0;
 }
 
 static void
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 0597641..d592a96 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2049,10 +2049,16 @@ struct rte_eth_dev *
 	int ret = 0;
 	int mask = 0;
 	int cur, org = 0;
+	uint8_t org_strip, org_filter, org_extend;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
 
+	/* save original values in case of failure */
+	org_strip = dev->data->dev_conf.rxmode.hw_vlan_strip;
+	org_filter = dev->data->dev_conf.rxmode.hw_vlan_filter;
+	org_extend = dev->data->dev_conf.rxmode.hw_vlan_extend;
+
 	/*check which option changed by application*/
 	cur = !!(offload_mask & ETH_VLAN_STRIP_OFFLOAD);
 	org = !!(dev->data->dev_conf.rxmode.hw_vlan_strip);
@@ -2080,7 +2086,13 @@ struct rte_eth_dev *
 		return ret;
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_offload_set, -ENOTSUP);
-	(*dev->dev_ops->vlan_offload_set)(dev, mask);
+	ret = (*dev->dev_ops->vlan_offload_set)(dev, mask);
+	if (ret) {
+		/* hit an error restore  original values */
+		dev->data->dev_conf.rxmode.hw_vlan_strip = org_strip;
+		dev->data->dev_conf.rxmode.hw_vlan_filter = org_filter;
+		dev->data->dev_conf.rxmode.hw_vlan_extend = org_extend;
+	}
 
 	return ret;
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 0adf327..7254fd0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1245,7 +1245,7 @@ typedef int (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
 			       enum rte_vlan_type type, uint16_t tpid);
 /**< @internal set the outer/inner VLAN-TPID by an Ethernet device. */
 
-typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
+typedef int (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
 /**< @internal set VLAN offload function by an Ethernet device. */
 
 typedef int (*vlan_pvid_set_t)(struct rte_eth_dev *dev,
-- 
1.8.3.1

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v2] ethdev: modifiy vlan_offload_set_t to return int
  2017-08-24 23:18  4% [dpdk-dev] [PATCH] ethdev: modifiy vlan_offload_set_t to return int David Harton
@ 2017-08-25 13:33  4% ` David Harton
  2017-08-25 13:47  4%   ` [dpdk-dev] [PATCH v3] " David Harton
  0 siblings, 1 reply; 200+ results
From: David Harton @ 2017-08-25 13:33 UTC (permalink / raw)
  To: thomas, ferruh.yigit, stephen.hurd, ajit.khaparde, johndale,
	konstantin.ananyev, jingjing.wu, beilei.xing, jing.d.chen,
	adrien.mazarguil, nelio.laranjeiro, alejandro.lucero,
	hemant.agrawal, rasesh.mody, harish.patil, skhare, yliu,
	maxime.coquelin, allain.legacy
  Cc: dev, David Harton

Some devices may not support or fail setting VLAN offload
configuration based on dynamic circurmstances so the
vlan_offload_set_t vector is modified to return an int so
the caller can determine success or not.

rte_eth_dev_set_vlan_offload is updated to return the
value provided by the vector when called along with restoring
the original offload configs on failure.

Existing vlan_offload_set_t vectors are modified to return
an int.  Majority of cases return 0 but a few that actually
can fail now return their failure codes.

Finally, a vlan_offload_set_t vector is added to virtio
to facilitate dynamically turning VLAN strip on or off.

Signed-off-by: David Harton <dharton@cisco.com>
---

*v2
Fixed a missed format error.
Removed vlan offload vector call casts and replaced with checks 
for return values.

*v1
This is an ABI breakage that has been previously negotiated
with Thomas and the proposed rel note change is included as well.

 doc/guides/rel_notes/release_17_11.rst |  2 +-
 drivers/net/avp/avp_ethdev.c           | 12 +++++++++---
 drivers/net/bnxt/bnxt_ethdev.c         |  9 ++++++---
 drivers/net/dpaa2/dpaa2_ethdev.c       | 13 ++++++++++---
 drivers/net/e1000/em_ethdev.c          | 12 +++++++++---
 drivers/net/e1000/igb_ethdev.c         | 12 +++++++++---
 drivers/net/enic/enic_ethdev.c         |  8 +++++---
 drivers/net/fm10k/fm10k_ethdev.c       |  3 ++-
 drivers/net/i40e/i40e_ethdev.c         | 11 ++++++++---
 drivers/net/i40e/i40e_ethdev_vf.c      |  9 ++++++---
 drivers/net/ixgbe/ixgbe_ethdev.c       | 25 ++++++++++++++++++-------
 drivers/net/mlx5/mlx5.h                |  2 +-
 drivers/net/mlx5/mlx5_vlan.c           |  3 ++-
 drivers/net/nfp/nfp_net.c              | 13 +++++++------
 drivers/net/qede/qede_ethdev.c         |  9 +++++++--
 drivers/net/virtio/virtio_ethdev.c     | 21 +++++++++++++++++++++
 drivers/net/vmxnet3/vmxnet3_ethdev.c   | 10 +++++++---
 lib/librte_ether/rte_ethdev.c          | 14 +++++++++++++-
 lib/librte_ether/rte_ethdev.h          |  2 +-
 19 files changed, 142 insertions(+), 48 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..e74f70c 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,7 +124,7 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
-
+* Changed return type of ``vlan_offload_set_t`` from ``void`` to ``int``.
 
 Shared Library Versions
 -----------------------
diff --git a/drivers/net/avp/avp_ethdev.c b/drivers/net/avp/avp_ethdev.c
index c746a0e..4011dfa 100644
--- a/drivers/net/avp/avp_ethdev.c
+++ b/drivers/net/avp/avp_ethdev.c
@@ -70,7 +70,7 @@ static int avp_dev_create(struct rte_pci_device *pci_dev,
 static void avp_dev_close(struct rte_eth_dev *dev);
 static void avp_dev_info_get(struct rte_eth_dev *dev,
 			     struct rte_eth_dev_info *dev_info);
-static void avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int avp_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 static void avp_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static void avp_dev_promiscuous_disable(struct rte_eth_dev *dev);
@@ -2031,7 +2031,12 @@ struct avp_queue {
 	mask = (ETH_VLAN_STRIP_MASK |
 		ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK);
-	avp_vlan_offload_set(eth_dev, mask);
+	ret = avp_vlan_offload_set(eth_dev, mask);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "VLAN offload set failed by host, ret=%d\n",
+			    ret);
+		goto unlock;
+	}
 
 	/* update device config */
 	memset(&config, 0, sizeof(config));
@@ -2214,7 +2219,7 @@ struct avp_queue {
 	}
 }
 
-static void
+static int
 avp_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
@@ -2239,6 +2244,7 @@ struct avp_queue {
 		if (eth_dev->data->dev_conf.rxmode.hw_vlan_extend)
 			PMD_DRV_LOG(ERR, "VLAN extend offload not supported\n");
 	}
+	return 0;
 }
 
 static void
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index c9d1122..547bd55 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -144,7 +144,7 @@
 	ETH_RSS_NONFRAG_IPV6_TCP |	\
 	ETH_RSS_NONFRAG_IPV6_UDP)
 
-static void bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
+static int bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
 
 /***********************/
 
@@ -522,7 +522,9 @@ static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev)
 		vlan_mask |= ETH_VLAN_FILTER_MASK;
 	if (eth_dev->data->dev_conf.rxmode.hw_vlan_strip)
 		vlan_mask |= ETH_VLAN_STRIP_MASK;
-	bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	rc = bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	if (rc)
+		goto error;
 
 	return 0;
 
@@ -1275,7 +1277,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 		return bnxt_del_vlan_filter(bp, vlan_id);
 }
 
-static void
+static int
 bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask)
 {
 	struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
@@ -1307,6 +1309,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 
 	if (mask & ETH_VLAN_EXTEND_MASK)
 		RTE_LOG(ERR, PMD, "Extend VLAN Not supported\n");
+	return 0;
 }
 
 static void
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 429b3a0..3390cb3 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -138,7 +138,7 @@
 	return ret;
 }
 
-static void
+static int
 dpaa2_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct dpaa2_dev_priv *priv = dev->data->dev_private;
@@ -158,6 +158,7 @@
 			RTE_LOG(ERR, PMD, "Unable to set vlan filter = %d\n",
 				ret);
 	}
+	return 0;
 }
 
 static int
@@ -643,8 +644,14 @@
 		return ret;
 	}
 	/* VLAN Offload Settings */
-	if (priv->max_vlan_filters)
-		dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+	if (priv->max_vlan_filters) {
+		ret = dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+		if (ret) {
+			PMD_INIT_LOG(ERR, "Error to dpaa2_vlan_offload_set:"
+				     "code = %d\n", ret);
+			return ret;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index 3d4ab93..51f49d8 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -99,7 +99,7 @@ static int eth_em_interrupt_action(struct rte_eth_dev *dev,
 
 static int eth_em_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
-static void eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void em_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void em_vlan_hw_filter_disable(struct rte_eth_dev *dev);
 static void em_vlan_hw_strip_enable(struct rte_eth_dev *dev);
@@ -668,7 +668,12 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_em_vlan_offload_set(dev, mask);
+	ret = eth_em_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to update vlan offload");
+		em_dev_clear_queues(dev);
+		return ret;
+	}
 
 	/* Set Interrupt Throttling Rate to maximum allowed value. */
 	E1000_WRITE_REG(hw, E1000_ITR, UINT16_MAX);
@@ -1447,7 +1452,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
 }
 
-static void
+static int
 eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -1463,6 +1468,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			em_vlan_hw_filter_disable(dev);
 	}
+	return 0;
 }
 
 /*
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index e4f7a9f..fa15ee9 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -157,7 +157,7 @@ static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
 				 enum rte_vlan_type vlan_type,
 				 uint16_t tpid_id);
-static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev);
@@ -1400,7 +1400,12 @@ static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_igb_vlan_offload_set(dev, mask);
+	ret = eth_igb_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to set vlan offload");
+		igb_dev_clear_queues(dev);
+		return ret;
+	}
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable VLAN filter since VMDq always use VLAN filter */
@@ -2715,7 +2720,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 						2 * VLAN_TAG_SIZE);
 }
 
-static void
+static int
 eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -2738,6 +2743,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			igb_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index da8fec2..fc1eac2 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -347,7 +347,7 @@ static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return err;
 }
 
-static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
 
@@ -371,6 +371,8 @@ static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
+
+	return 0;
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -392,9 +394,9 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 			eth_dev->data->dev_conf.rxmode.split_hdr_size);
 	}
 
-	enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
 	enic->hw_ip_checksum = eth_dev->data->dev_conf.rxmode.hw_ip_checksum;
-	return 0;
+	return ret;
 }
 
 /* Start the device.
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index e60d3a3..f4626f7 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1590,7 +1590,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return 0;
 }
 
-static void
+static int
 fm10k_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -1609,6 +1609,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		if (!dev->data->dev_conf.rxmode.hw_vlan_filter)
 			PMD_INIT_LOG(ERR, "VLAN filter is always on in fm10k");
 	}
+	return 0;
 }
 
 /* Add/Remove a MAC address, and update filters to main VSI */
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 00b6082..d03a44b 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -278,7 +278,7 @@ static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
 static int i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			      enum rte_vlan_type vlan_type,
 			      uint16_t tpid);
-static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
 				      uint16_t queue,
 				      int on);
@@ -3130,7 +3130,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return ret;
 }
 
-static void
+static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -3163,6 +3163,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 	}
+	return 0;
 }
 
 static void
@@ -5216,7 +5217,11 @@ struct i40e_vsi *
 
 	/* Apply vlan offload setting */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
-	i40e_vlan_offload_set(dev, mask);
+	ret = i40e_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_DRV_LOG(INFO, "Failed to update vlan offload");
+		return ret;
+	}
 
 	/* Apply double-vlan setting, not implemented yet */
 
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index f6d8293..f7fffc2 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -118,7 +118,7 @@ static int i40evf_dev_xstats_get_names(struct rte_eth_dev *dev,
 static void i40evf_dev_xstats_reset(struct rte_eth_dev *dev);
 static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
 				  uint16_t vlan_id, int on);
-static void i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int i40evf_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid,
 				int on);
 static void i40evf_dev_close(struct rte_eth_dev *dev);
@@ -1634,7 +1634,9 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	int ret;
 
 	/* Apply vlan offload setting */
-	i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	ret = i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	if (ret)
+		return ret;
 
 	/* Apply pvid setting */
 	ret = i40evf_vlan_pvid_set(dev, data->dev_conf.txmode.pvid,
@@ -1642,7 +1644,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	return ret;
 }
 
-static void
+static int
 i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
@@ -1655,6 +1657,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			i40evf_disable_vlan_strip(dev);
 	}
+	return 0;
 }
 
 static int
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 22171d8..1ec5aaf 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -218,7 +218,7 @@ static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
 		uint16_t queue, bool on);
 static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
 		int on);
-static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev);
@@ -274,7 +274,7 @@ static int ixgbevf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev,
 		uint16_t queue, int on);
-static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on);
 static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
 					    uint16_t queue_id);
@@ -2125,7 +2125,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 }
 
-static void
+static int
 ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -2148,6 +2148,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			ixgbe_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 static void
@@ -2568,9 +2569,13 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 		goto error;
 	}
 
-    mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
+	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbe_vlan_offload_set(dev, mask);
+	err = ixgbe_vlan_offload_set(dev, mask);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Unable to set VLAN offload");
+		goto error;
+	}
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable vlan filtering for VMDq */
@@ -4993,7 +4998,12 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	/* Set HW strip */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbevf_vlan_offload_set(dev, mask);
+	err = ixgbevf_vlan_offload_set(dev, mask);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Unable to set VLAN offload (%d)", err);
+		ixgbe_dev_clear_queues(dev);
+		return err;
+	}
 
 	ixgbevf_dev_rxtx_start(dev);
 
@@ -5153,7 +5163,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 	ixgbe_vlan_hw_strip_bitmap_set(dev, queue, on);
 }
 
-static void
+static int
 ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct ixgbe_hw *hw =
@@ -5168,6 +5178,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 		for (i = 0; i < hw->mac.max_rx_queues; i++)
 			ixgbevf_vlan_strip_queue_set(dev, i, on);
 	}
+	return 0;
 }
 
 int
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 43c5384..93e71be 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -283,7 +283,7 @@ int mlx5_xstats_get_names(struct rte_eth_dev *,
 /* mlx5_vlan.c */
 
 int mlx5_vlan_filter_set(struct rte_eth_dev *, uint16_t, int);
-void mlx5_vlan_offload_set(struct rte_eth_dev *, int);
+int mlx5_vlan_offload_set(struct rte_eth_dev *, int);
 void mlx5_vlan_strip_queue_set(struct rte_eth_dev *, uint16_t, int);
 
 /* mlx5_trigger.c */
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index 1b0fa40..7215909 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -210,7 +210,7 @@
  * @param mask
  *   VLAN offload bit mask.
  */
-void
+int
 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct priv *priv = dev->data->dev_private;
@@ -230,4 +230,5 @@
 			priv_vlan_strip_queue_set(priv, i, hw_vlan_strip);
 		priv_unlock(priv);
 	}
+	return 0;
 }
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 92b03c4..6473edc 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2149,11 +2149,12 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 	return i;
 }
 
-static void
+static int
 nfp_net_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	uint32_t new_ctrl, update;
 	struct nfp_net_hw *hw;
+	int ret;
 
 	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	new_ctrl = 0;
@@ -2174,14 +2175,14 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 		new_ctrl = hw->ctrl & ~NFP_NET_CFG_CTRL_RXVLAN;
 
 	if (new_ctrl == 0)
-		return;
+		return 0;
 
 	update = NFP_NET_CFG_UPDATE_GEN;
 
-	if (nfp_net_reconfig(hw, new_ctrl, update) < 0)
-		return;
-
-	hw->ctrl = new_ctrl;
+	ret = nfp_net_reconfig(hw, new_ctrl, update);
+	if (!ret)
+		hw->ctrl = new_ctrl;
+	return ret;
 }
 
 /* Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device */
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 0e05989..c5b1653 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -975,7 +975,7 @@ static int qede_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return rc;
 }
 
-static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
 	struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
@@ -1013,6 +1013,8 @@ static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 
 	DP_INFO(edev, "vlan offload mask %d vlan-strip %d vlan-filter %d\n",
 		mask, rxmode->hw_vlan_strip, rxmode->hw_vlan_filter);
+
+	return 0;
 }
 
 static void qede_prandom_bytes(uint32_t *buff)
@@ -1157,6 +1159,7 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
 	struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
 	struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
 	struct rte_eth_rxmode *rxmode = &eth_dev->data->dev_conf.rxmode;
+        int ret;
 
 	PMD_INIT_FUNC_TRACE(edev);
 
@@ -1237,9 +1240,11 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
 	qdev->enable_lro = rxmode->enable_lro;
 
 	/* Enable VLAN offloads by default */
-	qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
+	ret = qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
 			ETH_VLAN_FILTER_MASK |
 			ETH_VLAN_EXTEND_MASK);
+	if (ret)
+		return ret;
 
 	DP_INFO(edev, "Device configured with RSS=%d TSS=%d\n",
 			QEDE_RSS_COUNT(qdev), QEDE_TSS_COUNT(qdev));
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index e320811..72b4248 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -72,6 +72,7 @@ static void virtio_dev_info_get(struct rte_eth_dev *dev,
 				struct rte_eth_dev_info *dev_info);
 static int virtio_dev_link_update(struct rte_eth_dev *dev,
 	int wait_to_complete);
+static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void virtio_set_hwaddr(struct virtio_hw *hw);
 static void virtio_get_hwaddr(struct virtio_hw *hw);
@@ -779,6 +780,7 @@ struct rte_virtio_xstats_name_off {
 	.stats_reset             = virtio_dev_stats_reset,
 	.xstats_reset            = virtio_dev_stats_reset,
 	.link_update             = virtio_dev_link_update,
+	.vlan_offload_set        = virtio_dev_vlan_offload_set,
 	.rx_queue_setup          = virtio_dev_rx_queue_setup,
 	.rx_queue_intr_enable    = virtio_dev_rx_queue_intr_enable,
 	.rx_queue_intr_disable   = virtio_dev_rx_queue_intr_disable,
@@ -1875,6 +1877,25 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev)
 	return (old.link_status == link.link_status) ? -1 : 0;
 }
 
+static int
+virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+	const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	if (rxmode->hw_vlan_filter &&
+	    !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) {
+		PMD_DRV_LOG(NOTICE,
+			    "vlan filtering not available on this host");
+		return -ENOTSUP;
+	}
+
+	if (mask & ETH_VLAN_STRIP_MASK)
+		hw->vlan_strip = rxmode->hw_vlan_strip;
+
+	return 0;
+}
+
 static void
 virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 3910991..06735dd 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -100,7 +100,7 @@ static void vmxnet3_dev_info_get(struct rte_eth_dev *dev,
 vmxnet3_dev_supported_ptypes_get(struct rte_eth_dev *dev);
 static int vmxnet3_dev_vlan_filter_set(struct rte_eth_dev *dev,
 				       uint16_t vid, int on);
-static void vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void vmxnet3_mac_addr_set(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr);
 static void vmxnet3_interrupt_handler(void *param);
@@ -730,8 +730,10 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		devRead->rssConfDesc.confPA  = hw->rss_confPA;
 	}
 
-	vmxnet3_dev_vlan_offload_set(dev,
+	ret = vmxnet3_dev_vlan_offload_set(dev,
 				     ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK);
+	if (ret)
+		return ret;
 
 	vmxnet3_write_mac(hw, dev->data->mac_addrs->addr_bytes);
 
@@ -1275,7 +1277,7 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 	return 0;
 }
 
-static void
+static int
 vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct vmxnet3_hw *hw = dev->data->dev_private;
@@ -1301,6 +1303,8 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD,
 				       VMXNET3_CMD_UPDATE_VLAN_FILTERS);
 	}
+
+	return 0;
 }
 
 static void
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 0597641..d592a96 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2049,10 +2049,16 @@ struct rte_eth_dev *
 	int ret = 0;
 	int mask = 0;
 	int cur, org = 0;
+	uint8_t org_strip, org_filter, org_extend;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
 
+	/* save original values in case of failure */
+	org_strip = dev->data->dev_conf.rxmode.hw_vlan_strip;
+	org_filter = dev->data->dev_conf.rxmode.hw_vlan_filter;
+	org_extend = dev->data->dev_conf.rxmode.hw_vlan_extend;
+
 	/*check which option changed by application*/
 	cur = !!(offload_mask & ETH_VLAN_STRIP_OFFLOAD);
 	org = !!(dev->data->dev_conf.rxmode.hw_vlan_strip);
@@ -2080,7 +2086,13 @@ struct rte_eth_dev *
 		return ret;
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_offload_set, -ENOTSUP);
-	(*dev->dev_ops->vlan_offload_set)(dev, mask);
+	ret = (*dev->dev_ops->vlan_offload_set)(dev, mask);
+	if (ret) {
+		/* hit an error restore  original values */
+		dev->data->dev_conf.rxmode.hw_vlan_strip = org_strip;
+		dev->data->dev_conf.rxmode.hw_vlan_filter = org_filter;
+		dev->data->dev_conf.rxmode.hw_vlan_extend = org_extend;
+	}
 
 	return ret;
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 0adf327..7254fd0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1245,7 +1245,7 @@ typedef int (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
 			       enum rte_vlan_type type, uint16_t tpid);
 /**< @internal set the outer/inner VLAN-TPID by an Ethernet device. */
 
-typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
+typedef int (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
 /**< @internal set VLAN offload function by an Ethernet device. */
 
 typedef int (*vlan_pvid_set_t)(struct rte_eth_dev *dev,
-- 
1.8.3.1

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API
  2017-08-07 10:54  4% [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API Shahaf Shuler
                   ` (2 preceding siblings ...)
  2017-08-23  6:39  0% ` [dpdk-dev] [RFC PATCH 0/4] ethdev new " Shahaf Shuler
@ 2017-08-25 10:31  0% ` Jerin Jacob
  3 siblings, 0 replies; 200+ results
From: Jerin Jacob @ 2017-08-25 10:31 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: dev

-----Original Message-----
> Date: Mon,  7 Aug 2017 13:54:27 +0300
> From: Shahaf Shuler <shahafs@mellanox.com>
> To: dev@dpdk.org
> Subject: [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API
> X-Mailer: git-send-email 2.12.0
> 
> Tx offloads configuration is per queue. Tx offloads are enabled by default, 
> and can be disabled using ETH_TXQ_FLAGS_NO* flags. 
> This behaviour is not consistent with the Rx side where the Rx offloads
> configuration is per port. Rx offloads are disabled by default and enabled 
> according to bit field in rte_eth_rxmode structure.
> 
> Moreover, considering more Tx and Rx offloads will be added 
> over time, the cost of managing them all inside the PMD will be tremendous,
> as the PMD will need to check the matching for the entire offload set 
> for each mbuf it handles.
> In addition, on the current approach each Rx offload added breaks the
> ABI compatibility as it requires to add entries to existing bit-fields.
>  
> The RFC address above issues by defining a new offloads API.
> With the new API, Tx and Rx offloads configuration is per queue.
> The offloads are disabled by default. Each offload can be enabled or
> disabled using the existing DEV_TX_OFFLOADS_* or DEV_RX_OFFLOADS_* flags.
> Such API will enable to easily add or remove offloads, without breaking the
> ABI compatibility.
> 
> The new API does not have an equivalent for the below Tx flags:
> 
> * ETH_TXQ_FLAGS_NOREFCOUNT
> * ETH_TXQ_FLAGS_NOMULTMEMP

IMO, it make sense to keep those flags as PMD optimization if an application
does not need reference count and multi mempool in the application.
As example, An non trivial application like l3fwd does not need both of them.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] vhost: added user callbacks for socket open/close
  2017-08-22 16:24  3% ` [dpdk-dev] [PATCH v2] " Dariusz Stojaczyk
@ 2017-08-25  9:22  0%   ` Jens Freimann
  2017-08-29  6:08  3%     ` Stojaczyk, DariuszX
  2017-08-30 10:50  3%   ` [dpdk-dev] [PATCH v3] rte_vhost: " Dariusz Stojaczyk
  1 sibling, 1 reply; 200+ results
From: Jens Freimann @ 2017-08-25  9:22 UTC (permalink / raw)
  To: Dariusz Stojaczyk; +Cc: dev, Pawel Wodkowski, maxime.coquelin, yliu


Hi Dariusz,

On Tue, Aug 22, 2017 at 06:24:52PM +0200, Dariusz Stojaczyk wrote:
>When user receives destroy_device signal, he does not know *why* that
>event happened. He does not differ between socket shutdown and virtio
>processing pause. User could completely delete device during transition
>from BIOS to kernel, causing freeze or possibly kernel panic. Instead
>of changing new_device/destroy_device callbacks and breaking the ABI,
>a set of new functions new_connection/destroy_connection has been added.
>
>Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
>---
>v2: also updated vhost_lib.rst
> doc/guides/prog_guide/vhost_lib.rst | 15 +++++++++++++--
> lib/librte_vhost/rte_vhost.h        |  5 ++++-
> lib/librte_vhost/socket.c           | 23 +++++++++++++++++++----
> 3 files changed, 36 insertions(+), 7 deletions(-)

thanks for adding documentation!

I'm still not sure I understand the use case. So just for my
understanding: users need to distinct between "the device is going
away temporarily, keep the connection" and "we're shutting down for good", is that it?
Maybe it's just me or maybe it means you could explain your example in
the commit message a bit more.  I think the code looks sane, so 

Reviewed-by: Jens Freimann <jfreimann@redhat.com> 

Oh, and you should put the maintainers on Cc to get a faster review. 

regards,
Jens 

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] ethdev: modifiy vlan_offload_set_t to return int
@ 2017-08-24 23:18  4% David Harton
  2017-08-25 13:33  4% ` [dpdk-dev] [PATCH v2] " David Harton
  0 siblings, 1 reply; 200+ results
From: David Harton @ 2017-08-24 23:18 UTC (permalink / raw)
  To: thomas, ferruh.yigit, stephen.hurd, ajit.khaparde, johndale,
	wenzhuo.lu, konstantin.ananyev, jingjing.wu, beilei.xing,
	jing.d.chen, adrien.mazarguil, nelio.laranjeiro,
	alejandro.lucero, hemant.agrawal, rasesh.mody, harish.patil,
	skhare, yliu, maxime.coquelin, allain.legacy
  Cc: dev, David Harton

Some devices may not support or fail setting VLAN offload
configuration based on dynamic circurmstances so the
vlan_offload_set_t vector is modified to return an int so
the caller can determine success or not.

rte_eth_dev_set_vlan_offload is updated to return the
value provided by the vector when called along with restoring
the original offload configs on failure.

Existing vlan_offload_set_t vectors are modified to return
an int.  Majority of cases return 0 but a few that actually
can fail now return their failure codes.

Finally, a vlan_offload_set_t vector is added to virtio
to facilitate dynamically turning VLAN strip on or off.

This is an ABI breakage that has been previously negotiated
with Thomas and the proposed rel note change is included as well.

Signed-off-by: David Harton <dharton@cisco.com>
---
 doc/guides/rel_notes/release_17_11.rst |  2 +-
 drivers/net/avp/avp_ethdev.c           |  7 ++++---
 drivers/net/bnxt/bnxt_ethdev.c         |  9 ++++++---
 drivers/net/dpaa2/dpaa2_ethdev.c       | 13 ++++++++++---
 drivers/net/e1000/em_ethdev.c          | 12 +++++++++---
 drivers/net/e1000/igb_ethdev.c         | 12 +++++++++---
 drivers/net/enic/enic_ethdev.c         |  8 +++++---
 drivers/net/fm10k/fm10k_ethdev.c       |  3 ++-
 drivers/net/i40e/i40e_ethdev.c         | 11 ++++++++---
 drivers/net/i40e/i40e_ethdev_vf.c      |  9 ++++++---
 drivers/net/ixgbe/ixgbe_ethdev.c       | 14 ++++++++------
 drivers/net/mlx5/mlx5.h                |  2 +-
 drivers/net/mlx5/mlx5_vlan.c           |  3 ++-
 drivers/net/nfp/nfp_net.c              | 13 +++++++------
 drivers/net/qede/qede_ethdev.c         |  6 ++++--
 drivers/net/virtio/virtio_ethdev.c     | 21 +++++++++++++++++++++
 drivers/net/vmxnet3/vmxnet3_ethdev.c   |  8 +++++---
 lib/librte_ether/rte_ethdev.c          | 14 +++++++++++++-
 lib/librte_ether/rte_ethdev.h          |  2 +-
 19 files changed, 122 insertions(+), 47 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..e74f70c 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,7 +124,7 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
-
+* Changed return type of ``vlan_offload_set_t`` from ``void`` to ``int``.
 
 Shared Library Versions
 -----------------------
diff --git a/drivers/net/avp/avp_ethdev.c b/drivers/net/avp/avp_ethdev.c
index c746a0e..3525e8f 100644
--- a/drivers/net/avp/avp_ethdev.c
+++ b/drivers/net/avp/avp_ethdev.c
@@ -70,7 +70,7 @@ static int avp_dev_create(struct rte_pci_device *pci_dev,
 static void avp_dev_close(struct rte_eth_dev *dev);
 static void avp_dev_info_get(struct rte_eth_dev *dev,
 			     struct rte_eth_dev_info *dev_info);
-static void avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int avp_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 static void avp_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static void avp_dev_promiscuous_disable(struct rte_eth_dev *dev);
@@ -2031,7 +2031,7 @@ struct avp_queue {
 	mask = (ETH_VLAN_STRIP_MASK |
 		ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK);
-	avp_vlan_offload_set(eth_dev, mask);
+	(void)avp_vlan_offload_set(eth_dev, mask);
 
 	/* update device config */
 	memset(&config, 0, sizeof(config));
@@ -2214,7 +2214,7 @@ struct avp_queue {
 	}
 }
 
-static void
+static int
 avp_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
@@ -2239,6 +2239,7 @@ struct avp_queue {
 		if (eth_dev->data->dev_conf.rxmode.hw_vlan_extend)
 			PMD_DRV_LOG(ERR, "VLAN extend offload not supported\n");
 	}
+	return 0;
 }
 
 static void
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index c9d1122..547bd55 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -144,7 +144,7 @@
 	ETH_RSS_NONFRAG_IPV6_TCP |	\
 	ETH_RSS_NONFRAG_IPV6_UDP)
 
-static void bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
+static int bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
 
 /***********************/
 
@@ -522,7 +522,9 @@ static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev)
 		vlan_mask |= ETH_VLAN_FILTER_MASK;
 	if (eth_dev->data->dev_conf.rxmode.hw_vlan_strip)
 		vlan_mask |= ETH_VLAN_STRIP_MASK;
-	bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	rc = bnxt_vlan_offload_set_op(eth_dev, vlan_mask);
+	if (rc)
+		goto error;
 
 	return 0;
 
@@ -1275,7 +1277,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 		return bnxt_del_vlan_filter(bp, vlan_id);
 }
 
-static void
+static int
 bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask)
 {
 	struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
@@ -1307,6 +1309,7 @@ static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev,
 
 	if (mask & ETH_VLAN_EXTEND_MASK)
 		RTE_LOG(ERR, PMD, "Extend VLAN Not supported\n");
+	return 0;
 }
 
 static void
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 429b3a0..3390cb3 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -138,7 +138,7 @@
 	return ret;
 }
 
-static void
+static int
 dpaa2_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct dpaa2_dev_priv *priv = dev->data->dev_private;
@@ -158,6 +158,7 @@
 			RTE_LOG(ERR, PMD, "Unable to set vlan filter = %d\n",
 				ret);
 	}
+	return 0;
 }
 
 static int
@@ -643,8 +644,14 @@
 		return ret;
 	}
 	/* VLAN Offload Settings */
-	if (priv->max_vlan_filters)
-		dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+	if (priv->max_vlan_filters) {
+		ret = dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+		if (ret) {
+			PMD_INIT_LOG(ERR, "Error to dpaa2_vlan_offload_set:"
+				     "code = %d\n", ret);
+			return ret;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index 3d4ab93..51f49d8 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -99,7 +99,7 @@ static int eth_em_interrupt_action(struct rte_eth_dev *dev,
 
 static int eth_em_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
-static void eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void em_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void em_vlan_hw_filter_disable(struct rte_eth_dev *dev);
 static void em_vlan_hw_strip_enable(struct rte_eth_dev *dev);
@@ -668,7 +668,12 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_em_vlan_offload_set(dev, mask);
+	ret = eth_em_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to update vlan offload");
+		em_dev_clear_queues(dev);
+		return ret;
+	}
 
 	/* Set Interrupt Throttling Rate to maximum allowed value. */
 	E1000_WRITE_REG(hw, E1000_ITR, UINT16_MAX);
@@ -1447,7 +1452,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 	E1000_WRITE_REG(hw, E1000_CTRL, reg);
 }
 
-static void
+static int
 eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -1463,6 +1468,7 @@ static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			em_vlan_hw_filter_disable(dev);
 	}
+	return 0;
 }
 
 /*
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index e4f7a9f..fa15ee9 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -157,7 +157,7 @@ static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
 				 enum rte_vlan_type vlan_type,
 				 uint16_t tpid_id);
-static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev);
@@ -1400,7 +1400,12 @@ static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
 			ETH_VLAN_EXTEND_MASK;
-	eth_igb_vlan_offload_set(dev, mask);
+	ret = eth_igb_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Unable to set vlan offload");
+		igb_dev_clear_queues(dev);
+		return ret;
+	}
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable VLAN filter since VMDq always use VLAN filter */
@@ -2715,7 +2720,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 						2 * VLAN_TAG_SIZE);
 }
 
-static void
+static int
 eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if(mask & ETH_VLAN_STRIP_MASK){
@@ -2738,6 +2743,7 @@ static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			igb_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index da8fec2..fc1eac2 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -347,7 +347,7 @@ static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return err;
 }
 
-static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
 
@@ -371,6 +371,8 @@ static void enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
+
+	return 0;
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -392,9 +394,9 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 			eth_dev->data->dev_conf.rxmode.split_hdr_size);
 	}
 
-	enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
 	enic->hw_ip_checksum = eth_dev->data->dev_conf.rxmode.hw_ip_checksum;
-	return 0;
+	return ret;
 }
 
 /* Start the device.
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index e60d3a3..f4626f7 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1590,7 +1590,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return 0;
 }
 
-static void
+static int
 fm10k_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -1609,6 +1609,7 @@ static int fm10k_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		if (!dev->data->dev_conf.rxmode.hw_vlan_filter)
 			PMD_INIT_LOG(ERR, "VLAN filter is always on in fm10k");
 	}
+	return 0;
 }
 
 /* Add/Remove a MAC address, and update filters to main VSI */
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 00b6082..d03a44b 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -278,7 +278,7 @@ static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
 static int i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			      enum rte_vlan_type vlan_type,
 			      uint16_t tpid);
-static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
 				      uint16_t queue,
 				      int on);
@@ -3130,7 +3130,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	return ret;
 }
 
-static void
+static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -3163,6 +3163,7 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		else
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 	}
+	return 0;
 }
 
 static void
@@ -5216,7 +5217,11 @@ struct i40e_vsi *
 
 	/* Apply vlan offload setting */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
-	i40e_vlan_offload_set(dev, mask);
+	ret = i40e_vlan_offload_set(dev, mask);
+	if (ret) {
+		PMD_DRV_LOG(INFO, "Failed to update vlan offload");
+		return ret;
+	}
 
 	/* Apply double-vlan setting, not implemented yet */
 
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index f6d8293..f7fffc2 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -118,7 +118,7 @@ static int i40evf_dev_xstats_get_names(struct rte_eth_dev *dev,
 static void i40evf_dev_xstats_reset(struct rte_eth_dev *dev);
 static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
 				  uint16_t vlan_id, int on);
-static void i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static int i40evf_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid,
 				int on);
 static void i40evf_dev_close(struct rte_eth_dev *dev);
@@ -1634,7 +1634,9 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	int ret;
 
 	/* Apply vlan offload setting */
-	i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	ret = i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+	if (ret)
+		return ret;
 
 	/* Apply pvid setting */
 	ret = i40evf_vlan_pvid_set(dev, data->dev_conf.txmode.pvid,
@@ -1642,7 +1644,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 	return ret;
 }
 
-static void
+static int
 i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
@@ -1655,6 +1657,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			i40evf_disable_vlan_strip(dev);
 	}
+	return 0;
 }
 
 static int
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 22171d8..043a713 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -218,7 +218,7 @@ static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
 		uint16_t queue, bool on);
 static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
 		int on);
-static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev);
@@ -274,7 +274,7 @@ static int ixgbevf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev,
 		uint16_t queue, int on);
-static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on);
 static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
 					    uint16_t queue_id);
@@ -2125,7 +2125,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 	 */
 }
 
-static void
+static int
 ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	if (mask & ETH_VLAN_STRIP_MASK) {
@@ -2148,6 +2148,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 		else
 			ixgbe_vlan_hw_extend_disable(dev);
 	}
+	return 0;
 }
 
 static void
@@ -2570,7 +2571,7 @@ static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
 
     mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbe_vlan_offload_set(dev, mask);
+	(void)ixgbe_vlan_offload_set(dev, mask);
 
 	if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
 		/* Enable vlan filtering for VMDq */
@@ -4993,7 +4994,7 @@ static int ixgbevf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	/* Set HW strip */
 	mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
 		ETH_VLAN_EXTEND_MASK;
-	ixgbevf_vlan_offload_set(dev, mask);
+	(void)ixgbevf_vlan_offload_set(dev, mask);
 
 	ixgbevf_dev_rxtx_start(dev);
 
@@ -5153,7 +5154,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 	ixgbe_vlan_hw_strip_bitmap_set(dev, queue, on);
 }
 
-static void
+static int
 ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct ixgbe_hw *hw =
@@ -5168,6 +5169,7 @@ static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
 		for (i = 0; i < hw->mac.max_rx_queues; i++)
 			ixgbevf_vlan_strip_queue_set(dev, i, on);
 	}
+	return 0;
 }
 
 int
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 43c5384..93e71be 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -283,7 +283,7 @@ int mlx5_xstats_get_names(struct rte_eth_dev *,
 /* mlx5_vlan.c */
 
 int mlx5_vlan_filter_set(struct rte_eth_dev *, uint16_t, int);
-void mlx5_vlan_offload_set(struct rte_eth_dev *, int);
+int mlx5_vlan_offload_set(struct rte_eth_dev *, int);
 void mlx5_vlan_strip_queue_set(struct rte_eth_dev *, uint16_t, int);
 
 /* mlx5_trigger.c */
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index 1b0fa40..7215909 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -210,7 +210,7 @@
  * @param mask
  *   VLAN offload bit mask.
  */
-void
+int
 mlx5_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct priv *priv = dev->data->dev_private;
@@ -230,4 +230,5 @@
 			priv_vlan_strip_queue_set(priv, i, hw_vlan_strip);
 		priv_unlock(priv);
 	}
+	return 0;
 }
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 92b03c4..6473edc 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2149,11 +2149,12 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 	return i;
 }
 
-static void
+static int
 nfp_net_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	uint32_t new_ctrl, update;
 	struct nfp_net_hw *hw;
+	int ret;
 
 	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	new_ctrl = 0;
@@ -2174,14 +2175,14 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 		new_ctrl = hw->ctrl & ~NFP_NET_CFG_CTRL_RXVLAN;
 
 	if (new_ctrl == 0)
-		return;
+		return 0;
 
 	update = NFP_NET_CFG_UPDATE_GEN;
 
-	if (nfp_net_reconfig(hw, new_ctrl, update) < 0)
-		return;
-
-	hw->ctrl = new_ctrl;
+	ret = nfp_net_reconfig(hw, new_ctrl, update);
+	if (!ret)
+		hw->ctrl = new_ctrl;
+	return ret;
 }
 
 /* Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device */
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 0e05989..ee29754 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -975,7 +975,7 @@ static int qede_vlan_filter_set(struct rte_eth_dev *eth_dev,
 	return rc;
 }
 
-static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+static int qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
 	struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
@@ -1013,6 +1013,8 @@ static void qede_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 
 	DP_INFO(edev, "vlan offload mask %d vlan-strip %d vlan-filter %d\n",
 		mask, rxmode->hw_vlan_strip, rxmode->hw_vlan_filter);
+
+	return 0;
 }
 
 static void qede_prandom_bytes(uint32_t *buff)
@@ -1237,7 +1239,7 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
 	qdev->enable_lro = rxmode->enable_lro;
 
 	/* Enable VLAN offloads by default */
-	qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
+	(void)qede_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK  |
 			ETH_VLAN_FILTER_MASK |
 			ETH_VLAN_EXTEND_MASK);
 
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index e320811..fba92f4 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -72,6 +72,7 @@ static void virtio_dev_info_get(struct rte_eth_dev *dev,
 				struct rte_eth_dev_info *dev_info);
 static int virtio_dev_link_update(struct rte_eth_dev *dev,
 	int wait_to_complete);
+static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void virtio_set_hwaddr(struct virtio_hw *hw);
 static void virtio_get_hwaddr(struct virtio_hw *hw);
@@ -779,6 +780,7 @@ struct rte_virtio_xstats_name_off {
 	.stats_reset             = virtio_dev_stats_reset,
 	.xstats_reset            = virtio_dev_stats_reset,
 	.link_update             = virtio_dev_link_update,
+	.vlan_offload_set        = virtio_dev_vlan_offload_set,
 	.rx_queue_setup          = virtio_dev_rx_queue_setup,
 	.rx_queue_intr_enable    = virtio_dev_rx_queue_intr_enable,
 	.rx_queue_intr_disable   = virtio_dev_rx_queue_intr_disable,
@@ -1875,6 +1877,25 @@ static void virtio_dev_free_mbufs(struct rte_eth_dev *dev)
 	return (old.link_status == link.link_status) ? -1 : 0;
 }
 
+static int
+virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+	const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	if (rxmode->hw_vlan_filter
+	    && !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) {
+		PMD_DRV_LOG(NOTICE,
+			    "vlan filtering not available on this host");
+		return -ENOTSUP;
+	}
+
+	if (mask & ETH_VLAN_STRIP_MASK)
+		hw->vlan_strip = rxmode->hw_vlan_strip;
+
+	return 0;
+}
+
 static void
 virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 3910991..81ee262 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -100,7 +100,7 @@ static void vmxnet3_dev_info_get(struct rte_eth_dev *dev,
 vmxnet3_dev_supported_ptypes_get(struct rte_eth_dev *dev);
 static int vmxnet3_dev_vlan_filter_set(struct rte_eth_dev *dev,
 				       uint16_t vid, int on);
-static void vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void vmxnet3_mac_addr_set(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr);
 static void vmxnet3_interrupt_handler(void *param);
@@ -730,7 +730,7 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		devRead->rssConfDesc.confPA  = hw->rss_confPA;
 	}
 
-	vmxnet3_dev_vlan_offload_set(dev,
+	(void)vmxnet3_dev_vlan_offload_set(dev,
 				     ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK);
 
 	vmxnet3_write_mac(hw, dev->data->mac_addrs->addr_bytes);
@@ -1275,7 +1275,7 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 	return 0;
 }
 
-static void
+static int
 vmxnet3_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct vmxnet3_hw *hw = dev->data->dev_private;
@@ -1301,6 +1301,8 @@ static int eth_vmxnet3_pci_remove(struct rte_pci_device *pci_dev)
 		VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD,
 				       VMXNET3_CMD_UPDATE_VLAN_FILTERS);
 	}
+
+	return 0;
 }
 
 static void
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 0597641..f13f813 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2049,10 +2049,16 @@ struct rte_eth_dev *
 	int ret = 0;
 	int mask = 0;
 	int cur, org = 0;
+	uint8_t org_strip, org_filter, org_extend;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
 
+	/* save original values in case of failure */
+	org_strip = dev->data->dev_conf.rxmode.hw_vlan_strip;
+	org_filter = dev->data->dev_conf.rxmode.hw_vlan_filter;
+	org_extend = dev->data->dev_conf.rxmode.hw_vlan_extend;
+
 	/*check which option changed by application*/
 	cur = !!(offload_mask & ETH_VLAN_STRIP_OFFLOAD);
 	org = !!(dev->data->dev_conf.rxmode.hw_vlan_strip);
@@ -2080,7 +2086,13 @@ struct rte_eth_dev *
 		return ret;
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_offload_set, -ENOTSUP);
-	(*dev->dev_ops->vlan_offload_set)(dev, mask);
+	ret = (*dev->dev_ops->vlan_offload_set)(dev, mask);
+	if (ret) {
+		/* hit an error restore  original values */
+		dev->data->dev_conf.rxmode.hw_vlan_strip = org_strip;
+		dev->data->dev_conf.rxmode.hw_vlan_filter = org_filter;
+		dev->data->dev_conf.rxmode.hw_vlan_extend = org_extend;
+        }
 
 	return ret;
 }
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 0adf327..7254fd0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1245,7 +1245,7 @@ typedef int (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
 			       enum rte_vlan_type type, uint16_t tpid);
 /**< @internal set the outer/inner VLAN-TPID by an Ethernet device. */
 
-typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
+typedef int (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
 /**< @internal set VLAN offload function by an Ethernet device. */
 
 typedef int (*vlan_pvid_set_t)(struct rte_eth_dev *dev,
-- 
1.8.3.1

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH 11/16] nfp: allocate eth_dev from pf probe function
    2017-08-24 16:20 10% ` [dpdk-dev] [PATCH 02/16] nfp: add specific pf probe function Alejandro Lucero
@ 2017-08-24 16:20  6% ` Alejandro Lucero
  1 sibling, 0 replies; 200+ results
From: Alejandro Lucero @ 2017-08-24 16:20 UTC (permalink / raw)
  To: dev

NFP can support several physical ports per PF device. Depending on
firmware info, one or more eth_dev objects will need to be created.

This patch adds the call to create just one eth_dev by now with future
commits supporting the multiport option. Once the eth_dev has been
created, probe function invokes pmd initialization with the new eth_dev.

Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>
---
 drivers/net/nfp/nfp_net.c | 50 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 7c23b7a..6005e41 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2677,13 +2677,16 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 			    struct rte_pci_device *dev)
 {
+	struct rte_eth_dev *eth_dev;
+	struct nfp_net_hw *hw;
 	nfpu_desc_t *nfpu_desc;
 	nspu_desc_t *nspu_desc;
 	uint64_t offset_symbol;
 	int major, minor;
+	int ret = -ENODEV;
 
 	if (!dev)
-		return -ENODEV;
+		return ret;
 
 	nfpu_desc = rte_malloc("nfp nfpu", sizeof(nfpu_desc_t), 0);
 	if (!nfpu_desc)
@@ -2697,29 +2700,60 @@ static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	nspu_desc = nfpu_desc->nspu;
 
-
 	/* Check NSP ABI version */
 	if (nfp_nsp_get_abi_version(nspu_desc, &major, &minor) < 0) {
 		RTE_LOG(INFO, PMD, "NFP NSP not present\n");
-		goto no_abi;
+		goto error;
 	}
 	PMD_INIT_LOG(INFO, "nspu ABI version: %d.%d\n", major, minor);
 
 	if (minor < 20) {
 		RTE_LOG(INFO, PMD, "NFP NSP ABI version too old. Required 0.20 or higher\n");
-		goto no_abi;
+		goto error;
 	}
 
-	nfp_nsp_fw_setup(nspu_desc, "nfd_cfg_pf0_num_ports", &offset_symbol);
+	ret = nfp_nsp_fw_setup(nspu_desc, "nfd_cfg_pf0_num_ports",
+			       &offset_symbol);
+	if (ret)
+		goto error;
 
-	/* No port is created yet */
+	eth_dev = rte_eth_dev_allocate(dev->device.name);
+	if (!eth_dev) {
+		ret = -ENODEV;
+		goto error;
+	}
 
-no_abi:
+	eth_dev->data->dev_private = rte_zmalloc("nfp_pf_port",
+						 sizeof(struct nfp_net_adapter),
+						 RTE_CACHE_LINE_SIZE);
+	if (!eth_dev->data->dev_private) {
+		rte_eth_dev_release_port(eth_dev);
+		ret = -ENODEV;
+		goto error;
+	}
+
+	hw = (struct nfp_net_hw *)(eth_dev->data->dev_private);
+	hw->nspu_desc = nspu_desc;
+	hw->nfpu_desc = nfpu_desc;
+	hw->is_pf = 1;
+
+	eth_dev->device = &dev->device;
+	rte_eth_copy_pci_info(eth_dev, dev);
+
+	ret = nfp_net_init(eth_dev);
+
+	if (!ret)
+		return 0;
+
+	/* something went wrong */
+	rte_eth_dev_release_port(eth_dev);
+
+error:
 	nfpu_close(nfpu_desc);
 nfpu_error:
 	rte_free(nfpu_desc);
 
-	return -ENODEV;
+	return ret;
 }
 
 static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
-- 
1.9.1

^ permalink raw reply	[relevance 6%]

* [dpdk-dev] [PATCH 02/16] nfp: add specific pf probe function
  @ 2017-08-24 16:20 10% ` Alejandro Lucero
  2017-08-28 16:42  0%   ` Ferruh Yigit
  2017-08-24 16:20  6% ` [dpdk-dev] [PATCH 11/16] nfp: allocate eth_dev from " Alejandro Lucero
  1 sibling, 1 reply; 200+ results
From: Alejandro Lucero @ 2017-08-24 16:20 UTC (permalink / raw)
  To: dev

Configuring the NFP PMD for using the PF requires access through the
NSPU interface for device configuration. This patch adds a specific probe
function for the PF which uses the NSPU interface. Just basic NSPU access
is done by now reading the NSPU ABI version.

No ethernet port is created yet.

Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>
---
 drivers/net/nfp/nfp_net.c | 75 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 69 insertions(+), 6 deletions(-)

diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index a3bf5e1..e2fe83a 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -59,6 +59,8 @@
 #include "nfp_net_logs.h"
 #include "nfp_net_ctrl.h"
 
+#include "nfp_nfpu.h"
+
 /* Prototypes */
 static void nfp_net_close(struct rte_eth_dev *dev);
 static int nfp_net_configure(struct rte_eth_dev *dev);
@@ -2632,12 +2634,63 @@ uint32_t nfp_net_txq_full(struct nfp_net_txq *txq)
 	return 0;
 }
 
-static const struct rte_pci_id pci_id_nfp_net_map[] = {
+static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+			    struct rte_pci_device *dev)
+{
+	nfpu_desc_t *nfpu_desc;
+	nspu_desc_t *nspu_desc;
+	int major, minor;
+
+	if (!dev)
+		return -ENODEV;
+
+	nfpu_desc = rte_malloc("nfp nfpu", sizeof(nfpu_desc_t), 0);
+	if (!nfpu_desc)
+		return -ENOMEM;
+
+	if (nfpu_open(dev, nfpu_desc, 0) < 0) {
+		RTE_LOG(ERR, PMD,
+			"nfpu_open failed\n");
+		goto nfpu_error;
+	}
+
+	nspu_desc = nfpu_desc->nspu;
+
+
+	/* Check NSP ABI version */
+	if (nfp_nsp_get_abi_version(nspu_desc, &major, &minor) < 0) {
+		RTE_LOG(INFO, PMD, "NFP NSP not present\n");
+		goto no_abi;
+	}
+	PMD_INIT_LOG(INFO, "nspu ABI version: %d.%d\n", major, minor);
+
+	if (minor < 20) {
+		RTE_LOG(INFO, PMD, "NFP NSP ABI version too old. Required 0.20 or higher\n");
+		goto no_abi;
+	}
+
+	/* No port is created yet */
+
+no_abi:
+	nfpu_close(nfpu_desc);
+nfpu_error:
+	rte_free(nfpu_desc);
+
+	return -ENODEV;
+}
+
+static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
 	{
 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
 			       PCI_DEVICE_ID_NFP6000_PF_NIC)
 	},
 	{
+		.vendor_id = 0,
+	},
+};
+
+static const struct rte_pci_id pci_id_nfp_vf_net_map[] = {
+	{
 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
 			       PCI_DEVICE_ID_NFP6000_VF_NIC)
 	},
@@ -2658,16 +2711,26 @@ static int eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
 	return rte_eth_dev_pci_generic_remove(pci_dev, NULL);
 }
 
-static struct rte_pci_driver rte_nfp_net_pmd = {
-	.id_table = pci_id_nfp_net_map,
+static struct rte_pci_driver rte_nfp_net_pf_pmd = {
+	.id_table = pci_id_nfp_pf_net_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+	.probe = nfp_pf_pci_probe,
+	.remove = eth_nfp_pci_remove,
+};
+
+static struct rte_pci_driver rte_nfp_net_vf_pmd = {
+	.id_table = pci_id_nfp_vf_net_map,
 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_nfp_pci_probe,
 	.remove = eth_nfp_pci_remove,
 };
 
-RTE_PMD_REGISTER_PCI(net_nfp, rte_nfp_net_pmd);
-RTE_PMD_REGISTER_PCI_TABLE(net_nfp, pci_id_nfp_net_map);
-RTE_PMD_REGISTER_KMOD_DEP(net_nfp, "* igb_uio | uio_pci_generic | vfio-pci");
+RTE_PMD_REGISTER_PCI(net_nfp_pf, rte_nfp_net_pf_pmd);
+RTE_PMD_REGISTER_PCI(net_nfp_vf, rte_nfp_net_vf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_nfp_pf, pci_id_nfp_pf_net_map);
+RTE_PMD_REGISTER_PCI_TABLE(net_nfp_vf, pci_id_nfp_vf_net_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_nfp_pf, "* igb_uio | uio_pci_generic | vfio");
+RTE_PMD_REGISTER_KMOD_DEP(net_nfp_vf, "* igb_uio | uio_pci_generic | vfio");
 
 /*
  * Local variables:
-- 
1.9.1

^ permalink raw reply	[relevance 10%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
  2017-08-23 12:21  0%   ` Ananyev, Konstantin
@ 2017-08-23 21:48  0%   ` Thomas Monjalon
  2017-08-29 12:50  0%   ` Ferruh Yigit
  2017-08-29 13:11  0%   ` Ferruh Yigit
  3 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-23 21:48 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: dev

07/08/2017 12:54, Shahaf Shuler:
> Introduce a new API to configure Rx offloads.
> 
> The new API will re-use existing DEV_RX_OFFLOAD_* flags
> to enable the different offloads. This will ease the process
> of adding a new Rx offloads, as no ABI breakage is involved.
> In addition, the offload configuration can be done per queue,
> instead of per port.
> 
> The Rx queue offload API can be used only with devices which advertize
> the RTE_ETH_DEV_RXQ_OFFLOAD capability.
> 
> The old Rx offloads API is kept for the meanwhile, in order to enable a
> smooth transition for PMDs and application to the new API.
> 
> Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
[...]
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -357,7 +357,14 @@ struct rte_eth_rxmode {
>  		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
>  		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
>  		enable_scatter   : 1, /**< Enable scatter packets rx handler */
> -		enable_lro       : 1; /**< Enable LRO */
> +		enable_lro       : 1, /**< Enable LRO */
> +		ignore		 : 1;
> +		/**
> +		 * When set the rxmode offloads should be ignored,
> +		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
> +		 * This bit is temporary till rxmode Rx offloads API will
> +		 * be deprecated.
> +		 */

Who is responsible to set the "ignore" flag?

Should it be documented in queue config functions?

> +/** Device supports the rte_eth_rxq_conf offloads API */
> +#define RTE_ETH_DEV_RXQ_OFFLOAD 0x0010

Otherwise, looks good

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by rte_eth_stats_get
  2017-08-23 21:27  0%         ` David Harton (dharton)
@ 2017-08-23 21:35  0%           ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-23 21:35 UTC (permalink / raw)
  To: David Harton (dharton); +Cc: dev

23/08/2017 23:27, David Harton (dharton):
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 23/08/2017 14:18, David Harton (dharton):
> > > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > > 23/08/2017 04:55, David Harton:
> > > > > rte_eth_stats_get() unconditonally would set rx_nombuf even if the
> > > > > device was setting the value.  A check has been added in
> > > > > rte_eth_stats_get() to leave the device value in-tact when non-zero.
> > > >
> > > > If we get this counter from stats->rx_nombuf, why keeping
> > > > dev->data->rx_mbuf_alloc_failed ?
> > > > We could rework other PMDs to not use this global variable.
> > > > It is inconsistent to use it for some PMDs but not all.
> > > > And it seems not used outside of PMDs.
> > >
> > > Are you also asking to remove dev->data->rx_mbuf_alloc_failed as well
> > since we will have an ABI breakage anyway?
> > 
> > Not asking, just giving my thought :)
> 
> I did some more digging.  For this count it looks like some devices:
> - have their own internal version
> - have a count shared with the pf
> - rely on this field to maintain the count
> - don't count this failure at all :(
> 
> With that said I'd like to keep with the requested changes.
> 
> Thoughts?

I don't see how it is a problem for removing dev->data->rx_mbuf_alloc_failed.
If this field is used, we just have to replace it by a PMD internal variable.
Isn't it?

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by rte_eth_stats_get
  2017-08-23 13:24  0%       ` Thomas Monjalon
@ 2017-08-23 21:27  0%         ` David Harton (dharton)
  2017-08-23 21:35  0%           ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: David Harton (dharton) @ 2017-08-23 21:27 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Wednesday, August 23, 2017 9:24 AM
> To: David Harton (dharton) <dharton@cisco.com>
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by
> rte_eth_stats_get
> 
> 23/08/2017 14:18, David Harton (dharton):
> >
> > > -----Original Message-----
> > > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > Sent: Wednesday, August 23, 2017 3:52 AM
> > > To: David Harton (dharton) <dharton@cisco.com>
> > > Cc: dev@dpdk.org
> > > Subject: Re: [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by
> > > rte_eth_stats_get
> > >
> > > 23/08/2017 04:55, David Harton:
> > > > rte_eth_stats_get() unconditonally would set rx_nombuf even if the
> > > > device was setting the value.  A check has been added in
> > > > rte_eth_stats_get() to leave the device value in-tact when non-zero.
> > >
> > > If we get this counter from stats->rx_nombuf, why keeping
> > > dev->data->rx_mbuf_alloc_failed ?
> > > We could rework other PMDs to not use this global variable.
> > > It is inconsistent to use it for some PMDs but not all.
> > > And it seems not used outside of PMDs.
> >
> > Are you also asking to remove dev->data->rx_mbuf_alloc_failed as well
> since we will have an ABI breakage anyway?
> 
> Not asking, just giving my thought :)

I did some more digging.  For this count it looks like some devices:
- have their own internal version
- have a count shared with the pf
- rely on this field to maintain the count
- don't count this failure at all :(

With that said I'd like to keep with the requested changes.

Thoughts?
Dave

> 
> > On an somewhat related note, since we are introducing an ABI breakage
> how do you feel about re-adding the return code for the vlan_offload_set
> vector?  Some devices conditionally provide the ability to modify some
> offload and the caller should know.  Since I've got your attention thought
> I'd ask here before posting the patch.
> 
> Seems reasonnable
> 
> > <soapbox>
> > In fact, I believe all the API function calls should provide a return
> code to help mitigate ABI breakages and also provide the ability to let
> the caller distinguish between - no device, not supported and some other
> error.  A control plane often needs to understand these distinctions to
> properly orchestrate the system and/or report real errors.  This is more
> than I'm willing to take on myself but believe it's a principle I'd like
> to discuss (can start separate thread if desired).
> > </soapbox>
> 
> Yes you're right

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by rte_eth_stats_get
  2017-08-23 12:18  4%     ` David Harton (dharton)
@ 2017-08-23 13:24  0%       ` Thomas Monjalon
  2017-08-23 21:27  0%         ` David Harton (dharton)
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2017-08-23 13:24 UTC (permalink / raw)
  To: David Harton (dharton); +Cc: dev

23/08/2017 14:18, David Harton (dharton):
> 
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > Sent: Wednesday, August 23, 2017 3:52 AM
> > To: David Harton (dharton) <dharton@cisco.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by
> > rte_eth_stats_get
> > 
> > 23/08/2017 04:55, David Harton:
> > > rte_eth_stats_get() unconditonally would set rx_nombuf even if the
> > > device was setting the value.  A check has been added in
> > > rte_eth_stats_get() to leave the device value in-tact when non-zero.
> > 
> > If we get this counter from stats->rx_nombuf, why keeping
> > dev->data->rx_mbuf_alloc_failed ?
> > We could rework other PMDs to not use this global variable.
> > It is inconsistent to use it for some PMDs but not all.
> > And it seems not used outside of PMDs.
> 
> Are you also asking to remove dev->data->rx_mbuf_alloc_failed as well since we will have an ABI breakage anyway?

Not asking, just giving my thought :)

> On an somewhat related note, since we are introducing an ABI breakage how do you feel about re-adding the return code for the vlan_offload_set vector?  Some devices conditionally provide the ability to modify some offload and the caller should know.  Since I've got your attention thought I'd ask here before posting the patch.

Seems reasonnable

> <soapbox>
> In fact, I believe all the API function calls should provide a return code to help mitigate ABI breakages and also provide the ability to let the caller distinguish between - no device, not supported and some other error.  A control plane often needs to understand these distinctions to properly orchestrate the system and/or report real errors.  This is more than I'm willing to take on myself but believe it's a principle I'd like to discuss (can start separate thread if desired).
> </soapbox>

Yes you're right

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-23 12:21  0%   ` Ananyev, Konstantin
@ 2017-08-23 13:06  0%     ` Shahaf Shuler
  0 siblings, 0 replies; 200+ results
From: Shahaf Shuler @ 2017-08-23 13:06 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev

Wednesday, August 23, 2017 3:21 PM, Ananyev, Konstantin:
> Hi,
> 
> > Introduce a new API to configure Rx offloads.
> >
> > The new API will re-use existing DEV_RX_OFFLOAD_* flags to enable the
> > different offloads. This will ease the process of adding a new Rx
> > offloads, as no ABI breakage is involved.
> > In addition, the offload configuration can be done per queue, instead
> > of per port.
> >
> > The Rx queue offload API can be used only with devices which advertize
> > the RTE_ETH_DEV_RXQ_OFFLOAD capability.
> 
> Not sure why do we need that?
> Why (till the deprication) user can't use both old rxmode and new offload
> flags?
> I.E. at rte_ethdev_rx_queue_setup() we always convert rxmode to new
> offload flags (as I can see you already have a function for it), then we call
> dev_ops->rx_queue_setup().
> That way both new and old ethdev API should work.
> Of course that mean that all PMDs have to support new way to setup rx
> offloads...
> But I suppose that have to be done anyway.
> Same for TX path.

The reason for this capability is to enable the different PMDs to *gradually move* to the new API.
Offloads management on the PMD is complex, it has to deal with the internal of the device on which they work. For example some devices probably
have offloads configuration they can do only per port.  Another example can be that some PMDs enable Tx offloads from the PMD specific parameters (like mlx5). 

This is why I believe that the task to move the PMD to the new API should be done by the PMD developers/maintainers.
This work provides the means (the copy functions and the capability bits) for both APIs to co-exists and to be used on top of PMDs which support either old or new API.

Once the majority of the PMD made the transition, we can remove and deprecate this cap (and the old API).

> Konstantin
> 
> >
> > The old Rx offloads API is kept for the meanwhile, in order to enable
> > a smooth transition for PMDs and application to the new API.
> >
> > Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
> > ---
> >  lib/librte_ether/rte_ethdev.h | 30 +++++++++++++++++++++++++++++-
> >  1 file changed, 29 insertions(+), 1 deletion(-)
> >
> > diff --git a/lib/librte_ether/rte_ethdev.h
> > b/lib/librte_ether/rte_ethdev.h index f7a44578c..ce33c61c4 100644
> > --- a/lib/librte_ether/rte_ethdev.h
> > +++ b/lib/librte_ether/rte_ethdev.h
> > @@ -357,7 +357,14 @@ struct rte_eth_rxmode {
> >  		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
> >  		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
> >  		enable_scatter   : 1, /**< Enable scatter packets rx handler */
> > -		enable_lro       : 1; /**< Enable LRO */
> > +		enable_lro       : 1, /**< Enable LRO */
> > +		ignore		 : 1;
> > +		/**
> > +		 * When set the rxmode offloads should be ignored,
> > +		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
> > +		 * This bit is temporary till rxmode Rx offloads API will
> > +		 * be deprecated.
> > +		 */
> >  };
> >
> >  /**
> > @@ -691,6 +698,12 @@ struct rte_eth_rxq_conf {
> >  	uint16_t rx_free_thresh; /**< Drives the freeing of RX descriptors.
> */
> >  	uint8_t rx_drop_en; /**< Drop packets if no descriptors are
> available. */
> >  	uint8_t rx_deferred_start; /**< Do not start queue with
> > rte_eth_dev_start(). */
> > +	uint64_t offloads;
> > +	/**
> > +	 * Enable Rx offloads using DEV_RX_OFFLOAD_* flags.
> > +	 * Supported only for devices which advertize the
> > +	 * RTE_ETH_DEV_RXQ_OFFLOAD capability.
> > +	 */
> >  };
> >
> >  #define ETH_TXQ_FLAGS_NOMULTSEGS 0x0001 /**< nb_segs=1 for all
> mbufs
> > */ @@ -907,6 +920,19 @@ struct rte_eth_conf {  #define
> > DEV_RX_OFFLOAD_QINQ_STRIP  0x00000020  #define
> > DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM 0x00000040
> >  #define DEV_RX_OFFLOAD_MACSEC_STRIP     0x00000080
> > +#define DEV_RX_OFFLOAD_HEADER_SPLIT	0x00000100
> > +#define DEV_RX_OFFLOAD_VLAN_FILTER	0x00000200
> > +#define DEV_RX_OFFLOAD_VLAN_EXTEND	0x00000400
> > +#define DEV_RX_OFFLOAD_JUMBO_FRAME	0x00000800
> > +#define DEV_RX_OFFLOAD_CRC_STRIP	0x00001000
> > +#define DEV_RX_OFFLOAD_SCATTER		0x00002000
> > +#define DEV_RX_OFFLOAD_LRO		0x00004000
> > +#define DEV_RX_OFFLOAD_CHECKSUM
> (DEV_RX_OFFLOAD_IPV4_CKSUM | \
> > +				 DEV_RX_OFFLOAD_UDP_CKSUM | \
> > +				 DEV_RX_OFFLOAD_TCP_CKSUM)
> > +#define DEV_RX_OFFLOAD_VLAN (DEV_RX_OFFLOAD_VLAN_STRIP | \
> > +			     DEV_RX_OFFLOAD_VLAN_FILTER | \
> > +			     DEV_RX_OFFLOAD_VLAN_EXTEND)
> >
> >  /**
> >   * TX offload capabilities of a device.
> > @@ -1723,6 +1749,8 @@ struct rte_eth_dev_data {  #define
> > RTE_ETH_DEV_BONDED_SLAVE 0x0004
> >  /** Device supports device removal interrupt */
> >  #define RTE_ETH_DEV_INTR_RMV     0x0008
> > +/** Device supports the rte_eth_rxq_conf offloads API */ #define
> > +RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
> >
> >  /**
> >   * @internal
> > --
> > 2.12.0

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
@ 2017-08-23 12:21  0%   ` Ananyev, Konstantin
  2017-08-23 13:06  0%     ` Shahaf Shuler
  2017-08-23 21:48  0%   ` Thomas Monjalon
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 200+ results
From: Ananyev, Konstantin @ 2017-08-23 12:21 UTC (permalink / raw)
  To: Shahaf Shuler, dev

Hi,

> Introduce a new API to configure Rx offloads.
> 
> The new API will re-use existing DEV_RX_OFFLOAD_* flags
> to enable the different offloads. This will ease the process
> of adding a new Rx offloads, as no ABI breakage is involved.
> In addition, the offload configuration can be done per queue,
> instead of per port.
> 
> The Rx queue offload API can be used only with devices which advertize
> the RTE_ETH_DEV_RXQ_OFFLOAD capability.

Not sure why do we need that?
Why (till the deprication) user can't use both old rxmode and new offload flags?
I.E. at rte_ethdev_rx_queue_setup() we always convert rxmode to new offload flags
(as I can see you already have a function for it), then we call dev_ops->rx_queue_setup().
That way both new and old ethdev API should work.
Of course that mean that all PMDs have to support new way to setup rx offloads...
But I suppose that have to be done anyway.
Same for TX path.
Konstantin

> 
> The old Rx offloads API is kept for the meanwhile, in order to enable a
> smooth transition for PMDs and application to the new API.
> 
> Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
> ---
>  lib/librte_ether/rte_ethdev.h | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index f7a44578c..ce33c61c4 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -357,7 +357,14 @@ struct rte_eth_rxmode {
>  		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
>  		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
>  		enable_scatter   : 1, /**< Enable scatter packets rx handler */
> -		enable_lro       : 1; /**< Enable LRO */
> +		enable_lro       : 1, /**< Enable LRO */
> +		ignore		 : 1;
> +		/**
> +		 * When set the rxmode offloads should be ignored,
> +		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
> +		 * This bit is temporary till rxmode Rx offloads API will
> +		 * be deprecated.
> +		 */
>  };
> 
>  /**
> @@ -691,6 +698,12 @@ struct rte_eth_rxq_conf {
>  	uint16_t rx_free_thresh; /**< Drives the freeing of RX descriptors. */
>  	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
>  	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
> +	uint64_t offloads;
> +	/**
> +	 * Enable Rx offloads using DEV_RX_OFFLOAD_* flags.
> +	 * Supported only for devices which advertize the
> +	 * RTE_ETH_DEV_RXQ_OFFLOAD capability.
> +	 */
>  };
> 
>  #define ETH_TXQ_FLAGS_NOMULTSEGS 0x0001 /**< nb_segs=1 for all mbufs */
> @@ -907,6 +920,19 @@ struct rte_eth_conf {
>  #define DEV_RX_OFFLOAD_QINQ_STRIP  0x00000020
>  #define DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM 0x00000040
>  #define DEV_RX_OFFLOAD_MACSEC_STRIP     0x00000080
> +#define DEV_RX_OFFLOAD_HEADER_SPLIT	0x00000100
> +#define DEV_RX_OFFLOAD_VLAN_FILTER	0x00000200
> +#define DEV_RX_OFFLOAD_VLAN_EXTEND	0x00000400
> +#define DEV_RX_OFFLOAD_JUMBO_FRAME	0x00000800
> +#define DEV_RX_OFFLOAD_CRC_STRIP	0x00001000
> +#define DEV_RX_OFFLOAD_SCATTER		0x00002000
> +#define DEV_RX_OFFLOAD_LRO		0x00004000
> +#define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
> +				 DEV_RX_OFFLOAD_UDP_CKSUM | \
> +				 DEV_RX_OFFLOAD_TCP_CKSUM)
> +#define DEV_RX_OFFLOAD_VLAN (DEV_RX_OFFLOAD_VLAN_STRIP | \
> +			     DEV_RX_OFFLOAD_VLAN_FILTER | \
> +			     DEV_RX_OFFLOAD_VLAN_EXTEND)
> 
>  /**
>   * TX offload capabilities of a device.
> @@ -1723,6 +1749,8 @@ struct rte_eth_dev_data {
>  #define RTE_ETH_DEV_BONDED_SLAVE 0x0004
>  /** Device supports device removal interrupt */
>  #define RTE_ETH_DEV_INTR_RMV     0x0008
> +/** Device supports the rte_eth_rxq_conf offloads API */
> +#define RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
> 
>  /**
>   * @internal
> --
> 2.12.0

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by rte_eth_stats_get
  @ 2017-08-23 12:18  4%     ` David Harton (dharton)
  2017-08-23 13:24  0%       ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: David Harton (dharton) @ 2017-08-23 12:18 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev


> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Wednesday, August 23, 2017 3:52 AM
> To: David Harton (dharton) <dharton@cisco.com>
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v2 1/2] ethdev: stop overriding rx_nombuf by
> rte_eth_stats_get
> 
> 23/08/2017 04:55, David Harton:
> > rte_eth_stats_get() unconditonally would set rx_nombuf even if the
> > device was setting the value.  A check has been added in
> > rte_eth_stats_get() to leave the device value in-tact when non-zero.
> 
> If we get this counter from stats->rx_nombuf, why keeping
> dev->data->rx_mbuf_alloc_failed ?
> We could rework other PMDs to not use this global variable.
> It is inconsistent to use it for some PMDs but not all.
> And it seems not used outside of PMDs.

Are you also asking to remove dev->data->rx_mbuf_alloc_failed as well since we will have an ABI breakage anyway?

On an somewhat related note, since we are introducing an ABI breakage how do you feel about re-adding the return code for the vlan_offload_set vector?  Some devices conditionally provide the ability to modify some offload and the caller should know.  Since I've got your attention thought I'd ask here before posting the patch.

<soapbox>
In fact, I believe all the API function calls should provide a return code to help mitigate ABI breakages and also provide the ability to let the caller distinguish between - no device, not supported and some other error.  A control plane often needs to understand these distinctions to properly orchestrate the system and/or report real errors.  This is more than I'm willing to take on myself but believe it's a principle I'd like to discuss (can start separate thread if desired).
</soapbox>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API
  2017-08-07 10:54  4% [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API Shahaf Shuler
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 3/4] ethdev: introduce Tx " Shahaf Shuler
@ 2017-08-23  6:39  0% ` Shahaf Shuler
  2017-08-25 10:31  0% ` Jerin Jacob
  3 siblings, 0 replies; 200+ results
From: Shahaf Shuler @ 2017-08-23  6:39 UTC (permalink / raw)
  To: Shahaf Shuler, dev, Thomas Monjalon

Hi,

I would like to get some inputs on the below. 
This is a big (and important) work which I want to include on 17.11. I need to understand the current approach is acceptable before I continue.


Monday, August 7, 2017 1:54 PM, Shahaf Shuler:
> Tx offloads configuration is per queue. Tx offloads are enabled by default,
> and can be disabled using ETH_TXQ_FLAGS_NO* flags.
> This behaviour is not consistent with the Rx side where the Rx offloads
> configuration is per port. Rx offloads are disabled by default and enabled
> according to bit field in rte_eth_rxmode structure.
> 
> Moreover, considering more Tx and Rx offloads will be added over time, the
> cost of managing them all inside the PMD will be tremendous, as the PMD
> will need to check the matching for the entire offload set for each mbuf it
> handles.
> In addition, on the current approach each Rx offload added breaks the ABI
> compatibility as it requires to add entries to existing bit-fields.
> 
> The RFC address above issues by defining a new offloads API.
> With the new API, Tx and Rx offloads configuration is per queue.
> The offloads are disabled by default. Each offload can be enabled or disabled
> using the existing DEV_TX_OFFLOADS_* or DEV_RX_OFFLOADS_* flags.
> Such API will enable to easily add or remove offloads, without breaking the
> ABI compatibility.
> 
> The new API does not have an equivalent for the below Tx flags:
> 
> * ETH_TXQ_FLAGS_NOREFCOUNT
> * ETH_TXQ_FLAGS_NOMULTMEMP
> 
> The reason is that those flags are not to manage offloads, rather some
> guarantee from application on the way it uses mbufs, therefore could not be
> present as part of DEV_TX_OFFLOADS_*.
> Such flags are useful only for benchmarks, and therefore provide a non-
> realistic
> performance for DPDK customers using simple benchmarks for evaluation.
> Leveraging the work being done in this series to clean up those flags.
> 
> In order to provide a smooth transition between the APIs the following
> actions were taken:
> *  The old offloads API is kept for the meanwhile.
> *  New capabilities were added for PMD to advertize it has moved to the
> new
>    offloads API.
> *  Helper function which copy from old to new API and vice versa were
> added to ethdev,
>    enabling the PMD to support only one of the APIs, and the application to
> move to
>    the new API regardless the underlying device and without extra branching.
> 



> Shahaf Shuler (4):
>   ethdev: rename Rx and Tx configuration structs
>   ethdev: introduce Rx queue offloads API
>   ethdev: introduce Tx queue offloads API
>   ethdev: add helpers to move to the new offloads API
> 
>  lib/librte_ether/rte_ethdev.c | 144
> ++++++++++++++++++++++++++++++++++++-
>  lib/librte_ether/rte_ethdev.h |  72 +++++++++++++++----
>  2 files changed, 202 insertions(+), 14 deletions(-)
> 
> --
> 2.12.0

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v2] vhost: added user callbacks for socket open/close
  2017-08-21  9:34  3% [dpdk-dev] [PATCH] vhost: added user callbacks for socket open/close Dariusz Stojaczyk
  2017-08-21 15:00  0% ` Jens Freimann
@ 2017-08-22 16:24  3% ` Dariusz Stojaczyk
  2017-08-25  9:22  0%   ` Jens Freimann
  2017-08-30 10:50  3%   ` [dpdk-dev] [PATCH v3] rte_vhost: " Dariusz Stojaczyk
  1 sibling, 2 replies; 200+ results
From: Dariusz Stojaczyk @ 2017-08-22 16:24 UTC (permalink / raw)
  To: dev; +Cc: Pawel Wodkowski, Dariusz Stojaczyk

When user receives destroy_device signal, he does not know *why* that
event happened. He does not differ between socket shutdown and virtio
processing pause. User could completely delete device during transition
from BIOS to kernel, causing freeze or possibly kernel panic. Instead
of changing new_device/destroy_device callbacks and breaking the ABI,
a set of new functions new_connection/destroy_connection has been added.

Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
---
v2: also updated vhost_lib.rst
 doc/guides/prog_guide/vhost_lib.rst | 15 +++++++++++++--
 lib/librte_vhost/rte_vhost.h        |  5 ++++-
 lib/librte_vhost/socket.c           | 23 +++++++++++++++++++----
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/vhost_lib.rst b/doc/guides/prog_guide/vhost_lib.rst
index 5979290..861a0e2 100644
--- a/doc/guides/prog_guide/vhost_lib.rst
+++ b/doc/guides/prog_guide/vhost_lib.rst
@@ -129,8 +129,7 @@ The following is an overview of some key Vhost API functions:
 
   * ``destroy_device(int vid)``
 
-    This callback is invoked when a virtio device shuts down (or when the
-    vhost connection is broken).
+    This callback is invoked when a virtio device is paused or shut down.
 
   * ``vring_state_changed(int vid, uint16_t queue_id, int enable)``
 
@@ -143,6 +142,18 @@ The following is an overview of some key Vhost API functions:
     ``VHOST_F_LOG_ALL`` will be set/cleared at the start/end of live
     migration, respectively.
 
+  * ``new_connection(int vid)``
+
+    This callback is invoked on new vhost-user socket connection. If DPDK
+    acts as the server the device should not be deleted before
+     ``destroy_connection`` callback is received.
+
+  * ``destroy_connection(int vid)``
+
+    This callback is invoked when vhost-user socket connection is closed.
+    It indicates that device with id ``vid`` is no longer in use and can be
+    safely deleted.
+
 * ``rte_vhost_driver_disable/enable_features(path, features))``
 
   This function disables/enables some features. For example, it can be used to
diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
index 8c974eb..8f86167 100644
--- a/lib/librte_vhost/rte_vhost.h
+++ b/lib/librte_vhost/rte_vhost.h
@@ -107,7 +107,10 @@ struct vhost_device_ops {
 	 */
 	int (*features_changed)(int vid, uint64_t features);
 
-	void *reserved[4]; /**< Reserved for future extension */
+	int (*new_connection)(int vid);		/**< Connect to socket. */
+	void (*destroy_connection)(int vid);	/**< Disconnect from socket */
+
+	void *reserved[2]; /**< Reserved for future extension */
 };
 
 /**
diff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c
index 41aa3f9..4ab4ff7 100644
--- a/lib/librte_vhost/socket.c
+++ b/lib/librte_vhost/socket.c
@@ -230,24 +230,36 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
 
 	RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
 
+	if (vsocket->notify_ops->new_connection) {
+		ret = vsocket->notify_ops->new_connection(vid);
+		if (ret < 0) {
+			RTE_LOG(ERR, VHOST_CONFIG,
+				"failed to add vhost user connection with fd %d\n",
+				fd);
+			goto err;
+		}
+	}
+
 	conn->connfd = fd;
 	conn->vsocket = vsocket;
 	conn->vid = vid;
 	ret = fdset_add(&vhost_user.fdset, fd, vhost_user_read_cb,
 			NULL, conn);
 	if (ret < 0) {
-		conn->connfd = -1;
-		free(conn);
-		close(fd);
 		RTE_LOG(ERR, VHOST_CONFIG,
 			"failed to add fd %d into vhost server fdset\n",
 			fd);
-		return;
+		goto err;
 	}
 
 	pthread_mutex_lock(&vsocket->conn_mutex);
 	TAILQ_INSERT_TAIL(&vsocket->conn_list, conn, next);
 	pthread_mutex_unlock(&vsocket->conn_mutex);
+	return;
+
+err:
+	free(conn);
+	close(fd);
 }
 
 /* call back when there is new vhost-user connection from client  */
@@ -277,6 +289,9 @@ vhost_user_read_cb(int connfd, void *dat, int *remove)
 		*remove = 1;
 		vhost_destroy_device(conn->vid);
 
+		if (vsocket->notify_ops->destroy_connection)
+			vsocket->notify_ops->destroy_connection(conn->vid);
+
 		pthread_mutex_lock(&vsocket->conn_mutex);
 		TAILQ_REMOVE(&vsocket->conn_list, conn, next);
 		pthread_mutex_unlock(&vsocket->conn_mutex);
-- 
2.7.4

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] vhost: added user callbacks for socket open/close
  2017-08-21  9:34  3% [dpdk-dev] [PATCH] vhost: added user callbacks for socket open/close Dariusz Stojaczyk
@ 2017-08-21 15:00  0% ` Jens Freimann
  2017-08-22 16:24  3% ` [dpdk-dev] [PATCH v2] " Dariusz Stojaczyk
  1 sibling, 0 replies; 200+ results
From: Jens Freimann @ 2017-08-21 15:00 UTC (permalink / raw)
  To: Dariusz Stojaczyk; +Cc: dev, Pawel Wodkowski, Maxime Coquelin (mcoqueli), yliu

Hi Dariusz,

On Mon, Aug 21, 2017 at 11:34:42AM +0200, Dariusz Stojaczyk wrote:
>When user receives destroy_device signal, he does not know *why* that
>event happened. He does not differ between socket shutdown and virtio
>processing pause. User could completely delete device during transition
>from BIOS to kernel, causing freeze or possibly kernel panic. Instead
>of changing new_device/destroy_device callbacks and breaking the ABI,
>a set of new functions new_connection/destroy_connection has been added.
>
>Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
>---
> lib/librte_vhost/rte_vhost.h |  5 ++++-
> lib/librte_vhost/socket.c    | 23 +++++++++++++++++++----
> 2 files changed, 23 insertions(+), 5 deletions(-)
>
>diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
>index 8c974eb..8f86167 100644
>--- a/lib/librte_vhost/rte_vhost.h
>+++ b/lib/librte_vhost/rte_vhost.h
>@@ -107,7 +107,10 @@ struct vhost_device_ops {
> 	 */
> 	int (*features_changed)(int vid, uint64_t features);
>
>-	void *reserved[4]; /**< Reserved for future extension */
>+	int (*new_connection)(int vid);		/**< Connect to socket. */
>+	void (*destroy_connection)(int vid);	/**< Disconnect from socket */

I'm a little uncertain but my gut feeling is that in this context a connection is
something between two sockets, not between devices. I would probably
add these callbacks to struct vhost_user_socket. This is also where we
keep the list of connections.

regards,
Jens 

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v2 15/15] docs: add notes on service cores API updates
  @ 2017-08-21 12:58  4%   ` Harry van Haaren
  0 siblings, 0 replies; 200+ results
From: Harry van Haaren @ 2017-08-21 12:58 UTC (permalink / raw)
  To: dev; +Cc: Harry van Haaren

Add a section on the service cores API changes to 17.11 release notes.

Suggested-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
---
 doc/guides/rel_notes/release_17_11.rst | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 6e6ba1c..8bf91bd 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -117,6 +117,19 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Service cores API updated for usability**
+
+  The service cores API has been changed, removing pointers from the API
+  where possible, instead using integer IDs to identify each service. This
+  simplifed application code, aids debugging, and provides better
+  encapsulation. A summary of the main changes made is as follows:
+
+  * Services identified by ID not by ``rte_service_spec`` pointer
+  * Reduced API surface by using ``set`` functions instead of enable/disable
+  * Reworked ``rte_service_register`` to provide the service ID to registrar
+  * Rework start and stop APIs into ``rte_service_runstate_set``
+  * Added API to set runstate of service implementation to indicate readyness
+
 
 ABI Changes
 -----------
-- 
2.7.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] vhost: added user callbacks for socket open/close
@ 2017-08-21  9:34  3% Dariusz Stojaczyk
  2017-08-21 15:00  0% ` Jens Freimann
  2017-08-22 16:24  3% ` [dpdk-dev] [PATCH v2] " Dariusz Stojaczyk
  0 siblings, 2 replies; 200+ results
From: Dariusz Stojaczyk @ 2017-08-21  9:34 UTC (permalink / raw)
  To: dev; +Cc: Pawel Wodkowski, Dariusz Stojaczyk

When user receives destroy_device signal, he does not know *why* that
event happened. He does not differ between socket shutdown and virtio
processing pause. User could completely delete device during transition
from BIOS to kernel, causing freeze or possibly kernel panic. Instead
of changing new_device/destroy_device callbacks and breaking the ABI,
a set of new functions new_connection/destroy_connection has been added.

Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
---
 lib/librte_vhost/rte_vhost.h |  5 ++++-
 lib/librte_vhost/socket.c    | 23 +++++++++++++++++++----
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
index 8c974eb..8f86167 100644
--- a/lib/librte_vhost/rte_vhost.h
+++ b/lib/librte_vhost/rte_vhost.h
@@ -107,7 +107,10 @@ struct vhost_device_ops {
 	 */
 	int (*features_changed)(int vid, uint64_t features);
 
-	void *reserved[4]; /**< Reserved for future extension */
+	int (*new_connection)(int vid);		/**< Connect to socket. */
+	void (*destroy_connection)(int vid);	/**< Disconnect from socket */
+
+	void *reserved[2]; /**< Reserved for future extension */
 };
 
 /**
diff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c
index 41aa3f9..4ab4ff7 100644
--- a/lib/librte_vhost/socket.c
+++ b/lib/librte_vhost/socket.c
@@ -230,24 +230,36 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
 
 	RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
 
+	if (vsocket->notify_ops->new_connection) {
+		ret = vsocket->notify_ops->new_connection(vid);
+		if (ret < 0) {
+			RTE_LOG(ERR, VHOST_CONFIG,
+				"failed to add vhost user connection with fd %d\n",
+				fd);
+			goto err;
+		}
+	}
+
 	conn->connfd = fd;
 	conn->vsocket = vsocket;
 	conn->vid = vid;
 	ret = fdset_add(&vhost_user.fdset, fd, vhost_user_read_cb,
 			NULL, conn);
 	if (ret < 0) {
-		conn->connfd = -1;
-		free(conn);
-		close(fd);
 		RTE_LOG(ERR, VHOST_CONFIG,
 			"failed to add fd %d into vhost server fdset\n",
 			fd);
-		return;
+		goto err;
 	}
 
 	pthread_mutex_lock(&vsocket->conn_mutex);
 	TAILQ_INSERT_TAIL(&vsocket->conn_list, conn, next);
 	pthread_mutex_unlock(&vsocket->conn_mutex);
+	return;
+
+err:
+	free(conn);
+	close(fd);
 }
 
 /* call back when there is new vhost-user connection from client  */
@@ -277,6 +289,9 @@ vhost_user_read_cb(int connfd, void *dat, int *remove)
 		*remove = 1;
 		vhost_destroy_device(conn->vid);
 
+		if (vsocket->notify_ops->destroy_connection)
+			vsocket->notify_ops->destroy_connection(conn->vid);
+
 		pthread_mutex_lock(&vsocket->conn_mutex);
 		TAILQ_REMOVE(&vsocket->conn_list, conn, next);
 		pthread_mutex_unlock(&vsocket->conn_mutex);
-- 
2.7.4

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] net/i40e: new API to add VF MAC address from PF
  2017-08-17 13:05  0%   ` Ferruh Yigit
@ 2017-08-17 13:36  0%     ` Lu, Wenzhuo
  0 siblings, 0 replies; 200+ results
From: Lu, Wenzhuo @ 2017-08-17 13:36 UTC (permalink / raw)
  To: Yigit, Ferruh, dev
  Cc: Wu, Jingjing, Xing, Beilei, Stephen Hurd, Ajit Khaparde

Hi Ferruh,

> -----Original Message-----
> From: Yigit, Ferruh
> Sent: Thursday, August 17, 2017 9:05 AM
> To: Lu, Wenzhuo <wenzhuo.lu@intel.com>; dev@dpdk.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei <beilei.xing@intel.com>;
> Stephen Hurd <stephen.hurd@broadcom.com>; Ajit Khaparde
> <ajit.khaparde@broadcom.com>
> Subject: Re: [dpdk-dev] [PATCH v2] net/i40e: new API to add VF MAC address
> from PF
> 
> On 7/25/2017 3:09 PM, Wenzhuo Lu wrote:
> > Currently, on i40e the parameter 'pool' of API
> > rte_eth_dev_mac_addr_add means the VMDq pool, not VF.
> 
> The argument "pool" in rte_eth_dev_mac_addr_add() IS VMDq pool.
> This is not just for i40e, this is by API definition.
> 
> > So, it's wrong to use it to set the VF MAC address.
> 
> Agreed, it seems testpmd function cmd_vf_mac_addr_parsed() implemented
> wrong.
> 
> > As this API is also used by the VMDq example, ideally we need a
> > parameter to tell the pool is VMDq or VF.
> > But it's hard to change it because of the ABI change concern.
> 
> I think we shouldn't NOT update rte_eth_dev_mac_addr_add() API, it is not
> wrong.
Agree :)

> 
> But should fix testpmd ""mac_addr add port <port_id> vf <vf_id>
> <mac_addr>" command.
> 
> Can you please update this patch as two patches:
> 
> 1- i40e rte_pmd_i40e_add_vf_mac_addr() API
> 
> 2- Fix testpmd function, instead of inserting new i40e API replace it with
> wrong rte_eth_dev_mac_addr_add() call.
> And I guess bnxt driver also has API to add VF MAC, can you add that one too?
Thanks for the suggestion. Will send a new version.

> 
> > Now the solution is to provide a new API, users can call it to add VF
> > MAC address from PF on i40e.
> >
> > Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
> 
> <...>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] net/i40e: new API to add VF MAC address from PF
  2017-07-25 14:09  3% ` [dpdk-dev] [PATCH v2] " Wenzhuo Lu
@ 2017-08-17 13:05  0%   ` Ferruh Yigit
  2017-08-17 13:36  0%     ` Lu, Wenzhuo
  0 siblings, 1 reply; 200+ results
From: Ferruh Yigit @ 2017-08-17 13:05 UTC (permalink / raw)
  To: Wenzhuo Lu, dev; +Cc: jingjing.wu, beilei.xing, Stephen Hurd, Ajit Khaparde

On 7/25/2017 3:09 PM, Wenzhuo Lu wrote:
> Currently, on i40e the parameter 'pool' of API
> rte_eth_dev_mac_addr_add means the VMDq pool, not VF.

The argument "pool" in rte_eth_dev_mac_addr_add() IS VMDq pool.
This is not just for i40e, this is by API definition.

> So, it's wrong to use it to set the VF MAC address.

Agreed, it seems testpmd function cmd_vf_mac_addr_parsed() implemented
wrong.

> As this API is also used by the VMDq example, ideally
> we need a parameter to tell the pool is VMDq or VF.
> But it's hard to change it because of the ABI change
> concern.

I think we shouldn't NOT update rte_eth_dev_mac_addr_add() API, it is
not wrong.

But should fix testpmd ""mac_addr add port <port_id> vf <vf_id>
<mac_addr>" command.

Can you please update this patch as two patches:

1- i40e rte_pmd_i40e_add_vf_mac_addr() API

2- Fix testpmd function, instead of inserting new i40e API replace it
with wrong rte_eth_dev_mac_addr_add() call.
And I guess bnxt driver also has API to add VF MAC, can you add that one
too?

> Now the solution is to provide a new API, users can
> call it to add VF MAC address from PF on i40e.
> 
> Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>

<...>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
  2017-08-16 12:07  0%     ` Van Haaren, Harry
@ 2017-08-16 13:27  0%       ` Neil Horman
  0 siblings, 0 replies; 200+ results
From: Neil Horman @ 2017-08-16 13:27 UTC (permalink / raw)
  To: Van Haaren, Harry; +Cc: dev

On Wed, Aug 16, 2017 at 12:07:11PM +0000, Van Haaren, Harry wrote:
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Van Haaren, Harry
> > Sent: Wednesday, August 16, 2017 12:32 PM
> > To: Neil Horman <nhorman@tuxdriver.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
> > 
> > > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > > Sent: Wednesday, August 16, 2017 12:16 PM
> > > To: Van Haaren, Harry <harry.van.haaren@intel.com>
> > > Cc: dev@dpdk.org
> > > Subject: Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
> > >
> > > On Tue, Aug 15, 2017 at 01:32:32PM +0100, Harry van Haaren wrote:
> > > > This patchset reworks the service apis to be more user
> > > > friendly. In particular, the various rte_service_* functions
> > > > now take an integer id parameter instead of a service pointer.
> > > > This both reduces the API surface (no service_get_from_id()),
> > > > and allows easier debugging (gdb function calls with integer args),
> > > > and various other benefits (better encapsulation, less pointers :)
> > > >
> > > > Finally, some APIs are changed or renamed for consistency and
> > > > clarity of what they do. See commit messages for details.
> > > > Note that the service library is merged as EXPERIMENTAL in
> > > > the 17.08 release, allowing API improvements for 17.11 release.
> > > >
> > > > I hope to merge this patchset early in the 17.11 timeframe,
> > > > so please review ASAP to allow time for other DPDK components
> > > > to utilize services in this release :)
> > > >
> > > > Feedback and input welcome, -Harry
> > > >
> > > You need to add a deprecation note in the rel notes area so that people are
> > > aware of the upcomming ABI changes
> > 
> > Service cores was merged into 17.08 with the EXPERIMENTAL tag, which indicates that the
> > API and ABI are not stable. The version map file has the service cores functions added in
> > the Experimental staging area, instead of in the 17.08 stable ABI[1]. To make this very
> > visible to the users, the documentation has large "Warning: Experimental, this API may
> > change without prior notice" marks[2], and the MAINTAINERS file[3] has the Experimental
> > tag.
> > 
> > As far as I am aware, those are all the requirements to be able to remove / change /
> > update / fix APIs. It was discussed on #IRC that it would be better to merge service-cores
> > as experimental to allow faster iteration, and to get improvements out the door, and I'm
> > still of that opinion.
> > 
> > Given the above, I don't see any issue with merging service-core changes into the 17.11
> > release.
> > 
> > [1] http://dpdk.org/browse/dpdk/tree/lib/librte_eal/linuxapp/eal/rte_eal_version.map#n212
> > [2] http://dpdk.org/doc/api/rte__service_8h.html#aea7fce2a101bf2c00194dffb30bfc4ea
> > [3] http://dpdk.org/browse/dpdk/tree/MAINTAINERS#n138
> 
> Self-reply;
> 
> On re-reading, perhaps I understood you wrong; did you mean that I need to add a section to the Release notes that the service core APIs have been updated in 17.11 itself?
> 
> That's a very valid point - and I'll fix that in v2, (some other typo fixes to fix too).
> 
I hadn't noted the experimental tag, so you likely don't need a deprecation
warning, but yes, a release note to indicate the change to the API in 17.11
would be good.

Best
NEil

> -Harry
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
  2017-08-16 11:31  4%   ` Van Haaren, Harry
@ 2017-08-16 12:07  0%     ` Van Haaren, Harry
  2017-08-16 13:27  0%       ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2017-08-16 12:07 UTC (permalink / raw)
  To: Van Haaren, Harry, Neil Horman; +Cc: dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Van Haaren, Harry
> Sent: Wednesday, August 16, 2017 12:32 PM
> To: Neil Horman <nhorman@tuxdriver.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
> 
> > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > Sent: Wednesday, August 16, 2017 12:16 PM
> > To: Van Haaren, Harry <harry.van.haaren@intel.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
> >
> > On Tue, Aug 15, 2017 at 01:32:32PM +0100, Harry van Haaren wrote:
> > > This patchset reworks the service apis to be more user
> > > friendly. In particular, the various rte_service_* functions
> > > now take an integer id parameter instead of a service pointer.
> > > This both reduces the API surface (no service_get_from_id()),
> > > and allows easier debugging (gdb function calls with integer args),
> > > and various other benefits (better encapsulation, less pointers :)
> > >
> > > Finally, some APIs are changed or renamed for consistency and
> > > clarity of what they do. See commit messages for details.
> > > Note that the service library is merged as EXPERIMENTAL in
> > > the 17.08 release, allowing API improvements for 17.11 release.
> > >
> > > I hope to merge this patchset early in the 17.11 timeframe,
> > > so please review ASAP to allow time for other DPDK components
> > > to utilize services in this release :)
> > >
> > > Feedback and input welcome, -Harry
> > >
> > You need to add a deprecation note in the rel notes area so that people are
> > aware of the upcomming ABI changes
> 
> Service cores was merged into 17.08 with the EXPERIMENTAL tag, which indicates that the
> API and ABI are not stable. The version map file has the service cores functions added in
> the Experimental staging area, instead of in the 17.08 stable ABI[1]. To make this very
> visible to the users, the documentation has large "Warning: Experimental, this API may
> change without prior notice" marks[2], and the MAINTAINERS file[3] has the Experimental
> tag.
> 
> As far as I am aware, those are all the requirements to be able to remove / change /
> update / fix APIs. It was discussed on #IRC that it would be better to merge service-cores
> as experimental to allow faster iteration, and to get improvements out the door, and I'm
> still of that opinion.
> 
> Given the above, I don't see any issue with merging service-core changes into the 17.11
> release.
> 
> [1] http://dpdk.org/browse/dpdk/tree/lib/librte_eal/linuxapp/eal/rte_eal_version.map#n212
> [2] http://dpdk.org/doc/api/rte__service_8h.html#aea7fce2a101bf2c00194dffb30bfc4ea
> [3] http://dpdk.org/browse/dpdk/tree/MAINTAINERS#n138

Self-reply;

On re-reading, perhaps I understood you wrong; did you mean that I need to add a section to the Release notes that the service core APIs have been updated in 17.11 itself?

That's a very valid point - and I'll fix that in v2, (some other typo fixes to fix too).

-Harry

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
  2017-08-16 11:16  3% ` Neil Horman
@ 2017-08-16 11:31  4%   ` Van Haaren, Harry
  2017-08-16 12:07  0%     ` Van Haaren, Harry
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2017-08-16 11:31 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev

> From: Neil Horman [mailto:nhorman@tuxdriver.com]
> Sent: Wednesday, August 16, 2017 12:16 PM
> To: Van Haaren, Harry <harry.van.haaren@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
> 
> On Tue, Aug 15, 2017 at 01:32:32PM +0100, Harry van Haaren wrote:
> > This patchset reworks the service apis to be more user
> > friendly. In particular, the various rte_service_* functions
> > now take an integer id parameter instead of a service pointer.
> > This both reduces the API surface (no service_get_from_id()),
> > and allows easier debugging (gdb function calls with integer args),
> > and various other benefits (better encapsulation, less pointers :)
> >
> > Finally, some APIs are changed or renamed for consistency and
> > clarity of what they do. See commit messages for details.
> > Note that the service library is merged as EXPERIMENTAL in
> > the 17.08 release, allowing API improvements for 17.11 release.
> >
> > I hope to merge this patchset early in the 17.11 timeframe,
> > so please review ASAP to allow time for other DPDK components
> > to utilize services in this release :)
> >
> > Feedback and input welcome, -Harry
> >
> You need to add a deprecation note in the rel notes area so that people are
> aware of the upcomming ABI changes

Service cores was merged into 17.08 with the EXPERIMENTAL tag, which indicates that the API and ABI are not stable. The version map file has the service cores functions added in the Experimental staging area, instead of in the 17.08 stable ABI[1]. To make this very visible to the users, the documentation has large "Warning: Experimental, this API may change without prior notice" marks[2], and the MAINTAINERS file[3] has the Experimental tag.

As far as I am aware, those are all the requirements to be able to remove / change / update / fix APIs. It was discussed on #IRC that it would be better to merge service-cores as experimental to allow faster iteration, and to get improvements out the door, and I'm still of that opinion.

Given the above, I don't see any issue with merging service-core changes into the 17.11 release.

[1] http://dpdk.org/browse/dpdk/tree/lib/librte_eal/linuxapp/eal/rte_eal_version.map#n212
[2] http://dpdk.org/doc/api/rte__service_8h.html#aea7fce2a101bf2c00194dffb30bfc4ea
[3] http://dpdk.org/browse/dpdk/tree/MAINTAINERS#n138

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 0/8] service: rework for usability
  @ 2017-08-16 11:16  3% ` Neil Horman
  2017-08-16 11:31  4%   ` Van Haaren, Harry
    1 sibling, 1 reply; 200+ results
From: Neil Horman @ 2017-08-16 11:16 UTC (permalink / raw)
  To: Harry van Haaren; +Cc: dev

On Tue, Aug 15, 2017 at 01:32:32PM +0100, Harry van Haaren wrote:
> This patchset reworks the service apis to be more user
> friendly. In particular, the various rte_service_* functions
> now take an integer id parameter instead of a service pointer.
> This both reduces the API surface (no service_get_from_id()),
> and allows easier debugging (gdb function calls with integer args),
> and various other benefits (better encapsulation, less pointers :)
> 
> Finally, some APIs are changed or renamed for consistency and
> clarity of what they do. See commit messages for details.
> Note that the service library is merged as EXPERIMENTAL in
> the 17.08 release, allowing API improvements for 17.11 release.
> 
> I hope to merge this patchset early in the 17.11 timeframe,
> so please review ASAP to allow time for other DPDK components
> to utilize services in this release :)
> 
> Feedback and input welcome, -Harry
> 
You need to add a deprecation note in the rel notes area so that people are
aware of the upcomming ABI changes
Neil

> ---
> 
> There is one checkpatch warning: "macro with flow control", however
> this same type of macro is used extensively in Ethdev and others,
> I presume it is a false-positive.
> 
> Harry van Haaren (8):
>   service: rework probe and get name to use ids
>   service: rework lcore to service map functions
>   service: rework register to return service id
>   service: rework service start stop to runstate
>   service: rework service stats functions
>   service: rework unregister api to use integers
>   service: rework get by name function to use id
>   service: clarify documentation for register
> 
>  drivers/event/sw/sw_evdev.c                        |   7 +-
>  drivers/event/sw/sw_evdev.h                        |   1 +
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  11 +-
>  lib/librte_eal/common/include/rte_service.h        | 144 +++++++-----------
>  .../common/include/rte_service_component.h         |  13 +-
>  lib/librte_eal/common/rte_service.c                | 167 +++++++++------------
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  11 +-
>  test/test/test_service_cores.c                     | 123 +++++++--------
>  8 files changed, 215 insertions(+), 262 deletions(-)
> 
> -- 
> 2.7.4
> 
> 

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v3] cryptodev: allocate driver structure statically
  @ 2017-08-16  2:41  3% ` Pablo de Lara
  0 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-08-16  2:41 UTC (permalink / raw)
  To: declan.doherty, fiona.trahe, deepak.k.jain, john.griffin,
	jerin.jacob, akhil.goyal, hemant.agrawal
  Cc: dev, Pablo de Lara

When register a crypto driver, a cryptodev driver
structure was being allocated, using malloc.
Since this call may fail, it is safer to allocate
this memory statically in each PMD, so driver registration
will never fail.

Coverity issue: 158645

Fixes: 7a364faef185 ("cryptodev: remove crypto device type enumeration")

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---

Changes in v3:

- Added documentation (removed deprecation notice and added API Change)
- Modified title to something more explicit

Changes in v2:

- Allocate statically the cryptodev driver structure,
  instead of using malloc, that can potentially fail.

 doc/guides/rel_notes/deprecation.rst        |  6 ------
 doc/guides/rel_notes/release_17_11.rst      |  5 +++++
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c    |  5 ++++-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c  |  6 +++++-
 drivers/crypto/armv8/rte_armv8_pmd.c        |  9 ++++++---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  5 ++++-
 drivers/crypto/kasumi/rte_kasumi_pmd.c      |  5 ++++-
 drivers/crypto/null/null_crypto_pmd.c       |  5 ++++-
 drivers/crypto/openssl/rte_openssl_pmd.c    |  5 ++++-
 drivers/crypto/qat/rte_qat_cryptodev.c      |  7 +++++--
 drivers/crypto/scheduler/scheduler_pmd.c    |  5 ++++-
 drivers/crypto/snow3g/rte_snow3g_pmd.c      |  5 ++++-
 drivers/crypto/zuc/rte_zuc_pmd.c            |  5 ++++-
 lib/librte_cryptodev/rte_cryptodev.c        | 18 +++++------------
 lib/librte_cryptodev/rte_cryptodev.h        | 20 -------------------
 lib/librte_cryptodev/rte_cryptodev_pmd.h    | 30 +++++++++++++++++++++++++++++
 16 files changed, 88 insertions(+), 53 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 3362f33..8be626e 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -106,12 +106,6 @@ Deprecation Notices
 
   - ``rte_cryptodev_vdev_pmd_init``
 
-* cryptodev: the following function will have an extra parameter, passing a
-  statically allocated crypto driver structure, instead of calling malloc,
-  in 17.11:
-
-  - ``rte_cryptodev_allocate_driver``
-
 * librte_meter: The API will change to accommodate configuration profiles.
   Most of the API functions will have an additional opaque parameter.
 
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..cdb99f4 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -110,6 +110,11 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Modified the rte_cryptodev_allocate_driver function in the cryptodev library.**
+
+  The function ``rte_cryptodev_allocate_driver()`` has been modified.
+  An extra parameter ``struct cryptodev_driver *crypto_drv`` has been added.
+
 
 ABI Changes
 -----------
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index d9c91d0..b59f399 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -630,10 +630,13 @@ static struct rte_vdev_driver aesni_gcm_pmd_drv = {
 	.remove = aesni_gcm_remove
 };
 
+static struct cryptodev_driver aesni_gcm_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_AESNI_GCM_PMD, aesni_gcm_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_AESNI_GCM_PMD, cryptodev_aesni_gcm_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_AESNI_GCM_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(aesni_gcm_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(aesni_gcm_crypto_drv, aesni_gcm_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 16e1451..5846bc9 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -823,10 +823,14 @@ static struct rte_vdev_driver cryptodev_aesni_mb_pmd_drv = {
 	.remove = cryptodev_aesni_mb_remove
 };
 
+static struct cryptodev_driver aesni_mb_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_AESNI_MB_PMD, cryptodev_aesni_mb_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_AESNI_MB_PMD, cryptodev_aesni_mb_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_AESNI_MB_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_aesni_mb_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(aesni_mb_crypto_drv,
+		cryptodev_aesni_mb_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index a5c39c9..b0d68d1 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -882,15 +882,18 @@ cryptodev_armv8_crypto_uninit(struct rte_vdev_device *vdev)
 	return 0;
 }
 
-static struct rte_vdev_driver armv8_crypto_drv = {
+static struct rte_vdev_driver armv8_crypto_pmd_drv = {
 	.probe = cryptodev_armv8_crypto_init,
 	.remove = cryptodev_armv8_crypto_uninit
 };
 
-RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_ARMV8_PMD, armv8_crypto_drv);
+static struct cryptodev_driver armv8_crypto_drv;
+
+RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_ARMV8_PMD, armv8_crypto_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_ARMV8_PMD, cryptodev_armv8_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_ARMV8_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(armv8_crypto_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(armv8_crypto_drv, armv8_crypto_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index e0f6cfc..dae296f 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -2008,5 +2008,8 @@ static struct rte_dpaa2_driver rte_dpaa2_sec_driver = {
 	.remove = cryptodev_dpaa2_sec_remove,
 };
 
+static struct cryptodev_driver dpaa2_sec_crypto_drv;
+
 RTE_PMD_REGISTER_DPAA2(CRYPTODEV_NAME_DPAA2_SEC_PMD, rte_dpaa2_sec_driver);
-RTE_PMD_REGISTER_CRYPTO_DRIVER(rte_dpaa2_sec_driver, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(dpaa2_sec_crypto_drv, rte_dpaa2_sec_driver,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index 38cd8a9..84cce34 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -661,10 +661,13 @@ static struct rte_vdev_driver cryptodev_kasumi_pmd_drv = {
 	.remove = cryptodev_kasumi_remove
 };
 
+static struct cryptodev_driver kasumi_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_KASUMI_PMD, cryptodev_kasumi_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_KASUMI_PMD, cryptodev_kasumi_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_KASUMI_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_kasumi_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(kasumi_crypto_drv, cryptodev_kasumi_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index 2c82725..d5d2bb3 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -286,10 +286,13 @@ static struct rte_vdev_driver cryptodev_null_pmd_drv = {
 	.remove = cryptodev_null_remove_dev,
 };
 
+static struct cryptodev_driver null_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_NULL_PMD, cryptodev_null_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_NULL_PMD, cryptodev_null_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_NULL_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_null_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(null_crypto_drv, cryptodev_null_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 0bd5f98..5b863c8 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -1502,10 +1502,13 @@ static struct rte_vdev_driver cryptodev_openssl_pmd_drv = {
 	.remove = cryptodev_openssl_remove
 };
 
+static struct cryptodev_driver openssl_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_OPENSSL_PMD,
 	cryptodev_openssl_pmd_drv);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_OPENSSL_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_openssl_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(openssl_crypto_drv, cryptodev_openssl_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/qat/rte_qat_cryptodev.c b/drivers/crypto/qat/rte_qat_cryptodev.c
index 7d56fca..3d9f3c8 100644
--- a/drivers/crypto/qat/rte_qat_cryptodev.c
+++ b/drivers/crypto/qat/rte_qat_cryptodev.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -169,6 +169,9 @@ static struct rte_pci_driver rte_qat_pmd = {
 	.remove = crypto_qat_pci_remove
 };
 
+static struct cryptodev_driver qat_crypto_drv;
+
 RTE_PMD_REGISTER_PCI(CRYPTODEV_NAME_QAT_SYM_PMD, rte_qat_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(CRYPTODEV_NAME_QAT_SYM_PMD, pci_id_qat_map);
-RTE_PMD_REGISTER_CRYPTO_DRIVER(rte_qat_pmd, cryptodev_qat_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(qat_crypto_drv, rte_qat_pmd,
+		cryptodev_qat_driver_id);
diff --git a/drivers/crypto/scheduler/scheduler_pmd.c b/drivers/crypto/scheduler/scheduler_pmd.c
index 400fc4f..3170f7f 100644
--- a/drivers/crypto/scheduler/scheduler_pmd.c
+++ b/drivers/crypto/scheduler/scheduler_pmd.c
@@ -505,6 +505,8 @@ static struct rte_vdev_driver cryptodev_scheduler_pmd_drv = {
 	.remove = cryptodev_scheduler_remove
 };
 
+static struct cryptodev_driver scheduler_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_SCHEDULER_PMD,
 	cryptodev_scheduler_pmd_drv);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SCHEDULER_PMD,
@@ -512,5 +514,6 @@ RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SCHEDULER_PMD,
 	"max_nb_sessions=<int> "
 	"socket_id=<int> "
 	"slave=<name>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_scheduler_pmd_drv,
+RTE_PMD_REGISTER_CRYPTO_DRIVER(scheduler_crypto_drv,
+		cryptodev_scheduler_pmd_drv,
 		cryptodev_driver_id);
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index dad4506..b2f6222 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -661,10 +661,13 @@ static struct rte_vdev_driver cryptodev_snow3g_pmd_drv = {
 	.remove = cryptodev_snow3g_remove
 };
 
+static struct cryptodev_driver snow3g_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_SNOW3G_PMD, cryptodev_snow3g_pmd_drv);
 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_SNOW3G_PMD, cryptodev_snow3g_pmd);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SNOW3G_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_snow3g_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(snow3g_crypto_drv, cryptodev_snow3g_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index b301711..70966d4 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -565,9 +565,12 @@ static struct rte_vdev_driver cryptodev_zuc_pmd_drv = {
 	.remove = cryptodev_zuc_remove
 };
 
+static struct cryptodev_driver zuc_crypto_drv;
+
 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_ZUC_PMD, cryptodev_zuc_pmd_drv);
 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_ZUC_PMD,
 	"max_nb_queue_pairs=<int> "
 	"max_nb_sessions=<int> "
 	"socket_id=<int>");
-RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_zuc_pmd_drv, cryptodev_driver_id);
+RTE_PMD_REGISTER_CRYPTO_DRIVER(zuc_crypto_drv, cryptodev_zuc_pmd_drv,
+		cryptodev_driver_id);
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 327d7e8..a239395 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1362,12 +1362,6 @@ TAILQ_HEAD(cryptodev_driver_list, cryptodev_driver);
 static struct cryptodev_driver_list cryptodev_driver_list =
 	TAILQ_HEAD_INITIALIZER(cryptodev_driver_list);
 
-struct cryptodev_driver {
-	TAILQ_ENTRY(cryptodev_driver) next; /**< Next in list. */
-	const struct rte_driver *driver;
-	uint8_t id;
-};
-
 int
 rte_cryptodev_driver_id_get(const char *name)
 {
@@ -1399,15 +1393,13 @@ rte_cryptodev_driver_name_get(uint8_t driver_id)
 }
 
 uint8_t
-rte_cryptodev_allocate_driver(const struct rte_driver *drv)
+rte_cryptodev_allocate_driver(struct cryptodev_driver *crypto_drv,
+		const struct rte_driver *drv)
 {
-	struct cryptodev_driver *driver;
-
-	driver = malloc(sizeof(*driver));
-	driver->driver = drv;
-	driver->id = nb_drivers;
+	crypto_drv->driver = drv;
+	crypto_drv->id = nb_drivers;
 
-	TAILQ_INSERT_TAIL(&cryptodev_driver_list, driver, next);
+	TAILQ_INSERT_TAIL(&cryptodev_driver_list, crypto_drv, next);
 
 	return nb_drivers++;
 }
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 7ec9c4b..5225a5b 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -1025,26 +1025,6 @@ int rte_cryptodev_driver_id_get(const char *name);
  */
 const char *rte_cryptodev_driver_name_get(uint8_t driver_id);
 
-/**
- * @internal
- * Allocate Cryptodev driver.
- *
- * @param driver
- *   Pointer to rte_driver.
- * @return
- *  The driver type identifier
- */
-uint8_t rte_cryptodev_allocate_driver(const struct rte_driver *driver);
-
-
-#define RTE_PMD_REGISTER_CRYPTO_DRIVER(drv, driver_id)\
-RTE_INIT(init_ ##driver_id);\
-static void init_ ##driver_id(void)\
-{\
-	driver_id = rte_cryptodev_allocate_driver(&(drv).driver);\
-}
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
index c983eb2..ba074e1 100644
--- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
+++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
@@ -65,6 +65,13 @@ struct rte_cryptodev_global {
 	uint8_t max_devs;		/**< Max number of devices */
 };
 
+/* Cryptodev driver, containing the driver ID */
+struct cryptodev_driver {
+	TAILQ_ENTRY(cryptodev_driver) next; /**< Next in list. */
+	const struct rte_driver *driver;
+	uint8_t id;
+};
+
 /** pointer to global crypto devices data structure. */
 extern struct rte_cryptodev_global *rte_cryptodev_globals;
 
@@ -405,6 +412,29 @@ void rte_cryptodev_pmd_callback_process(struct rte_cryptodev *dev,
 int
 rte_cryptodev_pmd_create_dev_name(char *name, const char *dev_name_prefix);
 
+/**
+ * @internal
+ * Allocate Cryptodev driver.
+ *
+ * @param crypto_drv
+ *   Pointer to cryptodev_driver.
+ * @param drv
+ *   Pointer to rte_driver.
+ *
+ * @return
+ *  The driver type identifier
+ */
+uint8_t rte_cryptodev_allocate_driver(struct cryptodev_driver *crypto_drv,
+		const struct rte_driver *drv);
+
+
+#define RTE_PMD_REGISTER_CRYPTO_DRIVER(crypto_drv, drv, driver_id)\
+RTE_INIT(init_ ##driver_id);\
+static void init_ ##driver_id(void)\
+{\
+	driver_id = rte_cryptodev_allocate_driver(&crypto_drv, &(drv).driver);\
+}
+
 static inline void *
 get_session_private_data(const struct rte_cryptodev_sym_session *sess,
 		uint8_t driver_id) {
-- 
2.9.4

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v4 3/7] doc: remove mempool api change notice
  @ 2017-08-15  6:07  4%   ` Santosh Shukla
  0 siblings, 0 replies; 200+ results
From: Santosh Shukla @ 2017-08-15  6:07 UTC (permalink / raw)
  To: olivier.matz, dev; +Cc: thomas, jerin.jacob, hemant.agrawal, Santosh Shukla

Removed mempool api change deprecation notice and
updated change info in release_17.11.

Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
---
 doc/guides/rel_notes/deprecation.rst   | 9 ---------
 doc/guides/rel_notes/release_17_11.rst | 7 +++++++
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 3362f3350..0e4cb1f95 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -44,15 +44,6 @@ Deprecation Notices
   PKT_RX_QINQ_STRIPPED, that are better described. The old flags and
   their behavior will be kept until 17.08 and will be removed in 17.11.
 
-* mempool: The following will be modified in 17.11:
-
-  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
-    the mempool flag status so adding new param rte_mempool in those API.
-  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
-    and ``rte_mempool_generic_get`` API.
-  - ``rte_mempool`` flags data type will changed from int to
-    unsigned int.
-
 * ethdev: Tx offloads will no longer be enabled by default in 17.11.
   Instead, the ``rte_eth_txmode`` structure will be extended with
   bit field to enable each Tx offload.
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f916..055ba10a4 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -110,6 +110,13 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **The following changes made in mempool library**
+
+  * Moved ``flag`` datatype from int to unsigned int for ``rte_mempool``.
+  * Removed ``__rte_unused int flag`` param from ``rte_mempool_generic_put``
+    and ``rte_mempool_generic_get`` API.
+  * Added ``rte_mempool`` param in ``rte_mempool_xmem_size`` and
+    ``rte_mempool_xmem_usage``.
 
 ABI Changes
 -----------
-- 
2.11.0

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v1 4/4] doc: remove dpdk iova aware notice
  @ 2017-08-14 15:15 15% ` Santosh Shukla
  0 siblings, 0 replies; 200+ results
From: Santosh Shukla @ 2017-08-14 15:15 UTC (permalink / raw)
  To: dev; +Cc: olivier.matz, thomas, jerin.jacob, hemant.agrawal, Santosh Shukla

Removed dpdk iova aware ABI deprecation notice,
and updated ABI change details in release_17.11.rst.

Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
---
 doc/guides/rel_notes/deprecation.rst   |  7 -------
 doc/guides/rel_notes/release_17_11.rst | 27 +++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 3362f3350..6482363bf 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -32,13 +32,6 @@ Deprecation Notices
 * eal: the support of Xen dom0 will be removed from EAL in 17.11; and with
   that, drivers/net/xenvirt and examples/vhost_xen will also be removed.
 
-* eal: An ABI change is planned for 17.11 to make DPDK aware of IOVA address
-  translation scheme.
-  Reference to phys address in EAL data-structure or functions may change to
-  IOVA address or more appropriate name.
-  The change will be only for the name.
-  Functional aspects of the API or data-structure will remain same.
-
 * The mbuf flags PKT_RX_VLAN_PKT and PKT_RX_QINQ_PKT are deprecated and
   are respectively replaced by PKT_RX_VLAN_STRIPPED and
   PKT_RX_QINQ_STRIPPED, that are better described. The old flags and
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f916..30d0c0229 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,7 +124,34 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Following datatypes, structure member and function renamed to iova type.**
 
+  * Renamed ``phys_addr_t`` to ``iova_addr_t``.
+  * Renamed ``buf_physaddr`` to ``buf_iovaaddr`` for struct rte_mbuf.
+  * Renamed ``phys_addr`` to ``iova_addr`` for struct rte_memseg.
+  * The Following memory translation api renamed from:
+
+    * ``rte_mempool_populate_phys()``
+    * ``rte_mempool_populate_phys_tab()``
+    * ``rte_eal_using_phys_addrs()``
+    * ``rte_mem_virt2phy()``
+    * ``rte_dump_physmem_layout()``
+    * ``rte_eal_get_physmem_layout()``
+    * ``rte_eal_get_physmem_size()``
+    * ``rte_malloc_virt2phy()``
+    * ``rte_mem_phy2mch()``
+
+  * To the following iova types api:
+
+    * ``rte_mempool_populate_iova()``
+    * ``rte_mempool_populate_iova_tab()``
+    * ``rte_eal_using_iova_addrs()``
+    * ``rte_mem_virt2iova()``
+    * ``rte_dump_iovamem_layout()``
+    * ``rte_eal_get_iovamem_layout()``
+    * ``rte_eal_get_iovamem_size()``
+    * ``rte_malloc_virt2iova()``
+    * ``rte_mem_phy2iova()``
 
 Shared Library Versions
 -----------------------
-- 
2.11.0

^ permalink raw reply	[relevance 15%]

* Re: [dpdk-dev] Announcement of SSE requirement change in dpdk
  2017-08-14 10:58  0%         ` Bruce Richardson
@ 2017-08-14 11:23  4%           ` Neil Horman
  0 siblings, 0 replies; 200+ results
From: Neil Horman @ 2017-08-14 11:23 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev, techboard

On Mon, Aug 14, 2017 at 11:58:21AM +0100, Bruce Richardson wrote:
> On Mon, Aug 14, 2017 at 06:50:40AM -0400, Neil Horman wrote:
> > On Mon, Aug 14, 2017 at 10:32:15AM +0100, Bruce Richardson wrote:
> > > On Sat, Aug 12, 2017 at 02:19:45PM -0400, Neil Horman wrote:
> > > > On Fri, Aug 11, 2017 at 09:29:24PM +0100, Bruce Richardson wrote:
> > > > > On Wed, Aug 09, 2017 at 04:21:32PM -0400, Neil Horman wrote:
> > > > > > Can anyone point out to me when and where the change to require SSE4.2 was
> > > > > > dicussed?  The first I saw of it was when the commit to the release notes went
> > > > > > in on August 3, and I can find no prior mention of it, save for the patches that
> > > > > > went in separately in the prior weeks.
> > > > > > 
> > > > > > Neil
> > > > > > 
> > > > > There was no real widespread discussion of it, if that's what you are
> > > > > looking for. I made the proposal via patch, and it was reviewed and
> > > > > acked by a number of folks, with nobody raising any objections at the
> > > > I had a feeling that was the case, and yes, that does concern me somewhat.  In
> > > > this particular case I think its ok, because I can't really imagine anyone using
> > > > older atom processors, but I think it could become problematic in the future If
> > > > that support line moves too far into territory in which theres downstream
> > > > support issues (with things like OVS or other tree-external applications)
> > > > 
> > > > > time. Possibly it was a change that should have been more widely
> > > > > publicised ahead of time, but I'm not sure what form that publicization
> > > > > should have taken, since all tech discussion happens on the dev mailing
> > > > > list anyway.
> > > > > Not that I'm planning any similar changes, but for the future, what do
> > > > > you think the process for changes like this should be - and what changes
> > > > > would classify for it? If we have a process problem, let's try and fix
> > > > > it.
> > > > > 
> > > > 
> > > > I don't rightly know, to be honest.  DPDK is a little unique in this situation,
> > > > since user libraries are built to just access the lowest common denominator of a
> > > > given arch.  And in many ways, so is the kernel.  I'm open to suggestions, but I
> > > > think so some sort of plan would be a good idea.  These are just off the top of
> > > > my head, and likely have drawbacks, but just to get some conversation started:
> > > > 
> > > > 1) Use extendend ISA instructions opportunistically
> > > > 	By this I mean  to say, we could implement an alternatives system,
> > > > simmilar to what we have in the kernel, which can do dynamic instruction
> > > > replacement based on a run time test.  For example, you can write two versions
> > > > of a function, one which impements its method with sse4 and another version
> > > > which does the same thing using core isa instructions).  If sse4 is available at
> > > > runtime, the sse4 variant is mapped in, else the other version is.
> > > > 	This is something we sort of talked about before, and while theres been
> > > > general support in its philosophy, its the sort of thing that takes alot of
> > > > work, and it is only used in those cases where you know you can use the
> > > > acceleration.
> > > > 
> > > > 2) Limit where you introduce hardware deprecation
> > > > 	Perhaps hardware deprecation can be announced in the same way ABI
> > > > deprecation is, and then introduced at a later date (I would make an opening
> > > > argument for the next LTS release).  Using the LTS release as a deprecation
> > > > point is nice because it lets downstream consumers standardize on a release
> > > > without having to worry about hardware support going away.
> > > > 
> > > > Just my $0.02.  food for thought
> > > > Neil
> > > > 
> > > I think the ABI deprecation policy suggestion is a good one, where if we
> > > want to drop support for some HW that was otherwise supported, we should
> > > announce it at least one release in advance to make sure everyone is
> > > aware of it.
> > > 
> > 
> > Ok, I can agree with that. Are we also agreed on limiting hardware deprecation
> > to LTS release points?
> > Neil
> > 
> To be clear, you think any hardware deprecation should be done as part
> of the LTS release, rather than just after one? I would have thought the
> latter, so as to keep legacy HW support around for as long as possible,
> but I won't have a problem either way.
> 
Thats what I was proposing, yes, that we should limit HW deprecation to LTS
releases, as that allows people using an LTS release to be guaranteed hardware
support for the lifetime of the release, though I'm not really married to the
idea, I'm just using it as a starting point to discuss the decision.

I do think we need to state that LTS releases maintain hardware compatibility as
well as ABI, but if we're comfortable with just adhering to that statement and
doing the backport work needed if it comes up, I'm also fine with hardware
deprecation on the "one release ahead" ABI schedule.

> If you think it's a good policy to have a fixed point at which any HW
> deprecations happen, I don't have an objection to that, but I'm curious
> as to whether others think it may be too restrictive. It's not something
> we've had a lot of up till now to know how big a deal such a restriction
> might be.
> 
I do think a deprecation schedule is warranted, but I'm flexible on the cadence.
I too was hoping we could get other opinions on the matter regarding how
restrictive this needs to be.

> +techboard: I suggest the tech board take an agenda item to ratify and
> assign owner to document a HW deprecation policy, based on this thread,
> at it's next meeting.
> 
That would be great, please!

Best
Neil

> /Bruce
> 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] Announcement of SSE requirement change in dpdk
  2017-08-14 10:50  0%       ` Neil Horman
@ 2017-08-14 10:58  0%         ` Bruce Richardson
  2017-08-14 11:23  4%           ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Bruce Richardson @ 2017-08-14 10:58 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, techboard

On Mon, Aug 14, 2017 at 06:50:40AM -0400, Neil Horman wrote:
> On Mon, Aug 14, 2017 at 10:32:15AM +0100, Bruce Richardson wrote:
> > On Sat, Aug 12, 2017 at 02:19:45PM -0400, Neil Horman wrote:
> > > On Fri, Aug 11, 2017 at 09:29:24PM +0100, Bruce Richardson wrote:
> > > > On Wed, Aug 09, 2017 at 04:21:32PM -0400, Neil Horman wrote:
> > > > > Can anyone point out to me when and where the change to require SSE4.2 was
> > > > > dicussed?  The first I saw of it was when the commit to the release notes went
> > > > > in on August 3, and I can find no prior mention of it, save for the patches that
> > > > > went in separately in the prior weeks.
> > > > > 
> > > > > Neil
> > > > > 
> > > > There was no real widespread discussion of it, if that's what you are
> > > > looking for. I made the proposal via patch, and it was reviewed and
> > > > acked by a number of folks, with nobody raising any objections at the
> > > I had a feeling that was the case, and yes, that does concern me somewhat.  In
> > > this particular case I think its ok, because I can't really imagine anyone using
> > > older atom processors, but I think it could become problematic in the future If
> > > that support line moves too far into territory in which theres downstream
> > > support issues (with things like OVS or other tree-external applications)
> > > 
> > > > time. Possibly it was a change that should have been more widely
> > > > publicised ahead of time, but I'm not sure what form that publicization
> > > > should have taken, since all tech discussion happens on the dev mailing
> > > > list anyway.
> > > > Not that I'm planning any similar changes, but for the future, what do
> > > > you think the process for changes like this should be - and what changes
> > > > would classify for it? If we have a process problem, let's try and fix
> > > > it.
> > > > 
> > > 
> > > I don't rightly know, to be honest.  DPDK is a little unique in this situation,
> > > since user libraries are built to just access the lowest common denominator of a
> > > given arch.  And in many ways, so is the kernel.  I'm open to suggestions, but I
> > > think so some sort of plan would be a good idea.  These are just off the top of
> > > my head, and likely have drawbacks, but just to get some conversation started:
> > > 
> > > 1) Use extendend ISA instructions opportunistically
> > > 	By this I mean  to say, we could implement an alternatives system,
> > > simmilar to what we have in the kernel, which can do dynamic instruction
> > > replacement based on a run time test.  For example, you can write two versions
> > > of a function, one which impements its method with sse4 and another version
> > > which does the same thing using core isa instructions).  If sse4 is available at
> > > runtime, the sse4 variant is mapped in, else the other version is.
> > > 	This is something we sort of talked about before, and while theres been
> > > general support in its philosophy, its the sort of thing that takes alot of
> > > work, and it is only used in those cases where you know you can use the
> > > acceleration.
> > > 
> > > 2) Limit where you introduce hardware deprecation
> > > 	Perhaps hardware deprecation can be announced in the same way ABI
> > > deprecation is, and then introduced at a later date (I would make an opening
> > > argument for the next LTS release).  Using the LTS release as a deprecation
> > > point is nice because it lets downstream consumers standardize on a release
> > > without having to worry about hardware support going away.
> > > 
> > > Just my $0.02.  food for thought
> > > Neil
> > > 
> > I think the ABI deprecation policy suggestion is a good one, where if we
> > want to drop support for some HW that was otherwise supported, we should
> > announce it at least one release in advance to make sure everyone is
> > aware of it.
> > 
> 
> Ok, I can agree with that. Are we also agreed on limiting hardware deprecation
> to LTS release points?
> Neil
> 
To be clear, you think any hardware deprecation should be done as part
of the LTS release, rather than just after one? I would have thought the
latter, so as to keep legacy HW support around for as long as possible,
but I won't have a problem either way.

If you think it's a good policy to have a fixed point at which any HW
deprecations happen, I don't have an objection to that, but I'm curious
as to whether others think it may be too restrictive. It's not something
we've had a lot of up till now to know how big a deal such a restriction
might be.

+techboard: I suggest the tech board take an agenda item to ratify and
assign owner to document a HW deprecation policy, based on this thread,
at it's next meeting.

/Bruce

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] Announcement of SSE requirement change in dpdk
  2017-08-14  9:32  3%     ` Bruce Richardson
@ 2017-08-14 10:50  0%       ` Neil Horman
  2017-08-14 10:58  0%         ` Bruce Richardson
  0 siblings, 1 reply; 200+ results
From: Neil Horman @ 2017-08-14 10:50 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev

On Mon, Aug 14, 2017 at 10:32:15AM +0100, Bruce Richardson wrote:
> On Sat, Aug 12, 2017 at 02:19:45PM -0400, Neil Horman wrote:
> > On Fri, Aug 11, 2017 at 09:29:24PM +0100, Bruce Richardson wrote:
> > > On Wed, Aug 09, 2017 at 04:21:32PM -0400, Neil Horman wrote:
> > > > Can anyone point out to me when and where the change to require SSE4.2 was
> > > > dicussed?  The first I saw of it was when the commit to the release notes went
> > > > in on August 3, and I can find no prior mention of it, save for the patches that
> > > > went in separately in the prior weeks.
> > > > 
> > > > Neil
> > > > 
> > > There was no real widespread discussion of it, if that's what you are
> > > looking for. I made the proposal via patch, and it was reviewed and
> > > acked by a number of folks, with nobody raising any objections at the
> > I had a feeling that was the case, and yes, that does concern me somewhat.  In
> > this particular case I think its ok, because I can't really imagine anyone using
> > older atom processors, but I think it could become problematic in the future If
> > that support line moves too far into territory in which theres downstream
> > support issues (with things like OVS or other tree-external applications)
> > 
> > > time. Possibly it was a change that should have been more widely
> > > publicised ahead of time, but I'm not sure what form that publicization
> > > should have taken, since all tech discussion happens on the dev mailing
> > > list anyway.
> > > Not that I'm planning any similar changes, but for the future, what do
> > > you think the process for changes like this should be - and what changes
> > > would classify for it? If we have a process problem, let's try and fix
> > > it.
> > > 
> > 
> > I don't rightly know, to be honest.  DPDK is a little unique in this situation,
> > since user libraries are built to just access the lowest common denominator of a
> > given arch.  And in many ways, so is the kernel.  I'm open to suggestions, but I
> > think so some sort of plan would be a good idea.  These are just off the top of
> > my head, and likely have drawbacks, but just to get some conversation started:
> > 
> > 1) Use extendend ISA instructions opportunistically
> > 	By this I mean  to say, we could implement an alternatives system,
> > simmilar to what we have in the kernel, which can do dynamic instruction
> > replacement based on a run time test.  For example, you can write two versions
> > of a function, one which impements its method with sse4 and another version
> > which does the same thing using core isa instructions).  If sse4 is available at
> > runtime, the sse4 variant is mapped in, else the other version is.
> > 	This is something we sort of talked about before, and while theres been
> > general support in its philosophy, its the sort of thing that takes alot of
> > work, and it is only used in those cases where you know you can use the
> > acceleration.
> > 
> > 2) Limit where you introduce hardware deprecation
> > 	Perhaps hardware deprecation can be announced in the same way ABI
> > deprecation is, and then introduced at a later date (I would make an opening
> > argument for the next LTS release).  Using the LTS release as a deprecation
> > point is nice because it lets downstream consumers standardize on a release
> > without having to worry about hardware support going away.
> > 
> > Just my $0.02.  food for thought
> > Neil
> > 
> I think the ABI deprecation policy suggestion is a good one, where if we
> want to drop support for some HW that was otherwise supported, we should
> announce it at least one release in advance to make sure everyone is
> aware of it.
> 

Ok, I can agree with that. Are we also agreed on limiting hardware deprecation
to LTS release points?
Neil

> /Bruce
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] Announcement of SSE requirement change in dpdk
  2017-08-12 18:19  3%   ` Neil Horman
@ 2017-08-14  9:32  3%     ` Bruce Richardson
  2017-08-14 10:50  0%       ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Bruce Richardson @ 2017-08-14  9:32 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev

On Sat, Aug 12, 2017 at 02:19:45PM -0400, Neil Horman wrote:
> On Fri, Aug 11, 2017 at 09:29:24PM +0100, Bruce Richardson wrote:
> > On Wed, Aug 09, 2017 at 04:21:32PM -0400, Neil Horman wrote:
> > > Can anyone point out to me when and where the change to require SSE4.2 was
> > > dicussed?  The first I saw of it was when the commit to the release notes went
> > > in on August 3, and I can find no prior mention of it, save for the patches that
> > > went in separately in the prior weeks.
> > > 
> > > Neil
> > > 
> > There was no real widespread discussion of it, if that's what you are
> > looking for. I made the proposal via patch, and it was reviewed and
> > acked by a number of folks, with nobody raising any objections at the
> I had a feeling that was the case, and yes, that does concern me somewhat.  In
> this particular case I think its ok, because I can't really imagine anyone using
> older atom processors, but I think it could become problematic in the future If
> that support line moves too far into territory in which theres downstream
> support issues (with things like OVS or other tree-external applications)
> 
> > time. Possibly it was a change that should have been more widely
> > publicised ahead of time, but I'm not sure what form that publicization
> > should have taken, since all tech discussion happens on the dev mailing
> > list anyway.
> > Not that I'm planning any similar changes, but for the future, what do
> > you think the process for changes like this should be - and what changes
> > would classify for it? If we have a process problem, let's try and fix
> > it.
> > 
> 
> I don't rightly know, to be honest.  DPDK is a little unique in this situation,
> since user libraries are built to just access the lowest common denominator of a
> given arch.  And in many ways, so is the kernel.  I'm open to suggestions, but I
> think so some sort of plan would be a good idea.  These are just off the top of
> my head, and likely have drawbacks, but just to get some conversation started:
> 
> 1) Use extendend ISA instructions opportunistically
> 	By this I mean  to say, we could implement an alternatives system,
> simmilar to what we have in the kernel, which can do dynamic instruction
> replacement based on a run time test.  For example, you can write two versions
> of a function, one which impements its method with sse4 and another version
> which does the same thing using core isa instructions).  If sse4 is available at
> runtime, the sse4 variant is mapped in, else the other version is.
> 	This is something we sort of talked about before, and while theres been
> general support in its philosophy, its the sort of thing that takes alot of
> work, and it is only used in those cases where you know you can use the
> acceleration.
> 
> 2) Limit where you introduce hardware deprecation
> 	Perhaps hardware deprecation can be announced in the same way ABI
> deprecation is, and then introduced at a later date (I would make an opening
> argument for the next LTS release).  Using the LTS release as a deprecation
> point is nice because it lets downstream consumers standardize on a release
> without having to worry about hardware support going away.
> 
> Just my $0.02.  food for thought
> Neil
> 
I think the ABI deprecation policy suggestion is a good one, where if we
want to drop support for some HW that was otherwise supported, we should
announce it at least one release in advance to make sure everyone is
aware of it.

/Bruce

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] Announcement of SSE requirement change in dpdk
  @ 2017-08-12 18:19  3%   ` Neil Horman
  2017-08-14  9:32  3%     ` Bruce Richardson
  0 siblings, 1 reply; 200+ results
From: Neil Horman @ 2017-08-12 18:19 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev

On Fri, Aug 11, 2017 at 09:29:24PM +0100, Bruce Richardson wrote:
> On Wed, Aug 09, 2017 at 04:21:32PM -0400, Neil Horman wrote:
> > Can anyone point out to me when and where the change to require SSE4.2 was
> > dicussed?  The first I saw of it was when the commit to the release notes went
> > in on August 3, and I can find no prior mention of it, save for the patches that
> > went in separately in the prior weeks.
> > 
> > Neil
> > 
> There was no real widespread discussion of it, if that's what you are
> looking for. I made the proposal via patch, and it was reviewed and
> acked by a number of folks, with nobody raising any objections at the
I had a feeling that was the case, and yes, that does concern me somewhat.  In
this particular case I think its ok, because I can't really imagine anyone using
older atom processors, but I think it could become problematic in the future If
that support line moves too far into territory in which theres downstream
support issues (with things like OVS or other tree-external applications)

> time. Possibly it was a change that should have been more widely
> publicised ahead of time, but I'm not sure what form that publicization
> should have taken, since all tech discussion happens on the dev mailing
> list anyway.
> Not that I'm planning any similar changes, but for the future, what do
> you think the process for changes like this should be - and what changes
> would classify for it? If we have a process problem, let's try and fix
> it.
> 

I don't rightly know, to be honest.  DPDK is a little unique in this situation,
since user libraries are built to just access the lowest common denominator of a
given arch.  And in many ways, so is the kernel.  I'm open to suggestions, but I
think so some sort of plan would be a good idea.  These are just off the top of
my head, and likely have drawbacks, but just to get some conversation started:

1) Use extendend ISA instructions opportunistically
	By this I mean  to say, we could implement an alternatives system,
simmilar to what we have in the kernel, which can do dynamic instruction
replacement based on a run time test.  For example, you can write two versions
of a function, one which impements its method with sse4 and another version
which does the same thing using core isa instructions).  If sse4 is available at
runtime, the sse4 variant is mapped in, else the other version is.
	This is something we sort of talked about before, and while theres been
general support in its philosophy, its the sort of thing that takes alot of
work, and it is only used in those cases where you know you can use the
acceleration.

2) Limit where you introduce hardware deprecation
	Perhaps hardware deprecation can be announced in the same way ABI
deprecation is, and then introduced at a later date (I would make an opening
argument for the next LTS release).  Using the LTS release as a deprecation
point is nice because it lets downstream consumers standardize on a release
without having to worry about hardware support going away.

Just my $0.02.  food for thought
Neil

> Regards,
> /Bruce.
> 

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v4 2/2] doc: Update ABI Change for rte_eth_stats_reset
  @ 2017-08-10 13:29 13%   ` David Harton
  0 siblings, 0 replies; 200+ results
From: David Harton @ 2017-08-10 13:29 UTC (permalink / raw)
  To: thomas; +Cc: dev, harry.van.haaren, christian.ehrhardt, David Harton

Signed-off-by: David Harton <dharton@cisco.com>
---

v4:
* Added requested release note about ABI change.

 doc/guides/rel_notes/release_17_11.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 170f4f9..e329f8a 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -124,6 +124,7 @@ ABI Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* Changed return type of ``rte_eth_stats_reset`` from ``void`` to ``int``.
 
 
 Shared Library Versions
-- 
2.10.3.dirty

^ permalink raw reply	[relevance 13%]

* Re: [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist
  2017-08-09 14:35  3%   ` Wiles, Keith
@ 2017-08-09 14:47  0%     ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2017-08-09 14:47 UTC (permalink / raw)
  To: Wiles, Keith; +Cc: dev



> -----Original Message-----
> From: Wiles, Keith
> Sent: Wednesday, August 9, 2017 5:36 PM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist
> 
> 
> > On Aug 9, 2017, at 8:53 AM, Ananyev, Konstantin <konstantin.ananyev@intel.com> wrote:
> >
> >
> >
> >> -----Original Message-----
> >> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Keith Wiles
> >> Sent: Wednesday, August 9, 2017 4:30 PM
> >> To: dev@dpdk.org
> >> Subject: [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist
> >>
> >> rte_kvargs_process() should return error if the key
> >> is not found in the kvlist or kvlist is NULL.
> >
> > Looks like an API breakage for me…
> 
> To me it is not an ABI breakage only fixing the routine to return the correct status.
> 
> > Could you probably explain why do you think it is necessary?
> 
> For the no key found surely seems like an error to me,

Not necessary, it could be an optional one.

> but I guess you can always require someone to call the rte_kvargs_count() API first

Yep.

> which is not stated any place.

> 
> As for the kvlist being null that is an error IMO and returning success is not valid.
> 
> But to save a huge discussion I rejected the patch in patchwork for now.

Ok.
Konstantin

> 
> > Konstantin
> >
> >>
> >> Minor documentation changes and update for when an
> >> error is returned.
> >>
> >> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> >> ---
> >> lib/librte_kvargs/rte_kvargs.c | 7 ++++---
> >> lib/librte_kvargs/rte_kvargs.h | 7 ++++---
> >> 2 files changed, 8 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
> >> index 854ac83f5..c8e8f4b28 100755
> >> --- a/lib/librte_kvargs/rte_kvargs.c
> >> +++ b/lib/librte_kvargs/rte_kvargs.c
> >> @@ -158,16 +158,17 @@ rte_kvargs_process(const struct rte_kvargs *kvlist,
> >> 		void *opaque_arg)
> >> {
> >> 	const struct rte_kvargs_pair *pair;
> >> -	unsigned i;
> >> +	unsigned int i, found = 0;
> >>
> >> 	for (i = 0; i < kvlist->count; i++) {
> >> 		pair = &kvlist->pairs[i];
> >> -		if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
> >> +		if (!key_match || strcmp(pair->key, key_match) == 0) {
> >> +			found++;
> >> 			if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
> >> 				return -1;
> >> 		}
> >> 	}
> >> -	return 0;
> >> +	return (!found) ? -1 : 0;
> >> }
> >>
> >> /* free the rte_kvargs structure */
> >> diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
> >> index 5821c726a..260d4db5b 100755
> >> --- a/lib/librte_kvargs/rte_kvargs.h
> >> +++ b/lib/librte_kvargs/rte_kvargs.h
> >> @@ -115,9 +115,9 @@ void rte_kvargs_free(struct rte_kvargs *kvlist);
> >>  * Call a handler function for each key/value matching the key
> >>  *
> >>  * For each key/value association that matches the given key, calls the
> >> - * handler function with the for a given arg_name passing the value on the
> >> + * handler function with the given arg_name passing the value in the
> >>  * dictionary for that key and a given extra argument. If *kvlist* is NULL
> >> - * function does nothing.
> >> + * function does nothing and returns error.
> >>  *
> >>  * @param kvlist
> >>  *   The rte_kvargs structure
> >> @@ -131,7 +131,8 @@ void rte_kvargs_free(struct rte_kvargs *kvlist);
> >>  *
> >>  * @return
> >>  *   - 0 on success
> >> - *   - Negative on error
> >> + *   - Negative on error or
> >> + *       if *key_match* does not match an entry in *kvlist*
> >>  */
> >> int rte_kvargs_process(const struct rte_kvargs *kvlist,
> >> 	const char *key_match, arg_handler_t handler, void *opaque_arg);
> >> --
> >> 2.11.0
> >
> 
> Regards,
> Keith


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist
  @ 2017-08-09 14:35  3%   ` Wiles, Keith
  2017-08-09 14:47  0%     ` Ananyev, Konstantin
  0 siblings, 1 reply; 200+ results
From: Wiles, Keith @ 2017-08-09 14:35 UTC (permalink / raw)
  To: Ananyev, Konstantin; +Cc: dev


> On Aug 9, 2017, at 8:53 AM, Ananyev, Konstantin <konstantin.ananyev@intel.com> wrote:
> 
> 
> 
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Keith Wiles
>> Sent: Wednesday, August 9, 2017 4:30 PM
>> To: dev@dpdk.org
>> Subject: [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist
>> 
>> rte_kvargs_process() should return error if the key
>> is not found in the kvlist or kvlist is NULL.
> 
> Looks like an API breakage for me…

To me it is not an ABI breakage only fixing the routine to return the correct status.

> Could you probably explain why do you think it is necessary?

For the no key found surely seems like an error to me, but I guess you can always require someone to call the rte_kvargs_count() API first which is not stated any place.

As for the kvlist being null that is an error IMO and returning success is not valid.

But to save a huge discussion I rejected the patch in patchwork for now.

> Konstantin
> 
>> 
>> Minor documentation changes and update for when an
>> error is returned.
>> 
>> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
>> ---
>> lib/librte_kvargs/rte_kvargs.c | 7 ++++---
>> lib/librte_kvargs/rte_kvargs.h | 7 ++++---
>> 2 files changed, 8 insertions(+), 6 deletions(-)
>> 
>> diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
>> index 854ac83f5..c8e8f4b28 100755
>> --- a/lib/librte_kvargs/rte_kvargs.c
>> +++ b/lib/librte_kvargs/rte_kvargs.c
>> @@ -158,16 +158,17 @@ rte_kvargs_process(const struct rte_kvargs *kvlist,
>> 		void *opaque_arg)
>> {
>> 	const struct rte_kvargs_pair *pair;
>> -	unsigned i;
>> +	unsigned int i, found = 0;
>> 
>> 	for (i = 0; i < kvlist->count; i++) {
>> 		pair = &kvlist->pairs[i];
>> -		if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
>> +		if (!key_match || strcmp(pair->key, key_match) == 0) {
>> +			found++;
>> 			if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
>> 				return -1;
>> 		}
>> 	}
>> -	return 0;
>> +	return (!found) ? -1 : 0;
>> }
>> 
>> /* free the rte_kvargs structure */
>> diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
>> index 5821c726a..260d4db5b 100755
>> --- a/lib/librte_kvargs/rte_kvargs.h
>> +++ b/lib/librte_kvargs/rte_kvargs.h
>> @@ -115,9 +115,9 @@ void rte_kvargs_free(struct rte_kvargs *kvlist);
>>  * Call a handler function for each key/value matching the key
>>  *
>>  * For each key/value association that matches the given key, calls the
>> - * handler function with the for a given arg_name passing the value on the
>> + * handler function with the given arg_name passing the value in the
>>  * dictionary for that key and a given extra argument. If *kvlist* is NULL
>> - * function does nothing.
>> + * function does nothing and returns error.
>>  *
>>  * @param kvlist
>>  *   The rte_kvargs structure
>> @@ -131,7 +131,8 @@ void rte_kvargs_free(struct rte_kvargs *kvlist);
>>  *
>>  * @return
>>  *   - 0 on success
>> - *   - Negative on error
>> + *   - Negative on error or
>> + *       if *key_match* does not match an entry in *kvlist*
>>  */
>> int rte_kvargs_process(const struct rte_kvargs *kvlist,
>> 	const char *key_match, arg_handler_t handler, void *opaque_arg);
>> --
>> 2.11.0
> 

Regards,
Keith


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 0/2] increase port_id range
  2017-08-09  9:00  4% ` De Lara Guarch, Pablo
@ 2017-08-09  9:17  0%   ` Yang, Zhiyong
  0 siblings, 0 replies; 200+ results
From: Yang, Zhiyong @ 2017-08-09  9:17 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev; +Cc: thomas

Hi,Pablo: 

> -----Original Message-----
> From: De Lara Guarch, Pablo
> Sent: Wednesday, August 9, 2017 5:01 PM
> To: Yang, Zhiyong <zhiyong.yang@intel.com>; dev@dpdk.org
> Cc: thomas@monjalon.net
> Subject: RE: [dpdk-dev] [PATCH 0/2] increase port_id range
> 
> Hi Zhiyong,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Zhiyong Yang
> > Sent: Wednesday, August 9, 2017 9:42 AM
> > To: dev@dpdk.org
> > Cc: thomas@monjalon.net
> > Subject: [dpdk-dev] [PATCH 0/2] increase port_id range
> >
> > port_id is currently defined as uint8_t, which is limited to the range
> > 0 to 255. A larger range is required for vdev scalability.
> >
> > It is necessary for a redefinition of port_id to extend it from 1
> > bytes to
> > 2 bytes. All ethdev APIs and usages related to port_id will be changed
> > at the same time.
> >
> > Below is an API/ABI change notice for DPDK 17.11.
> > http://www.dpdk.org/dev/patchwork/patch/27475/
> >
> > Discussion about port_id is the following thread.
> > http://www.dpdk.org/dev/patchwork/patch/23208/
> >
> > Zhiyong Yang (2):
> >   ethdev: increase port_id range
> >   examples: increase port_id range
> >
> >  app/pdump/main.c                                |   2 +-
> >  app/test-pmd/cmdline.c                          |   4 +-
> >  app/test-pmd/testpmd.c                          |   4 +-
> >  app/test-pmd/testpmd.h                          |   2 +-
> >  drivers/net/bonding/rte_eth_bond.h              |  40 ++--
> >  drivers/net/bonding/rte_eth_bond_8023ad.c       |   6 +-
> >  drivers/net/bonding/rte_eth_bond_api.c          |  54 +++---
> >  drivers/net/bonding/rte_eth_bond_pmd.c          |  10 +-
> >  drivers/net/bonding/rte_eth_bond_private.h      |  36 ++--
> >  drivers/net/failsafe/failsafe_ether.c           |   4 +-
> >  drivers/net/failsafe/failsafe_private.h         |   4 +-
> >  drivers/net/ring/rte_eth_ring.c                 |   2 +-
> >  examples/bond/main.c                            |   6 +-
> >  examples/ip_fragmentation/main.c                |   4 +-
> >  examples/l3fwd-power/main.c                     |   7 +-
> >  examples/l3fwd/l3fwd.h                          |  10 +-
> >  examples/l3fwd/l3fwd_em.c                       |   2 +-
> >  examples/l3fwd/l3fwd_lpm.c                      |   2 +-
> >  examples/link_status_interrupt/main.c           |   5 +-
> >  examples/performance-thread/l3fwd-thread/main.c |   7 +-
> >  examples/rxtx_callbacks/main.c                  |   8 +-
> >  lib/librte_ether/rte_ethdev.c                   | 231 +++++++++++------------
> >  lib/librte_ether/rte_ethdev.h                   | 236 ++++++++++++------------
> >  lib/librte_ether/rte_tm.c                       |  62 +++----
> >  lib/librte_ether/rte_tm.h                       |  60 +++---
> >  lib/librte_ether/rte_tm_driver.h                |   2 +-
> >  lib/librte_latencystats/rte_latencystats.c      |   8 +-
> >  lib/librte_pdump/rte_pdump.c                    |  16 +-
> >  lib/librte_pdump/rte_pdump.h                    |   4 +-
> >  lib/librte_port/rte_port_ethdev.c               |   6 +-
> >  lib/librte_port/rte_port_ethdev.h               |   6 +-
> >  31 files changed, 431 insertions(+), 419 deletions(-)
> >
> > --
> > 2.13.3
> 
> You should remove the deprecation notice that was sent for the ABI breakage in
> this patchset, and add a note in release notes, documenting the API/ABI changes
> that you have done.
> 

Thank you, Pablo. I forget to add a note.  Deprecation notice will be removed if need v2 patch.
It is my first patchset which needs to send deprecation notice firstly. :)

Zhiyong

> Thanks,
> Pablo




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 0/2] increase port_id range
  2017-08-09  8:42  3% [dpdk-dev] [PATCH 0/2] increase port_id range Zhiyong Yang
@ 2017-08-09  9:00  4% ` De Lara Guarch, Pablo
  2017-08-09  9:17  0%   ` Yang, Zhiyong
  0 siblings, 1 reply; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-09  9:00 UTC (permalink / raw)
  To: Yang, Zhiyong, dev; +Cc: thomas

Hi Zhiyong,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Zhiyong Yang
> Sent: Wednesday, August 9, 2017 9:42 AM
> To: dev@dpdk.org
> Cc: thomas@monjalon.net
> Subject: [dpdk-dev] [PATCH 0/2] increase port_id range
> 
> port_id is currently defined as uint8_t, which is limited to the range 0 to
> 255. A larger range is required for vdev scalability.
> 
> It is necessary for a redefinition of port_id to extend it from 1 bytes to
> 2 bytes. All ethdev APIs and usages related to port_id will be changed at the
> same time.
> 
> Below is an API/ABI change notice for DPDK 17.11.
> http://www.dpdk.org/dev/patchwork/patch/27475/
> 
> Discussion about port_id is the following thread.
> http://www.dpdk.org/dev/patchwork/patch/23208/
> 
> Zhiyong Yang (2):
>   ethdev: increase port_id range
>   examples: increase port_id range
> 
>  app/pdump/main.c                                |   2 +-
>  app/test-pmd/cmdline.c                          |   4 +-
>  app/test-pmd/testpmd.c                          |   4 +-
>  app/test-pmd/testpmd.h                          |   2 +-
>  drivers/net/bonding/rte_eth_bond.h              |  40 ++--
>  drivers/net/bonding/rte_eth_bond_8023ad.c       |   6 +-
>  drivers/net/bonding/rte_eth_bond_api.c          |  54 +++---
>  drivers/net/bonding/rte_eth_bond_pmd.c          |  10 +-
>  drivers/net/bonding/rte_eth_bond_private.h      |  36 ++--
>  drivers/net/failsafe/failsafe_ether.c           |   4 +-
>  drivers/net/failsafe/failsafe_private.h         |   4 +-
>  drivers/net/ring/rte_eth_ring.c                 |   2 +-
>  examples/bond/main.c                            |   6 +-
>  examples/ip_fragmentation/main.c                |   4 +-
>  examples/l3fwd-power/main.c                     |   7 +-
>  examples/l3fwd/l3fwd.h                          |  10 +-
>  examples/l3fwd/l3fwd_em.c                       |   2 +-
>  examples/l3fwd/l3fwd_lpm.c                      |   2 +-
>  examples/link_status_interrupt/main.c           |   5 +-
>  examples/performance-thread/l3fwd-thread/main.c |   7 +-
>  examples/rxtx_callbacks/main.c                  |   8 +-
>  lib/librte_ether/rte_ethdev.c                   | 231 +++++++++++------------
>  lib/librte_ether/rte_ethdev.h                   | 236 ++++++++++++------------
>  lib/librte_ether/rte_tm.c                       |  62 +++----
>  lib/librte_ether/rte_tm.h                       |  60 +++---
>  lib/librte_ether/rte_tm_driver.h                |   2 +-
>  lib/librte_latencystats/rte_latencystats.c      |   8 +-
>  lib/librte_pdump/rte_pdump.c                    |  16 +-
>  lib/librte_pdump/rte_pdump.h                    |   4 +-
>  lib/librte_port/rte_port_ethdev.c               |   6 +-
>  lib/librte_port/rte_port_ethdev.h               |   6 +-
>  31 files changed, 431 insertions(+), 419 deletions(-)
> 
> --
> 2.13.3

You should remove the deprecation notice that was sent
for the ABI breakage in this patchset, and add a note in release notes,
documenting the API/ABI changes that you have done.

Thanks,
Pablo

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH 0/2] increase port_id range
@ 2017-08-09  8:42  3% Zhiyong Yang
  2017-08-09  9:00  4% ` De Lara Guarch, Pablo
  0 siblings, 1 reply; 200+ results
From: Zhiyong Yang @ 2017-08-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: thomas

port_id is currently defined as uint8_t, which is limited to the range 0 to
255. A larger range is required for vdev scalability.

It is necessary for a redefinition of port_id to extend it from 1 bytes to
2 bytes. All ethdev APIs and usages related to port_id will be changed at the
same time.

Below is an API/ABI change notice for DPDK 17.11.
http://www.dpdk.org/dev/patchwork/patch/27475/

Discussion about port_id is the following thread.
http://www.dpdk.org/dev/patchwork/patch/23208/

Zhiyong Yang (2):
  ethdev: increase port_id range
  examples: increase port_id range

 app/pdump/main.c                                |   2 +-
 app/test-pmd/cmdline.c                          |   4 +-
 app/test-pmd/testpmd.c                          |   4 +-
 app/test-pmd/testpmd.h                          |   2 +-
 drivers/net/bonding/rte_eth_bond.h              |  40 ++--
 drivers/net/bonding/rte_eth_bond_8023ad.c       |   6 +-
 drivers/net/bonding/rte_eth_bond_api.c          |  54 +++---
 drivers/net/bonding/rte_eth_bond_pmd.c          |  10 +-
 drivers/net/bonding/rte_eth_bond_private.h      |  36 ++--
 drivers/net/failsafe/failsafe_ether.c           |   4 +-
 drivers/net/failsafe/failsafe_private.h         |   4 +-
 drivers/net/ring/rte_eth_ring.c                 |   2 +-
 examples/bond/main.c                            |   6 +-
 examples/ip_fragmentation/main.c                |   4 +-
 examples/l3fwd-power/main.c                     |   7 +-
 examples/l3fwd/l3fwd.h                          |  10 +-
 examples/l3fwd/l3fwd_em.c                       |   2 +-
 examples/l3fwd/l3fwd_lpm.c                      |   2 +-
 examples/link_status_interrupt/main.c           |   5 +-
 examples/performance-thread/l3fwd-thread/main.c |   7 +-
 examples/rxtx_callbacks/main.c                  |   8 +-
 lib/librte_ether/rte_ethdev.c                   | 231 +++++++++++------------
 lib/librte_ether/rte_ethdev.h                   | 236 ++++++++++++------------
 lib/librte_ether/rte_tm.c                       |  62 +++----
 lib/librte_ether/rte_tm.h                       |  60 +++---
 lib/librte_ether/rte_tm_driver.h                |   2 +-
 lib/librte_latencystats/rte_latencystats.c      |   8 +-
 lib/librte_pdump/rte_pdump.c                    |  16 +-
 lib/librte_pdump/rte_pdump.h                    |   4 +-
 lib/librte_port/rte_port_ethdev.c               |   6 +-
 lib/librte_port/rte_port_ethdev.h               |   6 +-
 31 files changed, 431 insertions(+), 419 deletions(-)

-- 
2.13.3

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2] doc: add template release notes for 17.11
  2017-08-08 12:31  6% [dpdk-dev] [PATCH v1] doc: add template release notes for 17.11 John McNamara
@ 2017-08-09  8:22  6% ` John McNamara
  0 siblings, 0 replies; 200+ results
From: John McNamara @ 2017-08-09  8:22 UTC (permalink / raw)
  To: dev; +Cc: John McNamara

Add template release notes for DPDK 17.11 with inline
comments and explanations of the various sections.

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

V2: Updated library version numbers.


 doc/guides/rel_notes/index.rst         |   1 +
 doc/guides/rel_notes/release_17_11.rst | 200 +++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)
 create mode 100644 doc/guides/rel_notes/release_17_11.rst

diff --git a/doc/guides/rel_notes/index.rst b/doc/guides/rel_notes/index.rst
index b3c8090..35659d8 100644
--- a/doc/guides/rel_notes/index.rst
+++ b/doc/guides/rel_notes/index.rst
@@ -36,6 +36,7 @@ Release Notes
     :numbered:
 
     rel_description
+    release_17_11
     release_17_08
     release_17_05
     release_17_02
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
new file mode 100644
index 0000000..170f4f9
--- /dev/null
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -0,0 +1,200 @@
+DPDK Release 17.11
+==================
+
+.. **Read this first.**
+
+   The text in the sections below explains how to update the release notes.
+
+   Use proper spelling, capitalization and punctuation in all sections.
+
+   Variable and config names should be quoted as fixed width text:
+   ``LIKE_THIS``.
+
+   Build the docs and view the output file to ensure the changes are correct::
+
+      make doc-guides-html
+
+      xdg-open build/doc/html/guides/rel_notes/release_17_11.html
+
+
+New Features
+------------
+
+.. This section should contain new features added in this release. Sample
+   format:
+
+   * **Add a title in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description in the past tense. The description
+     should be enough to allow someone scanning the release notes to
+     understand the new feature.
+
+     If the feature adds a lot of sub-features you can use a bullet list like
+     this:
+
+     * Added feature foo to do something.
+     * Enhanced feature bar to do something else.
+
+     Refer to the previous release notes for examples.
+
+     This section is a comment. do not overwrite or remove it.
+     Also, make sure to start the actual text at the margin.
+     =========================================================
+
+
+Resolved Issues
+---------------
+
+.. This section should contain bug fixes added to the relevant
+   sections. Sample format:
+
+   * **code/section Fixed issue in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description of the resolved issue in the past
+     tense.
+
+     The title should contain the code/lib section like a commit message.
+
+     Add the entries in alphabetic order in the relevant sections below.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+EAL
+~~~
+
+
+Drivers
+~~~~~~~
+
+
+Libraries
+~~~~~~~~~
+
+
+Examples
+~~~~~~~~
+
+
+Other
+~~~~~
+
+
+Known Issues
+------------
+
+.. This section should contain new known issues in this release. Sample format:
+
+   * **Add title in present tense with full stop.**
+
+     Add a short 1-2 sentence description of the known issue in the present
+     tense. Add information on any known workarounds.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+API Changes
+-----------
+
+.. This section should contain API changes. Sample format:
+
+   * Add a short 1-2 sentence description of the API change. Use fixed width
+     quotes for ``rte_function_names`` or ``rte_struct_names``. Use the past
+     tense.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+ABI Changes
+-----------
+
+.. This section should contain ABI changes. Sample format:
+
+   * Add a short 1-2 sentence description of the ABI change that was announced
+     in the previous releases and made in this release. Use fixed width quotes
+     for ``rte_function_names`` or ``rte_struct_names``. Use the past tense.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+
+Shared Library Versions
+-----------------------
+
+.. Update any library version updated in this release and prepend with a ``+``
+   sign, like this:
+
+     librte_acl.so.2
+   + librte_cfgfile.so.2
+     librte_cmdline.so.2
+
+   This section is a comment. do not overwrite or remove it.
+   =========================================================
+
+
+The libraries prepended with a plus sign were incremented in this version.
+
+.. code-block:: diff
+
+     librte_acl.so.2
+     librte_bitratestats.so.1
+     librte_cfgfile.so.2
+     librte_cmdline.so.2
+     librte_cryptodev.so.3
+     librte_distributor.so.1
+     librte_eal.so.5
+     librte_ethdev.so.7
+     librte_eventdev.so.2
+     librte_gro.so.1
+     librte_hash.so.2
+     librte_ip_frag.so.1
+     librte_jobstats.so.1
+     librte_kni.so.2
+     librte_kvargs.so.1
+     librte_latencystats.so.1
+     librte_lpm.so.2
+     librte_mbuf.so.3
+     librte_mempool.so.2
+     librte_meter.so.1
+     librte_metrics.so.1
+     librte_net.so.1
+     librte_pdump.so.1
+     librte_pipeline.so.3
+     librte_pmd_bond.so.1
+     librte_pmd_ring.so.2
+     librte_port.so.3
+     librte_power.so.1
+     librte_reorder.so.1
+     librte_ring.so.1
+     librte_sched.so.1
+     librte_table.so.2
+     librte_timer.so.1
+     librte_vhost.so.3
+
+
+Tested Platforms
+----------------
+
+.. This section should contain a list of platforms that were tested with this
+   release.
+
+   The format is:
+
+   * <vendor> platform with <vendor> <type of devices> combinations
+
+     * List of CPU
+     * List of OS
+     * List of devices
+     * Other relevant details...
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
-- 
2.7.4

^ permalink raw reply	[relevance 6%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-08 18:02  0%           ` Stephen Hemminger
@ 2017-08-08 18:21  0%             ` Wiles, Keith
  0 siblings, 0 replies; 200+ results
From: Wiles, Keith @ 2017-08-08 18:21 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Yigit, Ferruh, Thomas Monjalon, DPDK, Richardson, Bruce,
	Chilikin, Andrey, Ananyev, Konstantin, Wu, Jingjing


> On Aug 8, 2017, at 1:02 PM, Stephen Hemminger <stephen@networkplumber.org> wrote:
> 
> On Tue, 8 Aug 2017 17:28:19 +0000
> "Wiles, Keith" <keith.wiles@intel.com> wrote:
> 
>> Fix format.
>> 
>>> On Aug 4, 2017, at 6:58 AM, Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>> 
>>> On 8/3/2017 8:53 PM, Thomas Monjalon wrote:  
>>>> 03/08/2017 18:15, Stephen Hemminger:  
>>>>> On Thu, 3 Aug 2017 14:21:38 +0100
>>>>> Bruce Richardson <bruce.richardson@intel.com> wrote:
>>>>> 
>>>>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:  
>>>>>>> To control some device-specific features public device-specific functions
>>>>>>> rte_pmd_*.h are used.
>>>>>>> 
>>>>>>> But this solution requires applications to distinguish devices at runtime
>>>>>>> and, depending on the device type, call corresponding device-specific
>>>>>>> functions even if functions' parameters are the same.
>>>>>>> 
>>>>>>> IOCTL-like API can be added to ethdev instead of public device-specific
>>>>>>> functions to address the following:
>>>>>>> 
>>>>>>> * allow more usable support of features across a range of NIC from
>>>>>>> one vendor, but not others
>>>>>>> * allow features to be implemented by multiple NIC drivers without
>>>>>>> relying on a critical mass to get the functionality in ethdev
>>>>>>> * there are a large number of possible device specific functions, and
>>>>>>> creating individual APIs for each one is not a good solution
>>>>>>> * IOCTLs are a proven method for solving this problem in other areas,
>>>>>>> i.e. OS kernels.
>>>>>>> 
>>>>>>> Control requests for this API will be globally defined at ethdev level, so
>>>>>>> an application will use single API call to control different devices from
>>>>>>> one/multiple vendors.
>>>>>>> 
>>>>>>> API call may look like as a classic ioctl with an extra parameter for
>>>>>>> argument length for better sanity checks:
>>>>>>> 
>>>>>>> int
>>>>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
>>>>>>>       unsigned arg_length);
>>>>>>> 
>>>>>>> Regards,
>>>>>>> Andrey    
>>>>>> 
>>>>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
>>>>>> to admit it, since I dislike IOCTLs and other functions with opaque
>>>>>> arguments! Having driver specific functions I don't think will scale
>>>>>> well as each vendor tries to expose as much of their driver specific
>>>>>> functionality as possible.
>>>>>> 
>>>>>> One other additional example: I discovered just this week another issue
>>>>>> with driver specific functions and testpmd, when I was working on the
>>>>>> meson build rework.
>>>>>> 
>>>>>> * With shared libraries, when we do "ninja install" we want our DPDK
>>>>>> libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
>>>>>> driver folder, so that they can be automatically loaded from that
>>>>>> single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
>>>>>> * However, testpmd, as well as using the drivers as plugins, uses
>>>>>> driver-specific functions, which means that it explicitly links
>>>>>> against the pmd .so files.
>>>>>> * Those driver .so files are not in with the other libraries, so ld.so
>>>>>> does not find the pmd, and the installed testpmd fails to run due to
>>>>>> missing library dependencies.
>>>>>> * The workaround is to add the drivers path to the ld load path, but we
>>>>>> should not require ld library path changes just to get DPDK apps to
>>>>>> work.
>>>>>> 
>>>>>> Using ioctls instead of driver-specific functions would solve this.
>>>>>> 
>>>>>> My 2c.  
>>>>> 
>>>>> My 2c. No.
>>>>> 
>>>>> Short answer:
>>>>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
>>>>> despised by Linux kernel developers. They provide an unstructured, unsecured,
>>>>> back door for device driver abuse. Try to get a new driver in Linux with
>>>>> a unique ioctl, and it will be hard to get accepted.
>>>>> 
>>>>> Long answer:
>>>>> So far every device specific feature has fit into ethdev model. Doing ioctl
>>>>> is admitting "it is too hard to be general, we need need an out". For something
>>>>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
>>>>> For a real feature (think flow direction), we want a first class API for that.
>>>>> For a wart, then devargs will do.
>>>>> 
>>>>> Give a good example of something that should be an ioctl. Don't build the
>>>>> API first and then let it get cluttered.  
>>>> 
>>>> I agree with Stephen.
>>>> 
>>>> And please do not forget that ioctl still requires an API:
>>>> the argument that you put in ioctl is the API of the feature.
>>>> So it is the same thing as defining a new function.  
>>> 
>>> I am also not fan of the ioctl usage. I believe it hides APIs behind ids
>>> and prevent argument check by compiler.
>>> 
>>> BUT, the number of the increasing PMD specific APIs are also worrying,
>>> it is becoming harder to maintain, and I believe this is something NOT
>>> sustainable in long run.
>>> 
>>> 
>>> What about having *eth_dev_extended_ops* ?  
>> 
>> 
>> We had talk about adding something like device specific APIs to DPDK in the past, which to me are just IOCTL like APIs. The big problem with IOCTLs is trying to cram a bunch of specific requests into a very generic API and I do not like ioctl as defined in Linux/Unix today. The old IOCTLs calls are too opaque and difficult for compilers to test args and many other issues.
>> 
>> We talked about having a single API in rte_eth_dev that would allow a user to ask for and possible get a list of function pointers in a given structure for the requested type. If a user calls this API to get some feature from a given NIC he would get NULL or a pointer to a set of functions. The generic API in rte_eth would allow the user to request what structures or types of APIs it supports.
>> 
>> Using a specific API to get the list of APIs or supported features in a NIC, will allow the developer to request the set of APIs (in an array or some method). Then we have real APIs for specific control or requests and not a generic API like ioctl.
>> 
>> Cristian had suggested an API like this to make it easy to add any IOCTL like needs to a driver. We can define a set of structures that seem generic for some IOCTL like needs or just allow the NIC to define his own structures and APIs. Allowing the developer to define his own structures and APIs is not very generic or usable by the users, so I would lean toward defining structures set need today and expand those structures in the future or add more structures.
>> 
>> int rte_eth_dev_something(uint16_t port_id, const char *feature, void **obj);
>> 
>> Using strings we can define or the NIC vendor can define to ask for a pointer to a structure he knows via a driver header. Strings are good, because we can read them via the debug or print them out quickly instead of trying to use some lookup table. Plus we can have any length or characters for defining the structure request.
>> 
>> Just off the top of my head, but it can be changed if needed.
>> 
>> 
>>> 
>>> 
>>> As a part of the rte_eth_dev. This can be in the librte_ether library
>>> but in a separated file.
>>> 
>>> And the APIs for these ops can be less strict on compatibility, and
>>> easier to add.
>>> 
>>> Benefits of having this new dev_ops:
>>> 
>>> * Having an abstraction layer for common checks.
>>> 
>>> * Even feature is not generic for all NICs, still a few NICs can share
>>> the ops.
>>> 
>>> * All APIs are in the same file makes it easy to see PMD specific APIs
>>> comparing to scattered into various PMDs.
>>> 
>>> * This is very like ioctl approach, but APIs are more clear and
>>> arguments can be verified.
>>> 
>>> Thanks,
>>> ferruh
>>> 
>>> 
>>>> 
>>>> The real debate is to decide if we want to continue adding more
>>>> control path features in DPDK or focus on Rx/Tx.
>>>> But this discussion would be better lead with some examples/requests.  
>> 
> 
> The real question is how important is that DPDK is the playground for HW features?
> My impression is that the current process is HW supplier driven "we support offload of XYZZY”.

It is not really a playground as I see it, but defining clean usable solution for vendors and developers to gain access to HW features. Every vendor loves to expose its features and allowing them to create APIs called directly from an application will make it impossible for a generic application and we need to provide some structure to allow the application to determine what features are supported and how they gain access to those features.

> 
> The existing control of device model is already a multi-path mess of config API's, device args,
> and magic scripts. That needs to be addressed first.

Not sure where the ‘magic scripts’ support comes from :-), but I agree we need to clean up the current configuration of devices. I only really see two methods in the work I have done, which are device args strings and configuration from ethdev. The DPDK configuration is another problem in that it sometimes requires a huge command line to startup an application. I think I saw a patch to add better config file support, but it does not address everything IMO. Which BTW was one of the reasons I wrote the dpdk-run.py script to help solve this problem without having to change the current config file/command line interface.

> 
> There is very little community input from users, that is the problem.

I believe I am a user with Pktgen and my usage of DPDK today, but I maybe a bit more of an expert then most users (I hope). I see these usability problems and I try to address them, but we all need to be aware of the usability aspect of DPDK for the casual user.

> 
> IMHO if a new hardware feature can't be made to fit into a standard OS model like Linux
> because it is too hard then adding it to DPDK is a mistake.

I guess I agree, but what is the Linux model anyway and how does that effect FreeBSD or Windows or name your next OS. We need to provide good hardware support for DPDK and I feel it maybe impossible to always define everything in a super clean generic way, this is why IOCTL were created and I think we can define a better solution then IOCTL as in Linux/Unix.


Regards,
Keith


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-08 17:28  0%         ` Wiles, Keith
@ 2017-08-08 18:02  0%           ` Stephen Hemminger
  2017-08-08 18:21  0%             ` Wiles, Keith
  0 siblings, 1 reply; 200+ results
From: Stephen Hemminger @ 2017-08-08 18:02 UTC (permalink / raw)
  To: Wiles, Keith
  Cc: Yigit, Ferruh, Thomas Monjalon, DPDK, Richardson, Bruce,
	Chilikin, Andrey, Ananyev, Konstantin, Wu, Jingjing

On Tue, 8 Aug 2017 17:28:19 +0000
"Wiles, Keith" <keith.wiles@intel.com> wrote:

> Fix format.
> 
> > On Aug 4, 2017, at 6:58 AM, Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> > 
> > On 8/3/2017 8:53 PM, Thomas Monjalon wrote:  
> >> 03/08/2017 18:15, Stephen Hemminger:  
> >>> On Thu, 3 Aug 2017 14:21:38 +0100
> >>> Bruce Richardson <bruce.richardson@intel.com> wrote:
> >>>   
> >>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:  
> >>>>> To control some device-specific features public device-specific functions
> >>>>> rte_pmd_*.h are used.
> >>>>> 
> >>>>> But this solution requires applications to distinguish devices at runtime
> >>>>> and, depending on the device type, call corresponding device-specific
> >>>>> functions even if functions' parameters are the same.
> >>>>> 
> >>>>> IOCTL-like API can be added to ethdev instead of public device-specific
> >>>>> functions to address the following:
> >>>>> 
> >>>>> * allow more usable support of features across a range of NIC from
> >>>>>  one vendor, but not others
> >>>>> * allow features to be implemented by multiple NIC drivers without
> >>>>>  relying on a critical mass to get the functionality in ethdev
> >>>>> * there are a large number of possible device specific functions, and
> >>>>>  creating individual APIs for each one is not a good solution
> >>>>> * IOCTLs are a proven method for solving this problem in other areas,
> >>>>>  i.e. OS kernels.
> >>>>> 
> >>>>> Control requests for this API will be globally defined at ethdev level, so
> >>>>> an application will use single API call to control different devices from
> >>>>> one/multiple vendors.
> >>>>> 
> >>>>> API call may look like as a classic ioctl with an extra parameter for
> >>>>> argument length for better sanity checks:
> >>>>> 
> >>>>> int
> >>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> >>>>>        unsigned arg_length);
> >>>>> 
> >>>>> Regards,
> >>>>> Andrey    
> >>>> 
> >>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
> >>>> to admit it, since I dislike IOCTLs and other functions with opaque
> >>>> arguments! Having driver specific functions I don't think will scale
> >>>> well as each vendor tries to expose as much of their driver specific
> >>>> functionality as possible.
> >>>> 
> >>>> One other additional example: I discovered just this week another issue
> >>>> with driver specific functions and testpmd, when I was working on the
> >>>> meson build rework.
> >>>> 
> >>>> * With shared libraries, when we do "ninja install" we want our DPDK
> >>>>  libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> >>>>  driver folder, so that they can be automatically loaded from that
> >>>>  single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> >>>> * However, testpmd, as well as using the drivers as plugins, uses
> >>>>  driver-specific functions, which means that it explicitly links
> >>>>  against the pmd .so files.
> >>>> * Those driver .so files are not in with the other libraries, so ld.so
> >>>>  does not find the pmd, and the installed testpmd fails to run due to
> >>>>  missing library dependencies.
> >>>> * The workaround is to add the drivers path to the ld load path, but we
> >>>>  should not require ld library path changes just to get DPDK apps to
> >>>>  work.
> >>>> 
> >>>> Using ioctls instead of driver-specific functions would solve this.
> >>>> 
> >>>> My 2c.  
> >>> 
> >>> My 2c. No.
> >>> 
> >>> Short answer:
> >>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> >>> despised by Linux kernel developers. They provide an unstructured, unsecured,
> >>> back door for device driver abuse. Try to get a new driver in Linux with
> >>> a unique ioctl, and it will be hard to get accepted.
> >>> 
> >>> Long answer:
> >>> So far every device specific feature has fit into ethdev model. Doing ioctl
> >>> is admitting "it is too hard to be general, we need need an out". For something
> >>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
> >>> For a real feature (think flow direction), we want a first class API for that.
> >>> For a wart, then devargs will do.
> >>> 
> >>> Give a good example of something that should be an ioctl. Don't build the
> >>> API first and then let it get cluttered.  
> >> 
> >> I agree with Stephen.
> >> 
> >> And please do not forget that ioctl still requires an API:
> >> the argument that you put in ioctl is the API of the feature.
> >> So it is the same thing as defining a new function.  
> > 
> > I am also not fan of the ioctl usage. I believe it hides APIs behind ids
> > and prevent argument check by compiler.
> > 
> > BUT, the number of the increasing PMD specific APIs are also worrying,
> > it is becoming harder to maintain, and I believe this is something NOT
> > sustainable in long run.
> > 
> > 
> > What about having *eth_dev_extended_ops* ?  
> 
> 
> We had talk about adding something like device specific APIs to DPDK in the past, which to me are just IOCTL like APIs. The big problem with IOCTLs is trying to cram a bunch of specific requests into a very generic API and I do not like ioctl as defined in Linux/Unix today. The old IOCTLs calls are too opaque and difficult for compilers to test args and many other issues.
> 
> We talked about having a single API in rte_eth_dev that would allow a user to ask for and possible get a list of function pointers in a given structure for the requested type. If a user calls this API to get some feature from a given NIC he would get NULL or a pointer to a set of functions. The generic API in rte_eth would allow the user to request what structures or types of APIs it supports.
> 
> Using a specific API to get the list of APIs or supported features in a NIC, will allow the developer to request the set of APIs (in an array or some method). Then we have real APIs for specific control or requests and not a generic API like ioctl.
> 
> Cristian had suggested an API like this to make it easy to add any IOCTL like needs to a driver. We can define a set of structures that seem generic for some IOCTL like needs or just allow the NIC to define his own structures and APIs. Allowing the developer to define his own structures and APIs is not very generic or usable by the users, so I would lean toward defining structures set need today and expand those structures in the future or add more structures.
> 
> int rte_eth_dev_something(uint16_t port_id, const char *feature, void **obj);
> 
> Using strings we can define or the NIC vendor can define to ask for a pointer to a structure he knows via a driver header. Strings are good, because we can read them via the debug or print them out quickly instead of trying to use some lookup table. Plus we can have any length or characters for defining the structure request.
> 
> Just off the top of my head, but it can be changed if needed.
> 
> 
> > 
> > 
> > As a part of the rte_eth_dev. This can be in the librte_ether library
> > but in a separated file.
> > 
> > And the APIs for these ops can be less strict on compatibility, and
> > easier to add.
> > 
> > Benefits of having this new dev_ops:
> > 
> > * Having an abstraction layer for common checks.
> > 
> > * Even feature is not generic for all NICs, still a few NICs can share
> > the ops.
> > 
> > * All APIs are in the same file makes it easy to see PMD specific APIs
> > comparing to scattered into various PMDs.
> > 
> > * This is very like ioctl approach, but APIs are more clear and
> > arguments can be verified.
> > 
> > Thanks,
> > ferruh
> > 
> >   
> >> 
> >> The real debate is to decide if we want to continue adding more
> >> control path features in DPDK or focus on Rx/Tx.
> >> But this discussion would be better lead with some examples/requests.  
> 

The real question is how important is that DPDK is the playground for HW features?
My impression is that the current process is HW supplier driven "we support offload of XYZZY".

The existing control of device model is already a multi-path mess of config API's, device args,
and magic scripts. That needs to be addressed first.

There is very little community input from users, that is the problem.

IMHO if a new hardware feature can't be made to fit into a standard OS model like Linux
because it is too hard then adding it to DPDK is a mistake.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 2/2] eventdev: bump library version
  2017-08-08 14:48  3% ` [dpdk-dev] [PATCH 2/2] eventdev: bump library version Jerin Jacob
@ 2017-08-08 17:45  0%   ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08 17:45 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: dev, john.mcnamara

08/08/2017 16:48, Jerin Jacob:
> Bumping the library version to reflect the ABI change, where
> rte_event_pmd_pci_probe(), rte_event_pmd_pci_remove(),
> rte_event_pmd_vdev_init(), rte_event_pmd_vdev_uninit()
> functions removed from the library.
> 
> Fixes: b1b3d9f90502 ("eventdev: make vdev init and uninit functions optional")
> Fixes: 9a8269d56942 ("eventdev: make PCI probe and remove functions optional")
> 
> Reported-by: Thomas Monjalon <thomas.monjalon@6wind.com>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

Series applied, thanks

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-04 11:58  0%       ` Ferruh Yigit
  2017-08-04 12:56  0%         ` Bruce Richardson
  2017-08-08 17:23  2%         ` Wiles, Keith
@ 2017-08-08 17:28  0%         ` Wiles, Keith
  2017-08-08 18:02  0%           ` Stephen Hemminger
  2 siblings, 1 reply; 200+ results
From: Wiles, Keith @ 2017-08-08 17:28 UTC (permalink / raw)
  To: Yigit, Ferruh
  Cc: Thomas Monjalon, DPDK, Stephen Hemminger, Richardson, Bruce,
	Chilikin, Andrey, Ananyev, Konstantin, Wu, Jingjing

Fix format.

> On Aug 4, 2017, at 6:58 AM, Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
> On 8/3/2017 8:53 PM, Thomas Monjalon wrote:
>> 03/08/2017 18:15, Stephen Hemminger:
>>> On Thu, 3 Aug 2017 14:21:38 +0100
>>> Bruce Richardson <bruce.richardson@intel.com> wrote:
>>> 
>>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
>>>>> To control some device-specific features public device-specific functions
>>>>> rte_pmd_*.h are used.
>>>>> 
>>>>> But this solution requires applications to distinguish devices at runtime
>>>>> and, depending on the device type, call corresponding device-specific
>>>>> functions even if functions' parameters are the same.
>>>>> 
>>>>> IOCTL-like API can be added to ethdev instead of public device-specific
>>>>> functions to address the following:
>>>>> 
>>>>> * allow more usable support of features across a range of NIC from
>>>>>  one vendor, but not others
>>>>> * allow features to be implemented by multiple NIC drivers without
>>>>>  relying on a critical mass to get the functionality in ethdev
>>>>> * there are a large number of possible device specific functions, and
>>>>>  creating individual APIs for each one is not a good solution
>>>>> * IOCTLs are a proven method for solving this problem in other areas,
>>>>>  i.e. OS kernels.
>>>>> 
>>>>> Control requests for this API will be globally defined at ethdev level, so
>>>>> an application will use single API call to control different devices from
>>>>> one/multiple vendors.
>>>>> 
>>>>> API call may look like as a classic ioctl with an extra parameter for
>>>>> argument length for better sanity checks:
>>>>> 
>>>>> int
>>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
>>>>>        unsigned arg_length);
>>>>> 
>>>>> Regards,
>>>>> Andrey  
>>>> 
>>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
>>>> to admit it, since I dislike IOCTLs and other functions with opaque
>>>> arguments! Having driver specific functions I don't think will scale
>>>> well as each vendor tries to expose as much of their driver specific
>>>> functionality as possible.
>>>> 
>>>> One other additional example: I discovered just this week another issue
>>>> with driver specific functions and testpmd, when I was working on the
>>>> meson build rework.
>>>> 
>>>> * With shared libraries, when we do "ninja install" we want our DPDK
>>>>  libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
>>>>  driver folder, so that they can be automatically loaded from that
>>>>  single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
>>>> * However, testpmd, as well as using the drivers as plugins, uses
>>>>  driver-specific functions, which means that it explicitly links
>>>>  against the pmd .so files.
>>>> * Those driver .so files are not in with the other libraries, so ld.so
>>>>  does not find the pmd, and the installed testpmd fails to run due to
>>>>  missing library dependencies.
>>>> * The workaround is to add the drivers path to the ld load path, but we
>>>>  should not require ld library path changes just to get DPDK apps to
>>>>  work.
>>>> 
>>>> Using ioctls instead of driver-specific functions would solve this.
>>>> 
>>>> My 2c.
>>> 
>>> My 2c. No.
>>> 
>>> Short answer:
>>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
>>> despised by Linux kernel developers. They provide an unstructured, unsecured,
>>> back door for device driver abuse. Try to get a new driver in Linux with
>>> a unique ioctl, and it will be hard to get accepted.
>>> 
>>> Long answer:
>>> So far every device specific feature has fit into ethdev model. Doing ioctl
>>> is admitting "it is too hard to be general, we need need an out". For something
>>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
>>> For a real feature (think flow direction), we want a first class API for that.
>>> For a wart, then devargs will do.
>>> 
>>> Give a good example of something that should be an ioctl. Don't build the
>>> API first and then let it get cluttered.
>> 
>> I agree with Stephen.
>> 
>> And please do not forget that ioctl still requires an API:
>> the argument that you put in ioctl is the API of the feature.
>> So it is the same thing as defining a new function.
> 
> I am also not fan of the ioctl usage. I believe it hides APIs behind ids
> and prevent argument check by compiler.
> 
> BUT, the number of the increasing PMD specific APIs are also worrying,
> it is becoming harder to maintain, and I believe this is something NOT
> sustainable in long run.
> 
> 
> What about having *eth_dev_extended_ops* ?


We had talk about adding something like device specific APIs to DPDK in the past, which to me are just IOCTL like APIs. The big problem with IOCTLs is trying to cram a bunch of specific requests into a very generic API and I do not like ioctl as defined in Linux/Unix today. The old IOCTLs calls are too opaque and difficult for compilers to test args and many other issues.

We talked about having a single API in rte_eth_dev that would allow a user to ask for and possible get a list of function pointers in a given structure for the requested type. If a user calls this API to get some feature from a given NIC he would get NULL or a pointer to a set of functions. The generic API in rte_eth would allow the user to request what structures or types of APIs it supports.

Using a specific API to get the list of APIs or supported features in a NIC, will allow the developer to request the set of APIs (in an array or some method). Then we have real APIs for specific control or requests and not a generic API like ioctl.

Cristian had suggested an API like this to make it easy to add any IOCTL like needs to a driver. We can define a set of structures that seem generic for some IOCTL like needs or just allow the NIC to define his own structures and APIs. Allowing the developer to define his own structures and APIs is not very generic or usable by the users, so I would lean toward defining structures set need today and expand those structures in the future or add more structures.

int rte_eth_dev_something(uint16_t port_id, const char *feature, void **obj);

Using strings we can define or the NIC vendor can define to ask for a pointer to a structure he knows via a driver header. Strings are good, because we can read them via the debug or print them out quickly instead of trying to use some lookup table. Plus we can have any length or characters for defining the structure request.

Just off the top of my head, but it can be changed if needed.


> 
> 
> As a part of the rte_eth_dev. This can be in the librte_ether library
> but in a separated file.
> 
> And the APIs for these ops can be less strict on compatibility, and
> easier to add.
> 
> Benefits of having this new dev_ops:
> 
> * Having an abstraction layer for common checks.
> 
> * Even feature is not generic for all NICs, still a few NICs can share
> the ops.
> 
> * All APIs are in the same file makes it easy to see PMD specific APIs
> comparing to scattered into various PMDs.
> 
> * This is very like ioctl approach, but APIs are more clear and
> arguments can be verified.
> 
> Thanks,
> ferruh
> 
> 
>> 
>> The real debate is to decide if we want to continue adding more
>> control path features in DPDK or focus on Rx/Tx.
>> But this discussion would be better lead with some examples/requests.

Regards,
Keith

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: notify EAL ABI change
  2017-08-08 14:26  9% [dpdk-dev] [PATCH] doc: notify EAL ABI change Gaetan Rivet
@ 2017-08-08 17:27  4% ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08 17:27 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

08/08/2017 16:26, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  doc/guides/rel_notes/release_17_08.rst | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)

Applied and merged with ABIVER bump, thanks

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] eal: bump ABI version for PCI, bus and devargs work
  2017-08-08 14:26  4% [dpdk-dev] [PATCH] eal: bump ABI version for PCI, bus and devargs work Gaetan Rivet
@ 2017-08-08 17:26  4% ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08 17:26 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

08/08/2017 16:26, Gaetan Rivet:
> 1. PCI domain field in PCI address structure grew from 16 to 32 bits.
> 
>    From: 463ced957c3f ("pci: increase domain storage to 32 bits")
> 
> 2. rte_bus structure gaining new ops.
> 
>    From: 3a8f0bc68a90 ("bus: add method to find device")
>    From: 7c8810f43f6e ("bus: introduce device plug/unplug")
>    From: 609eb7dde6d0 ("bus: introduce parsing functionality")
>    From: 98eb4b845c1a ("bus: introduce scan policies")
> 
> 3. rte_devargs structure having been mostly rewritten.
> 
>    From: f3a1188cee4a ("devargs: make device representation generic")
>    From: 47828c5f3bc3 ("devargs: parse bus info")
>    From: 39f403e0d5bb ("devargs: restore device type API")
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Applied and merged with release notes update, thanks

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-04 11:58  0%       ` Ferruh Yigit
  2017-08-04 12:56  0%         ` Bruce Richardson
@ 2017-08-08 17:23  2%         ` Wiles, Keith
  2017-08-08 17:28  0%         ` Wiles, Keith
  2 siblings, 0 replies; 200+ results
From: Wiles, Keith @ 2017-08-08 17:23 UTC (permalink / raw)
  To: Yigit, Ferruh
  Cc: Thomas Monjalon, dev, Stephen Hemminger, Richardson, Bruce,
	Chilikin, Andrey, Ananyev, Konstantin, Wu, Jingjing


On Aug 4, 2017, at 6:58 AM, Ferruh Yigit <ferruh.yigit@intel.com<mailto:ferruh.yigit@intel.com>> wrote:

On 8/3/2017 8:53 PM, Thomas Monjalon wrote:
03/08/2017 18:15, Stephen Hemminger:
On Thu, 3 Aug 2017 14:21:38 +0100
Bruce Richardson <bruce.richardson@intel.com<mailto:bruce.richardson@intel.com>> wrote:

On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
To control some device-specific features public device-specific functions
rte_pmd_*.h are used.

But this solution requires applications to distinguish devices at runtime
and, depending on the device type, call corresponding device-specific
functions even if functions' parameters are the same.

IOCTL-like API can be added to ethdev instead of public device-specific
functions to address the following:

* allow more usable support of features across a range of NIC from
 one vendor, but not others
* allow features to be implemented by multiple NIC drivers without
 relying on a critical mass to get the functionality in ethdev
* there are a large number of possible device specific functions, and
 creating individual APIs for each one is not a good solution
* IOCTLs are a proven method for solving this problem in other areas,
 i.e. OS kernels.

Control requests for this API will be globally defined at ethdev level, so
an application will use single API call to control different devices from
one/multiple vendors.

API call may look like as a classic ioctl with an extra parameter for
argument length for better sanity checks:

int
rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
       unsigned arg_length);

Regards,
Andrey

I think we need to start putting in IOCTLs for ethdevs, much as I hate
to admit it, since I dislike IOCTLs and other functions with opaque
arguments! Having driver specific functions I don't think will scale
well as each vendor tries to expose as much of their driver specific
functionality as possible.

One other additional example: I discovered just this week another issue
with driver specific functions and testpmd, when I was working on the
meson build rework.

* With shared libraries, when we do "ninja install" we want our DPDK
 libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
 driver folder, so that they can be automatically loaded from that
 single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
* However, testpmd, as well as using the drivers as plugins, uses
 driver-specific functions, which means that it explicitly links
 against the pmd .so files.
* Those driver .so files are not in with the other libraries, so ld.so
 does not find the pmd, and the installed testpmd fails to run due to
 missing library dependencies.
* The workaround is to add the drivers path to the ld load path, but we
 should not require ld library path changes just to get DPDK apps to
 work.

Using ioctls instead of driver-specific functions would solve this.

My 2c.

My 2c. No.

Short answer:
Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
despised by Linux kernel developers. They provide an unstructured, unsecured,
back door for device driver abuse. Try to get a new driver in Linux with
a unique ioctl, and it will be hard to get accepted.

Long answer:
So far every device specific feature has fit into ethdev model. Doing ioctl
is admitting "it is too hard to be general, we need need an out". For something
that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
For a real feature (think flow direction), we want a first class API for that.
For a wart, then devargs will do.

Give a good example of something that should be an ioctl. Don't build the
API first and then let it get cluttered.

I agree with Stephen.

And please do not forget that ioctl still requires an API:
the argument that you put in ioctl is the API of the feature.
So it is the same thing as defining a new function.

I am also not fan of the ioctl usage. I believe it hides APIs behind ids
and prevent argument check by compiler.

BUT, the number of the increasing PMD specific APIs are also worrying,
it is becoming harder to maintain, and I believe this is something NOT
sustainable in long run.


What about having *eth_dev_extended_ops* ?

We had talk about adding something like device specific APIs to DPDK in the past, which to me are just IOCTL like APIs. The big problem with IOCTLs is trying to cram a bunch of specific requests into a very generic API and I do not like ioctl as defined in Linux/Unix today. The old IOCTLs calls are too opaque and difficult for compilers to test args and many other issues.

We talked about having a single API in rte_eth_dev that would allow a user to ask for and possible get a list of function pointers in a given structure for the requested type. If a user calls this API to get some feature from a given NIC he would get NULL or a pointer to a set of functions. The generic API in rte_eth would allow the user to request what structures or types of APIs it supports.

Using a specific API to get the list of APIs or supported features in a NIC, will allow the developer to request the set of APIs (in an array or some method). Then we have real APIs for specific control or requests and not a generic API like ioctl.

Cristian had suggested an API like this to make it easy to add any IOCTL like needs to a driver. We can define a set of structures that seem generic for some IOCTL like needs or just allow the NIC to define his own structures and APIs. Allowing the developer to define his own structures and APIs is not very generic or usable by the users, so I would lean toward defining structures set need today and expand those structures in the future or add more structures.

int rte_eth_dev_something(uint16_t port_id, const char *feature, void **obj);

Using strings we can define or the NIC vendor can define to ask for a pointer to a structure he knows via a driver header. Strings are good, because we can read them via the debug or print them out quickly instead of trying to use some lookup table. Plus we can have any length or characters for defining the structure request.

Just off the top of my head, but it can be changed if needed.




As a part of the rte_eth_dev. This can be in the librte_ether library
but in a separated file.

And the APIs for these ops can be less strict on compatibility, and
easier to add.

Benefits of having this new dev_ops:

* Having an abstraction layer for common checks.

* Even feature is not generic for all NICs, still a few NICs can share
the ops.

* All APIs are in the same file makes it easy to see PMD specific APIs
comparing to scattered into various PMDs.

* This is very like ioctl approach, but APIs are more clear and
arguments can be verified.

Thanks,
ferruh



The real debate is to decide if we want to continue adding more
control path features in DPDK or focus on Rx/Tx.
But this discussion would be better lead with some examples/requests.

Regards,
Keith

^ permalink raw reply	[relevance 2%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-08  8:32  0%           ` Ferruh Yigit
@ 2017-08-08 15:27  3%             ` Stephen Hemminger
  0 siblings, 0 replies; 200+ results
From: Stephen Hemminger @ 2017-08-08 15:27 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Bruce Richardson, Thomas Monjalon, dev, Chilikin, Andrey,
	Ananyev, Konstantin, Wu, Jingjing

On Tue, 8 Aug 2017 09:32:07 +0100
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 8/4/2017 1:56 PM, Bruce Richardson wrote:
> > On Fri, Aug 04, 2017 at 12:58:01PM +0100, Ferruh Yigit wrote:  
> >> On 8/3/2017 8:53 PM, Thomas Monjalon wrote:  
> >>> 03/08/2017 18:15, Stephen Hemminger:  
> >>>> On Thu, 3 Aug 2017 14:21:38 +0100
> >>>> Bruce Richardson <bruce.richardson@intel.com> wrote:
> >>>>  
> >>>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:  
> >>>>>> To control some device-specific features public device-specific functions
> >>>>>> rte_pmd_*.h are used.
> >>>>>>
> >>>>>> But this solution requires applications to distinguish devices at runtime
> >>>>>> and, depending on the device type, call corresponding device-specific
> >>>>>> functions even if functions' parameters are the same.
> >>>>>>
> >>>>>> IOCTL-like API can be added to ethdev instead of public device-specific
> >>>>>> functions to address the following:
> >>>>>>
> >>>>>> * allow more usable support of features across a range of NIC from
> >>>>>>   one vendor, but not others
> >>>>>> * allow features to be implemented by multiple NIC drivers without
> >>>>>>   relying on a critical mass to get the functionality in ethdev
> >>>>>> * there are a large number of possible device specific functions, and
> >>>>>>   creating individual APIs for each one is not a good solution
> >>>>>> * IOCTLs are a proven method for solving this problem in other areas,
> >>>>>>   i.e. OS kernels.
> >>>>>>
> >>>>>> Control requests for this API will be globally defined at ethdev level, so
> >>>>>> an application will use single API call to control different devices from
> >>>>>> one/multiple vendors.
> >>>>>>
> >>>>>> API call may look like as a classic ioctl with an extra parameter for
> >>>>>> argument length for better sanity checks:
> >>>>>>
> >>>>>> int
> >>>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> >>>>>>         unsigned arg_length);
> >>>>>>
> >>>>>> Regards,
> >>>>>> Andrey    
> >>>>>
> >>>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
> >>>>> to admit it, since I dislike IOCTLs and other functions with opaque
> >>>>> arguments! Having driver specific functions I don't think will scale
> >>>>> well as each vendor tries to expose as much of their driver specific
> >>>>> functionality as possible.
> >>>>>
> >>>>> One other additional example: I discovered just this week another issue
> >>>>> with driver specific functions and testpmd, when I was working on the
> >>>>> meson build rework.
> >>>>>
> >>>>> * With shared libraries, when we do "ninja install" we want our DPDK
> >>>>>   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> >>>>>   driver folder, so that they can be automatically loaded from that
> >>>>>   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> >>>>> * However, testpmd, as well as using the drivers as plugins, uses
> >>>>>   driver-specific functions, which means that it explicitly links
> >>>>>   against the pmd .so files.
> >>>>> * Those driver .so files are not in with the other libraries, so ld.so
> >>>>>   does not find the pmd, and the installed testpmd fails to run due to
> >>>>>   missing library dependencies.
> >>>>> * The workaround is to add the drivers path to the ld load path, but we
> >>>>>   should not require ld library path changes just to get DPDK apps to
> >>>>>   work.
> >>>>>
> >>>>> Using ioctls instead of driver-specific functions would solve this.
> >>>>>
> >>>>> My 2c.  
> >>>>
> >>>> My 2c. No.
> >>>>
> >>>> Short answer:
> >>>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> >>>> despised by Linux kernel developers. They provide an unstructured, unsecured,
> >>>> back door for device driver abuse. Try to get a new driver in Linux with
> >>>> a unique ioctl, and it will be hard to get accepted.
> >>>>
> >>>> Long answer:
> >>>> So far every device specific feature has fit into ethdev model. Doing ioctl
> >>>> is admitting "it is too hard to be general, we need need an out". For something
> >>>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
> >>>> For a real feature (think flow direction), we want a first class API for that.
> >>>> For a wart, then devargs will do.
> >>>>
> >>>> Give a good example of something that should be an ioctl. Don't build the
> >>>> API first and then let it get cluttered.  
> >>>
> >>> I agree with Stephen.
> >>>
> >>> And please do not forget that ioctl still requires an API:
> >>> the argument that you put in ioctl is the API of the feature.
> >>> So it is the same thing as defining a new function.  
> >>
> >> I am also not fan of the ioctl usage. I believe it hides APIs behind ids
> >> and prevent argument check by compiler.
> >>
> >> BUT, the number of the increasing PMD specific APIs are also worrying,
> >> it is becoming harder to maintain, and I believe this is something NOT
> >> sustainable in long run.
> >>
> >>
> >> What about having *eth_dev_extended_ops* ?
> >>
> >>
> >> As a part of the rte_eth_dev. This can be in the librte_ether library
> >> but in a separated file.
> >>
> >> And the APIs for these ops can be less strict on compatibility, and
> >> easier to add.
> >>
> >> Benefits of having this new dev_ops:
> >>
> >> * Having an abstraction layer for common checks.
> >>
> >> * Even feature is not generic for all NICs, still a few NICs can share
> >> the ops.
> >>
> >> * All APIs are in the same file makes it easy to see PMD specific APIs
> >> comparing to scattered into various PMDs.
> >>
> >> * This is very like ioctl approach, but APIs are more clear and
> >> arguments can be verified.
> >>  
> > 
> > Sounds like an ethdev-staging library, where features can be put until
> > such time as they get critical mass for acceptance and promoted to
> > ethdev? It's sounds better than IOCTL, while giving the same benefits.
> > 
> > I'd be happy enough with any solution that allows NIC features to be
> > exposed that does not have functions limited to each individual driver,
> > so that common functionality can be exposed to apps via an API even if
> > only 2 drivers support it.  
> 
> This is not decided yet, but to enable working on this for next release,
> is a deprecation notice required to add a new field to "struct
> rte_eth_dev" ?
> 
> "struct rte_eth_dev" is marked as "@internal", so I believe deprecation
> notice is NOT required, but I would like to confirm.

Increasing the size of a structure used by API calls
will break ABI since the new version
of DPDK will read garbage off the end of the caller's input.
The problem could have been avoided if original DPDK API's had
used configuration structure and size of that struct.

Only structures allocated and only used internally could change.
It looks like rte_eth_dev is safe.

^ permalink raw reply	[relevance 3%]

* [dpdk-dev]  [PATCH 2/2] eventdev: bump library version
  @ 2017-08-08 14:48  3% ` Jerin Jacob
  2017-08-08 17:45  0%   ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Jerin Jacob @ 2017-08-08 14:48 UTC (permalink / raw)
  To: dev; +Cc: thomas, john.mcnamara, Jerin Jacob

Bumping the library version to reflect the ABI change, where
rte_event_pmd_pci_probe(), rte_event_pmd_pci_remove(),
rte_event_pmd_vdev_init(), rte_event_pmd_vdev_uninit()
functions removed from the library.

Fixes: b1b3d9f90502 ("eventdev: make vdev init and uninit functions optional")
Fixes: 9a8269d56942 ("eventdev: make PCI probe and remove functions optional")

Reported-by: Thomas Monjalon <thomas.monjalon@6wind.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 doc/guides/rel_notes/release_17_08.rst | 1 +
 lib/librte_eventdev/Makefile           | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index a137aa79f..1c2bc6de9 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -370,6 +370,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_distributor.so.1
      librte_eal.so.4
    + librte_ethdev.so.7
+   + librte_eventdev.so.2
    + librte_gro.so.1
      librte_hash.so.2
      librte_ip_frag.so.1
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 64165020a..410578a14 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -34,7 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_eventdev.a
 
 # library version
-LIBABIVER := 1
+LIBABIVER := 2
 
 # build flags
 CFLAGS += -O3
-- 
2.14.0

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH] doc: notify EAL ABI change
@ 2017-08-08 14:26  9% Gaetan Rivet
  2017-08-08 17:27  4% ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Gaetan Rivet @ 2017-08-08 14:26 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 doc/guides/rel_notes/release_17_08.rst | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index a137aa7..a723252 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -343,6 +343,14 @@ ABI Changes
 
 * Removed ``session_mp`` from ``rte_cryptodev_config``.
 
+* Changed type of ``domain`` field in ``rte_pci_addr`` to ``uint32_t``
+  to follow the PCI standard.
+
+* Added new ``rte_bus`` experimental APIs available as operators within the
+  ``rte_bus`` structure.
+
+* Made ``rte_devargs`` structure internal device representation generic to
+  prepare for a bus-agnostic EAL.
 
 Shared Library Versions
 -----------------------
@@ -368,7 +376,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_cmdline.so.2
    + librte_cryptodev.so.3
      librte_distributor.so.1
-     librte_eal.so.4
+   + librte_eal.so.5
    + librte_ethdev.so.7
    + librte_gro.so.1
      librte_hash.so.2
-- 
2.1.4

^ permalink raw reply	[relevance 9%]

* [dpdk-dev] [PATCH] eal: bump ABI version for PCI, bus and devargs work
@ 2017-08-08 14:26  4% Gaetan Rivet
  2017-08-08 17:26  4% ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Gaetan Rivet @ 2017-08-08 14:26 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

1. PCI domain field in PCI address structure grew from 16 to 32 bits.

   From: 463ced957c3f ("pci: increase domain storage to 32 bits")

2. rte_bus structure gaining new ops.

   From: 3a8f0bc68a90 ("bus: add method to find device")
   From: 7c8810f43f6e ("bus: introduce device plug/unplug")
   From: 609eb7dde6d0 ("bus: introduce parsing functionality")
   From: 98eb4b845c1a ("bus: introduce scan policies")

3. rte_devargs structure having been mostly rewritten.

   From: f3a1188cee4a ("devargs: make device representation generic")
   From: 47828c5f3bc3 ("devargs: parse bus info")
   From: 39f403e0d5bb ("devargs: restore device type API")

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile   | 2 +-
 lib/librte_eal/linuxapp/eal/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 05517a2..005019e 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,7 +48,7 @@ LDLIBS += -lgcc_s
 
 EXPORT_MAP := rte_eal_version.map
 
-LIBABIVER := 4
+LIBABIVER := 5
 
 # specific to bsdapp exec-env
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) := eal.c
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index e6ab6c3..90bca4d 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -37,7 +37,7 @@ ARCH_DIR ?= $(RTE_ARCH)
 EXPORT_MAP := rte_eal_version.map
 VPATH += $(RTE_SDK)/lib/librte_eal/common/arch/$(ARCH_DIR)
 
-LIBABIVER := 4
+LIBABIVER := 5
 
 VPATH += $(RTE_SDK)/lib/librte_eal/common
 
-- 
2.1.4

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset()
  2017-08-08 11:03  4%   ` Christian Ehrhardt
@ 2017-08-08 13:13  3%     ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08 13:13 UTC (permalink / raw)
  To: Christian Ehrhardt, David Harton; +Cc: Van Haaren, Harry, dev

08/08/2017 13:03, Christian Ehrhardt:
> On Tue, Aug 8, 2017 at 11:02 AM, Van Haaren, Harry <
> harry.van.haaren@intel.com> wrote:
> > >
> > > Some devices do not support reset of eth stats.  An application may
> > > need to know not to clear shadow stats if the device cannot.
> > >
> > > rte_eth_stats_reset is updated to provide a return code to share
> > > whether the device supports reset or not.
> > >
> > > Signed-off-by: David Harton <dharton@cisco.com>
> > > ---
> >
> > Hi,
> >
> > As far as I know changing the return type (void to int) of a function does
> > *not* break ABI, but does "break" API as the application code should now
> > check the return value. In theory the application could ignore the return
> > value and current behavior is maintained.
> >
> 
> After discussing with Harry on IRC it turns out we both ended up checking
> the same online sources
> to verify our thoughts, like [1].
> 
> Given this and several other sources it seems to be as outlined above an
> API but not ABI break.
> I'm not an expert and this is mostly opinion, but my personal rule mostly
> is: "if in doubt bump it".

Anyway, the ABI will be broken (and bumped) again in 17.11.
This patch will be accepted in 17.11.

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v1] doc: add template release notes for 17.11
@ 2017-08-08 12:31  6% John McNamara
  2017-08-09  8:22  6% ` [dpdk-dev] [PATCH v2] " John McNamara
  0 siblings, 1 reply; 200+ results
From: John McNamara @ 2017-08-08 12:31 UTC (permalink / raw)
  To: dev; +Cc: John McNamara

Add template release notes for DPDK 17.11 with inline
comments and explanations of the various sections.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/rel_notes/index.rst         |   1 +
 doc/guides/rel_notes/release_17_11.rst | 199 +++++++++++++++++++++++++++++++++
 2 files changed, 200 insertions(+)
 create mode 100644 doc/guides/rel_notes/release_17_11.rst

diff --git a/doc/guides/rel_notes/index.rst b/doc/guides/rel_notes/index.rst
index b3c8090..35659d8 100644
--- a/doc/guides/rel_notes/index.rst
+++ b/doc/guides/rel_notes/index.rst
@@ -36,6 +36,7 @@ Release Notes
     :numbered:
 
     rel_description
+    release_17_11
     release_17_08
     release_17_05
     release_17_02
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
new file mode 100644
index 0000000..6e5768f
--- /dev/null
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -0,0 +1,199 @@
+DPDK Release 17.11
+==================
+
+.. **Read this first.**
+
+   The text in the sections below explains how to update the release notes.
+
+   Use proper spelling, capitalization and punctuation in all sections.
+
+   Variable and config names should be quoted as fixed width text:
+   ``LIKE_THIS``.
+
+   Build the docs and view the output file to ensure the changes are correct::
+
+      make doc-guides-html
+
+      xdg-open build/doc/html/guides/rel_notes/release_17_11.html
+
+
+New Features
+------------
+
+.. This section should contain new features added in this release. Sample
+   format:
+
+   * **Add a title in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description in the past tense. The description
+     should be enough to allow someone scanning the release notes to
+     understand the new feature.
+
+     If the feature adds a lot of sub-features you can use a bullet list like
+     this:
+
+     * Added feature foo to do something.
+     * Enhanced feature bar to do something else.
+
+     Refer to the previous release notes for examples.
+
+     This section is a comment. do not overwrite or remove it.
+     Also, make sure to start the actual text at the margin.
+     =========================================================
+
+
+Resolved Issues
+---------------
+
+.. This section should contain bug fixes added to the relevant
+   sections. Sample format:
+
+   * **code/section Fixed issue in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description of the resolved issue in the past
+     tense.
+
+     The title should contain the code/lib section like a commit message.
+
+     Add the entries in alphabetic order in the relevant sections below.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+EAL
+~~~
+
+
+Drivers
+~~~~~~~
+
+
+Libraries
+~~~~~~~~~
+
+
+Examples
+~~~~~~~~
+
+
+Other
+~~~~~
+
+
+Known Issues
+------------
+
+.. This section should contain new known issues in this release. Sample format:
+
+   * **Add title in present tense with full stop.**
+
+     Add a short 1-2 sentence description of the known issue in the present
+     tense. Add information on any known workarounds.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+API Changes
+-----------
+
+.. This section should contain API changes. Sample format:
+
+   * Add a short 1-2 sentence description of the API change. Use fixed width
+     quotes for ``rte_function_names`` or ``rte_struct_names``. Use the past
+     tense.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+ABI Changes
+-----------
+
+.. This section should contain ABI changes. Sample format:
+
+   * Add a short 1-2 sentence description of the ABI change that was announced
+     in the previous releases and made in this release. Use fixed width quotes
+     for ``rte_function_names`` or ``rte_struct_names``. Use the past tense.
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+
+Shared Library Versions
+-----------------------
+
+.. Update any library version updated in this release and prepend with a ``+``
+   sign, like this:
+
+     librte_acl.so.2
+   + librte_cfgfile.so.2
+     librte_cmdline.so.2
+
+   This section is a comment. do not overwrite or remove it.
+   =========================================================
+
+
+The libraries prepended with a plus sign were incremented in this version.
+
+.. code-block:: diff
+
+     librte_acl.so.2
+     librte_bitratestats.so.1
+     librte_cfgfile.so.2
+     librte_cmdline.so.2
+     librte_cryptodev.so.3
+     librte_distributor.so.1
+     librte_eal.so.4
+     librte_ethdev.so.7
+     librte_gro.so.1
+     librte_hash.so.2
+     librte_ip_frag.so.1
+     librte_jobstats.so.1
+     librte_kni.so.2
+     librte_kvargs.so.1
+     librte_latencystats.so.1
+     librte_lpm.so.2
+     librte_mbuf.so.3
+     librte_mempool.so.2
+     librte_meter.so.1
+     librte_metrics.so.1
+     librte_net.so.1
+     librte_pdump.so.1
+     librte_pipeline.so.3
+     librte_pmd_bond.so.1
+     librte_pmd_ring.so.2
+     librte_port.so.3
+     librte_power.so.1
+     librte_reorder.so.1
+     librte_ring.so.1
+     librte_sched.so.1
+     librte_table.so.2
+     librte_timer.so.1
+     librte_vhost.so.3
+
+
+Tested Platforms
+----------------
+
+.. This section should contain a list of platforms that were tested with this
+   release.
+
+   The format is:
+
+   * <vendor> platform with <vendor> <type of devices> combinations
+
+     * List of CPU
+     * List of OS
+     * List of devices
+     * Other relevant details...
+
+   This section is a comment. do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
-- 
2.7.4

^ permalink raw reply	[relevance 6%]

* Re: [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset()
  2017-08-08  9:02  5% ` Van Haaren, Harry
  2017-08-08 11:01  0%   ` David Harton (dharton)
@ 2017-08-08 11:03  4%   ` Christian Ehrhardt
  2017-08-08 13:13  3%     ` Thomas Monjalon
  1 sibling, 1 reply; 200+ results
From: Christian Ehrhardt @ 2017-08-08 11:03 UTC (permalink / raw)
  To: Van Haaren, Harry; +Cc: David Harton, thomas, dev

On Tue, Aug 8, 2017 at 11:02 AM, Van Haaren, Harry <
harry.van.haaren@intel.com> wrote:

> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of David Harton
> > Sent: Monday, August 7, 2017 6:39 PM
> > To: thomas@monjalon.net
> > Cc: dev@dpdk.org; David Harton <dharton@cisco.com>
> > Subject: [dpdk-dev] [PATCH v3] ethdev: add return code to
> rte_eth_stats_reset()
> >
> > Some devices do not support reset of eth stats.  An application may
> > need to know not to clear shadow stats if the device cannot.
> >
> > rte_eth_stats_reset is updated to provide a return code to share
> > whether the device supports reset or not.
> >
> > Signed-off-by: David Harton <dharton@cisco.com>
> > ---
>
> Hi,
>
> As far as I know changing the return type (void to int) of a function does
> *not* break ABI, but does "break" API as the application code should now
> check the return value. In theory the application could ignore the return
> value and current behavior is maintained.
>

After discussing with Harry on IRC it turns out we both ended up checking
the same online sources
to verify our thoughts, like [1].

Given this and several other sources it seems to be as outlined above an
API but not ABI break.
I'm not an expert and this is mostly opinion, but my personal rule mostly
is: "if in doubt bump it".
Running similar issues I was the one providing [2] for a reason, with this
here being a case that
appears safe but there eventually always seems to come up an architecture
or alternative compiler
which does some arcane register juggling differently and makes those "safe"
changes breaking people after the fact.

[1]:
https://stackoverflow.com/questions/15626579/c-abi-is-it-safe-to-change-void-function-to-return-int
[2]:
http://dpdk.org/doc/guides/contributing/versioning.html#setting-a-major-abi-version

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset()
  2017-08-08  9:02  5% ` Van Haaren, Harry
@ 2017-08-08 11:01  0%   ` David Harton (dharton)
  2017-08-08 11:03  4%   ` Christian Ehrhardt
  1 sibling, 0 replies; 200+ results
From: David Harton (dharton) @ 2017-08-08 11:01 UTC (permalink / raw)
  To: Van Haaren, Harry, thomas; +Cc: dev

> -----Original Message-----
> From: Van Haaren, Harry [mailto:harry.van.haaren@intel.com]
> Sent: Tuesday, August 08, 2017 5:03 AM
> To: David Harton (dharton) <dharton@cisco.com>; thomas@monjalon.net
> Cc: dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v3] ethdev: add return code to
> rte_eth_stats_reset()
> 
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of David Harton
> > Sent: Monday, August 7, 2017 6:39 PM
> > To: thomas@monjalon.net
> > Cc: dev@dpdk.org; David Harton <dharton@cisco.com>
> > Subject: [dpdk-dev] [PATCH v3] ethdev: add return code to
> > rte_eth_stats_reset()
> >
> > Some devices do not support reset of eth stats.  An application may
> > need to know not to clear shadow stats if the device cannot.
> >
> > rte_eth_stats_reset is updated to provide a return code to share
> > whether the device supports reset or not.
> >
> > Signed-off-by: David Harton <dharton@cisco.com>
> > ---
> 
> Hi,
> 
> As far as I know changing the return type (void to int) of a function does
> *not* break ABI, but does "break" API as the application code should now
> check the return value. In theory the application could ignore the return
> value and current behavior is maintained.
> 
> The validate-abi.sh script says "Compatible" with the following item
> flagged:
> 
> Problems with Symbols
> High 0
> Medium 0
> Low	1
> 
> Change>> Type of return value has been changed from void to int (4 bytes).
> Effect>> Replacement of return type may indicate a change in its semantic
> meaning.
> 
> Perhaps somebody with more ABI expertise than I would double check the
> return value change?
> 
> 
> Some smaller things inline below.
> 
> > v3:
> > * overcame noob errors and figured out patch challenges
> > * this release should finally be clean :)
> >
> > v2:
> > * fixed soft tab issue inserted while moving changes
> >
> >  lib/librte_ether/rte_ethdev.c | 8 +++++---
> > lib/librte_ether/rte_ethdev.h | 4 +++-
> >  2 files changed, 8 insertions(+), 4 deletions(-)
> >
> > diff --git a/lib/librte_ether/rte_ethdev.c
> > b/lib/librte_ether/rte_ethdev.c index 0597641..f72cc5a 100644
> > --- a/lib/librte_ether/rte_ethdev.c
> > +++ b/lib/librte_ether/rte_ethdev.c
> > @@ -1341,17 +1341,19 @@ rte_eth_stats_get(uint8_t port_id, struct
> rte_eth_stats *stats)
> >  	return 0;
> >  }
> >
> > -void
> > +int
> >  rte_eth_stats_reset(uint8_t port_id)
> >  {
> >  	struct rte_eth_dev *dev;
> >
> > -	RTE_ETH_VALID_PORTID_OR_RET(port_id);
> > +	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
> >  	dev = &rte_eth_devices[port_id];
> >
> > -	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->stats_reset);
> > +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->stats_reset, -ENOTSUP);
> >  	(*dev->dev_ops->stats_reset)(dev);
> >  	dev->data->rx_mbuf_alloc_failed = 0;
> > +
> > +	return 0;
> >  }
> >
> >  static int
> > diff --git a/lib/librte_ether/rte_ethdev.h
> > b/lib/librte_ether/rte_ethdev.h index 0adf327..d8ccd60 100644
> > --- a/lib/librte_ether/rte_ethdev.h
> > +++ b/lib/librte_ether/rte_ethdev.h
> > @@ -2246,8 +2246,10 @@ int rte_eth_stats_get(uint8_t port_id, struct
> > rte_eth_stats *stats);
> >   *
> >   * @param port_id
> >   *   The port identifier of the Ethernet device.
> > + * @return
> > + *   Zero if successful. Non-zero otherwise.
> 
> We should document all return values:
> 
> @retval 0 Success
> @retval -EINVAL Invalid port_id provided @retval -ENOTSUP Stats reset
> functionality not supported by PMD

Sure.  I was following the convention of function above it
rte_eth_stats_get() but I agree better to advertise externally.
I'll also modify the port number check errval to -ENODEV.

> 
> The API change itself should probably be added to release notes, as
> applications may wish to be aware this function has changed.

Sounds good.

> 
> >   */
> > -void rte_eth_stats_reset(uint8_t port_id);
> > +int rte_eth_stats_reset(uint8_t port_id);
> >
> >  /**
> >   * Retrieve names of extended statistics of an Ethernet device.
> > --
> > 2.10.3.dirty
> 
> 
> I'm happy to Ack the code/release-notes with above suggestions, but I'd
> like a second opinion to Ack ABI.

Thanks for the review,
Dave

> 
> -Harry

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3] doc: announce API and ABI change for ethdev
  2017-08-08  4:02  4%     ` Yang, Zhiyong
@ 2017-08-08  9:35  4%       ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08  9:35 UTC (permalink / raw)
  To: Yang, Zhiyong
  Cc: dev, Tan, Jianfeng, yliu, jerin.jacob, Horton, Remy, shahafs

> > This is an API/ABI change notice for DPDK 17.11 announcing the redefinition of
> > port_id. port_id is currently defined as uint8_t, which is limited to the range 0 to
> > 255. A larger range is required for vdev scalability.
> > 
> > It is necessary for a redefinition of port_id to extend it from 1 bytes to
> > 2 bytes. All ethdev APIs and usages related to port_id will be changed at the
> > same time.
> > 
> > cc: jianfeng.tan@intel.com
> > cc: yliu@fridaylinux.org
> > cc: jerin.jacob@caviumnetworks.com
> > cc: thomas@monjalon.net
> > cc: remy.horton@intel.com
> > 
> > Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
> > Acked-by: Jianfeng Tan <jianfeng.tan@intel.com>
> > Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
> > Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > Acked-by: Remy Horton <remy.horton@intel.com>
> 
> This ack in v2 is added in v3. Thanks, Shahaf.
> 
> Acked-by: Shahaf Shuler <shahafs@mellanox.com>

Applied, thanks

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-08  5:03  4%       ` Shahaf Shuler
@ 2017-08-08 10:00  4%         ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08 10:00 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, Shahaf Shuler, Boris Pismenny, Hemant Agrawal,
	declan.doherty, radu.nicolau, Aviad Yehezkel,
	pablo.de.lara.guarch, techboard

08/08/2017 07:03, Shahaf Shuler:
> Monday, August 7, 2017 9:07 PM, Boris Pismenny:
> > > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > 04/08/2017 07:26, Hemant Agrawal:
> > > > On 8/3/2017 9:02 PM, Akhil Goyal wrote:
> > > > > Support for security operations is planned to be added in ethdev
> > > > > and cryptodev for the 17.11 release.
> > > > >
> > > > > For this following changes are required.
> > > > > - rte_cryptodev and rte_eth_dev structures need to be added new
> > > > > parameter rte_security_ops which extend support for security ops
> > > > > to the corresponding driver.
> > > > > - rte_cryptodev_info and rte_ethd_dev_info need to be added with
> > > > > rte_security_capabilities to identify the capabilities of the
> > > > > corresponding driver.
> > >
> > > It is not explained what is the fundamental difference between
> > > rte_security and rte_crypto?
> > > It looks to be just a technical workaround.
> > 
> > rte_security is a layer between crypto and NIC.
> > 
> > Today crypto sessions are created exclusively against crypto devices, but
> > they don't use network related fields, while the network namespace doesn't
> > use crypto related fields. We expect this API to represent crypto sessions
> > that combine network fields and allow to add/delete them for all devices.
> > 
> > For NICs we will use rte_flow with rte_security for inline/full crypto protocol
> > offload such as ESP.
> > 
> > >
> > > Why the ABI would be changed by rte_security additions?
> > >
> > > > > Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> > > > >
> > > > Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> > >
> > > No more opinions outside of NXP?
> > > It seems there is not yet a consensus on how to manage IPsec offloading.
> > > I heard there were some phone calls about these stuff but nothing
> > > clear appears publicly on the mailing list.
> > > Looks to be a community failure.
> > 
> > We agreed to go ahead with this approach on one such phone call. I hope we
> > could use the dpdk github for development.
> > 
> > Acked-by: Boris Pismenny <borisp@mellanox.com>
> 
> Acked-by: Shahaf Shuler <shahafs@mellanox.com>

Applied
It means you have a chance to do this change in 17.11.
It does not mean you can be sure that the patches will be accepted.

This is introducing a new complexity.
It must be discussed with the technical board before approving
the final design in 17.11.

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] ethdev: add notice for planned name size change
  2017-08-08  4:56  0%   ` Shahaf Shuler
@ 2017-08-08  9:47  0%     ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08  9:47 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, Shahaf Shuler, Yongseok Koh

> > > VMBUS support will use GUID in eth_dev_data name field which requires
> > > at least 37 characters. Plan for increase in size now.
> > >
> > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > > ---
> > > +* ethdev: An ABI change is planned for 17.11 for the structure
> > eth_dev_data.
> > Isn't it better to use "``rte_eth_dev_data``"?
> > 
> > > +  The size of the unique name will increase RTE_ETH_NAME_MAX_LEN
> > from
> > > + 32 to
> > > +  64 characters to allow using a globally unique identifier (GUID) in this
> > field.
> > 
> > Except for the small comment above,
> > Acked-by: Yongseok Koh <yskoh@mellanox.com>
> 
> Acked-by: Shahaf Shuler <shahafs@mellanox.com>

Acked-by: Thomas Monjalon <thomas@monjalon.net>

Applied, thanks

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset()
  @ 2017-08-08  9:02  5% ` Van Haaren, Harry
  2017-08-08 11:01  0%   ` David Harton (dharton)
  2017-08-08 11:03  4%   ` Christian Ehrhardt
    1 sibling, 2 replies; 200+ results
From: Van Haaren, Harry @ 2017-08-08  9:02 UTC (permalink / raw)
  To: David Harton, thomas; +Cc: dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of David Harton
> Sent: Monday, August 7, 2017 6:39 PM
> To: thomas@monjalon.net
> Cc: dev@dpdk.org; David Harton <dharton@cisco.com>
> Subject: [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset()
> 
> Some devices do not support reset of eth stats.  An application may
> need to know not to clear shadow stats if the device cannot.
> 
> rte_eth_stats_reset is updated to provide a return code to share
> whether the device supports reset or not.
> 
> Signed-off-by: David Harton <dharton@cisco.com>
> ---

Hi,

As far as I know changing the return type (void to int) of a function does *not* break ABI, but does "break" API as the application code should now check the return value. In theory the application could ignore the return value and current behavior is maintained.

The validate-abi.sh script says "Compatible" with the following item flagged:

Problems with Symbols
High 0
Medium 0
Low	1

Change>> Type of return value has been changed from void to int (4 bytes).
Effect>> Replacement of return type may indicate a change in its semantic meaning.

Perhaps somebody with more ABI expertise than I would double check the return value change?


Some smaller things inline below.

> v3:
> * overcame noob errors and figured out patch challenges
> * this release should finally be clean :)
> 
> v2:
> * fixed soft tab issue inserted while moving changes
> 
>  lib/librte_ether/rte_ethdev.c | 8 +++++---
>  lib/librte_ether/rte_ethdev.h | 4 +++-
>  2 files changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index 0597641..f72cc5a 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -1341,17 +1341,19 @@ rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
>  	return 0;
>  }
> 
> -void
> +int
>  rte_eth_stats_reset(uint8_t port_id)
>  {
>  	struct rte_eth_dev *dev;
> 
> -	RTE_ETH_VALID_PORTID_OR_RET(port_id);
> +	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
>  	dev = &rte_eth_devices[port_id];
> 
> -	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->stats_reset);
> +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->stats_reset, -ENOTSUP);
>  	(*dev->dev_ops->stats_reset)(dev);
>  	dev->data->rx_mbuf_alloc_failed = 0;
> +
> +	return 0;
>  }
> 
>  static int
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 0adf327..d8ccd60 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -2246,8 +2246,10 @@ int rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats
> *stats);
>   *
>   * @param port_id
>   *   The port identifier of the Ethernet device.
> + * @return
> + *   Zero if successful. Non-zero otherwise.

We should document all return values:

@retval 0 Success
@retval -EINVAL Invalid port_id provided
@retval -ENOTSUP Stats reset functionality not supported by PMD

The API change itself should probably be added to release notes, as
applications may wish to be aware this function has changed.

>   */
> -void rte_eth_stats_reset(uint8_t port_id);
> +int rte_eth_stats_reset(uint8_t port_id);
> 
>  /**
>   * Retrieve names of extended statistics of an Ethernet device.
> --
> 2.10.3.dirty


I'm happy to Ack the code/release-notes with above suggestions, but I'd like a second opinion to Ack ABI.

-Harry

^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [PATCH v2] doc: announce ABI change for cryptodev and ethdev
  2017-08-08  8:08  4%   ` De Lara Guarch, Pablo
@ 2017-08-08  8:42  4%     ` Akhil Goyal
  0 siblings, 0 replies; 200+ results
From: Akhil Goyal @ 2017-08-08  8:42 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev, Doherty, Declan, thomas, Nicolau,
	Radu, aviadye, borisp, hemant.agrawal
  Cc: shahafs

Hi Pablo,

On 8/8/2017 1:38 PM, De Lara Guarch, Pablo wrote:
> Hi Akhil,
> 
>> -----Original Message-----
>> From: Akhil Goyal [mailto:akhil.goyal@nxp.com]
>> Sent: Tuesday, August 8, 2017 8:10 AM
>> To: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>;
>> thomas@monjalon.net; Nicolau, Radu <radu.nicolau@intel.com>;
>> aviadye@mellanox.com; borisp@mellanox.com;
>> hemant.agrawal@nxp.com; De Lara Guarch, Pablo
>> <pablo.de.lara.guarch@intel.com>
>> Cc: shahafs@mellanox.com; Akhil Goyal <akhil.goyal@nxp.com>
>> Subject: [PATCH v2] doc: announce ABI change for cryptodev and ethdev
>>
>> Support for security operations is planned to be added in ethdev and
>> cryptodev for the 17.11 release.
>>
>> For this following changes are required.
>> - rte_cryptodev and rte_eth_dev structures need to be added new
>> parameter rte_security_ops which extend support for security ops to the
>> corresponding driver.
>> - rte_cryptodev_info and rte_eth_dev_info need to be added with
>> rte_security_capabilities to identify the capabilities of the corresponding
>> driver.
>> - rte_security_session needs to be added in the union inside structure
>> rte_crypto_sym_op to decide between various types of sessions
>>
>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
>> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>> Acked-by: Boris Pismenny <borisp@mellanox.com>
>> Acked-by: Shahaf Shuler <shahafs@mellanox.com>
>> Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
>> ---
>> changes in v2:
>> Added one more ABI change wrt to security session, This patch is not split
>> into 3 patches as these all will be implemented simultaneously with
>> rte_security support.
>>
>>   doc/guides/rel_notes/deprecation.rst | 15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/doc/guides/rel_notes/deprecation.rst
>> b/doc/guides/rel_notes/deprecation.rst
>> index 72d1f35..e34a809 100644
>> --- a/doc/guides/rel_notes/deprecation.rst
>> +++ b/doc/guides/rel_notes/deprecation.rst
>> @@ -78,3 +78,18 @@ Deprecation Notices
>>     be removed in 17.11:
>>
>>     - ``rte_cryptodev_create_vdev``
>> +
>> +* cryptodev: new parameters - ``rte_security_capabilities`` and
>> +  ``rte_security_ops`` will be added to ``rte_cryptodev_info`` and
>> +  ``rte_cryptodev`` respectively to support security protocol offloaded
>> +  operations.
>> +
>> +* cryptodev: new parameter ``rte_security_session`` will be added in
>> +the union
>> +  of the structure ``rte_crypto_sym_op``, so that the user can choose
>> +either to
>> +  use ``rte_cryptodev_sym_session`` or ``rte_crypto_sym_xform`` or
>> +  ``rte_security_session``.
> 
> I don't think it is required to have a deprecation notice for this, as it is adding
> another element in a union, and it is not changing its size.
> However, this would require an addition in rte_crypto_op_sess_type, which,
> as long as it is added at the end, should not require a deprecation notice.
> 
> About splitting this into two patches, I would do it, as I believe deprecation notices
> should target a specific library.
> 
> 
> 

Thanks for the comments. I have marked the v2 as not applicable and 
marked v1 as in review in the patchwork.

-Akhil

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-04 12:56  0%         ` Bruce Richardson
@ 2017-08-08  8:32  0%           ` Ferruh Yigit
  2017-08-08 15:27  3%             ` Stephen Hemminger
  0 siblings, 1 reply; 200+ results
From: Ferruh Yigit @ 2017-08-08  8:32 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Thomas Monjalon, dev, Stephen Hemminger, Chilikin, Andrey,
	Ananyev, Konstantin, Wu, Jingjing

On 8/4/2017 1:56 PM, Bruce Richardson wrote:
> On Fri, Aug 04, 2017 at 12:58:01PM +0100, Ferruh Yigit wrote:
>> On 8/3/2017 8:53 PM, Thomas Monjalon wrote:
>>> 03/08/2017 18:15, Stephen Hemminger:
>>>> On Thu, 3 Aug 2017 14:21:38 +0100
>>>> Bruce Richardson <bruce.richardson@intel.com> wrote:
>>>>
>>>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
>>>>>> To control some device-specific features public device-specific functions
>>>>>> rte_pmd_*.h are used.
>>>>>>
>>>>>> But this solution requires applications to distinguish devices at runtime
>>>>>> and, depending on the device type, call corresponding device-specific
>>>>>> functions even if functions' parameters are the same.
>>>>>>
>>>>>> IOCTL-like API can be added to ethdev instead of public device-specific
>>>>>> functions to address the following:
>>>>>>
>>>>>> * allow more usable support of features across a range of NIC from
>>>>>>   one vendor, but not others
>>>>>> * allow features to be implemented by multiple NIC drivers without
>>>>>>   relying on a critical mass to get the functionality in ethdev
>>>>>> * there are a large number of possible device specific functions, and
>>>>>>   creating individual APIs for each one is not a good solution
>>>>>> * IOCTLs are a proven method for solving this problem in other areas,
>>>>>>   i.e. OS kernels.
>>>>>>
>>>>>> Control requests for this API will be globally defined at ethdev level, so
>>>>>> an application will use single API call to control different devices from
>>>>>> one/multiple vendors.
>>>>>>
>>>>>> API call may look like as a classic ioctl with an extra parameter for
>>>>>> argument length for better sanity checks:
>>>>>>
>>>>>> int
>>>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
>>>>>>         unsigned arg_length);
>>>>>>
>>>>>> Regards,
>>>>>> Andrey  
>>>>>
>>>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
>>>>> to admit it, since I dislike IOCTLs and other functions with opaque
>>>>> arguments! Having driver specific functions I don't think will scale
>>>>> well as each vendor tries to expose as much of their driver specific
>>>>> functionality as possible.
>>>>>
>>>>> One other additional example: I discovered just this week another issue
>>>>> with driver specific functions and testpmd, when I was working on the
>>>>> meson build rework.
>>>>>
>>>>> * With shared libraries, when we do "ninja install" we want our DPDK
>>>>>   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
>>>>>   driver folder, so that they can be automatically loaded from that
>>>>>   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
>>>>> * However, testpmd, as well as using the drivers as plugins, uses
>>>>>   driver-specific functions, which means that it explicitly links
>>>>>   against the pmd .so files.
>>>>> * Those driver .so files are not in with the other libraries, so ld.so
>>>>>   does not find the pmd, and the installed testpmd fails to run due to
>>>>>   missing library dependencies.
>>>>> * The workaround is to add the drivers path to the ld load path, but we
>>>>>   should not require ld library path changes just to get DPDK apps to
>>>>>   work.
>>>>>
>>>>> Using ioctls instead of driver-specific functions would solve this.
>>>>>
>>>>> My 2c.
>>>>
>>>> My 2c. No.
>>>>
>>>> Short answer:
>>>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
>>>> despised by Linux kernel developers. They provide an unstructured, unsecured,
>>>> back door for device driver abuse. Try to get a new driver in Linux with
>>>> a unique ioctl, and it will be hard to get accepted.
>>>>
>>>> Long answer:
>>>> So far every device specific feature has fit into ethdev model. Doing ioctl
>>>> is admitting "it is too hard to be general, we need need an out". For something
>>>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
>>>> For a real feature (think flow direction), we want a first class API for that.
>>>> For a wart, then devargs will do.
>>>>
>>>> Give a good example of something that should be an ioctl. Don't build the
>>>> API first and then let it get cluttered.
>>>
>>> I agree with Stephen.
>>>
>>> And please do not forget that ioctl still requires an API:
>>> the argument that you put in ioctl is the API of the feature.
>>> So it is the same thing as defining a new function.
>>
>> I am also not fan of the ioctl usage. I believe it hides APIs behind ids
>> and prevent argument check by compiler.
>>
>> BUT, the number of the increasing PMD specific APIs are also worrying,
>> it is becoming harder to maintain, and I believe this is something NOT
>> sustainable in long run.
>>
>>
>> What about having *eth_dev_extended_ops* ?
>>
>>
>> As a part of the rte_eth_dev. This can be in the librte_ether library
>> but in a separated file.
>>
>> And the APIs for these ops can be less strict on compatibility, and
>> easier to add.
>>
>> Benefits of having this new dev_ops:
>>
>> * Having an abstraction layer for common checks.
>>
>> * Even feature is not generic for all NICs, still a few NICs can share
>> the ops.
>>
>> * All APIs are in the same file makes it easy to see PMD specific APIs
>> comparing to scattered into various PMDs.
>>
>> * This is very like ioctl approach, but APIs are more clear and
>> arguments can be verified.
>>
> 
> Sounds like an ethdev-staging library, where features can be put until
> such time as they get critical mass for acceptance and promoted to
> ethdev? It's sounds better than IOCTL, while giving the same benefits.
> 
> I'd be happy enough with any solution that allows NIC features to be
> exposed that does not have functions limited to each individual driver,
> so that common functionality can be exposed to apps via an API even if
> only 2 drivers support it.

This is not decided yet, but to enable working on this for next release,
is a deprecation notice required to add a new field to "struct
rte_eth_dev" ?

"struct rte_eth_dev" is marked as "@internal", so I believe deprecation
notice is NOT required, but I would like to confirm.

> 
>> Thanks,
>> ferruh
>>
>>
>>>
>>> The real debate is to decide if we want to continue adding more
>>> control path features in DPDK or focus on Rx/Tx.
> I don't see dropping control path as an option. It would severely limit
> the usefulness of DPDK.
> 
> /Bruce
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: announce ABI change for cryptodev and ethdev
  2017-08-08  7:09  7% ` [dpdk-dev] [PATCH v2] " Akhil Goyal
@ 2017-08-08  8:08  4%   ` De Lara Guarch, Pablo
  2017-08-08  8:42  4%     ` Akhil Goyal
  0 siblings, 1 reply; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-08  8:08 UTC (permalink / raw)
  To: Akhil Goyal, dev, Doherty, Declan, thomas, Nicolau, Radu,
	aviadye, borisp, hemant.agrawal
  Cc: shahafs

Hi Akhil,

> -----Original Message-----
> From: Akhil Goyal [mailto:akhil.goyal@nxp.com]
> Sent: Tuesday, August 8, 2017 8:10 AM
> To: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>;
> thomas@monjalon.net; Nicolau, Radu <radu.nicolau@intel.com>;
> aviadye@mellanox.com; borisp@mellanox.com;
> hemant.agrawal@nxp.com; De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com>
> Cc: shahafs@mellanox.com; Akhil Goyal <akhil.goyal@nxp.com>
> Subject: [PATCH v2] doc: announce ABI change for cryptodev and ethdev
> 
> Support for security operations is planned to be added in ethdev and
> cryptodev for the 17.11 release.
> 
> For this following changes are required.
> - rte_cryptodev and rte_eth_dev structures need to be added new
> parameter rte_security_ops which extend support for security ops to the
> corresponding driver.
> - rte_cryptodev_info and rte_eth_dev_info need to be added with
> rte_security_capabilities to identify the capabilities of the corresponding
> driver.
> - rte_security_session needs to be added in the union inside structure
> rte_crypto_sym_op to decide between various types of sessions
> 
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> Acked-by: Boris Pismenny <borisp@mellanox.com>
> Acked-by: Shahaf Shuler <shahafs@mellanox.com>
> Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> ---
> changes in v2:
> Added one more ABI change wrt to security session, This patch is not split
> into 3 patches as these all will be implemented simultaneously with
> rte_security support.
> 
>  doc/guides/rel_notes/deprecation.rst | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst
> b/doc/guides/rel_notes/deprecation.rst
> index 72d1f35..e34a809 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -78,3 +78,18 @@ Deprecation Notices
>    be removed in 17.11:
> 
>    - ``rte_cryptodev_create_vdev``
> +
> +* cryptodev: new parameters - ``rte_security_capabilities`` and
> +  ``rte_security_ops`` will be added to ``rte_cryptodev_info`` and
> +  ``rte_cryptodev`` respectively to support security protocol offloaded
> +  operations.
> +
> +* cryptodev: new parameter ``rte_security_session`` will be added in
> +the union
> +  of the structure ``rte_crypto_sym_op``, so that the user can choose
> +either to
> +  use ``rte_cryptodev_sym_session`` or ``rte_crypto_sym_xform`` or
> +  ``rte_security_session``.

I don't think it is required to have a deprecation notice for this, as it is adding
another element in a union, and it is not changing its size.
However, this would require an addition in rte_crypto_op_sess_type, which,
as long as it is added at the end, should not require a deprecation notice.

About splitting this into two patches, I would do it, as I believe deprecation notices
should target a specific library.

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v2] doc: announce ABI change for cryptodev and ethdev
  2017-08-03 15:32  4% [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev Akhil Goyal
                   ` (2 preceding siblings ...)
  2017-08-04 15:25  4% ` De Lara Guarch, Pablo
@ 2017-08-08  7:09  7% ` Akhil Goyal
  2017-08-08  8:08  4%   ` De Lara Guarch, Pablo
  3 siblings, 1 reply; 200+ results
From: Akhil Goyal @ 2017-08-08  7:09 UTC (permalink / raw)
  To: dev, declan.doherty, thomas, radu.nicolau, aviadye, borisp,
	hemant.agrawal, pablo.de.lara.guarch
  Cc: shahafs, Akhil Goyal

Support for security operations is planned to be added
in ethdev and cryptodev for the 17.11 release.

For this following changes are required.
- rte_cryptodev and rte_eth_dev structures need to be added
new parameter rte_security_ops which extend support for
security ops to the corresponding driver.
- rte_cryptodev_info and rte_eth_dev_info need to be added
with rte_security_capabilities to identify the capabilities of
the corresponding driver.
- rte_security_session needs to be added in the union inside
structure rte_crypto_sym_op to decide between various types of
sessions

Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Acked-by: Boris Pismenny <borisp@mellanox.com>
Acked-by: Shahaf Shuler <shahafs@mellanox.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
changes in v2:
Added one more ABI change wrt to security session,
This patch is not split into 3 patches as these all will be implemented
simultaneously with rte_security support.

 doc/guides/rel_notes/deprecation.rst | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 72d1f35..e34a809 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -78,3 +78,18 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_cryptodev_create_vdev``
+
+* cryptodev: new parameters - ``rte_security_capabilities`` and
+  ``rte_security_ops`` will be added to ``rte_cryptodev_info`` and
+  ``rte_cryptodev`` respectively to support security protocol offloaded
+  operations.
+
+* cryptodev: new parameter ``rte_security_session`` will be added in the union
+  of the structure ``rte_crypto_sym_op``, so that the user can choose either to
+  use ``rte_cryptodev_sym_session`` or ``rte_crypto_sym_xform`` or
+  ``rte_security_session``.
+
+* ethdev: new parameters - ``rte_security_capabilities`` and
+  ``rte_security_ops`` will be added to ``rte_eth_dev_info`` and
+  ``rte_eth_dev`` respectively  to support security operations like
+  ipsec inline.
-- 
2.9.3

^ permalink raw reply	[relevance 7%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-04 15:25  4% ` De Lara Guarch, Pablo
@ 2017-08-08  6:54  7%   ` Akhil Goyal
  0 siblings, 0 replies; 200+ results
From: Akhil Goyal @ 2017-08-08  6:54 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, Declan Doherty
  Cc: Nicolau, Radu, aviadye, borisp, hemant.agrawal, Thomas Monjalon, dev

Hi Pablo/Declan,

On 8/4/2017 8:55 PM, De Lara Guarch, Pablo wrote:
> 
> 
>> -----Original Message-----
>> From: Akhil Goyal [mailto:akhil.goyal@nxp.com]
>> Sent: Thursday, August 3, 2017 4:32 PM
>> To: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>;
>> thomas@monjalon.net; Nicolau, Radu <radu.nicolau@intel.com>;
>> aviadye@mellanox.com; borisp@mellanox.com;
>> hemant.agrawal@nxp.com; De Lara Guarch, Pablo
>> <pablo.de.lara.guarch@intel.com>
>> Cc: Akhil Goyal <akhil.goyal@nxp.com>
>> Subject: [PATCH] doc: announce ABI change for cryptodev and ethdev
>>
>> Support for security operations is planned to be added in ethdev and
>> cryptodev for the 17.11 release.
>>
>> For this following changes are required.
>> - rte_cryptodev and rte_eth_dev structures need to be added new
>> parameter rte_security_ops which extend support for security ops to the
>> corresponding driver.
>> - rte_cryptodev_info and rte_ethd_dev_info need to be added with
>> rte_security_capabilities to identify the capabilities of the corresponding
>> driver.
>>
>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> 
> Not sure if this needed to be split into two patches, as this affects two libraries.
> At least, from cryptodev side:
> 
> Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> 

We would be needing one more ABI change, Can I send it now. I discovered 
it after I sent this patch.

In the struct rte_crypto_sym_op, we would need to add a pointer to a 
security session in the union of session and xform.

Also, Do I need to split this patch into two for crypto and eth?

Regards,
Akhil

^ permalink raw reply	[relevance 7%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-07 18:07  4%     ` Boris Pismenny
@ 2017-08-08  5:03  4%       ` Shahaf Shuler
  2017-08-08 10:00  4%         ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Shahaf Shuler @ 2017-08-08  5:03 UTC (permalink / raw)
  To: Boris Pismenny, Thomas Monjalon, dev
  Cc: Hemant Agrawal, Akhil Goyal, declan.doherty, radu.nicolau,
	Aviad Yehezkel, pablo.de.lara.guarch, Boris Pismenny

Monday, August 7, 2017 9:07 PM, Boris Pismenny:
> > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 04/08/2017 07:26, Hemant Agrawal:
> > > On 8/3/2017 9:02 PM, Akhil Goyal wrote:
> > > > Support for security operations is planned to be added in ethdev
> > > > and cryptodev for the 17.11 release.
> > > >
> > > > For this following changes are required.
> > > > - rte_cryptodev and rte_eth_dev structures need to be added new
> > > > parameter rte_security_ops which extend support for security ops
> > > > to the corresponding driver.
> > > > - rte_cryptodev_info and rte_ethd_dev_info need to be added with
> > > > rte_security_capabilities to identify the capabilities of the
> > > > corresponding driver.
> >
> > It is not explained what is the fundamental difference between
> > rte_security and rte_crypto?
> > It looks to be just a technical workaround.
> 
> rte_security is a layer between crypto and NIC.
> 
> Today crypto sessions are created exclusively against crypto devices, but
> they don't use network related fields, while the network namespace doesn't
> use crypto related fields. We expect this API to represent crypto sessions
> that combine network fields and allow to add/delete them for all devices.
> 
> For NICs we will use rte_flow with rte_security for inline/full crypto protocol
> offload such as ESP.
> 
> >
> > Why the ABI would be changed by rte_security additions?
> >
> > > > Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> > > >
> > > Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> >
> > No more opinions outside of NXP?
> > It seems there is not yet a consensus on how to manage IPsec offloading.
> > I heard there were some phone calls about these stuff but nothing
> > clear appears publicly on the mailing list.
> > Looks to be a community failure.
> 
> We agreed to go ahead with this approach on one such phone call. I hope we
> could use the dpdk github for development.
> 
> Acked-by: Boris Pismenny <borisp@mellanox.com>

Acked-by: Shahaf Shuler <shahafs@mellanox.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] ethdev: add notice for planned name size change
  2017-08-07 22:19  0% ` [dpdk-dev] [PATCH] ethdev: add notice for planned name size change Yongseok Koh
@ 2017-08-08  4:56  0%   ` Shahaf Shuler
  2017-08-08  9:47  0%     ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Shahaf Shuler @ 2017-08-08  4:56 UTC (permalink / raw)
  To: Yongseok Koh, Stephen Hemminger; +Cc: dev

Tuesday, August 8, 2017 1:20 AM, Yongseok Koh:
> > On Jul 6, 2017, at 8:07 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > VMBUS support will use GUID in eth_dev_data name field which requires
> > at least 37 characters. Plan for increase in size now.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> > doc/guides/rel_notes/deprecation.rst | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/doc/guides/rel_notes/deprecation.rst
> > b/doc/guides/rel_notes/deprecation.rst
> > index 2e708dbe0deb..d5b70c50064a 100644
> > --- a/doc/guides/rel_notes/deprecation.rst
> > +++ b/doc/guides/rel_notes/deprecation.rst
> > @@ -95,3 +95,7 @@ Deprecation Notices
> >   The non-"do-sig" versions of the hash tables will be removed
> >   (including the ``signature_offset`` parameter)
> >   and the "do-sig" versions renamed accordingly.
> > +
> > +* ethdev: An ABI change is planned for 17.11 for the structure
> eth_dev_data.
> Isn't it better to use "``rte_eth_dev_data``"?
> 
> > +  The size of the unique name will increase RTE_ETH_NAME_MAX_LEN
> from
> > + 32 to
> > +  64 characters to allow using a globally unique identifier (GUID) in this
> field.
> 
> Except for the small comment above,
> Acked-by: Yongseok Koh <yskoh@mellanox.com>

Acked-by: Shahaf Shuler <shahafs@mellanox.com>

> 
> Thanks,
> Yongseok

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3] doc: announce API and ABI change for ethdev
  2017-08-07 12:42 13%   ` [dpdk-dev] [PATCH v3] " Zhiyong Yang
@ 2017-08-08  4:02  4%     ` Yang, Zhiyong
  2017-08-08  9:35  4%       ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Yang, Zhiyong @ 2017-08-08  4:02 UTC (permalink / raw)
  To: dev; +Cc: Tan, Jianfeng, yliu, jerin.jacob, thomas, Horton, Remy, shahafs


> -----Original Message-----
> From: Yang, Zhiyong
> Sent: Monday, August 7, 2017 8:43 PM
> To: dev@dpdk.org
> Cc: Tan, Jianfeng <jianfeng.tan@intel.com>; yliu@fridaylinux.org;
> jerin.jacob@caviumnetworks.com; thomas@monjalon.net; Horton, Remy
> <remy.horton@intel.com>; Yang, Zhiyong <zhiyong.yang@intel.com>
> Subject: [PATCH v3] doc: announce API and ABI change for ethdev
> 
> This is an API/ABI change notice for DPDK 17.11 announcing the redefinition of
> port_id. port_id is currently defined as uint8_t, which is limited to the range 0 to
> 255. A larger range is required for vdev scalability.
> 
> It is necessary for a redefinition of port_id to extend it from 1 bytes to
> 2 bytes. All ethdev APIs and usages related to port_id will be changed at the
> same time.
> 
> cc: jianfeng.tan@intel.com
> cc: yliu@fridaylinux.org
> cc: jerin.jacob@caviumnetworks.com
> cc: thomas@monjalon.net
> cc: remy.horton@intel.com
> 
> Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
> Acked-by: Jianfeng Tan <jianfeng.tan@intel.com>
> Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
> Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> Acked-by: Remy Horton <remy.horton@intel.com>
> ---

This ack in v2 is added in v3. Thanks, Shahaf.

Acked-by: Shahaf Shuler <shahafs@mellanox.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-08-05 20:24  4%     ` Olivier MATZ
@ 2017-08-08  0:10  4%       ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08  0:10 UTC (permalink / raw)
  To: Santosh Shukla; +Cc: dev, Olivier MATZ, Jerin Jacob

> > > An API/ABI change is planned for 17.11 to change following
> > > 
> > > * Remove unused flag param from rte_mempool_generic_get and _put.
> > > * Change data type for mempool 'flag' from int to unsigned int.
> > >   Refer [1].
> > > * Add struct rte_mempool * param into func rte_mempool_xmem_size,
> > >   rte_mempool_xmem_usage to make it mempool aware.
> > >   Refer [2].
> > > 
> > > [1] http://dpdk.org/dev/patchwork/patch/25603/
> > > [2] http://dpdk.org/dev/patchwork/patch/25605/
> > > 
> > > Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> > 
> > Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> 
> Acked-by: Olivier Matz <olivier.matz@6wind.com>

Applied, thanks

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware
  2017-08-06 21:22  0%     ` Olivier MATZ
@ 2017-08-08  0:04  0%       ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-08  0:04 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: dev, Olivier MATZ, Hemant Agrawal, santosh, stephen,
	bruce.richardson, shreyansh.jain, gaetan.rivet,
	sergio.gonzalez.monroy, anatoly.burakov

> > > > When we run DPDK on guest or VFIO mode on host,
> > > > the dpdk library or device will not be directly accessing
> > > > the physical address. Instead, the device does go through
> > > > an IO address translation memory management unit. On x86,
> > > > we call it as IOMMU and on ARM as SMMU.
> > > > 
> > > > More details:
> > > > http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf
> > > > 
> > > > Based on discussion in the following thread
> > > > http://dpdk.org/ml/archives/dev/2017-July/070850.html
> > > > 
> > > > We would like to change reference to physical address to more
> > > > appropriate name as with IOMMU/SMMU with
> > > > the device won't be dealing directly with the physical address.
> > > > 
> > > > An ABI change is planned for 17.11 to change following
> > > > data structure or functions to more appropriate name.
> > > > Currently planned to change it iova as instead of phys
> > > > 
> > > > Please note: The change will be only for the name and
> > > > functional aspects of the API will remain same.
> > > > 
> > > > Following functions/data structures name may change.
> > > > This list is based on v17.05-rc1. It may change based on v17.11 code base.
> > > > 
> > > > 
> > > > typedef:
> > > > phys_addr_t
> > > > 
> > > > structures:
> > > > 
> > > > struct rte_memseg::phys_addr
> > > > struct rte_mbuf::buf_physaddr
> > > > 
> > > > functions:
> > > > rte_mempool_populate_phys()
> > > > rte_mempool_populate_phys_tab()
> > > > rte_eal_using_phys_addrs()
> > > > rte_mem_virt2phy()
> > > > rte_dump_physmem_layout()
> > > > rte_eal_get_physmem_layout()
> > > > rte_eal_get_physmem_size()
> > > > rte_malloc_virt2phy()
> > > > rte_mem_phy2mch()
> > > > 
> > > > Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > > 
> > > Acked-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> > > 
> > Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> 
> Acked-by: Olivier Matz <olivier.matz@6wind.com>

Acked-by: Thomas Monjalon <thomas@monjalon.net>

The name will probably be discussed.
Applied, thanks

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: announce rte_devargs changes in 17.11
  2017-08-04 13:29  5% [dpdk-dev] [PATCH] doc: announce rte_devargs changes in 17.11 Gaetan Rivet
@ 2017-08-07 23:18  0% ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-07 23:18 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

04/08/2017 15:29, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> +* eal: several API and ABI changes are planned for ``rte_devargs`` in v17.11.
> +  The format of device command line parameters will change. The bus will need
> +  to be explicitly stated in the device declaration. The enum ``rte_devtype``
> +  was used to identify a bus and will disappear.
> +  The structure ``rte_devargs`` will change.
> +  The ``rte_devargs_list`` will be made private.
> +  The following functions are deprecated starting from 17.08 and will either be
> +  modified or removed in 17.11:
> +
> +  - ``rte_eal_devargs_add``
> +  - ``rte_eal_devargs_type_count``

Acked-by: Thomas Monjalon <thomas@monjalon.net>

This kind of change has already been suggested by Jan Blunck:
	http://dpdk.org/ml/archives/dev/2017-July/070729.html
	http://dpdk.org/ml/archives/dev/2017-July/071054.html

It is very important to continue progressing on device syntax and
bus rework during 17.11.

Applied

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI
  2017-07-09  9:28 11% ` [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI Jan Blunck
  2017-07-09 12:25  4%   ` Shreyansh Jain
@ 2017-08-07 23:03  4%   ` Thomas Monjalon
  1 sibling, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-07 23:03 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev

09/07/2017 11:28, Jan Blunck:
> Add deprecation notice necessary to do devargs refactoring for 17.11.
> 
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> +* devargs: An ABI change is planned for 17.11 for the structure ``rte_devargs``.
> +  The newly introduced devargs ABI in 17.08 is tightly couple to the bus
> +  implementations which will get fixed in 17.11. The following function is
> +  deprecated and will change API in 17.11:
> +
> +  - ``rte_eal_devargs_add``

This deprecation notice is superseded by:
	http://dpdk.org/dev/patchwork/patch/27443/

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 03/13] devargs: deprecate enum rte_devtype based functions
  2017-07-11 23:25  5% ` [dpdk-dev] [PATCH 03/13] devargs: deprecate enum rte_devtype based functions Jan Blunck
@ 2017-08-07 23:02  0%   ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-07 23:02 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev

12/07/2017 01:25, Jan Blunck:
> The enum rte_devtype will need to get extended every time we add a bus.
> Mark all related functions as deprecated for 17.11.
> 
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> +* devargs: An API/ABI change is planed for 17.11 for ``struct rte_devargs`` to
> +  remove ``enum rte_devtype`` so that starting from 17.08 the following
> +  functions are deprecated:
> +
> +  - ``rte_eal_devargs_add``
> +  - ``rte_eal_devargs_type_count``

This deprecation notice is superseded by:
	http://dpdk.org/dev/patchwork/patch/27443/

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] ethdev: add notice for planned name size change
       [not found]     <20170706150751.27251-1-stephen@networkplumber.org>
@ 2017-08-07 22:19  0% ` Yongseok Koh
  2017-08-08  4:56  0%   ` Shahaf Shuler
  0 siblings, 1 reply; 200+ results
From: Yongseok Koh @ 2017-08-07 22:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev


> On Jul 6, 2017, at 8:07 AM, Stephen Hemminger <stephen@networkplumber.org> wrote:
> 
> VMBUS support will use GUID in eth_dev_data name field which requires
> at least 37 characters. Plan for increase in size now.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> doc/guides/rel_notes/deprecation.rst | 4 ++++
> 1 file changed, 4 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 2e708dbe0deb..d5b70c50064a 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -95,3 +95,7 @@ Deprecation Notices
>   The non-"do-sig" versions of the hash tables will be removed
>   (including the ``signature_offset`` parameter)
>   and the "do-sig" versions renamed accordingly.
> +
> +* ethdev: An ABI change is planned for 17.11 for the structure eth_dev_data.
Isn't it better to use "``rte_eth_dev_data``"?

> +  The size of the unique name will increase RTE_ETH_NAME_MAX_LEN from 32 to
> +  64 characters to allow using a globally unique identifier (GUID) in this field.

Except for the small comment above,
Acked-by: Yongseok Koh <yskoh@mellanox.com>

Thanks,
Yongseok

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-07 17:41  7%   ` Thomas Monjalon
@ 2017-08-07 18:07  4%     ` Boris Pismenny
  2017-08-08  5:03  4%       ` Shahaf Shuler
  0 siblings, 1 reply; 200+ results
From: Boris Pismenny @ 2017-08-07 18:07 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Hemant Agrawal, Akhil Goyal, declan.doherty, radu.nicolau,
	Aviad Yehezkel, pablo.de.lara.guarch, Boris Pismenny

> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> 04/08/2017 07:26, Hemant Agrawal:
> > On 8/3/2017 9:02 PM, Akhil Goyal wrote:
> > > Support for security operations is planned to be added in ethdev and
> > > cryptodev for the 17.11 release.
> > >
> > > For this following changes are required.
> > > - rte_cryptodev and rte_eth_dev structures need to be added new
> > > parameter rte_security_ops which extend support for security ops to
> > > the corresponding driver.
> > > - rte_cryptodev_info and rte_ethd_dev_info need to be added with
> > > rte_security_capabilities to identify the capabilities of the
> > > corresponding driver.
> 
> It is not explained what is the fundamental difference between rte_security
> and rte_crypto?
> It looks to be just a technical workaround.

rte_security is a layer between crypto and NIC.

Today crypto sessions are created exclusively against crypto devices, but they don't use network related fields, while the network namespace doesn't use crypto related fields. We expect this API to represent crypto sessions that combine network fields and allow to add/delete them for all devices.

For NICs we will use rte_flow with rte_security for inline/full crypto protocol offload such as ESP.

> 
> Why the ABI would be changed by rte_security additions?
> 
> > > Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> > >
> > Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> 
> No more opinions outside of NXP?
> It seems there is not yet a consensus on how to manage IPsec offloading.
> I heard there were some phone calls about these stuff but nothing clear
> appears publicly on the mailing list.
> Looks to be a community failure.

We agreed to go ahead with this approach on one such phone call. I hope we could use the dpdk github for development. 

Acked-by: Boris Pismenny <borisp@mellanox.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-04  5:26  4% ` Hemant Agrawal
@ 2017-08-07 17:41  7%   ` Thomas Monjalon
  2017-08-07 18:07  4%     ` Boris Pismenny
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2017-08-07 17:41 UTC (permalink / raw)
  To: dev
  Cc: Hemant Agrawal, Akhil Goyal, declan.doherty, radu.nicolau,
	aviadye, borisp, pablo.de.lara.guarch

04/08/2017 07:26, Hemant Agrawal:
> On 8/3/2017 9:02 PM, Akhil Goyal wrote:
> > Support for security operations is planned to be added
> > in ethdev and cryptodev for the 17.11 release.
> >
> > For this following changes are required.
> > - rte_cryptodev and rte_eth_dev structures need to be added
> > new parameter rte_security_ops which extend support for
> > security ops to the corresponding driver.
> > - rte_cryptodev_info and rte_ethd_dev_info need to be added
> > with rte_security_capabilities to identify the capabilities of
> > the corresponding driver.

It is not explained what is the fundamental difference between
rte_security and rte_crypto?
It looks to be just a technical workaround.

Why the ABI would be changed by rte_security additions?

> > Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> >
> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

No more opinions outside of NXP?
It seems there is not yet a consensus on how to manage IPsec offloading.
I heard there were some phone calls about these stuff but nothing clear
appears publicly on the mailing list.
Looks to be a community failure.

^ permalink raw reply	[relevance 7%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-08-04  6:56  7%   ` Remy Horton
  2017-08-05 10:34  4%     ` Yang, Zhiyong
@ 2017-08-07 15:20  4%     ` Shahaf Shuler
  1 sibling, 0 replies; 200+ results
From: Shahaf Shuler @ 2017-08-07 15:20 UTC (permalink / raw)
  To: Remy Horton, Zhiyong Yang, dev
  Cc: jianfeng.tan, yliu, jerin.jacob, Thomas Monjalon

Friday, August 4, 2017 9:56 AM, Remy Horton:
> On 04/08/2017 06:27, Zhiyong Yang wrote:
> > This is an API/ABI change notice for DPDK 17.11 on redefinition of
> > port_id. port_id is defined as uint8_t by now, which is just ranged
> > from 0 to 255. For more and more scenerioes, more than 256 ports are
> > needed to support for vdev scalability.
> >
> > It is necessary for redefinition of port_id to extend from 1 bytes to
> > 2 bytes. All ethdev APIs and use cases related to port_id will be
> > changed at the same time.
> 
> I think this reads a little better:
> 
> This is an API/ABI change notice for DPDK 17.11 announcing the redefinition
> of port_id. port_id is currently defined as uint8_t, which is limited to the
> range 0 to 255. A larger range is required for vdev scalability.
> 
> It is necessary for a redefinition of port_id to extend it from 1 bytes to 2
> bytes. All ethdev APIs and usages related to port_id will be changed at the
> same time.
> 
> >  doc/guides/rel_notes/deprecation.rst | 6 ++++++
> >  1 file changed, 6 insertions(+)
> 
> Acked-by: Remy Horton <remy.horton@intel.com>

Acked-by: Shahaf Shuler <shahafs@mellanox.com>

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v3] doc: announce API and ABI change for ethdev
  2017-08-04  5:27 13% ` [dpdk-dev] [PATCH v2] " Zhiyong Yang
  2017-08-04  6:56  7%   ` Remy Horton
@ 2017-08-07 12:42 13%   ` Zhiyong Yang
  2017-08-08  4:02  4%     ` Yang, Zhiyong
  1 sibling, 1 reply; 200+ results
From: Zhiyong Yang @ 2017-08-07 12:42 UTC (permalink / raw)
  To: dev; +Cc: jianfeng.tan, yliu, jerin.jacob, thomas, remy.horton, Zhiyong Yang

This is an API/ABI change notice for DPDK 17.11 announcing the redefinition
of port_id. port_id is currently defined as uint8_t, which is limited to
the range 0 to 255. A larger range is required for vdev scalability.

It is necessary for a redefinition of port_id to extend it from 1 bytes to
2 bytes. All ethdev APIs and usages related to port_id will be changed at
the same time.

cc: jianfeng.tan@intel.com
cc: yliu@fridaylinux.org
cc: jerin.jacob@caviumnetworks.com
cc: thomas@monjalon.net
cc: remy.horton@intel.com

Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
Acked-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

Change in V3.
update the commit log. Thanks for Remy's comment.

Change in V2.
1. remove indent of paragraph in commit log.
2. add more description about API/ABI according to yuanhan's comments.

 doc/guides/rel_notes/deprecation.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 72aa40495..4edaf92fb 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -49,6 +49,12 @@ Deprecation Notices
   Target release for removal of the legacy API will be defined once most
   PMDs have switched to rte_flow.
 
+* ABI/API changes are planned for 17.11 in all structures which include port_id
+  definition such as "rte_eth_dev_data", "rte_port_ethdev_reader_params",
+  "rte_port_ethdev_writer_params", and so on. The definition of port_id will be
+  changed from 8 bits to 16 bits in order to support more than 256 ports in
+  DPDK. All APIs which have port_id parameter will be changed at the same time.
+
 * librte_table: The ``key_mask`` parameter will be added to all the hash tables
   that currently do not have it, as well as to the hash compute function prototype.
   The non-"do-sig" versions of the hash tables will be removed
-- 
2.13.3

^ permalink raw reply	[relevance 13%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-08-07  3:07  4%       ` Yang, Zhiyong
@ 2017-08-07 11:04  4%         ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-07 11:04 UTC (permalink / raw)
  To: Yang, Zhiyong; +Cc: Horton, Remy, dev, Tan, Jianfeng, yliu, jerin.jacob

07/08/2017 05:07, Yang, Zhiyong:
> Hi, Thomas:
> 	Need I sent another V3 patch to update commit log according to Remy's suggestion?

Yes it would be better if you can do it please

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [RFC PATCH 3/4] ethdev: introduce Tx queue offloads API
  2017-08-07 10:54  4% [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API Shahaf Shuler
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
@ 2017-08-07 10:54  3% ` Shahaf Shuler
  2017-08-23  6:39  0% ` [dpdk-dev] [RFC PATCH 0/4] ethdev new " Shahaf Shuler
  2017-08-25 10:31  0% ` Jerin Jacob
  3 siblings, 0 replies; 200+ results
From: Shahaf Shuler @ 2017-08-07 10:54 UTC (permalink / raw)
  To: dev

Introduce a new API to configure Tx offloads.

The new API will re-use existing DEV_TX_OFFLOAD_* flags
to enable the different offloads. This will ease the process
of adding a new Tx offloads, as no ABI breakage is involved.
In addition, the Tx offloads will be disabled by default and be
enabled per application needs. This will much simplify PMD management of
the different offloads.

The new API does not have an equivalent for the below, benchmark
specific, flags:
ETH_TXQ_FLAGS_NOREFCOUNT
ETH_TXQ_FLAGS_NOMULTMEMP

The Tx queue offload API can be used only with devices which advertize
the RTE_ETH_DEV_TXQ_OFFLOAD capability.

The old Tx offloads API is kept for the meanwhile, in order to enable a
smooth transition for PMDs and application to the new API.

Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
---
 lib/librte_ether/rte_ethdev.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index ce33c61c4..fd17ee81e 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -719,6 +719,14 @@ struct rte_eth_rxq_conf {
 #define ETH_TXQ_FLAGS_NOXSUMS \
 		(ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
 		 ETH_TXQ_FLAGS_NOXSUMTCP)
+#define ETH_TXQ_FLAGS_IGNORE	0x8000
+	/**
+	 * When set the txq_flags should be ignored,
+	 * instead the Tx offloads will be set on offloads field
+	 * located on rte_eth_txq_conf struct.
+	 * This flag is temporary till the rte_eth_txq_conf.txq_flags
+	 * API will be deprecated.
+	 */
 /**
  * A structure used to configure a TX ring of an Ethernet port.
  */
@@ -730,6 +738,12 @@ struct rte_eth_txq_conf {
 
 	uint32_t txq_flags; /**< Set flags for the Tx queue */
 	uint8_t tx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
+	uint64_t offloads;
+	/**
+	 * Enable Tx offloads using DEV_TX_OFFLOAD_* flags.
+	 * Supported only for devices which advertize the
+	 * RTE_ETH_DEV_TXQ_OFFLOAD capability.
+	 */
 };
 
 /**
@@ -955,6 +969,8 @@ struct rte_eth_conf {
 /**< Multiple threads can invoke rte_eth_tx_burst() concurrently on the same
  * tx queue without SW lock.
  */
+#define DEV_TX_OFFLOAD_MULTI_SEGS	0x00008000
+/**< multi segment send is supported. */
 
 struct rte_pci_device;
 
@@ -1751,6 +1767,8 @@ struct rte_eth_dev_data {
 #define RTE_ETH_DEV_INTR_RMV     0x0008
 /** Device supports the rte_eth_rxq_conf offloads API */
 #define RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
+/** Device supports the rte_eth_txq_conf offloads API */
+#define RTE_ETH_DEV_TXQ_OFFLOAD 0x0020
 
 /**
  * @internal
-- 
2.12.0

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue offloads API
  2017-08-07 10:54  4% [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API Shahaf Shuler
@ 2017-08-07 10:54  3% ` Shahaf Shuler
  2017-08-23 12:21  0%   ` Ananyev, Konstantin
                     ` (3 more replies)
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 3/4] ethdev: introduce Tx " Shahaf Shuler
                   ` (2 subsequent siblings)
  3 siblings, 4 replies; 200+ results
From: Shahaf Shuler @ 2017-08-07 10:54 UTC (permalink / raw)
  To: dev

Introduce a new API to configure Rx offloads.

The new API will re-use existing DEV_RX_OFFLOAD_* flags
to enable the different offloads. This will ease the process
of adding a new Rx offloads, as no ABI breakage is involved.
In addition, the offload configuration can be done per queue,
instead of per port.

The Rx queue offload API can be used only with devices which advertize
the RTE_ETH_DEV_RXQ_OFFLOAD capability.

The old Rx offloads API is kept for the meanwhile, in order to enable a
smooth transition for PMDs and application to the new API.

Signed-off-by: Shahaf Shuler <shahafs@mellanox.com>
---
 lib/librte_ether/rte_ethdev.h | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f7a44578c..ce33c61c4 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -357,7 +357,14 @@ struct rte_eth_rxmode {
 		jumbo_frame      : 1, /**< Jumbo Frame Receipt enable. */
 		hw_strip_crc     : 1, /**< Enable CRC stripping by hardware. */
 		enable_scatter   : 1, /**< Enable scatter packets rx handler */
-		enable_lro       : 1; /**< Enable LRO */
+		enable_lro       : 1, /**< Enable LRO */
+		ignore		 : 1;
+		/**
+		 * When set the rxmode offloads should be ignored,
+		 * instead the Rx offloads will be set on rte_eth_rxq_conf.
+		 * This bit is temporary till rxmode Rx offloads API will
+		 * be deprecated.
+		 */
 };
 
 /**
@@ -691,6 +698,12 @@ struct rte_eth_rxq_conf {
 	uint16_t rx_free_thresh; /**< Drives the freeing of RX descriptors. */
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
+	uint64_t offloads;
+	/**
+	 * Enable Rx offloads using DEV_RX_OFFLOAD_* flags.
+	 * Supported only for devices which advertize the
+	 * RTE_ETH_DEV_RXQ_OFFLOAD capability.
+	 */
 };
 
 #define ETH_TXQ_FLAGS_NOMULTSEGS 0x0001 /**< nb_segs=1 for all mbufs */
@@ -907,6 +920,19 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_QINQ_STRIP  0x00000020
 #define DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM 0x00000040
 #define DEV_RX_OFFLOAD_MACSEC_STRIP     0x00000080
+#define DEV_RX_OFFLOAD_HEADER_SPLIT	0x00000100
+#define DEV_RX_OFFLOAD_VLAN_FILTER	0x00000200
+#define DEV_RX_OFFLOAD_VLAN_EXTEND	0x00000400
+#define DEV_RX_OFFLOAD_JUMBO_FRAME	0x00000800
+#define DEV_RX_OFFLOAD_CRC_STRIP	0x00001000
+#define DEV_RX_OFFLOAD_SCATTER		0x00002000
+#define DEV_RX_OFFLOAD_LRO		0x00004000
+#define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
+				 DEV_RX_OFFLOAD_UDP_CKSUM | \
+				 DEV_RX_OFFLOAD_TCP_CKSUM)
+#define DEV_RX_OFFLOAD_VLAN (DEV_RX_OFFLOAD_VLAN_STRIP | \
+			     DEV_RX_OFFLOAD_VLAN_FILTER | \
+			     DEV_RX_OFFLOAD_VLAN_EXTEND)
 
 /**
  * TX offload capabilities of a device.
@@ -1723,6 +1749,8 @@ struct rte_eth_dev_data {
 #define RTE_ETH_DEV_BONDED_SLAVE 0x0004
 /** Device supports device removal interrupt */
 #define RTE_ETH_DEV_INTR_RMV     0x0008
+/** Device supports the rte_eth_rxq_conf offloads API */
+#define RTE_ETH_DEV_RXQ_OFFLOAD 0x0010
 
 /**
  * @internal
-- 
2.12.0

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API
@ 2017-08-07 10:54  4% Shahaf Shuler
  2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
                   ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Shahaf Shuler @ 2017-08-07 10:54 UTC (permalink / raw)
  To: dev

Tx offloads configuration is per queue. Tx offloads are enabled by default, 
and can be disabled using ETH_TXQ_FLAGS_NO* flags. 
This behaviour is not consistent with the Rx side where the Rx offloads
configuration is per port. Rx offloads are disabled by default and enabled 
according to bit field in rte_eth_rxmode structure.

Moreover, considering more Tx and Rx offloads will be added 
over time, the cost of managing them all inside the PMD will be tremendous,
as the PMD will need to check the matching for the entire offload set 
for each mbuf it handles.
In addition, on the current approach each Rx offload added breaks the
ABI compatibility as it requires to add entries to existing bit-fields.
 
The RFC address above issues by defining a new offloads API.
With the new API, Tx and Rx offloads configuration is per queue.
The offloads are disabled by default. Each offload can be enabled or
disabled using the existing DEV_TX_OFFLOADS_* or DEV_RX_OFFLOADS_* flags.
Such API will enable to easily add or remove offloads, without breaking the
ABI compatibility.

The new API does not have an equivalent for the below Tx flags:

* ETH_TXQ_FLAGS_NOREFCOUNT
* ETH_TXQ_FLAGS_NOMULTMEMP

The reason is that those flags are not to manage offloads, rather some
guarantee from application on the way it uses mbufs, therefore could not be
present as part of DEV_TX_OFFLOADS_*.
Such flags are useful only for benchmarks, and therefore provide a non-realistic    
performance for DPDK customers using simple benchmarks for evaluation.
Leveraging the work being done in this series to clean up those flags.

In order to provide a smooth transition between the APIs the following actions
were taken:
*  The old offloads API is kept for the meanwhile.
*  New capabilities were added for PMD to advertize it has moved to the new
   offloads API.
*  Helper function which copy from old to new API and vice versa were added to ethdev,
   enabling the PMD to support only one of the APIs, and the application to move to
   the new API regardless the underlying device and without extra branching.

Shahaf Shuler (4):
  ethdev: rename Rx and Tx configuration structs
  ethdev: introduce Rx queue offloads API
  ethdev: introduce Tx queue offloads API
  ethdev: add helpers to move to the new offloads API

 lib/librte_ether/rte_ethdev.c | 144 ++++++++++++++++++++++++++++++++++++-
 lib/librte_ether/rte_ethdev.h |  72 +++++++++++++++----
 2 files changed, 202 insertions(+), 14 deletions(-)

-- 
2.12.0

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-08-05 10:34  4%     ` Yang, Zhiyong
@ 2017-08-07  3:07  4%       ` Yang, Zhiyong
  2017-08-07 11:04  4%         ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Yang, Zhiyong @ 2017-08-07  3:07 UTC (permalink / raw)
  To: Yang, Zhiyong, Horton, Remy, dev; +Cc: Tan, Jianfeng, yliu, jerin.jacob, thomas

Hi, Thomas:
	Need I sent another V3 patch to update commit log according to Remy's suggestion?
Thanks
Zhiyong

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yang, Zhiyong
> Sent: Saturday, August 5, 2017 6:35 PM
> To: Horton, Remy <remy.horton@intel.com>; dev@dpdk.org
> Cc: Tan, Jianfeng <jianfeng.tan@intel.com>; yliu@fridaylinux.org;
> jerin.jacob@caviumnetworks.com; thomas@monjalon.net
> Subject: Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for
> ethdev
> 
> Hi, Remy:
> 
> > -----Original Message-----
> > From: Horton, Remy
> > Sent: Friday, August 4, 2017 2:56 PM
> > To: Yang, Zhiyong <zhiyong.yang@intel.com>; dev@dpdk.org
> > Cc: Tan, Jianfeng <jianfeng.tan@intel.com>; yliu@fridaylinux.org;
> > jerin.jacob@caviumnetworks.com; thomas@monjalon.net
> > Subject: Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change
> > for ethdev
> >
> >
> > On 04/08/2017 06:27, Zhiyong Yang wrote:
> > > This is an API/ABI change notice for DPDK 17.11 on redefinition of
> > > port_id. port_id is defined as uint8_t by now, which is just ranged
> > > from 0 to 255. For more and more scenerioes, more than 256 ports are
> > > needed to support for vdev scalability.
> > >
> > > It is necessary for redefinition of port_id to extend from 1 bytes
> > > to
> > > 2 bytes. All ethdev APIs and use cases related to port_id will be
> > > changed at the same time.
> >
> > I think this reads a little better:
> >
> > This is an API/ABI change notice for DPDK 17.11 announcing the
> > redefinition of port_id. port_id is currently defined as uint8_t,
> > which is limited to the range 0 to 255. A larger range is required for vdev
> scalability.
> >
> > It is necessary for a redefinition of port_id to extend it from 1 bytes to 2 bytes.
> > All ethdev APIs and usages related to port_id will be changed at the same time.
> 
> Thanks Remy, of course. Your statement is better. I have a lot of things  to learn
> when speaking in English. I hope I can describe things like you, a native
> speaker. :) Thanks again for your ack.
> 
> Zhiyong
> 
> >
> > >  doc/guides/rel_notes/deprecation.rst | 6 ++++++
> > >  1 file changed, 6 insertions(+)
> >
> > Acked-by: Remy Horton <remy.horton@intel.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware
  2017-08-04  5:25  0%   ` Hemant Agrawal
@ 2017-08-06 21:22  0%     ` Olivier MATZ
  2017-08-08  0:04  0%       ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Olivier MATZ @ 2017-08-06 21:22 UTC (permalink / raw)
  To: Hemant Agrawal
  Cc: santosh, Jerin Jacob, dev, thomas, stephen, bruce.richardson,
	shreyansh.jain, gaetan.rivet, sergio.gonzalez.monroy,
	anatoly.burakov

On Fri, Aug 04, 2017 at 10:55:25AM +0530, Hemant Agrawal wrote:
> On 8/4/2017 9:11 AM, santosh wrote:
> > On Tuesday 11 July 2017 03:31 PM, Jerin Jacob wrote:
> > 
> > > When we run DPDK on guest or VFIO mode on host,
> > > the dpdk library or device will not be directly accessing
> > > the physical address. Instead, the device does go through
> > > an IO address translation memory management unit. On x86,
> > > we call it as IOMMU and on ARM as SMMU.
> > > 
> > > More details:
> > > http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf
> > > 
> > > Based on discussion in the following thread
> > > http://dpdk.org/ml/archives/dev/2017-July/070850.html
> > > 
> > > We would like to change reference to physical address to more
> > > appropriate name as with IOMMU/SMMU with
> > > the device won't be dealing directly with the physical address.
> > > 
> > > An ABI change is planned for 17.11 to change following
> > > data structure or functions to more appropriate name.
> > > Currently planned to change it iova as instead of phys
> > > 
> > > Please note: The change will be only for the name and
> > > functional aspects of the API will remain same.
> > > 
> > > Following functions/data structures name may change.
> > > This list is based on v17.05-rc1. It may change based on v17.11 code base.
> > > 
> > > 
> > > typedef:
> > > phys_addr_t
> > > 
> > > structures:
> > > 
> > > struct rte_memseg::phys_addr
> > > struct rte_mbuf::buf_physaddr
> > > 
> > > functions:
> > > rte_mempool_populate_phys()
> > > rte_mempool_populate_phys_tab()
> > > rte_eal_using_phys_addrs()
> > > rte_mem_virt2phy()
> > > rte_dump_physmem_layout()
> > > rte_eal_get_physmem_layout()
> > > rte_eal_get_physmem_size()
> > > rte_malloc_virt2phy()
> > > rte_mem_phy2mch()
> > > 
> > > 
> > > Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > > ---
> > 
> > Acked-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> > 
> > 
> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> 

Acked-by: Olivier Matz <olivier.matz@6wind.com>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-08-03 14:21  4%   ` Jerin Jacob
  2017-08-03 14:30  4%     ` santosh
@ 2017-08-05 20:24  4%     ` Olivier MATZ
  2017-08-08  0:10  4%       ` Thomas Monjalon
  1 sibling, 1 reply; 200+ results
From: Olivier MATZ @ 2017-08-05 20:24 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: Santosh Shukla, dev, thomas.monjalon

On Thu, Aug 03, 2017 at 07:51:34PM +0530, Jerin Jacob wrote:
> -----Original Message-----
> > Date: Thu, 20 Jul 2017 15:59:15 +0530
> > From: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> > To: olivier.matz@6wind.com, dev@dpdk.org
> > CC: thomas.monjalon@6wind.com, Santosh Shukla
> >  <santosh.shukla@caviumnetworks.com>
> > Subject: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
> > X-Mailer: git-send-email 2.11.0
> > 
> > An API/ABI change is planned for 17.11 to change following
> > 
> > * Remove unused flag param from rte_mempool_generic_get and _put.
> > * Change data type for mempool 'flag' from int to unsigned int.
> >   Refer [1].
> > * Add struct rte_mempool * param into func rte_mempool_xmem_size,
> >   rte_mempool_xmem_usage to make it mempool aware.
> >   Refer [2].
> > 
> > [1] http://dpdk.org/dev/patchwork/patch/25603/
> > [2] http://dpdk.org/dev/patchwork/patch/25605/
> > 
> > Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> 
> Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

Acked-by: Olivier Matz <olivier.matz@6wind.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-08-04  6:56  7%   ` Remy Horton
@ 2017-08-05 10:34  4%     ` Yang, Zhiyong
  2017-08-07  3:07  4%       ` Yang, Zhiyong
  2017-08-07 15:20  4%     ` Shahaf Shuler
  1 sibling, 1 reply; 200+ results
From: Yang, Zhiyong @ 2017-08-05 10:34 UTC (permalink / raw)
  To: Horton, Remy, dev; +Cc: Tan, Jianfeng, yliu, jerin.jacob, thomas

Hi, Remy:

> -----Original Message-----
> From: Horton, Remy
> Sent: Friday, August 4, 2017 2:56 PM
> To: Yang, Zhiyong <zhiyong.yang@intel.com>; dev@dpdk.org
> Cc: Tan, Jianfeng <jianfeng.tan@intel.com>; yliu@fridaylinux.org;
> jerin.jacob@caviumnetworks.com; thomas@monjalon.net
> Subject: Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for
> ethdev
> 
> 
> On 04/08/2017 06:27, Zhiyong Yang wrote:
> > This is an API/ABI change notice for DPDK 17.11 on redefinition of
> > port_id. port_id is defined as uint8_t by now, which is just ranged
> > from 0 to 255. For more and more scenerioes, more than 256 ports are
> > needed to support for vdev scalability.
> >
> > It is necessary for redefinition of port_id to extend from 1 bytes to
> > 2 bytes. All ethdev APIs and use cases related to port_id will be
> > changed at the same time.
> 
> I think this reads a little better:
> 
> This is an API/ABI change notice for DPDK 17.11 announcing the redefinition of
> port_id. port_id is currently defined as uint8_t, which is limited to the range 0 to
> 255. A larger range is required for vdev scalability.
> 
> It is necessary for a redefinition of port_id to extend it from 1 bytes to 2 bytes.
> All ethdev APIs and usages related to port_id will be changed at the same time.

Thanks Remy, of course. Your statement is better. I have a lot of things  to learn
when speaking in English. I hope I can describe things like you, a native speaker. :)
Thanks again for your ack.
 
Zhiyong

> 
> >  doc/guides/rel_notes/deprecation.rst | 6 ++++++
> >  1 file changed, 6 insertions(+)
> 
> Acked-by: Remy Horton <remy.horton@intel.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-03 15:32  4% [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev Akhil Goyal
  2017-08-04  5:26  4% ` Hemant Agrawal
  2017-08-04  9:28  4% ` De Lara Guarch, Pablo
@ 2017-08-04 15:25  4% ` De Lara Guarch, Pablo
  2017-08-08  6:54  7%   ` Akhil Goyal
  2017-08-08  7:09  7% ` [dpdk-dev] [PATCH v2] " Akhil Goyal
  3 siblings, 1 reply; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-04 15:25 UTC (permalink / raw)
  To: Akhil Goyal, dev, Doherty, Declan, thomas, Nicolau, Radu,
	aviadye, borisp, hemant.agrawal



> -----Original Message-----
> From: Akhil Goyal [mailto:akhil.goyal@nxp.com]
> Sent: Thursday, August 3, 2017 4:32 PM
> To: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>;
> thomas@monjalon.net; Nicolau, Radu <radu.nicolau@intel.com>;
> aviadye@mellanox.com; borisp@mellanox.com;
> hemant.agrawal@nxp.com; De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com>
> Cc: Akhil Goyal <akhil.goyal@nxp.com>
> Subject: [PATCH] doc: announce ABI change for cryptodev and ethdev
> 
> Support for security operations is planned to be added in ethdev and
> cryptodev for the 17.11 release.
> 
> For this following changes are required.
> - rte_cryptodev and rte_eth_dev structures need to be added new
> parameter rte_security_ops which extend support for security ops to the
> corresponding driver.
> - rte_cryptodev_info and rte_ethd_dev_info need to be added with
> rte_security_capabilities to identify the capabilities of the corresponding
> driver.
> 
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>

Not sure if this needed to be split into two patches, as this affects two libraries.
At least, from cryptodev side:

Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v1] doc: update release notes for 17.08
@ 2017-08-04 14:20  6% John McNamara
  0 siblings, 0 replies; 200+ results
From: John McNamara @ 2017-08-04 14:20 UTC (permalink / raw)
  To: dev; +Cc: John McNamara

Fix grammar, spelling and formatting of DPDK 17.08 release notes.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 224 ++++++++++++++-------------------
 1 file changed, 94 insertions(+), 130 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 343331e..489ec44 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -41,7 +41,7 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
-* **Bumped minimal x86 ISA to SSE4.2.**
+* **Increase minimum x86 ISA version to SSE4.2.**
 
   Starting with version 17.08, DPDK requires SSE4.2 to run on x86.
   Previous versions required SSE3.
@@ -49,90 +49,92 @@ New Features
 * **Added Service Core functionality.**
 
   The service core functionality added to EAL allows DPDK to run services such
-  as SW PMDs on lcores without the application manually running them. The
+  as software PMDs on lcores without the application manually running them. The
   service core infrastructure allows flexibility of running multiple services
   on the same service lcore, and provides the application with powerful APIs to
   configure the mapping from service lcores to services.
 
 * **Added Generic Receive Offload API.**
 
-  Generic Receive Offload (GRO) API supports to reassemble TCP/IPv4
-  packets. GRO API assumes all inputted packets are with correct
+  Added Generic Receive Offload (GRO) API support to reassemble TCP/IPv4
+  packets. The GRO API assumes all input packets have the correct
   checksums. GRO API doesn't update checksums for merged packets. If
-  inputted packets are IP fragmented, GRO API assumes they are complete
+  input packets are IP fragmented, the GRO API assumes they are complete
   packets (i.e. with L4 headers).
 
-* **Added support for generic flow API (rte_flow) on igb NIC.**
+* **Added support for generic flow API (rte_flow) on igb NICs.**
 
-  This API provides a generic means to configure hardware to match specific
-  ingress or egress traffic, alter its behavior and query related counters
+  This API provides a generic means of configuring hardware to match specific
+  ingress or egress traffic, altering its behavior and querying related counters
   according to any number of user-defined rules.
 
-  * Generic flow API support for Ethernet, IPv4, UDP, TCP and
-    RAW pattern items with QUEUE actions. There are four
-    type of filter support for this feature on igb.
+  Added generic flow API support for Ethernet, IPv4, UDP, TCP and RAW pattern
+  items with QUEUE actions. There are four types of filter support for this
+  feature on igb.
 
-* **Added Generic Flow API support to enic.**
+* **Added support for generic flow API (rte_flow) on enic.**
 
-  Flow API support for outer Ethernet, VLAN, IPv4, IPv6, UDP, TCP, SCTP, VxLAN
-  and inner Ethernet, VLAN, IPv4, IPv6, UDP and TCP pattern items with QUEUE,
-  MARK, FLAG and VOID actions for ingress traffic.
+  Added flow API support for outer Ethernet, VLAN, IPv4, IPv6, UDP, TCP, SCTP,
+  VxLAN and inner Ethernet, VLAN, IPv4, IPv6, UDP and TCP pattern items with
+  QUEUE, MARK, FLAG and VOID actions for ingress traffic.
 
 * **Added support for Chelsio T6 family of adapters**
 
-  CXGBE PMD updated to run Chelsio T6 family of adapters.
+  The CXGBE PMD was updated to run Chelsio T6 family of adapters.
 
 * **Added latency and performance improvements for cxgbe**
 
-  TX and RX path reworked to improve performance.  Also reduced latency
-  for slow traffic.
+  the Tx and Rx path in cxgbe were reworked to improve performance. In
+  addition the latency was reduced for slow traffic.
 
-* **Updated bnxt PMD.**
+* **Updated the bnxt PMD.**
+
+  Updated the bnxt PMD. The major enhancements include:
 
-  Major enhancements include:
   * Support MTU modification.
-  * Support LRO.
-  * Support VLAN filter and strip functionality.
-  * Other enhancements to add support for more dev_ops.
-  * Add PMD specific APIs mainly to control VF from PF.
+  * Add support for LRO.
+  * Add support for VLAN filter and strip functionality.
+  * Additional enhancements to add support for more dev_ops.
+  * Added PMD specific APIs mainly to control VF from PF.
   * Update HWRM version to 1.7.7
 
 * **Added support for Rx interrupts on mlx4 driver.**
 
-  Rx queues can be armed with an interrupt which will trigger on the
+  Rx queues can be now be armed with an interrupt which will trigger on the
   next packet arrival.
 
 * **Updated mlx5 driver.**
 
-  Updated the mlx5 driver, include the following changes:
+  Updated the mlx5 driver including the following changes:
 
   * Added vectorized Rx/Tx burst for x86.
   * Added support for isolated mode from flow API.
-  * Re-worked flow drop action to implement in hardware classifier.
+  * Reworked the flow drop action to implement in hardware classifier.
   * Improved Rx interrupts management.
 
 * **Updated szedata2 PMD.**
 
-  Added support for firmwares with multiple Ethernet ports per physical port.
+  Added support for firmware with multiple Ethernet ports per physical port.
 
 * **Updated dpaa2 PMD.**
 
-  Major enhancements include:
-  * Support MAC Filter configuration
-  * Support Segmented Buffers
-  * Support VLAN filter and strip functionality.
-  * Other enhancements to add support for more dev_ops.
+  Updated dpaa2 PMD. Major enhancements include:
+
+  * Added support for MAC Filter configuration.
+  * Added support for Segmented Buffers.
+  * Added support for VLAN filter and strip functionality.
+  * Additional enhancements to add support for more dev_ops.
   * Optimized the packet receive path
 
 * **Reorganized the symmetric crypto operation structure.**
 
   The crypto operation (``rte_crypto_sym_op``) has been reorganized as follows:
 
-  * Removed field ``rte_crypto_sym_op_sess_type``.
-  * Replaced pointer and physical address of IV with offset from the start
+  * Removed the ``rte_crypto_sym_op_sess_type`` field.
+  * Replaced the pointer and physical address of IV with offset from the start
     of the crypto operation.
   * Moved length and offset of cipher IV to ``rte_crypto_cipher_xform``.
-  * Removed Additional Authentication Data (AAD) length.
+  * Removed "Additional Authentication Data" (AAD) length.
   * Removed digest length.
   * Removed AAD pointer and physical address from ``auth`` structure.
   * Added ``aead`` structure, containing parameters for AEAD algorithms.
@@ -141,9 +143,9 @@ New Features
 
   The crypto operation (``rte_crypto_op``) has been reorganized as follows:
 
-  * Added field ``rte_crypto_op_sess_type``.
-  * Enumerations ``rte_crypto_op_status`` and ``rte_crypto_op_type``
-    have been modified to be uint8_t values.
+  * Added the ``rte_crypto_op_sess_type`` field.
+  * The enumerations ``rte_crypto_op_status`` and ``rte_crypto_op_type``
+    have been modified to be ``uint8_t`` values.
   * Removed the field ``opaque_data``.
   * Pointer to ``rte_crypto_sym_op`` has been replaced with a zero length array.
 
@@ -152,9 +154,9 @@ New Features
   The crypto symmetric session structure (``rte_cryptodev_sym_session``) has
   been reorganized as follows:
 
-  * ``dev_id`` field has been removed.
-  * ``driver_id`` field has been removed.
-  * Mempool pointer ``mp`` has been removed.
+  * The ``dev_id`` field has been removed.
+  * The ``driver_id`` field has been removed.
+  * The mempool pointer ``mp`` has been removed.
   * Replaced ``private`` marker with array of pointers to private data sessions
     ``sess_private_data``.
 
@@ -167,25 +169,23 @@ New Features
   * Added support for multi-device sessions, so a single session can be
     used in multiple drivers.
   * Added functions to initialize and free individual driver private data
-    with a same session.
+    with the same session.
 
 * **Updated dpaa2_sec crypto PMD.**
 
-  Added support for AES-GCM and AES-CTR
+  Added support for AES-GCM and AES-CTR.
 
 * **Updated the AESNI MB PMD.**
 
   The AESNI MB PMD has been updated with additional support for:
 
-    * 12-byte IV on AES Counter Mode, apart from the previous 16-byte IV.
+  * 12-byte IV on AES Counter Mode, apart from the previous 16-byte IV.
 
 * **Updated the AES-NI GCM PMD.**
 
   The AES-NI GCM PMD was migrated from the ISA-L library to the Multi Buffer
   library, as the latter library has Scatter Gather List support
-  now. The migration entailed adding additional support for:
-
-  * 192-bit key.
+  now. The migration entailed adding additional support for 192-bit keys.
 
 * **Updated the Cryptodev Scheduler PMD.**
 
@@ -206,46 +206,6 @@ New Features
   eventdev devices.
 
 
-Resolved Issues
----------------
-
-.. This section should contain bug fixes added to the relevant
-   sections. Sample format:
-
-   * **code/section Fixed issue in the past tense with a full stop.**
-
-     Add a short 1-2 sentence description of the resolved issue in the past
-     tense.
-
-     The title should contain the code/lib section like a commit message.
-
-     Add the entries in alphabetic order in the relevant sections below.
-
-   This section is a comment. do not overwrite or remove it.
-   Also, make sure to start the actual text at the margin.
-   =========================================================
-
-
-EAL
-~~~
-
-
-Drivers
-~~~~~~~
-
-
-Libraries
-~~~~~~~~~
-
-
-Examples
-~~~~~~~~
-
-
-Other
-~~~~~
-
-
 Known Issues
 ------------
 
@@ -278,35 +238,35 @@ API Changes
 
 * **Modified the _rte_eth_dev_callback_process function in the ethdev library.**
 
-  The function ``_rte_eth_dev_callback_process()`` has been modified. The return
-  value has been changed from void to int and an extra parameter ``void *ret_param``
-  has been added.
+  The function ``_rte_eth_dev_callback_process()`` has been modified. The
+  return value has been changed from void to int and an extra parameter ``void
+  *ret_param`` has been added.
 
 * **Moved bypass functions from the rte_ethdev library to ixgbe PMD**
 
   * The following rte_ethdev library functions were removed:
 
-    * ``rte_eth_dev_bypass_event_show``
-    * ``rte_eth_dev_bypass_event_store``
-    * ``rte_eth_dev_bypass_init``
-    * ``rte_eth_dev_bypass_state_set``
-    * ``rte_eth_dev_bypass_state_show``
-    * ``rte_eth_dev_bypass_ver_show``
-    * ``rte_eth_dev_bypass_wd_reset``
-    * ``rte_eth_dev_bypass_wd_timeout_show``
-    * ``rte_eth_dev_wd_timeout_store``
+    * ``rte_eth_dev_bypass_event_show()``
+    * ``rte_eth_dev_bypass_event_store()``
+    * ``rte_eth_dev_bypass_init()``
+    * ``rte_eth_dev_bypass_state_set()``
+    * ``rte_eth_dev_bypass_state_show()``
+    * ``rte_eth_dev_bypass_ver_show()``
+    * ``rte_eth_dev_bypass_wd_reset()``
+    * ``rte_eth_dev_bypass_wd_timeout_show()``
+    * ``rte_eth_dev_wd_timeout_store()``
 
   * The following ixgbe PMD functions were added:
 
-    * ``rte_pmd_ixgbe_bypass_event_show``
-    * ``rte_pmd_ixgbe_bypass_event_store``
-    * ``rte_pmd_ixgbe_bypass_init``
-    * ``rte_pmd_ixgbe_bypass_state_set``
-    * ``rte_pmd_ixgbe_bypass_state_show``
-    * ``rte_pmd_ixgbe_bypass_ver_show``
-    * ``rte_pmd_ixgbe_bypass_wd_reset``
-    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
-    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
+    * ``rte_pmd_ixgbe_bypass_event_show()``
+    * ``rte_pmd_ixgbe_bypass_event_store()``
+    * ``rte_pmd_ixgbe_bypass_init()``
+    * ``rte_pmd_ixgbe_bypass_state_set()``
+    * ``rte_pmd_ixgbe_bypass_state_show()``
+    * ``rte_pmd_ixgbe_bypass_ver_show()``
+    * ``rte_pmd_ixgbe_bypass_wd_reset()``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show()``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store()``
 
 * **Reworked rte_cryptodev library.**
 
@@ -318,18 +278,21 @@ API Changes
     by the new function ``rte_crypto_count_by_driver()``.
   * Moved crypto device driver names definitions to the particular PMDs.
     These names are not public anymore.
-  * ``rte_cryptodev_configure()`` does not create the session mempool
-    for the device anymore.
-  * ``rte_cryptodev_queue_pair_attach_sym_session()`` and
+  * The ``rte_cryptodev_configure()`` function does not create the session
+    mempool for the device anymore.
+  * The ``rte_cryptodev_queue_pair_attach_sym_session()`` and
     ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
     the new parameter ``device id``.
-  * Modified parameters of ``rte_cryptodev_sym_session_create()``, to accept
-    ``mempool``, instead of ``device id`` and ``rte_crypto_sym_xform``.
-  * Remove ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
-  * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
-  * Removed ``aad_size`` parameter from ``rte_cryptodev_sym_capability_check_auth()``.
-  * Added ``iv_size`` parameter to ``rte_cryptodev_sym_capability_check_auth()``.
-  * Removed ``RTE_CRYPTO_OP_STATUS_ENQUEUED`` from enum ``rte_crypto_op_status``.
+  * Parameters of ``rte_cryptodev_sym_session_create()`` were modified to
+    accept ``mempool``, instead of ``device id`` and ``rte_crypto_sym_xform``.
+  * Removed ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
+  * Added a new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
+  * Removed ``aad_size`` parameter from
+    ``rte_cryptodev_sym_capability_check_auth()``.
+  * Added ``iv_size`` parameter to
+    ``rte_cryptodev_sym_capability_check_auth()``.
+  * Removed ``RTE_CRYPTO_OP_STATUS_ENQUEUED`` from enum
+    ``rte_crypto_op_status``.
 
 
 ABI Changes
@@ -347,28 +310,29 @@ ABI Changes
 
 * **Reorganized the crypto operation structures.**
 
-  Some fields have been modified in the ``rte_crypto_op`` and ``rte_crypto_sym_op``
-  structures, as described in the `New Features`_ section.
+  Some fields have been modified in the ``rte_crypto_op`` and
+  ``rte_crypto_sym_op`` structures, as described in the `New Features`_
+  section.
 
 * **Reorganized the crypto symmetric session structure.**
 
   Some fields have been modified in the ``rte_cryptodev_sym_session``
   structure, as described in the `New Features`_ section.
 
-* **Reorganized the ``rte_crypto_sym_cipher_xform`` structure.**
+* **Reorganized the rte_crypto_sym_cipher_xform structure.**
 
   * Added cipher IV length and offset parameters.
-  * Changed field size of key length from size_t to uint16_t.
+  * Changed field size of key length from ``size_t`` to ``uint16_t``.
 
-* **Reorganized the ``rte_crypto_sym_auth_xform`` structure.**
+* **Reorganized the rte_crypto_sym_auth_xform structure.**
 
   * Added authentication IV length and offset parameters.
-  * Changed field size of AAD length from uint32_t to uint16_t.
-  * Changed field size of digest length from uint32_t to uint16_t.
+  * Changed field size of AAD length from ``uint32_t`` to ``uint16_t``.
+  * Changed field size of digest length from ``uint32_t`` to ``uint16_t``.
   * Removed AAD length.
-  * Changed field size of key length from size_t to uint16_t.
+  * Changed field size of key length from ``size_t`` to ``uint16_t``.
 
-* Replaced ``dev_type`` enumeration with uint8_t ``driver_id`` in
+* Replaced ``dev_type`` enumeration with ``uint8_t`` ``driver_id`` in
   ``rte_cryptodev_info`` and  ``rte_cryptodev`` structures.
 
 * Removed ``session_mp`` from ``rte_cryptodev_config``.
@@ -521,7 +485,8 @@ Tested Platforms
        * Device ID: 15b3:1013
        * Firmware version: 12.18.2000
 
-     * Mellanox(R) ConnectX(R)-4 50G MCX415A-GCAT/MCX416A-BCAT/MCX416A-GCAT (2x50G)
+     * Mellanox(R) ConnectX(R)-4 50G MCX415A-GCAT/MCX416A-BCAT/MCX416A-GCAT
+       (2x50G)
 
        * Host interface: PCI Express 3.0 x16
        * Device ID: 15b3:1013
@@ -631,4 +596,3 @@ Tested Platforms
        * Firmware version: 1.48, 0x800006e7
        * Device id (pf/vf): 8086:1521 / 8086:1520
        * Driver version: 5.2.13-k (igb)
-
-- 
2.7.4

^ permalink raw reply	[relevance 6%]

* [dpdk-dev] [PATCH] doc: announce rte_devargs changes in 17.11
@ 2017-08-04 13:29  5% Gaetan Rivet
  2017-08-07 23:18  0% ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Gaetan Rivet @ 2017-08-04 13:29 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 doc/guides/rel_notes/deprecation.rst | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 7024c81..9e063f1 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -57,3 +57,15 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_cryptodev_create_vdev``
+
+* eal: several API and ABI changes are planned for ``rte_devargs`` in v17.11.
+  The format of device command line parameters will change. The bus will need
+  to be explicitly stated in the device declaration. The enum ``rte_devtype``
+  was used to identify a bus and will disappear.
+  The structure ``rte_devargs`` will change.
+  The ``rte_devargs_list`` will be made private.
+  The following functions are deprecated starting from 17.08 and will either be
+  modified or removed in 17.11:
+
+  - ``rte_eal_devargs_add``
+  - ``rte_eal_devargs_type_count``
-- 
2.1.4

^ permalink raw reply	[relevance 5%]

* [dpdk-dev] [PATCH] doc: remove planned devargs changes for v17.08
@ 2017-08-04 13:29  5% Gaetan Rivet
  0 siblings, 0 replies; 200+ results
From: Gaetan Rivet @ 2017-08-04 13:29 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

These changes have been implemented.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 doc/guides/rel_notes/deprecation.rst | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 72aa404..7024c81 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -16,13 +16,6 @@ Deprecation Notices
   - ``rte_set_log_type``, replaced by ``rte_log_set_level``
   - ``rte_get_log_type``, replaced by ``rte_log_get_level``
 
-* devargs: An ABI change is planned for 17.08 for the structure ``rte_devargs``.
-  The current version is dependent on bus-specific device identifier, which will
-  be made generic and abstracted, in order to make the EAL bus-agnostic.
-
-  Accompanying this evolution, device command line parameters will thus support
-  explicit bus definition in a device declaration.
-
 * The VDEV subsystem will be converted as driver of the new bus model.
   It may imply some EAL API changes in 17.08.
 
-- 
2.1.4

^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-04 11:58  0%       ` Ferruh Yigit
@ 2017-08-04 12:56  0%         ` Bruce Richardson
  2017-08-08  8:32  0%           ` Ferruh Yigit
  2017-08-08 17:23  2%         ` Wiles, Keith
  2017-08-08 17:28  0%         ` Wiles, Keith
  2 siblings, 1 reply; 200+ results
From: Bruce Richardson @ 2017-08-04 12:56 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Thomas Monjalon, dev, Stephen Hemminger, Chilikin, Andrey,
	Ananyev, Konstantin, Wu, Jingjing

On Fri, Aug 04, 2017 at 12:58:01PM +0100, Ferruh Yigit wrote:
> On 8/3/2017 8:53 PM, Thomas Monjalon wrote:
> > 03/08/2017 18:15, Stephen Hemminger:
> >> On Thu, 3 Aug 2017 14:21:38 +0100
> >> Bruce Richardson <bruce.richardson@intel.com> wrote:
> >>
> >>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
> >>>> To control some device-specific features public device-specific functions
> >>>> rte_pmd_*.h are used.
> >>>>
> >>>> But this solution requires applications to distinguish devices at runtime
> >>>> and, depending on the device type, call corresponding device-specific
> >>>> functions even if functions' parameters are the same.
> >>>>
> >>>> IOCTL-like API can be added to ethdev instead of public device-specific
> >>>> functions to address the following:
> >>>>
> >>>> * allow more usable support of features across a range of NIC from
> >>>>   one vendor, but not others
> >>>> * allow features to be implemented by multiple NIC drivers without
> >>>>   relying on a critical mass to get the functionality in ethdev
> >>>> * there are a large number of possible device specific functions, and
> >>>>   creating individual APIs for each one is not a good solution
> >>>> * IOCTLs are a proven method for solving this problem in other areas,
> >>>>   i.e. OS kernels.
> >>>>
> >>>> Control requests for this API will be globally defined at ethdev level, so
> >>>> an application will use single API call to control different devices from
> >>>> one/multiple vendors.
> >>>>
> >>>> API call may look like as a classic ioctl with an extra parameter for
> >>>> argument length for better sanity checks:
> >>>>
> >>>> int
> >>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> >>>>         unsigned arg_length);
> >>>>
> >>>> Regards,
> >>>> Andrey  
> >>>
> >>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
> >>> to admit it, since I dislike IOCTLs and other functions with opaque
> >>> arguments! Having driver specific functions I don't think will scale
> >>> well as each vendor tries to expose as much of their driver specific
> >>> functionality as possible.
> >>>
> >>> One other additional example: I discovered just this week another issue
> >>> with driver specific functions and testpmd, when I was working on the
> >>> meson build rework.
> >>>
> >>> * With shared libraries, when we do "ninja install" we want our DPDK
> >>>   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> >>>   driver folder, so that they can be automatically loaded from that
> >>>   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> >>> * However, testpmd, as well as using the drivers as plugins, uses
> >>>   driver-specific functions, which means that it explicitly links
> >>>   against the pmd .so files.
> >>> * Those driver .so files are not in with the other libraries, so ld.so
> >>>   does not find the pmd, and the installed testpmd fails to run due to
> >>>   missing library dependencies.
> >>> * The workaround is to add the drivers path to the ld load path, but we
> >>>   should not require ld library path changes just to get DPDK apps to
> >>>   work.
> >>>
> >>> Using ioctls instead of driver-specific functions would solve this.
> >>>
> >>> My 2c.
> >>
> >> My 2c. No.
> >>
> >> Short answer:
> >> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> >> despised by Linux kernel developers. They provide an unstructured, unsecured,
> >> back door for device driver abuse. Try to get a new driver in Linux with
> >> a unique ioctl, and it will be hard to get accepted.
> >>
> >> Long answer:
> >> So far every device specific feature has fit into ethdev model. Doing ioctl
> >> is admitting "it is too hard to be general, we need need an out". For something
> >> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
> >> For a real feature (think flow direction), we want a first class API for that.
> >> For a wart, then devargs will do.
> >>
> >> Give a good example of something that should be an ioctl. Don't build the
> >> API first and then let it get cluttered.
> > 
> > I agree with Stephen.
> > 
> > And please do not forget that ioctl still requires an API:
> > the argument that you put in ioctl is the API of the feature.
> > So it is the same thing as defining a new function.
> 
> I am also not fan of the ioctl usage. I believe it hides APIs behind ids
> and prevent argument check by compiler.
> 
> BUT, the number of the increasing PMD specific APIs are also worrying,
> it is becoming harder to maintain, and I believe this is something NOT
> sustainable in long run.
> 
> 
> What about having *eth_dev_extended_ops* ?
> 
> 
> As a part of the rte_eth_dev. This can be in the librte_ether library
> but in a separated file.
> 
> And the APIs for these ops can be less strict on compatibility, and
> easier to add.
> 
> Benefits of having this new dev_ops:
> 
> * Having an abstraction layer for common checks.
> 
> * Even feature is not generic for all NICs, still a few NICs can share
> the ops.
> 
> * All APIs are in the same file makes it easy to see PMD specific APIs
> comparing to scattered into various PMDs.
> 
> * This is very like ioctl approach, but APIs are more clear and
> arguments can be verified.
> 

Sounds like an ethdev-staging library, where features can be put until
such time as they get critical mass for acceptance and promoted to
ethdev? It's sounds better than IOCTL, while giving the same benefits.

I'd be happy enough with any solution that allows NIC features to be
exposed that does not have functions limited to each individual driver,
so that common functionality can be exposed to apps via an API even if
only 2 drivers support it.

> Thanks,
> ferruh
> 
> 
> > 
> > The real debate is to decide if we want to continue adding more
> > control path features in DPDK or focus on Rx/Tx.
I don't see dropping control path as an option. It would severely limit
the usefulness of DPDK.

/Bruce

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-03 19:53  0%     ` Thomas Monjalon
  2017-08-04  9:59  0%       ` Chilikin, Andrey
@ 2017-08-04 11:58  0%       ` Ferruh Yigit
  2017-08-04 12:56  0%         ` Bruce Richardson
                           ` (2 more replies)
  1 sibling, 3 replies; 200+ results
From: Ferruh Yigit @ 2017-08-04 11:58 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Stephen Hemminger, Bruce Richardson, Chilikin, Andrey, Ananyev,
	Konstantin, Wu, Jingjing

On 8/3/2017 8:53 PM, Thomas Monjalon wrote:
> 03/08/2017 18:15, Stephen Hemminger:
>> On Thu, 3 Aug 2017 14:21:38 +0100
>> Bruce Richardson <bruce.richardson@intel.com> wrote:
>>
>>> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
>>>> To control some device-specific features public device-specific functions
>>>> rte_pmd_*.h are used.
>>>>
>>>> But this solution requires applications to distinguish devices at runtime
>>>> and, depending on the device type, call corresponding device-specific
>>>> functions even if functions' parameters are the same.
>>>>
>>>> IOCTL-like API can be added to ethdev instead of public device-specific
>>>> functions to address the following:
>>>>
>>>> * allow more usable support of features across a range of NIC from
>>>>   one vendor, but not others
>>>> * allow features to be implemented by multiple NIC drivers without
>>>>   relying on a critical mass to get the functionality in ethdev
>>>> * there are a large number of possible device specific functions, and
>>>>   creating individual APIs for each one is not a good solution
>>>> * IOCTLs are a proven method for solving this problem in other areas,
>>>>   i.e. OS kernels.
>>>>
>>>> Control requests for this API will be globally defined at ethdev level, so
>>>> an application will use single API call to control different devices from
>>>> one/multiple vendors.
>>>>
>>>> API call may look like as a classic ioctl with an extra parameter for
>>>> argument length for better sanity checks:
>>>>
>>>> int
>>>> rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
>>>>         unsigned arg_length);
>>>>
>>>> Regards,
>>>> Andrey  
>>>
>>> I think we need to start putting in IOCTLs for ethdevs, much as I hate
>>> to admit it, since I dislike IOCTLs and other functions with opaque
>>> arguments! Having driver specific functions I don't think will scale
>>> well as each vendor tries to expose as much of their driver specific
>>> functionality as possible.
>>>
>>> One other additional example: I discovered just this week another issue
>>> with driver specific functions and testpmd, when I was working on the
>>> meson build rework.
>>>
>>> * With shared libraries, when we do "ninja install" we want our DPDK
>>>   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
>>>   driver folder, so that they can be automatically loaded from that
>>>   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
>>> * However, testpmd, as well as using the drivers as plugins, uses
>>>   driver-specific functions, which means that it explicitly links
>>>   against the pmd .so files.
>>> * Those driver .so files are not in with the other libraries, so ld.so
>>>   does not find the pmd, and the installed testpmd fails to run due to
>>>   missing library dependencies.
>>> * The workaround is to add the drivers path to the ld load path, but we
>>>   should not require ld library path changes just to get DPDK apps to
>>>   work.
>>>
>>> Using ioctls instead of driver-specific functions would solve this.
>>>
>>> My 2c.
>>
>> My 2c. No.
>>
>> Short answer:
>> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
>> despised by Linux kernel developers. They provide an unstructured, unsecured,
>> back door for device driver abuse. Try to get a new driver in Linux with
>> a unique ioctl, and it will be hard to get accepted.
>>
>> Long answer:
>> So far every device specific feature has fit into ethdev model. Doing ioctl
>> is admitting "it is too hard to be general, we need need an out". For something
>> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
>> For a real feature (think flow direction), we want a first class API for that.
>> For a wart, then devargs will do.
>>
>> Give a good example of something that should be an ioctl. Don't build the
>> API first and then let it get cluttered.
> 
> I agree with Stephen.
> 
> And please do not forget that ioctl still requires an API:
> the argument that you put in ioctl is the API of the feature.
> So it is the same thing as defining a new function.

I am also not fan of the ioctl usage. I believe it hides APIs behind ids
and prevent argument check by compiler.

BUT, the number of the increasing PMD specific APIs are also worrying,
it is becoming harder to maintain, and I believe this is something NOT
sustainable in long run.


What about having *eth_dev_extended_ops* ?


As a part of the rte_eth_dev. This can be in the librte_ether library
but in a separated file.

And the APIs for these ops can be less strict on compatibility, and
easier to add.

Benefits of having this new dev_ops:

* Having an abstraction layer for common checks.

* Even feature is not generic for all NICs, still a few NICs can share
the ops.

* All APIs are in the same file makes it easy to see PMD specific APIs
comparing to scattered into various PMDs.

* This is very like ioctl approach, but APIs are more clear and
arguments can be verified.

Thanks,
ferruh


> 
> The real debate is to decide if we want to continue adding more
> control path features in DPDK or focus on Rx/Tx.
> But this discussion would be better lead with some examples/requests.
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-04  9:59  0%       ` Chilikin, Andrey
@ 2017-08-04 10:08  0%         ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-04 10:08 UTC (permalink / raw)
  To: Chilikin, Andrey
  Cc: dev, Stephen Hemminger, Richardson, Bruce, Ananyev, Konstantin,
	Wu, Jingjing

04/08/2017 11:59, Chilikin, Andrey:
> > 03/08/2017 18:15, Stephen Hemminger:
> > > On Thu, 3 Aug 2017 14:21:38 +0100
> > > Bruce Richardson <bruce.richardson@intel.com> wrote:
> > >
> > > > On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
> > > > > To control some device-specific features public device-specific
> > functions
> > > > > rte_pmd_*.h are used.
> > > > >
> > > > > But this solution requires applications to distinguish devices at runtime
> > > > > and, depending on the device type, call corresponding device-specific
> > > > > functions even if functions' parameters are the same.
> > > > >
> > > > > IOCTL-like API can be added to ethdev instead of public device-specific
> > > > > functions to address the following:
> > > > >
> > > > > * allow more usable support of features across a range of NIC from
> > > > >   one vendor, but not others
> > > > > * allow features to be implemented by multiple NIC drivers without
> > > > >   relying on a critical mass to get the functionality in ethdev
> > > > > * there are a large number of possible device specific functions, and
> > > > >   creating individual APIs for each one is not a good solution
> > > > > * IOCTLs are a proven method for solving this problem in other areas,
> > > > >   i.e. OS kernels.
> > > > >
> > > > > Control requests for this API will be globally defined at ethdev level, so
> > > > > an application will use single API call to control different devices from
> > > > > one/multiple vendors.
> > > > >
> > > > > API call may look like as a classic ioctl with an extra parameter for
> > > > > argument length for better sanity checks:
> > > > >
> > > > > int
> > > > > rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> > > > >         unsigned arg_length);
> > > > >
> > > > > Regards,
> > > > > Andrey
> > > >
> > > > I think we need to start putting in IOCTLs for ethdevs, much as I hate
> > > > to admit it, since I dislike IOCTLs and other functions with opaque
> > > > arguments! Having driver specific functions I don't think will scale
> > > > well as each vendor tries to expose as much of their driver specific
> > > > functionality as possible.
> > > >
> > > > One other additional example: I discovered just this week another issue
> > > > with driver specific functions and testpmd, when I was working on the
> > > > meson build rework.
> > > >
> > > > * With shared libraries, when we do "ninja install" we want our DPDK
> > > >   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> > > >   driver folder, so that they can be automatically loaded from that
> > > >   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> > > > * However, testpmd, as well as using the drivers as plugins, uses
> > > >   driver-specific functions, which means that it explicitly links
> > > >   against the pmd .so files.
> > > > * Those driver .so files are not in with the other libraries, so ld.so
> > > >   does not find the pmd, and the installed testpmd fails to run due to
> > > >   missing library dependencies.
> > > > * The workaround is to add the drivers path to the ld load path, but we
> > > >   should not require ld library path changes just to get DPDK apps to
> > > >   work.
> > > >
> > > > Using ioctls instead of driver-specific functions would solve this.
> > > >
> > > > My 2c.
> > >
> > > My 2c. No.
> > >
> > > Short answer:
> > > Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> > > despised by Linux kernel developers. They provide an unstructured,
> > unsecured,
> > > back door for device driver abuse. Try to get a new driver in Linux with
> > > a unique ioctl, and it will be hard to get accepted.
> > >
> > > Long answer:
> > > So far every device specific feature has fit into ethdev model. Doing ioctl
> > > is admitting "it is too hard to be general, we need need an out". For
> > something
> > > that is a flag, it should fit into existing config model; ignoring silly ABI
> > constraints.
> > > For a real feature (think flow direction), we want a first class API for that.
> > > For a wart, then devargs will do.
> > >
> > > Give a good example of something that should be an ioctl. Don't build the
> > > API first and then let it get cluttered.
> > 
> > I agree with Stephen.
> > 
> > And please do not forget that ioctl still requires an API:
> > the argument that you put in ioctl is the API of the feature.
> > So it is the same thing as defining a new function.
> > 
> > The real debate is to decide if we want to continue adding more
> > control path features in DPDK or focus on Rx/Tx.
> > But this discussion would be better lead with some examples/requests.
> 
> In addition to what Bruce mentioned above, anything that requires dynamic re-configuration at run time would be a good example:
> * Internal resources partitioning, for example, RX buffers allocation for different traffic classes/flow types, depending on the load
> * Mapping user priorities from different sources (VLAN's PCP bits, IP DSCP, MPLS Exp) to traffic classes
> * Dynamic queue regions allocation for traffic classes
> * Dynamic statistics allocation
> * Dynamic flow types configuration depending on loaded parser profile

Why should it be device-specific?
If capabilities are well advertised, it could be generic.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-03 19:53  0%     ` Thomas Monjalon
@ 2017-08-04  9:59  0%       ` Chilikin, Andrey
  2017-08-04 10:08  0%         ` Thomas Monjalon
  2017-08-04 11:58  0%       ` Ferruh Yigit
  1 sibling, 1 reply; 200+ results
From: Chilikin, Andrey @ 2017-08-04  9:59 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Stephen Hemminger, Richardson, Bruce, Ananyev, Konstantin, Wu, Jingjing

> 03/08/2017 18:15, Stephen Hemminger:
> > On Thu, 3 Aug 2017 14:21:38 +0100
> > Bruce Richardson <bruce.richardson@intel.com> wrote:
> >
> > > On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
> > > > To control some device-specific features public device-specific
> functions
> > > > rte_pmd_*.h are used.
> > > >
> > > > But this solution requires applications to distinguish devices at runtime
> > > > and, depending on the device type, call corresponding device-specific
> > > > functions even if functions' parameters are the same.
> > > >
> > > > IOCTL-like API can be added to ethdev instead of public device-specific
> > > > functions to address the following:
> > > >
> > > > * allow more usable support of features across a range of NIC from
> > > >   one vendor, but not others
> > > > * allow features to be implemented by multiple NIC drivers without
> > > >   relying on a critical mass to get the functionality in ethdev
> > > > * there are a large number of possible device specific functions, and
> > > >   creating individual APIs for each one is not a good solution
> > > > * IOCTLs are a proven method for solving this problem in other areas,
> > > >   i.e. OS kernels.
> > > >
> > > > Control requests for this API will be globally defined at ethdev level, so
> > > > an application will use single API call to control different devices from
> > > > one/multiple vendors.
> > > >
> > > > API call may look like as a classic ioctl with an extra parameter for
> > > > argument length for better sanity checks:
> > > >
> > > > int
> > > > rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> > > >         unsigned arg_length);
> > > >
> > > > Regards,
> > > > Andrey
> > >
> > > I think we need to start putting in IOCTLs for ethdevs, much as I hate
> > > to admit it, since I dislike IOCTLs and other functions with opaque
> > > arguments! Having driver specific functions I don't think will scale
> > > well as each vendor tries to expose as much of their driver specific
> > > functionality as possible.
> > >
> > > One other additional example: I discovered just this week another issue
> > > with driver specific functions and testpmd, when I was working on the
> > > meson build rework.
> > >
> > > * With shared libraries, when we do "ninja install" we want our DPDK
> > >   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> > >   driver folder, so that they can be automatically loaded from that
> > >   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> > > * However, testpmd, as well as using the drivers as plugins, uses
> > >   driver-specific functions, which means that it explicitly links
> > >   against the pmd .so files.
> > > * Those driver .so files are not in with the other libraries, so ld.so
> > >   does not find the pmd, and the installed testpmd fails to run due to
> > >   missing library dependencies.
> > > * The workaround is to add the drivers path to the ld load path, but we
> > >   should not require ld library path changes just to get DPDK apps to
> > >   work.
> > >
> > > Using ioctls instead of driver-specific functions would solve this.
> > >
> > > My 2c.
> >
> > My 2c. No.
> >
> > Short answer:
> > Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> > despised by Linux kernel developers. They provide an unstructured,
> unsecured,
> > back door for device driver abuse. Try to get a new driver in Linux with
> > a unique ioctl, and it will be hard to get accepted.
> >
> > Long answer:
> > So far every device specific feature has fit into ethdev model. Doing ioctl
> > is admitting "it is too hard to be general, we need need an out". For
> something
> > that is a flag, it should fit into existing config model; ignoring silly ABI
> constraints.
> > For a real feature (think flow direction), we want a first class API for that.
> > For a wart, then devargs will do.
> >
> > Give a good example of something that should be an ioctl. Don't build the
> > API first and then let it get cluttered.
> 
> I agree with Stephen.
> 
> And please do not forget that ioctl still requires an API:
> the argument that you put in ioctl is the API of the feature.
> So it is the same thing as defining a new function.
> 
> The real debate is to decide if we want to continue adding more
> control path features in DPDK or focus on Rx/Tx.
> But this discussion would be better lead with some examples/requests.

In addition to what Bruce mentioned above, anything that requires dynamic re-configuration at run time would be a good example:
* Internal resources partitioning, for example, RX buffers allocation for different traffic classes/flow types, depending on the load
* Mapping user priorities from different sources (VLAN's PCP bits, IP DSCP, MPLS Exp) to traffic classes
* Dynamic queue regions allocation for traffic classes
* Dynamic statistics allocation
* Dynamic flow types configuration depending on loaded parser profile

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-03 15:32  4% [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev Akhil Goyal
  2017-08-04  5:26  4% ` Hemant Agrawal
@ 2017-08-04  9:28  4% ` De Lara Guarch, Pablo
  2017-08-04 15:25  4% ` De Lara Guarch, Pablo
  2017-08-08  7:09  7% ` [dpdk-dev] [PATCH v2] " Akhil Goyal
  3 siblings, 0 replies; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-04  9:28 UTC (permalink / raw)
  To: Akhil Goyal, dev, Doherty, Declan, thomas, Nicolau, Radu,
	aviadye, borisp, hemant.agrawal



> -----Original Message-----
> From: Akhil Goyal [mailto:akhil.goyal@nxp.com]
> Sent: Thursday, August 3, 2017 4:32 PM
> To: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>;
> thomas@monjalon.net; Nicolau, Radu <radu.nicolau@intel.com>;
> aviadye@mellanox.com; borisp@mellanox.com;
> hemant.agrawal@nxp.com; De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com>
> Cc: Akhil Goyal <akhil.goyal@nxp.com>
> Subject: [PATCH] doc: announce ABI change for cryptodev and ethdev
> 
> Support for security operations is planned to be added in ethdev and
> cryptodev for the 17.11 release.
> 
> For this following changes are required.
> - rte_cryptodev and rte_eth_dev structures need to be added new
> parameter rte_security_ops which extend support for security ops to the
> corresponding driver.
> - rte_cryptodev_info and rte_ethd_dev_info need to be added with
> rte_security_capabilities to identify the capabilities of the corresponding
> driver.
> 
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>

Boris, Aviad, could you review this patch?

Thanks,
Pablo

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-08-04  5:27 13% ` [dpdk-dev] [PATCH v2] " Zhiyong Yang
@ 2017-08-04  6:56  7%   ` Remy Horton
  2017-08-05 10:34  4%     ` Yang, Zhiyong
  2017-08-07 15:20  4%     ` Shahaf Shuler
  2017-08-07 12:42 13%   ` [dpdk-dev] [PATCH v3] " Zhiyong Yang
  1 sibling, 2 replies; 200+ results
From: Remy Horton @ 2017-08-04  6:56 UTC (permalink / raw)
  To: Zhiyong Yang, dev; +Cc: jianfeng.tan, yliu, jerin.jacob, thomas


On 04/08/2017 06:27, Zhiyong Yang wrote:
> This is an API/ABI change notice for DPDK 17.11 on redefinition of
> port_id. port_id is defined as uint8_t by now, which is just ranged
> from 0 to 255. For more and more scenerioes, more than 256 ports are
> needed to support for vdev scalability.
>
> It is necessary for redefinition of port_id to extend from 1 bytes
> to 2 bytes. All ethdev APIs and use cases related to port_id will be
> changed at the same time.

I think this reads a little better:

This is an API/ABI change notice for DPDK 17.11 announcing the 
redefinition of port_id. port_id is currently defined as uint8_t, which 
is limited to the range 0 to 255. A larger range is required for vdev 
scalability.

It is necessary for a redefinition of port_id to extend it from 1 bytes 
to 2 bytes. All ethdev APIs and usages related to port_id will be 
changed at the same time.

>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>  1 file changed, 6 insertions(+)

Acked-by: Remy Horton <remy.horton@intel.com>

^ permalink raw reply	[relevance 7%]

* Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
  2017-08-04  4:07  9% ` Yuanhan Liu
  2017-08-04  4:13  4%   ` Jerin Jacob
@ 2017-08-04  5:36  4%   ` Yang, Zhiyong
  1 sibling, 0 replies; 200+ results
From: Yang, Zhiyong @ 2017-08-04  5:36 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Wang, Zhihong, Mcnamara, John, thomas, Olivier Matz

Hi, yuanhan:

> -----Original Message-----
> From: Yuanhan Liu [mailto:yliu@fridaylinux.org]
> Sent: Friday, August 4, 2017 12:07 PM
> To: Yang, Zhiyong <zhiyong.yang@intel.com>
> Cc: dev@dpdk.org; Wang, Zhihong <zhihong.wang@intel.com>; Mcnamara,
> John <john.mcnamara@intel.com>; oilvier.matz@6wind.com;
> thomas@monjalon.net
> Subject: Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
> 
> On Wed, Jul 12, 2017 at 03:58:46PM +0800, Zhiyong Yang wrote:
> >   This is an API/ABI change notice for DPDK 17.11 on redefinition of
> 
> Don't put 2 whitespace char indentation here.
> 
> > port_id. port_id is defined as uint8_t by now, which is just ranged
> > from 0 to 255. For more and more scenerioes, more than 256 devices are
> > needed to support for vdev scalability.
> >
> >   It is necessary for redefinition of port_id to extend from 1 bytes
> > to 2 bytes. All ethdev APIs and use cases related to port_id will be
> > changed at the same time.
> >
> > Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
> > ---
> >  doc/guides/rel_notes/deprecation.rst | 4 ++++
> >  1 file changed, 4 insertions(+)
> >
> > diff --git a/doc/guides/rel_notes/deprecation.rst
> > b/doc/guides/rel_notes/deprecation.rst
> > index 257dcba..f265980 100644
> > --- a/doc/guides/rel_notes/deprecation.rst
> > +++ b/doc/guides/rel_notes/deprecation.rst
> > @@ -54,6 +54,10 @@ Deprecation Notices
> >    Target release for removal of the legacy API will be defined once most
> >    PMDs have switched to rte_flow.
> >
> > +* ABI/API changes are planned for 17.11 in the "rte_eth_dev_data" structure.
> 
> That's for ABI only and you missed the API part. Meaning, you need also mention
> that all APIs have port_id parameter will be changed too.
> 
> Also, rte_eth_dev_data is not the only structure has ABI changes. There are few
> more (for instance, rte_port_ethdev.h). As said before, you don't have to list all
> of them, but at least you should not list one example only as it seems that's the
> only structure has ABI change.
> 
> > +  Change the definition of port_id from 8bits to 16bits in order to
> > + support  more than 256 devices in DPDK.
> 
> 8bits -> 8 bits. You might want to reword it further. Besides that, this change is
> indeed needed. Thus,
> 
> Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
> 
> 	--yliu

Thank you, yuanhan. I have reworded and sent v2  according to your comments.

Zhiyong Yang

> > +
> >  * librte_table: The ``key_mask`` parameter will be added to all the hash tables
> >    that currently do not have it, as well as to the hash compute function
> prototype.
> >    The non-"do-sig" versions of the hash tables will be removed
> > --
> > 2.9.3

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v2] doc: announce API and ABI change for ethdev
  2017-07-12  7:58 13% [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev Zhiyong Yang
  2017-08-04  1:12  4% ` Tan, Jianfeng
  2017-08-04  4:07  9% ` Yuanhan Liu
@ 2017-08-04  5:27 13% ` Zhiyong Yang
  2017-08-04  6:56  7%   ` Remy Horton
  2017-08-07 12:42 13%   ` [dpdk-dev] [PATCH v3] " Zhiyong Yang
  2 siblings, 2 replies; 200+ results
From: Zhiyong Yang @ 2017-08-04  5:27 UTC (permalink / raw)
  To: dev; +Cc: jianfeng.tan, yliu, jerin.jacob, thomas, Zhiyong Yang

This is an API/ABI change notice for DPDK 17.11 on redefinition of
port_id. port_id is defined as uint8_t by now, which is just ranged
from 0 to 255. For more and more scenerioes, more than 256 ports are
needed to support for vdev scalability.

It is necessary for redefinition of port_id to extend from 1 bytes
to 2 bytes. All ethdev APIs and use cases related to port_id will be
changed at the same time.

cc: jianfeng.tan@intel.com
cc: yliu@fridaylinux.org
cc: jerin.jacob@caviumnetworks.com
cc: thomas@monjalon.net

Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
Acked-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---

Change in V2.
1. remove indent of paragraph in commit log.
2. add more description about API/ABI according to yuanhan's comments.

 doc/guides/rel_notes/deprecation.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 72aa40495..4edaf92fb 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -49,6 +49,12 @@ Deprecation Notices
   Target release for removal of the legacy API will be defined once most
   PMDs have switched to rte_flow.
 
+* ABI/API changes are planned for 17.11 in all structures which include port_id
+  definition such as "rte_eth_dev_data", "rte_port_ethdev_reader_params",
+  "rte_port_ethdev_writer_params", and so on. The definition of port_id will be
+  changed from 8 bits to 16 bits in order to support more than 256 ports in
+  DPDK. All APIs which have port_id parameter will be changed at the same time.
+
 * librte_table: The ``key_mask`` parameter will be added to all the hash tables
   that currently do not have it, as well as to the hash compute function prototype.
   The non-"do-sig" versions of the hash tables will be removed
-- 
2.13.3

^ permalink raw reply	[relevance 13%]

* Re: [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
  2017-08-03 15:32  4% [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev Akhil Goyal
@ 2017-08-04  5:26  4% ` Hemant Agrawal
  2017-08-07 17:41  7%   ` Thomas Monjalon
  2017-08-04  9:28  4% ` De Lara Guarch, Pablo
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 200+ results
From: Hemant Agrawal @ 2017-08-04  5:26 UTC (permalink / raw)
  To: Akhil Goyal, dev, declan.doherty, thomas, radu.nicolau, aviadye,
	borisp, pablo.de.lara.guarch

On 8/3/2017 9:02 PM, Akhil Goyal wrote:
> Support for security operations is planned to be added
> in ethdev and cryptodev for the 17.11 release.
>
> For this following changes are required.
> - rte_cryptodev and rte_eth_dev structures need to be added
> new parameter rte_security_ops which extend support for
> security ops to the corresponding driver.
> - rte_cryptodev_info and rte_ethd_dev_info need to be added
> with rte_security_capabilities to identify the capabilities of
> the corresponding driver.
>
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
>  doc/guides/rel_notes/deprecation.rst | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index f6bd910..2393b4c 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -69,3 +69,13 @@ Deprecation Notices
>    be removed in 17.11:
>
>    - ``rte_cryptodev_create_vdev``
> +
> +* cryptodev: new parameters - ``rte_security_capabilities`` and
> +  ``rte_security_ops`` will be added to ``rte_cryptodev_info`` and
> +  ``rte_cryptodev`` respectively to support security protocol offloaded
> +  operations.
> +
> +* ethdev: new parameters - ``rte_security_capabilities`` and
> +  ``rte_security_ops`` will be added to ``rte_eth_dev_info`` and
> +  ``rte_eth_dev`` respectively  to support security operations like
> +  ipsec inline.
>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware
  2017-08-04  3:41  0% ` santosh
@ 2017-08-04  5:25  0%   ` Hemant Agrawal
  2017-08-06 21:22  0%     ` Olivier MATZ
  0 siblings, 1 reply; 200+ results
From: Hemant Agrawal @ 2017-08-04  5:25 UTC (permalink / raw)
  To: santosh, Jerin Jacob, dev
  Cc: thomas, olivier.matz, stephen, bruce.richardson, shreyansh.jain,
	gaetan.rivet, sergio.gonzalez.monroy, anatoly.burakov

On 8/4/2017 9:11 AM, santosh wrote:
> On Tuesday 11 July 2017 03:31 PM, Jerin Jacob wrote:
>
>> When we run DPDK on guest or VFIO mode on host,
>> the dpdk library or device will not be directly accessing
>> the physical address. Instead, the device does go through
>> an IO address translation memory management unit. On x86,
>> we call it as IOMMU and on ARM as SMMU.
>>
>> More details:
>> http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf
>>
>> Based on discussion in the following thread
>> http://dpdk.org/ml/archives/dev/2017-July/070850.html
>>
>> We would like to change reference to physical address to more
>> appropriate name as with IOMMU/SMMU with
>> the device won't be dealing directly with the physical address.
>>
>> An ABI change is planned for 17.11 to change following
>> data structure or functions to more appropriate name.
>> Currently planned to change it iova as instead of phys
>>
>> Please note: The change will be only for the name and
>> functional aspects of the API will remain same.
>>
>> Following functions/data structures name may change.
>> This list is based on v17.05-rc1. It may change based on v17.11 code base.
>>
>>
>> typedef:
>> phys_addr_t
>>
>> structures:
>>
>> struct rte_memseg::phys_addr
>> struct rte_mbuf::buf_physaddr
>>
>> functions:
>> rte_mempool_populate_phys()
>> rte_mempool_populate_phys_tab()
>> rte_eal_using_phys_addrs()
>> rte_mem_virt2phy()
>> rte_dump_physmem_layout()
>> rte_eal_get_physmem_layout()
>> rte_eal_get_physmem_size()
>> rte_malloc_virt2phy()
>> rte_mem_phy2mch()
>>
>>
>> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
>> ---
>
> Acked-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
>
>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
  2017-08-04  4:07  9% ` Yuanhan Liu
@ 2017-08-04  4:13  4%   ` Jerin Jacob
  2017-08-04  5:36  4%   ` Yang, Zhiyong
  1 sibling, 0 replies; 200+ results
From: Jerin Jacob @ 2017-08-04  4:13 UTC (permalink / raw)
  To: Yuanhan Liu
  Cc: Zhiyong Yang, dev, zhihong.wang, john.mcnamara, oilvier.matz, thomas

-----Original Message-----
> Date: Fri, 4 Aug 2017 12:07:28 +0800
> From: Yuanhan Liu <yliu@fridaylinux.org>
> To: Zhiyong Yang <zhiyong.yang@intel.com>
> Cc: dev@dpdk.org, zhihong.wang@intel.com, john.mcnamara@intel.com,
>  oilvier.matz@6wind.com, thomas@monjalon.net
> Subject: Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
> User-Agent: Mutt/1.5.24 (2015-08-30)
> 
> On Wed, Jul 12, 2017 at 03:58:46PM +0800, Zhiyong Yang wrote:
> >   This is an API/ABI change notice for DPDK 17.11 on redefinition of
> 
> Don't put 2 whitespace char indentation here.
> 
> > port_id. port_id is defined as uint8_t by now, which is just ranged
> > from 0 to 255. For more and more scenerioes, more than 256 devices are
> > needed to support for vdev scalability.
> > 
> >   It is necessary for redefinition of port_id to extend from 1 bytes
> > to 2 bytes. All ethdev APIs and use cases related to port_id will be
> > changed at the same time.
> > 
> > Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
> > ---
> >  doc/guides/rel_notes/deprecation.rst | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> > index 257dcba..f265980 100644
> > --- a/doc/guides/rel_notes/deprecation.rst
> > +++ b/doc/guides/rel_notes/deprecation.rst
> > @@ -54,6 +54,10 @@ Deprecation Notices
> >    Target release for removal of the legacy API will be defined once most
> >    PMDs have switched to rte_flow.
> >  
> > +* ABI/API changes are planned for 17.11 in the "rte_eth_dev_data" structure.
> 
> That's for ABI only and you missed the API part. Meaning, you need also
> mention that all APIs have port_id parameter will be changed too.
> 
> Also, rte_eth_dev_data is not the only structure has ABI changes. There
> are few more (for instance, rte_port_ethdev.h). As said before, you don't
> have to list all of them, but at least you should not list one example
> only as it seems that's the only structure has ABI change.
> 
> > +  Change the definition of port_id from 8bits to 16bits in order to support
> > +  more than 256 devices in DPDK.
> 
> 8bits -> 8 bits. You might want to reword it further. Besides that, this
> change is indeed needed. Thus,
> 
> Acked-by: Yuanhan Liu <yliu@fridaylinux.org>

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>


> 
> 	--yliu
> > +
> >  * librte_table: The ``key_mask`` parameter will be added to all the hash tables
> >    that currently do not have it, as well as to the hash compute function prototype.
> >    The non-"do-sig" versions of the hash tables will be removed
> > -- 
> > 2.9.3

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
  2017-07-12  7:58 13% [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev Zhiyong Yang
  2017-08-04  1:12  4% ` Tan, Jianfeng
@ 2017-08-04  4:07  9% ` Yuanhan Liu
  2017-08-04  4:13  4%   ` Jerin Jacob
  2017-08-04  5:36  4%   ` Yang, Zhiyong
  2017-08-04  5:27 13% ` [dpdk-dev] [PATCH v2] " Zhiyong Yang
  2 siblings, 2 replies; 200+ results
From: Yuanhan Liu @ 2017-08-04  4:07 UTC (permalink / raw)
  To: Zhiyong Yang; +Cc: dev, zhihong.wang, john.mcnamara, oilvier.matz, thomas

On Wed, Jul 12, 2017 at 03:58:46PM +0800, Zhiyong Yang wrote:
>   This is an API/ABI change notice for DPDK 17.11 on redefinition of

Don't put 2 whitespace char indentation here.

> port_id. port_id is defined as uint8_t by now, which is just ranged
> from 0 to 255. For more and more scenerioes, more than 256 devices are
> needed to support for vdev scalability.
> 
>   It is necessary for redefinition of port_id to extend from 1 bytes
> to 2 bytes. All ethdev APIs and use cases related to port_id will be
> changed at the same time.
> 
> Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
> ---
>  doc/guides/rel_notes/deprecation.rst | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 257dcba..f265980 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -54,6 +54,10 @@ Deprecation Notices
>    Target release for removal of the legacy API will be defined once most
>    PMDs have switched to rte_flow.
>  
> +* ABI/API changes are planned for 17.11 in the "rte_eth_dev_data" structure.

That's for ABI only and you missed the API part. Meaning, you need also
mention that all APIs have port_id parameter will be changed too.

Also, rte_eth_dev_data is not the only structure has ABI changes. There
are few more (for instance, rte_port_ethdev.h). As said before, you don't
have to list all of them, but at least you should not list one example
only as it seems that's the only structure has ABI change.

> +  Change the definition of port_id from 8bits to 16bits in order to support
> +  more than 256 devices in DPDK.

8bits -> 8 bits. You might want to reword it further. Besides that, this
change is indeed needed. Thus,

Acked-by: Yuanhan Liu <yliu@fridaylinux.org>

	--yliu
> +
>  * librte_table: The ``key_mask`` parameter will be added to all the hash tables
>    that currently do not have it, as well as to the hash compute function prototype.
>    The non-"do-sig" versions of the hash tables will be removed
> -- 
> 2.9.3

^ permalink raw reply	[relevance 9%]

* Re: [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware
  2017-07-11 10:01  8% [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware Jerin Jacob
  2017-07-21  6:41  0% ` santosh
@ 2017-08-04  3:41  0% ` santosh
  2017-08-04  5:25  0%   ` Hemant Agrawal
  1 sibling, 1 reply; 200+ results
From: santosh @ 2017-08-04  3:41 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: thomas, olivier.matz, stephen, hemant.agrawal, bruce.richardson,
	shreyansh.jain, gaetan.rivet, sergio.gonzalez.monroy,
	anatoly.burakov

On Tuesday 11 July 2017 03:31 PM, Jerin Jacob wrote:

> When we run DPDK on guest or VFIO mode on host,
> the dpdk library or device will not be directly accessing
> the physical address. Instead, the device does go through
> an IO address translation memory management unit. On x86,
> we call it as IOMMU and on ARM as SMMU.
>
> More details:
> http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf
>
> Based on discussion in the following thread
> http://dpdk.org/ml/archives/dev/2017-July/070850.html
>
> We would like to change reference to physical address to more
> appropriate name as with IOMMU/SMMU with
> the device won't be dealing directly with the physical address.
>
> An ABI change is planned for 17.11 to change following
> data structure or functions to more appropriate name.
> Currently planned to change it iova as instead of phys
>
> Please note: The change will be only for the name and
> functional aspects of the API will remain same.
>
> Following functions/data structures name may change.
> This list is based on v17.05-rc1. It may change based on v17.11 code base.
>
>
> typedef:
> phys_addr_t
>
> structures:
>
> struct rte_memseg::phys_addr
> struct rte_mbuf::buf_physaddr
>
> functions:
> rte_mempool_populate_phys()
> rte_mempool_populate_phys_tab()
> rte_eal_using_phys_addrs()
> rte_mem_virt2phy()
> rte_dump_physmem_layout()
> rte_eal_get_physmem_layout()
> rte_eal_get_physmem_size()
> rte_malloc_virt2phy()
> rte_mem_phy2mch()
>
>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> ---

Acked-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
  2017-07-12  7:58 13% [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev Zhiyong Yang
@ 2017-08-04  1:12  4% ` Tan, Jianfeng
  2017-08-04  4:07  9% ` Yuanhan Liu
  2017-08-04  5:27 13% ` [dpdk-dev] [PATCH v2] " Zhiyong Yang
  2 siblings, 0 replies; 200+ results
From: Tan, Jianfeng @ 2017-08-04  1:12 UTC (permalink / raw)
  To: Zhiyong Yang, dev, zhihong.wang; +Cc: john.mcnamara, oilvier.matz, thomas



On 7/12/2017 12:58 AM, Zhiyong Yang wrote:
>    This is an API/ABI change notice for DPDK 17.11 on redefinition of

A nit: we usually don't indent at the commit message paragraph.

> port_id. port_id is defined as uint8_t by now, which is just ranged
> from 0 to 255. For more and more scenerioes, more than 256 devices are
> needed to support for vdev scalability.
>
>    It is necessary for redefinition of port_id to extend from 1 bytes
> to 2 bytes. All ethdev APIs and use cases related to port_id will be
> changed at the same time.
>
> Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>

Acked-by: Jianfeng Tan <jianfeng.tan@intel.com>

Thanks,
Jianfeng

> ---
>   doc/guides/rel_notes/deprecation.rst | 4 ++++
>   1 file changed, 4 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 257dcba..f265980 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -54,6 +54,10 @@ Deprecation Notices
>     Target release for removal of the legacy API will be defined once most
>     PMDs have switched to rte_flow.
>   
> +* ABI/API changes are planned for 17.11 in the "rte_eth_dev_data" structure.
> +  Change the definition of port_id from 8bits to 16bits in order to support
> +  more than 256 devices in DPDK.
> +
>   * librte_table: The ``key_mask`` parameter will be added to all the hash tables
>     that currently do not have it, as well as to the hash compute function prototype.
>     The non-"do-sig" versions of the hash tables will be removed

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v2] doc: deprecate Xen support
  2017-08-03 14:49  5% [dpdk-dev] [PATCH] doc: deprecate Xen dom0 support Thomas Monjalon
  2017-08-03 15:33  0% ` Tan, Jianfeng
@ 2017-08-03 20:38  5% ` Jianfeng Tan
  1 sibling, 0 replies; 200+ results
From: Jianfeng Tan @ 2017-08-03 20:38 UTC (permalink / raw)
  To: dev; +Cc: Jianfeng Tan, Thomas Monjalon

Following the calls on the mailing list:
	http://dpdk.org/ml/archives/dev/2017-June/068151.html
The Technical Board decided to drop Xen dom0 support from EAL:
	http://dpdk.org/ml/archives/dev/2017-June/068615.html

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
 doc/guides/rel_notes/deprecation.rst | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index f6bd910..9edd85d 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -8,6 +8,9 @@ API and ABI deprecation notices are to be posted here.
 Deprecation Notices
 -------------------
 
+* eal: the support of Xen dom0 will be removed from EAL in 17.11; and with
+  that, drivers/net/xenvirt and examples/vhost_xen will also be removed.
+
 * eal: the following functions are deprecated starting from 17.05 and will
   be removed in 17.08:
 
-- 
2.7.4

^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  2017-08-03 16:15  3%   ` Stephen Hemminger
@ 2017-08-03 19:53  0%     ` Thomas Monjalon
  2017-08-04  9:59  0%       ` Chilikin, Andrey
  2017-08-04 11:58  0%       ` Ferruh Yigit
  0 siblings, 2 replies; 200+ results
From: Thomas Monjalon @ 2017-08-03 19:53 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Bruce Richardson, Chilikin, Andrey, Ananyev,
	Konstantin, Wu, Jingjing

03/08/2017 18:15, Stephen Hemminger:
> On Thu, 3 Aug 2017 14:21:38 +0100
> Bruce Richardson <bruce.richardson@intel.com> wrote:
> 
> > On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
> > > To control some device-specific features public device-specific functions
> > > rte_pmd_*.h are used.
> > > 
> > > But this solution requires applications to distinguish devices at runtime
> > > and, depending on the device type, call corresponding device-specific
> > > functions even if functions' parameters are the same.
> > > 
> > > IOCTL-like API can be added to ethdev instead of public device-specific
> > > functions to address the following:
> > > 
> > > * allow more usable support of features across a range of NIC from
> > >   one vendor, but not others
> > > * allow features to be implemented by multiple NIC drivers without
> > >   relying on a critical mass to get the functionality in ethdev
> > > * there are a large number of possible device specific functions, and
> > >   creating individual APIs for each one is not a good solution
> > > * IOCTLs are a proven method for solving this problem in other areas,
> > >   i.e. OS kernels.
> > > 
> > > Control requests for this API will be globally defined at ethdev level, so
> > > an application will use single API call to control different devices from
> > > one/multiple vendors.
> > > 
> > > API call may look like as a classic ioctl with an extra parameter for
> > > argument length for better sanity checks:
> > > 
> > > int
> > > rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> > >         unsigned arg_length);
> > > 
> > > Regards,
> > > Andrey  
> > 
> > I think we need to start putting in IOCTLs for ethdevs, much as I hate
> > to admit it, since I dislike IOCTLs and other functions with opaque
> > arguments! Having driver specific functions I don't think will scale
> > well as each vendor tries to expose as much of their driver specific
> > functionality as possible.
> > 
> > One other additional example: I discovered just this week another issue
> > with driver specific functions and testpmd, when I was working on the
> > meson build rework.
> > 
> > * With shared libraries, when we do "ninja install" we want our DPDK
> >   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
> >   driver folder, so that they can be automatically loaded from that
> >   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> > * However, testpmd, as well as using the drivers as plugins, uses
> >   driver-specific functions, which means that it explicitly links
> >   against the pmd .so files.
> > * Those driver .so files are not in with the other libraries, so ld.so
> >   does not find the pmd, and the installed testpmd fails to run due to
> >   missing library dependencies.
> > * The workaround is to add the drivers path to the ld load path, but we
> >   should not require ld library path changes just to get DPDK apps to
> >   work.
> > 
> > Using ioctls instead of driver-specific functions would solve this.
> > 
> > My 2c.
> 
> My 2c. No.
> 
> Short answer:
> Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
> despised by Linux kernel developers. They provide an unstructured, unsecured,
> back door for device driver abuse. Try to get a new driver in Linux with
> a unique ioctl, and it will be hard to get accepted.
> 
> Long answer:
> So far every device specific feature has fit into ethdev model. Doing ioctl
> is admitting "it is too hard to be general, we need need an out". For something
> that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
> For a real feature (think flow direction), we want a first class API for that.
> For a wart, then devargs will do.
> 
> Give a good example of something that should be an ioctl. Don't build the
> API first and then let it get cluttered.

I agree with Stephen.

And please do not forget that ioctl still requires an API:
the argument that you put in ioctl is the API of the feature.
So it is the same thing as defining a new function.

The real debate is to decide if we want to continue adding more
control path features in DPDK or focus on Rx/Tx.
But this discussion would be better lead with some examples/requests.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features
  @ 2017-08-03 16:15  3%   ` Stephen Hemminger
  2017-08-03 19:53  0%     ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Stephen Hemminger @ 2017-08-03 16:15 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Chilikin, Andrey, dev, Ananyev, Konstantin, Wu, Jingjing

On Thu, 3 Aug 2017 14:21:38 +0100
Bruce Richardson <bruce.richardson@intel.com> wrote:

> On Thu, Aug 03, 2017 at 01:21:35PM +0100, Chilikin, Andrey wrote:
> > To control some device-specific features public device-specific functions
> > rte_pmd_*.h are used.
> > 
> > But this solution requires applications to distinguish devices at runtime
> > and, depending on the device type, call corresponding device-specific
> > functions even if functions' parameters are the same.
> > 
> > IOCTL-like API can be added to ethdev instead of public device-specific
> > functions to address the following:
> > 
> > * allow more usable support of features across a range of NIC from
> >   one vendor, but not others
> > * allow features to be implemented by multiple NIC drivers without
> >   relying on a critical mass to get the functionality in ethdev
> > * there are a large number of possible device specific functions, and
> >   creating individual APIs for each one is not a good solution
> > * IOCTLs are a proven method for solving this problem in other areas,
> >   i.e. OS kernels.
> > 
> > Control requests for this API will be globally defined at ethdev level, so
> > an application will use single API call to control different devices from
> > one/multiple vendors.
> > 
> > API call may look like as a classic ioctl with an extra parameter for
> > argument length for better sanity checks:
> > 
> > int
> > rte_eth_dev_ioctl(uint16_t port, uint64_t ctl, void *argp,
> >         unsigned arg_length);
> > 
> > Regards,
> > Andrey  
> 
> I think we need to start putting in IOCTLs for ethdevs, much as I hate
> to admit it, since I dislike IOCTLs and other functions with opaque
> arguments! Having driver specific functions I don't think will scale
> well as each vendor tries to expose as much of their driver specific
> functionality as possible.
> 
> One other additional example: I discovered just this week another issue
> with driver specific functions and testpmd, when I was working on the
> meson build rework.
> 
> * With shared libraries, when we do "ninja install" we want our DPDK
>   libs moved to e.g. /usr/local/lib, but the drivers moved to a separate
>   driver folder, so that they can be automatically loaded from that
>   single location by DPDK apps [== CONFIG_RTE_EAL_PMD_PATH].
> * However, testpmd, as well as using the drivers as plugins, uses
>   driver-specific functions, which means that it explicitly links
>   against the pmd .so files.
> * Those driver .so files are not in with the other libraries, so ld.so
>   does not find the pmd, and the installed testpmd fails to run due to
>   missing library dependencies.
> * The workaround is to add the drivers path to the ld load path, but we
>   should not require ld library path changes just to get DPDK apps to
>   work.
> 
> Using ioctls instead of driver-specific functions would solve this.
> 
> My 2c.

My 2c. No.

Short answer:
Ioctl's were a bad idea in Unix (per Dennis Ritchie et al) and are now
despised by Linux kernel developers. They provide an unstructured, unsecured,
back door for device driver abuse. Try to get a new driver in Linux with
a unique ioctl, and it will be hard to get accepted.

Long answer:
So far every device specific feature has fit into ethdev model. Doing ioctl
is admitting "it is too hard to be general, we need need an out". For something
that is a flag, it should fit into existing config model; ignoring silly ABI constraints.
For a real feature (think flow direction), we want a first class API for that.
For a wart, then devargs will do.

Give a good example of something that should be an ioctl. Don't build the
API first and then let it get cluttered.

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH] doc: move metrics libs to device API section
@ 2017-08-03 15:56  4% Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-03 15:56 UTC (permalink / raw)
  To: remy.horton; +Cc: dev

The metrics headers were listed in misc section,
whereas they belong to the device API family.

Fixes: 349950ddb9c5 ("metrics: add information metrics library")
Fixes: 2ad7ba9a6567 ("bitrate: add bitrate statistics library")
Fixes: 5cd3cac9ed22 ("latency: added new library for latency stats")

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 doc/api/doxy-api-index.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 1fd7ff17b..19e0d4f3d 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -43,6 +43,9 @@ The public API headers are grouped by topics:
   [rte_tm]             (@ref rte_tm.h),
   [cryptodev]          (@ref rte_cryptodev.h),
   [eventdev]           (@ref rte_eventdev.h),
+  [metrics]            (@ref rte_metrics.h),
+  [bitrate]            (@ref rte_bitrate.h),
+  [latency]            (@ref rte_latencystats.h),
   [devargs]            (@ref rte_devargs.h),
   [PCI]                (@ref rte_pci.h)
 
@@ -161,7 +164,4 @@ The public API headers are grouped by topics:
   [EAL config]         (@ref rte_eal.h),
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
-  [device metrics]     (@ref rte_metrics.h),
-  [bitrate statistics] (@ref rte_bitrate.h),
-  [latency statistics] (@ref rte_latencystats.h),
   [version]            (@ref rte_version.h)
-- 
2.13.2

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] doc: move keepalive to multicore API section
@ 2017-08-03 15:55  4% Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-03 15:55 UTC (permalink / raw)
  To: remy.horton; +Cc: dev

The keepalive header was listed in misc section,
despite its doxygen comment is "LCore Keepalive Monitor".

Fixes: 75583b0d1efd ("eal: add keep alive monitoring")

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 doc/api/doxy-api-index.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 04034ae78..1fd7ff17b 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -86,6 +86,7 @@ The public API headers are grouped by topics:
   [lcore]              (@ref rte_lcore.h),
   [per-lcore]          (@ref rte_per_lcore.h),
   [service cores]      (@ref rte_service.h),
+  [keepalive]          (@ref rte_keepalive.h),
   [power/freq]         (@ref rte_power.h)
 
 - **layers**:
@@ -160,7 +161,6 @@ The public API headers are grouped by topics:
   [EAL config]         (@ref rte_eal.h),
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
-  [keepalive]          (@ref rte_keepalive.h),
   [device metrics]     (@ref rte_metrics.h),
   [bitrate statistics] (@ref rte_bitrate.h),
   [latency statistics] (@ref rte_latencystats.h),
-- 
2.13.2

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev
@ 2017-08-03 15:32  4% Akhil Goyal
  2017-08-04  5:26  4% ` Hemant Agrawal
                   ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Akhil Goyal @ 2017-08-03 15:32 UTC (permalink / raw)
  To: dev, declan.doherty, thomas, radu.nicolau, aviadye, borisp,
	hemant.agrawal, pablo.de.lara.guarch
  Cc: Akhil Goyal

Support for security operations is planned to be added
in ethdev and cryptodev for the 17.11 release.

For this following changes are required.
- rte_cryptodev and rte_eth_dev structures need to be added
new parameter rte_security_ops which extend support for
security ops to the corresponding driver.
- rte_cryptodev_info and rte_ethd_dev_info need to be added
with rte_security_capabilities to identify the capabilities of
the corresponding driver.

Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/rel_notes/deprecation.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index f6bd910..2393b4c 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -69,3 +69,13 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_cryptodev_create_vdev``
+
+* cryptodev: new parameters - ``rte_security_capabilities`` and
+  ``rte_security_ops`` will be added to ``rte_cryptodev_info`` and
+  ``rte_cryptodev`` respectively to support security protocol offloaded
+  operations.
+
+* ethdev: new parameters - ``rte_security_capabilities`` and
+  ``rte_security_ops`` will be added to ``rte_eth_dev_info`` and
+  ``rte_eth_dev`` respectively  to support security operations like
+  ipsec inline.
-- 
2.9.3

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: deprecate Xen dom0 support
  2017-08-03 14:49  5% [dpdk-dev] [PATCH] doc: deprecate Xen dom0 support Thomas Monjalon
@ 2017-08-03 15:33  0% ` Tan, Jianfeng
  2017-08-03 20:38  5% ` [dpdk-dev] [PATCH v2] doc: deprecate Xen support Jianfeng Tan
  1 sibling, 0 replies; 200+ results
From: Tan, Jianfeng @ 2017-08-03 15:33 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

On 8/3/2017 7:49 AM, Thomas Monjalon wrote:
> Following the calls on the mailing list:
> 	http://dpdk.org/ml/archives/dev/2017-June/068151.html
> The Technical Board decided to drop Xen dom0 support from EAL:
> 	http://dpdk.org/ml/archives/dev/2017-June/068615.html

As dom0 is removed, drivers/net/xenvirt and examples/vhost_xen/ will not 
work any more. Shall we deprecate them also?

Thanks,
Jianfeng

>
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---
>   doc/guides/rel_notes/deprecation.rst | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 7b1997058..b7fd8049e 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -8,6 +8,8 @@ API and ABI deprecation notices are to be posted here.
>   Deprecation Notices
>   -------------------
>   
> +* eal: the support of Xen dom0 will be removed from EAL in 17.11.
> +
>   * eal: the following functions are deprecated starting from 17.05 and will
>     be removed in 17.11:
>   

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] doc: deprecate Xen dom0 support
@ 2017-08-03 14:49  5% Thomas Monjalon
  2017-08-03 15:33  0% ` Tan, Jianfeng
  2017-08-03 20:38  5% ` [dpdk-dev] [PATCH v2] doc: deprecate Xen support Jianfeng Tan
  0 siblings, 2 replies; 200+ results
From: Thomas Monjalon @ 2017-08-03 14:49 UTC (permalink / raw)
  To: Jianfeng Tan; +Cc: dev

Following the calls on the mailing list:
	http://dpdk.org/ml/archives/dev/2017-June/068151.html
The Technical Board decided to drop Xen dom0 support from EAL:
	http://dpdk.org/ml/archives/dev/2017-June/068615.html

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 doc/guides/rel_notes/deprecation.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 7b1997058..b7fd8049e 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -8,6 +8,8 @@ API and ABI deprecation notices are to be posted here.
 Deprecation Notices
 -------------------
 
+* eal: the support of Xen dom0 will be removed from EAL in 17.11.
+
 * eal: the following functions are deprecated starting from 17.05 and will
   be removed in 17.11:
 
-- 
2.13.2

^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-08-03 14:21  4%   ` Jerin Jacob
@ 2017-08-03 14:30  4%     ` santosh
  2017-08-05 20:24  4%     ` Olivier MATZ
  1 sibling, 0 replies; 200+ results
From: santosh @ 2017-08-03 14:30 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: olivier.matz, dev, Thomas Monjalon

On Thursday 03 August 2017 07:51 PM, Jerin Jacob wrote:

> -----Original Message-----
>> Date: Thu, 20 Jul 2017 15:59:15 +0530
>> From: Santosh Shukla <santosh.shukla@caviumnetworks.com>
>> To: olivier.matz@6wind.com, dev@dpdk.org
>> CC: thomas.monjalon@6wind.com, Santosh Shukla
>>  <santosh.shukla@caviumnetworks.com>
>> Subject: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
>> X-Mailer: git-send-email 2.11.0
>>
>> An API/ABI change is planned for 17.11 to change following
>>
>> * Remove unused flag param from rte_mempool_generic_get and _put.
>> * Change data type for mempool 'flag' from int to unsigned int.
>>   Refer [1].
>> * Add struct rte_mempool * param into func rte_mempool_xmem_size,
>>   rte_mempool_xmem_usage to make it mempool aware.
>>   Refer [2].
>>
>> [1] http://dpdk.org/dev/patchwork/patch/25603/
>> [2] http://dpdk.org/dev/patchwork/patch/25605/
>>
>> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

Olivier/Thomas, Review feedback pl.?

Thanks.

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-07-20 10:29  7% ` [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool Santosh Shukla
  2017-07-21  6:26  4%   ` santosh
@ 2017-08-03 14:21  4%   ` Jerin Jacob
  2017-08-03 14:30  4%     ` santosh
  2017-08-05 20:24  4%     ` Olivier MATZ
  1 sibling, 2 replies; 200+ results
From: Jerin Jacob @ 2017-08-03 14:21 UTC (permalink / raw)
  To: Santosh Shukla; +Cc: olivier.matz, dev, thomas.monjalon

-----Original Message-----
> Date: Thu, 20 Jul 2017 15:59:15 +0530
> From: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> To: olivier.matz@6wind.com, dev@dpdk.org
> CC: thomas.monjalon@6wind.com, Santosh Shukla
>  <santosh.shukla@caviumnetworks.com>
> Subject: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
> X-Mailer: git-send-email 2.11.0
> 
> An API/ABI change is planned for 17.11 to change following
> 
> * Remove unused flag param from rte_mempool_generic_get and _put.
> * Change data type for mempool 'flag' from int to unsigned int.
>   Refer [1].
> * Add struct rte_mempool * param into func rte_mempool_xmem_size,
>   rte_mempool_xmem_usage to make it mempool aware.
>   Refer [2].
> 
> [1] http://dpdk.org/dev/patchwork/patch/25603/
> [2] http://dpdk.org/dev/patchwork/patch/25605/
> 
> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

> ---
> v1 --> v2:
> - Changed the title.
> - Added empty line between 'mempool:' and - ``.
> (Both suggested by Olivier)
> 
>  doc/guides/rel_notes/deprecation.rst | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 257dcba32..1345b0e65 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -64,3 +64,12 @@ Deprecation Notices
>    be removed in 17.11:
>  
>    - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
> +
> +* mempool: The following will be modified in 17.11:
> +
> +  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
> +    the mempool flag status so adding new param rte_mempool in those API.
> +  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
> +    and ``rte_mempool_generic_get`` API.
> +  - ``rte_mempool`` flags data type will changed from int to
> +    unsigned int.
> -- 
> 2.11.0
> 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] cryptodev: fix NULL pointer dereference
  2017-08-01 10:48  4%         ` De Lara Guarch, Pablo
@ 2017-08-01 12:36  3%           ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-08-01 12:36 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, Gonzalez Monroy, Sergio; +Cc: dev, Jan Blunck

01/08/2017 12:48, De Lara Guarch, Pablo:
> From: Gonzalez Monroy, Sergio
> > On 01/08/2017 10:35, Thomas Monjalon wrote:
> > > 01/08/2017 10:13, Sergio Gonzalez Monroy:
> > >> On 31/07/2017 20:33, Thomas Monjalon wrote:
> > >>> 31/07/2017 11:18, Pablo de Lara:
> > >>>> When register a crypto driver, a cryptodev driver structure was
> > >>>> being allocated, using malloc.
> > >>>> Since this call may fail, it is safer to allocate this memory
> > >>>> statically in each PMD, so driver registration will never fail.
> > >>>>
> > >>>> Coverity issue: 158645
> > >>>>
> > >>>> Fixes: 7a364faef185 ("cryptodev: remove crypto device type
> > >>>> enumeration")
> > >>>>
> > >>>> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> > >>>> ---
> > >>>>
> > >>>> Changes in v2:
> > >>>>
> > >>>> - Allocate statically the cryptodev driver structure,
> > >>>>     instead of using malloc, that can potentially fail.
> > >>>>
> > >>>>    drivers/crypto/aesni_gcm/aesni_gcm_pmd.c    |  5 ++++-
> > >>>>    drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c  |  6 +++++-
> > >>>>    drivers/crypto/armv8/rte_armv8_pmd.c        |  9 ++++++---
> > >>>>    drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  5 ++++-
> > >>>>    drivers/crypto/kasumi/rte_kasumi_pmd.c      |  5 ++++-
> > >>>>    drivers/crypto/null/null_crypto_pmd.c       |  5 ++++-
> > >>>>    drivers/crypto/openssl/rte_openssl_pmd.c    |  5 ++++-
> > >>>>    drivers/crypto/qat/rte_qat_cryptodev.c      |  7 +++++--
> > >>>>    drivers/crypto/scheduler/scheduler_pmd.c    |  5 ++++-
> > >>>>    drivers/crypto/snow3g/rte_snow3g_pmd.c      |  5 ++++-
> > >>>>    drivers/crypto/zuc/rte_zuc_pmd.c            |  5 ++++-
> > >>>>    lib/librte_cryptodev/rte_cryptodev.c        | 18 +++++------------
> > >>>>    lib/librte_cryptodev/rte_cryptodev.h        | 20 -------------------
> > >>>>    lib/librte_cryptodev/rte_cryptodev_pmd.h    | 30
> > +++++++++++++++++++++++++++++
> > >>>>    14 files changed, 83 insertions(+), 47 deletions(-)
> > >>> This is a big change for a small/unlikely issue.
> > >>> The main benefit of this patch is an allocation cleanup.
> > >>> I think it is better to wait 17.11 cycle to integrate it.
> > >> We initially thought of exit given that it is a constructor and if
> > >> you fail to allocate memory at this stage, things are likely not
> > >> going to work out anyway.
> > > You don't know how the application wants to manage it.
> > 
> > IMHO setting an internal variable indicating an error in constructors and
> > then reporting the problem during EAL init seems overly complex.
> > I think the proposed change is a cleaner solution.
> > 
> > >> The patch is an API change, do we really want to break again (we are
> > >> breaking in this release) next release?
> > > Good question. Any opinions?
> > 
> > Merge the patch unless there are already outstanding and/or planned
> > changes for the next release that are going to break ABI/API?
> 
> There is another patchset that was postponed for next release, because the
> compilation was broken in one of the patches (just double checked and it is easy to fix),
> and by then, I thought that no ABI/API was being broken,
> but it will be (my bad here). This is the patchset I am talking about:
> 
> [PATCH v2 0/4] cryptodev vdev changes for -rc2
>  http://dpdk.org/ml/archives/dev/2017-July/071160.html
> 
> So we have two options here:
> 1 - Get both patches now, since we are breaking the ABI in this release (as Sergio pointed out).
> 2 - Postpone both changes to next release.
> 
> I would go for option 1, as there are no other changes expected for next release
> (only one function, rte_cryptodev_create_vdev, will be removed).

Given that there is a new release every 3 months, I prefer the safe way.
Anyway, if a function is going to be removed, the API and ABI will change.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] cryptodev: fix NULL pointer dereference
  2017-08-01 10:17  3%       ` Sergio Gonzalez Monroy
@ 2017-08-01 10:48  4%         ` De Lara Guarch, Pablo
  2017-08-01 12:36  3%           ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-01 10:48 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, Thomas Monjalon; +Cc: dev, Jan Blunck



> -----Original Message-----
> From: Gonzalez Monroy, Sergio
> Sent: Tuesday, August 1, 2017 11:18 AM
> To: Thomas Monjalon <thomas@monjalon.net>
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>;
> dev@dpdk.org
> Subject: Re: [PATCH v2] cryptodev: fix NULL pointer dereference
> 
> On 01/08/2017 10:35, Thomas Monjalon wrote:
> > 01/08/2017 10:13, Sergio Gonzalez Monroy:
> >> On 31/07/2017 20:33, Thomas Monjalon wrote:
> >>> 31/07/2017 11:18, Pablo de Lara:
> >>>> When register a crypto driver, a cryptodev driver structure was
> >>>> being allocated, using malloc.
> >>>> Since this call may fail, it is safer to allocate this memory
> >>>> statically in each PMD, so driver registration will never fail.
> >>>>
> >>>> Coverity issue: 158645
> >>>>
> >>>> Fixes: 7a364faef185 ("cryptodev: remove crypto device type
> >>>> enumeration")
> >>>>
> >>>> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> >>>> ---
> >>>>
> >>>> Changes in v2:
> >>>>
> >>>> - Allocate statically the cryptodev driver structure,
> >>>>     instead of using malloc, that can potentially fail.
> >>>>
> >>>>    drivers/crypto/aesni_gcm/aesni_gcm_pmd.c    |  5 ++++-
> >>>>    drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c  |  6 +++++-
> >>>>    drivers/crypto/armv8/rte_armv8_pmd.c        |  9 ++++++---
> >>>>    drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  5 ++++-
> >>>>    drivers/crypto/kasumi/rte_kasumi_pmd.c      |  5 ++++-
> >>>>    drivers/crypto/null/null_crypto_pmd.c       |  5 ++++-
> >>>>    drivers/crypto/openssl/rte_openssl_pmd.c    |  5 ++++-
> >>>>    drivers/crypto/qat/rte_qat_cryptodev.c      |  7 +++++--
> >>>>    drivers/crypto/scheduler/scheduler_pmd.c    |  5 ++++-
> >>>>    drivers/crypto/snow3g/rte_snow3g_pmd.c      |  5 ++++-
> >>>>    drivers/crypto/zuc/rte_zuc_pmd.c            |  5 ++++-
> >>>>    lib/librte_cryptodev/rte_cryptodev.c        | 18 +++++------------
> >>>>    lib/librte_cryptodev/rte_cryptodev.h        | 20 -------------------
> >>>>    lib/librte_cryptodev/rte_cryptodev_pmd.h    | 30
> +++++++++++++++++++++++++++++
> >>>>    14 files changed, 83 insertions(+), 47 deletions(-)
> >>> This is a big change for a small/unlikely issue.
> >>> The main benefit of this patch is an allocation cleanup.
> >>> I think it is better to wait 17.11 cycle to integrate it.
> >> We initially thought of exit given that it is a constructor and if
> >> you fail to allocate memory at this stage, things are likely not
> >> going to work out anyway.
> > You don't know how the application wants to manage it.
> 
> IMHO setting an internal variable indicating an error in constructors and
> then reporting the problem during EAL init seems overly complex.
> I think the proposed change is a cleaner solution.
> 
> >> The patch is an API change, do we really want to break again (we are
> >> breaking in this release) next release?
> > Good question. Any opinions?
> 
> Merge the patch unless there are already outstanding and/or planned
> changes for the next release that are going to break ABI/API?

There is another patchset that was postponed for next release, because the
compilation was broken in one of the patches (just double checked and it is easy to fix),
and by then, I thought that no ABI/API was being broken,
but it will be (my bad here). This is the patchset I am talking about:

[PATCH v2 0/4] cryptodev vdev changes for -rc2
 http://dpdk.org/ml/archives/dev/2017-July/071160.html

So we have two options here:
1 - Get both patches now, since we are breaking the ABI in this release (as Sergio pointed out).
2 - Postpone both changes to next release.

I would go for option 1, as there are no other changes expected for next release
(only one function, rte_cryptodev_create_vdev, will be removed).

Thanks,
Pablo

> 
> 
> Thanks,
> Sergio

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 0/4] cryptodev vdev changes for -rc2
  2017-07-27 19:31  3%     ` Jan Blunck
@ 2017-08-01 10:39  4%       ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 200+ results
From: De Lara Guarch, Pablo @ 2017-08-01 10:39 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev, Doherty, Declan



> -----Original Message-----
> From: jblunck@gmail.com [mailto:jblunck@gmail.com] On Behalf Of Jan
> Blunck
> Sent: Thursday, July 27, 2017 8:32 PM
> To: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>
> Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>
> Subject: Re: [PATCH v2 0/4] cryptodev vdev changes for -rc2
> 
> On Wed, Jul 19, 2017 at 9:31 AM, De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com> wrote:
> >
> >
> >
> > > -----Original Message-----
> > > From: Jan Blunck [mailto:jblunck@gmail.com] On Behalf Of Jan Blunck
> > > Sent: Wednesday, July 12, 2017 8:59 PM
> > > To: dev@dpdk.org
> > > Cc: Doherty, Declan <declan.doherty@intel.com>; De Lara Guarch,
> > > Pablo <pablo.de.lara.guarch@intel.com>
> > > Subject: [PATCH v2 0/4] cryptodev vdev changes for -rc2
> > >
> > > This series is a preparation to move the vdev bus out of librte_eal.
> > > For that the newly added cryptodev vdev functions need to change
> > > signature to not require the rte_vdev.h header.
> > >
> > > Changes since v1:
> > > - move params parsing into new header
> > > - make rte_cryptodev_vdev_pmd_init() static inline
> > >
> > > Jan Blunck (4):
> > >   cryptodev: remove obsolete include
> > >   cryptodev: move initialization
> > >   cryptodev: rework PMD init to not require rte_vdev.h
> > >   cryptodev: move parameter parsing to its own header
> > >
> > >  lib/librte_cryptodev/Makefile                    |  1 +
> > >  lib/librte_cryptodev/rte_cryptodev.c             |  3 +
> > >  lib/librte_cryptodev/rte_cryptodev.h             |  1 -
> > >  lib/librte_cryptodev/rte_cryptodev_pmd.c         | 37 +---------
> > >  lib/librte_cryptodev/rte_cryptodev_vdev.h        | 71 ++++++++-----------
> > >  lib/librte_cryptodev/rte_cryptodev_vdev_params.h | 89
> > > ++++++++++++++++++++++++
> > >  lib/librte_cryptodev/rte_cryptodev_version.map   |  1 -
> > >  7 files changed, 122 insertions(+), 81 deletions(-)  create mode
> > > 100644 lib/librte_cryptodev/rte_cryptodev_vdev_params.h
> > >
> > > --
> > > 2.13.2
> >
> > Hi Jan,
> >
> > Since there are some issues in this patchset and knowing that these
> > changes are required for work to be done in 17.11 (vdev moving out of
> > EAL), let's postpone this for the next release, as also there is no API
> breakage in this (correct me if I am wrong).
> 
> Unexporting a function does require a soname change. So this is affecting
> ABI.

Right, sorry for the delay. You are right, I thought this was not affecting,
as it was internal for the PMDs, but that is also an ABI breakage.

We are discussing in another thread ("cryptodev: fix NULL pointer dereference),
if we are going to have any further API/ABI breakages in the next release, and this is one then.

Pablo

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] cryptodev: fix NULL pointer dereference
  @ 2017-08-01 10:17  3%       ` Sergio Gonzalez Monroy
  2017-08-01 10:48  4%         ` De Lara Guarch, Pablo
  0 siblings, 1 reply; 200+ results
From: Sergio Gonzalez Monroy @ 2017-08-01 10:17 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: Pablo de Lara, dev

On 01/08/2017 10:35, Thomas Monjalon wrote:
> 01/08/2017 10:13, Sergio Gonzalez Monroy:
>> On 31/07/2017 20:33, Thomas Monjalon wrote:
>>> 31/07/2017 11:18, Pablo de Lara:
>>>> When register a crypto driver, a cryptodev driver
>>>> structure was being allocated, using malloc.
>>>> Since this call may fail, it is safer to allocate
>>>> this memory statically in each PMD, so driver registration
>>>> will never fail.
>>>>
>>>> Coverity issue: 158645
>>>>
>>>> Fixes: 7a364faef185 ("cryptodev: remove crypto device type enumeration")
>>>>
>>>> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
>>>> ---
>>>>
>>>> Changes in v2:
>>>>
>>>> - Allocate statically the cryptodev driver structure,
>>>>     instead of using malloc, that can potentially fail.
>>>>
>>>>    drivers/crypto/aesni_gcm/aesni_gcm_pmd.c    |  5 ++++-
>>>>    drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c  |  6 +++++-
>>>>    drivers/crypto/armv8/rte_armv8_pmd.c        |  9 ++++++---
>>>>    drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  5 ++++-
>>>>    drivers/crypto/kasumi/rte_kasumi_pmd.c      |  5 ++++-
>>>>    drivers/crypto/null/null_crypto_pmd.c       |  5 ++++-
>>>>    drivers/crypto/openssl/rte_openssl_pmd.c    |  5 ++++-
>>>>    drivers/crypto/qat/rte_qat_cryptodev.c      |  7 +++++--
>>>>    drivers/crypto/scheduler/scheduler_pmd.c    |  5 ++++-
>>>>    drivers/crypto/snow3g/rte_snow3g_pmd.c      |  5 ++++-
>>>>    drivers/crypto/zuc/rte_zuc_pmd.c            |  5 ++++-
>>>>    lib/librte_cryptodev/rte_cryptodev.c        | 18 +++++------------
>>>>    lib/librte_cryptodev/rte_cryptodev.h        | 20 -------------------
>>>>    lib/librte_cryptodev/rte_cryptodev_pmd.h    | 30 +++++++++++++++++++++++++++++
>>>>    14 files changed, 83 insertions(+), 47 deletions(-)
>>> This is a big change for a small/unlikely issue.
>>> The main benefit of this patch is an allocation cleanup.
>>> I think it is better to wait 17.11 cycle to integrate it.
>> We initially thought of exit given that it is a constructor and if you
>> fail to allocate memory at this stage, things are likely not going to
>> work out anyway.
> You don't know how the application wants to manage it.

IMHO setting an internal variable indicating an error in constructors 
and then reporting the problem during EAL init seems overly complex.
I think the proposed change is a cleaner solution.

>> The patch is an API change, do we really want to break again (we are
>> breaking in this release) next release?
> Good question. Any opinions?

Merge the patch unless there are already outstanding and/or planned 
changes for the next release that are going to break ABI/API?


Thanks,
Sergio

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 0/4] cryptodev vdev changes for -rc2
  @ 2017-07-27 19:31  3%     ` Jan Blunck
  2017-08-01 10:39  4%       ` De Lara Guarch, Pablo
  0 siblings, 1 reply; 200+ results
From: Jan Blunck @ 2017-07-27 19:31 UTC (permalink / raw)
  To: De Lara Guarch, Pablo; +Cc: dev, Doherty, Declan

On Wed, Jul 19, 2017 at 9:31 AM, De Lara Guarch, Pablo
<pablo.de.lara.guarch@intel.com> wrote:
>
>
>
> > -----Original Message-----
> > From: Jan Blunck [mailto:jblunck@gmail.com] On Behalf Of Jan Blunck
> > Sent: Wednesday, July 12, 2017 8:59 PM
> > To: dev@dpdk.org
> > Cc: Doherty, Declan <declan.doherty@intel.com>; De Lara Guarch, Pablo
> > <pablo.de.lara.guarch@intel.com>
> > Subject: [PATCH v2 0/4] cryptodev vdev changes for -rc2
> >
> > This series is a preparation to move the vdev bus out of librte_eal. For that
> > the newly added cryptodev vdev functions need to change signature to not
> > require the rte_vdev.h header.
> >
> > Changes since v1:
> > - move params parsing into new header
> > - make rte_cryptodev_vdev_pmd_init() static inline
> >
> > Jan Blunck (4):
> >   cryptodev: remove obsolete include
> >   cryptodev: move initialization
> >   cryptodev: rework PMD init to not require rte_vdev.h
> >   cryptodev: move parameter parsing to its own header
> >
> >  lib/librte_cryptodev/Makefile                    |  1 +
> >  lib/librte_cryptodev/rte_cryptodev.c             |  3 +
> >  lib/librte_cryptodev/rte_cryptodev.h             |  1 -
> >  lib/librte_cryptodev/rte_cryptodev_pmd.c         | 37 +---------
> >  lib/librte_cryptodev/rte_cryptodev_vdev.h        | 71 ++++++++-----------
> >  lib/librte_cryptodev/rte_cryptodev_vdev_params.h | 89
> > ++++++++++++++++++++++++
> >  lib/librte_cryptodev/rte_cryptodev_version.map   |  1 -
> >  7 files changed, 122 insertions(+), 81 deletions(-)  create mode 100644
> > lib/librte_cryptodev/rte_cryptodev_vdev_params.h
> >
> > --
> > 2.13.2
>
> Hi Jan,
>
> Since there are some issues in this patchset and knowing that these changes are required
> for work to be done in 17.11 (vdev moving out of EAL), let's postpone this for the next release,
> as also there is no API breakage in this (correct me if I am wrong).

Unexporting a function does require a soname change. So this is affecting ABI.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] 17.11 Intel Roadmap
  2017-07-25 10:18  3% [dpdk-dev] 17.11 Intel Roadmap O'Driscoll, Tim
  2017-07-25 13:51  0% ` O'Driscoll, Tim
@ 2017-07-25 15:46  0% ` Alejandro Lucero
  1 sibling, 0 replies; 200+ results
From: Alejandro Lucero @ 2017-07-25 15:46 UTC (permalink / raw)
  To: O'Driscoll, Tim; +Cc: dev

Hi Tim,

I'd like to add this:

Netronome NFP PMD with PF support, including PF mutliport suport. Currently
NFP PMF just supports VFs.

Thanks

On Tue, Jul 25, 2017 at 11:18 AM, O'Driscoll, Tim <tim.odriscoll@intel.com>
wrote:

> Below are the features that we're planning to submit for the 17.11
> release. We'll submit a patch to update the roadmap page with this info.
>
> It would be good if others are also willing to share their plans so that
> we can build up a complete picture of what's planned for 17.11 and make
> sure there's no duplication.
>
>
> QoS Traffic Management Software Fallback and Sample App: The new QoS
> traffic management API (rte_tm) was added to ethdev in 17.08. A software
> fallback using the existing DPDK QoS scheduling library (librte_sched) will
> be added. A sample application will also be created which demonstrates
> usage of this API.
>
> Extend Power Management Lib to Support Per-Core Turbo Boost: The power
> management library will be enhanced to support the ability to enable
> per-core turbo boost for CPUs that support this capability. An example
> usage of this would be in a pipeline model where enabling turbo boost on a
> distributor core will increase overall system performance without having to
> enable turbo on the worker cores.
>
> Power Management Policy Control: This change will allow policy control to
> be applied to power management actions such as changes to p-states. A guest
> will be able to send policy info to a power management process on the host,
> which will apply that policy when making power management changes.
>
> DES SW PMD: A new SW crypto PMD will be created to support DES. This will
> provide an optimized implementation for AVX512, and an unoptimised
> implementation for AVX2/AVX/SSE.
>
> AES CCM Support in OpenSSL PMD: Support for AES CCM mode will be added to
> the OpenSSL PMD. Further details on AES CCM are available at:
> https://en.wikipedia.org/wiki/CCM_mode.
>
> QAT PMD Performance Enhancements: Improve QAT cryptodev driver performance
> by 1) RX/TX CSR writes coalescing, 2) deferred freeing of RX descriptors,
> and 3) removing atomics and assuming single threaded queue pair operation.
>
> Generic Segmentation Offload (GSO): Support for Generic Receive Offload
> (GRO) was added in 17.08. Similar support for GSO will be added in 17.11.
>
> GRO Heavyweight Mode Sample App: The Generic Receive Offload library added
> in 17.08 operates in two modes: lightweight and heavyweight. Use of the
> lightweight mode is demonstrated with testpmd. A sample application will be
> created to demonstrate usage of the heavyweight mode.
>
> Primary/Secondary Process Support for Virtual Devices: Most virtual
> devices don't currently support the primary/secondary process model.
> Support for this will be added.
>
> Extend Port ID to 2 Bytes: The Port ID will be extended to 2 bytes. See
> the ABI deprecation notice for further details: http://www.dpdk.org/dev/
> patchwork/patch/26852/.
>
> I40E API to Configure RSS Queue Regions: The I40E allows queue regions to
> be defined, so that different traffic classes or different packet
> classification types can be sent to different queues.
>
>

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v2] net/i40e: new API to add VF MAC address from PF
  2017-07-24 20:51  3% [dpdk-dev] [PATCH] net/i40e: new API to add VF MAC address from PF Wenzhuo Lu
@ 2017-07-25 14:09  3% ` Wenzhuo Lu
  2017-08-17 13:05  0%   ` Ferruh Yigit
  0 siblings, 1 reply; 200+ results
From: Wenzhuo Lu @ 2017-07-25 14:09 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, Wenzhuo Lu

Currently, on i40e the parameter 'pool' of API
rte_eth_dev_mac_addr_add means the VMDq pool, not VF.
So, it's wrong to use it to set the VF MAC address.
As this API is also used by the VMDq example, ideally
we need a parameter to tell the pool is VMDq or VF.
But it's hard to change it because of the ABI change
concern.
Now the solution is to provide a new API, users can
call it to add VF MAC address from PF on i40e.

Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
---
v2:
 - fixed the compiling issue without i40e pmd.

 app/test-pmd/cmdline.c                    | 11 ++++++--
 drivers/net/i40e/rte_pmd_i40e.c           | 44 +++++++++++++++++++++++++++++++
 drivers/net/i40e/rte_pmd_i40e.h           | 20 ++++++++++++++
 drivers/net/i40e/rte_pmd_i40e_version.map |  1 +
 4 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b1b36c1..87257ad 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -7211,9 +7211,16 @@ static void cmd_vf_mac_addr_parsed(void *parsed_result,
 	struct cmd_vf_mac_addr_result *res = parsed_result;
 	int ret = 0;
 
-	if (strcmp(res->what, "add") == 0)
+	if (strcmp(res->what, "add") != 0)
+		return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+	ret = rte_pmd_i40e_add_vf_mac_addr(res->port_num, res->vf_num,
+					   &res->address);
+	if (ret == -ENOTSUP)
+#endif
 		ret = rte_eth_dev_mac_addr_add(res->port_num,
-					&res->address, res->vf_num);
+					       &res->address, res->vf_num);
 	if(ret < 0)
 		printf("vf_mac_addr_cmd error: (%s)\n", strerror(-ret));
 
diff --git a/drivers/net/i40e/rte_pmd_i40e.c b/drivers/net/i40e/rte_pmd_i40e.c
index f12b7f4..8877239 100644
--- a/drivers/net/i40e/rte_pmd_i40e.c
+++ b/drivers/net/i40e/rte_pmd_i40e.c
@@ -2115,3 +2115,47 @@ int rte_pmd_i40e_ptype_mapping_replace(uint8_t port,
 
 	return 0;
 }
+
+int
+rte_pmd_i40e_add_vf_mac_addr(uint8_t port, uint16_t vf_id,
+			     struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *dev;
+	struct i40e_pf_vf *vf;
+	struct i40e_vsi *vsi;
+	struct i40e_pf *pf;
+	struct i40e_mac_filter_info mac_filter;
+	int ret;
+
+	if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS)
+		return -EINVAL;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+
+	dev = &rte_eth_devices[port];
+
+	if (!is_i40e_supported(dev))
+		return -ENOTSUP;
+
+	pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+	if (vf_id >= pf->vf_num || !pf->vfs)
+		return -EINVAL;
+
+	vf = &pf->vfs[vf_id];
+	vsi = vf->vsi;
+	if (!vsi) {
+		PMD_DRV_LOG(ERR, "Invalid VSI.");
+		return -EINVAL;
+	}
+
+	mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+	ether_addr_copy(mac_addr, &mac_filter.mac_addr);
+	ret = i40e_vsi_add_mac(vsi, &mac_filter);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to add MAC filter.");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/i40e/rte_pmd_i40e.h b/drivers/net/i40e/rte_pmd_i40e.h
index 356fa89..155b7e8 100644
--- a/drivers/net/i40e/rte_pmd_i40e.h
+++ b/drivers/net/i40e/rte_pmd_i40e.h
@@ -637,4 +637,24 @@ int rte_pmd_i40e_ptype_mapping_replace(uint8_t port,
 				       uint8_t mask,
 				       uint32_t pkt_type);
 
+/**
+ * Add a VF MAC address.
+ *
+ * Add more MAC address for VF. The existing MAC addresses
+ * are still effective.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param vf_id
+ *   VF id.
+ * @param mac_addr
+ *   VF MAC address.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENODEV) if *port* invalid.
+ *   - (-EINVAL) if *vf* or *mac_addr* is invalid.
+ */
+int rte_pmd_i40e_add_vf_mac_addr(uint8_t port, uint16_t vf_id,
+				 struct ether_addr *mac_addr);
+
 #endif /* _PMD_I40E_H_ */
diff --git a/drivers/net/i40e/rte_pmd_i40e_version.map b/drivers/net/i40e/rte_pmd_i40e_version.map
index 20cc980..84c6ff1 100644
--- a/drivers/net/i40e/rte_pmd_i40e_version.map
+++ b/drivers/net/i40e/rte_pmd_i40e_version.map
@@ -42,6 +42,7 @@ DPDK_17.05 {
 DPDK_17.08 {
 	global:
 
+	rte_pmd_i40e_add_vf_mac_addr;
 	rte_pmd_i40e_get_ddp_info;
 
 } DPDK_17.05;
-- 
1.9.3

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] 17.11 Intel Roadmap
  2017-07-25 10:18  3% [dpdk-dev] 17.11 Intel Roadmap O'Driscoll, Tim
@ 2017-07-25 13:51  0% ` O'Driscoll, Tim
  2017-07-25 15:46  0% ` Alejandro Lucero
  1 sibling, 0 replies; 200+ results
From: O'Driscoll, Tim @ 2017-07-25 13:51 UTC (permalink / raw)
  To: O'Driscoll, Tim, dev

Apologies, but I missed a feature:

QoS Metering and Policing: A new API will be created to support QoS Metering and Policing. This will include a software implementation using the existing QoS metering library (librte_meter). Further details are available in the RFC at: http://dpdk.org/ml/archives/dev/2017-May/066888.html.


> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of O'Driscoll, Tim
> Sent: Tuesday, July 25, 2017 11:19 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] 17.11 Intel Roadmap
> 
> Below are the features that we're planning to submit for the 17.11
> release. We'll submit a patch to update the roadmap page with this info.
> 
> It would be good if others are also willing to share their plans so that
> we can build up a complete picture of what's planned for 17.11 and make
> sure there's no duplication.
> 
> 
> QoS Traffic Management Software Fallback and Sample App: The new QoS
> traffic management API (rte_tm) was added to ethdev in 17.08. A software
> fallback using the existing DPDK QoS scheduling library (librte_sched)
> will be added. A sample application will also be created which
> demonstrates usage of this API.
> 
> Extend Power Management Lib to Support Per-Core Turbo Boost: The power
> management library will be enhanced to support the ability to enable
> per-core turbo boost for CPUs that support this capability. An example
> usage of this would be in a pipeline model where enabling turbo boost on
> a distributor core will increase overall system performance without
> having to enable turbo on the worker cores.
> 
> Power Management Policy Control: This change will allow policy control
> to be applied to power management actions such as changes to p-states. A
> guest will be able to send policy info to a power management process on
> the host, which will apply that policy when making power management
> changes.
> 
> DES SW PMD: A new SW crypto PMD will be created to support DES. This
> will provide an optimized implementation for AVX512, and an unoptimised
> implementation for AVX2/AVX/SSE.
> 
> AES CCM Support in OpenSSL PMD: Support for AES CCM mode will be added
> to the OpenSSL PMD. Further details on AES CCM are available at:
> https://en.wikipedia.org/wiki/CCM_mode.
> 
> QAT PMD Performance Enhancements: Improve QAT cryptodev driver
> performance by 1) RX/TX CSR writes coalescing, 2) deferred freeing of RX
> descriptors, and 3) removing atomics and assuming single threaded queue
> pair operation.
> 
> Generic Segmentation Offload (GSO): Support for Generic Receive Offload
> (GRO) was added in 17.08. Similar support for GSO will be added in
> 17.11.
> 
> GRO Heavyweight Mode Sample App: The Generic Receive Offload library
> added in 17.08 operates in two modes: lightweight and heavyweight. Use
> of the lightweight mode is demonstrated with testpmd. A sample
> application will be created to demonstrate usage of the heavyweight
> mode.
> 
> Primary/Secondary Process Support for Virtual Devices: Most virtual
> devices don't currently support the primary/secondary process model.
> Support for this will be added.
> 
> Extend Port ID to 2 Bytes: The Port ID will be extended to 2 bytes. See
> the ABI deprecation notice for further details:
> http://www.dpdk.org/dev/patchwork/patch/26852/.
> 
> I40E API to Configure RSS Queue Regions: The I40E allows queue regions
> to be defined, so that different traffic classes or different packet
> classification types can be sent to different queues.

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] 17.11 Intel Roadmap
@ 2017-07-25 10:18  3% O'Driscoll, Tim
  2017-07-25 13:51  0% ` O'Driscoll, Tim
  2017-07-25 15:46  0% ` Alejandro Lucero
  0 siblings, 2 replies; 200+ results
From: O'Driscoll, Tim @ 2017-07-25 10:18 UTC (permalink / raw)
  To: dev

Below are the features that we're planning to submit for the 17.11 release. We'll submit a patch to update the roadmap page with this info.

It would be good if others are also willing to share their plans so that we can build up a complete picture of what's planned for 17.11 and make sure there's no duplication.


QoS Traffic Management Software Fallback and Sample App: The new QoS traffic management API (rte_tm) was added to ethdev in 17.08. A software fallback using the existing DPDK QoS scheduling library (librte_sched) will be added. A sample application will also be created which demonstrates usage of this API.

Extend Power Management Lib to Support Per-Core Turbo Boost: The power management library will be enhanced to support the ability to enable per-core turbo boost for CPUs that support this capability. An example usage of this would be in a pipeline model where enabling turbo boost on a distributor core will increase overall system performance without having to enable turbo on the worker cores.

Power Management Policy Control: This change will allow policy control to be applied to power management actions such as changes to p-states. A guest will be able to send policy info to a power management process on the host, which will apply that policy when making power management changes.

DES SW PMD: A new SW crypto PMD will be created to support DES. This will provide an optimized implementation for AVX512, and an unoptimised implementation for AVX2/AVX/SSE.

AES CCM Support in OpenSSL PMD: Support for AES CCM mode will be added to the OpenSSL PMD. Further details on AES CCM are available at: https://en.wikipedia.org/wiki/CCM_mode.

QAT PMD Performance Enhancements: Improve QAT cryptodev driver performance by 1) RX/TX CSR writes coalescing, 2) deferred freeing of RX descriptors, and 3) removing atomics and assuming single threaded queue pair operation.

Generic Segmentation Offload (GSO): Support for Generic Receive Offload (GRO) was added in 17.08. Similar support for GSO will be added in 17.11.

GRO Heavyweight Mode Sample App: The Generic Receive Offload library added in 17.08 operates in two modes: lightweight and heavyweight. Use of the lightweight mode is demonstrated with testpmd. A sample application will be created to demonstrate usage of the heavyweight mode.

Primary/Secondary Process Support for Virtual Devices: Most virtual devices don't currently support the primary/secondary process model. Support for this will be added.

Extend Port ID to 2 Bytes: The Port ID will be extended to 2 bytes. See the ABI deprecation notice for further details: http://www.dpdk.org/dev/patchwork/patch/26852/.

I40E API to Configure RSS Queue Regions: The I40E allows queue regions to be defined, so that different traffic classes or different packet classification types can be sent to different queues.

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH] net/i40e: new API to add VF MAC address from PF
@ 2017-07-24 20:51  3% Wenzhuo Lu
  2017-07-25 14:09  3% ` [dpdk-dev] [PATCH v2] " Wenzhuo Lu
  0 siblings, 1 reply; 200+ results
From: Wenzhuo Lu @ 2017-07-24 20:51 UTC (permalink / raw)
  To: dev; +Cc: jingjing.wu, beilei.xing, Wenzhuo Lu

Currently, on i40e the parameter 'pool' of API
rte_eth_dev_mac_addr_add means the VMDq pool, not VF.
So, it's wrong to use it to set the VF MAC address.
As this API is also used by the VMDq example, ideally
we need a parameter to tell the pool is VMDq or VF.
But it's hard to change it because of the ABI change
concern.
Now the solution is to provide a new API, users can
call it to add VF MAC address from PF on i40e.

Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
---
 app/test-pmd/cmdline.c                    |  9 +++++--
 drivers/net/i40e/rte_pmd_i40e.c           | 44 +++++++++++++++++++++++++++++++
 drivers/net/i40e/rte_pmd_i40e.h           | 20 ++++++++++++++
 drivers/net/i40e/rte_pmd_i40e_version.map |  1 +
 4 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b1b36c1..2d2a56e 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -7211,9 +7211,14 @@ static void cmd_vf_mac_addr_parsed(void *parsed_result,
 	struct cmd_vf_mac_addr_result *res = parsed_result;
 	int ret = 0;
 
-	if (strcmp(res->what, "add") == 0)
+	if (strcmp(res->what, "add") != 0)
+		return;
+
+	ret = rte_pmd_i40e_add_vf_mac_addr(res->port_num, res->vf_num,
+					   &res->address);
+	if (ret == -ENOTSUP)
 		ret = rte_eth_dev_mac_addr_add(res->port_num,
-					&res->address, res->vf_num);
+					       &res->address, res->vf_num);
 	if(ret < 0)
 		printf("vf_mac_addr_cmd error: (%s)\n", strerror(-ret));
 
diff --git a/drivers/net/i40e/rte_pmd_i40e.c b/drivers/net/i40e/rte_pmd_i40e.c
index f12b7f4..8877239 100644
--- a/drivers/net/i40e/rte_pmd_i40e.c
+++ b/drivers/net/i40e/rte_pmd_i40e.c
@@ -2115,3 +2115,47 @@ int rte_pmd_i40e_ptype_mapping_replace(uint8_t port,
 
 	return 0;
 }
+
+int
+rte_pmd_i40e_add_vf_mac_addr(uint8_t port, uint16_t vf_id,
+			     struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *dev;
+	struct i40e_pf_vf *vf;
+	struct i40e_vsi *vsi;
+	struct i40e_pf *pf;
+	struct i40e_mac_filter_info mac_filter;
+	int ret;
+
+	if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS)
+		return -EINVAL;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+
+	dev = &rte_eth_devices[port];
+
+	if (!is_i40e_supported(dev))
+		return -ENOTSUP;
+
+	pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+	if (vf_id >= pf->vf_num || !pf->vfs)
+		return -EINVAL;
+
+	vf = &pf->vfs[vf_id];
+	vsi = vf->vsi;
+	if (!vsi) {
+		PMD_DRV_LOG(ERR, "Invalid VSI.");
+		return -EINVAL;
+	}
+
+	mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+	ether_addr_copy(mac_addr, &mac_filter.mac_addr);
+	ret = i40e_vsi_add_mac(vsi, &mac_filter);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to add MAC filter.");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/i40e/rte_pmd_i40e.h b/drivers/net/i40e/rte_pmd_i40e.h
index 356fa89..155b7e8 100644
--- a/drivers/net/i40e/rte_pmd_i40e.h
+++ b/drivers/net/i40e/rte_pmd_i40e.h
@@ -637,4 +637,24 @@ int rte_pmd_i40e_ptype_mapping_replace(uint8_t port,
 				       uint8_t mask,
 				       uint32_t pkt_type);
 
+/**
+ * Add a VF MAC address.
+ *
+ * Add more MAC address for VF. The existing MAC addresses
+ * are still effective.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param vf_id
+ *   VF id.
+ * @param mac_addr
+ *   VF MAC address.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENODEV) if *port* invalid.
+ *   - (-EINVAL) if *vf* or *mac_addr* is invalid.
+ */
+int rte_pmd_i40e_add_vf_mac_addr(uint8_t port, uint16_t vf_id,
+				 struct ether_addr *mac_addr);
+
 #endif /* _PMD_I40E_H_ */
diff --git a/drivers/net/i40e/rte_pmd_i40e_version.map b/drivers/net/i40e/rte_pmd_i40e_version.map
index 20cc980..84c6ff1 100644
--- a/drivers/net/i40e/rte_pmd_i40e_version.map
+++ b/drivers/net/i40e/rte_pmd_i40e_version.map
@@ -42,6 +42,7 @@ DPDK_17.05 {
 DPDK_17.08 {
 	global:
 
+	rte_pmd_i40e_add_vf_mac_addr;
 	rte_pmd_i40e_get_ddp_info;
 
 } DPDK_17.05;
-- 
1.9.3

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware
  2017-07-11 10:01  8% [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware Jerin Jacob
@ 2017-07-21  6:41  0% ` santosh
  2017-08-04  3:41  0% ` santosh
  1 sibling, 0 replies; 200+ results
From: santosh @ 2017-07-21  6:41 UTC (permalink / raw)
  To: Jerin Jacob, dev
  Cc: thomas, olivier.matz, stephen, hemant.agrawal, bruce.richardson,
	shreyansh.jain, gaetan.rivet, sergio.gonzalez.monroy,
	anatoly.burakov

On Tuesday 11 July 2017 03:31 PM, Jerin Jacob wrote:

> When we run DPDK on guest or VFIO mode on host,
> the dpdk library or device will not be directly accessing
> the physical address. Instead, the device does go through
> an IO address translation memory management unit. On x86,
> we call it as IOMMU and on ARM as SMMU.
>
> More details:
> http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf
>
> Based on discussion in the following thread
> http://dpdk.org/ml/archives/dev/2017-July/070850.html
>
> We would like to change reference to physical address to more
> appropriate name as with IOMMU/SMMU with
> the device won't be dealing directly with the physical address.
>
> An ABI change is planned for 17.11 to change following
> data structure or functions to more appropriate name.
> Currently planned to change it iova as instead of phys
>
> Please note: The change will be only for the name and
> functional aspects of the API will remain same.
>
> Following functions/data structures name may change.
> This list is based on v17.05-rc1. It may change based on v17.11 code base.
>
>
> typedef:
> phys_addr_t
>
> structures:
>
> struct rte_memseg::phys_addr
> struct rte_mbuf::buf_physaddr
>
> functions:
> rte_mempool_populate_phys()
> rte_mempool_populate_phys_tab()
> rte_eal_using_phys_addrs()
> rte_mem_virt2phy()
> rte_dump_physmem_layout()
> rte_eal_get_physmem_layout()
> rte_eal_get_physmem_size()
> rte_malloc_virt2phy()
> rte_mem_phy2mch()
>
>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> ---

Thomas, All:
Any objection on iova aware deprecation notice?

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-07-20 10:29  7% ` [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool Santosh Shukla
@ 2017-07-21  6:26  4%   ` santosh
  2017-08-03 14:21  4%   ` Jerin Jacob
  1 sibling, 0 replies; 200+ results
From: santosh @ 2017-07-21  6:26 UTC (permalink / raw)
  To: olivier.matz, dev; +Cc: thomas.monjalon


On Thursday 20 July 2017 03:59 PM, Santosh Shukla wrote:

> An API/ABI change is planned for 17.11 to change following
>
> * Remove unused flag param from rte_mempool_generic_get and _put.
> * Change data type for mempool 'flag' from int to unsigned int.
>   Refer [1].
> * Add struct rte_mempool * param into func rte_mempool_xmem_size,
>   rte_mempool_xmem_usage to make it mempool aware.
>   Refer [2].
>
> [1] http://dpdk.org/dev/patchwork/patch/25603/
> [2] http://dpdk.org/dev/patchwork/patch/25605/
>
> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> ---
> v1 --> v2:
> - Changed the title.
> - Added empty line between 'mempool:' and - ``.
> (Both suggested by Olivier)

Thomas, Olivier, all:
If no objection on mempool deprecation notice then
can we plan to get it merged to 17.08? 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v10 20/20] ethdev: add control interface support
  2017-07-08  6:28  3%   ` Yuanhan Liu
@ 2017-07-20 14:55  0%     ` Ferruh Yigit
  0 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2017-07-20 14:55 UTC (permalink / raw)
  To: Yuanhan Liu
  Cc: dev, Stephen Hemminger, Bruce Richardson, Anatoly Burakov,
	Thomas Monjalon

On 7/8/2017 7:28 AM, Yuanhan Liu wrote:
> On Tue, Jul 04, 2017 at 05:13:37PM +0100, Ferruh Yigit wrote:
>> @@ -157,8 +164,12 @@ rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
>>  
>>  	RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL);
>>  	ret = dev_init(eth_dev);
>> -	if (ret)
>> +	if (ret) {
>>  		rte_eth_dev_pci_release(eth_dev);
>> +		return ret;
>> +	}
>> +
>> +	rte_eth_control_interface_create(eth_dev->data->port_id);
> 
> Hi,
> 
> So you are creating a virtual kernel interface for each PCI port. What
> about the VDEVs? If you plan to create one for each port, why not create
> it at the stage while allocating the eth device, or at the stage while
> starting the port if the former is too earlier?

Technically it is possible to support vdevs, but I don't know if there
is usecase for it. If this is required, the change is simple, as you
said this can be possible by moving create API to port start.

> 
> Another thing comes to my mind is have you tried it with multi-process
> model? Looks like it will create the control interface twice? Or it will
> just be failed since the interface already exists?

I didn't test mult-process scenarios, I will test.

> 
> 
> I also have few questions regarding the whole design. So seems that the
> ctrl_if only exports two APIs and they all will be only used in the EAL
> layer. Thus, one question is did you plan to let APP use them? Judging
> EAL already calls them automatically, I don't think it makes sense to
> let the APP call it again. That being said, what's the point of the making
> it be an lib? Why not just put it under EAL or somewhere else, and let
> EAL invoke it as normal helper functions (instead of by public APIs)?

Public APIs are from previous version of the patchset, where user
application was in control on create/destroy and processing messages.
With interfaces automatically created as you said these APIs are not
very meaningful for application.

But code is not so small to put into another library, I believe it is
good to separate this code.

> 
> I will avoid adding a new lib if possible. Otherwise, it increases the
> chance of ABI/API breakage is needed in future for extensions.

Those API are required for other libraries, not sure how to include the
code otherwise.

> 
> The same question goes to the ethtool lib. Since your solution can work
> well with the well-known ethtool, which is also way more widely available
> than the DPDK ethtool app, what's the point of keeping the ethtool app
> then? Like above, I also don't think those APIs are meant for APPs (or
> are they?). Thus, with the ethtool app removed, we then could again avoid
> introducing a new lib.

Ethtool library is ready to use abstraction on ethdev layer, I don't
insist on having it as a separate library, but I believe it is good to
reuse that code instead of re-writing it.

> 
> 	--yliu
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI
  2017-07-20  9:27  4%   ` santosh
@ 2017-07-20 11:26  7%     ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-07-20 11:26 UTC (permalink / raw)
  To: santosh; +Cc: Olivier Matz, dev, jerin.jacob

20/07/2017 12:27, santosh:
> On Thursday 20 July 2017 02:16 PM, Olivier Matz wrote:
> 
> > On Thu, 13 Jul 2017 09:12:31 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:
> >> [PATCH] mempool: add notice to change mempool API/ABI
> > I think the usual titles for these notices are more:
> >
> > doc: announce API/ABI changes for mempool
> 
> in v2.
> 
> > Ideally, the title should describe more precisely the kind of
> > changes. In that particular case, it looks quite difficult,
> > so just saying "mempool" looks okay. Maybe Thomas will prefer
> > one entry per change, I don't know.
> >
> Thomas, Are you fine with approach?

Yes it is OK.
The important words are "announce", "API" and "mempool".
As you are breaking the API, no need to be explicit about ABI.

^ permalink raw reply	[relevance 7%]

* [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool
  2017-07-13  9:12  7% [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI Santosh Shukla
  2017-07-20  8:46  7% ` Olivier Matz
@ 2017-07-20 10:29  7% ` Santosh Shukla
  2017-07-21  6:26  4%   ` santosh
  2017-08-03 14:21  4%   ` Jerin Jacob
  1 sibling, 2 replies; 200+ results
From: Santosh Shukla @ 2017-07-20 10:29 UTC (permalink / raw)
  To: olivier.matz, dev; +Cc: thomas.monjalon, Santosh Shukla

An API/ABI change is planned for 17.11 to change following

* Remove unused flag param from rte_mempool_generic_get and _put.
* Change data type for mempool 'flag' from int to unsigned int.
  Refer [1].
* Add struct rte_mempool * param into func rte_mempool_xmem_size,
  rte_mempool_xmem_usage to make it mempool aware.
  Refer [2].

[1] http://dpdk.org/dev/patchwork/patch/25603/
[2] http://dpdk.org/dev/patchwork/patch/25605/

Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
---
v1 --> v2:
- Changed the title.
- Added empty line between 'mempool:' and - ``.
(Both suggested by Olivier)

 doc/guides/rel_notes/deprecation.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba32..1345b0e65 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,12 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
+
+* mempool: The following will be modified in 17.11:
+
+  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
+    the mempool flag status so adding new param rte_mempool in those API.
+  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
+    and ``rte_mempool_generic_get`` API.
+  - ``rte_mempool`` flags data type will changed from int to
+    unsigned int.
-- 
2.11.0

^ permalink raw reply	[relevance 7%]

* Re: [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI
  2017-07-20  8:46  7% ` Olivier Matz
@ 2017-07-20  9:27  4%   ` santosh
  2017-07-20 11:26  7%     ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: santosh @ 2017-07-20  9:27 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, Thomas Monjalon, jerin.jacob

On Thursday 20 July 2017 02:16 PM, Olivier Matz wrote:

> On Thu, 13 Jul 2017 09:12:31 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:
>> [PATCH] mempool: add notice to change mempool API/ABI
> I think the usual titles for these notices are more:
>
> doc: announce API/ABI changes for mempool

in v2.

> Ideally, the title should describe more precisely the kind of
> changes. In that particular case, it looks quite difficult,
> so just saying "mempool" looks okay. Maybe Thomas will prefer
> one entry per change, I don't know.
>
Thomas, Are you fine with approach?

>> An API/ABI change is planned for 17.11 to change following
>>
>> * Remove unused flag param from rte_mempool_generic_get and _put.
>> * Change data type for mempool 'flag' from int to unsigned int.
>>   Refer [1].
>> * Add struct rte_mempool * param into func rte_mempool_xmem_size,
>>   rte_mempool_xmem_usage to make it mempool aware.
>>   Refer [2].
>>
>> [1] http://dpdk.org/dev/patchwork/patch/25603/
>> [2] http://dpdk.org/dev/patchwork/patch/25605/
>>
>> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
>> ---
>>  doc/guides/rel_notes/deprecation.rst | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>> index 257dcba32..7abb30f5f 100644
>> --- a/doc/guides/rel_notes/deprecation.rst
>> +++ b/doc/guides/rel_notes/deprecation.rst
>> @@ -64,3 +64,11 @@ Deprecation Notices
>>    be removed in 17.11:
>>  
>>    - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
>> +
>> +* mempool: The following will be modified in 17.11:
> I think an empty line is required here, else the generated pdf will
> be incorrect.

in v2. Thanks.

>> +  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
>> +    the mempool flag status so adding new param rte_mempool in those API.
>> +  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
>> +    and ``rte_mempool_generic_get`` API.
>> +  - ``rte_mempool`` flags data type will changed from int to
>> +    unsigned int.

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC] ring: relax alignment constraint on ring structure
  @ 2017-07-20  8:52  0% ` Olivier Matz
  0 siblings, 0 replies; 200+ results
From: Olivier Matz @ 2017-07-20  8:52 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, konstantin.ananyev, daniel.verkamp

Hi,

On Fri, 30 Jun 2017 16:26:09 +0200, Olivier Matz <olivier.matz@6wind.com> wrote:
> The initial objective of
> commit d9f0d3a1ffd4 ("ring: remove split cacheline build setting")
> was to add an empty cache line betwee, the producer and consumer
> data (on platform with cache line size = 64B), preventing from
> having them on adjacent cache lines.
> 
> Following discussion on the mailing list, it appears that this
> also imposes an alignment constraint that is not required.
> 
> This patch removes the extra alignment constraint and adds the
> empty cache lines using padding fields in the structure. The
> size of rte_ring structure and the offset of the fields remain
> the same on platforms with cache line size = 64B:
> 
>   rte_ring = 384
>   rte_ring.name = 0
>   rte_ring.flags = 32
>   rte_ring.memzone = 40
>   rte_ring.size = 48
>   rte_ring.mask = 52
>   rte_ring.prod = 128
>   rte_ring.cons = 256
> 
> But it has an impact on platform where cache line size is 128B:
> 
>   rte_ring = 384        -> 768
>   rte_ring.name = 0
>   rte_ring.flags = 32
>   rte_ring.memzone = 40
>   rte_ring.size = 48
>   rte_ring.mask = 52
>   rte_ring.prod = 128   -> 256
>   rte_ring.cons = 256   -> 512
> 
> Link: http://dpdk.org/dev/patchwork/patch/25039/
> Suggested-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
> ---
> 
> I'm sending this patch to throw the discussion again, but since it
> breaks the ABI on platform with cache lines = 128B, I think we should
> follow the usual ABI breakage process.
> 
> If everybody agree, I'll send a notice and resend a similar patch after
> 17.08.
> 

If there is no comment, I'll send a deprecation notice in the
coming days.

Thanks,
Olivier

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI
  2017-07-13  9:12  7% [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI Santosh Shukla
@ 2017-07-20  8:46  7% ` Olivier Matz
  2017-07-20  9:27  4%   ` santosh
  2017-07-20 10:29  7% ` [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool Santosh Shukla
  1 sibling, 1 reply; 200+ results
From: Olivier Matz @ 2017-07-20  8:46 UTC (permalink / raw)
  To: Santosh Shukla; +Cc: dev, thomas.monjalon, jerin.jacob

On Thu, 13 Jul 2017 09:12:31 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:
> [PATCH] mempool: add notice to change mempool API/ABI

I think the usual titles for these notices are more:

doc: announce API/ABI changes for mempool

Ideally, the title should describe more precisely the kind of
changes. In that particular case, it looks quite difficult,
so just saying "mempool" looks okay. Maybe Thomas will prefer
one entry per change, I don't know.


> An API/ABI change is planned for 17.11 to change following
> 
> * Remove unused flag param from rte_mempool_generic_get and _put.
> * Change data type for mempool 'flag' from int to unsigned int.
>   Refer [1].
> * Add struct rte_mempool * param into func rte_mempool_xmem_size,
>   rte_mempool_xmem_usage to make it mempool aware.
>   Refer [2].
> 
> [1] http://dpdk.org/dev/patchwork/patch/25603/
> [2] http://dpdk.org/dev/patchwork/patch/25605/
> 
> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> ---
>  doc/guides/rel_notes/deprecation.rst | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 257dcba32..7abb30f5f 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -64,3 +64,11 @@ Deprecation Notices
>    be removed in 17.11:
>  
>    - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
> +
> +* mempool: The following will be modified in 17.11:

I think an empty line is required here, else the generated pdf will
be incorrect.

> +  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
> +    the mempool flag status so adding new param rte_mempool in those API.
> +  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
> +    and ``rte_mempool_generic_get`` API.
> +  - ``rte_mempool`` flags data type will changed from int to
> +    unsigned int.

^ permalink raw reply	[relevance 7%]

* [dpdk-dev] [PATCH 1/3] cryptodev: modify some field sizes
@ 2017-07-17  8:29  6% Pablo de Lara
  0 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-17  8:29 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev, Pablo de Lara

Crypto keys and digests are not expected
to be big, so using a uint16_t to store
their lengths should be enough.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 2 ++
 lib/librte_cryptodev/rte_crypto_sym.h  | 8 ++++----
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index c6281eb..27453a3 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -313,6 +313,7 @@ ABI Changes
 * **Reorganized the ``rte_crypto_sym_cipher_xform`` structure.**
 
   * Added cipher IV length and offset parameters.
+  * Changed field size of key length from size_t to uint16_t.
 
 * **Reorganized the ``rte_crypto_sym_auth_xform`` structure.**
 
@@ -320,6 +321,7 @@ ABI Changes
   * Changed field size of AAD length from uint32_t to uint16_t.
   * Changed field size of digest length from uint32_t to uint16_t.
   * Removed AAD length.
+  * Changed field size of key length from size_t to uint16_t.
 
 * Replaced ``dev_type`` enumeration with uint8_t ``driver_id`` in
   ``rte_cryptodev_info`` and  ``rte_cryptodev`` structures.
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index f9955a4..27439af 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -143,7 +143,7 @@ struct rte_crypto_cipher_xform {
 
 	struct {
 		uint8_t *data;	/**< pointer to key data */
-		size_t length;	/**< key length in bytes */
+		uint16_t length;/**< key length in bytes */
 	} key;
 	/**< Cipher key
 	 *
@@ -306,7 +306,7 @@ struct rte_crypto_auth_xform {
 
 	struct {
 		uint8_t *data;	/**< pointer to key data */
-		size_t length;	/**< key length in bytes */
+		uint16_t length;/**< key length in bytes */
 	} key;
 	/**< Authentication key data.
 	 * The authentication key length MUST be less than or equal to the
@@ -389,7 +389,7 @@ struct rte_crypto_aead_xform {
 
 	struct {
 		uint8_t *data;  /**< pointer to key data */
-		size_t length;   /**< key length in bytes */
+		uint16_t length;/**< key length in bytes */
 	} key;
 
 	struct {
@@ -424,7 +424,7 @@ struct rte_crypto_aead_xform {
 		 */
 	} iv;	/**< Initialisation vector parameters */
 
-	uint32_t digest_length;
+	uint16_t digest_length;
 
 	uint16_t add_auth_data_length;
 	/**< The length of the additional authenticated data (AAD) in bytes. */
-- 
2.9.4

^ permalink raw reply	[relevance 6%]

* [dpdk-dev] [PATCH] cryptodev: remove crypto operation status value
@ 2017-07-17 15:25  4% Kirill Rybalchenko
  0 siblings, 0 replies; 200+ results
From: Kirill Rybalchenko @ 2017-07-17 15:25 UTC (permalink / raw)
  To: roy.fan.zhang, declan.doherty; +Cc: dev, Kirill Rybalchenko

Crypto operation status RTE_CRYPTO_OP_STATUS_ENQUEUED is removed
from rte_crypto.h as it is not needed for crypto operation processing.
This status value is redundant to RTE_CRYPTO_OP_STATUS_NOT_PROCESSED value
and it was not intended to be part of public API.

Signed-off-by: Kirill Rybalchenko <kirill.rybalchenko@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst           | 1 +
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c       | 3 +--
 drivers/crypto/scheduler/scheduler_pmd_private.h | 3 +--
 lib/librte_cryptodev/rte_crypto.h                | 2 --
 4 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 6f3b662..fc886a3 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -293,6 +293,7 @@ API Changes
   * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
   * Removed ``aad_size`` parameter from ``rte_cryptodev_sym_capability_check_auth()``.
   * Added ``iv_size`` parameter to ``rte_cryptodev_sym_capability_check_auth()``.
+  * Removed ``RTE_CRYPTO_OP_STATUS_ENQUEUED`` from enum ``rte_crypto_op_status``.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 13cffaf..1b335e0 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -414,7 +414,6 @@ set_mb_job_params(JOB_AES_HMAC *job, struct aesni_mb_qp *qp,
 		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
 		return -1;
 	}
-	op->status = RTE_CRYPTO_OP_STATUS_ENQUEUED;
 
 	/* Set crypto operation */
 	job->chain_order = session->chain_order;
@@ -541,7 +540,7 @@ post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 							op->sym->session,
 							cryptodev_driver_id);
 
-	if (unlikely(op->status == RTE_CRYPTO_OP_STATUS_ENQUEUED)) {
+	if (likely(op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)) {
 		switch (job->status) {
 		case STS_COMPLETED:
 			op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
diff --git a/drivers/crypto/scheduler/scheduler_pmd_private.h b/drivers/crypto/scheduler/scheduler_pmd_private.h
index a786d3a..e606716 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_private.h
+++ b/drivers/crypto/scheduler/scheduler_pmd_private.h
@@ -142,8 +142,7 @@ scheduler_order_drain(struct rte_ring *order_ring,
 
 	while (nb_ops_to_deq < nb_objs) {
 		SCHEDULER_GET_RING_OBJ(order_ring, nb_ops_to_deq, op);
-		if (op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED ||
-					op->status == RTE_CRYPTO_OP_STATUS_ENQUEUED)
+		if (op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
 			break;
 		nb_ops_to_deq++;
 	}
diff --git a/lib/librte_cryptodev/rte_crypto.h b/lib/librte_cryptodev/rte_crypto.h
index 4695229..0908368 100644
--- a/lib/librte_cryptodev/rte_crypto.h
+++ b/lib/librte_cryptodev/rte_crypto.h
@@ -66,8 +66,6 @@ enum rte_crypto_op_status {
 	/**< Operation completed successfully */
 	RTE_CRYPTO_OP_STATUS_NOT_PROCESSED,
 	/**< Operation has not yet been processed by a crypto device */
-	RTE_CRYPTO_OP_STATUS_ENQUEUED,
-	/**< Operation is enqueued on device */
 	RTE_CRYPTO_OP_STATUS_AUTH_FAILED,
 	/**< Authentication verification failed */
 	RTE_CRYPTO_OP_STATUS_INVALID_SESSION,
-- 
2.5.5

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v2 04/15] devargs: deprecate enum rte_devtype based functions
  @ 2017-07-14 21:12  5%   ` Jan Blunck
  0 siblings, 0 replies; 200+ results
From: Jan Blunck @ 2017-07-14 21:12 UTC (permalink / raw)
  To: dev

The enum rte_devtype will need to get extended every time we add a bus.
Mark all related functions as deprecated for 17.11.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 doc/guides/rel_notes/deprecation.rst        | 7 +++++++
 lib/librte_eal/common/include/rte_devargs.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba32..0c763d522 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,10 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
+
+* devargs: An API/ABI change is planed for 17.11 for ``struct rte_devargs`` to
+  remove ``enum rte_devtype`` so that starting from 17.08 the following
+  functions are deprecated:
+
+  - ``rte_eal_devargs_add``
+  - ``rte_eal_devargs_type_count``
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 62dd67bff..41db817cc 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -53,6 +53,7 @@ extern "C" {
 #include <rte_bus.h>
 
 /**
+ * @deprecated
  * Type of generic device
  */
 enum rte_devtype {
@@ -139,6 +140,7 @@ rte_eal_devargs_parse(const char *dev,
 		      struct rte_devargs *da);
 
 /**
+ * @deprecated
  * Add a device to the user device list
  *
  * For PCI devices, the format of arguments string is "PCI_ADDR" or
@@ -163,6 +165,7 @@ rte_eal_devargs_parse(const char *dev,
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * @deprecated
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
2.13.2

^ permalink raw reply	[relevance 5%]

* [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI
@ 2017-07-13  9:12  7% Santosh Shukla
  2017-07-20  8:46  7% ` Olivier Matz
  2017-07-20 10:29  7% ` [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool Santosh Shukla
  0 siblings, 2 replies; 200+ results
From: Santosh Shukla @ 2017-07-13  9:12 UTC (permalink / raw)
  To: olivier.matz, dev; +Cc: thomas.monjalon, jerin.jacob, Santosh Shukla

An API/ABI change is planned for 17.11 to change following

* Remove unused flag param from rte_mempool_generic_get and _put.
* Change data type for mempool 'flag' from int to unsigned int.
  Refer [1].
* Add struct rte_mempool * param into func rte_mempool_xmem_size,
  rte_mempool_xmem_usage to make it mempool aware.
  Refer [2].

[1] http://dpdk.org/dev/patchwork/patch/25603/
[2] http://dpdk.org/dev/patchwork/patch/25605/

Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
---
 doc/guides/rel_notes/deprecation.rst | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba32..7abb30f5f 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,11 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
+
+* mempool: The following will be modified in 17.11:
+  - ``rte_mempool_xmem_size`` and ``rte_mempool_xmem_usage`` need to know
+    the mempool flag status so adding new param rte_mempool in those API.
+  - Removing __rte_unused int flag param from ``rte_mempool_generic_put``
+    and ``rte_mempool_generic_get`` API.
+  - ``rte_mempool`` flags data type will changed from int to
+    unsigned int.
-- 
2.13.0

^ permalink raw reply	[relevance 7%]

* [dpdk-dev] [PATCH] doc: notify callback process API change
@ 2017-07-12  9:25  4% Bernard Iremonger
  0 siblings, 0 replies; 200+ results
From: Bernard Iremonger @ 2017-07-12  9:25 UTC (permalink / raw)
  To: dev, thomas; +Cc: Bernard Iremonger

The _rte_eth_dev_callback_process function has been modified.
The return value has been changed form void to int and an
extra parameter "void *ret_param" has been added.

Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 6273098..24f0741 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -284,6 +284,11 @@ API Changes
   * Remove ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
   * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
 
+* **Modified the _rte_eth_dev_callback_process function in the rte_ethdev library.**
+
+  The function ``_rte_eth_dev_callback_process()`` has been modified. The return
+  value has been changed from void to int and an extra parameter ``void *ret_param``
+  has been added.
 
 ABI Changes
 -----------
@@ -350,7 +355,7 @@ The libraries prepended with a plus sign were incremented in this version.
    + librte_cryptodev.so.3
      librte_distributor.so.1
      librte_eal.so.4
-     librte_ethdev.so.6
+   + librte_ethdev.so.7
    + librte_gro.so.1
      librte_hash.so.2
      librte_ip_frag.so.1
-- 
1.9.1

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev
@ 2017-07-12  7:58 13% Zhiyong Yang
  2017-08-04  1:12  4% ` Tan, Jianfeng
                   ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Zhiyong Yang @ 2017-07-12  7:58 UTC (permalink / raw)
  To: dev, zhihong.wang; +Cc: john.mcnamara, oilvier.matz, thomas, Zhiyong Yang

  This is an API/ABI change notice for DPDK 17.11 on redefinition of
port_id. port_id is defined as uint8_t by now, which is just ranged
from 0 to 255. For more and more scenerioes, more than 256 devices are
needed to support for vdev scalability.

  It is necessary for redefinition of port_id to extend from 1 bytes
to 2 bytes. All ethdev APIs and use cases related to port_id will be
changed at the same time.

Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
---
 doc/guides/rel_notes/deprecation.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba..f265980 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -54,6 +54,10 @@ Deprecation Notices
   Target release for removal of the legacy API will be defined once most
   PMDs have switched to rte_flow.
 
+* ABI/API changes are planned for 17.11 in the "rte_eth_dev_data" structure.
+  Change the definition of port_id from 8bits to 16bits in order to support
+  more than 256 devices in DPDK.
+
 * librte_table: The ``key_mask`` parameter will be added to all the hash tables
   that currently do not have it, as well as to the hash compute function prototype.
   The non-"do-sig" versions of the hash tables will be removed
-- 
2.9.3

^ permalink raw reply	[relevance 13%]

* [dpdk-dev] [PATCH 03/13] devargs: deprecate enum rte_devtype based functions
  @ 2017-07-11 23:25  5% ` Jan Blunck
  2017-08-07 23:02  0%   ` Thomas Monjalon
    1 sibling, 1 reply; 200+ results
From: Jan Blunck @ 2017-07-11 23:25 UTC (permalink / raw)
  To: dev

The enum rte_devtype will need to get extended every time we add a bus.
Mark all related functions as deprecated for 17.11.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 doc/guides/rel_notes/deprecation.rst        | 7 +++++++
 lib/librte_eal/common/include/rte_devargs.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba32..0c763d522 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,10 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
+
+* devargs: An API/ABI change is planed for 17.11 for ``struct rte_devargs`` to
+  remove ``enum rte_devtype`` so that starting from 17.08 the following
+  functions are deprecated:
+
+  - ``rte_eal_devargs_add``
+  - ``rte_eal_devargs_type_count``
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 62dd67bff..41db817cc 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -53,6 +53,7 @@ extern "C" {
 #include <rte_bus.h>
 
 /**
+ * @deprecated
  * Type of generic device
  */
 enum rte_devtype {
@@ -139,6 +140,7 @@ rte_eal_devargs_parse(const char *dev,
 		      struct rte_devargs *da);
 
 /**
+ * @deprecated
  * Add a device to the user device list
  *
  * For PCI devices, the format of arguments string is "PCI_ADDR" or
@@ -163,6 +165,7 @@ rte_eal_devargs_parse(const char *dev,
 int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
 
 /**
+ * @deprecated
  * Count the number of user devices of a specified type
  *
  * @param devtype
-- 
2.13.2

^ permalink raw reply	[relevance 5%]

* [dpdk-dev] [PATCH] cryptodev: remove AAD size in auth capabilities
@ 2017-07-11  6:30  3% Pablo de Lara
  0 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-11  6:30 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev, Pablo de Lara

Additional Authenticated Data (AAD) was removed from the
authentication parameters, but still the supported size
was part of the authentication capabilities of a PMD.

Fixes: 4428eda8bb75 ("cryptodev: remove AAD from authentication structure")

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/main.c                    |  1 -
 doc/guides/rel_notes/release_17_08.rst         |  2 ++
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c   |  1 -
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c |  7 -------
 drivers/crypto/armv8/rte_armv8_pmd_ops.c       |  2 --
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h      |  6 ------
 drivers/crypto/kasumi/rte_kasumi_pmd_ops.c     |  3 +--
 drivers/crypto/null/null_crypto_pmd_ops.c      |  1 -
 drivers/crypto/openssl/rte_openssl_pmd_ops.c   | 12 ------------
 drivers/crypto/qat/qat_crypto_capabilities.h   | 16 +++-------------
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c     |  3 +--
 drivers/crypto/zuc/rte_zuc_pmd_ops.c           |  3 +--
 lib/librte_cryptodev/rte_cryptodev.c           |  6 +-----
 lib/librte_cryptodev/rte_cryptodev.h           |  4 +---
 14 files changed, 10 insertions(+), 57 deletions(-)

diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 51345ea..99f5d3e 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -208,7 +208,6 @@ cperf_verify_devices_capabilities(struct cperf_options *opts,
 					capability,
 					opts->auth_key_sz,
 					opts->digest_sz,
-					0,
 					opts->auth_iv_sz);
 			if (ret != 0)
 				return ret;
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 6c00509..36e9ddb 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -257,6 +257,8 @@ API Changes
     ``mempool``, instead of ``device id`` and ``rte_crypto_sym_xform``.
   * Remove ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
   * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
+  * Removed ``aad_size`` parameter from ``rte_cryptodev_sym_capability_check_auth()``.
+  * Added ``iv_size`` parameter to ``rte_cryptodev_sym_capability_check_auth().
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
index 6d24a32..af107a5 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
@@ -56,7 +56,6 @@ static const struct rte_cryptodev_capabilities aesni_gcm_pmd_capabilities[] = {
 					.max = 16,
 					.increment = 4
 				},
-				.aad_size = { 0 },
 				.iv_size = {
 					.min = 12,
 					.max = 12,
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
index e3a6ef5..d033408 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -57,7 +57,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 12,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -79,7 +78,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 12,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -101,7 +99,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 14,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -123,7 +120,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 16,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -145,7 +141,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 24,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -167,7 +162,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 32,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -189,7 +183,6 @@ static const struct rte_cryptodev_capabilities aesni_mb_pmd_capabilities[] = {
 					.max = 12,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
index 05a7703..cc77d40 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
@@ -59,7 +59,6 @@ static const struct rte_cryptodev_capabilities
 						.max = 20,
 						.increment = 0
 					},
-					.aad_size = { 0 },
 					.iv_size = { 0 }
 				}, }
 			}, }
@@ -81,7 +80,6 @@ static const struct rte_cryptodev_capabilities
 						.max = 32,
 						.increment = 0
 					},
-					.aad_size = { 0 },
 					.iv_size = { 0 }
 				}, }
 			}, }
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index bd85e3a..2bf4edc 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -209,7 +209,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 					.max = 16,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -231,7 +230,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 					.max = 20,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -253,7 +251,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 					.max = 28,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -275,7 +272,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 						.max = 32,
 						.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 				}, }
 			}, }
@@ -297,7 +293,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 					.max = 48,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -319,7 +314,6 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 					.max = 64,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
index 1d9c0fc..e92ccbd 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
@@ -60,8 +60,7 @@ static const struct rte_cryptodev_capabilities kasumi_pmd_capabilities[] = {
 					.min = 8,
 					.max = 8,
 					.increment = 0
-				},
-				.aad_size = { 0 }
+				}
 			}, }
 		}, }
 	},
diff --git a/drivers/crypto/null/null_crypto_pmd_ops.c b/drivers/crypto/null/null_crypto_pmd_ops.c
index c618e6b..13e7a19 100644
--- a/drivers/crypto/null/null_crypto_pmd_ops.c
+++ b/drivers/crypto/null/null_crypto_pmd_ops.c
@@ -56,7 +56,6 @@ static const struct rte_cryptodev_capabilities null_crypto_pmd_capabilities[] =
 					.max = 0,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, },
 		}, },
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 1db4d14..ae367ac 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -57,7 +57,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 16,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -79,7 +78,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 16,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -101,7 +99,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 20,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -123,7 +120,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 20,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -145,7 +141,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 28,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -167,7 +162,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 28,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -189,7 +183,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 32,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -211,7 +204,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 32,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -233,7 +225,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 48,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -255,7 +246,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 48,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -277,7 +267,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 64,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
@@ -299,7 +288,6 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 					.max = 64,
 					.increment = 0
 				},
-				.aad_size = { 0 },
 				.iv_size = { 0 }
 			}, }
 		}, }
diff --git a/drivers/crypto/qat/qat_crypto_capabilities.h b/drivers/crypto/qat/qat_crypto_capabilities.h
index fee8ee1..16b2c11 100644
--- a/drivers/crypto/qat/qat_crypto_capabilities.h
+++ b/drivers/crypto/qat/qat_crypto_capabilities.h
@@ -52,7 +52,6 @@
 					.max = 20,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -74,7 +73,6 @@
 					.max = 28,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -96,7 +94,6 @@
 					.max = 32,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -118,7 +115,6 @@
 					.max = 48,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -140,7 +136,6 @@
 					.max = 64,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -162,7 +157,6 @@
 					.max = 16,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, }						\
 		}, }							\
@@ -265,8 +259,7 @@
 					.min = 16,			\
 					.max = 16,			\
 					.increment = 0			\
-				},					\
-				.aad_size = { 0 }			\
+				}					\
 			}, }						\
 		}, }							\
 	},								\
@@ -367,7 +360,6 @@
 					.max = 0,			\
 					.increment = 0			\
 				},					\
-				.aad_size = { 0 },			\
 				.iv_size = { 0 }			\
 			}, },						\
 		}, },							\
@@ -433,8 +425,7 @@
 					.min = 8,			\
 					.max = 8,			\
 					.increment = 0			\
-				},					\
-				.aad_size = { 0 }			\
+				}					\
 			}, }						\
 		}, }							\
 	},								\
@@ -561,8 +552,7 @@
 					.min = 16,			\
 					.max = 16,			\
 					.increment = 0			\
-				},					\
-				.aad_size = { 0 }			\
+				}					\
 			}, }						\
 		}, }							\
 	}
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
index 108f251..62ba3a6 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -60,8 +60,7 @@ static const struct rte_cryptodev_capabilities snow3g_pmd_capabilities[] = {
 					.min = 16,
 					.max = 16,
 					.increment = 0
-				},
-				.aad_size = { 0 }
+				}
 			}, }
 		}, }
 	},
diff --git a/drivers/crypto/zuc/rte_zuc_pmd_ops.c b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
index 7cb3f1c..7624e67 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd_ops.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
@@ -60,8 +60,7 @@ static const struct rte_cryptodev_capabilities zuc_pmd_capabilities[] = {
 					.min = 16,
 					.max = 16,
 					.increment = 0
-				},
-				.aad_size = { 0 }
+				}
 			}, }
 		}, }
 	},
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 8ee5d47..bdea267 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -311,8 +311,7 @@ rte_cryptodev_sym_capability_check_cipher(
 int
 rte_cryptodev_sym_capability_check_auth(
 		const struct rte_cryptodev_symmetric_capability *capability,
-		uint16_t key_size, uint16_t digest_size, uint16_t aad_size,
-		uint16_t iv_size)
+		uint16_t key_size, uint16_t digest_size, uint16_t iv_size)
 {
 	if (param_range_check(key_size, capability->auth.key_size))
 		return -1;
@@ -320,9 +319,6 @@ rte_cryptodev_sym_capability_check_auth(
 	if (param_range_check(digest_size, capability->auth.digest_size))
 		return -1;
 
-	if (param_range_check(aad_size, capability->auth.aad_size))
-		return -1;
-
 	if (param_range_check(iv_size, capability->auth.iv_size))
 		return -1;
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index ca7cbdd..3ec8af9 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -238,7 +238,6 @@ rte_cryptodev_sym_capability_check_cipher(
  * @param	capability	Description of the symmetric crypto capability.
  * @param	key_size	Auth key size.
  * @param	digest_size	Auth digest size.
- * @param	aad_size	Auth aad size.
  * @param	iv_size		Auth initial vector size.
  *
  * @return
@@ -248,8 +247,7 @@ rte_cryptodev_sym_capability_check_cipher(
 int
 rte_cryptodev_sym_capability_check_auth(
 		const struct rte_cryptodev_symmetric_capability *capability,
-		uint16_t key_size, uint16_t digest_size, uint16_t aad_size,
-		uint16_t iv_size);
+		uint16_t key_size, uint16_t digest_size, uint16_t iv_size);
 
 /**
  * Check if key, digest, AAD and initial vector sizes are supported
-- 
2.9.4

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v5 1/7] service cores: header and implementation
  @ 2017-07-11 14:19  1%     ` Harry van Haaren
  0 siblings, 0 replies; 200+ results
From: Harry van Haaren @ 2017-07-11 14:19 UTC (permalink / raw)
  To: dev; +Cc: thomas, jerin.jacob, keith.wiles, bruce.richardson, Harry van Haaren

Add header files, update .map files with new service
functions, and add the service header to the doxygen
for building.

This service header API allows DPDK to use services as
a concept of something that requires CPU cycles. An example
is a PMD that runs in software to schedule events, where a
hardware version exists that does not require a CPU.

Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>

---

v5:
- Improved service_set_stats_enable() to operate per service (Jerin)
- Fixed un-documented doxygen parameter (Jerin)
- Renamed cores_state to lcore_states (Jerin)
- Optimized atomic operations and flags (Jerin)
- Removed info about RFCs etc from commit message (Jerin)
- Add lcore_count check to default setup function and return early (Jerin)
- Add memory barriers to lcore_add() and lcore_del() (Jerin)
- Rename start function to rte_service_start_with_defaults() (Jerin)
- Rename header to rte_service_component.h (Jerin/Thomas)

v4:
- Fixed (unsigned) checkpatch error
- Fixed misleading-indentation/if { } brackets (checkpatch/Jerin)
- Fixed set function argument to be "enable" instead of "enabled" (Jerin)
- Improve doxygen comment for size of array in rte_service_core_list (Jerin)
- Fixed typos (Jerin)
- Optimized atomic clear after running service (Jerin)
- Added smp_rmb() at end of loop to re-load runstate / mapping (Jerin)
- Fix issue with lcore role not being adhered to (Jerin)
- Add experimental warnings for all service core functions (Thomas)
- Moved service core functions into EXPERIMENTAL section of .map (Thomas)
- Improve documentation of rte_service_lcore_reset_all() (Harry)

v3:
- None.

v2:
Thanks Jerin for review - below a list your suggested changes;
- Doxygen rename to "service cores" for consistency
- use lcore instead of core for function names
- Fix about 10 typos / seplling msitakse ;)
- Dix doxygen /** comments for functions
- Doxygen @param[out] improvements
- int8_t for socket_id to ordinary int
- Rename MACROS for readability
- Align structs to cache lines
- Allocate fastpath-used data from hugepages
- Added/fixed memory barriers for multi-core scheduling
- Add const to variables, and hoist above loop
- Optimize cmpset atomic if MT_SAFE or only one core mapped
- Statistics collection only when requested
- Add error check for array pointer
- Remove panic() calls from library
- Fix TODO notes from previous patchset

There are also some other changes;
- Checkpatch issues fixed
- .map file updates
- Add rte_service_get_by_name() function
---
 doc/api/doxy-api-index.md                          |   1 +
 lib/librte_eal/bsdapp/eal/Makefile                 |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  23 +
 lib/librte_eal/common/Makefile                     |   1 +
 lib/librte_eal/common/eal_common_lcore.c           |   1 +
 lib/librte_eal/common/include/rte_eal.h            |   4 +
 lib/librte_eal/common/include/rte_lcore.h          |   3 +-
 lib/librte_eal/common/include/rte_service.h        | 387 +++++++++++
 .../common/include/rte_service_component.h         | 144 +++++
 lib/librte_eal/common/rte_service.c                | 704 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_thread.c           |   9 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  23 +
 13 files changed, 1300 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/common/include/rte_service.h
 create mode 100644 lib/librte_eal/common/include/rte_service_component.h
 create mode 100644 lib/librte_eal/common/rte_service.c

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 67594e1..e99e114 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -160,6 +160,7 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
+  [service cores]      (@ref rte_service.h),
   [device metrics]     (@ref rte_metrics.h),
   [bitrate statistics] (@ref rte_bitrate.h),
   [latency statistics] (@ref rte_latencystats.h),
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a0f9950..05517a2 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -87,6 +87,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 381f895..480ad23 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -209,5 +209,28 @@ EXPERIMENTAL {
 	rte_eal_devargs_parse;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_start_with_defaults;
+	rte_service_stop;
+	rte_service_unregister;
 
 } DPDK_17.08;
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index f2fe052..e8fd67a 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -41,6 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
+INC += rte_service.h rte_service_component.h
 
 GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
 GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h
diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
index 84fa0cb..0db1555 100644
--- a/lib/librte_eal/common/eal_common_lcore.c
+++ b/lib/librte_eal/common/eal_common_lcore.c
@@ -81,6 +81,7 @@ rte_eal_cpu_init(void)
 
 		/* By default, each detected core is enabled */
 		config->lcore_role[lcore_id] = ROLE_RTE;
+		lcore_config[lcore_id].core_role = ROLE_RTE;
 		lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
 		lcore_config[lcore_id].socket_id = eal_cpu_socket_id(lcore_id);
 		if (lcore_config[lcore_id].socket_id >= RTE_MAX_NUMA_NODES) {
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
index 6b7c5ca..0e7363d 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -61,6 +61,7 @@ extern "C" {
 enum rte_lcore_role_t {
 	ROLE_RTE,
 	ROLE_OFF,
+	ROLE_SERVICE,
 };
 
 /**
@@ -80,6 +81,7 @@ enum rte_proc_type_t {
 struct rte_config {
 	uint32_t master_lcore;       /**< Id of the master lcore */
 	uint32_t lcore_count;        /**< Number of available logical cores. */
+	uint32_t service_lcore_count;/**< Number of available service cores. */
 	enum rte_lcore_role_t lcore_role[RTE_MAX_LCORE]; /**< State of cores. */
 
 	/** Primary or secondary configuration */
@@ -185,6 +187,8 @@ int rte_eal_iopl_init(void);
  *
  *     EPROTO indicates that the PCI bus is either not present, or is not
  *            readable by the eal.
+ *
+ *     ENOEXEC indicates that a service core failed to launch successfully.
  */
 int rte_eal_init(int argc, char **argv);
 
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/common/include/rte_lcore.h
index fe7b586..50e0d0f 100644
--- a/lib/librte_eal/common/include/rte_lcore.h
+++ b/lib/librte_eal/common/include/rte_lcore.h
@@ -73,6 +73,7 @@ struct lcore_config {
 	unsigned core_id;          /**< core number on socket for this lcore */
 	int core_index;            /**< relative index, starting from 0 */
 	rte_cpuset_t cpuset;       /**< cpu set which the lcore affinity to */
+	uint8_t core_role;         /**< role of core eg: OFF, RTE, SERVICE */
 };
 
 /**
@@ -175,7 +176,7 @@ rte_lcore_is_enabled(unsigned lcore_id)
 	struct rte_config *cfg = rte_eal_get_configuration();
 	if (lcore_id >= RTE_MAX_LCORE)
 		return 0;
-	return cfg->lcore_role[lcore_id] != ROLE_OFF;
+	return cfg->lcore_role[lcore_id] == ROLE_RTE;
 }
 
 /**
diff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/common/include/rte_service.h
new file mode 100644
index 0000000..7c6f738
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service.h
@@ -0,0 +1,387 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_H_
+#define _RTE_SERVICE_H_
+
+/**
+ * @file
+ *
+ * Service functions
+ *
+ * The service functionality provided by this header allows a DPDK component
+ * to indicate that it requires a function call in order for it to perform
+ * its processing.
+ *
+ * An example usage of this functionality would be a component that registers
+ * a service to perform a particular packet processing duty: for example the
+ * eventdev software PMD. At startup the application requests all services
+ * that have been registered, and the cores in the service-coremask run the
+ * required services. The EAL removes these number of cores from the available
+ * runtime cores, and dedicates them to performing service-core workloads. The
+ * application has access to the remaining lcores as normal.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include<stdio.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_lcore.h>
+
+/* forward declaration only. Definition in rte_service_private.h */
+struct rte_service_spec;
+
+#define RTE_SERVICE_NAME_MAX 32
+
+/* Capabilities of a service.
+ *
+ * Use the *rte_service_probe_capability* function to check if a service is
+ * capable of a specific capability.
+ */
+/** When set, the service is capable of having multiple threads run it at the
+ *  same time.
+ */
+#define RTE_SERVICE_CAP_MT_SAFE (1 << 0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ *  Return the number of services registered.
+ *
+ * The number of services registered can be passed to *rte_service_get_by_id*,
+ * enabling the application to retrieve the specification of each service.
+ *
+ * @return The number of services registered.
+ */
+uint32_t rte_service_get_count(void);
+
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the specification of a service by integer id.
+ *
+ * This function provides the specification of a service. This can be used by
+ * the application to understand what the service represents. The service
+ * must not be modified by the application directly, only passed to the various
+ * rte_service_* functions.
+ *
+ * @param id The integer id of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *id* provided.
+ */
+struct rte_service_spec *rte_service_get_by_id(uint32_t id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the specification of a service by name.
+ *
+ * This function provides the specification of a service using the service name
+ * as lookup key. This can be used by the application to understand what the
+ * service represents. The service must not be modified by the application
+ * directly, only passed to the various rte_service_* functions.
+ *
+ * @param name The name of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *name* provided.
+ */
+struct rte_service_spec *rte_service_get_by_name(const char *name);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the name of the service.
+ *
+ * @return A pointer to the name of the service. The returned pointer remains
+ *         in ownership of the service, and the application must not free it.
+ */
+const char *rte_service_get_name(const struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check if a service has a specific capability.
+ *
+ * This function returns if *service* has implements *capability*.
+ * See RTE_SERVICE_CAP_* defines for a list of valid capabilities.
+ * @retval 1 Capability supported by this service instance
+ * @retval 0 Capability not supported by this service instance
+ */
+int32_t rte_service_probe_capability(const struct rte_service_spec *service,
+				     uint32_t capability);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions adds *lcore* to the set of cores that will run *service*.
+ *
+ * If multiple cores are enabled on a service, an atomic is used to ensure that
+ * only one cores runs the service at a time. The exception to this is when
+ * a service indicates that it is multi-thread safe by setting the capability
+ * called RTE_SERVICE_CAP_MT_SAFE. With the multi-thread safe capability set,
+ * the service function can be run on multiple threads at the same time.
+ *
+ * @retval 0 lcore added successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_enable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Disable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions removes *lcore* to the set of cores that will run *service*.
+ *
+ * @retval 0 Lcore removed successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_disable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return if an lcore is enabled for the service.
+ *
+ * This function allows the application to query if *lcore* is currently set to
+ * run *service*.
+ *
+ * @retval 1 Lcore enabled on this lcore
+ * @retval 0 Lcore disabled on this lcore
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore);
+
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable *service* to run.
+ *
+ * This function switches on a service during runtime.
+ * @retval 0 The service was successfully started
+ */
+int32_t rte_service_start(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Disable *service*.
+ *
+ * Switch off a service, so it is not run until it is *rte_service_start* is
+ * called on it.
+ * @retval 0 Service successfully switched off
+ */
+int32_t rte_service_stop(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Returns if *service* is currently running.
+ *
+ * This function returns true if the service has been started using
+ * *rte_service_start*, AND a service core is mapped to the service. This
+ * function can be used to ensure that the service will be run.
+ *
+ * @retval 1 Service is currently running, and has a service lcore mapped
+ * @retval 0 Service is currently stopped, or no service lcore is mapped
+ * @retval -EINVAL Invalid service pointer provided
+ */
+int32_t rte_service_is_running(const struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a service core.
+ *
+ * Starting a core makes the core begin polling. Any services assigned to it
+ * will be run as fast as possible.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Failed to start core. The *lcore_id* passed in is not
+ *          currently assigned to be a service core.
+ */
+int32_t rte_service_lcore_start(uint32_t lcore_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop a service core.
+ *
+ * Stopping a core makes the core become idle, but remains  assigned as a
+ * service core.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Invalid *lcore_id* provided
+ * @retval -EALREADY Already stopped core
+ * @retval -EBUSY Failed to stop core, as it would cause a service to not
+ *          be run, as this is the only core currently running the service.
+ *          The application must stop the service first, and then stop the
+ *          lcore.
+ */
+int32_t rte_service_lcore_stop(uint32_t lcore_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Adds lcore to the list of service cores.
+ *
+ * This functions can be used at runtime in order to modify the service core
+ * mask.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY lcore is busy, and not available for service core duty
+ * @retval -EALREADY lcore is already added to the service core list
+ * @retval -EINVAL Invalid lcore provided
+ */
+int32_t rte_service_lcore_add(uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Removes lcore from the list of service cores.
+ *
+ * This can fail if the core is not stopped, see *rte_service_core_stop*.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY Lcore is not stopped, stop service core before removing.
+ * @retval -EINVAL failed to add lcore to service core mask.
+ */
+int32_t rte_service_lcore_del(uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the number of service cores currently available.
+ *
+ * This function returns the integer count of service cores available. The
+ * service core count can be used in mapping logic when creating mappings
+ * from service cores to services.
+ *
+ * See *rte_service_lcore_list* for details on retrieving the lcore_id of each
+ * service core.
+ *
+ * @return The number of service cores currently configured.
+ */
+int32_t rte_service_lcore_count(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Resets all service core mappings. This does not remove the service cores
+ * from duty, just unmaps all services / cores, and stops() the service cores.
+ * The runstate of services is not modified.
+ *
+ * @retval 0 Success
+ */
+int32_t rte_service_lcore_reset_all(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable or disable statistics collection for *service*.
+ *
+ * This function enables per core, per-service cycle count collection.
+ * @param service The service to enable statistics gathering on.
+ * @param enable Zero to disable statistics, non-zero to enable.
+ * @retval 0 Success
+ * @retval -EINVAL Invalid service pointer passed
+ */
+int32_t rte_service_set_stats_enable(struct rte_service_spec *service,
+				  int32_t enable);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the list of currently enabled service cores.
+ *
+ * This function fills in an application supplied array, with each element
+ * indicating the lcore_id of a service core.
+ *
+ * Adding and removing service cores can be performed using
+ * *rte_service_lcore_add* and *rte_service_lcore_del*.
+ * @param [out] array An array of at least *rte_service_lcore_count* items.
+ *              If statically allocating the buffer, use RTE_MAX_LCORE.
+ * @param [out] n The size of *array*.
+ * @retval >=0 Number of service cores that have been populated in the array
+ * @retval -ENOMEM The provided array is not large enough to fill in the
+ *          service core list. No items have been populated, call this function
+ *          with a size of at least *rte_service_core_count* items.
+ */
+int32_t rte_service_lcore_list(uint32_t array[], uint32_t n);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Dumps any information available about the service. If service is NULL,
+ * dumps info for all services.
+ */
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_SERVICE_H_ */
diff --git a/lib/librte_eal/common/include/rte_service_component.h b/lib/librte_eal/common/include/rte_service_component.h
new file mode 100644
index 0000000..7a946a1
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service_component.h
@@ -0,0 +1,144 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_PRIVATE_H_
+#define _RTE_SERVICE_PRIVATE_H_
+
+/* This file specifies the internal service specification.
+ * Include this file if you are writing a component that requires CPU cycles to
+ * operate, and you wish to run the component using service cores
+ */
+
+#include <rte_service.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Signature of callback function to run a service.
+ */
+typedef int32_t (*rte_service_func)(void *args);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * The specification of a service.
+ *
+ * This struct contains metadata about the service itself, the callback
+ * function to run one iteration of the service, a userdata pointer, flags etc.
+ */
+struct rte_service_spec {
+	/** The name of the service. This should be used by the application to
+	 * understand what purpose this service provides.
+	 */
+	char name[RTE_SERVICE_NAME_MAX];
+	/** The callback to invoke to run one iteration of the service. */
+	rte_service_func callback;
+	/** The userdata pointer provided to the service callback. */
+	void *callback_userdata;
+	/** Flags to indicate the capabilities of this service. See defines in
+	 * the public header file for values of RTE_SERVICE_CAP_*
+	 */
+	uint32_t capabilities;
+	/** NUMA socket ID that this service is affinitized to */
+	int socket_id;
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register a new service.
+ *
+ * A service represents a component that the requires CPU time periodically to
+ * achieve its purpose.
+ *
+ * For example the eventdev SW PMD requires CPU cycles to perform its
+ * scheduling. This can be achieved by registering it as a service, and the
+ * application can then assign CPU resources to it using
+ * *rte_service_set_coremask*.
+ *
+ * @param spec The specification of the service to register
+ * @retval 0 Successfully registered the service.
+ *         -EINVAL Attempted to register an invalid service (eg, no callback
+ *         set)
+ */
+int32_t rte_service_register(const struct rte_service_spec *spec);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Unregister a service.
+ *
+ * The service being removed must be stopped before calling this function.
+ *
+ * @retval 0 The service was successfully unregistered.
+ * @retval -EBUSY The service is currently running, stop the service before
+ *          calling unregister. No action has been taken.
+ */
+int32_t rte_service_unregister(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Private function to allow EAL to initialized default mappings.
+ *
+ * This function iterates all the services, and maps then to the available
+ * cores. Based on the capabilities of the services, they are set to run on the
+ * available cores in a round-robin manner.
+ *
+ * @retval 0 Success
+ * @retval -ENOTSUP No service lcores in use
+ * @retval -EINVAL Error while iterating over services
+ * @retval -ENODEV Error in enabling service lcore on a service
+ * @retval -ENOEXEC Error when starting services
+ */
+int32_t rte_service_start_with_defaults(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Initialize the service library.
+ *
+ * In order to use the service library, it must be initialized. EAL initializes
+ * the library at startup.
+ *
+ * @retval 0 Success
+ * @retval -EALREADY Service library is already initialized
+ */
+int32_t rte_service_init(void);
+
+#endif /* _RTE_SERVICE_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c
new file mode 100644
index 0000000..e82b9ad
--- /dev/null
+++ b/lib/librte_eal/common/rte_service.c
@@ -0,0 +1,704 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <rte_service.h>
+#include "include/rte_service_component.h"
+
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_atomic.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+#define RTE_SERVICE_NUM_MAX 64
+
+#define SERVICE_F_REGISTERED    (1 << 0)
+#define SERVICE_F_STATS_ENABLED (1 << 1)
+
+/* runstates for services and lcores, denoting if they are active or not */
+#define RUNSTATE_STOPPED 0
+#define RUNSTATE_RUNNING 1
+
+/* internal representation of a service */
+struct rte_service_spec_impl {
+	/* public part of the struct */
+	struct rte_service_spec spec;
+
+	/* atomic lock that when set indicates a service core is currently
+	 * running this service callback. When not set, a core may take the
+	 * lock and then run the service callback.
+	 */
+	rte_atomic32_t execute_lock;
+
+	/* API set/get-able variables */
+	int32_t runstate;
+	uint8_t internal_flags;
+
+	/* per service statistics */
+	uint32_t num_mapped_cores;
+	uint64_t calls;
+	uint64_t cycles_spent;
+} __rte_cache_aligned;
+
+/* the internal values of a service core */
+struct core_state {
+	/* map of services IDs are run on this core */
+	uint64_t service_mask;
+	uint8_t runstate; /* running or stopped */
+	uint8_t is_service_core; /* set if core is currently a service core */
+
+	/* extreme statistics */
+	uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
+} __rte_cache_aligned;
+
+static uint32_t rte_service_count;
+static struct rte_service_spec_impl *rte_services;
+static struct core_state *lcore_states;
+static uint32_t rte_service_library_initialized;
+
+int32_t rte_service_init(void)
+{
+	if (rte_service_library_initialized) {
+		printf("service library init() called, init flag %d\n",
+			rte_service_library_initialized);
+		return -EALREADY;
+	}
+
+	rte_services = rte_calloc("rte_services", RTE_SERVICE_NUM_MAX,
+			sizeof(struct rte_service_spec_impl),
+			RTE_CACHE_LINE_SIZE);
+	if (!rte_services) {
+		printf("error allocating rte services array\n");
+		return -ENOMEM;
+	}
+
+	lcore_states = rte_calloc("rte_service_core_states", RTE_MAX_LCORE,
+			sizeof(struct core_state), RTE_CACHE_LINE_SIZE);
+	if (!lcore_states) {
+		printf("error allocating core states array\n");
+		return -ENOMEM;
+	}
+
+	int i;
+	int count = 0;
+	struct rte_config *cfg = rte_eal_get_configuration();
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role == ROLE_SERVICE) {
+			if ((unsigned int)i == cfg->master_lcore)
+				continue;
+			rte_service_lcore_add(i);
+			count++;
+		}
+	}
+
+	rte_service_library_initialized = 1;
+	return 0;
+}
+
+/* returns 1 if service is registered and has not been unregistered
+ * Returns 0 if service never registered, or has been unregistered
+ */
+static inline int
+service_valid(uint32_t id)
+{
+	return !!(rte_services[id].internal_flags & SERVICE_F_REGISTERED);
+}
+
+/* returns 1 if statistics should be colleced for service
+ * Returns 0 if statistics should not be collected for service
+ */
+static inline int
+service_stats_enabled(struct rte_service_spec_impl *impl)
+{
+	return !!(impl->internal_flags & SERVICE_F_STATS_ENABLED);
+}
+
+static inline int
+service_mt_safe(struct rte_service_spec_impl *s)
+{
+	return s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE;
+}
+
+int32_t rte_service_set_stats_enable(struct rte_service_spec *service,
+				  int32_t enabled)
+{
+	struct rte_service_spec_impl *impl =
+		(struct rte_service_spec_impl *)service;
+	if (!impl)
+		return -EINVAL;
+
+	if (enabled)
+		impl->internal_flags |= SERVICE_F_STATS_ENABLED;
+	else
+		impl->internal_flags &= ~(SERVICE_F_STATS_ENABLED);
+
+	return 0;
+}
+
+uint32_t
+rte_service_get_count(void)
+{
+	return rte_service_count;
+}
+
+struct rte_service_spec *
+rte_service_get_by_id(uint32_t id)
+{
+	struct rte_service_spec *service = NULL;
+	if (id < rte_service_count)
+		service = (struct rte_service_spec *)&rte_services[id];
+
+	return service;
+}
+
+struct rte_service_spec *rte_service_get_by_name(const char *name)
+{
+	struct rte_service_spec *service = NULL;
+	int i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (service_valid(i) &&
+				strcmp(name, rte_services[i].spec.name) == 0) {
+			service = (struct rte_service_spec *)&rte_services[i];
+			break;
+		}
+	}
+
+	return service;
+}
+
+const char *
+rte_service_get_name(const struct rte_service_spec *service)
+{
+	return service->name;
+}
+
+int32_t
+rte_service_probe_capability(const struct rte_service_spec *service,
+			     uint32_t capability)
+{
+	return service->capabilities & capability;
+}
+
+int32_t
+rte_service_is_running(const struct rte_service_spec *spec)
+{
+	const struct rte_service_spec_impl *impl =
+		(const struct rte_service_spec_impl *)spec;
+	if (!impl)
+		return -EINVAL;
+
+	return (impl->runstate == RUNSTATE_RUNNING) &&
+		(impl->num_mapped_cores > 0);
+}
+
+int32_t
+rte_service_register(const struct rte_service_spec *spec)
+{
+	uint32_t i;
+	int32_t free_slot = -1;
+
+	if (spec->callback == NULL || strlen(spec->name) == 0)
+		return -EINVAL;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i)) {
+			free_slot = i;
+			break;
+		}
+	}
+
+	if ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))
+		return -ENOSPC;
+
+	struct rte_service_spec_impl *s = &rte_services[free_slot];
+	s->spec = *spec;
+	s->internal_flags |= SERVICE_F_REGISTERED;
+
+	rte_smp_wmb();
+	rte_service_count++;
+
+	return 0;
+}
+
+int32_t
+rte_service_unregister(struct rte_service_spec *spec)
+{
+	struct rte_service_spec_impl *s = NULL;
+	struct rte_service_spec_impl *spec_impl =
+		(struct rte_service_spec_impl *)spec;
+
+	uint32_t i;
+	uint32_t service_id;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (&rte_services[i] == spec_impl) {
+			s = spec_impl;
+			service_id = i;
+			break;
+		}
+	}
+
+	if (!s)
+		return -EINVAL;
+
+	rte_service_count--;
+	rte_smp_wmb();
+
+	s->internal_flags &= ~(SERVICE_F_REGISTERED);
+
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		lcore_states[i].service_mask &= ~(1 << service_id);
+
+	memset(&rte_services[service_id], 0,
+			sizeof(struct rte_service_spec_impl));
+
+	return 0;
+}
+
+int32_t
+rte_service_start(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_RUNNING;
+	rte_smp_wmb();
+	return 0;
+}
+
+int32_t
+rte_service_stop(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_STOPPED;
+	rte_smp_wmb();
+	return 0;
+}
+
+static int32_t
+rte_service_runner_func(void *arg)
+{
+	RTE_SET_USED(arg);
+	uint32_t i;
+	const int lcore = rte_lcore_id();
+	struct core_state *cs = &lcore_states[lcore];
+
+	while (lcore_states[lcore].runstate == RUNSTATE_RUNNING) {
+		const uint64_t service_mask = cs->service_mask;
+		for (i = 0; i < rte_service_count; i++) {
+			struct rte_service_spec_impl *s = &rte_services[i];
+			if (s->runstate != RUNSTATE_RUNNING ||
+					!(service_mask & (1 << i)))
+				continue;
+
+			/* check do we need cmpset, if MT safe or <= 1 core
+			 * mapped, atomic ops are not required.
+			 */
+			const int need_cmpset = !((service_mt_safe(s) == 0) &&
+						(s->num_mapped_cores > 1));
+			uint32_t *lock = (uint32_t *)&s->execute_lock;
+
+			if (need_cmpset || rte_atomic32_cmpset(lock, 0, 1)) {
+				void *userdata = s->spec.callback_userdata;
+
+				if (service_stats_enabled(s)) {
+					uint64_t start = rte_rdtsc();
+					s->spec.callback(userdata);
+					uint64_t end = rte_rdtsc();
+					s->cycles_spent += end - start;
+					cs->calls_per_service[i]++;
+					s->calls++;
+				} else
+					s->spec.callback(userdata);
+
+				if (need_cmpset)
+					rte_atomic32_clear(&s->execute_lock);
+			}
+		}
+
+		rte_smp_rmb();
+	}
+
+	lcore_config[lcore].state = WAIT;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_count(void)
+{
+	int32_t count = 0;
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		count += lcore_states[i].is_service_core;
+	return count;
+}
+
+int32_t
+rte_service_lcore_list(uint32_t array[], uint32_t n)
+{
+	uint32_t count = rte_service_lcore_count();
+	if (count > n)
+		return -ENOMEM;
+
+	if (!array)
+		return -EINVAL;
+
+	uint32_t i;
+	uint32_t idx = 0;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct core_state *cs = &lcore_states[i];
+		if (cs->is_service_core) {
+			array[idx] = i;
+			idx++;
+		}
+	}
+
+	return count;
+}
+
+int32_t
+rte_service_start_with_defaults(void)
+{
+	/* create a default mapping from cores to services, then start the
+	 * services to make them transparent to unaware applications.
+	 */
+	uint32_t i;
+	int ret;
+	uint32_t count = rte_service_get_count();
+
+	int32_t lcore_iter = 0;
+	uint32_t ids[RTE_MAX_LCORE];
+	int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
+
+	if (lcore_count == 0)
+		return -ENOTSUP;
+
+	for (i = 0; (int)i < lcore_count; i++)
+		rte_service_lcore_start(ids[i]);
+
+	for (i = 0; i < count; i++) {
+		struct rte_service_spec *s = rte_service_get_by_id(i);
+		if (!s)
+			return -EINVAL;
+
+		/* do 1:1 core mapping here, with each service getting
+		 * assigned a single core by default. Adding multiple services
+		 * should multiplex to a single core, or 1:1 if there are the
+		 * same amount of services as service-cores
+		 */
+		ret = rte_service_enable_on_lcore(s, ids[lcore_iter]);
+		if (ret)
+			return -ENODEV;
+
+		lcore_iter++;
+		if (lcore_iter >= lcore_count)
+			lcore_iter = 0;
+
+		ret = rte_service_start(s);
+		if (ret)
+			return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static int32_t
+service_update(struct rte_service_spec *service, uint32_t lcore,
+		uint32_t *set, uint32_t *enabled)
+{
+	uint32_t i;
+	int32_t sid = -1;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if ((struct rte_service_spec *)&rte_services[i] == service &&
+				service_valid(i)) {
+			sid = i;
+			break;
+		}
+	}
+
+	if (sid == -1 || lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (!lcore_states[lcore].is_service_core)
+		return -EINVAL;
+
+	if (set) {
+		if (*set) {
+			lcore_states[lcore].service_mask |=  (1 << sid);
+			rte_services[sid].num_mapped_cores++;
+		} else {
+			lcore_states[lcore].service_mask &= ~(1 << sid);
+			rte_services[sid].num_mapped_cores--;
+		}
+	}
+
+	if (enabled)
+		*enabled = (lcore_states[lcore].service_mask & (1 << sid));
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore)
+{
+	uint32_t enabled;
+	int ret = service_update(service, lcore, 0, &enabled);
+	if (ret == 0)
+		return enabled;
+	return -EINVAL;
+}
+
+int32_t
+rte_service_enable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t on = 1;
+	return service_update(service, lcore, &on, 0);
+}
+
+int32_t
+rte_service_disable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t off = 0;
+	return service_update(service, lcore, &off, 0);
+}
+
+int32_t rte_service_lcore_reset_all(void)
+{
+	/* loop over cores, reset all to mask 0 */
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		lcore_states[i].service_mask = 0;
+		lcore_states[i].is_service_core = 0;
+		lcore_states[i].runstate = RUNSTATE_STOPPED;
+	}
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
+		rte_services[i].num_mapped_cores = 0;
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+static void
+set_lcore_state(uint32_t lcore, int32_t state)
+{
+	/* mark core state in hugepage backed config */
+	struct rte_config *cfg = rte_eal_get_configuration();
+	cfg->lcore_role[lcore] = state;
+
+	/* mark state in process local lcore_config */
+	lcore_config[lcore].core_role = state;
+
+	/* update per-lcore optimized state tracking */
+	lcore_states[lcore].is_service_core = (state == ROLE_SERVICE);
+}
+
+int32_t
+rte_service_lcore_add(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+	if (lcore_states[lcore].is_service_core)
+		return -EALREADY;
+
+	set_lcore_state(lcore, ROLE_SERVICE);
+
+	/* ensure that after adding a core the mask and state are defaults */
+	lcore_states[lcore].service_mask = 0;
+	lcore_states[lcore].runstate = RUNSTATE_STOPPED;
+
+	rte_smp_wmb();
+	return 0;
+}
+
+int32_t
+rte_service_lcore_del(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &lcore_states[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate != RUNSTATE_STOPPED)
+		return -EBUSY;
+
+	set_lcore_state(lcore, ROLE_RTE);
+
+	rte_smp_wmb();
+	return 0;
+}
+
+int32_t
+rte_service_lcore_start(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &lcore_states[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate == RUNSTATE_RUNNING)
+		return -EALREADY;
+
+	/* set core to run state first, and then launch otherwise it will
+	 * return immediately as runstate keeps it in the service poll loop
+	 */
+	lcore_states[lcore].runstate = RUNSTATE_RUNNING;
+
+	int ret = rte_eal_remote_launch(rte_service_runner_func, 0, lcore);
+	/* returns -EBUSY if the core is already launched, 0 on success */
+	return ret;
+}
+
+int32_t
+rte_service_lcore_stop(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (lcore_states[lcore].runstate == RUNSTATE_STOPPED)
+		return -EALREADY;
+
+	uint32_t i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		int32_t enabled = lcore_states[i].service_mask & (1 << i);
+		int32_t service_running = rte_services[i].runstate !=
+						RUNSTATE_STOPPED;
+		int32_t only_core = rte_services[i].num_mapped_cores == 1;
+
+		/* if the core is mapped, and the service is running, and this
+		 * is the only core that is mapped, the service would cease to
+		 * run if this core stopped, so fail instead.
+		 */
+		if (enabled && service_running && only_core)
+			return -EBUSY;
+	}
+
+	lcore_states[lcore].runstate = RUNSTATE_STOPPED;
+
+	return 0;
+}
+
+static void
+rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,
+		     uint64_t all_cycles, uint32_t reset)
+{
+	/* avoid divide by zero */
+	if (all_cycles == 0)
+		all_cycles = 1;
+
+	int calls = 1;
+	if (s->calls != 0)
+		calls = s->calls;
+
+	fprintf(f, "  %s: stats %d\tcalls %"PRIu64"\tcycles %"
+			PRIu64"\tavg: %"PRIu64"\n",
+			s->spec.name, service_stats_enabled(s), s->calls,
+			s->cycles_spent, s->cycles_spent / calls);
+
+	if (reset) {
+		s->cycles_spent = 0;
+		s->calls = 0;
+	}
+}
+
+static void
+service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)
+{
+	uint32_t i;
+	struct core_state *cs = &lcore_states[lcore];
+
+	fprintf(f, "%02d\t", lcore);
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i))
+			continue;
+		fprintf(f, "%"PRIu64"\t", cs->calls_per_service[i]);
+		if (reset)
+			cs->calls_per_service[i] = 0;
+	}
+	fprintf(f, "\n");
+}
+
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service)
+{
+	uint32_t i;
+
+	uint64_t total_cycles = 0;
+	for (i = 0; i < rte_service_count; i++) {
+		if (!service_valid(i))
+			continue;
+		total_cycles += rte_services[i].cycles_spent;
+	}
+
+	if (service) {
+		struct rte_service_spec_impl *s =
+			(struct rte_service_spec_impl *)service;
+		fprintf(f, "Service %s Summary\n", s->spec.name);
+		uint32_t reset = 0;
+		rte_service_dump_one(f, s, total_cycles, reset);
+		return 0;
+	}
+
+	fprintf(f, "Services Summary\n");
+	for (i = 0; i < rte_service_count; i++) {
+		uint32_t reset = 1;
+		rte_service_dump_one(f, &rte_services[i], total_cycles, reset);
+	}
+
+	fprintf(f, "Service Cores Summary\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role != ROLE_SERVICE)
+			continue;
+
+		uint32_t reset = 0;
+		service_dump_calls_per_lcore(f, i, reset);
+	}
+
+	return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 8651e27..e6ab6c3 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -99,6 +99,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/linuxapp/eal/eal_thread.c b/lib/librte_eal/linuxapp/eal/eal_thread.c
index 9f88530..831ba07 100644
--- a/lib/librte_eal/linuxapp/eal/eal_thread.c
+++ b/lib/librte_eal/linuxapp/eal/eal_thread.c
@@ -184,7 +184,14 @@ eal_thread_loop(__attribute__((unused)) void *arg)
 		ret = lcore_config[lcore_id].f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		rte_wmb();
-		lcore_config[lcore_id].state = FINISHED;
+
+		/* when a service core returns, it should go directly to WAIT
+		 * state, because the application will not lcore_wait() for it.
+		 */
+		if (lcore_config[lcore_id].core_role == ROLE_SERVICE)
+			lcore_config[lcore_id].state = WAIT;
+		else
+			lcore_config[lcore_id].state = FINISHED;
 	}
 
 	/* never reached */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 0f9e009..fbaec39 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -214,5 +214,28 @@ EXPERIMENTAL {
 	rte_eal_devargs_parse;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_start_with_defaults;
+	rte_service_stop;
+	rte_service_unregister;
 
 } DPDK_17.08;
-- 
2.7.4

^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [PATCH] cryptodev: fix cryptodev start return value
  @ 2017-07-11 14:08  0%     ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 200+ results
From: De Lara Guarch, Pablo @ 2017-07-11 14:08 UTC (permalink / raw)
  To: Pavan Nikhilesh Bhagavatula, dev, Trahe, Fiona; +Cc: Doherty, Declan



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Pavan Nikhilesh
> Bhagavatula
> Sent: Thursday, June 8, 2017 9:13 AM
> To: dev@dpdk.org; Trahe, Fiona <fiona.trahe@intel.com>
> Cc: Doherty, Declan <declan.doherty@intel.com>; Pavan Nikhilesh
> <pbhagavatula@caviumnetworks.com>
> Subject: Re: [dpdk-dev] [PATCH] cryptodev: fix cryptodev start return value
> 
> On Wed, Jun 07, 2017 at 03:54:23PM +0000, Trahe, Fiona wrote:
> > Hi Pavan,
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Pavan
> Nikhilesh
> > > Sent: Wednesday, June 7, 2017 11:37 AM
> > > To: dev@dpdk.org
> > > Cc: Doherty, Declan <declan.doherty@intel.com>; Pavan Nikhilesh
> > > Bhagavatula <pbhagavatula@caviumnetworks.com>
> > > Subject: [dpdk-dev] [PATCH] cryptodev: fix cryptodev start return
> > > value
> > >
> > > From: Pavan Nikhilesh Bhagavatula
> <pbhagavatula@caviumnetworks.com>
> > >
> > > If cryptodev has already started it should return -EBUSY instead of
> > > 0 when rte_cryptodev_start is called.
> > >
> > > Fixes: d11b0f30df88 ("cryptodev: introduce API and framework for
> > > crypto devices")
> > >
> > > Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> > > ---
> > >  lib/librte_cryptodev/rte_cryptodev.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/lib/librte_cryptodev/rte_cryptodev.c
> > > b/lib/librte_cryptodev/rte_cryptodev.c
> > > index b65cd9c..c815038 100644
> > > --- a/lib/librte_cryptodev/rte_cryptodev.c
> > > +++ b/lib/librte_cryptodev/rte_cryptodev.c
> > > @@ -1000,7 +1000,7 @@ rte_cryptodev_start(uint8_t dev_id)
> > >  	if (dev->data->dev_started != 0) {
> > >  		CDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
> started",
> > >  			dev_id);
> > > -		return 0;
> > > +		return -EBUSY;
> > It makes sense to me to return 0/success in this case, as the end
> > result is the same, the device is successfully started.
> > But I don't feel strongly about it if there's a good argument for making the
> change?
> 
> I do agree with this but from an application perspective when the API is
> called again after the device has already started (without calling the stop
> API) it would mean that there is an underlying issue with the application's
> business logic and it would go undetected, so I feel that we should strictly
> enforce this scenario as an error.
> 
> > However, as it is an API change doesn't it need to be flagged in a release
> before the change is made?
> 
> I don't think that this would be an API change as it doesn't deprecate the
> existing ABI.
> Any thoughts about this from the community are welcome as the same
> issue affects multiple core libraries (crytodev, ethdev, eventdev).

Hi Pavan,

As said by Fiona and Thomas (for ethdev), this is an API change, so it would
require a deprecation notice, in order to be changed in the next release.

Thanks,
Pablo
> >
> >
> > }
> > >
> > >  	diag = (*dev->dev_ops->dev_start)(dev);
> > > --
> > > 2.7.4
> >

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation
  2017-07-11 12:32  3%         ` Van Haaren, Harry
@ 2017-07-11 12:44  0%           ` Jerin Jacob
  0 siblings, 0 replies; 200+ results
From: Jerin Jacob @ 2017-07-11 12:44 UTC (permalink / raw)
  To: Van Haaren, Harry; +Cc: Thomas Monjalon, dev, Wiles, Keith, Richardson, Bruce

-----Original Message-----
> Date: Tue, 11 Jul 2017 12:32:58 +0000
> From: "Van Haaren, Harry" <harry.van.haaren@intel.com>
> To: Thomas Monjalon <thomas@monjalon.net>, Jerin Jacob
>  <jerin.jacob@caviumnetworks.com>
> CC: "dev@dpdk.org" <dev@dpdk.org>, "Wiles, Keith" <keith.wiles@intel.com>,
>  "Richardson, Bruce" <bruce.richardson@intel.com>
> Subject: RE: [PATCH v4 1/7] service cores: header and implementation
> 
> > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > Sent: Tuesday, July 11, 2017 10:55 AM
> > To: Jerin Jacob <jerin.jacob@caviumnetworks.com>; Van Haaren, Harry
> > <harry.van.haaren@intel.com>
> > Cc: dev@dpdk.org; Wiles, Keith <keith.wiles@intel.com>; Richardson, Bruce
> > <bruce.richardson@intel.com>
> > Subject: Re: [PATCH v4 1/7] service cores: header and implementation
> > 
> > 11/07/2017 10:29, Jerin Jacob:
> > > IMO, We don't need to expose rte_service_private.h to application. If
> > > you agree, add the following or similar change
> > 
> > If it must not be exposed, the file should not have the prefix rte_
> > In doc/api/doxy-api.conf, every files with rte_ prefix will be processed
> > for doxygen documentation:
> > 	FILE_PATTERNS = rte_*.h
> 
> 
> The service registration API should be exposed to the application.
> 
> Imagine a use case where the application wants to run services *and* an application specific function on the same core.  In the current implementation this is possible, as the application can register a service. The app then configures all services (including its own "app-service") to run on a service lcore.
> 
> If we hide the service registration from the application, we make it impossible for the application to multiplex services and application specific workloads on a single core.

Then we could move the registration functions to service.h.
IMO, It does not look correct if we expose _prviate.h to application or
we could rename to service_component.h or something like that.

> 
> 
> I strongly prefer of leaving the header as is. Given we have EXPERIMENTAL tag, ABI/API are not a concern until later - we have time to figure out if the service-registration API is good enough in current form, before we commit to it.
> 
> I'll send v5 asap with headers as is.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation
  @ 2017-07-11 12:32  3%         ` Van Haaren, Harry
  2017-07-11 12:44  0%           ` Jerin Jacob
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2017-07-11 12:32 UTC (permalink / raw)
  To: Thomas Monjalon, Jerin Jacob; +Cc: dev, Wiles, Keith, Richardson, Bruce

> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Tuesday, July 11, 2017 10:55 AM
> To: Jerin Jacob <jerin.jacob@caviumnetworks.com>; Van Haaren, Harry
> <harry.van.haaren@intel.com>
> Cc: dev@dpdk.org; Wiles, Keith <keith.wiles@intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>
> Subject: Re: [PATCH v4 1/7] service cores: header and implementation
> 
> 11/07/2017 10:29, Jerin Jacob:
> > IMO, We don't need to expose rte_service_private.h to application. If
> > you agree, add the following or similar change
> 
> If it must not be exposed, the file should not have the prefix rte_
> In doc/api/doxy-api.conf, every files with rte_ prefix will be processed
> for doxygen documentation:
> 	FILE_PATTERNS = rte_*.h


The service registration API should be exposed to the application.

Imagine a use case where the application wants to run services *and* an application specific function on the same core.  In the current implementation this is possible, as the application can register a service. The app then configures all services (including its own "app-service") to run on a service lcore.

If we hide the service registration from the application, we make it impossible for the application to multiplex services and application specific workloads on a single core.


I strongly prefer of leaving the header as is. Given we have EXPERIMENTAL tag, ABI/API are not a concern until later - we have time to figure out if the service-registration API is good enough in current form, before we commit to it.

I'll send v5 asap with headers as is.

^ permalink raw reply	[relevance 3%]

* [dpdk-dev]  [PATCH] eal: add notice to make DPDK IOVA aware
@ 2017-07-11 10:01  8% Jerin Jacob
  2017-07-21  6:41  0% ` santosh
  2017-08-04  3:41  0% ` santosh
  0 siblings, 2 replies; 200+ results
From: Jerin Jacob @ 2017-07-11 10:01 UTC (permalink / raw)
  To: dev
  Cc: thomas, olivier.matz, stephen, santosh.shukla, hemant.agrawal,
	bruce.richardson, shreyansh.jain, gaetan.rivet,
	sergio.gonzalez.monroy, anatoly.burakov, Jerin Jacob

When we run DPDK on guest or VFIO mode on host,
the dpdk library or device will not be directly accessing
the physical address. Instead, the device does go through
an IO address translation memory management unit. On x86,
we call it as IOMMU and on ARM as SMMU.

More details:
http://osidays.com/osidays/wp-content/uploads/2014/12/Final_OSI2014_IOMMU_DetailedView_Sanil_Anurup.pdf

Based on discussion in the following thread
http://dpdk.org/ml/archives/dev/2017-July/070850.html

We would like to change reference to physical address to more
appropriate name as with IOMMU/SMMU with
the device won't be dealing directly with the physical address.

An ABI change is planned for 17.11 to change following
data structure or functions to more appropriate name.
Currently planned to change it iova as instead of phys

Please note: The change will be only for the name and
functional aspects of the API will remain same.

Following functions/data structures name may change.
This list is based on v17.05-rc1. It may change based on v17.11 code base.


typedef:
phys_addr_t

structures:

struct rte_memseg::phys_addr
struct rte_mbuf::buf_physaddr

functions:
rte_mempool_populate_phys()
rte_mempool_populate_phys_tab()
rte_eal_using_phys_addrs()
rte_mem_virt2phy()
rte_dump_physmem_layout()
rte_eal_get_physmem_layout()
rte_eal_get_physmem_size()
rte_malloc_virt2phy()
rte_mem_phy2mch()


Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 doc/guides/rel_notes/deprecation.rst | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 257dcba32..379920fbb 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,10 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
+
+* eal: An ABI change is planned for 17.11 to make dpdk aware of IOVA address
+  translation scheme.
+  Reference to phys address in eal data-structure or functions may change to
+  IOVA address or more appropriate name.
+  The change will be only for the name.
+  Functional aspects of the API or data-structure will remain same.
-- 
2.13.2

^ permalink raw reply	[relevance 8%]

* Re: [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation
  2017-07-07 16:41  1%   ` [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation Harry van Haaren
@ 2017-07-11  8:29  0%     ` Jerin Jacob
    0 siblings, 1 reply; 200+ results
From: Jerin Jacob @ 2017-07-11  8:29 UTC (permalink / raw)
  To: Harry van Haaren; +Cc: dev, thomas, keith.wiles, bruce.richardson

-----Original Message-----
> Date: Fri, 7 Jul 2017 17:41:01 +0100
> From: Harry van Haaren <harry.van.haaren@intel.com>
> To: dev@dpdk.org
> CC: thomas@monjalon.net, jerin.jacob@caviumnetworks.com,
>  keith.wiles@intel.com, bruce.richardson@intel.com, Harry van Haaren
>  <harry.van.haaren@intel.com>
> Subject: [PATCH v4 1/7] service cores: header and implementation
> X-Mailer: git-send-email 2.7.4
> 
> Add header files, update .map files with new service
> functions, and add the service header to the doxygen
> for building.
> 
> This service header API allows DPDK to use services as
> a concept of something that requires CPU cycles. An example
> is a PMD that runs in software to schedule events, where a
> hardware version exists that does not require a CPU.
> 
> The code presented here is based on an initial RFC:
> http://dpdk.org/ml/archives/dev/2017-May/065207.html
> This was then reworked, and RFC v2 with the changes posted:
> http://dpdk.org/ml/archives/dev/2017-June/067194.html
> 
> This is the fourth iteration of the service core concept,
> with 2 RFCs and this being v2 of the implementation.

Remove above info from the git commit.

> 
> Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
> 
> ---
>  doc/api/doxy-api-index.md                          |   1 +
>  lib/librte_eal/bsdapp/eal/Makefile                 |   1 +
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  22 +
>  lib/librte_eal/common/Makefile                     |   1 +
>  lib/librte_eal/common/eal_common_lcore.c           |   1 +
>  lib/librte_eal/common/include/rte_eal.h            |   4 +
>  lib/librte_eal/common/include/rte_lcore.h          |   3 +-
>  lib/librte_eal/common/include/rte_service.h        | 383 ++++++++++++
>  .../common/include/rte_service_private.h           | 140 +++++
>  lib/librte_eal/common/rte_service.c                | 687 +++++++++++++++++++++
>  lib/librte_eal/linuxapp/eal/Makefile               |   1 +
>  lib/librte_eal/linuxapp/eal/eal_thread.c           |   9 +-
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  22 +
>  13 files changed, 1273 insertions(+), 2 deletions(-)
>  create mode 100644 lib/librte_eal/common/include/rte_service.h
>  create mode 100644 lib/librte_eal/common/include/rte_service_private.h
>  create mode 100644 lib/librte_eal/common/rte_service.c
> 
> diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
> index 3b83288..e2abdf4 100644
> --- a/doc/api/doxy-api-index.md
> +++ b/doc/api/doxy-api-index.md
> @@ -159,6 +159,7 @@ There are many libraries, so their headers may be grouped by topics:
>    [common]             (@ref rte_common.h),
>    [ABI compat]         (@ref rte_compat.h),
>    [keepalive]          (@ref rte_keepalive.h),
> +  [service cores]      (@ref rte_service.h),
>    [device metrics]     (@ref rte_metrics.h),
>    [bitrate statistics] (@ref rte_bitrate.h),
>    [latency statistics] (@ref rte_latencystats.h),


Fix the below mentioned documentation warning.

+/export/dpdk.org/lib/librte_eal/common/include/rte_service.h:338:
warning: argument 'enabled' of command @param is not found in the
argument list of rte_service_set_stats_enable(int enable)
+/export/dpdk.org/lib/librte_eal/common/include/rte_service.h:346:
warning: The following parameters of rte_service_set_stats_enable(int
enable) are not documented:
+  parameter 'enable'                                                           
+/export/dpdk.org/lib/librte_eal/common/include/rte_service.h:349:
warning: argument 'The' of command @param is not found in the argument
list of rte_service_lcore_list(uint32_t array[], uint32_t n)
+/export/dpdk.org/lib/librte_eal/common/include/rte_service.h:367:
warning: The following parameters of rte_service_lcore_list(uint32_t
array[], uint32_t n) are not documented:
+  parameter 'n'      

command to reproduce:
./devtools/test-build.sh -j8 x86_64-native-linuxapp-gcc+shared x86_64-native-linuxapp-gcc+debug



>  } DPDK_17.08;
> diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
> index f2fe052..942f03c 100644
> --- a/lib/librte_eal/common/Makefile
> +++ b/lib/librte_eal/common/Makefile
> @@ -41,6 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h
>  INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
>  INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
>  INC += rte_malloc.h rte_keepalive.h rte_time.h
> +INC += rte_service.h rte_service_private.h

IMO, We don't need to expose rte_service_private.h to application. If
you agree, add the following or similar change

diff --git a/drivers/event/sw/Makefile b/drivers/event/sw/Makefile
index 857a87cc5..442652e93 100644
--- a/drivers/event/sw/Makefile
+++ b/drivers/event/sw/Makefile
@@ -36,6 +36,8 @@ LIB = librte_pmd_sw_event.a
 # build flags
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include/
+
 # for older GCC versions, allow us to initialize an event using
 # designated initializers.
 ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
diff --git a/lib/librte_eal/common/Makefile
b/lib/librte_eal/common/Makefile
index 942f03cdd..ea6c1f8f1 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -41,7 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
-INC += rte_service.h rte_service_private.h
+INC += rte_service.h

diff --git a/test/test/Makefile b/test/test/Makefile
index 42d9a49e2..b603b6563 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -152,6 +152,7 @@ SRCS-y += test_version.c
 SRCS-y += test_func_reentrancy.c
 
 SRCS-y += test_service_cores.c
+CFLAGS_test_service_cores.o += -I$(RTE_SDK)/lib/librte_eal/common/include/
 
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_num.



>  
>  GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
>  GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h
> diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
> index 84fa0cb..0db1555 100644
> --- a/lib/librte_eal/common/eal_common_lcore.c
> +++ b/lib/librte_eal/common/eal_common_lcore.c
> @@ -81,6 +81,7 @@ rte_eal_cpu_init(void)
>  
>  		/* By default, each detected core is enabled */
>  		config->lcore_role[lcore_id] = ROLE_RTE;
> +		lcore_config[lcore_id].core_role = ROLE_RTE;
>  		lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
>  		lcore_config[lcore_id].socket_id = eal_cpu_socket_id(lcore_id);
>  		if (lcore_config[lcore_id].socket_id >= RTE_MAX_NUMA_NODES) {
> diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
> index abf020b..4dd0518 100644
> --- a/lib/librte_eal/common/include/rte_eal.h
> +++ b/lib/librte_eal/common/include/rte_eal.h
> @@ -61,6 +61,7 @@ extern "C" {
>  enum rte_lcore_role_t {
>  	ROLE_RTE,
>  	ROLE_OFF,
> +	ROLE_SERVICE,
>  };
>  
> +
> +#define SERVICE_F_REGISTERED 0
> +
> +/* runstates for services and lcores, denoting if they are active or not */
> +#define RUNSTATE_STOPPED 0
> +#define RUNSTATE_RUNNING 1
> +
> +/* internal representation of a service */
> +struct rte_service_spec_impl {
> +	/* public part of the struct */
> +	struct rte_service_spec spec;
> +
> +	/* atomic lock that when set indicates a service core is currently
> +	 * running this service callback. When not set, a core may take the
> +	 * lock and then run the service callback.
> +	 */
> +	rte_atomic32_t execute_lock;
> +
> +	/* API set/get-able variables */
> +	int32_t runstate;
> +	uint8_t internal_flags;
> +
> +	/* per service statistics */
> +	uint32_t num_mapped_cores;
> +	uint64_t calls;
> +	uint64_t cycles_spent;
> +} __rte_cache_aligned;
> +
> +/* the internal values of a service core */
> +struct core_state {

Change to lcore_state.

> +	/* map of services IDs are run on this core */
> +	uint64_t service_mask;
> +	uint8_t runstate; /* running or stopped */
> +	uint8_t is_service_core; /* set if core is currently a service core */
> +	uint8_t collect_statistics; /* if set, measure cycle counts */
> +
> +	/* extreme statistics */
> +	uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
> +} __rte_cache_aligned;
> +
> +static uint32_t rte_service_count;
> +static struct rte_service_spec_impl *rte_services;
> +static struct core_state *cores_state;
> +static uint32_t rte_service_library_initialized;
> +
> +int32_t rte_service_init(void)
> +{
> +	if (rte_service_library_initialized) {
> +		printf("service library init() called, init flag %d\n",
> +			rte_service_library_initialized);
> +		return -EALREADY;
> +	}
> +
> +	rte_services = rte_calloc("rte_services", RTE_SERVICE_NUM_MAX,
> +			sizeof(struct rte_service_spec_impl),
> +			RTE_CACHE_LINE_SIZE);
> +	if (!rte_services) {
> +		printf("error allocating rte services array\n");
> +		return -ENOMEM;
> +	}
> +
> +	cores_state = rte_calloc("rte_service_core_states", RTE_MAX_LCORE,
> +			sizeof(struct core_state), RTE_CACHE_LINE_SIZE);
> +	if (!cores_state) {
> +		printf("error allocating core states array\n");
> +		return -ENOMEM;
> +	}
> +
> +	int i;
> +	int count = 0;
> +	struct rte_config *cfg = rte_eal_get_configuration();
> +	for (i = 0; i < RTE_MAX_LCORE; i++) {
> +		if (lcore_config[i].core_role == ROLE_SERVICE) {
> +			if ((unsigned int)i == cfg->master_lcore)
> +				continue;
> +			rte_service_lcore_add(i);
> +			count++;
> +		}
> +	}
> +
> +	rte_service_library_initialized = 1;
> +	return 0;
> +}
> +
> +void rte_service_set_stats_enable(int enabled)

IMO, It should be per service  i.e
rte_service_set_stats_enable(const struct rte_service_spec *spec, int enable)

> +{
> +	uint32_t i;
> +	for (i = 0; i < RTE_MAX_LCORE; i++)
> +		cores_state[i].collect_statistics = enabled;
> +}
> +
> +/* returns 1 if service is registered and has not been unregistered
> + * Returns 0 if service never registered, or has been unregistered
> + */
> +static inline int
> +service_valid(uint32_t id) {
> +	return !!(rte_services[id].internal_flags &
> +		 (1 << SERVICE_F_REGISTERED));
> +}
> +
> +uint32_t
> +rte_service_get_count(void)
> +{
> +	return rte_service_count;
> +}
> +
> +struct rte_service_spec *
> +rte_service_get_by_id(uint32_t id)
> +{
> +	struct rte_service_spec *service = NULL;
> +	if (id < rte_service_count)
> +		service = (struct rte_service_spec *)&rte_services[id];
> +
> +	return service;
> +}
> +
> +struct rte_service_spec *rte_service_get_by_name(const char *name)
> +{
> +	struct rte_service_spec *service = NULL;
> +	int i;
> +	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
> +		if (service_valid(i) &&
> +				strcmp(name, rte_services[i].spec.name) == 0) {
> +			service = (struct rte_service_spec *)&rte_services[i];
> +			break;
> +		}
> +	}
> +
> +	return service;
> +}
> +
> +const char *
> +rte_service_get_name(const struct rte_service_spec *service)
> +{
> +	return service->name;
> +}
> +
> +int32_t
> +rte_service_probe_capability(const struct rte_service_spec *service,
> +			     uint32_t capability)
> +{
> +	return service->capabilities & capability;
> +}
> +
> +int32_t
> +rte_service_is_running(const struct rte_service_spec *spec)
> +{
> +	const struct rte_service_spec_impl *impl =
> +		(const struct rte_service_spec_impl *)spec;
> +	if (!impl)
> +		return -EINVAL;
> +
> +	return (impl->runstate == RUNSTATE_RUNNING) &&
> +		(impl->num_mapped_cores > 0);
> +}
> +
> +int32_t
> +rte_service_register(const struct rte_service_spec *spec)
> +{
> +	uint32_t i;
> +	int32_t free_slot = -1;
> +
> +	if (spec->callback == NULL || strlen(spec->name) == 0)
> +		return -EINVAL;
> +
> +	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
> +		if (!service_valid(i)) {
> +			free_slot = i;
> +			break;
> +		}
> +	}
> +
> +	if ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))
> +		return -ENOSPC;
> +
> +	struct rte_service_spec_impl *s = &rte_services[free_slot];
> +	s->spec = *spec;
> +	s->internal_flags |= (1 << SERVICE_F_REGISTERED);
> +
> +	rte_smp_wmb();
> +	rte_service_count++;
> +
> +	return 0;
> +}
> +
> +int32_t
> +rte_service_unregister(struct rte_service_spec *spec)
> +{
> +	struct rte_service_spec_impl *s = NULL;
> +	struct rte_service_spec_impl *spec_impl =
> +		(struct rte_service_spec_impl *)spec;
> +
> +	uint32_t i;
> +	uint32_t service_id;
> +	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
> +		if (&rte_services[i] == spec_impl) {
> +			s = spec_impl;
> +			service_id = i;
> +			break;
> +		}
> +	}
> +
> +	if (!s)
> +		return -EINVAL;
> +
> +	rte_service_count--;
> +	rte_smp_wmb();
> +
> +	s->internal_flags &= ~(1 << SERVICE_F_REGISTERED);
> +
> +	for (i = 0; i < RTE_MAX_LCORE; i++)
> +		cores_state[i].service_mask &= ~(1 << service_id);
> +
> +	memset(&rte_services[service_id], 0,
> +			sizeof(struct rte_service_spec_impl));
> +
> +	return 0;
> +}
> +
> +int32_t
> +rte_service_start(struct rte_service_spec *service)
> +{
> +	struct rte_service_spec_impl *s =
> +		(struct rte_service_spec_impl *)service;
> +	s->runstate = RUNSTATE_RUNNING;
> +	rte_smp_wmb();
> +	return 0;
> +}
> +
> +int32_t
> +rte_service_stop(struct rte_service_spec *service)
> +{
> +	struct rte_service_spec_impl *s =
> +		(struct rte_service_spec_impl *)service;
> +	s->runstate = RUNSTATE_STOPPED;
> +	rte_smp_wmb();
> +	return 0;
> +}
> +
> +static int32_t
> +rte_service_runner_func(void *arg)
> +{
> +	RTE_SET_USED(arg);
> +	uint32_t i;
> +	const int lcore = rte_lcore_id();
> +	struct core_state *cs = &cores_state[lcore];
> +
> +	while (cores_state[lcore].runstate == RUNSTATE_RUNNING) {
> +		const uint64_t service_mask = cs->service_mask;
> +		for (i = 0; i < rte_service_count; i++) {
> +			struct rte_service_spec_impl *s = &rte_services[i];
> +			if (s->runstate != RUNSTATE_RUNNING ||
> +					!(service_mask & (1 << i)))
> +				continue;
> +
> +			/* check if this is the only core mapped, else use
> +			 * atomic to serialize cores mapped to this service
> +			 */
> +			uint32_t *lock = (uint32_t *)&s->execute_lock;
> +			if ((s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE) ||
> +					(s->num_mapped_cores == 1 ||
> +					rte_atomic32_cmpset(lock, 0, 1))) {
> +				void *userdata = s->spec.callback_userdata;
> +
> +				if (cs->collect_statistics) {
> +					uint64_t start = rte_rdtsc();
> +					s->spec.callback(userdata);
> +					uint64_t end = rte_rdtsc();
> +					s->cycles_spent += end - start;
> +					cs->calls_per_service[i]++;
> +					s->calls++;
> +				} else
> +					s->spec.callback(userdata);
> +
> +				if ((s->spec.capabilities &
> +						RTE_SERVICE_CAP_MT_SAFE) == 0 &&
> +						s->num_mapped_cores > 1)

How about computing the non rte_atomic32_cmpset() mode value first and
using in both place i.e here and in the top "if" loop

	const int need_cmpset = (s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE)...
	if (need_cmpset || rte_atomic32_cmpset(lock, 0, 1))
	..
	if (need_cmpset)
		rte_atomic32_clear()..


> +					rte_atomic32_clear(&s->execute_lock);
> +			}
> +		}
> +
> +		rte_smp_rmb();
> +	}
> +
> +	lcore_config[lcore].state = WAIT;
> +
> +	return 0;
> +}
> +
> +int32_t
> +rte_service_lcore_count(void)
> +{
> +	int32_t count = 0;
> +	uint32_t i;
> +	for (i = 0; i < RTE_MAX_LCORE; i++)
> +		count += cores_state[i].is_service_core;
> +	return count;
> +}
> +
> +int32_t
> +rte_service_lcore_list(uint32_t array[], uint32_t n)
> +{
> +	uint32_t count = rte_service_lcore_count();
> +	if (count > n)
> +		return -ENOMEM;
> +
> +	if (!array)
> +		return -EINVAL;
> +
> +	uint32_t i;
> +	uint32_t idx = 0;
> +	for (i = 0; i < RTE_MAX_LCORE; i++) {
> +		struct core_state *cs = &cores_state[i];
> +		if (cs->is_service_core) {
> +			array[idx] = i;
> +			idx++;
> +		}
> +	}
> +
> +	return count;
> +}
> +
> +int32_t
> +rte_service_set_default_mapping(void)
> +{
> +	/* create a default mapping from cores to services, then start the
> +	 * services to make them transparent to unaware applications.
> +	 */
> +	uint32_t i;
> +	int ret;
> +	uint32_t count = rte_service_get_count();
> +
> +	int32_t lcore_iter = 0;
> +	uint32_t ids[RTE_MAX_LCORE];
> +	int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
> +
> +	for (i = 0; i < count; i++) {
> +		struct rte_service_spec *s = rte_service_get_by_id(i);
> +		if (!s)
> +			return -EINVAL;
> +
> +		/* if no lcores available as services cores, don't setup map.
> +		 * This means app logic must add cores, and setup mappings
> +		 */
> +		if (lcore_count > 0) {


> +			/* do 1:1 core mapping here, with each service getting
> +			 * assigned a single core by default. Adding multiple
> +			 * services should multiplex to a single core, or 1:1
> +			 * if services == cores
> +			 */
> +			ret = rte_service_enable_on_lcore(s, ids[lcore_iter]);
> +			if (ret)
> +				return -ENODEV;
> +		}
> +
> +		lcore_iter++;
> +		if (lcore_iter >= lcore_count)
> +			lcore_iter = 0;
> +
> +		ret = rte_service_start(s);

IMO, we don't need to start the service if lcore_count == 0. How about
moving the "if (lcore_count > 0)" check on top of for the loop and exist
from the function if lcore_count == 0.


> +		if (ret)
> +			return -ENOEXEC;
> +	}
> +
> +	return 0;
> +}
> +
> +static int32_t
> +service_update(struct rte_service_spec *service, uint32_t lcore,
> +		uint32_t *set, uint32_t *enabled)
> +{
> +	uint32_t i;
> +	int32_t sid = -1;
> +
> +	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
> +		if ((struct rte_service_spec *)&rte_services[i] == service &&
> +				service_valid(i)) {
> +			sid = i;
> +			break;
> +		}
> +	}
> +
> +	if (sid == -1 || lcore >= RTE_MAX_LCORE)
> +		return -EINVAL;
> +
> +	if (!cores_state[lcore].is_service_core)
> +		return -EINVAL;
> +
> +	if (set) {
> +		if (*set) {
> +			cores_state[lcore].service_mask |=  (1 << sid);
> +			rte_services[sid].num_mapped_cores++;
> +		} else {
> +			cores_state[lcore].service_mask &= ~(1 << sid);
> +			rte_services[sid].num_mapped_cores--;
> +		}
> +	}
> +
> +	if (enabled)
> +		*enabled = (cores_state[lcore].service_mask & (1 << sid));
> +
> +	rte_smp_wmb();
> +
> +	return 0;
> +}
> +
> +int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
> +					uint32_t lcore)
> +{
> +	uint32_t enabled;
> +	int ret = service_update(service, lcore, 0, &enabled);
> +	if (ret == 0)
> +		return enabled;
> +	return -EINVAL;
> +}
> +
> +int32_t
> +rte_service_enable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
> +{
> +	uint32_t on = 1;
> +	return service_update(service, lcore, &on, 0);
> +}
> +
> +int32_t
> +rte_service_disable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
> +{
> +	uint32_t off = 0;
> +	return service_update(service, lcore, &off, 0);
> +}
> +
> +int32_t rte_service_lcore_reset_all(void)
> +{
> +	/* loop over cores, reset all to mask 0 */
> +	uint32_t i;
> +	for (i = 0; i < RTE_MAX_LCORE; i++) {
> +		cores_state[i].service_mask = 0;
> +		cores_state[i].is_service_core = 0;
> +		cores_state[i].runstate = RUNSTATE_STOPPED;
> +	}
> +	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
> +		rte_services[i].num_mapped_cores = 0;
> +
> +	rte_smp_wmb();
> +
> +	return 0;
> +}
> +
> +static void
> +set_lcore_state(uint32_t lcore, int32_t state)
> +{
> +	/* mark core state in hugepage backed config */
> +	struct rte_config *cfg = rte_eal_get_configuration();
> +	cfg->lcore_role[lcore] = state;
> +
> +	/* mark state in process local lcore_config */
> +	lcore_config[lcore].core_role = state;
> +
> +	/* update per-lcore optimized state tracking */
> +	cores_state[lcore].is_service_core = (state == ROLE_SERVICE);
> +}
> +
> +int32_t
> +rte_service_lcore_add(uint32_t lcore)
> +{
> +	if (lcore >= RTE_MAX_LCORE)
> +		return -EINVAL;
> +	if (cores_state[lcore].is_service_core)
> +		return -EALREADY;
> +
> +	set_lcore_state(lcore, ROLE_SERVICE);
> +
> +	/* ensure that after adding a core the mask and state are defaults */
> +	cores_state[lcore].service_mask = 0;
> +	cores_state[lcore].runstate = RUNSTATE_STOPPED;

If worker core can call rte_service_lcore_add() then add rte_smp_wmb()
here. Applies to rte_service_lcore_del() as well.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 1/4] mempool: get the external mempool capability
  2017-07-10 13:55  0%       ` Olivier Matz
@ 2017-07-10 16:09  0%         ` santosh
  0 siblings, 0 replies; 200+ results
From: santosh @ 2017-07-10 16:09 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, thomas, hemant.agrawal, jerin.jacob, bruce.richardson

On Monday 10 July 2017 07:25 PM, Olivier Matz wrote:

> On Wed, 5 Jul 2017 12:11:52 +0530, santosh <santosh.shukla@caviumnetworks.com> wrote:
>> Hi Olivier,
>>
>> On Monday 03 July 2017 10:07 PM, Olivier Matz wrote:
>>
>>> Hi Santosh,
>>>
>>> On Wed, 21 Jun 2017 17:32:45 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:  
>>>> Allow external mempool to advertise its capability.
>>>> A handler been introduced called rte_mempool_ops_get_hw_cap.
>>>> - Upon ->get_hw_cap call, mempool driver will advertise
>>>> capability by returning flag.
>>>> - Common layer updates flag value in 'mp->flags'.
>>>>
>>>> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
>>>> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>  
>>> I guess you've already seen the compilation issue when shared libs
>>> are enabled:
>>> http://dpdk.org/dev/patchwork/patch/25603
>>>  
>> Yes, Will fix in v2.
>>
>>>  
>>>> ---
>>>>  lib/librte_mempool/rte_mempool.c           |  5 +++++
>>>>  lib/librte_mempool/rte_mempool.h           | 20 ++++++++++++++++++++
>>>>  lib/librte_mempool/rte_mempool_ops.c       | 14 ++++++++++++++
>>>>  lib/librte_mempool/rte_mempool_version.map |  7 +++++++
>>>>  4 files changed, 46 insertions(+)
>>>>
>>>> diff --git a/lib/librte_mempool/rte_mempool.c b/lib/librte_mempool/rte_mempool.c
>>>> index f65310f60..045baef45 100644
>>>> --- a/lib/librte_mempool/rte_mempool.c
>>>> +++ b/lib/librte_mempool/rte_mempool.c
>>>> @@ -527,6 +527,11 @@ rte_mempool_populate_default(struct rte_mempool *mp)
>>>>  	if (mp->nb_mem_chunks != 0)
>>>>  		return -EEXIST;
>>>>  
>>>> +	/* Get external mempool capability */
>>>> +	ret = rte_mempool_ops_get_hw_cap(mp);  
>>> "hw" can be removed since some handlers are software (the other occurences
>>> of hw should be removed too)
>>>
>>> "capabilities" is clearer than "cap"
>>>
>>> So I suggest rte_mempool_ops_get_capabilities() instead
>>> With this name, the comment above becomes overkill...  
>> ok. Will take care in v2.
>>
>>>> +	if (ret != -ENOENT)  
>>> -ENOTSUP looks more appropriate (like in ethdev)
>>>  
>> imo: -ENOENT tell that driver has no new entry for capability flag(mp->flag).
>> But no strong opinion for -ENOTSUP.
>>
>>>> +		mp->flags |= ret;  
>>> I'm wondering if these capability flags should be mixed with
>>> other mempool flags.
>>>
>>> We can maybe remove this code above and directly call
>>> rte_mempool_ops_get_capabilities() when we need to get them.  
>> 0) Treating this capability flag different vs existing RTE_MEMPOLL_F would
>> result to adding new flag entry in struct rte_mempool { .drv_flag} for example.
>> 1) That new flag entry will break ABI.
>> 2) In-fact application can benefit this capability flag by explicitly setting
>> in pool create api (e.g: rte_mempool_create_empty (, , , , , _F_POOL_CONGIG | F_BLK_SZ_ALIGNED)).
>>
>> Those flag use-case not limited till driver scope, application too can benefit.
>>
>> 3) Also provided that we have space in RTE_MEMPOOL_F_XX area, so adding couple of
>> more bit won't impact design or effect pool creation sequence.
>>
>> 4) By calling _ops_get_capability() at _populate_default() area would address issues pointed by
>> you at patch [3/4]. Will explain details on ' how' in respective patch [3/4].
>>
>> 5) Above all, Intent is to make sure that common layer managing capability flag 
>> on behalf of driver or application.
>
> I don't see any use case where an application could request
> a block size alignment.
>
> The problem of adding flags that are accessible to the user
> is the complexity it adds to the API. If every driver comes
> with its own flags, I'm affraid the generic code will soon become
> unmaintainable. Especially, the dependencies between the flags
> will have to be handled somewhere.
>
> But, ok, let's do it.
>
>
>
>>>> +
>>>>  	if (rte_xen_dom0_supported()) {
>>>>  		pg_sz = RTE_PGSIZE_2M;
>>>>  		pg_shift = rte_bsf32(pg_sz);
>>>> diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
>>>> index a65f1a79d..c3cdc77e4 100644
>>>> --- a/lib/librte_mempool/rte_mempool.h
>>>> +++ b/lib/librte_mempool/rte_mempool.h
>>>> @@ -390,6 +390,12 @@ typedef int (*rte_mempool_dequeue_t)(struct rte_mempool *mp,
>>>>   */
>>>>  typedef unsigned (*rte_mempool_get_count)(const struct rte_mempool *mp);
>>>>  
>>>> +/**
>>>> + * Get the mempool hw capability.
>>>> + */
>>>> +typedef int (*rte_mempool_get_hw_cap_t)(struct rte_mempool *mp);
>>>> +
>>>> +  
>>> If possible, use "const struct rte_mempool *mp"
>>>
>>> Since flags are unsigned, I would also prefer a function returning an
>>> int (0 on success, negative on error) and writing to an unsigned pointer
>>> provided by the user.
>>>  
>> confused? mp->flag is int not unsigned. and We're returning
>> -ENOENT/-ENOTSUP at error and positive value in-case driver supports capability.
> Returing an int that is either an error or a flag mask prevents
> from using the last flag 0x80000000 because it is also the sign bit.
>
Ok. Will address in v2.

BTW: mp->flag is int and in case of updating a flag to a value like
0x80000000 will be a problem.. so do you want me to change
mp->flag data type from int to unsigned int and send out deprecation notice
for same?

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 1/4] mempool: get the external mempool capability
  2017-07-05  6:41  3%     ` santosh
@ 2017-07-10 13:55  0%       ` Olivier Matz
  2017-07-10 16:09  0%         ` santosh
  0 siblings, 1 reply; 200+ results
From: Olivier Matz @ 2017-07-10 13:55 UTC (permalink / raw)
  To: santosh; +Cc: dev, thomas, hemant.agrawal, jerin.jacob, bruce.richardson

On Wed, 5 Jul 2017 12:11:52 +0530, santosh <santosh.shukla@caviumnetworks.com> wrote:
> Hi Olivier,
> 
> On Monday 03 July 2017 10:07 PM, Olivier Matz wrote:
> 
> > Hi Santosh,
> >
> > On Wed, 21 Jun 2017 17:32:45 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:  
> >> Allow external mempool to advertise its capability.
> >> A handler been introduced called rte_mempool_ops_get_hw_cap.
> >> - Upon ->get_hw_cap call, mempool driver will advertise
> >> capability by returning flag.
> >> - Common layer updates flag value in 'mp->flags'.
> >>
> >> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
> >> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>  
> > I guess you've already seen the compilation issue when shared libs
> > are enabled:
> > http://dpdk.org/dev/patchwork/patch/25603
> >  
> Yes, Will fix in v2.
> 
> >  
> >> ---
> >>  lib/librte_mempool/rte_mempool.c           |  5 +++++
> >>  lib/librte_mempool/rte_mempool.h           | 20 ++++++++++++++++++++
> >>  lib/librte_mempool/rte_mempool_ops.c       | 14 ++++++++++++++
> >>  lib/librte_mempool/rte_mempool_version.map |  7 +++++++
> >>  4 files changed, 46 insertions(+)
> >>
> >> diff --git a/lib/librte_mempool/rte_mempool.c b/lib/librte_mempool/rte_mempool.c
> >> index f65310f60..045baef45 100644
> >> --- a/lib/librte_mempool/rte_mempool.c
> >> +++ b/lib/librte_mempool/rte_mempool.c
> >> @@ -527,6 +527,11 @@ rte_mempool_populate_default(struct rte_mempool *mp)
> >>  	if (mp->nb_mem_chunks != 0)
> >>  		return -EEXIST;
> >>  
> >> +	/* Get external mempool capability */
> >> +	ret = rte_mempool_ops_get_hw_cap(mp);  
> > "hw" can be removed since some handlers are software (the other occurences
> > of hw should be removed too)
> >
> > "capabilities" is clearer than "cap"
> >
> > So I suggest rte_mempool_ops_get_capabilities() instead
> > With this name, the comment above becomes overkill...  
> 
> ok. Will take care in v2.
> 
> >> +	if (ret != -ENOENT)  
> > -ENOTSUP looks more appropriate (like in ethdev)
> >  
> imo: -ENOENT tell that driver has no new entry for capability flag(mp->flag).
> But no strong opinion for -ENOTSUP.
> 
> >> +		mp->flags |= ret;  
> > I'm wondering if these capability flags should be mixed with
> > other mempool flags.
> >
> > We can maybe remove this code above and directly call
> > rte_mempool_ops_get_capabilities() when we need to get them.  
> 
> 0) Treating this capability flag different vs existing RTE_MEMPOLL_F would
> result to adding new flag entry in struct rte_mempool { .drv_flag} for example.
> 1) That new flag entry will break ABI.
> 2) In-fact application can benefit this capability flag by explicitly setting
> in pool create api (e.g: rte_mempool_create_empty (, , , , , _F_POOL_CONGIG | F_BLK_SZ_ALIGNED)).
> 
> Those flag use-case not limited till driver scope, application too can benefit.
> 
> 3) Also provided that we have space in RTE_MEMPOOL_F_XX area, so adding couple of
> more bit won't impact design or effect pool creation sequence.
> 
> 4) By calling _ops_get_capability() at _populate_default() area would address issues pointed by
> you at patch [3/4]. Will explain details on ' how' in respective patch [3/4].
> 
> 5) Above all, Intent is to make sure that common layer managing capability flag 
> on behalf of driver or application.


I don't see any use case where an application could request
a block size alignment.

The problem of adding flags that are accessible to the user
is the complexity it adds to the API. If every driver comes
with its own flags, I'm affraid the generic code will soon become
unmaintainable. Especially, the dependencies between the flags
will have to be handled somewhere.

But, ok, let's do it.



> >> +
> >>  	if (rte_xen_dom0_supported()) {
> >>  		pg_sz = RTE_PGSIZE_2M;
> >>  		pg_shift = rte_bsf32(pg_sz);
> >> diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
> >> index a65f1a79d..c3cdc77e4 100644
> >> --- a/lib/librte_mempool/rte_mempool.h
> >> +++ b/lib/librte_mempool/rte_mempool.h
> >> @@ -390,6 +390,12 @@ typedef int (*rte_mempool_dequeue_t)(struct rte_mempool *mp,
> >>   */
> >>  typedef unsigned (*rte_mempool_get_count)(const struct rte_mempool *mp);
> >>  
> >> +/**
> >> + * Get the mempool hw capability.
> >> + */
> >> +typedef int (*rte_mempool_get_hw_cap_t)(struct rte_mempool *mp);
> >> +
> >> +  
> > If possible, use "const struct rte_mempool *mp"
> >
> > Since flags are unsigned, I would also prefer a function returning an
> > int (0 on success, negative on error) and writing to an unsigned pointer
> > provided by the user.
> >  
> confused? mp->flag is int not unsigned. and We're returning
> -ENOENT/-ENOTSUP at error and positive value in-case driver supports capability.

Returing an int that is either an error or a flag mask prevents
from using the last flag 0x80000000 because it is also the sign bit.

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v6] doc: release notes 17.08, API change description
  2017-07-10  9:18  4%       ` [dpdk-dev] [PATCH v5] " Radu Nicolau
@ 2017-07-10 11:39  4%         ` Radu Nicolau
  0 siblings, 0 replies; 200+ results
From: Radu Nicolau @ 2017-07-10 11:39 UTC (permalink / raw)
  To: dev; +Cc: thomas, john.mcnamara, radu.nicolau

Added API change description - moved bypass functions
from the rte_ethdev library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---

v6: changed library name to rte_ethdev and "APIs" to "functions", 
    added newline after section.

 doc/guides/rel_notes/release_17_08.rst | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..234994e 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,32 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ethdev library to ixgbe PMD**
+
+  * The following rte_ethdev library functions were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+
+  * The following ixgbe PMD functions were added:
+
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
+
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v5] doc: release notes 17.08, API change description
  2017-07-10  9:15  4%     ` [dpdk-dev] [PATCH v4] " Radu Nicolau
@ 2017-07-10  9:18  4%       ` Radu Nicolau
  2017-07-10 11:39  4%         ` [dpdk-dev] [PATCH v6] " Radu Nicolau
  0 siblings, 1 reply; 200+ results
From: Radu Nicolau @ 2017-07-10  9:18 UTC (permalink / raw)
  To: dev; +Cc: thomas, john.mcnamara, radu.nicolau

Added API change description - moved bypass functions
from the rte_ethdev library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---

v5: changed library name to rte_ethdev and "APIs" to "functions"

 doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..c5e9e51 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,31 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ethdev library to ixgbe PMD**
+
+  * The following rte_ethdev library functions were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+
+  * The following ixgbe PMD functions were added:
+
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v4] doc: release notes 17.08, API change description
  2017-07-07  9:21  4%   ` [dpdk-dev] [PATCH v3] " Radu Nicolau
  2017-07-08 16:23  0%     ` Thomas Monjalon
@ 2017-07-10  9:15  4%     ` Radu Nicolau
  2017-07-10  9:18  4%       ` [dpdk-dev] [PATCH v5] " Radu Nicolau
  1 sibling, 1 reply; 200+ results
From: Radu Nicolau @ 2017-07-10  9:15 UTC (permalink / raw)
  To: dev; +Cc: thomas, john.mcnamara, radu.nicolau

Added API change description - moved bypass functions
from the rte_ethdev library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---

v4: changed library name to rte_ethdev and "APIs" to "functions"

 doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..2a035d9 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,31 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ether library to ixgbe PMD**
+
+  * The following rte_ethdev library functions were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+
+  * The following ixgbe PMD functions were added:
+
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI
  2017-07-09  9:28 11% ` [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI Jan Blunck
@ 2017-07-09 12:25  4%   ` Shreyansh Jain
  2017-08-07 23:03  4%   ` Thomas Monjalon
  1 sibling, 0 replies; 200+ results
From: Shreyansh Jain @ 2017-07-09 12:25 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev

On 7/9/2017 2:58 PM, Jan Blunck wrote:
> Add deprecation notice necessary to do devargs refactoring for 17.11.
>
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
>  doc/guides/rel_notes/deprecation.rst | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 33e8b93db..5b6ed0444 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -64,3 +64,10 @@ Deprecation Notices
>    be removed in 17.11:
>
>    - ``rte_eal_parse_devargs_str``
> +
> +* devargs: An ABI change is planned for 17.11 for the structure ``rte_devargs``.
> +  The newly introduced devargs ABI in 17.08 is tightly couple to the bus
                                                           ^^^^^^^
Trivial comment:                                          coupled

> +  implementations which will get fixed in 17.11. The following function is
> +  deprecated and will change API in 17.11:
> +
> +  - ``rte_eal_devargs_add``
>


-- 
-
Shreyansh

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI
  2017-07-09  9:28  3% [dpdk-dev] [PATCH 0/2] devargs changes / deprecation notice Jan Blunck
@ 2017-07-09  9:28 11% ` Jan Blunck
  2017-07-09 12:25  4%   ` Shreyansh Jain
  2017-08-07 23:03  4%   ` Thomas Monjalon
  0 siblings, 2 replies; 200+ results
From: Jan Blunck @ 2017-07-09  9:28 UTC (permalink / raw)
  To: dev

Add deprecation notice necessary to do devargs refactoring for 17.11.

Signed-off-by: Jan Blunck <jblunck@infradead.org>
---
 doc/guides/rel_notes/deprecation.rst | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 33e8b93db..5b6ed0444 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -64,3 +64,10 @@ Deprecation Notices
   be removed in 17.11:
 
   - ``rte_eal_parse_devargs_str``
+
+* devargs: An ABI change is planned for 17.11 for the structure ``rte_devargs``.
+  The newly introduced devargs ABI in 17.08 is tightly couple to the bus
+  implementations which will get fixed in 17.11. The following function is
+  deprecated and will change API in 17.11:
+
+  - ``rte_eal_devargs_add``
-- 
2.11.0 (Apple Git-81)

^ permalink raw reply	[relevance 11%]

* [dpdk-dev] [PATCH 0/2] devargs changes / deprecation notice
@ 2017-07-09  9:28  3% Jan Blunck
  2017-07-09  9:28 11% ` [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI Jan Blunck
  0 siblings, 1 reply; 200+ results
From: Jan Blunck @ 2017-07-09  9:28 UTC (permalink / raw)
  To: dev

Since rte_devargs API will change again for 17.11 I'll add a deprecation notice
now to be able to get the change into the next release.

Jan Blunck (2):
  eal: internalize devargs parsing
  eal: deprecate 17.08 devargs API/ABI

 doc/guides/rel_notes/deprecation.rst            |  9 ++++++++-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  1 -
 lib/librte_eal/common/eal_common_devargs.c      |  2 +-
 lib/librte_eal/common/include/rte_devargs.h     | 20 --------------------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  1 -
 5 files changed, 9 insertions(+), 24 deletions(-)

--
2.11.0 (Apple Git-81)

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v3] doc: release notes 17.08, API change description
  2017-07-07  9:21  4%   ` [dpdk-dev] [PATCH v3] " Radu Nicolau
@ 2017-07-08 16:23  0%     ` Thomas Monjalon
  2017-07-10  9:15  4%     ` [dpdk-dev] [PATCH v4] " Radu Nicolau
  1 sibling, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-07-08 16:23 UTC (permalink / raw)
  To: Radu Nicolau; +Cc: dev, john.mcnamara

Hi,

07/07/2017 11:21, Radu Nicolau:
> Added API change description - moved bypass functions
> from the rte_ether library to ixgbe PMD
> 
> Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
> ---
> 
> v3: fixed indentation issue
> 
>  doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
> index 842f46f..3b371d3 100644
> --- a/doc/guides/rel_notes/release_17_08.rst
> +++ b/doc/guides/rel_notes/release_17_08.rst
> @@ -144,6 +144,31 @@ API Changes
>     Also, make sure to start the actual text at the margin.
>     =========================================================
>  
> +* **Moved bypass functions from the rte_ether library to ixgbe PMD**

The library name is not rte_ether but rte_ethdev or just ethdev.
The name rte_ether refers to the directory where the library code
is wrongly located.

> +  * The following rte_ether library APIs were removed:

They are all functions, right?
So it's better to replace "APIs" by "functions".

> +
> +    * ``rte_eth_dev_bypass_event_show``
> +    * ``rte_eth_dev_bypass_event_store``
> +    * ``rte_eth_dev_bypass_init``
> +    * ``rte_eth_dev_bypass_state_set``
> +    * ``rte_eth_dev_bypass_state_show``
> +    * ``rte_eth_dev_bypass_ver_show``
> +    * ``rte_eth_dev_bypass_wd_reset``
> +    * ``rte_eth_dev_bypass_wd_timeout_show``
> +    * ``rte_eth_dev_wd_timeout_store``
> +
> +  * The following ixgbe PMD APIs were added:
> +
> +    * ``rte_pmd_ixgbe_bypass_event_show``
> +    * ``rte_pmd_ixgbe_bypass_event_store``
> +    * ``rte_pmd_ixgbe_bypass_init``
> +    * ``rte_pmd_ixgbe_bypass_state_set``
> +    * ``rte_pmd_ixgbe_bypass_state_show``
> +    * ``rte_pmd_ixgbe_bypass_ver_show``
> +    * ``rte_pmd_ixgbe_bypass_wd_reset``
> +    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
> +    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
>  
>  ABI Changes
>  -----------

A newline is missing before next section.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v10 20/20] ethdev: add control interface support
  @ 2017-07-08  6:28  3%   ` Yuanhan Liu
  2017-07-20 14:55  0%     ` Ferruh Yigit
  0 siblings, 1 reply; 200+ results
From: Yuanhan Liu @ 2017-07-08  6:28 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: dev, Stephen Hemminger, Bruce Richardson, Anatoly Burakov,
	Thomas Monjalon

On Tue, Jul 04, 2017 at 05:13:37PM +0100, Ferruh Yigit wrote:
> @@ -157,8 +164,12 @@ rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
>  
>  	RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL);
>  	ret = dev_init(eth_dev);
> -	if (ret)
> +	if (ret) {
>  		rte_eth_dev_pci_release(eth_dev);
> +		return ret;
> +	}
> +
> +	rte_eth_control_interface_create(eth_dev->data->port_id);

Hi,

So you are creating a virtual kernel interface for each PCI port. What
about the VDEVs? If you plan to create one for each port, why not create
it at the stage while allocating the eth device, or at the stage while
starting the port if the former is too earlier?

Another thing comes to my mind is have you tried it with multi-process
model? Looks like it will create the control interface twice? Or it will
just be failed since the interface already exists?


I also have few questions regarding the whole design. So seems that the
ctrl_if only exports two APIs and they all will be only used in the EAL
layer. Thus, one question is did you plan to let APP use them? Judging
EAL already calls them automatically, I don't think it makes sense to
let the APP call it again. That being said, what's the point of the making
it be an lib? Why not just put it under EAL or somewhere else, and let
EAL invoke it as normal helper functions (instead of by public APIs)?

I will avoid adding a new lib if possible. Otherwise, it increases the
chance of ABI/API breakage is needed in future for extensions.

The same question goes to the ethtool lib. Since your solution can work
well with the well-known ethtool, which is also way more widely available
than the DPDK ethtool app, what's the point of keeping the ethtool app
then? Like above, I also don't think those APIs are meant for APPs (or
are they?). Thus, with the ethtool app removed, we then could again avoid
introducing a new lib.

	--yliu

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation
  @ 2017-07-07 16:41  1%   ` Harry van Haaren
  2017-07-11  8:29  0%     ` Jerin Jacob
    1 sibling, 1 reply; 200+ results
From: Harry van Haaren @ 2017-07-07 16:41 UTC (permalink / raw)
  To: dev; +Cc: thomas, jerin.jacob, keith.wiles, bruce.richardson, Harry van Haaren

Add header files, update .map files with new service
functions, and add the service header to the doxygen
for building.

This service header API allows DPDK to use services as
a concept of something that requires CPU cycles. An example
is a PMD that runs in software to schedule events, where a
hardware version exists that does not require a CPU.

The code presented here is based on an initial RFC:
http://dpdk.org/ml/archives/dev/2017-May/065207.html
This was then reworked, and RFC v2 with the changes posted:
http://dpdk.org/ml/archives/dev/2017-June/067194.html

This is the fourth iteration of the service core concept,
with 2 RFCs and this being v2 of the implementation.

Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>

---

v4:
- Fixed (unsigned) checkpatch error
- Fixed misleading-indentation/if { } brackets (checkpatch/Jerin)
- Fixed set function argument to be "enable" instead of "enabled" (Jerin)
- Improve doxygen comment for size of array in rte_service_core_list (Jerin)
- Fixed typos (Jerin)
- Optimized atomic clear after running service (Jerin)
- Added smp_rmb() at end of loop to re-load runstate / mapping (Jerin)
- Fix issue with lcore role not being adhered to (Jerin)
- Add experimental warnings for all service core functions (Thomas)
- Moved service core functions into EXPERIMENTAL section of .map (Thomas)
- Improve documentation of rte_service_lcore_reset_all() (Harry)

v3:
- None.

v2:
Thanks Jerin for review - below a list your suggested changes;
- Doxygen rename to "service cores" for consistency
- use lcore instead of core for function names
- Fix about 10 typos / seplling msitakse ;)
- Dix doxygen /** comments for functions
- Doxygen @param[out] improvements
- int8_t for socket_id to ordinary int
- Rename MACROS for readability
- Align structs to cache lines
- Allocate fastpath-used data from hugepages
- Added/fixed memory barriers for multi-core scheduling
- Add const to variables, and hoist above loop
- Optimize cmpset atomic if MT_SAFE or only one core mapped
- Statistics collection only when requested
- Add error check for array pointer
- Remove panic() calls from library
- Fix TODO notes from previous patchset

There are also some other changes;
- Checkpatch issues fixed
- .map file updates
- Add rte_service_get_by_name() function
---
 doc/api/doxy-api-index.md                          |   1 +
 lib/librte_eal/bsdapp/eal/Makefile                 |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  22 +
 lib/librte_eal/common/Makefile                     |   1 +
 lib/librte_eal/common/eal_common_lcore.c           |   1 +
 lib/librte_eal/common/include/rte_eal.h            |   4 +
 lib/librte_eal/common/include/rte_lcore.h          |   3 +-
 lib/librte_eal/common/include/rte_service.h        | 383 ++++++++++++
 .../common/include/rte_service_private.h           | 140 +++++
 lib/librte_eal/common/rte_service.c                | 687 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_thread.c           |   9 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  22 +
 13 files changed, 1273 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/common/include/rte_service.h
 create mode 100644 lib/librte_eal/common/include/rte_service_private.h
 create mode 100644 lib/librte_eal/common/rte_service.c

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 3b83288..e2abdf4 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
+  [service cores]      (@ref rte_service.h),
   [device metrics]     (@ref rte_metrics.h),
   [bitrate statistics] (@ref rte_bitrate.h),
   [latency statistics] (@ref rte_latencystats.h),
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a0f9950..05517a2 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -87,6 +87,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 0295ea9..130b2c0 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -208,5 +208,27 @@ EXPERIMENTAL {
 
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_stop;
+	rte_service_unregister;
 
 } DPDK_17.08;
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index f2fe052..942f03c 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -41,6 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
+INC += rte_service.h rte_service_private.h
 
 GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
 GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h
diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
index 84fa0cb..0db1555 100644
--- a/lib/librte_eal/common/eal_common_lcore.c
+++ b/lib/librte_eal/common/eal_common_lcore.c
@@ -81,6 +81,7 @@ rte_eal_cpu_init(void)
 
 		/* By default, each detected core is enabled */
 		config->lcore_role[lcore_id] = ROLE_RTE;
+		lcore_config[lcore_id].core_role = ROLE_RTE;
 		lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
 		lcore_config[lcore_id].socket_id = eal_cpu_socket_id(lcore_id);
 		if (lcore_config[lcore_id].socket_id >= RTE_MAX_NUMA_NODES) {
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
index abf020b..4dd0518 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -61,6 +61,7 @@ extern "C" {
 enum rte_lcore_role_t {
 	ROLE_RTE,
 	ROLE_OFF,
+	ROLE_SERVICE,
 };
 
 /**
@@ -80,6 +81,7 @@ enum rte_proc_type_t {
 struct rte_config {
 	uint32_t master_lcore;       /**< Id of the master lcore */
 	uint32_t lcore_count;        /**< Number of available logical cores. */
+	uint32_t service_lcore_count;/**< Number of available service cores. */
 	enum rte_lcore_role_t lcore_role[RTE_MAX_LCORE]; /**< State of cores. */
 
 	/** Primary or secondary configuration */
@@ -185,6 +187,8 @@ int rte_eal_iopl_init(void);
  *
  *     EPROTO indicates that the PCI bus is either not present, or is not
  *            readable by the eal.
+ *
+ *     ENOEXEC indicates that a service core failed to launch successfully.
  */
 int rte_eal_init(int argc, char **argv);
 
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/common/include/rte_lcore.h
index fe7b586..50e0d0f 100644
--- a/lib/librte_eal/common/include/rte_lcore.h
+++ b/lib/librte_eal/common/include/rte_lcore.h
@@ -73,6 +73,7 @@ struct lcore_config {
 	unsigned core_id;          /**< core number on socket for this lcore */
 	int core_index;            /**< relative index, starting from 0 */
 	rte_cpuset_t cpuset;       /**< cpu set which the lcore affinity to */
+	uint8_t core_role;         /**< role of core eg: OFF, RTE, SERVICE */
 };
 
 /**
@@ -175,7 +176,7 @@ rte_lcore_is_enabled(unsigned lcore_id)
 	struct rte_config *cfg = rte_eal_get_configuration();
 	if (lcore_id >= RTE_MAX_LCORE)
 		return 0;
-	return cfg->lcore_role[lcore_id] != ROLE_OFF;
+	return cfg->lcore_role[lcore_id] == ROLE_RTE;
 }
 
 /**
diff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/common/include/rte_service.h
new file mode 100644
index 0000000..7588a41
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service.h
@@ -0,0 +1,383 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_H_
+#define _RTE_SERVICE_H_
+
+/**
+ * @file
+ *
+ * Service functions
+ *
+ * The service functionality provided by this header allows a DPDK component
+ * to indicate that it requires a function call in order for it to perform
+ * its processing.
+ *
+ * An example usage of this functionality would be a component that registers
+ * a service to perform a particular packet processing duty: for example the
+ * eventdev software PMD. At startup the application requests all services
+ * that have been registered, and the cores in the service-coremask run the
+ * required services. The EAL removes these number of cores from the available
+ * runtime cores, and dedicates them to performing service-core workloads. The
+ * application has access to the remaining lcores as normal.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include<stdio.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_lcore.h>
+
+/* forward declaration only. Definition in rte_service_private.h */
+struct rte_service_spec;
+
+#define RTE_SERVICE_NAME_MAX 32
+
+/* Capabilities of a service.
+ *
+ * Use the *rte_service_probe_capability* function to check if a service is
+ * capable of a specific capability.
+ */
+/** When set, the service is capable of having multiple threads run it at the
+ *  same time.
+ */
+#define RTE_SERVICE_CAP_MT_SAFE (1 << 0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ *  Return the number of services registered.
+ *
+ * The number of services registered can be passed to *rte_service_get_by_id*,
+ * enabling the application to retrieve the specification of each service.
+ *
+ * @return The number of services registered.
+ */
+uint32_t rte_service_get_count(void);
+
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the specification of a service by integer id.
+ *
+ * This function provides the specification of a service. This can be used by
+ * the application to understand what the service represents. The service
+ * must not be modified by the application directly, only passed to the various
+ * rte_service_* functions.
+ *
+ * @param id The integer id of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *id* provided.
+ */
+struct rte_service_spec *rte_service_get_by_id(uint32_t id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the specification of a service by name.
+ *
+ * This function provides the specification of a service using the service name
+ * as lookup key. This can be used by the application to understand what the
+ * service represents. The service must not be modified by the application
+ * directly, only passed to the various rte_service_* functions.
+ *
+ * @param name The name of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *name* provided.
+ */
+struct rte_service_spec *rte_service_get_by_name(const char *name);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the name of the service.
+ *
+ * @return A pointer to the name of the service. The returned pointer remains
+ *         in ownership of the service, and the application must not free it.
+ */
+const char *rte_service_get_name(const struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check if a service has a specific capability.
+ *
+ * This function returns if *service* has implements *capability*.
+ * See RTE_SERVICE_CAP_* defines for a list of valid capabilities.
+ * @retval 1 Capability supported by this service instance
+ * @retval 0 Capability not supported by this service instance
+ */
+int32_t rte_service_probe_capability(const struct rte_service_spec *service,
+				     uint32_t capability);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions adds *lcore* to the set of cores that will run *service*.
+ *
+ * If multiple cores are enabled on a service, an atomic is used to ensure that
+ * only one cores runs the service at a time. The exception to this is when
+ * a service indicates that it is multi-thread safe by setting the capability
+ * called RTE_SERVICE_CAP_MT_SAFE. With the multi-thread safe capability set,
+ * the service function can be run on multiple threads at the same time.
+ *
+ * @retval 0 lcore added successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_enable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Disable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions removes *lcore* to the set of cores that will run *service*.
+ *
+ * @retval 0 Lcore removed successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_disable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return if an lcore is enabled for the service.
+ *
+ * This function allows the application to query if *lcore* is currently set to
+ * run *service*.
+ *
+ * @retval 1 Lcore enabled on this lcore
+ * @retval 0 Lcore disabled on this lcore
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore);
+
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable *service* to run.
+ *
+ * This function switches on a service during runtime.
+ * @retval 0 The service was successfully started
+ */
+int32_t rte_service_start(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Disable *service*.
+ *
+ * Switch off a service, so it is not run until it is *rte_service_start* is
+ * called on it.
+ * @retval 0 Service successfully switched off
+ */
+int32_t rte_service_stop(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Returns if *service* is currently running.
+ *
+ * This function returns true if the service has been started using
+ * *rte_service_start*, AND a service core is mapped to the service. This
+ * function can be used to ensure that the service will be run.
+ *
+ * @retval 1 Service is currently running, and has a service lcore mapped
+ * @retval 0 Service is currently stopped, or no service lcore is mapped
+ * @retval -EINVAL Invalid service pointer provided
+ */
+int32_t rte_service_is_running(const struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a service core.
+ *
+ * Starting a core makes the core begin polling. Any services assigned to it
+ * will be run as fast as possible.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Failed to start core. The *lcore_id* passed in is not
+ *          currently assigned to be a service core.
+ */
+int32_t rte_service_lcore_start(uint32_t lcore_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop a service core.
+ *
+ * Stopping a core makes the core become idle, but remains  assigned as a
+ * service core.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Invalid *lcore_id* provided
+ * @retval -EALREADY Already stopped core
+ * @retval -EBUSY Failed to stop core, as it would cause a service to not
+ *          be run, as this is the only core currently running the service.
+ *          The application must stop the service first, and then stop the
+ *          lcore.
+ */
+int32_t rte_service_lcore_stop(uint32_t lcore_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Adds lcore to the list of service cores.
+ *
+ * This functions can be used at runtime in order to modify the service core
+ * mask.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY lcore is busy, and not available for service core duty
+ * @retval -EALREADY lcore is already added to the service core list
+ * @retval -EINVAL Invalid lcore provided
+ */
+int32_t rte_service_lcore_add(uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Removes lcore from the list of service cores.
+ *
+ * This can fail if the core is not stopped, see *rte_service_core_stop*.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY Lcore is not stopped, stop service core before removing.
+ * @retval -EINVAL failed to add lcore to service core mask.
+ */
+int32_t rte_service_lcore_del(uint32_t lcore);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the number of service cores currently available.
+ *
+ * This function returns the integer count of service cores available. The
+ * service core count can be used in mapping logic when creating mappings
+ * from service cores to services.
+ *
+ * See *rte_service_lcore_list* for details on retrieving the lcore_id of each
+ * service core.
+ *
+ * @return The number of service cores currently configured.
+ */
+int32_t rte_service_lcore_count(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Resets all service core mappings. This does not remove the service cores
+ * from duty, just unmaps all services / cores, and stops() the service cores.
+ * The runstate of services is not modified.
+ *
+ * @retval 0 Success
+ */
+int32_t rte_service_lcore_reset_all(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enable or disable statistics collection.
+ *
+ * This function enables per core, per-service cycle count collection.
+ * @param enabled Zero to turn off statistics collection, non-zero to enable.
+ */
+void rte_service_set_stats_enable(int enable);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the list of currently enabled service cores.
+ *
+ * This function fills in an application supplied array, with each element
+ * indicating the lcore_id of a service core.
+ *
+ * Adding and removing service cores can be performed using
+ * *rte_service_lcore_add* and *rte_service_lcore_del*.
+ * @param [out] array An array of at least *rte_service_lcore_count* items.
+ *              If statically allocating the buffer, use RTE_MAX_LCORE.
+ * @param [out] The size of *array*.
+ * @retval >=0 Number of service cores that have been populated in the array
+ * @retval -ENOMEM The provided array is not large enough to fill in the
+ *          service core list. No items have been populated, call this function
+ *          with a size of at least *rte_service_core_count* items.
+ */
+int32_t rte_service_lcore_list(uint32_t array[], uint32_t n);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Dumps any information available about the service. If service is NULL,
+ * dumps info for all services.
+ */
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_SERVICE_H_ */
diff --git a/lib/librte_eal/common/include/rte_service_private.h b/lib/librte_eal/common/include/rte_service_private.h
new file mode 100644
index 0000000..e726108
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service_private.h
@@ -0,0 +1,140 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_PRIVATE_H_
+#define _RTE_SERVICE_PRIVATE_H_
+
+/* This file specifies the internal service specification.
+ * Include this file if you are writing a component that requires CPU cycles to
+ * operate, and you wish to run the component using service cores
+ */
+
+#include <rte_service.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Signature of callback function to run a service.
+ */
+typedef int32_t (*rte_service_func)(void *args);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * The specification of a service.
+ *
+ * This struct contains metadata about the service itself, the callback
+ * function to run one iteration of the service, a userdata pointer, flags etc.
+ */
+struct rte_service_spec {
+	/** The name of the service. This should be used by the application to
+	 * understand what purpose this service provides.
+	 */
+	char name[RTE_SERVICE_NAME_MAX];
+	/** The callback to invoke to run one iteration of the service. */
+	rte_service_func callback;
+	/** The userdata pointer provided to the service callback. */
+	void *callback_userdata;
+	/** Flags to indicate the capabilities of this service. See defines in
+	 * the public header file for values of RTE_SERVICE_CAP_*
+	 */
+	uint32_t capabilities;
+	/** NUMA socket ID that this service is affinitized to */
+	int socket_id;
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Register a new service.
+ *
+ * A service represents a component that the requires CPU time periodically to
+ * achieve its purpose.
+ *
+ * For example the eventdev SW PMD requires CPU cycles to perform its
+ * scheduling. This can be achieved by registering it as a service, and the
+ * application can then assign CPU resources to it using
+ * *rte_service_set_coremask*.
+ *
+ * @param spec The specification of the service to register
+ * @retval 0 Successfully registered the service.
+ *         -EINVAL Attempted to register an invalid service (eg, no callback
+ *         set)
+ */
+int32_t rte_service_register(const struct rte_service_spec *spec);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Unregister a service.
+ *
+ * The service being removed must be stopped before calling this function.
+ *
+ * @retval 0 The service was successfully unregistered.
+ * @retval -EBUSY The service is currently running, stop the service before
+ *          calling unregister. No action has been taken.
+ */
+int32_t rte_service_unregister(struct rte_service_spec *service);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Private function to allow EAL to initialized default mappings.
+ *
+ * This function iterates all the services, and maps then to the available
+ * cores. Based on the capabilities of the services, they are set to run on the
+ * available cores in a round-robin manner.
+ *
+ * @retval 0 Success
+ */
+int32_t rte_service_set_default_mapping(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Initialize the service library.
+ *
+ * In order to use the service library, it must be initialized. EAL initializes
+ * the library at startup.
+ *
+ * @retval 0 Success
+ * @retval -EALREADY Service library is already initialized
+ */
+int32_t rte_service_init(void);
+
+#endif /* _RTE_SERVICE_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c
new file mode 100644
index 0000000..223ca22
--- /dev/null
+++ b/lib/librte_eal/common/rte_service.c
@@ -0,0 +1,687 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <rte_service.h>
+#include "include/rte_service_private.h"
+
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_atomic.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+#define RTE_SERVICE_NUM_MAX 64
+
+#define SERVICE_F_REGISTERED 0
+
+/* runstates for services and lcores, denoting if they are active or not */
+#define RUNSTATE_STOPPED 0
+#define RUNSTATE_RUNNING 1
+
+/* internal representation of a service */
+struct rte_service_spec_impl {
+	/* public part of the struct */
+	struct rte_service_spec spec;
+
+	/* atomic lock that when set indicates a service core is currently
+	 * running this service callback. When not set, a core may take the
+	 * lock and then run the service callback.
+	 */
+	rte_atomic32_t execute_lock;
+
+	/* API set/get-able variables */
+	int32_t runstate;
+	uint8_t internal_flags;
+
+	/* per service statistics */
+	uint32_t num_mapped_cores;
+	uint64_t calls;
+	uint64_t cycles_spent;
+} __rte_cache_aligned;
+
+/* the internal values of a service core */
+struct core_state {
+	/* map of services IDs are run on this core */
+	uint64_t service_mask;
+	uint8_t runstate; /* running or stopped */
+	uint8_t is_service_core; /* set if core is currently a service core */
+	uint8_t collect_statistics; /* if set, measure cycle counts */
+
+	/* extreme statistics */
+	uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
+} __rte_cache_aligned;
+
+static uint32_t rte_service_count;
+static struct rte_service_spec_impl *rte_services;
+static struct core_state *cores_state;
+static uint32_t rte_service_library_initialized;
+
+int32_t rte_service_init(void)
+{
+	if (rte_service_library_initialized) {
+		printf("service library init() called, init flag %d\n",
+			rte_service_library_initialized);
+		return -EALREADY;
+	}
+
+	rte_services = rte_calloc("rte_services", RTE_SERVICE_NUM_MAX,
+			sizeof(struct rte_service_spec_impl),
+			RTE_CACHE_LINE_SIZE);
+	if (!rte_services) {
+		printf("error allocating rte services array\n");
+		return -ENOMEM;
+	}
+
+	cores_state = rte_calloc("rte_service_core_states", RTE_MAX_LCORE,
+			sizeof(struct core_state), RTE_CACHE_LINE_SIZE);
+	if (!cores_state) {
+		printf("error allocating core states array\n");
+		return -ENOMEM;
+	}
+
+	int i;
+	int count = 0;
+	struct rte_config *cfg = rte_eal_get_configuration();
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role == ROLE_SERVICE) {
+			if ((unsigned int)i == cfg->master_lcore)
+				continue;
+			rte_service_lcore_add(i);
+			count++;
+		}
+	}
+
+	rte_service_library_initialized = 1;
+	return 0;
+}
+
+void rte_service_set_stats_enable(int enabled)
+{
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		cores_state[i].collect_statistics = enabled;
+}
+
+/* returns 1 if service is registered and has not been unregistered
+ * Returns 0 if service never registered, or has been unregistered
+ */
+static inline int
+service_valid(uint32_t id) {
+	return !!(rte_services[id].internal_flags &
+		 (1 << SERVICE_F_REGISTERED));
+}
+
+uint32_t
+rte_service_get_count(void)
+{
+	return rte_service_count;
+}
+
+struct rte_service_spec *
+rte_service_get_by_id(uint32_t id)
+{
+	struct rte_service_spec *service = NULL;
+	if (id < rte_service_count)
+		service = (struct rte_service_spec *)&rte_services[id];
+
+	return service;
+}
+
+struct rte_service_spec *rte_service_get_by_name(const char *name)
+{
+	struct rte_service_spec *service = NULL;
+	int i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (service_valid(i) &&
+				strcmp(name, rte_services[i].spec.name) == 0) {
+			service = (struct rte_service_spec *)&rte_services[i];
+			break;
+		}
+	}
+
+	return service;
+}
+
+const char *
+rte_service_get_name(const struct rte_service_spec *service)
+{
+	return service->name;
+}
+
+int32_t
+rte_service_probe_capability(const struct rte_service_spec *service,
+			     uint32_t capability)
+{
+	return service->capabilities & capability;
+}
+
+int32_t
+rte_service_is_running(const struct rte_service_spec *spec)
+{
+	const struct rte_service_spec_impl *impl =
+		(const struct rte_service_spec_impl *)spec;
+	if (!impl)
+		return -EINVAL;
+
+	return (impl->runstate == RUNSTATE_RUNNING) &&
+		(impl->num_mapped_cores > 0);
+}
+
+int32_t
+rte_service_register(const struct rte_service_spec *spec)
+{
+	uint32_t i;
+	int32_t free_slot = -1;
+
+	if (spec->callback == NULL || strlen(spec->name) == 0)
+		return -EINVAL;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i)) {
+			free_slot = i;
+			break;
+		}
+	}
+
+	if ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))
+		return -ENOSPC;
+
+	struct rte_service_spec_impl *s = &rte_services[free_slot];
+	s->spec = *spec;
+	s->internal_flags |= (1 << SERVICE_F_REGISTERED);
+
+	rte_smp_wmb();
+	rte_service_count++;
+
+	return 0;
+}
+
+int32_t
+rte_service_unregister(struct rte_service_spec *spec)
+{
+	struct rte_service_spec_impl *s = NULL;
+	struct rte_service_spec_impl *spec_impl =
+		(struct rte_service_spec_impl *)spec;
+
+	uint32_t i;
+	uint32_t service_id;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (&rte_services[i] == spec_impl) {
+			s = spec_impl;
+			service_id = i;
+			break;
+		}
+	}
+
+	if (!s)
+		return -EINVAL;
+
+	rte_service_count--;
+	rte_smp_wmb();
+
+	s->internal_flags &= ~(1 << SERVICE_F_REGISTERED);
+
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		cores_state[i].service_mask &= ~(1 << service_id);
+
+	memset(&rte_services[service_id], 0,
+			sizeof(struct rte_service_spec_impl));
+
+	return 0;
+}
+
+int32_t
+rte_service_start(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_RUNNING;
+	rte_smp_wmb();
+	return 0;
+}
+
+int32_t
+rte_service_stop(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_STOPPED;
+	rte_smp_wmb();
+	return 0;
+}
+
+static int32_t
+rte_service_runner_func(void *arg)
+{
+	RTE_SET_USED(arg);
+	uint32_t i;
+	const int lcore = rte_lcore_id();
+	struct core_state *cs = &cores_state[lcore];
+
+	while (cores_state[lcore].runstate == RUNSTATE_RUNNING) {
+		const uint64_t service_mask = cs->service_mask;
+		for (i = 0; i < rte_service_count; i++) {
+			struct rte_service_spec_impl *s = &rte_services[i];
+			if (s->runstate != RUNSTATE_RUNNING ||
+					!(service_mask & (1 << i)))
+				continue;
+
+			/* check if this is the only core mapped, else use
+			 * atomic to serialize cores mapped to this service
+			 */
+			uint32_t *lock = (uint32_t *)&s->execute_lock;
+			if ((s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE) ||
+					(s->num_mapped_cores == 1 ||
+					rte_atomic32_cmpset(lock, 0, 1))) {
+				void *userdata = s->spec.callback_userdata;
+
+				if (cs->collect_statistics) {
+					uint64_t start = rte_rdtsc();
+					s->spec.callback(userdata);
+					uint64_t end = rte_rdtsc();
+					s->cycles_spent += end - start;
+					cs->calls_per_service[i]++;
+					s->calls++;
+				} else
+					s->spec.callback(userdata);
+
+				if ((s->spec.capabilities &
+						RTE_SERVICE_CAP_MT_SAFE) == 0 &&
+						s->num_mapped_cores > 1)
+					rte_atomic32_clear(&s->execute_lock);
+			}
+		}
+
+		rte_smp_rmb();
+	}
+
+	lcore_config[lcore].state = WAIT;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_count(void)
+{
+	int32_t count = 0;
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		count += cores_state[i].is_service_core;
+	return count;
+}
+
+int32_t
+rte_service_lcore_list(uint32_t array[], uint32_t n)
+{
+	uint32_t count = rte_service_lcore_count();
+	if (count > n)
+		return -ENOMEM;
+
+	if (!array)
+		return -EINVAL;
+
+	uint32_t i;
+	uint32_t idx = 0;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct core_state *cs = &cores_state[i];
+		if (cs->is_service_core) {
+			array[idx] = i;
+			idx++;
+		}
+	}
+
+	return count;
+}
+
+int32_t
+rte_service_set_default_mapping(void)
+{
+	/* create a default mapping from cores to services, then start the
+	 * services to make them transparent to unaware applications.
+	 */
+	uint32_t i;
+	int ret;
+	uint32_t count = rte_service_get_count();
+
+	int32_t lcore_iter = 0;
+	uint32_t ids[RTE_MAX_LCORE];
+	int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
+
+	for (i = 0; i < count; i++) {
+		struct rte_service_spec *s = rte_service_get_by_id(i);
+		if (!s)
+			return -EINVAL;
+
+		/* if no lcores available as services cores, don't setup map.
+		 * This means app logic must add cores, and setup mappings
+		 */
+		if (lcore_count > 0) {
+			/* do 1:1 core mapping here, with each service getting
+			 * assigned a single core by default. Adding multiple
+			 * services should multiplex to a single core, or 1:1
+			 * if services == cores
+			 */
+			ret = rte_service_enable_on_lcore(s, ids[lcore_iter]);
+			if (ret)
+				return -ENODEV;
+		}
+
+		lcore_iter++;
+		if (lcore_iter >= lcore_count)
+			lcore_iter = 0;
+
+		ret = rte_service_start(s);
+		if (ret)
+			return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static int32_t
+service_update(struct rte_service_spec *service, uint32_t lcore,
+		uint32_t *set, uint32_t *enabled)
+{
+	uint32_t i;
+	int32_t sid = -1;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if ((struct rte_service_spec *)&rte_services[i] == service &&
+				service_valid(i)) {
+			sid = i;
+			break;
+		}
+	}
+
+	if (sid == -1 || lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (!cores_state[lcore].is_service_core)
+		return -EINVAL;
+
+	if (set) {
+		if (*set) {
+			cores_state[lcore].service_mask |=  (1 << sid);
+			rte_services[sid].num_mapped_cores++;
+		} else {
+			cores_state[lcore].service_mask &= ~(1 << sid);
+			rte_services[sid].num_mapped_cores--;
+		}
+	}
+
+	if (enabled)
+		*enabled = (cores_state[lcore].service_mask & (1 << sid));
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore)
+{
+	uint32_t enabled;
+	int ret = service_update(service, lcore, 0, &enabled);
+	if (ret == 0)
+		return enabled;
+	return -EINVAL;
+}
+
+int32_t
+rte_service_enable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t on = 1;
+	return service_update(service, lcore, &on, 0);
+}
+
+int32_t
+rte_service_disable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t off = 0;
+	return service_update(service, lcore, &off, 0);
+}
+
+int32_t rte_service_lcore_reset_all(void)
+{
+	/* loop over cores, reset all to mask 0 */
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		cores_state[i].service_mask = 0;
+		cores_state[i].is_service_core = 0;
+		cores_state[i].runstate = RUNSTATE_STOPPED;
+	}
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
+		rte_services[i].num_mapped_cores = 0;
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+static void
+set_lcore_state(uint32_t lcore, int32_t state)
+{
+	/* mark core state in hugepage backed config */
+	struct rte_config *cfg = rte_eal_get_configuration();
+	cfg->lcore_role[lcore] = state;
+
+	/* mark state in process local lcore_config */
+	lcore_config[lcore].core_role = state;
+
+	/* update per-lcore optimized state tracking */
+	cores_state[lcore].is_service_core = (state == ROLE_SERVICE);
+}
+
+int32_t
+rte_service_lcore_add(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+	if (cores_state[lcore].is_service_core)
+		return -EALREADY;
+
+	set_lcore_state(lcore, ROLE_SERVICE);
+
+	/* ensure that after adding a core the mask and state are defaults */
+	cores_state[lcore].service_mask = 0;
+	cores_state[lcore].runstate = RUNSTATE_STOPPED;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_del(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &cores_state[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate != RUNSTATE_STOPPED)
+		return -EBUSY;
+
+	set_lcore_state(lcore, ROLE_RTE);
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_start(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &cores_state[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate == RUNSTATE_RUNNING)
+		return -EALREADY;
+
+	/* set core to run state first, and then launch otherwise it will
+	 * return immediately as runstate keeps it in the service poll loop
+	 */
+	cores_state[lcore].runstate = RUNSTATE_RUNNING;
+
+	int ret = rte_eal_remote_launch(rte_service_runner_func, 0, lcore);
+	/* returns -EBUSY if the core is already launched, 0 on success */
+	return ret;
+}
+
+int32_t
+rte_service_lcore_stop(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (cores_state[lcore].runstate == RUNSTATE_STOPPED)
+		return -EALREADY;
+
+	uint32_t i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		int32_t enabled = cores_state[i].service_mask & (1 << i);
+		int32_t service_running = rte_services[i].runstate !=
+						RUNSTATE_STOPPED;
+		int32_t only_core = rte_services[i].num_mapped_cores == 1;
+
+		/* if the core is mapped, and the service is running, and this
+		 * is the only core that is mapped, the service would cease to
+		 * run if this core stopped, so fail instead.
+		 */
+		if (enabled && service_running && only_core)
+			return -EBUSY;
+	}
+
+	cores_state[lcore].runstate = RUNSTATE_STOPPED;
+
+	return 0;
+}
+
+static void
+rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,
+		     uint64_t all_cycles, uint32_t reset)
+{
+	/* avoid divide by zero */
+	if (all_cycles == 0)
+		all_cycles = 1;
+
+	int calls = 1;
+	if (s->calls != 0)
+		calls = s->calls;
+
+	float cycles_pct = (((float)s->cycles_spent) / all_cycles) * 100.f;
+	fprintf(f,
+			"  %s : %0.1f %%\tcalls %"PRIu64"\tcycles %"
+			PRIu64"\tavg: %"PRIu64"\n",
+			s->spec.name, cycles_pct, s->calls, s->cycles_spent,
+			s->cycles_spent / calls);
+
+	if (reset) {
+		s->cycles_spent = 0;
+		s->calls = 0;
+	}
+}
+
+static void
+service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)
+{
+	uint32_t i;
+	struct core_state *cs = &cores_state[lcore];
+
+	fprintf(f, "%02d\t", lcore);
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i))
+			continue;
+		fprintf(f, "%"PRIu64"\t", cs->calls_per_service[i]);
+		if (reset)
+			cs->calls_per_service[i] = 0;
+	}
+	fprintf(f, "\n");
+}
+
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service)
+{
+	uint32_t i;
+
+	uint64_t total_cycles = 0;
+	for (i = 0; i < rte_service_count; i++) {
+		if (!service_valid(i))
+			continue;
+		total_cycles += rte_services[i].cycles_spent;
+	}
+
+	int print_no_collect_warning = 0;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		if (cores_state[i].collect_statistics == 0)
+			print_no_collect_warning = 1;
+	if (print_no_collect_warning)
+		fprintf(f, "Warning; cycle counts not collectd; refer to rte_service_set_stats_enable\n");
+
+	if (service) {
+		struct rte_service_spec_impl *s =
+			(struct rte_service_spec_impl *)service;
+		fprintf(f, "Service %s Summary\n", s->spec.name);
+		uint32_t reset = 0;
+		rte_service_dump_one(f, s, total_cycles, reset);
+		return 0;
+	}
+
+	fprintf(f, "Services Summary\n");
+	for (i = 0; i < rte_service_count; i++) {
+		uint32_t reset = 1;
+		rte_service_dump_one(f, &rte_services[i], total_cycles, reset);
+	}
+
+	fprintf(f, "Service Cores Summary\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role != ROLE_SERVICE)
+			continue;
+
+		uint32_t reset = 0;
+		service_dump_calls_per_lcore(f, i, reset);
+	}
+
+	return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 8651e27..e6ab6c3 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -99,6 +99,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/linuxapp/eal/eal_thread.c b/lib/librte_eal/linuxapp/eal/eal_thread.c
index 9f88530..831ba07 100644
--- a/lib/librte_eal/linuxapp/eal/eal_thread.c
+++ b/lib/librte_eal/linuxapp/eal/eal_thread.c
@@ -184,7 +184,14 @@ eal_thread_loop(__attribute__((unused)) void *arg)
 		ret = lcore_config[lcore_id].f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		rte_wmb();
-		lcore_config[lcore_id].state = FINISHED;
+
+		/* when a service core returns, it should go directly to WAIT
+		 * state, because the application will not lcore_wait() for it.
+		 */
+		if (lcore_config[lcore_id].core_role == ROLE_SERVICE)
+			lcore_config[lcore_id].state = WAIT;
+		else
+			lcore_config[lcore_id].state = FINISHED;
 	}
 
 	/* never reached */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index a118fb1..ce5fcf0 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -213,5 +213,27 @@ EXPERIMENTAL {
 
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_stop;
+	rte_service_unregister;
 
 } DPDK_17.08;
-- 
2.7.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v3] doc: release notes 17.08, API change description
  2017-07-06  9:29  4% ` [dpdk-dev] [PATCH v2] " Radu Nicolau
@ 2017-07-07  9:21  4%   ` Radu Nicolau
  2017-07-08 16:23  0%     ` Thomas Monjalon
  2017-07-10  9:15  4%     ` [dpdk-dev] [PATCH v4] " Radu Nicolau
  0 siblings, 2 replies; 200+ results
From: Radu Nicolau @ 2017-07-07  9:21 UTC (permalink / raw)
  To: dev; +Cc: thomas, john.mcnamara, radu.nicolau

Added API change description - moved bypass functions
from the rte_ether library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---

v3: fixed indentation issue

 doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..3b371d3 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,31 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ether library to ixgbe PMD**
+
+  * The following rte_ether library APIs were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+
+  * The following ixgbe PMD APIs were added:
+
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] drivers/net: add support for IF-MIB and EtherLike-MIB for e1000
  @ 2017-07-06 11:48  3%     ` Pattan, Reshma
  0 siblings, 0 replies; 200+ results
From: Pattan, Reshma @ 2017-07-06 11:48 UTC (permalink / raw)
  To: Stephen Hemminger, Yigit, Ferruh, Richardson, Bruce
  Cc: dev, Lu, Wenzhuo, Jastrzebski, MichalX K, Jain, Deepak K,
	Van Haaren, Harry, piotrx.t.azarewicz, Nicolau, Radu

Hi ,

> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Tuesday, June 27, 2017 11:26 PM
> To: Nicolau, Radu <radu.nicolau@intel.com>
> Cc: dev@dpdk.org; Lu, Wenzhuo <wenzhuo.lu@intel.com>; Pattan, Reshma
> <reshma.pattan@intel.com>; Jastrzebski, MichalX K
> <michalx.k.jastrzebski@intel.com>; Jain, Deepak K
> <deepak.k.jain@intel.com>; Van Haaren, Harry
> <harry.van.haaren@intel.com>; piotrx.t.azarewicz@intel.com
> Subject: Re: [dpdk-dev] [PATCH v2] drivers/net: add support for IF-MIB and
> EtherLike-MIB for e1000
> 
> On Mon, 26 Jun 2017 10:42:13 +0100
> Radu Nicolau <radu.nicolau@intel.com> wrote:
> 
> > From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
> >
> > If-MIB xstats:
> > ifNumber
> > ifIndex
> > ifType
> > ifMtu
> > ifSpeed
> > ifPhysAddress
> > ifOperStatus
> > ifLastChange
> > ifHighSpeed
> > ifConnectorPresent
> > ifCounterDiscontinuityTime
> >
> > EtherLike-MIB xstats:
> > dot3PauseOperMode
> > dot3StatsDuplexStatus
> > dot3StatsRateControlAbility
> > dot3StatsRateControlStatus
> > dot3ControlFunctionsSupported
> >
> > -updated in v2: coding style
> >
> > Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
> > Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
> > Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
> 
> Although this maybe the easiest way for Intel, and satisfy a specific user's
> request. It is not a good way forward for the DPDK project.
> 
> This must be generic, not specific to device drivers.
> If implementing a MIB variable  requires more information than ethdev API
> has now, then extend ethdev API first.
> 

Yes, most of the MIB attributes can be fetched from rte_eth_dev_data/rte_eth_dev_info. 
Re expressing my opinion (a) below which I did in other mail: 
(a)For the MIB attributes which do not have any ethdev API support, how about getting all of them from PMDs via a new dev_op like xstats_get?. 
   Then add the new eth_dev API, which does call to this new dev_op and other existing ethdev APIs to gather all mib information and expose that 
   to user based on port_id. 

(Or)

(b)Should we expand rte_eth_dev_info or rte_eth_dev_data to add missing mib attributes, fetch them from PMDs using dev_infos_get() and expose to user.
   Adding new mib attributes to existing  structs might need ABI break announcements.  
   
But both cases (a) and (b) does need some PMD changes.

Please let me know what you think about the  points a and b.

Thanks,
Reshma

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2] doc: release notes 17.08, API change description
  2017-07-06  9:23  4% [dpdk-dev] [PATCH] doc: release notes 17.08, API change description Radu Nicolau
@ 2017-07-06  9:29  4% ` Radu Nicolau
  2017-07-07  9:21  4%   ` [dpdk-dev] [PATCH v3] " Radu Nicolau
  0 siblings, 1 reply; 200+ results
From: Radu Nicolau @ 2017-07-06  9:29 UTC (permalink / raw)
  To: dev; +Cc: thomas, radu.nicolau

Added API change description - moved bypass functions
from the rte_ether library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---

v2: Fixed style errors

 doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..7c891b4 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,31 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ether library to ixgbe PMD**
+
+  * The following rte_ether library APIs were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+
+   * The following ixgbe PMD APIs were added:
+
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] doc: release notes 17.08, API change description
@ 2017-07-06  9:23  4% Radu Nicolau
  2017-07-06  9:29  4% ` [dpdk-dev] [PATCH v2] " Radu Nicolau
  0 siblings, 1 reply; 200+ results
From: Radu Nicolau @ 2017-07-06  9:23 UTC (permalink / raw)
  To: dev; +Cc: thomas, radu.nicolau

Added API change description - moved bypass functions
from the rte_ether library to ixgbe PMD

Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 842f46f..6959720 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -144,6 +144,31 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **Moved bypass functions from the rte_ether library to ixgbe PMD**
+  
+  * The following rte_ether library APIs were removed:
+
+    * ``rte_eth_dev_bypass_event_show``
+    * ``rte_eth_dev_bypass_event_store``
+    * ``rte_eth_dev_bypass_init``
+    * ``rte_eth_dev_bypass_state_set``
+    * ``rte_eth_dev_bypass_state_show``
+    * ``rte_eth_dev_bypass_ver_show``
+    * ``rte_eth_dev_bypass_wd_reset``
+    * ``rte_eth_dev_bypass_wd_timeout_show``
+    * ``rte_eth_dev_wd_timeout_store``
+    
+   * The following ixgbe PMD APIs were added:
+   
+    * ``rte_pmd_ixgbe_bypass_event_show``
+    * ``rte_pmd_ixgbe_bypass_event_store``
+    * ``rte_pmd_ixgbe_bypass_init``
+    * ``rte_pmd_ixgbe_bypass_state_set``
+    * ``rte_pmd_ixgbe_bypass_state_show``
+    * ``rte_pmd_ixgbe_bypass_ver_show``
+    * ``rte_pmd_ixgbe_bypass_wd_reset``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_show``
+    * ``rte_pmd_ixgbe_bypass_wd_timeout_store``
 
 ABI Changes
 -----------
-- 
2.7.5

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] RFC - increasing the size of ethenet device name
  2017-07-05 17:58  3% [dpdk-dev] RFC - increasing the size of ethenet device name Stephen Hemminger
@ 2017-07-05 23:20  0% ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2017-07-05 23:20 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

05/07/2017 19:58, Stephen Hemminger:
> In order to support VMBUS, the ethernet device name needs to be increased.
> What would be good timing; vmbus support will be in 17.11.
> Either break ABI now, and vmbus won't have to do it later.
> Or wait and make it part of of VMBUS patches?

Please send a deprecation notice for 17.08,
and wait 17.11 to change it while introducing VMBUS.

Thanks

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] RFC - increasing the size of ethenet device name
@ 2017-07-05 17:58  3% Stephen Hemminger
  2017-07-05 23:20  0% ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Stephen Hemminger @ 2017-07-05 17:58 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

In order to support VMBUS, the ethernet device name needs to be increased.
What would be good timing; vmbus support will be in 17.11.
Either break ABI now, and vmbus won't have to do it later.
Or wait and make it part of of VMBUS patches?

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v3 2/3] eal: PCI domain should be 32 bits
  @ 2017-07-05 16:55  3% ` Stephen Hemminger
  0 siblings, 0 replies; 200+ results
From: Stephen Hemminger @ 2017-07-05 16:55 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Stephen Hemminger

In some environments, the PCI domain can be larger than 16 bits.
For example, a PCI device passed through in Azure gets a synthetic domain
id  which is internally generated based on GUID. The PCI standard does
not restrict domain to be 16 bits.

This change breaks ABI for API's that expose PCI address structure.

The printf format for PCI remains unchanged, so that on most
systems (with only 16 bit domain) the output format is unchanged
and is 4 characters wide.  For example: 0000:00:01.0 
Only on sysetms with higher bits will the domain take up more
space; example: 12000:00:01.0

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 lib/librte_eal/common/include/rte_pci.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 0284a6208aa5..e416714b32ff 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -63,7 +63,7 @@ const char *pci_get_sysfs_path(void);
 
 /** Formatting string for PCI device identifier: Ex: 0000:00:01.0 */
 #define PCI_PRI_FMT "%.4" PRIx16 ":%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8
-#define PCI_PRI_STR_SIZE sizeof("XXXX:XX:XX.X")
+#define PCI_PRI_STR_SIZE sizeof("XXXXXXXX:XX:XX.X")
 
 /** Short formatting string, without domain, for PCI device: Ex: 00:01.0 */
 #define PCI_SHORT_PRI_FMT "%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8
@@ -112,7 +112,7 @@ struct rte_pci_id {
  * A structure describing the location of a PCI device.
  */
 struct rte_pci_addr {
-	uint16_t domain;                /**< Device domain */
+	uint32_t domain;                /**< Device domain */
 	uint8_t bus;                    /**< Device bus */
 	uint8_t devid;                  /**< Device ID */
 	uint8_t function;               /**< Device function. */
@@ -346,10 +346,10 @@ rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
 	if ((addr == NULL) || (addr2 == NULL))
 		return -1;
 
-	dev_addr = (addr->domain << 24) | (addr->bus << 16) |
-				(addr->devid << 8) | addr->function;
-	dev_addr2 = (addr2->domain << 24) | (addr2->bus << 16) |
-				(addr2->devid << 8) | addr2->function;
+	dev_addr = ((uint64_t)addr->domain << 24) |
+		(addr->bus << 16) | (addr->devid << 8) | addr->function;
+	dev_addr2 = ((uint64_t)addr2->domain << 24) |
+		(addr2->bus << 16) | (addr2->devid << 8) | addr2->function;
 
 	if (dev_addr > dev_addr2)
 		return 1;
-- 
2.11.0

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v4 10/12] cryptodev: add mempool pointer in queue pair setup
                         ` (5 preceding siblings ...)
  2017-07-05  5:26  1%     ` [dpdk-dev] [PATCH v4 09/12] cryptodev: support device independent sessions Pablo de Lara
@ 2017-07-05  5:26  2%     ` Pablo de Lara
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

The session mempool pointer is needed in each queue pair,
if session-less operations are being handled.
Therefore, the API is changed to accept this parameter,
as the session mempool is created outside the
device configuration function, similar to what ethdev
does with the rx queues.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/main.c                    | 18 ++++----
 doc/guides/rel_notes/release_17_08.rst         |  1 +
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c   |  4 +-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c |  4 +-
 drivers/crypto/armv8/rte_armv8_pmd_ops.c       |  4 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c    |  3 +-
 drivers/crypto/kasumi/rte_kasumi_pmd_ops.c     |  4 +-
 drivers/crypto/null/null_crypto_pmd_ops.c      |  4 +-
 drivers/crypto/openssl/rte_openssl_pmd_ops.c   |  4 +-
 drivers/crypto/qat/qat_crypto.h                |  3 +-
 drivers/crypto/qat/qat_qp.c                    |  2 +-
 drivers/crypto/scheduler/scheduler_pmd_ops.c   | 13 ++++--
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c     |  4 +-
 drivers/crypto/zuc/rte_zuc_pmd_ops.c           |  4 +-
 examples/ipsec-secgw/ipsec-secgw.c             |  6 +--
 examples/l2fwd-crypto/main.c                   |  5 +--
 lib/librte_cryptodev/rte_cryptodev.c           | 11 +++--
 lib/librte_cryptodev/rte_cryptodev.h           |  9 ++--
 lib/librte_cryptodev/rte_cryptodev_pmd.h       |  3 +-
 test/test/test_cryptodev.c                     | 58 +++++++++++++++-----------
 test/test/test_cryptodev_perf.c                |  5 ++-
 21 files changed, 93 insertions(+), 76 deletions(-)

diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 90edb24..d300704 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -155,20 +155,20 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
 			session_pool_socket[socket_id] = sess_mp;
 		}
 
-		ret = rte_cryptodev_configure(cdev_id, &conf,
-				session_pool_socket[socket_id]);
+		ret = rte_cryptodev_configure(cdev_id, &conf);
 		if (ret < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -EINVAL;
 		}
 
-		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				socket_id);
-		if (ret < 0) {
-			printf("Failed to setup queue pair %u on "
-				"cryptodev %u",	0, cdev_id);
-			return -EINVAL;
-		}
+		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0,
+				&qp_conf, socket_id,
+				session_pool_socket[socket_id]);
+			if (ret < 0) {
+				printf("Failed to setup queue pair %u on "
+					"cryptodev %u",	0, cdev_id);
+				return -EINVAL;
+			}
 
 		ret = rte_cryptodev_start(cdev_id);
 		if (ret < 0) {
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 4fae766..638b582 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -220,6 +220,7 @@ API Changes
   * Modified parameters of ``rte_cryptodev_sym_session_create()``, to accept
     ``mempool``, instead of ``device id`` and ``rte_crypto_sym_xform``.
   * Remove ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
+  * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
index 21052cd..6d24a32 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
@@ -230,7 +230,7 @@ aesni_gcm_pmd_qp_create_processed_pkts_ring(struct aesni_gcm_qp *qp,
 static int
 aesni_gcm_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct aesni_gcm_qp *qp = NULL;
 	struct aesni_gcm_private *internals = dev->data->dev_private;
@@ -258,7 +258,7 @@ aesni_gcm_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_pkts == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
index ae74ae3..e3a6ef5 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -404,7 +404,7 @@ aesni_mb_pmd_qp_create_processed_ops_ring(struct aesni_mb_qp *qp,
 static int
 aesni_mb_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct aesni_mb_qp *qp = NULL;
 	struct aesni_mb_private *internals = dev->data->dev_private;
@@ -433,7 +433,7 @@ aesni_mb_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->ingress_queue == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
index e14b68c..3aa4888 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
@@ -249,7 +249,7 @@ armv8_crypto_pmd_qp_create_processed_ops_ring(struct armv8_crypto_qp *qp,
 static int
 armv8_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct armv8_crypto_qp *qp = NULL;
 
@@ -274,7 +274,7 @@ armv8_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index b764f33..e5bfcf2 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -816,7 +816,8 @@ dpaa2_sec_queue_pair_release(struct rte_cryptodev *dev, uint16_t queue_pair_id)
 static int
 dpaa2_sec_queue_pair_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		__rte_unused const struct rte_cryptodev_qp_conf *qp_conf,
-		__rte_unused int socket_id)
+		__rte_unused int socket_id,
+		__rte_unused struct rte_mempool *session_pool)
 {
 	struct dpaa2_sec_dev_private *priv = dev->data->dev_private;
 	struct dpaa2_sec_qp *qp;
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
index e7bbc29..1d9c0fc 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
@@ -224,7 +224,7 @@ kasumi_pmd_qp_create_processed_ops_ring(struct kasumi_qp *qp,
 static int
 kasumi_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct kasumi_qp *qp = NULL;
 
@@ -249,7 +249,7 @@ kasumi_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/null/null_crypto_pmd_ops.c b/drivers/crypto/null/null_crypto_pmd_ops.c
index d57644d..c618e6b 100644
--- a/drivers/crypto/null/null_crypto_pmd_ops.c
+++ b/drivers/crypto/null/null_crypto_pmd_ops.c
@@ -212,7 +212,7 @@ null_crypto_pmd_qp_create_processed_pkts_ring(struct null_crypto_qp *qp,
 static int
 null_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct null_crypto_private *internals = dev->data->dev_private;
 	struct null_crypto_qp *qp;
@@ -255,7 +255,7 @@ null_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		goto qp_setup_cleanup;
 	}
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 1f8a011..1db4d14 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -599,7 +599,7 @@ openssl_pmd_qp_create_processed_ops_ring(struct openssl_qp *qp,
 static int
 openssl_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct openssl_qp *qp = NULL;
 
@@ -624,7 +624,7 @@ openssl_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/qat/qat_crypto.h b/drivers/crypto/qat/qat_crypto.h
index d9d8887..915f960 100644
--- a/drivers/crypto/qat/qat_crypto.h
+++ b/drivers/crypto/qat/qat_crypto.h
@@ -103,7 +103,8 @@ void qat_crypto_sym_stats_get(struct rte_cryptodev *dev,
 void qat_crypto_sym_stats_reset(struct rte_cryptodev *dev);
 
 int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
-	const struct rte_cryptodev_qp_conf *rx_conf, int socket_id);
+	const struct rte_cryptodev_qp_conf *rx_conf, int socket_id,
+	struct rte_mempool *session_pool);
 int qat_crypto_sym_qp_release(struct rte_cryptodev *dev,
 	uint16_t queue_pair_id);
 
diff --git a/drivers/crypto/qat/qat_qp.c b/drivers/crypto/qat/qat_qp.c
index 3921c2e..2b2ab42 100644
--- a/drivers/crypto/qat/qat_qp.c
+++ b/drivers/crypto/qat/qat_qp.c
@@ -134,7 +134,7 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size,
 
 int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
 	const struct rte_cryptodev_qp_conf *qp_conf,
-	int socket_id)
+	int socket_id, struct rte_mempool *session_pool __rte_unused)
 {
 	struct qat_qp *qp;
 	struct rte_pci_device *pci_dev;
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index c450f6a..e7f796c 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -101,8 +101,7 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
 		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
 
-		ret = rte_cryptodev_configure(slave_dev_id, config,
-				dev->data->session_pool);
+		ret = rte_cryptodev_configure(slave_dev_id, config);
 		if (ret < 0)
 			break;
 	}
@@ -400,7 +399,8 @@ scheduler_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
 /** Setup a queue pair */
 static int
 scheduler_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
-	const struct rte_cryptodev_qp_conf *qp_conf, int socket_id)
+	const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+	struct rte_mempool *session_pool)
 {
 	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
 	struct scheduler_qp_ctx *qp_ctx;
@@ -422,8 +422,13 @@ scheduler_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
 		uint8_t slave_id = sched_ctx->slaves[i].dev_id;
 
+		/*
+		 * All slaves will share the same session mempool
+		 * for session-less operations, so the objects
+		 * must be big enough for all the drivers used.
+		 */
 		ret = rte_cryptodev_queue_pair_setup(slave_id, qp_id,
-				qp_conf, socket_id);
+				qp_conf, socket_id, session_pool);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
index 3accba5..108f251 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -221,7 +221,7 @@ snow3g_pmd_qp_create_processed_ops_ring(struct snow3g_qp *qp,
 static int
 snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct snow3g_qp *qp = NULL;
 
@@ -246,7 +246,7 @@ snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/zuc/rte_zuc_pmd_ops.c b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
index adef343..7cb3f1c 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd_ops.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
@@ -221,7 +221,7 @@ zuc_pmd_qp_create_processed_ops_ring(struct zuc_qp *qp,
 static int
 zuc_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct zuc_qp *qp = NULL;
 
@@ -246,7 +246,7 @@ zuc_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 708eadd..11f0966 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1299,15 +1299,15 @@ cryptodevs_init(void)
 			socket_ctx[dev_conf.socket_id].session_pool = sess_mp;
 		}
 
-		if (rte_cryptodev_configure(cdev_id, &dev_conf,
-				socket_ctx[dev_conf.socket_id].session_pool))
+		if (rte_cryptodev_configure(cdev_id, &dev_conf))
 			rte_panic("Failed to initialize cryptodev %u\n",
 					cdev_id);
 
 		qp_conf.nb_descriptors = CDEV_QUEUE_DESC;
 		for (qp = 0; qp < dev_conf.nb_queue_pairs; qp++)
 			if (rte_cryptodev_queue_pair_setup(cdev_id, qp,
-						&qp_conf, dev_conf.socket_id))
+					&qp_conf, dev_conf.socket_id,
+					socket_ctx[dev_conf.socket_id].session_pool))
 				rte_panic("Failed to setup queue %u for "
 						"cdev_id %u\n",	0, cdev_id);
 
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index cba29ce..2a71feb 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -2232,8 +2232,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 						cap->sym.auth.digest_size.min;
 		}
 
-		retval = rte_cryptodev_configure(cdev_id, &conf,
-				session_pool_socket[socket_id]);
+		retval = rte_cryptodev_configure(cdev_id, &conf);
 		if (retval < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -1;
@@ -2242,7 +2241,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		qp_conf.nb_descriptors = 2048;
 
 		retval = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				socket_id);
+				socket_id, session_pool_socket[socket_id]);
 		if (retval < 0) {
 			printf("Failed to setup queue pair %u on cryptodev %u",
 					0, cdev_id);
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 373c05b..8ee5d47 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -747,8 +747,7 @@ rte_cryptodev_queue_pair_stop(uint8_t dev_id, uint16_t queue_pair_id)
 }
 
 int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
-		struct rte_mempool *session_pool)
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 {
 	struct rte_cryptodev *dev;
 	int diag;
@@ -768,8 +767,6 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
 
-	dev->data->session_pool = session_pool;
-
 	/* Setup new number of queue pairs and reconfigure device. */
 	diag = rte_cryptodev_queue_pairs_config(dev, config->nb_queue_pairs,
 			config->socket_id);
@@ -881,7 +878,9 @@ rte_cryptodev_close(uint8_t dev_id)
 
 int
 rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
-		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id)
+		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+		struct rte_mempool *session_pool)
+
 {
 	struct rte_cryptodev *dev;
 
@@ -905,7 +904,7 @@ rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_pair_setup, -ENOTSUP);
 
 	return (*dev->dev_ops->queue_pair_setup)(dev, queue_pair_id, qp_conf,
-			socket_id);
+			socket_id, session_pool);
 }
 
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 3ba3efb..ca7cbdd 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -525,15 +525,13 @@ struct rte_cryptodev_config {
  *
  * @param	dev_id		The identifier of the device to configure.
  * @param	config		The crypto device configuration structure.
- * @param	session_pool	Pointer to device session mempool
  *
  * @return
  *   - 0: Success, device configured.
  *   - <0: Error code returned by the driver configuration function.
  */
 extern int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
-		struct rte_mempool *session_pool);
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config);
 
 /**
  * Start an device.
@@ -592,6 +590,8 @@ rte_cryptodev_close(uint8_t dev_id);
  *				*SOCKET_ID_ANY* if there is no NUMA constraint
  *				for the DMA memory allocated for the receive
  *				queue pair.
+ * @param	session_pool	Pointer to device session mempool, used
+ *				for session-less operations.
  *
  * @return
  *   - 0: Success, queue pair correctly set up.
@@ -599,7 +599,8 @@ rte_cryptodev_close(uint8_t dev_id);
  */
 extern int
 rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
-		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id);
+		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+		struct rte_mempool *session_pool);
 
 /**
  * Start a specified queue pair of a device. It is used
diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
index 2896171..82ad1f7 100644
--- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
+++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
@@ -207,12 +207,13 @@ typedef int (*cryptodev_queue_pair_stop_t)(struct rte_cryptodev *dev,
  * @param	qp_id		Queue Pair Index
  * @param	qp_conf		Queue configuration structure
  * @param	socket_id	Socket Index
+ * @param	session_pool	Pointer to device session mempool
  *
  * @return	Returns 0 on success.
  */
 typedef int (*cryptodev_queue_pair_setup_t)(struct rte_cryptodev *dev,
 		uint16_t qp_id,	const struct rte_cryptodev_qp_conf *qp_conf,
-		int socket_id);
+		int socket_id, struct rte_mempool *session_pool);
 
 /**
  * Release memory resources allocated by given queue pair.
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 745f261..b068609 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -404,7 +404,7 @@ testsuite_setup(void)
 			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id,
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u with %u qps",
 			dev_id, ts_params->conf.nb_queue_pairs);
 
@@ -413,7 +413,8 @@ testsuite_setup(void)
 	for (qp_id = 0; qp_id < info.max_nb_queue_pairs; qp_id++) {
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			dev_id, qp_id, &ts_params->qp_conf,
-			rte_cryptodev_socket_id(dev_id)),
+			rte_cryptodev_socket_id(dev_id),
+			ts_params->session_mpool),
 			"Failed to setup queue pair %u on cryptodev %u",
 			qp_id, dev_id);
 	}
@@ -458,7 +459,7 @@ ut_setup(void)
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -466,7 +467,8 @@ ut_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0], qp_id,
 			&ts_params->qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed to setup queue pair %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
 	}
@@ -542,23 +544,20 @@ test_device_configure_invalid_dev_id(void)
 	/* Stop the device in case it's started so it can be configured */
 	rte_cryptodev_stop(ts_params->valid_devs[dev_id]);
 
-	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	/* invalid dev_id values */
 	dev_id = num_devs;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	dev_id = 0xff;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure:"
 			"invalid dev_num %u", dev_id);
 
@@ -578,7 +577,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 1;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
 
@@ -587,7 +586,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0],
 			ts_params->conf.nb_queue_pairs);
@@ -597,7 +596,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 0;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -608,7 +607,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = UINT16_MAX;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -619,7 +618,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE + 1;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -649,7 +648,7 @@ test_queue_pair_descriptor_setup(void)
 	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -663,7 +662,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for "
 				"rte_cryptodev_queue_pair_setup: num_inflights "
 				"%u on qp %u on cryptodev %u",
@@ -677,7 +677,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for"
 				" rte_cryptodev_queue_pair_setup: num_inflights"
 				" %u on qp %u on cryptodev %u",
@@ -691,7 +692,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for "
 				"rte_cryptodev_queue_pair_setup: num_inflights"
 				" %u on qp %u on cryptodev %u",
@@ -706,7 +708,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -721,7 +724,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -735,7 +739,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for"
 				" rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -750,7 +755,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -766,7 +772,8 @@ test_queue_pair_descriptor_setup(void)
 	TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0],
 			qp_id, &qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed test for rte_cryptodev_queue_pair_setup:"
 			"invalid qp %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
@@ -776,7 +783,8 @@ test_queue_pair_descriptor_setup(void)
 	TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0],
 			qp_id, &qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed test for rte_cryptodev_queue_pair_setup:"
 			"invalid qp %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index e21f5e7..8cddaa7 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -423,7 +423,7 @@ testsuite_setup(void)
 			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->dev_id,
-			&ts_params->conf, ts_params->sess_mp),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->dev_id);
 
@@ -433,7 +433,8 @@ testsuite_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			ts_params->dev_id, qp_id,
 				&ts_params->qp_conf,
-				rte_cryptodev_socket_id(ts_params->dev_id)),
+				rte_cryptodev_socket_id(ts_params->dev_id),
+				ts_params->sess_mp),
 				"Failed to setup queue pair %u on cryptodev %u",
 				qp_id, ts_params->dev_id);
 	}
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

* [dpdk-dev] [PATCH v4 09/12] cryptodev: support device independent sessions
                         ` (4 preceding siblings ...)
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 08/12] cryptodev: remove mempool " Pablo de Lara
@ 2017-07-05  5:26  1%     ` Pablo de Lara
  2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 10/12] cryptodev: add mempool pointer in queue pair setup Pablo de Lara
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Change crypto device's session management to make it
device independent and simplify architecture when session
is intended to be used on more than one device.

Sessions private data is agnostic to underlying device
by adding an indirection in the sessions private data
using the crypto driver identifier.
A single session can contain indirections to multiple device types.

New function rte_cryptodev_sym_session_init has been created,
to initialize the private data per driver to be used on
a same session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/cperf.h                       |   5 +-
 app/test-crypto-perf/cperf_ops.c                   |  21 +-
 app/test-crypto-perf/cperf_ops.h                   |   1 +
 app/test-crypto-perf/cperf_test_latency.c          |  12 +-
 app/test-crypto-perf/cperf_test_latency.h          |   5 +-
 app/test-crypto-perf/cperf_test_throughput.c       |  12 +-
 app/test-crypto-perf/cperf_test_throughput.h       |   5 +-
 app/test-crypto-perf/cperf_test_verify.c           |  12 +-
 app/test-crypto-perf/cperf_test_verify.h           |   5 +-
 app/test-crypto-perf/main.c                        |   8 +-
 doc/guides/rel_notes/release_17_08.rst             |   9 +
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c           |  47 ++-
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c       |  45 ++-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c         |  40 ++-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c     |  46 ++-
 drivers/crypto/armv8/rte_armv8_pmd.c               |  35 ++-
 drivers/crypto/armv8/rte_armv8_pmd_ops.c           |  45 ++-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c        |  55 +++-
 drivers/crypto/kasumi/rte_kasumi_pmd.c             |  40 ++-
 drivers/crypto/kasumi/rte_kasumi_pmd_ops.c         |  47 ++-
 drivers/crypto/null/null_crypto_pmd.c              |  41 ++-
 drivers/crypto/null/null_crypto_pmd_ops.c          |  47 ++-
 drivers/crypto/openssl/rte_openssl_pmd.c           |  37 ++-
 drivers/crypto/openssl/rte_openssl_pmd_ops.c       |  48 ++-
 drivers/crypto/qat/qat_crypto.c                    |  95 ++++--
 drivers/crypto/qat/qat_crypto.h                    |  16 +-
 drivers/crypto/qat/rte_qat_cryptodev.c             |   1 -
 drivers/crypto/scheduler/scheduler_failover.c      |  45 +--
 .../crypto/scheduler/scheduler_pkt_size_distr.c    |  18 --
 drivers/crypto/scheduler/scheduler_pmd_ops.c       |  81 ++---
 drivers/crypto/scheduler/scheduler_pmd_private.h   |   4 -
 drivers/crypto/scheduler/scheduler_roundrobin.c    |  41 ---
 drivers/crypto/snow3g/rte_snow3g_pmd.c             |  41 ++-
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c         |  47 ++-
 drivers/crypto/zuc/rte_zuc_pmd.c                   |  37 ++-
 drivers/crypto/zuc/rte_zuc_pmd_ops.c               |  47 ++-
 examples/ipsec-secgw/ipsec-secgw.c                 |   3 +-
 examples/ipsec-secgw/ipsec.c                       |   7 +-
 examples/l2fwd-crypto/main.c                       |  17 +-
 lib/librte_cryptodev/rte_cryptodev.c               | 140 ++++++---
 lib/librte_cryptodev/rte_cryptodev.h               |  82 +++--
 lib/librte_cryptodev/rte_cryptodev_pmd.h           |  32 +-
 lib/librte_cryptodev/rte_cryptodev_version.map     |   3 +
 test/test/test_cryptodev.c                         | 347 +++++++++++++++------
 test/test/test_cryptodev_blockcipher.c             |  18 +-
 test/test/test_cryptodev_blockcipher.h             |   1 +
 test/test/test_cryptodev_perf.c                    | 191 ++++++++----
 47 files changed, 1315 insertions(+), 667 deletions(-)

diff --git a/app/test-crypto-perf/cperf.h b/app/test-crypto-perf/cperf.h
index 293ba94..c9f7f81 100644
--- a/app/test-crypto-perf/cperf.h
+++ b/app/test-crypto-perf/cperf.h
@@ -41,7 +41,10 @@ struct cperf_options;
 struct cperf_test_vector;
 struct cperf_op_fns;
 
-typedef void  *(*cperf_constructor_t)(uint8_t dev_id, uint16_t qp_id,
+typedef void  *(*cperf_constructor_t)(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *t_vec,
 		const struct cperf_op_fns *op_fns);
diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index d718278..a5bf09b 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -367,7 +367,8 @@ cperf_set_ops_aead(struct rte_crypto_op **ops,
 }
 
 static struct rte_cryptodev_sym_session *
-cperf_create_session(uint8_t dev_id,
+cperf_create_session(struct rte_mempool *sess_mp,
+	uint8_t dev_id,
 	const struct cperf_options *options,
 	const struct cperf_test_vector *test_vector,
 	uint16_t iv_offset)
@@ -377,6 +378,7 @@ cperf_create_session(uint8_t dev_id,
 	struct rte_crypto_sym_xform aead_xform;
 	struct rte_cryptodev_sym_session *sess = NULL;
 
+	sess = rte_cryptodev_sym_session_create(sess_mp);
 	/*
 	 * cipher only
 	 */
@@ -401,7 +403,8 @@ cperf_create_session(uint8_t dev_id,
 			cipher_xform.cipher.iv.length = 0;
 		}
 		/* create crypto session */
-		sess = rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		rte_cryptodev_sym_session_init(dev_id, sess, &cipher_xform,
+				sess_mp);
 	/*
 	 *  auth only
 	 */
@@ -427,7 +430,8 @@ cperf_create_session(uint8_t dev_id,
 			auth_xform.auth.iv.length = 0;
 		}
 		/* create crypto session */
-		sess =  rte_cryptodev_sym_session_create(dev_id, &auth_xform);
+		rte_cryptodev_sym_session_init(dev_id, sess, &auth_xform,
+				sess_mp);
 	/*
 	 * cipher and auth
 	 */
@@ -483,13 +487,13 @@ cperf_create_session(uint8_t dev_id,
 		if (options->op_type == CPERF_CIPHER_THEN_AUTH) {
 			cipher_xform.next = &auth_xform;
 			/* create crypto session */
-			sess = rte_cryptodev_sym_session_create(dev_id,
-						&cipher_xform);
+			rte_cryptodev_sym_session_init(dev_id,
+					sess, &cipher_xform, sess_mp);
 		} else { /* auth then cipher */
 			auth_xform.next = &cipher_xform;
 			/* create crypto session */
-			sess = rte_cryptodev_sym_session_create(dev_id,
-					&auth_xform);
+			rte_cryptodev_sym_session_init(dev_id,
+					sess, &auth_xform, sess_mp);
 		}
 	} else { /* options->op_type == CPERF_AEAD */
 		aead_xform.type = RTE_CRYPTO_SYM_XFORM_AEAD;
@@ -509,7 +513,8 @@ cperf_create_session(uint8_t dev_id,
 					options->aead_aad_sz;
 
 		/* Create crypto session */
-		sess = rte_cryptodev_sym_session_create(dev_id, &aead_xform);
+		rte_cryptodev_sym_session_init(dev_id,
+					sess, &aead_xform, sess_mp);
 	}
 
 	return sess;
diff --git a/app/test-crypto-perf/cperf_ops.h b/app/test-crypto-perf/cperf_ops.h
index bb83cd5..1f8fa93 100644
--- a/app/test-crypto-perf/cperf_ops.h
+++ b/app/test-crypto-perf/cperf_ops.h
@@ -41,6 +41,7 @@
 
 
 typedef struct rte_cryptodev_sym_session *(*cperf_sessions_create_t)(
+		struct rte_mempool *sess_mp,
 		uint8_t dev_id, const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		uint16_t iv_offset);
diff --git a/app/test-crypto-perf/cperf_test_latency.c b/app/test-crypto-perf/cperf_test_latency.c
index 8841d39..1a42602 100644
--- a/app/test-crypto-perf/cperf_test_latency.c
+++ b/app/test-crypto-perf/cperf_test_latency.c
@@ -79,8 +79,10 @@ cperf_latency_test_free(struct cperf_latency_ctx *ctx, uint32_t mbuf_nb)
 	uint32_t i;
 
 	if (ctx) {
-		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+		if (ctx->sess) {
+			rte_cryptodev_sym_session_clear(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
+		}
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -191,7 +193,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_latency_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -216,7 +219,8 @@ cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
 		sizeof(struct rte_crypto_sym_op) +
 		sizeof(struct cperf_op_result *);
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector, iv_offset);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector,
+			iv_offset);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_latency.h b/app/test-crypto-perf/cperf_test_latency.h
index 6a2cf61..1bbedb4 100644
--- a/app/test-crypto-perf/cperf_test_latency.h
+++ b/app/test-crypto-perf/cperf_test_latency.h
@@ -43,7 +43,10 @@
 #include "cperf_test_vectors.h"
 
 void *
-cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_latency_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/cperf_test_throughput.c b/app/test-crypto-perf/cperf_test_throughput.c
index 87fac0f..3025044 100644
--- a/app/test-crypto-perf/cperf_test_throughput.c
+++ b/app/test-crypto-perf/cperf_test_throughput.c
@@ -64,8 +64,10 @@ cperf_throughput_test_free(struct cperf_throughput_ctx *ctx, uint32_t mbuf_nb)
 	uint32_t i;
 
 	if (ctx) {
-		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+		if (ctx->sess) {
+			rte_cryptodev_sym_session_clear(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
+		}
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -175,7 +177,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_throughput_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -199,7 +202,8 @@ cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
 	uint16_t iv_offset = sizeof(struct rte_crypto_op) +
 		sizeof(struct rte_crypto_sym_op);
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector, iv_offset);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector,
+					iv_offset);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_throughput.h b/app/test-crypto-perf/cperf_test_throughput.h
index f1b5766..987d0c3 100644
--- a/app/test-crypto-perf/cperf_test_throughput.h
+++ b/app/test-crypto-perf/cperf_test_throughput.h
@@ -44,7 +44,10 @@
 
 
 void *
-cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_throughput_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/cperf_test_verify.c b/app/test-crypto-perf/cperf_test_verify.c
index 3ee0560..9c37954 100644
--- a/app/test-crypto-perf/cperf_test_verify.c
+++ b/app/test-crypto-perf/cperf_test_verify.c
@@ -68,8 +68,10 @@ cperf_verify_test_free(struct cperf_verify_ctx *ctx, uint32_t mbuf_nb)
 	uint32_t i;
 
 	if (ctx) {
-		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+		if (ctx->sess) {
+			rte_cryptodev_sym_session_clear(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
+		}
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -179,7 +181,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_verify_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -203,7 +206,8 @@ cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
 	uint16_t iv_offset = sizeof(struct rte_crypto_op) +
 		sizeof(struct rte_crypto_sym_op);
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector, iv_offset);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector,
+			iv_offset);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_verify.h b/app/test-crypto-perf/cperf_test_verify.h
index 3fa78ee..e67b48d 100644
--- a/app/test-crypto-perf/cperf_test_verify.h
+++ b/app/test-crypto-perf/cperf_test_verify.h
@@ -44,7 +44,10 @@
 
 
 void *
-cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_verify_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 45524ad..90edb24 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -109,8 +109,7 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
 	for (i = 0; i < enabled_cdev_count &&
 			i < RTE_CRYPTO_MAX_DEVS; i++) {
 		uint8_t cdev_id = enabled_cdevs[i];
-		sess_size = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_size = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_size > max_sess_size)
 			max_sess_size = sess_size;
 	}
@@ -477,7 +476,10 @@ main(int argc, char **argv)
 
 		cdev_id = enabled_cdevs[i];
 
-		ctx[cdev_id] = cperf_testmap[opts.test].constructor(cdev_id, 0,
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
+
+		ctx[cdev_id] = cperf_testmap[opts.test].constructor(
+				session_pool_socket[socket_id], cdev_id, 0,
 				&opts, t_vec, &op_fns);
 		if (ctx[cdev_id] == NULL) {
 			RTE_LOG(ERR, USER1, "Test run constructor failed\n");
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 74275e0..4fae766 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -81,6 +81,10 @@ New Features
     necessary to use a combination of cipher and authentication
     structures anymore.
   * Added helper functions for crypto device driver identification.
+  * Added support for multi-device sessions, so a single session can be
+    used in multiple drivers.
+  * Added functions to initialize and free individual driver private data
+    with a same session.
 
 * **Updated dpaa2_sec crypto PMD.**
 
@@ -211,6 +215,11 @@ API Changes
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * Mempool pointer ``mp`` has been removed from ``rte_cryptodev_sym_session`` structure.
+  * Replaced ``private`` marker with array of pointers to private data sessions
+    ``sess_private_data`` in ``rte_cryptodev_sym_session``
+  * Modified parameters of ``rte_cryptodev_sym_session_create()``, to accept
+    ``mempool``, instead of ``device id`` and ``rte_crypto_sym_xform``.
+  * Remove ``device id`` parameter from ``rte_cryptodev_sym_session_free()``.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index d226c23..91c3801 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -155,22 +155,37 @@ aesni_gcm_get_session(struct aesni_gcm_qp *qp, struct rte_crypto_op *op)
 	struct rte_crypto_sym_op *sym_op = op->sym;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		sess = (struct aesni_gcm_session *)sym_op->session->_private;
+		if (likely(sym_op->session != NULL))
+			sess = (struct aesni_gcm_session *)
+					get_session_private_data(
+					sym_op->session,
+					cryptodev_driver_id);
 	} else  {
 		void *_sess;
+		void *_sess_private_data = NULL;
 
-		if (rte_mempool_get(qp->sess_mp, &_sess))
-			return sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		sess = (struct aesni_gcm_session *)
-			((struct rte_cryptodev_sym_session *)_sess)->_private;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
 
-		if (unlikely(aesni_gcm_set_session_parameters(qp->ops, sess,
-				sym_op->xform) != 0)) {
+		sess = (struct aesni_gcm_session *)_sess_private_data;
+
+		if (unlikely(aesni_gcm_set_session_parameters(qp->ops,
+				sess, sym_op->xform) != 0)) {
 			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
 			sess = NULL;
 		}
+		sym_op->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(sym_op->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
+
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -370,13 +385,11 @@ process_gcm_crypto_op(struct aesni_gcm_qp *qp, struct rte_crypto_op *op,
  * - Returns NULL on invalid job
  */
 static void
-post_process_gcm_crypto_op(struct rte_crypto_op *op)
+post_process_gcm_crypto_op(struct rte_crypto_op *op,
+		struct aesni_gcm_session *session)
 {
 	struct rte_mbuf *m = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
 
-	struct aesni_gcm_session *session =
-		(struct aesni_gcm_session *)op->sym->session->_private;
-
 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
 	/* Verify digest if required */
@@ -411,6 +424,7 @@ post_process_gcm_crypto_op(struct rte_crypto_op *op)
  * Process a completed GCM request
  *
  * @param qp		Queue Pair to process
+ * @param op		Crypto operation
  * @param job		JOB_AES_HMAC job
  *
  * @return
@@ -418,12 +432,17 @@ post_process_gcm_crypto_op(struct rte_crypto_op *op)
  */
 static void
 handle_completed_gcm_crypto_op(struct aesni_gcm_qp *qp,
-		struct rte_crypto_op *op)
+		struct rte_crypto_op *op,
+		struct aesni_gcm_session *sess)
 {
-	post_process_gcm_crypto_op(op);
+	post_process_gcm_crypto_op(op, sess);
 
 	/* Free session if a session-less crypto op */
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+		memset(sess, 0, sizeof(struct aesni_gcm_session));
+		memset(op->sym->session, 0,
+				rte_cryptodev_get_header_session_size());
+		rte_mempool_put(qp->sess_mp, sess);
 		rte_mempool_put(qp->sess_mp, op->sym->session);
 		op->sym->session = NULL;
 	}
@@ -458,7 +477,7 @@ aesni_gcm_pmd_dequeue_burst(void *queue_pair,
 			break;
 		}
 
-		handle_completed_gcm_crypto_op(qp, ops[i]);
+		handle_completed_gcm_crypto_op(qp, ops[i], sess);
 	}
 
 	qp->qp_stats.dequeued_count += i;
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
index 85c7485..21052cd 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -302,32 +302,55 @@ aesni_gcm_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a aesni gcm session from a crypto xform chain */
-static void *
-aesni_gcm_pmd_session_configure(struct rte_cryptodev *dev,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+static int
+aesni_gcm_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
 	struct aesni_gcm_private *internals = dev->data->dev_private;
 
 	if (unlikely(sess == NULL)) {
 		GCM_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
 	}
 
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
+	}
 	if (aesni_gcm_set_session_parameters(gcm_ops[internals->vector_mode],
-			sess, xform) != 0) {
+				sess_private_data, xform) != 0) {
 		GCM_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-aesni_gcm_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+aesni_gcm_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	if (sess)
-		memset(sess, 0, sizeof(struct aesni_gcm_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct aesni_gcm_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops aesni_gcm_pmd_ops = {
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 699779a..3aaa070 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -354,25 +354,38 @@ get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *op)
 {
 	struct aesni_mb_session *sess = NULL;
 
-	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION)
-		sess = (struct aesni_mb_session *)op->sym->session->_private;
-	else  {
+	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
+		if (likely(op->sym->session != NULL))
+			sess = (struct aesni_mb_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
 		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
 			return NULL;
 
-		sess = (struct aesni_mb_session *)
-			((struct rte_cryptodev_sym_session *)_sess)->_private;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct aesni_mb_session *)_sess_private_data;
 
 		if (unlikely(aesni_mb_set_session_parameters(qp->op_fns,
 				sess, op->sym->xform) != 0)) {
 			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
 			sess = NULL;
 		}
 		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -512,19 +525,21 @@ verify_digest(JOB_AES_HMAC *job, struct rte_crypto_op *op) {
 /**
  * Process a completed job and return rte_mbuf which job processed
  *
+ * @param qp		Queue Pair to process
  * @param job	JOB_AES_HMAC job to process
  *
  * @return
- * - Returns processed mbuf which is trimmed of output digest used in
- * verification of supplied digest in the case of a HASH_CIPHER operation
+ * - Returns processed crypto operation which mbuf is trimmed of output digest
+ *   used in verification of supplied digest.
  * - Returns NULL on invalid job
  */
 static inline struct rte_crypto_op *
 post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 {
 	struct rte_crypto_op *op = (struct rte_crypto_op *)job->user_data;
-
-	struct aesni_mb_session *sess;
+	struct aesni_mb_session *sess = get_session_private_data(
+							op->sym->session,
+							cryptodev_driver_id);
 
 	if (unlikely(op->status == RTE_CRYPTO_OP_STATUS_ENQUEUED)) {
 		switch (job->status) {
@@ -532,9 +547,6 @@ post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 			op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
 			if (job->hash_alg != NULL_HASH) {
-				sess = (struct aesni_mb_session *)
-						op->sym->session->_private;
-
 				if (sess->auth.operation ==
 						RTE_CRYPTO_AUTH_OP_VERIFY)
 					verify_digest(job, op);
@@ -547,6 +559,10 @@ post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 
 	/* Free session if a session-less crypto op */
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+		memset(sess, 0, sizeof(struct aesni_mb_session));
+		memset(op->sym->session, 0,
+				rte_cryptodev_get_header_session_size());
+		rte_mempool_put(qp->sess_mp, sess);
 		rte_mempool_put(qp->sess_mp, op->sym->session);
 		op->sym->session = NULL;
 	}
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
index b5abb6c..ae74ae3 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -479,36 +479,56 @@ aesni_mb_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a aesni multi-buffer session from a crypto xform chain */
-static void *
+static int
 aesni_mb_pmd_session_configure(struct rte_cryptodev *dev,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
 	struct aesni_mb_private *internals = dev->data->dev_private;
 
 	if (unlikely(sess == NULL)) {
 		MB_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
 	if (aesni_mb_set_session_parameters(&job_ops[internals->vector_mode],
-			sess, xform) != 0) {
+			sess_private_data, xform) != 0) {
 		MB_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-aesni_mb_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+aesni_mb_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	/*
-	 * Current just resetting the whole data structure, need to investigate
-	 * whether a more selective reset of key would be more performant
-	 */
-	if (sess)
-		memset(sess, 0, sizeof(struct aesni_mb_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct aesni_mb_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops aesni_mb_pmd_ops = {
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index 590803a..eeeaab7 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -557,24 +557,32 @@ get_session(struct armv8_crypto_qp *qp, struct rte_crypto_op *op)
 		/* get existing session */
 		if (likely(op->sym->session != NULL)) {
 			sess = (struct armv8_crypto_session *)
-				op->sym->session->_private;
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
 		}
 	} else {
 		/* provide internal session */
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
-		if (!rte_mempool_get(qp->sess_mp, (void **)&_sess)) {
-			sess = (struct armv8_crypto_session *)
-				((struct rte_cryptodev_sym_session *)_sess)
-				->_private;
-
-			if (unlikely(armv8_crypto_set_session_parameters(
-					sess, op->sym->xform) != 0)) {
-				rte_mempool_put(qp->sess_mp, _sess);
-				sess = NULL;
-			} else
-				op->sym->session = _sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct armv8_crypto_session *)_sess_private_data;
+
+		if (unlikely(armv8_crypto_set_session_parameters(sess,
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
 		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	if (unlikely(sess == NULL))
@@ -704,6 +712,9 @@ process_op(const struct armv8_crypto_qp *qp, struct rte_crypto_op *op,
 	/* Free session if a session-less crypto op */
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
 		memset(sess, 0, sizeof(struct armv8_crypto_session));
+		memset(op->sym->session, 0,
+				rte_cryptodev_get_header_session_size());
+		rte_mempool_put(qp->sess_mp, sess);
 		rte_mempool_put(qp->sess_mp, op->sym->session);
 		op->sym->session = NULL;
 	}
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
index 1bce2ea..e14b68c 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
@@ -318,33 +318,54 @@ armv8_crypto_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure the session from a crypto xform chain */
-static void *
-armv8_crypto_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform, void *sess)
+static int
+armv8_crypto_pmd_session_configure(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		ARMV8_CRYPTO_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (armv8_crypto_set_session_parameters(
-			sess, xform) != 0) {
+	if (armv8_crypto_set_session_parameters(sess_private_data, xform) != 0) {
 		ARMV8_CRYPTO_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-armv8_crypto_pmd_session_clear(struct rte_cryptodev *dev __rte_unused,
-				void *sess)
+armv8_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
 
 	/* Zero out the whole structure */
-	if (sess)
-		memset(sess, 0, sizeof(struct armv8_crypto_session));
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct armv8_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops armv8_crypto_pmd_ops = {
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 9d1c266..b764f33 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -619,7 +619,9 @@ dpaa2_sec_enqueue_burst(void *qp, struct rte_crypto_op **ops,
 			/*Clear the unused FD fields before sending*/
 			memset(&fd_arr[loop], 0, sizeof(struct qbman_fd));
 			sess = (dpaa2_sec_session *)
-				(*ops)->sym->session->_private;
+					get_session_private_data(
+					(*ops)->sym->session,
+					cryptodev_driver_id);
 			mb_pool = (*ops)->sym->m_src->pool;
 			bpid = mempool_to_bpid(mb_pool);
 			ret = build_sec_fd(sess, *ops, &fd_arr[loop], bpid);
@@ -1498,8 +1500,8 @@ dpaa2_sec_aead_chain_init(struct rte_cryptodev *dev,
 	return -1;
 }
 
-static void *
-dpaa2_sec_session_configure(struct rte_cryptodev *dev,
+static int
+dpaa2_sec_set_session_parameters(struct rte_cryptodev *dev,
 			    struct rte_crypto_sym_xform *xform,	void *sess)
 {
 	dpaa2_sec_session *session = sess;
@@ -1508,7 +1510,7 @@ dpaa2_sec_session_configure(struct rte_cryptodev *dev,
 
 	if (unlikely(sess == NULL)) {
 		RTE_LOG(ERR, PMD, "invalid session struct");
-		return NULL;
+		return -1;
 	}
 
 	/* Default IV length = 0 */
@@ -1544,24 +1546,59 @@ dpaa2_sec_session_configure(struct rte_cryptodev *dev,
 
 	} else {
 		RTE_LOG(ERR, PMD, "Invalid crypto type");
-		return NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+dpaa2_sec_session_configure(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
+{
+	void *sess_private_data;
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	return session;
+	if (dpaa2_sec_set_session_parameters(dev, xform, sess_private_data) != 0) {
+		PMD_DRV_LOG(ERR, "DPAA2 PMD: failed to configure "
+				"session parameters");
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
+	}
+
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-dpaa2_sec_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+dpaa2_sec_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
 	PMD_INIT_FUNC_TRACE();
-	dpaa2_sec_session *s = (dpaa2_sec_session *)sess;
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+	dpaa2_sec_session *s = (dpaa2_sec_session *)sess_priv;
 
-	if (s) {
+	if (sess_priv) {
 		rte_free(s->ctxt);
 		rte_free(s->cipher_key.data);
 		rte_free(s->auth_key.data);
 		memset(sess, 0, sizeof(dpaa2_sec_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
 	}
 }
 
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index 35afa99..cff40fb 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -163,23 +163,40 @@ kasumi_set_session_parameters(struct kasumi_session *sess,
 static struct kasumi_session *
 kasumi_get_session(struct kasumi_qp *qp, struct rte_crypto_op *op)
 {
-	struct kasumi_session *sess;
+	struct kasumi_session *sess = NULL;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		sess = (struct kasumi_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct kasumi_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct kasumi_session *)c_sess->_private;
+		sess = (struct kasumi_session *)_sess_private_data;
 
 		if (unlikely(kasumi_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -354,6 +371,10 @@ process_ops(struct rte_crypto_op **ops, struct kasumi_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+			memset(session, 0, sizeof(struct kasumi_session));
+			memset(ops[i]->sym->session, 0,
+					rte_cryptodev_get_header_session_size());
+			rte_mempool_put(qp->sess_mp, session);
 			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
@@ -406,7 +427,8 @@ process_op_bit(struct rte_crypto_op *op, struct kasumi_session *session,
 
 	/* Free session if a session-less crypto op. */
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct kasumi_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
index 5cb0024..e7bbc29 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
@@ -292,33 +292,54 @@ kasumi_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a KASUMI session from a crypto xform chain */
-static void *
+static int
 kasumi_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		KASUMI_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (kasumi_set_session_parameters(sess, xform) != 0) {
+	if (kasumi_set_session_parameters(sess_private_data, xform) != 0) {
 		KASUMI_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-kasumi_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+kasumi_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	/*
-	 * Current just resetting the whole data structure, need to investigate
-	 * whether a more selective reset of key would be more performant
-	 */
-	if (sess)
-		memset(sess, 0, sizeof(struct kasumi_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct kasumi_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops kasumi_pmd_ops = {
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index 27cb9a2..7f7dee6 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -84,6 +84,14 @@ process_op(const struct null_crypto_qp *qp, struct rte_crypto_op *op,
 	/* set status as successful by default */
 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
+	/* Free session if a session-less crypto op. */
+	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+		memset(op->sym->session, 0,
+				sizeof(struct null_crypto_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
+		op->sym->session = NULL;
+	}
+
 	/*
 	 * if crypto session and operation are valid just enqueue the packet
 	 * in the processed ring
@@ -94,24 +102,35 @@ process_op(const struct null_crypto_qp *qp, struct rte_crypto_op *op,
 static struct null_crypto_session *
 get_session(struct null_crypto_qp *qp, struct rte_crypto_op *op)
 {
-	struct null_crypto_session *sess;
+	struct null_crypto_session *sess = NULL;
 	struct rte_crypto_sym_op *sym_op = op->sym;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(sym_op->session == NULL))
+		if (likely(sym_op->session != NULL))
+			sess = (struct null_crypto_session *)
+					get_session_private_data(
+					sym_op->session, cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
 			return NULL;
 
-		sess = (struct null_crypto_session *)sym_op->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
-
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct null_crypto_session *)c_sess->_private;
-
-		if (null_crypto_set_session_parameters(sess, sym_op->xform) != 0)
-			return NULL;
+		sess = (struct null_crypto_session *)_sess_private_data;
+
+		if (unlikely(null_crypto_set_session_parameters(sess,
+				sym_op->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		sym_op->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(sym_op->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	return sess;
diff --git a/drivers/crypto/null/null_crypto_pmd_ops.c b/drivers/crypto/null/null_crypto_pmd_ops.c
index a3f2e4c..d57644d 100644
--- a/drivers/crypto/null/null_crypto_pmd_ops.c
+++ b/drivers/crypto/null/null_crypto_pmd_ops.c
@@ -299,33 +299,54 @@ null_crypto_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a null crypto session from a crypto xform chain */
-static void *
+static int
 null_crypto_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform, void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
 {
-	int retval;
+	void *sess_private_data;
 
 	if (unlikely(sess == NULL)) {
 		NULL_CRYPTO_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
-	retval = null_crypto_set_session_parameters(
-			(struct null_crypto_session *)sess, xform);
-	if (retval != 0) {
+
+	if (null_crypto_set_session_parameters(sess_private_data, xform) != 0) {
 		NULL_CRYPTO_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-null_crypto_pmd_session_clear(struct rte_cryptodev *dev __rte_unused,
-		void *sess)
+null_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	if (sess)
-		memset(sess, 0, sizeof(struct null_crypto_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct null_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops pmd_ops = {
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 6f5937d..d943d72 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -560,23 +560,31 @@ get_session(struct openssl_qp *qp, struct rte_crypto_op *op)
 		/* get existing session */
 		if (likely(op->sym->session != NULL))
 			sess = (struct openssl_session *)
-				op->sym->session->_private;
-	} else  {
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
 		/* provide internal session */
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
-		if (!rte_mempool_get(qp->sess_mp, (void **)&_sess)) {
-			sess = (struct openssl_session *)
-				((struct rte_cryptodev_sym_session *)_sess)
-				->_private;
-
-			if (unlikely(openssl_set_session_parameters(
-					sess, op->sym->xform) != 0)) {
-				rte_mempool_put(qp->sess_mp, _sess);
-				sess = NULL;
-			} else
-				op->sym->session = _sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct openssl_session *)_sess_private_data;
+
+		if (unlikely(openssl_set_session_parameters(sess,
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
 		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	if (sess == NULL)
@@ -1318,6 +1326,9 @@ process_op(const struct openssl_qp *qp, struct rte_crypto_op *op,
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
 		openssl_reset_session(sess);
 		memset(sess, 0, sizeof(struct openssl_session));
+		memset(op->sym->session, 0,
+				rte_cryptodev_get_header_session_size());
+		rte_mempool_put(qp->sess_mp, sess);
 		rte_mempool_put(qp->sess_mp, op->sym->session);
 		op->sym->session = NULL;
 	}
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 6093b61..1f8a011 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -668,36 +668,56 @@ openssl_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure the session from a crypto xform chain */
-static void *
+static int
 openssl_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		OPENSSL_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
 	if (openssl_set_session_parameters(
-			sess, xform) != 0) {
+			sess_private_data, xform) != 0) {
 		OPENSSL_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-openssl_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+openssl_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	/*
-	 * Current just resetting the whole data structure, need to investigate
-	 * whether a more selective reset of key would be more performant
-	 */
-	if (sess) {
-		openssl_reset_session(sess);
-		memset(sess, 0, sizeof(struct openssl_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		openssl_reset_session(sess_priv);
+		memset(sess_priv, 0, sizeof(struct openssl_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
 	}
 }
 
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index d0638a2..3e621c5 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -216,23 +216,23 @@ static inline int
 qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		struct qat_crypto_op_cookie *qat_op_cookie);
 
-void qat_crypto_sym_clear_session(struct rte_cryptodev *dev,
-		void *session)
+void
+qat_crypto_sym_clear_session(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	struct qat_session *sess = session;
-	phys_addr_t cd_paddr;
-
 	PMD_INIT_FUNC_TRACE();
-	if (sess) {
-		if (sess->bpi_ctx) {
-			bpi_cipher_ctx_free(sess->bpi_ctx);
-			sess->bpi_ctx = NULL;
-		}
-		cd_paddr = sess->cd_paddr;
-		memset(sess, 0, qat_crypto_sym_get_session_private_size(dev));
-		sess->cd_paddr = cd_paddr;
-	} else
-		PMD_DRV_LOG(ERR, "NULL session");
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+	struct qat_session *s = (struct qat_session *)sess_priv;
+
+	if (sess_priv) {
+		if (s->bpi_ctx)
+			bpi_cipher_ctx_free(s->bpi_ctx);
+		memset(s, 0, qat_crypto_sym_get_session_private_size(dev));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 static int
@@ -450,9 +450,37 @@ qat_crypto_sym_configure_session_cipher(struct rte_cryptodev *dev,
 	return NULL;
 }
 
-
-void *
+int
 qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
+{
+	void *sess_private_data;
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
+	}
+
+	if (qat_crypto_set_session_parameters(dev, xform, sess_private_data) != 0) {
+		PMD_DRV_LOG(ERR, "Crypto QAT PMD: failed to configure "
+				"session parameters");
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
+	}
+
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
+}
+
+int
+qat_crypto_set_session_parameters(struct rte_cryptodev *dev,
 		struct rte_crypto_sym_xform *xform, void *session_private)
 {
 	struct qat_session *session = session_private;
@@ -460,6 +488,10 @@ qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
 	int qat_cmd_id;
 	PMD_INIT_FUNC_TRACE();
 
+	/* Set context descriptor physical address */
+	session->cd_paddr = rte_mempool_virt2phy(NULL, session) +
+			offsetof(struct qat_session, cd);
+
 	/* Get requested QAT command id */
 	qat_cmd_id = qat_get_cmd_id(xform);
 	if (qat_cmd_id < 0 || qat_cmd_id >= ICP_QAT_FW_LA_CMD_DELIMITER) {
@@ -514,10 +546,10 @@ qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
 		goto error_out;
 	}
 
-	return session;
+	return 0;
 
 error_out:
-	return NULL;
+	return -1;
 }
 
 struct qat_session *
@@ -946,7 +978,10 @@ qat_pmd_dequeue_op_burst(void *qp, struct rte_crypto_op **ops,
 			rx_op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 		} else {
 			struct qat_session *sess = (struct qat_session *)
-						(rx_op->sym->session->_private);
+					get_session_private_data(
+					rx_op->sym->session,
+					cryptodev_qat_driver_id);
+
 			if (sess->bpi_ctx)
 				qat_bpicipher_postprocess(sess, rx_op);
 			rx_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
@@ -1072,7 +1107,14 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		return -EINVAL;
 	}
 
-	ctx = (struct qat_session *)op->sym->session->_private;
+	ctx = (struct qat_session *)get_session_private_data(
+			op->sym->session, cryptodev_qat_driver_id);
+
+	if (unlikely(ctx == NULL)) {
+		PMD_DRV_LOG(ERR, "Session was not created for this device");
+		return -EINVAL;
+	}
+
 	qat_req = (struct icp_qat_fw_la_bulk_req *)out_msg;
 	rte_mov128((uint8_t *)qat_req, (const uint8_t *)&(ctx->fw_req));
 	qat_req->comn_mid.opaque_data = (uint64_t)(uintptr_t)op;
@@ -1371,17 +1413,6 @@ static inline uint32_t adf_modulo(uint32_t data, uint32_t shift)
 	return data - mult;
 }
 
-void qat_crypto_sym_session_init(struct rte_mempool *mp, void *sym_sess)
-{
-	struct rte_cryptodev_sym_session *sess = sym_sess;
-	struct qat_session *s = (void *)sess->_private;
-
-	PMD_INIT_FUNC_TRACE();
-	s->cd_paddr = rte_mempool_virt2phy(mp, sess) +
-		offsetof(struct qat_session, cd) +
-		offsetof(struct rte_cryptodev_sym_session, _private);
-}
-
 int qat_dev_config(__rte_unused struct rte_cryptodev *dev,
 		__rte_unused struct rte_cryptodev_config *config)
 {
diff --git a/drivers/crypto/qat/qat_crypto.h b/drivers/crypto/qat/qat_crypto.h
index 1258b6d..d9d8887 100644
--- a/drivers/crypto/qat/qat_crypto.h
+++ b/drivers/crypto/qat/qat_crypto.h
@@ -114,11 +114,15 @@ qat_pmd_session_mempool_create(struct rte_cryptodev *dev,
 extern unsigned
 qat_crypto_sym_get_session_private_size(struct rte_cryptodev *dev);
 
-extern void
-qat_crypto_sym_session_init(struct rte_mempool *mempool, void *priv_sess);
-
-extern void *
+extern int
 qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool);
+
+
+int
+qat_crypto_set_session_parameters(struct rte_cryptodev *dev,
 		struct rte_crypto_sym_xform *xform, void *session_private);
 
 struct qat_session *
@@ -136,8 +140,8 @@ qat_crypto_sym_configure_session_cipher(struct rte_cryptodev *dev,
 
 
 extern void
-qat_crypto_sym_clear_session(struct rte_cryptodev *dev, void *session);
-
+qat_crypto_sym_clear_session(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *session);
 
 extern uint16_t
 qat_pmd_enqueue_op_burst(void *qp, struct rte_crypto_op **ops,
diff --git a/drivers/crypto/qat/rte_qat_cryptodev.c b/drivers/crypto/qat/rte_qat_cryptodev.c
index 1c5ff77..9a710e6 100644
--- a/drivers/crypto/qat/rte_qat_cryptodev.c
+++ b/drivers/crypto/qat/rte_qat_cryptodev.c
@@ -73,7 +73,6 @@ static struct rte_cryptodev_ops crypto_qat_ops = {
 		/* Crypto related operations */
 		.session_get_size	= qat_crypto_sym_get_session_private_size,
 		.session_configure	= qat_crypto_sym_configure_session,
-		.session_initialize	= qat_crypto_sym_session_init,
 		.session_clear		= qat_crypto_sym_clear_session
 };
 
diff --git a/drivers/crypto/scheduler/scheduler_failover.c b/drivers/crypto/scheduler/scheduler_failover.c
index 162a29b..2aa13f8 100644
--- a/drivers/crypto/scheduler/scheduler_failover.c
+++ b/drivers/crypto/scheduler/scheduler_failover.c
@@ -49,57 +49,18 @@ struct fo_scheduler_qp_ctx {
 };
 
 static __rte_always_inline uint16_t
-failover_slave_enqueue(struct scheduler_slave *slave, uint8_t slave_idx,
+failover_slave_enqueue(struct scheduler_slave *slave,
 		struct rte_crypto_op **ops, uint16_t nb_ops)
 {
 	uint16_t i, processed_ops;
-	struct rte_cryptodev_sym_session *sessions[nb_ops];
-	struct scheduler_session *sess0, *sess1, *sess2, *sess3;
 
 	for (i = 0; i < nb_ops && i < 4; i++)
 		rte_prefetch0(ops[i]->sym->session);
 
-	for (i = 0; (i < (nb_ops - 8)) && (nb_ops > 8); i += 4) {
-		rte_prefetch0(ops[i + 4]->sym->session);
-		rte_prefetch0(ops[i + 5]->sym->session);
-		rte_prefetch0(ops[i + 6]->sym->session);
-		rte_prefetch0(ops[i + 7]->sym->session);
-
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sess1 = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
-		sess2 = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
-		sess3 = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
-		sessions[i] = ops[i]->sym->session;
-		sessions[i + 1] = ops[i + 1]->sym->session;
-		sessions[i + 2] = ops[i + 2]->sym->session;
-		sessions[i + 3] = ops[i + 3]->sym->session;
-
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-		ops[i + 1]->sym->session = sess1->sessions[slave_idx];
-		ops[i + 2]->sym->session = sess2->sessions[slave_idx];
-		ops[i + 3]->sym->session = sess3->sessions[slave_idx];
-	}
-
-	for (; i < nb_ops; i++) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sessions[i] = ops[i]->sym->session;
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-	}
-
 	processed_ops = rte_cryptodev_enqueue_burst(slave->dev_id,
 			slave->qp_id, ops, nb_ops);
 	slave->nb_inflight_cops += processed_ops;
 
-	if (unlikely(processed_ops < nb_ops))
-		for (i = processed_ops; i < nb_ops; i++)
-			ops[i]->sym->session = sessions[i];
-
 	return processed_ops;
 }
 
@@ -114,11 +75,11 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		return 0;
 
 	enqueued_ops = failover_slave_enqueue(&qp_ctx->primary_slave,
-			PRIMARY_SLAVE_IDX, ops, nb_ops);
+			ops, nb_ops);
 
 	if (enqueued_ops < nb_ops)
 		enqueued_ops += failover_slave_enqueue(&qp_ctx->secondary_slave,
-				SECONDARY_SLAVE_IDX, &ops[enqueued_ops],
+				&ops[enqueued_ops],
 				nb_ops - enqueued_ops);
 
 	return enqueued_ops;
diff --git a/drivers/crypto/scheduler/scheduler_pkt_size_distr.c b/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
index 6b628df..1dd1bc3 100644
--- a/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
+++ b/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
@@ -67,7 +67,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	struct scheduler_qp_ctx *qp_ctx = qp;
 	struct psd_scheduler_qp_ctx *psd_qp_ctx = qp_ctx->private_qp_ctx;
 	struct rte_crypto_op *sched_ops[NB_PKT_SIZE_SLAVES][nb_ops];
-	struct scheduler_session *sess;
 	uint32_t in_flight_ops[NB_PKT_SIZE_SLAVES] = {
 			psd_qp_ctx->primary_slave.nb_inflight_cops,
 			psd_qp_ctx->secondary_slave.nb_inflight_cops
@@ -97,8 +96,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		rte_prefetch0(ops[i + 7]->sym);
 		rte_prefetch0(ops[i + 7]->sym->session);
 
-		sess = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
 		/* job_len is initialized as cipher data length, once
 		 * it is 0, equals to auth data length
 		 */
@@ -118,11 +115,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i];
-		ops[i]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
 		job_len = ops[i+1]->sym->cipher.data.length;
 		job_len += (ops[i+1]->sym->cipher.data.length == 0) *
 				ops[i+1]->sym->auth.data.length;
@@ -135,11 +129,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+1];
-		ops[i+1]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
 		job_len = ops[i+2]->sym->cipher.data.length;
 		job_len += (ops[i+2]->sym->cipher.data.length == 0) *
 				ops[i+2]->sym->auth.data.length;
@@ -152,12 +143,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+2];
-		ops[i+2]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
 		job_len = ops[i+3]->sym->cipher.data.length;
 		job_len += (ops[i+3]->sym->cipher.data.length == 0) *
 				ops[i+3]->sym->auth.data.length;
@@ -170,14 +157,10 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+3];
-		ops[i+3]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 	}
 
 	for (; i < nb_ops; i++) {
-		sess = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-
 		job_len = ops[i]->sym->cipher.data.length;
 		job_len += (ops[i]->sym->cipher.data.length == 0) *
 				ops[i]->sym->auth.data.length;
@@ -190,7 +173,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i];
-		ops[i]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 	}
 
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index b9d8973..c450f6a 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -85,8 +85,10 @@ scheduler_attach_init_slave(struct rte_cryptodev *dev)
 /** Configure device */
 static int
 scheduler_pmd_config(struct rte_cryptodev *dev,
-		struct rte_cryptodev_config *config __rte_unused)
+		struct rte_cryptodev_config *config)
 {
+	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint32_t i;
 	int ret;
 
 	/* although scheduler_attach_init_slave presents multiple times,
@@ -96,6 +98,15 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	if (ret < 0)
 		return ret;
 
+	for (i = 0; i < sched_ctx->nb_slaves; i++) {
+		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
+
+		ret = rte_cryptodev_configure(slave_dev_id, config,
+				dev->data->session_pool);
+		if (ret < 0)
+			break;
+	}
+
 	return ret;
 }
 
@@ -474,37 +485,39 @@ scheduler_pmd_qp_count(struct rte_cryptodev *dev)
 static uint32_t
 scheduler_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 {
-	return sizeof(struct scheduler_session);
+	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint8_t i = 0;
+	uint32_t max_priv_sess_size = 0;
+
+	/* Check what is the maximum private session size for all slaves */
+	for (i = 0; i < sched_ctx->nb_slaves; i++) {
+		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
+		struct rte_cryptodev *dev = &rte_cryptodevs[slave_dev_id];
+		uint32_t priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
+
+		if (max_priv_sess_size < priv_sess_size)
+			max_priv_sess_size = priv_sess_size;
+	}
+
+	return max_priv_sess_size;
 }
 
 static int
-config_slave_sess(struct scheduler_ctx *sched_ctx,
-		struct rte_crypto_sym_xform *xform,
-		struct scheduler_session *sess,
-		uint32_t create)
+scheduler_pmd_session_configure(struct rte_cryptodev *dev,
+	struct rte_crypto_sym_xform *xform,
+	struct rte_cryptodev_sym_session *sess,
+	struct rte_mempool *mempool)
 {
+	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
 	uint32_t i;
 
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
 		struct scheduler_slave *slave = &sched_ctx->slaves[i];
 
-		if (sess->sessions[i]) {
-			if (create)
-				continue;
-			/* !create */
-			sess->sessions[i] = rte_cryptodev_sym_session_free(
-					slave->dev_id, sess->sessions[i]);
-		} else {
-			if (!create)
-				continue;
-			/* create */
-			sess->sessions[i] =
-					rte_cryptodev_sym_session_create(
-							slave->dev_id, xform);
-			if (!sess->sessions[i]) {
-				config_slave_sess(sched_ctx, NULL, sess, 0);
-				return -1;
-			}
+		if (rte_cryptodev_sym_session_init(slave->dev_id, sess,
+					xform, mempool) < 0) {
+			CS_LOG_ERR("unabled to config sym session");
+			return -1;
 		}
 	}
 
@@ -514,27 +527,17 @@ config_slave_sess(struct scheduler_ctx *sched_ctx,
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
 scheduler_pmd_session_clear(struct rte_cryptodev *dev,
-	void *sess)
+		struct rte_cryptodev_sym_session *sess)
 {
 	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint32_t i;
 
-	config_slave_sess(sched_ctx, NULL, sess, 0);
-
-	memset(sess, 0, sizeof(struct scheduler_session));
-}
-
-static void *
-scheduler_pmd_session_configure(struct rte_cryptodev *dev,
-	struct rte_crypto_sym_xform *xform, void *sess)
-{
-	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	/* Clear private data of slaves */
+	for (i = 0; i < sched_ctx->nb_slaves; i++) {
+		struct scheduler_slave *slave = &sched_ctx->slaves[i];
 
-	if (config_slave_sess(sched_ctx, xform, sess, 1) < 0) {
-		CS_LOG_ERR("unabled to config sym session");
-		return NULL;
+		rte_cryptodev_sym_session_clear(slave->dev_id, sess);
 	}
-
-	return sess;
 }
 
 struct rte_cryptodev_ops scheduler_pmd_ops = {
diff --git a/drivers/crypto/scheduler/scheduler_pmd_private.h b/drivers/crypto/scheduler/scheduler_pmd_private.h
index a78e9a6..a915ef4 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_private.h
+++ b/drivers/crypto/scheduler/scheduler_pmd_private.h
@@ -103,10 +103,6 @@ struct scheduler_qp_ctx {
 	uint32_t seqn;
 } __rte_cache_aligned;
 
-struct scheduler_session {
-	struct rte_cryptodev_sym_session *sessions[
-			RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES];
-};
 
 extern uint8_t cryptodev_driver_id;
 
diff --git a/drivers/crypto/scheduler/scheduler_roundrobin.c b/drivers/crypto/scheduler/scheduler_roundrobin.c
index 0116276..4a84728 100644
--- a/drivers/crypto/scheduler/scheduler_roundrobin.c
+++ b/drivers/crypto/scheduler/scheduler_roundrobin.c
@@ -52,8 +52,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	uint32_t slave_idx = rr_qp_ctx->last_enq_slave_idx;
 	struct scheduler_slave *slave = &rr_qp_ctx->slaves[slave_idx];
 	uint16_t i, processed_ops;
-	struct rte_cryptodev_sym_session *sessions[nb_ops];
-	struct scheduler_session *sess0, *sess1, *sess2, *sess3;
 
 	if (unlikely(nb_ops == 0))
 		return 0;
@@ -61,39 +59,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	for (i = 0; i < nb_ops && i < 4; i++)
 		rte_prefetch0(ops[i]->sym->session);
 
-	for (i = 0; (i < (nb_ops - 8)) && (nb_ops > 8); i += 4) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sess1 = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
-		sess2 = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
-		sess3 = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
-		sessions[i] = ops[i]->sym->session;
-		sessions[i + 1] = ops[i + 1]->sym->session;
-		sessions[i + 2] = ops[i + 2]->sym->session;
-		sessions[i + 3] = ops[i + 3]->sym->session;
-
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-		ops[i + 1]->sym->session = sess1->sessions[slave_idx];
-		ops[i + 2]->sym->session = sess2->sessions[slave_idx];
-		ops[i + 3]->sym->session = sess3->sessions[slave_idx];
-
-		rte_prefetch0(ops[i + 4]->sym->session);
-		rte_prefetch0(ops[i + 5]->sym->session);
-		rte_prefetch0(ops[i + 6]->sym->session);
-		rte_prefetch0(ops[i + 7]->sym->session);
-	}
-
-	for (; i < nb_ops; i++) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sessions[i] = ops[i]->sym->session;
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-	}
-
 	processed_ops = rte_cryptodev_enqueue_burst(slave->dev_id,
 			slave->qp_id, ops, nb_ops);
 
@@ -102,12 +67,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	rr_qp_ctx->last_enq_slave_idx += 1;
 	rr_qp_ctx->last_enq_slave_idx %= rr_qp_ctx->nb_slaves;
 
-	/* recover session if enqueue is failed */
-	if (unlikely(processed_ops < nb_ops)) {
-		for (i = processed_ops; i < nb_ops; i++)
-			ops[i]->sym->session = sessions[i];
-	}
-
 	return processed_ops;
 }
 
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index f28b8d6..107e1b4 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -163,23 +163,41 @@ snow3g_set_session_parameters(struct snow3g_session *sess,
 static struct snow3g_session *
 snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
 {
-	struct snow3g_session *sess;
+	struct snow3g_session *sess = NULL;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		sess = (struct snow3g_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct snow3g_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct snow3g_session *)c_sess->_private;
+		sess = (struct snow3g_session *)_sess_private_data;
 
 		if (unlikely(snow3g_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
+
 	return sess;
 }
 
@@ -355,6 +373,10 @@ process_ops(struct rte_crypto_op **ops, struct snow3g_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+			memset(session, 0, sizeof(struct snow3g_session));
+			memset(ops[i]->sym->session, 0,
+					rte_cryptodev_get_header_session_size());
+			rte_mempool_put(qp->sess_mp, session);
 			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
@@ -407,7 +429,8 @@ process_op_bit(struct rte_crypto_op *op, struct snow3g_session *session,
 
 	/* Free session if a session-less crypto op. */
 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct snow3g_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
index e3fa0fa..3accba5 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -290,33 +290,54 @@ snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a SNOW 3G session from a crypto xform chain */
-static void *
+static int
 snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		SNOW3G_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (snow3g_set_session_parameters(sess, xform) != 0) {
+	if (snow3g_set_session_parameters(sess_private_data, xform) != 0) {
 		SNOW3G_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-snow3g_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+snow3g_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	/*
-	 * Current just resetting the whole data structure, need to investigate
-	 * whether a more selective reset of key would be more performant
-	 */
-	if (sess)
-		memset(sess, 0, sizeof(struct snow3g_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct snow3g_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops snow3g_pmd_ops = {
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index 951f1f4..664c58f 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -162,23 +162,40 @@ zuc_set_session_parameters(struct zuc_session *sess,
 static struct zuc_session *
 zuc_get_session(struct zuc_qp *qp, struct rte_crypto_op *op)
 {
-	struct zuc_session *sess;
+	struct zuc_session *sess = NULL;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		sess = (struct zuc_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct zuc_session *)get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct zuc_session *)c_sess->_private;
+		sess = (struct zuc_session *)_sess_private_data;
 
 		if (unlikely(zuc_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
+
 	return sess;
 }
 
@@ -337,6 +354,10 @@ process_ops(struct rte_crypto_op **ops, struct zuc_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
+			memset(session, 0, sizeof(struct zuc_session));
+			memset(ops[i]->sym->session, 0,
+					rte_cryptodev_get_header_session_size());
+			rte_mempool_put(qp->sess_mp, session);
 			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
diff --git a/drivers/crypto/zuc/rte_zuc_pmd_ops.c b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
index abfa0e2..adef343 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd_ops.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
@@ -290,33 +290,54 @@ zuc_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a ZUC session from a crypto xform chain */
-static void *
+static int
 zuc_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		ZUC_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (zuc_set_session_parameters(sess, xform) != 0) {
+	if (zuc_set_session_parameters(sess_private_data, xform) != 0) {
 		ZUC_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
 static void
-zuc_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+zuc_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
 {
-	/*
-	 * Current just resetting the whole data structure, need to investigate
-	 * whether a more selective reset of key would be more performant
-	 */
-	if (sess)
-		memset(sess, 0, sizeof(struct zuc_session));
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		memset(sess_priv, 0, sizeof(struct zuc_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
 }
 
 struct rte_cryptodev_ops zuc_pmd_ops = {
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 4d6c7ce..708eadd 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1242,8 +1242,7 @@ cryptodevs_init(void)
 
 	uint32_t max_sess_sz = 0, sess_sz;
 	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
-		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_sz = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_sz > max_sess_sz)
 			max_sess_sz = sess_sz;
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index f09dce9..0afb9d6 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -45,7 +45,7 @@
 #include "esp.h"
 
 static inline int
-create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
+create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 {
 	struct rte_cryptodev_info cdev_info;
 	unsigned long cdev_id_qp = 0;
@@ -72,7 +72,10 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 			ipsec_ctx->tbl[cdev_id_qp].qp);
 
 	sa->crypto_session = rte_cryptodev_sym_session_create(
-			ipsec_ctx->tbl[cdev_id_qp].id, sa->xforms);
+			ipsec_ctx->session_pool);
+	rte_cryptodev_sym_session_init(ipsec_ctx->tbl[cdev_id_qp].id,
+			sa->crypto_session, sa->xforms,
+			ipsec_ctx->session_pool);
 
 	rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id, &cdev_info);
 	if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 9b24e51..cba29ce 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -649,6 +649,9 @@ static struct rte_cryptodev_sym_session *
 initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 {
 	struct rte_crypto_sym_xform *first_xform;
+	struct rte_cryptodev_sym_session *session;
+	uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
+	struct rte_mempool *sess_mp = session_pool_socket[socket_id];
 
 	if (options->xform_chain == L2FWD_CRYPTO_AEAD) {
 		first_xform = &options->aead_xform;
@@ -664,7 +667,16 @@ initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 		first_xform = &options->auth_xform;
 	}
 
-	return rte_cryptodev_sym_session_create(cdev_id, first_xform);
+	session = rte_cryptodev_sym_session_create(sess_mp);
+
+	if (session == NULL)
+		return NULL;
+
+	if (rte_cryptodev_sym_session_init(cdev_id, session,
+				first_xform, sess_mp) < 0)
+		return NULL;
+
+	return session;
 }
 
 static void
@@ -1935,8 +1947,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 	}
 
 	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
-		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_sz = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_sz > max_sess_sz)
 			max_sess_sz = sess_sz;
 	}
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index dfced85..373c05b 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -69,6 +69,8 @@
 #include "rte_cryptodev.h"
 #include "rte_cryptodev_pmd.h"
 
+static uint8_t nb_drivers;
+
 struct rte_cryptodev rte_crypto_devices[RTE_CRYPTO_MAX_DEVS];
 
 struct rte_cryptodev *rte_cryptodevs = &rte_crypto_devices[0];
@@ -1080,53 +1082,47 @@ rte_cryptodev_pmd_callback_process(struct rte_cryptodev *dev,
 }
 
 
-static void
-rte_cryptodev_sym_session_init(struct rte_mempool *mp,
-		const struct rte_cryptodev *dev,
-		struct rte_cryptodev_sym_session *sess)
+int
+rte_cryptodev_sym_session_init(uint8_t dev_id,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_crypto_sym_xform *xforms,
+		struct rte_mempool *mp)
 {
-	memset(sess, 0, mp->elt_size);
+	struct rte_cryptodev *dev;
+	uint8_t index;
 
-	if (dev->dev_ops->session_initialize)
-		(*dev->dev_ops->session_initialize)(mp, sess);
-}
+	dev = rte_cryptodev_pmd_get_dev(dev_id);
 
+	if (sess == NULL || xforms == NULL || dev == NULL)
+		return -1;
 
-struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_create(uint8_t dev_id,
-		struct rte_crypto_sym_xform *xform)
-{
-	struct rte_cryptodev *dev;
-	struct rte_cryptodev_sym_session *sess;
-	void *_sess;
+	index = dev->driver_id;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
-		return NULL;
+	if (sess->sess_private_data[index] == NULL) {
+		if (dev->dev_ops->session_configure(dev, xforms, sess, mp) < 0) {
+			CDEV_LOG_ERR(
+				"dev_id %d failed to configure session details",
+				dev_id);
+			return -1;
+		}
 	}
 
-	dev = &rte_crypto_devices[dev_id];
+	return 0;
+}
+
+struct rte_cryptodev_sym_session *
+rte_cryptodev_sym_session_create(struct rte_mempool *mp)
+{
+	struct rte_cryptodev_sym_session *sess;
 
 	/* Allocate a session structure from the session pool */
-	if (rte_mempool_get(dev->data->session_pool, &_sess)) {
-		CDEV_LOG_ERR("Couldn't get object from session mempool");
+	if (rte_mempool_get(mp, (void *)&sess)) {
+		CDEV_LOG_ERR("couldn't get object from session mempool");
 		return NULL;
 	}
 
-	sess = _sess;
-
-	rte_cryptodev_sym_session_init(dev->data->session_pool, dev,
-					sess);
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_configure, NULL);
-	if (dev->dev_ops->session_configure(dev, xform, sess->_private) ==
-			NULL) {
-		CDEV_LOG_ERR("dev_id %d failed to configure session details",
-				dev_id);
-
-		/* Return session to mempool */
-		rte_mempool_put(dev->data->session_pool, _sess);
-		return NULL;
-	}
+	/* Clear device session pointer */
+	memset(sess, 0, (sizeof(void *) * nb_drivers));
 
 	return sess;
 }
@@ -1146,7 +1142,10 @@ rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_attach_session, 0);
-	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess->_private)) {
+
+	void *sess_priv = get_session_private_data(sess, dev->driver_id);
+
+	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess_priv)) {
 		CDEV_LOG_ERR("dev_id %d failed to attach qp: %d with session",
 				dev_id, qp_id);
 		return -EPERM;
@@ -1170,7 +1169,10 @@ rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_detach_session, 0);
-	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess->_private)) {
+
+	void *sess_priv = get_session_private_data(sess, dev->driver_id);
+
+	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess_priv)) {
 		CDEV_LOG_ERR("dev_id %d failed to detach qp: %d from session",
 				dev_id, qp_id);
 		return -EPERM;
@@ -1178,34 +1180,62 @@ rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	return 0;
 }
-struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_free(uint8_t dev_id,
+
+int
+rte_cryptodev_sym_session_clear(uint8_t dev_id,
 		struct rte_cryptodev_sym_session *sess)
 {
 	struct rte_cryptodev *dev;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
-		return sess;
-	}
+	dev = rte_cryptodev_pmd_get_dev(dev_id);
 
-	dev = &rte_crypto_devices[dev_id];
+	if (dev == NULL || sess == NULL)
+		return -EINVAL;
+
+	dev->dev_ops->session_clear(dev, sess);
 
-	/* Let device implementation clear session material */
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_clear, sess);
-	dev->dev_ops->session_clear(dev, (void *)sess->_private);
+	return 0;
+}
+
+int
+rte_cryptodev_sym_session_free(struct rte_cryptodev_sym_session *sess)
+{
+	uint8_t i;
+	void *sess_priv;
+	struct rte_mempool *sess_mp;
+
+	if (sess == NULL)
+		return -EINVAL;
+
+	/* Check that all device private data has been freed */
+	for (i = 0; i < nb_drivers; i++) {
+		sess_priv = get_session_private_data(sess, i);
+		if (sess_priv != NULL)
+			return -EBUSY;
+	}
 
 	/* Return session to mempool */
-	struct rte_mempool *mp = rte_mempool_from_obj(sess);
-	rte_mempool_put(mp, (void *)sess);
+	sess_mp = rte_mempool_from_obj(sess);
+	rte_mempool_put(sess_mp, sess);
 
-	return NULL;
+	return 0;
+}
+
+unsigned int
+rte_cryptodev_get_header_session_size(void)
+{
+	/*
+	 * Header contains pointers to the private data
+	 * of all registered drivers
+	 */
+	return (sizeof(void *) * nb_drivers);
 }
 
 unsigned int
 rte_cryptodev_get_private_session_size(uint8_t dev_id)
 {
 	struct rte_cryptodev *dev;
+	unsigned int header_size = sizeof(void *) * nb_drivers;
 	unsigned int priv_sess_size;
 
 	if (!rte_cryptodev_pmd_is_valid_dev(dev_id))
@@ -1218,6 +1248,14 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id)
 
 	priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
 
+	/*
+	 * If size is less than session header size,
+	 * return the latter, as this guarantees that
+	 * sessionless operations will work
+	 */
+	if (priv_sess_size < header_size)
+		return header_size;
+
 	return priv_sess_size;
 
 }
@@ -1333,8 +1371,6 @@ struct cryptodev_driver {
 	uint8_t id;
 };
 
-static uint8_t nb_drivers;
-
 int
 rte_cryptodev_driver_id_get(const char *name)
 {
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 508c672..3ba3efb 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -883,50 +883,80 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 /** Cryptodev symmetric crypto session */
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
-	__extension__ char _private[0];
+	__extension__ void *sess_private_data[0];
 	/**< Private session material */
 };
 
 
 /**
- * Initialise a session for symmetric cryptographic operations.
+ * Create symmetric crypto session header (generic with no private data)
  *
- * This function is used by the client to initialize immutable
- * parameters of symmetric cryptographic operation.
- * To perform the operation the rte_cryptodev_enqueue_burst function is
- * used.  Each mbuf should contain a reference to the session
- * pointer returned from this function contained within it's crypto_op if a
- * session-based operation is being provisioned. Memory to contain the session
- * information is allocated from within mempool managed by the cryptodev.
+ * @param   mempool    Symmetric session mempool to allocate session
+ *                     objects from
+ * @return
+ *  - On success return pointer to sym-session
+ *  - On failure returns NULL
+ */
+struct rte_cryptodev_sym_session *
+rte_cryptodev_sym_session_create(struct rte_mempool *mempool);
+
+/**
+ * Frees symmetric crypto session header, after checking that all
+ * the device private data has been freed, returning it
+ * to its original mempool.
  *
- * The rte_cryptodev_session_free must be called to free allocated
- * memory when the session is no longer required.
+ * @param   sess     Session header to be freed.
  *
- * @param	dev_id		The device identifier.
- * @param	xform		Crypto transform chain.
+ * @return
+ *  - 0 if successful.
+ *  - -EINVAL if session is NULL.
+ *  - -EBUSY if not all device private data has been freed.
+ */
+int
+rte_cryptodev_sym_session_free(struct rte_cryptodev_sym_session *sess);
 
+/**
+ * Fill out private data for the device id, based on its device type.
+ *
+ * @param   dev_id   ID of device that we want the session to be used on
+ * @param   sess     Session where the private data will be attached to
+ * @param   xforms   Symmetric crypto transform operations to apply on flow
+ *                   processed with this session
+ * @param   mempool  Mempool where the private data is allocated.
  *
  * @return
- *  Pointer to the created session or NULL
+ *  - On success, zero.
+ *  - On failure, a negative value.
  */
-extern struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_create(uint8_t dev_id,
-		struct rte_crypto_sym_xform *xform);
+int
+rte_cryptodev_sym_session_init(uint8_t dev_id,
+			struct rte_cryptodev_sym_session *sess,
+			struct rte_crypto_sym_xform *xforms,
+			struct rte_mempool *mempool);
 
 /**
- * Free the memory associated with a previously allocated session.
+ * Frees private data for the device id, based on its device type,
+ * returning it to its mempool.
  *
- * @param	dev_id		The device identifier.
- * @param	session		Session pointer previously allocated by
- *				*rte_cryptodev_sym_session_create*.
+ * @param   dev_id   ID of device that uses the session.
+ * @param   sess     Session containing the reference to the private data
  *
  * @return
- *   NULL on successful freeing of session.
- *   Session pointer on failure to free session.
+ *  - 0 if successful.
+ *  - -EINVAL if device is invalid or session is NULL.
  */
-extern struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_free(uint8_t dev_id,
-		struct rte_cryptodev_sym_session *session);
+int
+rte_cryptodev_sym_session_clear(uint8_t dev_id,
+			struct rte_cryptodev_sym_session *sess);
+
+/**
+ * Get the size of the header session, for all registered drivers.
+ *
+ * @return
+ *   Size of the header session.
+ */
+unsigned int
+rte_cryptodev_get_header_session_size(void);
 
 /**
  * Get the size of the private session data for a device.
diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
index 5911b83..2896171 100644
--- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
+++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
@@ -285,20 +285,25 @@ typedef void (*cryptodev_sym_initialize_session_t)(struct rte_mempool *mempool,
  * @param	dev		Crypto device pointer
  * @param	xform		Single or chain of crypto xforms
  * @param	priv_sess	Pointer to cryptodev's private session structure
+ * @param	mp		Mempool where the private session is allocated
  *
  * @return
- *  - Returns private session structure on success.
- *  - Returns NULL on failure.
+ *  - Returns 0 if private session structure have been created successfully.
+ *  - Returns -1 on failure.
  */
-typedef void * (*cryptodev_sym_configure_session_t)(struct rte_cryptodev *dev,
-		struct rte_crypto_sym_xform *xform, void *session_private);
+typedef int (*cryptodev_sym_configure_session_t)(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *session,
+		struct rte_mempool *mp);
 
 /**
- * Free Crypto session.
- * @param	session		Cryptodev session structure to free
+ * Free driver private session data.
+ *
+ * @param	dev		Crypto device pointer
+ * @param	sess		Cryptodev session structure
  */
 typedef void (*cryptodev_sym_free_session_t)(struct rte_cryptodev *dev,
-		void *session_private);
+		struct rte_cryptodev_sym_session *sess);
 
 /**
  * Optional API for drivers to attach sessions with queue pair.
@@ -413,6 +418,19 @@ void rte_cryptodev_pmd_callback_process(struct rte_cryptodev *dev,
 int
 rte_cryptodev_pmd_create_dev_name(char *name, const char *dev_name_prefix);
 
+static inline void *
+get_session_private_data(const struct rte_cryptodev_sym_session *sess,
+		uint8_t driver_id) {
+	return sess->sess_private_data[driver_id];
+}
+
+static inline void
+set_session_private_data(struct rte_cryptodev_sym_session *sess,
+		uint8_t driver_id, void *private_data)
+{
+	sess->sess_private_data[driver_id] = private_data;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_cryptodev/rte_cryptodev_version.map b/lib/librte_cryptodev/rte_cryptodev_version.map
index d817421..e9ba88a 100644
--- a/lib/librte_cryptodev/rte_cryptodev_version.map
+++ b/lib/librte_cryptodev/rte_cryptodev_version.map
@@ -66,10 +66,13 @@ DPDK_17.08 {
 	rte_cryptodev_driver_id_get;
 	rte_cryptodev_driver_name_get;
 	rte_cryptodev_get_aead_algo_enum;
+	rte_cryptodev_get_header_session_size;
 	rte_cryptodev_get_private_session_size;
 	rte_cryptodev_pci_generic_probe;
 	rte_cryptodev_pci_generic_remove;
 	rte_cryptodev_sym_capability_check_aead;
+	rte_cryptodev_sym_session_init;
+	rte_cryptodev_sym_session_clear;
 	rte_cryptodev_vdev_parse_init_params;
 	rte_cryptodev_vdev_pmd_init;
 	rte_crypto_aead_algorithm_strings;
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index e5d6c07..745f261 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -68,7 +68,6 @@ struct crypto_testsuite_params {
 	struct rte_mempool *large_mbuf_pool;
 	struct rte_mempool *op_mpool;
 	struct rte_mempool *session_mpool;
-	struct rte_mempool *slave_session_mpool;
 	struct rte_cryptodev_config conf;
 	struct rte_cryptodev_qp_conf qp_conf;
 
@@ -387,12 +386,15 @@ testsuite_setup(void)
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
 
-	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
-		rte_cryptodev_get_private_session_size(dev_id);
+	unsigned int session_size = rte_cryptodev_get_private_session_size(dev_id);
 
+	/*
+	 * Create mempool with maximum number of sessions * 2,
+	 * to include the session headers
+	 */
 	ts_params->session_mpool = rte_mempool_create(
 				"test_sess_mp",
-				info.sym.max_nb_sessions,
+				info.sym.max_nb_sessions * 2,
 				session_size,
 				0, 0, NULL, NULL, NULL,
 				NULL, SOCKET_ID_ANY,
@@ -439,11 +441,6 @@ testsuite_teardown(void)
 		rte_mempool_free(ts_params->session_mpool);
 		ts_params->session_mpool = NULL;
 	}
-
-	if (ts_params->slave_session_mpool != NULL) {
-		rte_mempool_free(ts_params->slave_session_mpool);
-		ts_params->slave_session_mpool = NULL;
-	}
 }
 
 static int
@@ -494,8 +491,9 @@ ut_teardown(void)
 
 	/* free crypto session structure */
 	if (ut_params->sess) {
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
+		rte_cryptodev_sym_session_clear(ts_params->valid_devs[0],
 				ut_params->sess);
+		rte_cryptodev_sym_session_free(ut_params->sess);
 		ut_params->sess = NULL;
 	}
 
@@ -1280,10 +1278,13 @@ test_AES_CBC_HMAC_SHA1_encrypt_digest(void)
 	ut_params->auth_xform.auth.key.data = hmac_sha1_key;
 	ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA1;
 
-	/* Create crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0],
-			&ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate crypto op data structure */
@@ -1496,7 +1497,9 @@ test_AES_cipheronly_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1513,7 +1516,9 @@ test_AES_docsis_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_DOCSIS_TYPE);
@@ -1530,7 +1535,9 @@ test_AES_docsis_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_DOCSIS_TYPE);
@@ -1547,7 +1554,9 @@ test_DES_docsis_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_DES_DOCSIS_TYPE);
@@ -1564,7 +1573,9 @@ test_authonly_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1581,7 +1592,9 @@ test_AES_chain_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1600,7 +1613,9 @@ test_AES_cipheronly_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1617,7 +1632,9 @@ test_AES_chain_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1634,7 +1651,9 @@ test_authonly_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1653,7 +1672,9 @@ test_AES_chain_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1670,7 +1691,9 @@ test_AES_cipheronly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1687,7 +1710,9 @@ test_AES_chain_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1704,7 +1729,9 @@ test_AES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1721,7 +1748,9 @@ test_AES_chain_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1738,7 +1767,9 @@ test_AES_cipheronly_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1755,7 +1786,9 @@ test_authonly_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(RTE_CRYPTODEV_DPAA2_SEC_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1772,7 +1805,9 @@ test_authonly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1789,7 +1824,9 @@ test_AES_chain_armv8_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1809,6 +1846,7 @@ create_wireless_algo_hash_session(uint8_t dev_id,
 {
 	uint8_t hash_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(hash_key, key, key_len);
@@ -1826,8 +1864,11 @@ create_wireless_algo_hash_session(uint8_t dev_id,
 	ut_params->auth_xform.auth.digest_length = auth_len;
 	ut_params->auth_xform.auth.iv.offset = IV_OFFSET;
 	ut_params->auth_xform.auth.iv.length = iv_len;
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->auth_xform, ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
 }
@@ -1841,6 +1882,7 @@ create_wireless_algo_cipher_session(uint8_t dev_id,
 {
 	uint8_t cipher_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_key, key, key_len);
@@ -1859,9 +1901,11 @@ create_wireless_algo_cipher_session(uint8_t dev_id,
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session */
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-						&ut_params->
-						cipher_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->cipher_xform, ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
 }
@@ -1940,6 +1984,7 @@ create_wireless_algo_cipher_auth_session(uint8_t dev_id,
 {
 	uint8_t cipher_auth_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_auth_key, key, key_len);
@@ -1972,8 +2017,11 @@ create_wireless_algo_cipher_auth_session(uint8_t dev_id,
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->cipher_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->cipher_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
@@ -1990,6 +2038,7 @@ create_wireless_cipher_auth_session(uint8_t dev_id,
 	const uint8_t key_len = tdata->key.len;
 	uint8_t cipher_auth_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 	const uint8_t *key = tdata->key.data;
 	const uint8_t auth_len = tdata->digest.len;
@@ -2027,8 +2076,11 @@ create_wireless_cipher_auth_session(uint8_t dev_id,
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->cipher_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->cipher_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
@@ -2056,6 +2108,7 @@ create_wireless_algo_auth_cipher_session(uint8_t dev_id,
 {
 	uint8_t auth_cipher_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(auth_cipher_key, key, key_len);
@@ -2085,8 +2138,11 @@ create_wireless_algo_auth_cipher_session(uint8_t dev_id,
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->auth_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -4536,7 +4592,9 @@ test_3DES_chain_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4553,7 +4611,9 @@ test_DES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_DES_CIPHERONLY_TYPE);
@@ -4570,7 +4630,9 @@ test_DES_docsis_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_DES_DOCSIS_TYPE);
@@ -4587,7 +4649,9 @@ test_3DES_chain_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4604,7 +4668,9 @@ test_3DES_cipheronly_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4621,7 +4687,9 @@ test_3DES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4638,7 +4706,9 @@ test_3DES_chain_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4655,7 +4725,9 @@ test_3DES_cipheronly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4675,6 +4747,7 @@ create_gcm_session(uint8_t dev_id, enum rte_crypto_aead_operation op,
 {
 	uint8_t aead_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(aead_key, key, key_len);
@@ -4694,8 +4767,11 @@ create_gcm_session(uint8_t dev_id, enum rte_crypto_aead_operation op,
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-			&ut_params->aead_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->aead_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -5656,7 +5732,11 @@ static int MD5_HMAC_create_session(struct crypto_testsuite_params *ts_params,
 	ut_params->auth_xform.auth.key.data = key;
 
 	ut_params->sess = rte_cryptodev_sym_session_create(
-		ts_params->valid_devs[0], &ut_params->auth_xform);
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
 
 	if (ut_params->sess == NULL)
 		return TEST_FAILED;
@@ -5831,9 +5911,13 @@ test_multi_session(void)
 
 	/* Create multiple crypto sessions*/
 	for (i = 0; i < dev_info.sym.max_nb_sessions; i++) {
+
 		sessions[i] = rte_cryptodev_sym_session_create(
-				ts_params->valid_devs[0],
-			&ut_params->auth_xform);
+				ts_params->session_mpool);
+
+		rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+				sessions[i], &ut_params->auth_xform,
+				ts_params->session_mpool);
 		TEST_ASSERT_NOT_NULL(sessions[i],
 				"Session creation failed at session number %u",
 				i);
@@ -5869,14 +5953,17 @@ test_multi_session(void)
 	}
 
 	/* Next session create should fail */
-	sessions[i] = rte_cryptodev_sym_session_create(ts_params->valid_devs[0],
-			&ut_params->auth_xform);
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			sessions[i], &ut_params->auth_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NULL(sessions[i],
 			"Session creation succeeded unexpectedly!");
 
-	for (i = 0; i < dev_info.sym.max_nb_sessions; i++)
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
+	for (i = 0; i < dev_info.sym.max_nb_sessions; i++) {
+		rte_cryptodev_sym_session_clear(ts_params->valid_devs[0],
 				sessions[i]);
+		rte_cryptodev_sym_session_free(sessions[i]);
+	}
 
 	rte_free(sessions);
 
@@ -5934,6 +6021,9 @@ test_multi_session_random_usage(void)
 					* dev_info.sym.max_nb_sessions) + 1, 0);
 
 	for (i = 0; i < MB_SESSION_NUMBER; i++) {
+		sessions[i] = rte_cryptodev_sym_session_create(
+				ts_params->session_mpool);
+
 		rte_memcpy(&ut_paramz[i].ut_params, &testsuite_params,
 				sizeof(struct crypto_unittest_params));
 
@@ -5942,9 +6032,11 @@ test_multi_session_random_usage(void)
 				ut_paramz[i].cipher_key, ut_paramz[i].hmac_key);
 
 		/* Create multiple crypto sessions*/
-		sessions[i] = rte_cryptodev_sym_session_create(
+		rte_cryptodev_sym_session_init(
 				ts_params->valid_devs[0],
-				&ut_paramz[i].ut_params.auth_xform);
+				sessions[i],
+				&ut_paramz[i].ut_params.auth_xform,
+				ts_params->session_mpool);
 
 		TEST_ASSERT_NOT_NULL(sessions[i],
 				"Session creation failed at session number %u",
@@ -5987,9 +6079,11 @@ test_multi_session_random_usage(void)
 		}
 	}
 
-	for (i = 0; i < MB_SESSION_NUMBER; i++)
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
+	for (i = 0; i < MB_SESSION_NUMBER; i++) {
+		rte_cryptodev_sym_session_clear(ts_params->valid_devs[0],
 				sessions[i]);
+		rte_cryptodev_sym_session_free(sessions[i]);
+	}
 
 	rte_free(sessions);
 
@@ -6013,9 +6107,14 @@ test_null_cipher_only_operation(void)
 	ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL;
 	ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+				ut_params->sess,
+				&ut_params->cipher_xform,
+				ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6070,9 +6169,13 @@ test_null_auth_only_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->auth_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6126,9 +6229,13 @@ test_null_cipher_auth_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6192,9 +6299,13 @@ test_null_auth_cipher_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6240,6 +6351,7 @@ test_null_invalid_operation(void)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
+	int ret;
 
 	/* Setup Cipher Parameters */
 	ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
@@ -6248,10 +6360,14 @@ test_null_invalid_operation(void)
 	ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
 	ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
-	TEST_ASSERT_NULL(ut_params->sess,
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	ret = rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
+	TEST_ASSERT(ret == -1,
 			"Session creation succeeded unexpectedly");
 
 
@@ -6262,10 +6378,14 @@ test_null_invalid_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->auth_xform);
-	TEST_ASSERT_NULL(ut_params->sess,
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	ret = rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
+	TEST_ASSERT(ret == -1,
 			"Session creation succeeded unexpectedly");
 
 	return TEST_SUCCESS;
@@ -6299,9 +6419,13 @@ test_null_burst_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	TEST_ASSERT_EQUAL(rte_crypto_op_bulk_alloc(ts_params->op_mpool,
@@ -6414,6 +6538,7 @@ static int create_gmac_session(uint8_t dev_id,
 {
 	uint8_t auth_key[tdata->key.len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(auth_key, tdata->key.data, tdata->key.len);
@@ -6430,8 +6555,12 @@ static int create_gmac_session(uint8_t dev_id,
 	ut_params->auth_xform.auth.iv.length = tdata->iv.len;
 
 
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-			&ut_params->auth_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->auth_xform,
+			ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -6791,6 +6920,7 @@ create_auth_session(struct crypto_unittest_params *ut_params,
 		const struct test_crypto_vector *reference,
 		enum rte_crypto_auth_operation auth_op)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	uint8_t auth_key[reference->auth_key.len + 1];
 
 	memcpy(auth_key, reference->auth_key.data, reference->auth_key.len);
@@ -6805,8 +6935,12 @@ create_auth_session(struct crypto_unittest_params *ut_params,
 	ut_params->auth_xform.auth.digest_length = reference->digest.len;
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform,
+				ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -6820,6 +6954,7 @@ create_auth_cipher_session(struct crypto_unittest_params *ut_params,
 		enum rte_crypto_auth_operation auth_op,
 		enum rte_crypto_cipher_operation cipher_op)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	uint8_t cipher_key[reference->cipher_key.len + 1];
 	uint8_t auth_key[reference->auth_key.len + 1];
 
@@ -6853,8 +6988,12 @@ create_auth_cipher_session(struct crypto_unittest_params *ut_params,
 	}
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform,
+				ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -7710,30 +7849,32 @@ test_scheduler_attach_slave_op(void)
 			continue;
 
 		/*
-		 * Create a separate mempool for the slaves, as they need different
-		 * session size and then configure them to store the pointer
-		 * to this mempool
+		 * Create the session mempool again, since now there are new devices
+		 * to use the mempool.
 		 */
-		unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(i);
+		if (ts_params->session_mpool) {
+			rte_mempool_free(ts_params->session_mpool);
+			ts_params->session_mpool = NULL;
+		}
+		unsigned int session_size = rte_cryptodev_get_private_session_size(i);
 
-		if (ts_params->slave_session_mpool == NULL) {
-			ts_params->slave_session_mpool = rte_mempool_create(
-				"test_slave_sess_mp",
-				info.sym.max_nb_sessions,
-				session_size,
-				0, 0, NULL, NULL, NULL, NULL,
-				SOCKET_ID_ANY, 0);
+		/*
+		 * Create mempool with maximum number of sessions * 2,
+		 * to include the session headers
+		 */
+		if (ts_params->session_mpool == NULL) {
+			ts_params->session_mpool = rte_mempool_create(
+					"test_sess_mp",
+					info.sym.max_nb_sessions * 2,
+					session_size,
+					0, 0, NULL, NULL, NULL,
+					NULL, SOCKET_ID_ANY,
+					0);
 
-			TEST_ASSERT_NOT_NULL(ts_params->slave_session_mpool,
+			TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
 					"session mempool allocation failed");
 		}
 
-		TEST_ASSERT_SUCCESS(rte_cryptodev_configure(i,
-				&ts_params->conf, ts_params->slave_session_mpool),
-				"Failed to configure cryptodev %u with %u qps",
-				i, ts_params->conf.nb_queue_pairs);
-
 		ret = rte_cryptodev_scheduler_slave_attach(sched_id,
 				(uint8_t)i);
 
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 0b512c2..e822c96 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -53,6 +53,7 @@ static int
 test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	char *test_msg)
@@ -65,8 +66,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	struct rte_crypto_sym_xform *init_xform = NULL;
 	struct rte_crypto_sym_op *sym_op = NULL;
 	struct rte_crypto_op *op = NULL;
-	struct rte_cryptodev_sym_session *sess = NULL;
 	struct rte_cryptodev_info dev_info;
+	struct rte_cryptodev_sym_session *sess = NULL;
 
 	int status = TEST_SUCCESS;
 	const struct blockcipher_test_data *tdata = t->test_data;
@@ -340,8 +341,10 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 
 	/* create session for sessioned op */
 	if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) {
-		sess = rte_cryptodev_sym_session_create(dev_id,
-			init_xform);
+		sess = rte_cryptodev_sym_session_create(sess_mpool);
+
+		rte_cryptodev_sym_session_init(dev_id, sess, init_xform,
+				sess_mpool);
 		if (!sess) {
 			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
 				"FAILED: %s", __LINE__,
@@ -561,8 +564,10 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 
 error_exit:
 	if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) {
-		if (sess)
-			rte_cryptodev_sym_session_free(dev_id, sess);
+		if (sess) {
+			rte_cryptodev_sym_session_clear(dev_id, sess);
+			rte_cryptodev_sym_session_free(sess);
+		}
 		if (cipher_xform)
 			rte_free(cipher_xform);
 		if (auth_xform)
@@ -584,6 +589,7 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 int
 test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	enum blockcipher_test_type test_type)
@@ -675,7 +681,7 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			continue;
 
 		status = test_blockcipher_one_case(tc, mbuf_pool, op_mpool,
-			dev_id, driver_id, test_msg);
+			sess_mpool, dev_id, driver_id, test_msg);
 
 		printf("  %u) TestCase %s %s\n", test_index ++,
 			tc->test_descr, test_msg);
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 22fb420..22b8d20 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -125,6 +125,7 @@ struct blockcipher_test_data {
 int
 test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	enum blockcipher_test_type test_type);
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 9caba87..e21f5e7 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -108,6 +108,8 @@ struct symmetric_session_attrs {
 	uint32_t digest_len;
 };
 
+static struct rte_cryptodev_sym_session *test_crypto_session;
+
 #define ALIGN_POW2_ROUNDUP(num, align) \
 	(((num) + (align) - 1) & ~((align) - 1))
 
@@ -156,18 +158,18 @@ struct crypto_unittest_params {
 	uint8_t *digest;
 };
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo);
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo,
 		enum rte_crypto_aead_algorithm aead_algo);
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
@@ -487,9 +489,11 @@ ut_teardown(void)
 	unsigned i;
 
 	/* free crypto session structure */
-	if (ut_params->sess)
-		rte_cryptodev_sym_session_free(ts_params->dev_id,
+	if (ut_params->sess) {
+		rte_cryptodev_sym_session_clear(ts_params->dev_id,
 				ut_params->sess);
+		rte_cryptodev_sym_session_free(ut_params->sess);
+	}
 
 	/* free crypto operation structure */
 	if (ut_params->op)
@@ -1969,10 +1973,13 @@ test_perf_crypto_qp_vary_burst_size(uint16_t dev_num)
 	ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA256;
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(ts_params->dev_id,
-		&ut_params->cipher_xform);
 
-	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
+
+	rte_cryptodev_sym_session_init(ts_params->dev_id, test_crypto_session,
+			&ut_params->cipher_xform, ts_params->sess_mp);
+
+	TEST_ASSERT_NOT_NULL(test_crypto_session, "Session creation failed");
 
 	/* Generate Crypto op data structure(s) */
 	for (i = 0; i < num_to_submit ; i++) {
@@ -1994,7 +2001,7 @@ test_perf_crypto_qp_vary_burst_size(uint16_t dev_num)
 				rte_crypto_op_alloc(ts_params->op_mpool,
 						RTE_CRYPTO_OP_TYPE_SYMMETRIC);
 
-		rte_crypto_op_attach_sym_session(op, ut_params->sess);
+		rte_crypto_op_attach_sym_session(op, test_crypto_session);
 
 		op->sym->auth.digest.data = ut_params->digest;
 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
@@ -2105,9 +2112,12 @@ test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_snow3g_session(ts_params->dev_id,
+	if (test_perf_create_snow3g_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->key_length, pparams->auth_algo);
+			pparams->key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate Crypto op data structure(s)*/
@@ -2211,7 +2221,10 @@ test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams)
 		rte_pktmbuf_free(c_ops[i]->sym->m_src);
 		rte_crypto_op_free(c_ops[i]);
 	}
-	rte_cryptodev_sym_session_free(ts_params->dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id,
+				sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return TEST_SUCCESS;
 }
@@ -2290,10 +2303,13 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_openssl_session(ts_params->dev_id,
+	if (test_perf_create_openssl_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
 			pparams->key_length, pparams->auth_algo,
-			pparams->aead_algo);
+			pparams->aead_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate Crypto op data structure(s)*/
@@ -2425,7 +2441,9 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 		rte_pktmbuf_free(c_ops[i]->sym->m_src);
 		rte_crypto_op_free(c_ops[i]);
 	}
-	rte_cryptodev_sym_session_free(ts_params->dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return TEST_SUCCESS;
 }
@@ -2452,10 +2470,12 @@ test_perf_armv8_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_armv8_session(ts_params->dev_id,
+	if (test_perf_create_armv8_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->key_length, pparams->auth_algo);
-	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
+			pparams->key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 
 	/* Generate Crypto op data structure(s)*/
 	for (i = 0; i < num_to_submit ; i++) {
@@ -2672,12 +2692,13 @@ static uint8_t snow3g_hash_key[] = {
 		0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E
 };
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_aes_sha_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -2701,33 +2722,42 @@ test_perf_create_aes_sha_session(uint8_t dev_id, enum chain_mode chain,
 		auth_xform.auth.digest_length =
 					get_auth_digest_length(auth_algo);
 	}
+
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	case CIPHER_ONLY:
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
 #define SNOW3G_CIPHER_IV_LENGTH 16
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo, unsigned cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = {0};
 	struct rte_crypto_sym_xform auth_xform = {0};
 
@@ -2755,37 +2785,47 @@ test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 	auth_xform.auth.iv.offset = IV_OFFSET + SNOW3G_CIPHER_IV_LENGTH;
 	auth_xform.auth.iv.length = SNOW3G_CIPHER_IV_LENGTH;
 
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	case CIPHER_ONLY:
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id, &cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_ONLY:
 		auth_xform.next = NULL;
 		/* Create Crypto session */
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int key_len,
 		enum rte_crypto_auth_algorithm auth_algo,
 		enum rte_crypto_aead_algorithm aead_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 	struct rte_crypto_sym_xform aead_xform = { 0 };
@@ -2809,7 +2849,7 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 			cipher_xform.cipher.iv.length = AES_CIPHER_IV_LENGTH;
 			break;
 		default:
-			return NULL;
+			return -1;
 		}
 
 		cipher_xform.cipher.key.length = key_len;
@@ -2824,7 +2864,7 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 			auth_xform.auth.key.data = hmac_sha_key;
 			break;
 		default:
-			return NULL;
+			return -1;
 		}
 
 		auth_xform.auth.key.length =  get_auth_key_max_length(auth_algo);
@@ -2844,37 +2884,45 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 			aead_xform.aead.digest_length = get_aead_digest_length(aead_algo);
 			break;
 		default:
-			return NULL;
+			return -1;
 		}
 
 		aead_xform.aead.key.length = key_len;
 	}
 
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	case AEAD:
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&aead_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &aead_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -2887,7 +2935,7 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		cipher_xform.cipher.key.data = aes_cbc_128_key;
 		break;
 	default:
-		return NULL;
+		return -1;
 	}
 
 	cipher_xform.cipher.key.length = cipher_key_len;
@@ -2901,6 +2949,8 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 
 	auth_xform.auth.digest_length = get_auth_digest_length(auth_algo);
 
+	rte_cryptodev_sym_session_create(ts_params->sess_mp);
+
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
@@ -2908,16 +2958,20 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		/* Encrypt and hash the result */
 		cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Hash encrypted message and decrypt */
 		cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
@@ -3167,9 +3221,12 @@ test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_aes_sha_session(ts_params->dev_id,
+	if (test_perf_create_aes_sha_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->key_length, pparams->auth_algo);
+			pparams->key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3264,7 +3321,9 @@ test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3300,9 +3359,12 @@ test_perf_snow3g(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_snow3g_session(ts_params->dev_id,
+	if (test_perf_create_snow3g_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->key_length, pparams->auth_algo);
+			pparams->key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3429,7 +3491,9 @@ test_perf_snow3g(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3486,10 +3550,13 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_openssl_session(ts_params->dev_id,
+	if (test_perf_create_openssl_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
 			pparams->key_length, pparams->auth_algo,
-			pparams->aead_algo);
+			pparams->aead_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3582,7 +3649,9 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3617,9 +3686,12 @@ test_perf_armv8(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_armv8_session(ts_params->dev_id,
+	if (test_perf_create_armv8_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->key_length, pparams->auth_algo);
+			pparams->key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -4177,7 +4249,7 @@ test_perf_aes_cbc_vary_burst_size(void)
 static struct rte_cryptodev_sym_session *
 test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams)
 {
-	static struct rte_cryptodev_sym_session *sess;
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform aead_xform = { 0 };
 
 	uint8_t aead_key[pparams->session_attrs->key_aead_len];
@@ -4197,9 +4269,12 @@ test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams)
 	aead_xform.aead.add_auth_data_length = pparams->session_attrs->aad_len;
 	aead_xform.aead.digest_length = pparams->session_attrs->digest_len;
 
-	sess = rte_cryptodev_sym_session_create(dev_id,	&aead_xform);
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
+
+	rte_cryptodev_sym_session_init(dev_id, test_crypto_session,
+				&aead_xform, ts_params->sess_mp);
 
-	return sess;
+	return test_crypto_session;
 }
 
 static inline struct rte_crypto_op *
@@ -4418,7 +4493,9 @@ perf_AES_GCM(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < burst; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+
+	rte_cryptodev_sym_session_clear(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return 0;
 }
-- 
2.9.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v4 08/12] cryptodev: remove mempool from session
                         ` (3 preceding siblings ...)
  2017-07-05  5:26  3%     ` [dpdk-dev] [PATCH v4 07/12] cryptodev: remove driver id from session Pablo de Lara
@ 2017-07-05  5:26  4%     ` Pablo de Lara
  2017-07-05  5:26  1%     ` [dpdk-dev] [PATCH v4 09/12] cryptodev: support device independent sessions Pablo de Lara
  2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 10/12] cryptodev: add mempool pointer in queue pair setup Pablo de Lara
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Mempool pointer can be obtained from the object itself,
which means that it is not required to actually store the pointer
in the session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 7 +++----
 lib/librte_cryptodev/rte_cryptodev.h   | 6 ------
 3 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index c3d3b34..74275e0 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -210,6 +210,7 @@ API Changes
     the new parameter ``device id``.
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
+  * Mempool pointer ``mp`` has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index c2123cd..dfced85 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1087,8 +1087,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->mp = mp;
-
 	if (dev->dev_ops->session_initialize)
 		(*dev->dev_ops->session_initialize)(mp, sess);
 }
@@ -1126,7 +1124,7 @@ rte_cryptodev_sym_session_create(uint8_t dev_id,
 				dev_id);
 
 		/* Return session to mempool */
-		rte_mempool_put(sess->mp, _sess);
+		rte_mempool_put(dev->data->session_pool, _sess);
 		return NULL;
 	}
 
@@ -1198,7 +1196,8 @@ rte_cryptodev_sym_session_free(uint8_t dev_id,
 	dev->dev_ops->session_clear(dev, (void *)sess->_private);
 
 	/* Return session to mempool */
-	rte_mempool_put(sess->mp, (void *)sess);
+	struct rte_mempool *mp = rte_mempool_from_obj(sess);
+	rte_mempool_put(mp, (void *)sess);
 
 	return NULL;
 }
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 0fb5608..508c672 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -883,12 +883,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 /** Cryptodev symmetric crypto session */
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
-	struct {
-		struct rte_mempool *mp;
-		/**< Mempool session allocated from */
-	} __rte_aligned(8);
-	/**< Public symmetric session details */
-
 	__extension__ char _private[0];
 	/**< Private session material */
 };
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v4 07/12] cryptodev: remove driver id from session
                         ` (2 preceding siblings ...)
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 06/12] cryptodev: remove device id from crypto session Pablo de Lara
@ 2017-07-05  5:26  3%     ` Pablo de Lara
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 08/12] cryptodev: remove mempool " Pablo de Lara
                       ` (2 subsequent siblings)
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Since crypto session will not be attached to a specific
device or driver, the field driver_id is not required
anymore (only used to check that a session was being
handled by the right device).

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst     | 1 +
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c   | 4 ----
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 9 ++-------
 drivers/crypto/armv8/rte_armv8_pmd.c       | 4 +---
 drivers/crypto/kasumi/rte_kasumi_pmd.c     | 4 ----
 drivers/crypto/null/null_crypto_pmd.c      | 4 +---
 drivers/crypto/openssl/rte_openssl_pmd.c   | 4 +---
 drivers/crypto/qat/qat_crypto.c            | 6 ------
 drivers/crypto/snow3g/rte_snow3g_pmd.c     | 4 ----
 drivers/crypto/zuc/rte_zuc_pmd.c           | 4 ----
 lib/librte_cryptodev/rte_cryptodev.c       | 5 -----
 lib/librte_cryptodev/rte_cryptodev.h       | 2 --
 12 files changed, 6 insertions(+), 45 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index d5fcb74..c3d3b34 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -209,6 +209,7 @@ API Changes
     ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
     the new parameter ``device id``.
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
+  * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index 1ef83fa..d226c23 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -155,10 +155,6 @@ aesni_gcm_get_session(struct aesni_gcm_qp *qp, struct rte_crypto_op *op)
 	struct rte_crypto_sym_op *sym_op = op->sym;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(sym_op->session->driver_id !=
-				cryptodev_driver_id))
-			return sess;
-
 		sess = (struct aesni_gcm_session *)sym_op->session->_private;
 	} else  {
 		void *_sess;
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 4dab849..699779a 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -354,14 +354,9 @@ get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *op)
 {
 	struct aesni_mb_session *sess = NULL;
 
-	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id)) {
-			return NULL;
-		}
-
+	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION)
 		sess = (struct aesni_mb_session *)op->sym->session->_private;
-	} else  {
+	else  {
 		void *_sess = NULL;
 
 		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index 7cce09f..590803a 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -555,9 +555,7 @@ get_session(struct armv8_crypto_qp *qp, struct rte_crypto_op *op)
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
 		/* get existing session */
-		if (likely(op->sym->session != NULL &&
-				op->sym->session->driver_id ==
-				cryptodev_driver_id)) {
+		if (likely(op->sym->session != NULL)) {
 			sess = (struct armv8_crypto_session *)
 				op->sym->session->_private;
 		}
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index 37ca2cc..35afa99 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -166,10 +166,6 @@ kasumi_get_session(struct kasumi_qp *qp, struct rte_crypto_op *op)
 	struct kasumi_session *sess;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct kasumi_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index da62592..27cb9a2 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -98,9 +98,7 @@ get_session(struct null_crypto_qp *qp, struct rte_crypto_op *op)
 	struct rte_crypto_sym_op *sym_op = op->sym;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(sym_op->session == NULL ||
-				sym_op->session->driver_id !=
-					cryptodev_driver_id))
+		if (unlikely(sym_op->session == NULL))
 			return NULL;
 
 		sess = (struct null_crypto_session *)sym_op->session->_private;
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index d497a27..6f5937d 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -558,9 +558,7 @@ get_session(struct openssl_qp *qp, struct rte_crypto_op *op)
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
 		/* get existing session */
-		if (likely(op->sym->session != NULL &&
-				op->sym->session->driver_id ==
-				cryptodev_driver_id))
+		if (likely(op->sym->session != NULL))
 			sess = (struct openssl_session *)
 				op->sym->session->_private;
 	} else  {
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index e2c8e43..d0638a2 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -1072,12 +1072,6 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		return -EINVAL;
 	}
 
-	if (unlikely(op->sym->session->driver_id !=
-			cryptodev_qat_driver_id)) {
-		PMD_DRV_LOG(ERR, "Session was not created for this device");
-		return -EINVAL;
-	}
-
 	ctx = (struct qat_session *)op->sym->session->_private;
 	qat_req = (struct icp_qat_fw_la_bulk_req *)out_msg;
 	rte_mov128((uint8_t *)qat_req, (const uint8_t *)&(ctx->fw_req));
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index 0c65b2d..f28b8d6 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -166,10 +166,6 @@ snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
 	struct snow3g_session *sess;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct snow3g_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index 82710d3..951f1f4 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -165,10 +165,6 @@ zuc_get_session(struct zuc_qp *qp, struct rte_crypto_op *op)
 	struct zuc_session *sess;
 
 	if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct zuc_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index cb773c7..c2123cd 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1087,7 +1087,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->driver_id = dev->driver_id;
 	sess->mp = mp;
 
 	if (dev->dev_ops->session_initialize)
@@ -1194,10 +1193,6 @@ rte_cryptodev_sym_session_free(uint8_t dev_id,
 
 	dev = &rte_crypto_devices[dev_id];
 
-	/* Check the session belongs to this device type */
-	if (sess->driver_id != dev->driver_id)
-		return sess;
-
 	/* Let device implementation clear session material */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_clear, sess);
 	dev->dev_ops->session_clear(dev, (void *)sess->_private);
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index d1e7c2f..0fb5608 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -884,8 +884,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
 	struct {
-		uint8_t driver_id;
-		/** Crypto driver identifier session created on */
 		struct rte_mempool *mp;
 		/**< Mempool session allocated from */
 	} __rte_aligned(8);
-- 
2.9.4

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v4 06/12] cryptodev: remove device id from crypto session
    2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 04/12] cryptodev: do not create session mempool internally Pablo de Lara
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
@ 2017-07-05  5:26  4%     ` Pablo de Lara
  2017-07-05  5:26  3%     ` [dpdk-dev] [PATCH v4 07/12] cryptodev: remove driver id from session Pablo de Lara
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Device id is necessary in the crypto session,
as it was only used for the functions that attach/detach
a session to a queue pair.

Since the session is not going to be attached to a device
anymore, this is field is no longer necessary.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 1 -
 lib/librte_cryptodev/rte_cryptodev.h   | 2 --
 3 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 9b0b4d4..d5fcb74 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -208,6 +208,7 @@ API Changes
   * ``rte_cryptodev_queue_pair_attach_sym_session()`` and
     ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
     the new parameter ``device id``.
+  * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 078e26b..cb773c7 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1087,7 +1087,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->dev_id = dev->data->dev_id;
 	sess->driver_id = dev->driver_id;
 	sess->mp = mp;
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 0ade05e..d1e7c2f 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -884,8 +884,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
 	struct {
-		uint8_t dev_id;
-		/**< Device Id */
 		uint8_t driver_id;
 		/** Crypto driver identifier session created on */
 		struct rte_mempool *mp;
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v4 05/12] cryptodev: change attach session to queue pair API
    2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 04/12] cryptodev: do not create session mempool internally Pablo de Lara
@ 2017-07-05  5:26  4%     ` Pablo de Lara
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 06/12] cryptodev: remove device id from crypto session Pablo de Lara
                       ` (4 subsequent siblings)
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Device id is going to be removed from session,
as the session will be device independent.
Therefore, the functions that attach/dettach a session
to a queue pair need to be updated, to accept the device id
as a parameter, apart from the queue pair id and the session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst |  3 +++
 examples/ipsec-secgw/ipsec.c           |  1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 20 ++++++++++----------
 lib/librte_cryptodev/rte_cryptodev.h   | 10 ++++++----
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 06c5e4e..9b0b4d4 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -205,6 +205,9 @@ API Changes
   * ``rte_cryptodev_configure()`` does not create the session mempool
     for the device anymore.
   * Removed ``session_mp`` from ``rte_cryptodev_config``.
+  * ``rte_cryptodev_queue_pair_attach_sym_session()`` and
+    ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
+    the new parameter ``device id``.
 
 
 ABI Changes
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index ecfd4e8..f09dce9 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -77,6 +77,7 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 	rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id, &cdev_info);
 	if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
 		ret = rte_cryptodev_queue_pair_attach_sym_session(
+				ipsec_ctx->tbl[cdev_id_qp].id,
 				ipsec_ctx->tbl[cdev_id_qp].qp,
 				sa->crypto_session);
 		if (ret < 0) {
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 0778d5f..078e26b 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1136,23 +1136,23 @@ rte_cryptodev_sym_session_create(uint8_t dev_id,
 }
 
 int
-rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *sess)
 {
 	struct rte_cryptodev *dev;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(sess->dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", sess->dev_id);
+	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
+		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
 		return -EINVAL;
 	}
 
-	dev = &rte_crypto_devices[sess->dev_id];
+	dev = &rte_crypto_devices[dev_id];
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_attach_session, 0);
 	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess->_private)) {
 		CDEV_LOG_ERR("dev_id %d failed to attach qp: %d with session",
-				sess->dev_id, qp_id);
+				dev_id, qp_id);
 		return -EPERM;
 	}
 
@@ -1160,23 +1160,23 @@ rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
 }
 
 int
-rte_cryptodev_queue_pair_detach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *sess)
 {
 	struct rte_cryptodev *dev;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(sess->dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", sess->dev_id);
+	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
+		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
 		return -EINVAL;
 	}
 
-	dev = &rte_crypto_devices[sess->dev_id];
+	dev = &rte_crypto_devices[dev_id];
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_detach_session, 0);
 	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess->_private)) {
 		CDEV_LOG_ERR("dev_id %d failed to detach qp: %d from session",
-				sess->dev_id, qp_id);
+				dev_id, qp_id);
 		return -EPERM;
 	}
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 33842f9..0ade05e 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -953,7 +953,8 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id);
 /**
  * Attach queue pair with sym session.
  *
- * @param	qp_id		Queue pair to which session will be attached.
+ * @param	dev_id		Device to which the session will be attached.
+ * @param	qp_id		Queue pair to which the session will be attached.
  * @param	session		Session pointer previously allocated by
  *				*rte_cryptodev_sym_session_create*.
  *
@@ -962,13 +963,14 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id);
  *  - On failure, a negative value.
  */
 int
-rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *session);
 
 /**
  * Detach queue pair with sym session.
  *
- * @param	qp_id		Queue pair to which session is attached.
+ * @param	dev_id		Device to which the session is attached.
+ * @param	qp_id		Queue pair to which the session is attached.
  * @param	session		Session pointer previously allocated by
  *				*rte_cryptodev_sym_session_create*.
  *
@@ -977,7 +979,7 @@ rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
  *  - On failure, a negative value.
  */
 int
-rte_cryptodev_queue_pair_detach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *session);
 
 /**
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v4 04/12] cryptodev: do not create session mempool internally
  @ 2017-07-05  5:26  2%     ` Pablo de Lara
  2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-05  5:26 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Instead of creating the session mempool while configuring
the crypto device, apps will create the mempool themselves.
This way, it gives flexibility to the user to have a single
mempool for all devices (as long as the objects are big
enough to contain the biggest private session size) or
separate mempools for different drivers.

Also, since the mempool is now created outside the
device configuration function, now it needs to be passed
through this function, which will be eventually passed
when setting up the queue pairs, as ethernet devices do.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/main.c                  | 91 +++++++++++++++++++++-------
 doc/guides/rel_notes/release_17_08.rst       |  3 +
 drivers/crypto/scheduler/scheduler_pmd_ops.c | 12 +---
 examples/ipsec-secgw/ipsec-secgw.c           | 42 +++++++++++--
 examples/ipsec-secgw/ipsec.h                 |  2 +
 examples/l2fwd-crypto/main.c                 | 67 +++++++++++++++-----
 lib/librte_cryptodev/rte_cryptodev.c         | 77 ++---------------------
 lib/librte_cryptodev/rte_cryptodev.h         |  9 +--
 test/test/test_cryptodev.c                   | 85 ++++++++++++++++++++------
 test/test/test_cryptodev_perf.c              | 24 +++++++-
 10 files changed, 261 insertions(+), 151 deletions(-)

diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 4dea6d7..45524ad 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -43,6 +43,9 @@
 #include "cperf_test_latency.h"
 #include "cperf_test_verify.h"
 
+#define NUM_SESSIONS 2048
+#define SESS_MEMPOOL_CACHE_SIZE 64
+
 const char *cperf_test_type_strs[] = {
 	[CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
 	[CPERF_TEST_TYPE_LATENCY] = "latency",
@@ -76,9 +79,11 @@ const struct cperf_test cperf_testmap[] = {
 };
 
 static int
-cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
+cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
+			struct rte_mempool *session_pool_socket[])
 {
-	uint8_t cdev_id, enabled_cdev_count = 0, nb_lcores;
+	uint8_t enabled_cdev_count = 0, nb_lcores;
+	unsigned int i;
 	int ret;
 
 	enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
@@ -98,40 +103,78 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
 		return -EINVAL;
 	}
 
-	for (cdev_id = 0; cdev_id < enabled_cdev_count &&
-			cdev_id < RTE_CRYPTO_MAX_DEVS; cdev_id++) {
+	/* Create a mempool shared by all the devices */
+	uint32_t max_sess_size = 0, sess_size;
+
+	for (i = 0; i < enabled_cdev_count &&
+			i < RTE_CRYPTO_MAX_DEVS; i++) {
+		uint8_t cdev_id = enabled_cdevs[i];
+		sess_size = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_size > max_sess_size)
+			max_sess_size = sess_size;
+	}
+
+
+	for (i = 0; i < enabled_cdev_count &&
+			i < RTE_CRYPTO_MAX_DEVS; i++) {
+		uint8_t cdev_id = enabled_cdevs[i];
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
 
 		struct rte_cryptodev_config conf = {
 				.nb_queue_pairs = 1,
-				.socket_id = SOCKET_ID_ANY,
-				.session_mp = {
-					.nb_objs = 2048,
-					.cache_size = 64
-				}
-			};
+				.socket_id = socket_id
+		};
+
 		struct rte_cryptodev_qp_conf qp_conf = {
 				.nb_descriptors = 2048
 		};
 
-		ret = rte_cryptodev_configure(enabled_cdevs[cdev_id], &conf);
+
+		if (session_pool_socket[socket_id] == NULL) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+				"sess_mp_%u", socket_id);
+
+			sess_mp = rte_mempool_create(mp_name,
+						NUM_SESSIONS,
+						max_sess_size,
+						SESS_MEMPOOL_CACHE_SIZE,
+						0, NULL, NULL, NULL,
+						NULL, socket_id,
+						0);
+
+			if (sess_mp == NULL) {
+				printf("Cannot create session pool on socket %d\n",
+					socket_id);
+				return -ENOMEM;
+			}
+
+			printf("Allocated session pool on socket %d\n", socket_id);
+			session_pool_socket[socket_id] = sess_mp;
+		}
+
+		ret = rte_cryptodev_configure(cdev_id, &conf,
+				session_pool_socket[socket_id]);
 		if (ret < 0) {
-			printf("Failed to configure cryptodev %u",
-					enabled_cdevs[cdev_id]);
+			printf("Failed to configure cryptodev %u", cdev_id);
 			return -EINVAL;
 		}
 
-		ret = rte_cryptodev_queue_pair_setup(enabled_cdevs[cdev_id], 0,
-				&qp_conf, SOCKET_ID_ANY);
-			if (ret < 0) {
-				printf("Failed to setup queue pair %u on "
-					"cryptodev %u",	0, cdev_id);
-				return -EINVAL;
-			}
+		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
+				socket_id);
+		if (ret < 0) {
+			printf("Failed to setup queue pair %u on "
+				"cryptodev %u",	0, cdev_id);
+			return -EINVAL;
+		}
 
-		ret = rte_cryptodev_start(enabled_cdevs[cdev_id]);
+		ret = rte_cryptodev_start(cdev_id);
 		if (ret < 0) {
 			printf("Failed to start device %u: error %d\n",
-					enabled_cdevs[cdev_id], ret);
+					cdev_id, ret);
 			return -EPERM;
 		}
 	}
@@ -339,6 +382,7 @@ main(int argc, char **argv)
 	struct cperf_op_fns op_fns;
 
 	void *ctx[RTE_MAX_LCORE] = { };
+	struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
 
 	int nb_cryptodevs = 0;
 	uint8_t cdev_id, i;
@@ -374,7 +418,8 @@ main(int argc, char **argv)
 	if (!opts.silent)
 		cperf_options_dump(&opts);
 
-	nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs);
+	nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs,
+			session_pool_socket);
 	if (nb_cryptodevs < 1) {
 		RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
 				"device type\n");
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index f7aca8e..06c5e4e 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -202,6 +202,9 @@ API Changes
     replacing the previous device type enumeration.
   * Moved crypto device driver names definitions to the particular PMDs.
     These names are not public anymore.
+  * ``rte_cryptodev_configure()`` does not create the session mempool
+    for the device anymore.
+  * Removed ``session_mp`` from ``rte_cryptodev_config``.
 
 
 ABI Changes
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index 90e3734..b9d8973 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -85,10 +85,8 @@ scheduler_attach_init_slave(struct rte_cryptodev *dev)
 /** Configure device */
 static int
 scheduler_pmd_config(struct rte_cryptodev *dev,
-		struct rte_cryptodev_config *config)
+		struct rte_cryptodev_config *config __rte_unused)
 {
-	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
-	uint32_t i;
 	int ret;
 
 	/* although scheduler_attach_init_slave presents multiple times,
@@ -98,14 +96,6 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < sched_ctx->nb_slaves; i++) {
-		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
-
-		ret = rte_cryptodev_configure(slave_dev_id, config);
-		if (ret < 0)
-			break;
-	}
-
 	return ret;
 }
 
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 8cbf6ac..4d6c7ce 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -710,10 +710,12 @@ main_loop(__attribute__((unused)) void *dummy)
 	qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
 	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
 	qconf->inbound.cdev_map = cdev_map_in;
+	qconf->inbound.session_pool = socket_ctx[socket_id].session_pool;
 	qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
 	qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
 	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
 	qconf->outbound.cdev_map = cdev_map_out;
+	qconf->outbound.session_pool = socket_ctx[socket_id].session_pool;
 
 	if (qconf->nb_rx_queue == 0) {
 		RTE_LOG(INFO, IPSEC, "lcore %u has nothing to do\n", lcore_id);
@@ -1238,6 +1240,14 @@ cryptodevs_init(void)
 
 	printf("lcore/cryptodev/qp mappings:\n");
 
+	uint32_t max_sess_sz = 0, sess_sz;
+	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
+		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_sz > max_sess_sz)
+			max_sess_sz = sess_sz;
+	}
+
 	idx = 0;
 	/* Start from last cdev id to give HW priority */
 	for (cdev_id = rte_cryptodev_count() - 1; cdev_id >= 0; cdev_id--) {
@@ -1266,11 +1276,33 @@ cryptodevs_init(void)
 
 		dev_conf.socket_id = rte_cryptodev_socket_id(cdev_id);
 		dev_conf.nb_queue_pairs = qp;
-		dev_conf.session_mp.nb_objs = CDEV_MP_NB_OBJS;
-		dev_conf.session_mp.cache_size = CDEV_MP_CACHE_SZ;
 
-		if (rte_cryptodev_configure(cdev_id, &dev_conf))
-			rte_panic("Failed to initialize crypodev %u\n",
+		if (!socket_ctx[dev_conf.socket_id].session_pool) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+					"sess_mp_%u", dev_conf.socket_id);
+			sess_mp = rte_mempool_create(mp_name,
+					CDEV_MP_NB_OBJS,
+					max_sess_sz,
+					CDEV_MP_CACHE_SZ,
+					0, NULL, NULL, NULL,
+					NULL, dev_conf.socket_id,
+					0);
+			if (sess_mp == NULL)
+				rte_exit(EXIT_FAILURE,
+					"Cannot create session pool on socket %d\n",
+					dev_conf.socket_id);
+			else
+				printf("Allocated session pool on socket %d\n",
+					dev_conf.socket_id);
+			socket_ctx[dev_conf.socket_id].session_pool = sess_mp;
+		}
+
+		if (rte_cryptodev_configure(cdev_id, &dev_conf,
+				socket_ctx[dev_conf.socket_id].session_pool))
+			rte_panic("Failed to initialize cryptodev %u\n",
 					cdev_id);
 
 		qp_conf.nb_descriptors = CDEV_QUEUE_DESC;
@@ -1433,7 +1465,7 @@ main(int32_t argc, char **argv)
 
 	nb_lcores = rte_lcore_count();
 
-	/* Replicate each contex per socket */
+	/* Replicate each context per socket */
 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
 		if (rte_lcore_is_enabled(lcore_id) == 0)
 			continue;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index ccd0aa8..da1fb1b 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -143,6 +143,7 @@ struct ipsec_ctx {
 	uint16_t nb_qps;
 	uint16_t last_qp;
 	struct cdev_qp tbl[MAX_QP_PER_LCORE];
+	struct rte_mempool *session_pool;
 };
 
 struct cdev_key {
@@ -161,6 +162,7 @@ struct socket_ctx {
 	struct rt_ctx *rt_ip4;
 	struct rt_ctx *rt_ip6;
 	struct rte_mempool *mbuf_pool;
+	struct rte_mempool *session_pool;
 };
 
 struct cnt_blk {
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 01f6dfe..9b24e51 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -88,6 +88,8 @@ enum cdev_type {
 #define MAX_KEY_SIZE 128
 #define MAX_PKT_BURST 32
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+#define MAX_SESSIONS 32
+#define SESSION_POOL_CACHE_SIZE 0
 
 #define MAXIMUM_IV_LENGTH	16
 #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
@@ -249,6 +251,7 @@ static const struct rte_eth_conf port_conf = {
 
 struct rte_mempool *l2fwd_pktmbuf_pool;
 struct rte_mempool *l2fwd_crypto_op_pool;
+struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
 
 /* Per-port statistics struct */
 struct l2fwd_port_statistics {
@@ -643,8 +646,7 @@ generate_random_key(uint8_t *key, unsigned length)
 }
 
 static struct rte_cryptodev_sym_session *
-initialize_crypto_session(struct l2fwd_crypto_options *options,
-		uint8_t cdev_id)
+initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 {
 	struct rte_crypto_sym_xform *first_xform;
 
@@ -662,7 +664,6 @@ initialize_crypto_session(struct l2fwd_crypto_options *options,
 		first_xform = &options->auth_xform;
 	}
 
-	/* Setup Cipher Parameters */
 	return rte_cryptodev_sym_session_create(cdev_id, first_xform);
 }
 
@@ -684,6 +685,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 			US_PER_S * BURST_TX_DRAIN_US;
 	struct l2fwd_crypto_params *cparams;
 	struct l2fwd_crypto_params port_cparams[qconf->nb_crypto_devs];
+	struct rte_cryptodev_sym_session *session;
 
 	if (qconf->nb_rx_ports == 0) {
 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
@@ -786,11 +788,13 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 						options->cipher_iv.length;
 		}
 
-		port_cparams[i].session = initialize_crypto_session(options,
+		session = initialize_crypto_session(options,
 				port_cparams[i].dev_id);
+		if (session == NULL)
+			rte_exit(EXIT_FAILURE, "Failed to initialize crypto session\n");
+
+		port_cparams[i].session = session;
 
-		if (port_cparams[i].session == NULL)
-			return;
 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u cryptoid=%u\n", lcore_id,
 				port_cparams[i].dev_id);
 	}
@@ -1921,6 +1925,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 {
 	unsigned int cdev_id, cdev_count, enabled_cdev_count = 0;
 	const struct rte_cryptodev_capabilities *cap;
+	unsigned int sess_sz, max_sess_sz = 0;
 	int retval;
 
 	cdev_count = rte_cryptodev_count();
@@ -1929,18 +1934,22 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		return -1;
 	}
 
+	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
+		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_sz > max_sess_sz)
+			max_sess_sz = sess_sz;
+	}
+
 	for (cdev_id = 0; cdev_id < cdev_count && enabled_cdev_count < nb_ports;
 			cdev_id++) {
 		struct rte_cryptodev_qp_conf qp_conf;
 		struct rte_cryptodev_info dev_info;
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
 
 		struct rte_cryptodev_config conf = {
 			.nb_queue_pairs = 1,
-			.socket_id = SOCKET_ID_ANY,
-			.session_mp = {
-				.nb_objs = 2048,
-				.cache_size = 64
-			}
+			.socket_id = socket_id,
 		};
 
 		if (check_cryptodev_mask(options, (uint8_t)cdev_id))
@@ -1948,6 +1957,35 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 
 		rte_cryptodev_info_get(cdev_id, &dev_info);
 
+		if (session_pool_socket[socket_id] == NULL) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+				"sess_mp_%u", socket_id);
+
+			/*
+			 * Create enough objects for session headers and
+			 * device private data
+			 */
+			sess_mp = rte_mempool_create(mp_name,
+						MAX_SESSIONS * 2,
+						max_sess_sz,
+						SESSION_POOL_CACHE_SIZE,
+						0, NULL, NULL, NULL,
+						NULL, socket_id,
+						0);
+
+			if (sess_mp == NULL) {
+				printf("Cannot create session pool on socket %d\n",
+					socket_id);
+				return -ENOMEM;
+			}
+
+			printf("Allocated session pool on socket %d\n", socket_id);
+			session_pool_socket[socket_id] = sess_mp;
+		}
+
 		/* Set AEAD parameters */
 		if (options->xform_chain == L2FWD_CRYPTO_AEAD) {
 			/* Check if device supports AEAD algo */
@@ -2183,7 +2221,8 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 						cap->sym.auth.digest_size.min;
 		}
 
-		retval = rte_cryptodev_configure(cdev_id, &conf);
+		retval = rte_cryptodev_configure(cdev_id, &conf,
+				session_pool_socket[socket_id]);
 		if (retval < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -1;
@@ -2192,7 +2231,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		qp_conf.nb_descriptors = 2048;
 
 		retval = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				SOCKET_ID_ANY);
+				socket_id);
 		if (retval < 0) {
 			printf("Failed to setup queue pair %u on cryptodev %u",
 					0, cdev_id);
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 5e9f823..0778d5f 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -744,12 +744,9 @@ rte_cryptodev_queue_pair_stop(uint8_t dev_id, uint16_t queue_pair_id)
 
 }
 
-static int
-rte_cryptodev_sym_session_pool_create(struct rte_cryptodev *dev,
-		unsigned nb_objs, unsigned obj_cache_size, int socket_id);
-
 int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
+		struct rte_mempool *session_pool)
 {
 	struct rte_cryptodev *dev;
 	int diag;
@@ -769,6 +766,8 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
 
+	dev->data->session_pool = session_pool;
+
 	/* Setup new number of queue pairs and reconfigure device. */
 	diag = rte_cryptodev_queue_pairs_config(dev, config->nb_queue_pairs,
 			config->socket_id);
@@ -778,14 +777,6 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 		return diag;
 	}
 
-	/* Setup Session mempool for device */
-	diag = rte_cryptodev_sym_session_pool_create(dev,
-			config->session_mp.nb_objs,
-			config->session_mp.cache_size,
-			config->socket_id);
-	if (diag != 0)
-		return diag;
-
 	return (*dev->dev_ops->dev_configure)(dev, config);
 }
 
@@ -1104,66 +1095,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 		(*dev->dev_ops->session_initialize)(mp, sess);
 }
 
-static int
-rte_cryptodev_sym_session_pool_create(struct rte_cryptodev *dev,
-		unsigned nb_objs, unsigned obj_cache_size, int socket_id)
-{
-	char mp_name[RTE_CRYPTODEV_NAME_MAX_LEN];
-	unsigned priv_sess_size;
-
-	unsigned n = snprintf(mp_name, sizeof(mp_name), "cdev_%d_sess_mp",
-			dev->data->dev_id);
-	if (n > sizeof(mp_name)) {
-		CDEV_LOG_ERR("Unable to create unique name for session mempool");
-		return -ENOMEM;
-	}
-
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_get_size, -ENOTSUP);
-	priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
-	if (priv_sess_size == 0) {
-		CDEV_LOG_ERR("%s returned and invalid private session size ",
-						dev->data->name);
-		return -ENOMEM;
-	}
-
-	unsigned elt_size = sizeof(struct rte_cryptodev_sym_session) +
-			priv_sess_size;
-
-	dev->data->session_pool = rte_mempool_lookup(mp_name);
-	if (dev->data->session_pool != NULL) {
-		if ((dev->data->session_pool->elt_size != elt_size) ||
-				(dev->data->session_pool->cache_size <
-				obj_cache_size) ||
-				(dev->data->session_pool->size < nb_objs)) {
-
-			CDEV_LOG_ERR("%s mempool already exists with different"
-					" initialization parameters", mp_name);
-			dev->data->session_pool = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		dev->data->session_pool = rte_mempool_create(
-				mp_name, /* mempool name */
-				nb_objs, /* number of elements*/
-				elt_size, /* element size*/
-				obj_cache_size, /* Cache size*/
-				0, /* private data size */
-				NULL, /* obj initialization constructor */
-				NULL, /* obj initialization constructor arg */
-				NULL, /**< obj constructor*/
-				dev, /* obj constructor arg */
-				socket_id, /* socket id */
-				0); /* flags */
-
-		if (dev->data->session_pool == NULL) {
-			CDEV_LOG_ERR("%s mempool allocation failed", mp_name);
-			return -ENOMEM;
-		}
-	}
-
-	CDEV_LOG_DEBUG("%s mempool created!", mp_name);
-	return 0;
-}
 
 struct rte_cryptodev_sym_session *
 rte_cryptodev_sym_session_create(uint8_t dev_id,
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index f7d248b..33842f9 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -514,11 +514,6 @@ struct rte_cryptodev_config {
 	int socket_id;			/**< Socket to allocate resources on */
 	uint16_t nb_queue_pairs;
 	/**< Number of queue pairs to configure on device */
-
-	struct {
-		uint32_t nb_objs;	/**< Number of objects in mempool */
-		uint32_t cache_size;	/**< l-core object cache size */
-	} session_mp;		/**< Session mempool configuration */
 };
 
 /**
@@ -530,13 +525,15 @@ struct rte_cryptodev_config {
  *
  * @param	dev_id		The identifier of the device to configure.
  * @param	config		The crypto device configuration structure.
+ * @param	session_pool	Pointer to device session mempool
  *
  * @return
  *   - 0: Success, device configured.
  *   - <0: Error code returned by the driver configuration function.
  */
 extern int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config);
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
+		struct rte_mempool *session_pool);
 
 /**
  * Start an device.
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 2a71f72..e5d6c07 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -67,6 +67,8 @@ struct crypto_testsuite_params {
 	struct rte_mempool *mbuf_pool;
 	struct rte_mempool *large_mbuf_pool;
 	struct rte_mempool *op_mpool;
+	struct rte_mempool *session_mpool;
+	struct rte_mempool *slave_session_mpool;
 	struct rte_cryptodev_config conf;
 	struct rte_cryptodev_qp_conf qp_conf;
 
@@ -384,10 +386,23 @@ testsuite_setup(void)
 
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions;
+
+	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+		rte_cryptodev_get_private_session_size(dev_id);
+
+	ts_params->session_mpool = rte_mempool_create(
+				"test_sess_mp",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL,
+				NULL, SOCKET_ID_ANY,
+				0);
+
+	TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
+			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id,
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev %u with %u qps",
 			dev_id, ts_params->conf.nb_queue_pairs);
 
@@ -419,6 +434,16 @@ testsuite_teardown(void)
 		rte_mempool_avail_count(ts_params->op_mpool));
 	}
 
+	/* Free session mempools */
+	if (ts_params->session_mpool != NULL) {
+		rte_mempool_free(ts_params->session_mpool);
+		ts_params->session_mpool = NULL;
+	}
+
+	if (ts_params->slave_session_mpool != NULL) {
+		rte_mempool_free(ts_params->slave_session_mpool);
+		ts_params->slave_session_mpool = NULL;
+	}
 }
 
 static int
@@ -434,10 +459,9 @@ ut_setup(void)
 
 	/* Reconfigure device to default parameters */
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = DEFAULT_NUM_OPS_INFLIGHT;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -520,20 +544,23 @@ test_device_configure_invalid_dev_id(void)
 	/* Stop the device in case it's started so it can be configured */
 	rte_cryptodev_stop(ts_params->valid_devs[dev_id]);
 
-	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	/* invalid dev_id values */
 	dev_id = num_devs;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	dev_id = 0xff;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure:"
 			"invalid dev_num %u", dev_id);
 
@@ -553,7 +580,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 1;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
 
@@ -562,16 +589,17 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
-			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
+			ts_params->valid_devs[0],
+			ts_params->conf.nb_queue_pairs);
 
 
 	/* invalid - zero queue pairs */
 	ts_params->conf.nb_queue_pairs = 0;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -582,7 +610,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = UINT16_MAX;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -593,7 +621,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE + 1;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -622,13 +650,11 @@ test_queue_pair_descriptor_setup(void)
 
 	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
 
-	ts_params->conf.session_mp.nb_objs = dev_info.sym.max_nb_sessions;
-
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf), "Failed to configure cryptodev %u",
+			&ts_params->conf, ts_params->session_mpool),
+			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
-
 	/*
 	 * Test various ring sizes on this device. memzones can't be
 	 * freed so are re-used if ring is released and re-created.
@@ -7683,6 +7709,31 @@ test_scheduler_attach_slave_op(void)
 				RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)))
 			continue;
 
+		/*
+		 * Create a separate mempool for the slaves, as they need different
+		 * session size and then configure them to store the pointer
+		 * to this mempool
+		 */
+		unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(i);
+
+		if (ts_params->slave_session_mpool == NULL) {
+			ts_params->slave_session_mpool = rte_mempool_create(
+				"test_slave_sess_mp",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL, NULL,
+				SOCKET_ID_ANY, 0);
+
+			TEST_ASSERT_NOT_NULL(ts_params->slave_session_mpool,
+					"session mempool allocation failed");
+		}
+
+		TEST_ASSERT_SUCCESS(rte_cryptodev_configure(i,
+				&ts_params->conf, ts_params->slave_session_mpool),
+				"Failed to configure cryptodev %u with %u qps",
+				i, ts_params->conf.nb_queue_pairs);
+
 		ret = rte_cryptodev_scheduler_slave_attach(sched_id,
 				(uint8_t)i);
 
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 7193d18..9caba87 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -53,6 +53,7 @@
 struct crypto_testsuite_params {
 	struct rte_mempool *mbuf_mp;
 	struct rte_mempool *op_mpool;
+	struct rte_mempool *sess_mp;
 
 	uint16_t nb_queue_pairs;
 
@@ -404,10 +405,23 @@ testsuite_setup(void)
 
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions;
+
+	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+		rte_cryptodev_get_private_session_size(ts_params->dev_id);
+
+	ts_params->sess_mp = rte_mempool_create(
+				"test_sess_mp_perf",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL,
+				NULL, SOCKET_ID_ANY,
+				0);
+
+	TEST_ASSERT_NOT_NULL(ts_params->sess_mp,
+			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->dev_id,
-			&ts_params->conf),
+			&ts_params->conf, ts_params->sess_mp),
 			"Failed to configure cryptodev %u",
 			ts_params->dev_id);
 
@@ -436,6 +450,12 @@ testsuite_teardown(void)
 	if (ts_params->op_mpool != NULL)
 		RTE_LOG(DEBUG, USER1, "CRYPTO_PERF_OP POOL count %u\n",
 		rte_mempool_avail_count(ts_params->op_mpool));
+	/* Free session mempool */
+	if (ts_params->sess_mp != NULL) {
+		rte_mempool_free(ts_params->sess_mp);
+		ts_params->sess_mp = NULL;
+	}
+
 }
 
 static int
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

* Re: [dpdk-dev] [PATCH 1/4] mempool: get the external mempool capability
  @ 2017-07-05  6:41  3%     ` santosh
  2017-07-10 13:55  0%       ` Olivier Matz
  0 siblings, 1 reply; 200+ results
From: santosh @ 2017-07-05  6:41 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, thomas, hemant.agrawal, jerin.jacob, bruce.richardson

Hi Olivier,

On Monday 03 July 2017 10:07 PM, Olivier Matz wrote:

> Hi Santosh,
>
> On Wed, 21 Jun 2017 17:32:45 +0000, Santosh Shukla <santosh.shukla@caviumnetworks.com> wrote:
>> Allow external mempool to advertise its capability.
>> A handler been introduced called rte_mempool_ops_get_hw_cap.
>> - Upon ->get_hw_cap call, mempool driver will advertise
>> capability by returning flag.
>> - Common layer updates flag value in 'mp->flags'.
>>
>> Signed-off-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
>> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> I guess you've already seen the compilation issue when shared libs
> are enabled:
> http://dpdk.org/dev/patchwork/patch/25603
>
Yes, Will fix in v2.

>
>> ---
>>  lib/librte_mempool/rte_mempool.c           |  5 +++++
>>  lib/librte_mempool/rte_mempool.h           | 20 ++++++++++++++++++++
>>  lib/librte_mempool/rte_mempool_ops.c       | 14 ++++++++++++++
>>  lib/librte_mempool/rte_mempool_version.map |  7 +++++++
>>  4 files changed, 46 insertions(+)
>>
>> diff --git a/lib/librte_mempool/rte_mempool.c b/lib/librte_mempool/rte_mempool.c
>> index f65310f60..045baef45 100644
>> --- a/lib/librte_mempool/rte_mempool.c
>> +++ b/lib/librte_mempool/rte_mempool.c
>> @@ -527,6 +527,11 @@ rte_mempool_populate_default(struct rte_mempool *mp)
>>  	if (mp->nb_mem_chunks != 0)
>>  		return -EEXIST;
>>  
>> +	/* Get external mempool capability */
>> +	ret = rte_mempool_ops_get_hw_cap(mp);
> "hw" can be removed since some handlers are software (the other occurences
> of hw should be removed too)
>
> "capabilities" is clearer than "cap"
>
> So I suggest rte_mempool_ops_get_capabilities() instead
> With this name, the comment above becomes overkill...

ok. Will take care in v2.

>> +	if (ret != -ENOENT)
> -ENOTSUP looks more appropriate (like in ethdev)
>
imo: -ENOENT tell that driver has no new entry for capability flag(mp->flag).
But no strong opinion for -ENOTSUP.

>> +		mp->flags |= ret;
> I'm wondering if these capability flags should be mixed with
> other mempool flags.
>
> We can maybe remove this code above and directly call
> rte_mempool_ops_get_capabilities() when we need to get them.

0) Treating this capability flag different vs existing RTE_MEMPOLL_F would
result to adding new flag entry in struct rte_mempool { .drv_flag} for example.
1) That new flag entry will break ABI.
2) In-fact application can benefit this capability flag by explicitly setting
in pool create api (e.g: rte_mempool_create_empty (, , , , , _F_POOL_CONGIG | F_BLK_SZ_ALIGNED)).

Those flag use-case not limited till driver scope, application too can benefit.

3) Also provided that we have space in RTE_MEMPOOL_F_XX area, so adding couple of
more bit won't impact design or effect pool creation sequence.

4) By calling _ops_get_capability() at _populate_default() area would address issues pointed by
you at patch [3/4]. Will explain details on ' how' in respective patch [3/4].

5) Above all, Intent is to make sure that common layer managing capability flag 
on behalf of driver or application.

>
>
>> +
>>  	if (rte_xen_dom0_supported()) {
>>  		pg_sz = RTE_PGSIZE_2M;
>>  		pg_shift = rte_bsf32(pg_sz);
>> diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
>> index a65f1a79d..c3cdc77e4 100644
>> --- a/lib/librte_mempool/rte_mempool.h
>> +++ b/lib/librte_mempool/rte_mempool.h
>> @@ -390,6 +390,12 @@ typedef int (*rte_mempool_dequeue_t)(struct rte_mempool *mp,
>>   */
>>  typedef unsigned (*rte_mempool_get_count)(const struct rte_mempool *mp);
>>  
>> +/**
>> + * Get the mempool hw capability.
>> + */
>> +typedef int (*rte_mempool_get_hw_cap_t)(struct rte_mempool *mp);
>> +
>> +
> If possible, use "const struct rte_mempool *mp"
>
> Since flags are unsigned, I would also prefer a function returning an
> int (0 on success, negative on error) and writing to an unsigned pointer
> provided by the user.
>
confused? mp->flag is int not unsigned. and We're returning
-ENOENT/-ENOTSUP at error and positive value in-case driver supports capability.

>
>>  /** Structure defining mempool operations structure */
>>  struct rte_mempool_ops {
>>  	char name[RTE_MEMPOOL_OPS_NAMESIZE]; /**< Name of mempool ops struct. */
>> @@ -398,6 +404,7 @@ struct rte_mempool_ops {
>>  	rte_mempool_enqueue_t enqueue;   /**< Enqueue an object. */
>>  	rte_mempool_dequeue_t dequeue;   /**< Dequeue an object. */
>>  	rte_mempool_get_count get_count; /**< Get qty of available objs. */
>> +	rte_mempool_get_hw_cap_t get_hw_cap; /**< Get hw capability */
>>  } __rte_cache_aligned;
>>  
>>  #define RTE_MEMPOOL_MAX_OPS_IDX 16  /**< Max registered ops structs */
>> @@ -509,6 +516,19 @@ rte_mempool_ops_enqueue_bulk(struct rte_mempool *mp, void * const *obj_table,
>>  unsigned
>>  rte_mempool_ops_get_count(const struct rte_mempool *mp);
>>  
>> +
>> +/**
>> + * @internal wrapper for mempool_ops get_hw_cap callback.
>> + *
>> + * @param mp
>> + *   Pointer to the memory pool.
>> + * @return
>> + *   - On success; Valid capability flag.
>> + *   - On failure; -ENOENT error code i.e. implementation not supported.
> The possible values for the capability flags should be better described.
>
ok,

>> + */
>> +int
>> +rte_mempool_ops_get_hw_cap(struct rte_mempool *mp);
>> +
>>  /**
>>   * @internal wrapper for mempool_ops free callback.
>>   *
>> diff --git a/lib/librte_mempool/rte_mempool_ops.c b/lib/librte_mempool/rte_mempool_ops.c
>> index 5f24de250..3a09f5d32 100644
>> --- a/lib/librte_mempool/rte_mempool_ops.c
>> +++ b/lib/librte_mempool/rte_mempool_ops.c
>> @@ -85,6 +85,7 @@ rte_mempool_register_ops(const struct rte_mempool_ops *h)
>>  	ops->enqueue = h->enqueue;
>>  	ops->dequeue = h->dequeue;
>>  	ops->get_count = h->get_count;
>> +	ops->get_hw_cap = h->get_hw_cap;
>>  
>>  	rte_spinlock_unlock(&rte_mempool_ops_table.sl);
>>  
>> @@ -123,6 +124,19 @@ rte_mempool_ops_get_count(const struct rte_mempool *mp)
>>  	return ops->get_count(mp);
>>  }
>>  
>> +/* wrapper to get external mempool capability. */
>> +int
>> +rte_mempool_ops_get_hw_cap(struct rte_mempool *mp)
>> +{
>> +	struct rte_mempool_ops *ops;
>> +
>> +	ops = rte_mempool_get_ops(mp->ops_index);
>> +	if (ops->get_hw_cap)
>> +		return ops->get_hw_cap(mp);
>> +
>> +	return -ENOENT;
>> +}
>> +
> RTE_FUNC_PTR_OR_ERR_RET() can be used

in v2.

>
>>  /* sets mempool ops previously registered by rte_mempool_register_ops. */
>>  int
>>  rte_mempool_set_ops_byname(struct rte_mempool *mp, const char *name,
>> diff --git a/lib/librte_mempool/rte_mempool_version.map b/lib/librte_mempool/rte_mempool_version.map
>> index f9c079447..d92334672 100644
>> --- a/lib/librte_mempool/rte_mempool_version.map
>> +++ b/lib/librte_mempool/rte_mempool_version.map
>> @@ -41,3 +41,10 @@ DPDK_16.07 {
>>  	rte_mempool_set_ops_byname;
>>  
>>  } DPDK_2.0;
>> +
>> +DPDK_17.08 {
>> +	global:
>> +
>> +	rte_mempool_ops_get_hw_cap;
>> +
>> +} DPDK_17.05;
>
> /usr/bin/ld: unable to find version dependency `DPDK_17.05'
> This should be 16.07 here
>
Will fix that in v2.
Thanks.

>

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v1] doc: add libnuma to the dpdk dependencies
@ 2017-07-03 13:21  4% John McNamara
  0 siblings, 0 replies; 200+ results
From: John McNamara @ 2017-07-03 13:21 UTC (permalink / raw)
  To: dev; +Cc: John McNamara

Add libnuma as a dependency to the Linux Getting Started Guide
since it is a new requirement in DPDK 17.08+.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/linux_gsg/sys_reqs.rst | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/doc/guides/linux_gsg/sys_reqs.rst b/doc/guides/linux_gsg/sys_reqs.rst
index 3a28c9e..af7a931 100644
--- a/doc/guides/linux_gsg/sys_reqs.rst
+++ b/doc/guides/linux_gsg/sys_reqs.rst
@@ -50,7 +50,7 @@ for more information on the required changes.
 Compilation of the DPDK
 -----------------------
 
-**Required Tools:**
+**Required Tools and Libraries:**
 
 .. note::
 
@@ -84,6 +84,8 @@ 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+.
 
+*   libnuma-devel - library for handling NUMA (Non Uniform Memory Access).
+
 *   Python, version 2.7+ or 3.2+, to use various helper scripts included in the DPDK package.
 
 
-- 
2.7.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v3 10/12] cryptodev: add mempool pointer in queue pair setup
                       ` (5 preceding siblings ...)
  2017-07-02 15:57  1%   ` [dpdk-dev] [PATCH v3 09/12] cryptodev: support device independent sessions Pablo de Lara
@ 2017-07-02 15:57  2%   ` Pablo de Lara
    7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

The session mempool pointer is needed in each queue pair,
if session-less operations are being handled.
Therefore, the API is changed to accept this parameter,
as the session mempool is created outside the
device configuration function, similar to what ethdev
does with the rx queues.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/main.c                    | 18 ++++----
 doc/guides/rel_notes/release_17_08.rst         |  2 +-
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c   |  4 +-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c |  4 +-
 drivers/crypto/armv8/rte_armv8_pmd_ops.c       |  4 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c    |  3 +-
 drivers/crypto/kasumi/rte_kasumi_pmd_ops.c     |  4 +-
 drivers/crypto/null/null_crypto_pmd_ops.c      |  4 +-
 drivers/crypto/openssl/rte_openssl_pmd_ops.c   |  4 +-
 drivers/crypto/qat/qat_crypto.h                |  3 +-
 drivers/crypto/qat/qat_qp.c                    |  2 +-
 drivers/crypto/scheduler/scheduler_pmd_ops.c   | 13 ++++--
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c     |  4 +-
 drivers/crypto/zuc/rte_zuc_pmd_ops.c           |  4 +-
 examples/ipsec-secgw/ipsec-secgw.c             |  6 +--
 examples/l2fwd-crypto/main.c                   |  5 +--
 lib/librte_cryptodev/rte_cryptodev.c           | 11 +++--
 lib/librte_cryptodev/rte_cryptodev.h           |  9 ++--
 lib/librte_cryptodev/rte_cryptodev_pmd.h       |  3 +-
 test/test/test_cryptodev.c                     | 58 +++++++++++++++-----------
 test/test/test_cryptodev_perf.c                |  5 ++-
 21 files changed, 93 insertions(+), 77 deletions(-)

diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index eb2737e..f325b11 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -123,20 +123,20 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
 			session_pool_socket[socket_id] = sess_mp;
 		}
 
-		ret = rte_cryptodev_configure(cdev_id, &conf,
-				session_pool_socket[socket_id]);
+		ret = rte_cryptodev_configure(cdev_id, &conf);
 		if (ret < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -EINVAL;
 		}
 
-		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				socket_id);
-		if (ret < 0) {
-			printf("Failed to setup queue pair %u on "
-				"cryptodev %u",	0, cdev_id);
-			return -EINVAL;
-		}
+		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0,
+				&qp_conf, socket_id,
+				session_pool_socket[socket_id]);
+			if (ret < 0) {
+				printf("Failed to setup queue pair %u on "
+					"cryptodev %u",	0, cdev_id);
+				return -EINVAL;
+			}
 
 		ret = rte_cryptodev_start(cdev_id);
 		if (ret < 0) {
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 463b616..8630b40 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -170,7 +170,7 @@ API Changes
   * Mempool pointer ``mp`` has been removed from ``rte_cryptodev_sym_session`` structure.
   * Replaced ``private`` marker with array of pointers to private data sessions
     ``sess_private_data`` in ``rte_cryptodev_sym_session``
-
+  * Added new field ``session_pool`` to ``rte_cryptodev_queue_pair_setup()``.
 
 ABI Changes
 -----------
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
index 0b063fd..d47a041 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
@@ -244,7 +244,7 @@ aesni_gcm_pmd_qp_create_processed_pkts_ring(struct aesni_gcm_qp *qp,
 static int
 aesni_gcm_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct aesni_gcm_qp *qp = NULL;
 
@@ -269,7 +269,7 @@ aesni_gcm_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_pkts == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
index fda8296..1216e56 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -397,7 +397,7 @@ aesni_mb_pmd_qp_create_processed_ops_ring(struct aesni_mb_qp *qp,
 static int
 aesni_mb_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct aesni_mb_qp *qp = NULL;
 	struct aesni_mb_private *internals = dev->data->dev_private;
@@ -426,7 +426,7 @@ aesni_mb_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->ingress_queue == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
index 3db420b..735116f 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
@@ -247,7 +247,7 @@ armv8_crypto_pmd_qp_create_processed_ops_ring(struct armv8_crypto_qp *qp,
 static int
 armv8_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct armv8_crypto_qp *qp = NULL;
 
@@ -272,7 +272,7 @@ armv8_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 0a85690..bab2b4e 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -660,7 +660,8 @@ dpaa2_sec_queue_pair_release(struct rte_cryptodev *dev, uint16_t queue_pair_id)
 static int
 dpaa2_sec_queue_pair_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		__rte_unused const struct rte_cryptodev_qp_conf *qp_conf,
-		__rte_unused int socket_id)
+		__rte_unused int socket_id,
+		__rte_unused struct rte_mempool *session_pool)
 {
 	struct dpaa2_sec_dev_private *priv = dev->data->dev_private;
 	struct dpaa2_sec_qp *qp;
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
index d590b91..2805e6f 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
@@ -223,7 +223,7 @@ kasumi_pmd_qp_create_processed_ops_ring(struct kasumi_qp *qp,
 static int
 kasumi_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct kasumi_qp *qp = NULL;
 
@@ -248,7 +248,7 @@ kasumi_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/null/null_crypto_pmd_ops.c b/drivers/crypto/null/null_crypto_pmd_ops.c
index 04147fe..7d0ac2d 100644
--- a/drivers/crypto/null/null_crypto_pmd_ops.c
+++ b/drivers/crypto/null/null_crypto_pmd_ops.c
@@ -215,7 +215,7 @@ null_crypto_pmd_qp_create_processed_pkts_ring(struct null_crypto_qp *qp,
 static int
 null_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct null_crypto_private *internals = dev->data->dev_private;
 	struct null_crypto_qp *qp;
@@ -258,7 +258,7 @@ null_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		goto qp_setup_cleanup;
 	}
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 005855b..d8eb335 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -602,7 +602,7 @@ openssl_pmd_qp_create_processed_ops_ring(struct openssl_qp *qp,
 static int
 openssl_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct openssl_qp *qp = NULL;
 
@@ -627,7 +627,7 @@ openssl_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->stats, 0, sizeof(qp->stats));
 
diff --git a/drivers/crypto/qat/qat_crypto.h b/drivers/crypto/qat/qat_crypto.h
index d5466c2..65af962 100644
--- a/drivers/crypto/qat/qat_crypto.h
+++ b/drivers/crypto/qat/qat_crypto.h
@@ -103,7 +103,8 @@ void qat_crypto_sym_stats_get(struct rte_cryptodev *dev,
 void qat_crypto_sym_stats_reset(struct rte_cryptodev *dev);
 
 int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
-	const struct rte_cryptodev_qp_conf *rx_conf, int socket_id);
+	const struct rte_cryptodev_qp_conf *rx_conf, int socket_id,
+	struct rte_mempool *session_pool);
 int qat_crypto_sym_qp_release(struct rte_cryptodev *dev,
 	uint16_t queue_pair_id);
 
diff --git a/drivers/crypto/qat/qat_qp.c b/drivers/crypto/qat/qat_qp.c
index 3921c2e..2b2ab42 100644
--- a/drivers/crypto/qat/qat_qp.c
+++ b/drivers/crypto/qat/qat_qp.c
@@ -134,7 +134,7 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size,
 
 int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
 	const struct rte_cryptodev_qp_conf *qp_conf,
-	int socket_id)
+	int socket_id, struct rte_mempool *session_pool __rte_unused)
 {
 	struct qat_qp *qp;
 	struct rte_pci_device *pci_dev;
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index 6e37efc..b434244 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -101,8 +101,7 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
 		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
 
-		ret = rte_cryptodev_configure(slave_dev_id, config,
-				dev->data->session_pool);
+		ret = rte_cryptodev_configure(slave_dev_id, config);
 		if (ret < 0)
 			break;
 	}
@@ -400,7 +399,8 @@ scheduler_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
 /** Setup a queue pair */
 static int
 scheduler_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
-	const struct rte_cryptodev_qp_conf *qp_conf, int socket_id)
+	const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+	struct rte_mempool *session_pool)
 {
 	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
 	struct scheduler_qp_ctx *qp_ctx;
@@ -422,8 +422,13 @@ scheduler_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
 		uint8_t slave_id = sched_ctx->slaves[i].dev_id;
 
+		/*
+		 * All slaves will share the same session mempool
+		 * for session-less operations, so the objects
+		 * must be big enough for all the drivers used.
+		 */
 		ret = rte_cryptodev_queue_pair_setup(slave_id, qp_id,
-				qp_conf, socket_id);
+				qp_conf, socket_id, session_pool);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
index 1967409..04151bc 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -220,7 +220,7 @@ snow3g_pmd_qp_create_processed_ops_ring(struct snow3g_qp *qp,
 static int
 snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct snow3g_qp *qp = NULL;
 
@@ -245,7 +245,7 @@ snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/drivers/crypto/zuc/rte_zuc_pmd_ops.c b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
index cdc783f..7cf6542 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd_ops.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
@@ -220,7 +220,7 @@ zuc_pmd_qp_create_processed_ops_ring(struct zuc_qp *qp,
 static int
 zuc_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 		const struct rte_cryptodev_qp_conf *qp_conf,
-		 int socket_id)
+		int socket_id, struct rte_mempool *session_pool)
 {
 	struct zuc_qp *qp = NULL;
 
@@ -245,7 +245,7 @@ zuc_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
 	if (qp->processed_ops == NULL)
 		goto qp_setup_cleanup;
 
-	qp->sess_mp = dev->data->session_pool;
+	qp->sess_mp = session_pool;
 
 	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
 
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 708eadd..11f0966 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1299,15 +1299,15 @@ cryptodevs_init(void)
 			socket_ctx[dev_conf.socket_id].session_pool = sess_mp;
 		}
 
-		if (rte_cryptodev_configure(cdev_id, &dev_conf,
-				socket_ctx[dev_conf.socket_id].session_pool))
+		if (rte_cryptodev_configure(cdev_id, &dev_conf))
 			rte_panic("Failed to initialize cryptodev %u\n",
 					cdev_id);
 
 		qp_conf.nb_descriptors = CDEV_QUEUE_DESC;
 		for (qp = 0; qp < dev_conf.nb_queue_pairs; qp++)
 			if (rte_cryptodev_queue_pair_setup(cdev_id, qp,
-						&qp_conf, dev_conf.socket_id))
+					&qp_conf, dev_conf.socket_id,
+					socket_ctx[dev_conf.socket_id].session_pool))
 				rte_panic("Failed to setup queue %u for "
 						"cdev_id %u\n",	0, cdev_id);
 
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 9ec8e6f..5dcbab9 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -1846,8 +1846,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 						cap->sym.auth.digest_size.min;
 		}
 
-		retval = rte_cryptodev_configure(cdev_id, &conf,
-				session_pool_socket[socket_id]);
+		retval = rte_cryptodev_configure(cdev_id, &conf);
 		if (retval < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -1;
@@ -1856,7 +1855,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		qp_conf.nb_descriptors = 2048;
 
 		retval = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				socket_id);
+				socket_id, session_pool_socket[socket_id]);
 		if (retval < 0) {
 			printf("Failed to setup queue pair %u on cryptodev %u",
 					0, cdev_id);
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index b304a7b..74399bb 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -686,8 +686,7 @@ rte_cryptodev_queue_pair_stop(uint8_t dev_id, uint16_t queue_pair_id)
 }
 
 int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
-		struct rte_mempool *session_pool)
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 {
 	struct rte_cryptodev *dev;
 	int diag;
@@ -707,8 +706,6 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
 
-	dev->data->session_pool = session_pool;
-
 	/* Setup new number of queue pairs and reconfigure device. */
 	diag = rte_cryptodev_queue_pairs_config(dev, config->nb_queue_pairs,
 			config->socket_id);
@@ -820,7 +817,9 @@ rte_cryptodev_close(uint8_t dev_id)
 
 int
 rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
-		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id)
+		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+		struct rte_mempool *session_pool)
+
 {
 	struct rte_cryptodev *dev;
 
@@ -844,7 +843,7 @@ rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_pair_setup, -ENOTSUP);
 
 	return (*dev->dev_ops->queue_pair_setup)(dev, queue_pair_id, qp_conf,
-			socket_id);
+			socket_id, session_pool);
 }
 
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 2204982..aa68095 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -439,15 +439,13 @@ struct rte_cryptodev_config {
  *
  * @param	dev_id		The identifier of the device to configure.
  * @param	config		The crypto device configuration structure.
- * @param	session_pool	Pointer to device session mempool
  *
  * @return
  *   - 0: Success, device configured.
  *   - <0: Error code returned by the driver configuration function.
  */
 extern int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
-		struct rte_mempool *session_pool);
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config);
 
 /**
  * Start an device.
@@ -506,6 +504,8 @@ rte_cryptodev_close(uint8_t dev_id);
  *				*SOCKET_ID_ANY* if there is no NUMA constraint
  *				for the DMA memory allocated for the receive
  *				queue pair.
+ * @param	session_pool	Pointer to device session mempool, used
+ *				for session-less operations.
  *
  * @return
  *   - 0: Success, queue pair correctly set up.
@@ -513,7 +513,8 @@ rte_cryptodev_close(uint8_t dev_id);
  */
 extern int
 rte_cryptodev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
-		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id);
+		const struct rte_cryptodev_qp_conf *qp_conf, int socket_id,
+		struct rte_mempool *session_pool);
 
 /**
  * Start a specified queue pair of a device. It is used
diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
index d7cefd8..4e49e87 100644
--- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
+++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
@@ -207,12 +207,13 @@ typedef int (*cryptodev_queue_pair_stop_t)(struct rte_cryptodev *dev,
  * @param	qp_id		Queue Pair Index
  * @param	qp_conf		Queue configuration structure
  * @param	socket_id	Socket Index
+ * @param	session_pool	Pointer to device session mempool
  *
  * @return	Returns 0 on success.
  */
 typedef int (*cryptodev_queue_pair_setup_t)(struct rte_cryptodev *dev,
 		uint16_t qp_id,	const struct rte_cryptodev_qp_conf *qp_conf,
-		int socket_id);
+		int socket_id, struct rte_mempool *session_pool);
 
 /**
  * Release memory resources allocated by given queue pair.
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 9d08eb8..bf117b3 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -401,7 +401,7 @@ testsuite_setup(void)
 			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id,
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u with %u qps",
 			dev_id, ts_params->conf.nb_queue_pairs);
 
@@ -410,7 +410,8 @@ testsuite_setup(void)
 	for (qp_id = 0; qp_id < info.max_nb_queue_pairs; qp_id++) {
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			dev_id, qp_id, &ts_params->qp_conf,
-			rte_cryptodev_socket_id(dev_id)),
+			rte_cryptodev_socket_id(dev_id),
+			ts_params->session_mpool),
 			"Failed to setup queue pair %u on cryptodev %u",
 			qp_id, dev_id);
 	}
@@ -455,7 +456,7 @@ ut_setup(void)
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -463,7 +464,8 @@ ut_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0], qp_id,
 			&ts_params->qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed to setup queue pair %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
 	}
@@ -537,23 +539,20 @@ test_device_configure_invalid_dev_id(void)
 	/* Stop the device in case it's started so it can be configured */
 	rte_cryptodev_stop(ts_params->valid_devs[dev_id]);
 
-	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	/* invalid dev_id values */
 	dev_id = num_devs;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	dev_id = 0xff;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
-				ts_params->session_mpool),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
 			"Failed test for rte_cryptodev_configure:"
 			"invalid dev_num %u", dev_id);
 
@@ -573,7 +572,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 1;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
 
@@ -582,7 +581,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0],
 			ts_params->conf.nb_queue_pairs);
@@ -592,7 +591,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 0;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -603,7 +602,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = UINT16_MAX;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -614,7 +613,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE + 1;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -644,7 +643,7 @@ test_queue_pair_descriptor_setup(void)
 	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf, ts_params->session_mpool),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -658,7 +657,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for "
 				"rte_cryptodev_queue_pair_setup: num_inflights "
 				"%u on qp %u on cryptodev %u",
@@ -672,7 +672,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for"
 				" rte_cryptodev_queue_pair_setup: num_inflights"
 				" %u on qp %u on cryptodev %u",
@@ -686,7 +687,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for "
 				"rte_cryptodev_queue_pair_setup: num_inflights"
 				" %u on qp %u on cryptodev %u",
@@ -701,7 +703,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -716,7 +719,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -730,7 +734,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Failed test for"
 				" rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -745,7 +750,8 @@ test_queue_pair_descriptor_setup(void)
 		TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 				ts_params->valid_devs[0], qp_id, &qp_conf,
 				rte_cryptodev_socket_id(
-						ts_params->valid_devs[0])),
+						ts_params->valid_devs[0]),
+				ts_params->session_mpool),
 				"Unexpectedly passed test for "
 				"rte_cryptodev_queue_pair_setup:"
 				"num_inflights %u on qp %u on cryptodev %u",
@@ -761,7 +767,8 @@ test_queue_pair_descriptor_setup(void)
 	TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0],
 			qp_id, &qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed test for rte_cryptodev_queue_pair_setup:"
 			"invalid qp %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
@@ -771,7 +778,8 @@ test_queue_pair_descriptor_setup(void)
 	TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup(
 			ts_params->valid_devs[0],
 			qp_id, &qp_conf,
-			rte_cryptodev_socket_id(ts_params->valid_devs[0])),
+			rte_cryptodev_socket_id(ts_params->valid_devs[0]),
+			ts_params->session_mpool),
 			"Failed test for rte_cryptodev_queue_pair_setup:"
 			"invalid qp %u on cryptodev %u",
 			qp_id, ts_params->valid_devs[0]);
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 68c5fdd..8a40381 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -413,7 +413,7 @@ testsuite_setup(void)
 			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->dev_id,
-			&ts_params->conf, ts_params->sess_mp),
+			&ts_params->conf),
 			"Failed to configure cryptodev %u",
 			ts_params->dev_id);
 
@@ -423,7 +423,8 @@ testsuite_setup(void)
 		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
 			ts_params->dev_id, qp_id,
 				&ts_params->qp_conf,
-				rte_cryptodev_socket_id(ts_params->dev_id)),
+				rte_cryptodev_socket_id(ts_params->dev_id),
+				ts_params->sess_mp),
 				"Failed to setup queue pair %u on cryptodev %u",
 				qp_id, ts_params->dev_id);
 	}
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

* [dpdk-dev] [PATCH v3 09/12] cryptodev: support device independent sessions
                       ` (4 preceding siblings ...)
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 08/12] cryptodev: remove mempool " Pablo de Lara
@ 2017-07-02 15:57  1%   ` Pablo de Lara
  2017-07-02 15:57  2%   ` [dpdk-dev] [PATCH v3 10/12] cryptodev: add mempool pointer in queue pair setup Pablo de Lara
    7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Change crypto device's session management to make it
device independent and simplify architecture when session
is intended to be used on more than one device.

Sessions private data is agnostic to underlying device
by adding an indirection in the sessions private data
using the crypto driver identifier.
A single session can contain indirections to multiple device types.

New function rte_cryptodev_sym_session_init has been created,
to initialize the private data per driver to be used on
a same session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/cperf.h                       |   5 +-
 app/test-crypto-perf/cperf_ops.c                   |  30 +-
 app/test-crypto-perf/cperf_ops.h                   |   1 +
 app/test-crypto-perf/cperf_test_latency.c          |   7 +-
 app/test-crypto-perf/cperf_test_latency.h          |   5 +-
 app/test-crypto-perf/cperf_test_throughput.c       |   7 +-
 app/test-crypto-perf/cperf_test_throughput.h       |   5 +-
 app/test-crypto-perf/cperf_test_verify.c           |   7 +-
 app/test-crypto-perf/cperf_test_verify.h           |   5 +-
 app/test-crypto-perf/main.c                        |   8 +-
 doc/guides/rel_notes/release_17_08.rst             |   4 +
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c           |  60 ++--
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c       |  28 +-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c         |  32 +-
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c     |  27 +-
 drivers/crypto/armv8/rte_armv8_pmd.c               |  37 ++-
 drivers/crypto/armv8/rte_armv8_pmd_ops.c           |  31 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c        |  45 ++-
 drivers/crypto/kasumi/rte_kasumi_pmd.c             |  42 ++-
 drivers/crypto/kasumi/rte_kasumi_pmd_ops.c         |  28 +-
 drivers/crypto/null/null_crypto_pmd.c              |  41 ++-
 drivers/crypto/null/null_crypto_pmd_ops.c          |  31 +-
 drivers/crypto/openssl/rte_openssl_pmd.c           |  36 ++-
 drivers/crypto/openssl/rte_openssl_pmd_ops.c       |  28 +-
 drivers/crypto/qat/qat_crypto.c                    |  68 ++--
 drivers/crypto/qat/qat_crypto.h                    |  12 +-
 drivers/crypto/qat/rte_qat_cryptodev.c             |   1 -
 drivers/crypto/scheduler/scheduler_failover.c      |  45 +--
 .../crypto/scheduler/scheduler_pkt_size_distr.c    |  18 --
 drivers/crypto/scheduler/scheduler_pmd_ops.c       |  87 +++---
 drivers/crypto/scheduler/scheduler_pmd_private.h   |   4 -
 drivers/crypto/scheduler/scheduler_roundrobin.c    |  41 ---
 drivers/crypto/snow3g/rte_snow3g_pmd.c             |  42 ++-
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c         |  28 +-
 drivers/crypto/zuc/rte_zuc_pmd.c                   |  38 ++-
 drivers/crypto/zuc/rte_zuc_pmd_ops.c               |  28 +-
 examples/ipsec-secgw/ipsec-secgw.c                 |   3 +-
 examples/ipsec-secgw/ipsec.c                       |   7 +-
 examples/l2fwd-crypto/main.c                       |  17 +-
 lib/librte_cryptodev/rte_cryptodev.c               | 127 ++++----
 lib/librte_cryptodev/rte_cryptodev.h               |  65 ++--
 lib/librte_cryptodev/rte_cryptodev_pmd.h           |  24 +-
 lib/librte_cryptodev/rte_cryptodev_version.map     |   2 +
 test/test/test_cryptodev.c                         | 344 ++++++++++++++-------
 test/test/test_cryptodev_blockcipher.c             |  15 +-
 test/test/test_cryptodev_blockcipher.h             |   1 +
 test/test/test_cryptodev_perf.c                    | 173 +++++++----
 47 files changed, 1106 insertions(+), 634 deletions(-)

diff --git a/app/test-crypto-perf/cperf.h b/app/test-crypto-perf/cperf.h
index 293ba94..c9f7f81 100644
--- a/app/test-crypto-perf/cperf.h
+++ b/app/test-crypto-perf/cperf.h
@@ -41,7 +41,10 @@ struct cperf_options;
 struct cperf_test_vector;
 struct cperf_op_fns;
 
-typedef void  *(*cperf_constructor_t)(uint8_t dev_id, uint16_t qp_id,
+typedef void  *(*cperf_constructor_t)(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *t_vec,
 		const struct cperf_op_fns *op_fns);
diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 17df2eb..82e5d60 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -331,14 +331,16 @@ cperf_set_ops_aead(struct rte_crypto_op **ops,
 }
 
 static struct rte_cryptodev_sym_session *
-cperf_create_session(uint8_t dev_id,
+cperf_create_session(struct rte_mempool *sess_mp,
+	uint8_t dev_id,
 	const struct cperf_options *options,
 	const struct cperf_test_vector *test_vector)
 {
 	struct rte_crypto_sym_xform cipher_xform;
 	struct rte_crypto_sym_xform auth_xform;
-	struct rte_cryptodev_sym_session *sess = NULL;
+	struct rte_cryptodev_sym_session *sess;
 
+	sess = rte_cryptodev_sym_session_create(sess_mp);
 	/*
 	 * cipher only
 	 */
@@ -359,7 +361,8 @@ cperf_create_session(uint8_t dev_id,
 			cipher_xform.cipher.key.length = 0;
 		}
 		/* create crypto session */
-		sess = rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		rte_cryptodev_sym_session_init(dev_id, sess, &cipher_xform,
+				sess_mp);
 	/*
 	 *  auth only
 	 */
@@ -385,7 +388,8 @@ cperf_create_session(uint8_t dev_id,
 			auth_xform.auth.key.data = NULL;
 		}
 		/* create crypto session */
-		sess =  rte_cryptodev_sym_session_create(dev_id, &auth_xform);
+		rte_cryptodev_sym_session_init(dev_id, sess, &auth_xform,
+				sess_mp);
 	/*
 	 * cipher and auth
 	 */
@@ -449,29 +453,31 @@ cperf_create_session(uint8_t dev_id,
 					RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
 				cipher_xform.next = &auth_xform;
 				/* create crypto session */
-				sess = rte_cryptodev_sym_session_create(dev_id,
-					&cipher_xform);
+				rte_cryptodev_sym_session_init(dev_id,
+						sess, &cipher_xform, sess_mp);
+
 			} else { /* decrypt */
 				auth_xform.next = &cipher_xform;
 				/* create crypto session */
-				sess = rte_cryptodev_sym_session_create(dev_id,
-					&auth_xform);
+				rte_cryptodev_sym_session_init(dev_id,
+						sess, &auth_xform, sess_mp);
 			}
 		} else { /* create crypto session for other */
 			/* cipher then auth */
 			if (options->op_type == CPERF_CIPHER_THEN_AUTH) {
 				cipher_xform.next = &auth_xform;
 				/* create crypto session */
-				sess = rte_cryptodev_sym_session_create(dev_id,
-						&cipher_xform);
+				rte_cryptodev_sym_session_init(dev_id,
+						sess, &cipher_xform, sess_mp);
 			} else { /* auth then cipher */
 				auth_xform.next = &cipher_xform;
 				/* create crypto session */
-				sess = rte_cryptodev_sym_session_create(dev_id,
-						&auth_xform);
+				rte_cryptodev_sym_session_init(dev_id,
+						sess, &auth_xform, sess_mp);
 			}
 		}
 	}
+
 	return sess;
 }
 
diff --git a/app/test-crypto-perf/cperf_ops.h b/app/test-crypto-perf/cperf_ops.h
index 1b748da..36daf9d 100644
--- a/app/test-crypto-perf/cperf_ops.h
+++ b/app/test-crypto-perf/cperf_ops.h
@@ -41,6 +41,7 @@
 
 
 typedef struct rte_cryptodev_sym_session *(*cperf_sessions_create_t)(
+		struct rte_mempool *sess_mp,
 		uint8_t dev_id, const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector);
 
diff --git a/app/test-crypto-perf/cperf_test_latency.c b/app/test-crypto-perf/cperf_test_latency.c
index 4fb7a9a..80b55f3 100644
--- a/app/test-crypto-perf/cperf_test_latency.c
+++ b/app/test-crypto-perf/cperf_test_latency.c
@@ -76,7 +76,7 @@ cperf_latency_test_free(struct cperf_latency_ctx *ctx, uint32_t mbuf_nb)
 
 	if (ctx) {
 		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -187,7 +187,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_latency_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -207,7 +208,7 @@ cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
 	ctx->options = options;
 	ctx->test_vector = test_vector;
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_latency.h b/app/test-crypto-perf/cperf_test_latency.h
index 6a2cf61..1bbedb4 100644
--- a/app/test-crypto-perf/cperf_test_latency.h
+++ b/app/test-crypto-perf/cperf_test_latency.h
@@ -43,7 +43,10 @@
 #include "cperf_test_vectors.h"
 
 void *
-cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_latency_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/cperf_test_throughput.c b/app/test-crypto-perf/cperf_test_throughput.c
index 85947a5..a9fbd74 100644
--- a/app/test-crypto-perf/cperf_test_throughput.c
+++ b/app/test-crypto-perf/cperf_test_throughput.c
@@ -65,7 +65,7 @@ cperf_throughput_test_free(struct cperf_throughput_ctx *ctx, uint32_t mbuf_nb)
 
 	if (ctx) {
 		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -175,7 +175,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_throughput_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -195,7 +196,7 @@ cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
 	ctx->options = options;
 	ctx->test_vector = test_vector;
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_throughput.h b/app/test-crypto-perf/cperf_test_throughput.h
index f1b5766..987d0c3 100644
--- a/app/test-crypto-perf/cperf_test_throughput.h
+++ b/app/test-crypto-perf/cperf_test_throughput.h
@@ -44,7 +44,10 @@
 
 
 void *
-cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_throughput_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/cperf_test_verify.c b/app/test-crypto-perf/cperf_test_verify.c
index b19f5e1..655bf08 100644
--- a/app/test-crypto-perf/cperf_test_verify.c
+++ b/app/test-crypto-perf/cperf_test_verify.c
@@ -69,7 +69,7 @@ cperf_verify_test_free(struct cperf_verify_ctx *ctx, uint32_t mbuf_nb)
 
 	if (ctx) {
 		if (ctx->sess)
-			rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+			rte_cryptodev_sym_session_free(ctx->sess);
 
 		if (ctx->mbufs_in) {
 			for (i = 0; i < mbuf_nb; i++)
@@ -179,7 +179,8 @@ cperf_mbuf_create(struct rte_mempool *mempool,
 }
 
 void *
-cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_verify_test_constructor(struct rte_mempool *sess_mp,
+		uint8_t dev_id, uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *op_fns)
@@ -199,7 +200,7 @@ cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
 	ctx->options = options;
 	ctx->test_vector = test_vector;
 
-	ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
+	ctx->sess = op_fns->sess_create(sess_mp, dev_id, options, test_vector);
 	if (ctx->sess == NULL)
 		goto err;
 
diff --git a/app/test-crypto-perf/cperf_test_verify.h b/app/test-crypto-perf/cperf_test_verify.h
index 3fa78ee..e67b48d 100644
--- a/app/test-crypto-perf/cperf_test_verify.h
+++ b/app/test-crypto-perf/cperf_test_verify.h
@@ -44,7 +44,10 @@
 
 
 void *
-cperf_verify_test_constructor(uint8_t dev_id, uint16_t qp_id,
+cperf_verify_test_constructor(
+		struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		uint16_t qp_id,
 		const struct cperf_options *options,
 		const struct cperf_test_vector *test_vector,
 		const struct cperf_op_fns *ops_fn);
diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index e013e82..eb2737e 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -77,8 +77,7 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
 	for (i = 0; i < enabled_cdev_count &&
 			i < RTE_CRYPTO_MAX_DEVS; i++) {
 		uint8_t cdev_id = enabled_cdevs[i];
-		sess_size = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_size = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_size > max_sess_size)
 			max_sess_size = sess_size;
 	}
@@ -412,7 +411,10 @@ main(int argc, char **argv)
 
 		cdev_id = enabled_cdevs[i];
 
-		ctx[cdev_id] = cperf_testmap[opts.test].constructor(cdev_id, 0,
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
+
+		ctx[cdev_id] = cperf_testmap[opts.test].constructor(
+				session_pool_socket[socket_id], cdev_id, 0,
 				&opts, t_vec, &op_fns);
 		if (ctx[cdev_id] == NULL) {
 			RTE_LOG(ERR, USER1, "Test run constructor failed\n");
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 785489a..463b616 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -80,6 +80,8 @@ New Features
   * Added helper functions for crypto device driver identification.
   * Moved crypto device driver names definitions to the particular PMDs.
     These names are not public anymore.
+  * Added support for multi-device sessions, so a single session can be
+    used in multiple drivers.
 
 
 Resolved Issues
@@ -166,6 +168,8 @@ API Changes
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * Mempool pointer ``mp`` has been removed from ``rte_cryptodev_sym_session`` structure.
+  * Replaced ``private`` marker with array of pointers to private data sessions
+    ``sess_private_data`` in ``rte_cryptodev_sym_session``
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index 2774b4e..393dfab 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -141,27 +141,44 @@ aesni_gcm_set_session_parameters(struct aesni_gcm_session *sess,
 
 /** Get gcm session */
 static struct aesni_gcm_session *
-aesni_gcm_get_session(struct aesni_gcm_qp *qp, struct rte_crypto_sym_op *op)
+aesni_gcm_get_session(struct aesni_gcm_qp *qp, struct rte_crypto_op *op)
 {
 	struct aesni_gcm_session *sess = NULL;
 
-	if (op->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		sess = (struct aesni_gcm_session *)op->session->_private;
-	} else  {
-		void *_sess;
+	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
+		if (likely(op->sym->session != NULL)) {
+			sess = (struct aesni_gcm_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+		}
+	} else {
+		/* provide internal session */
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
-		if (rte_mempool_get(qp->sess_mp, &_sess))
-			return sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		sess = (struct aesni_gcm_session *)
-			((struct rte_cryptodev_sym_session *)_sess)->_private;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct aesni_gcm_session *)_sess_private_data;
 
 		if (unlikely(aesni_gcm_set_session_parameters(sess,
-				op->xform) != 0)) {
+					op->sym->xform) != 0)) {
 			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
 			sess = NULL;
 		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
+
+	if (sess == NULL)
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -323,17 +340,16 @@ process_gcm_crypto_op(struct rte_crypto_sym_op *op,
  * - Returns NULL on invalid job
  */
 static void
-post_process_gcm_crypto_op(struct rte_crypto_op *op)
+post_process_gcm_crypto_op(struct rte_crypto_op *op,
+		struct aesni_gcm_session *sess)
 {
 	struct rte_mbuf *m = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
 
-	struct aesni_gcm_session *session =
-		(struct aesni_gcm_session *)op->sym->session->_private;
-
 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
+
 	/* Verify digest if required */
-	if (session->op == AESNI_GCM_OP_AUTHENTICATED_DECRYPTION) {
+	if (sess->op == AESNI_GCM_OP_AUTHENTICATED_DECRYPTION) {
 
 		uint8_t *tag = rte_pktmbuf_mtod_offset(m, uint8_t *,
 				m->data_len - op->sym->auth.digest.length);
@@ -357,21 +373,21 @@ post_process_gcm_crypto_op(struct rte_crypto_op *op)
 /**
  * Process a completed GCM request
  *
- * @param qp		Queue Pair to process
  * @param job		JOB_AES_HMAC job
  *
  * @return
  * - Number of processed jobs
  */
 static void
-handle_completed_gcm_crypto_op(struct aesni_gcm_qp *qp,
-		struct rte_crypto_op *op)
+handle_completed_gcm_crypto_op(struct rte_crypto_op *op,
+		struct aesni_gcm_session *sess)
 {
-	post_process_gcm_crypto_op(op);
+	post_process_gcm_crypto_op(op, sess);
 
 	/* Free session if a session-less crypto op */
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct aesni_gcm_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 }
@@ -391,7 +407,7 @@ aesni_gcm_pmd_dequeue_burst(void *queue_pair,
 
 	for (i = 0; i < nb_dequeued; i++) {
 
-		sess = aesni_gcm_get_session(qp, ops[i]->sym);
+		sess = aesni_gcm_get_session(qp, ops[i]);
 		if (unlikely(sess == NULL)) {
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
 			qp->qp_stats.dequeue_err_count++;
@@ -405,7 +421,7 @@ aesni_gcm_pmd_dequeue_burst(void *queue_pair,
 			break;
 		}
 
-		handle_completed_gcm_crypto_op(qp, ops[i]);
+		handle_completed_gcm_crypto_op(ops[i], sess);
 	}
 
 	qp->qp_stats.dequeued_count += i;
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
index 721dbda..0b063fd 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_ops.c
@@ -313,21 +313,37 @@ aesni_gcm_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a aesni gcm session from a crypto xform chain */
-static void *
+static int
 aesni_gcm_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		GCM_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (aesni_gcm_set_session_parameters(sess, xform) != 0) {
+	if (aesni_gcm_set_session_parameters(sess_private_data, xform) != 0) {
 		GCM_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index ec348ab..9d849c9 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -348,24 +348,37 @@ get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *op)
 	struct aesni_mb_session *sess = NULL;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		sess = (struct aesni_mb_session *)op->sym->session->_private;
-	} else  {
+		if (likely(op->sym->session != NULL))
+			sess = (struct aesni_mb_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
 		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
 			return NULL;
 
-		sess = (struct aesni_mb_session *)
-			((struct rte_cryptodev_sym_session *)_sess)->_private;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct aesni_mb_session *)_sess_private_data;
 
 		if (unlikely(aesni_mb_set_session_parameters(qp->op_fns,
 				sess, op->sym->xform) != 0)) {
 			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
 			sess = NULL;
 		}
 		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -512,7 +525,7 @@ verify_digest(JOB_AES_HMAC *job, struct rte_crypto_op *op) {
  * - Returns NULL on invalid job
  */
 static inline struct rte_crypto_op *
-post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
+post_process_mb_job(JOB_AES_HMAC *job)
 {
 	struct rte_crypto_op *op = (struct rte_crypto_op *)job->user_data;
 
@@ -525,7 +538,9 @@ post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 
 			if (job->hash_alg != NULL_HASH) {
 				sess = (struct aesni_mb_session *)
-						op->sym->session->_private;
+						get_session_private_data(
+						op->sym->session,
+						cryptodev_driver_id);
 
 				if (sess->auth.operation ==
 						RTE_CRYPTO_AUTH_OP_VERIFY)
@@ -539,7 +554,8 @@ post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
 
 	/* Free session if a session-less crypto op */
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct aesni_mb_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
@@ -564,7 +580,7 @@ handle_completed_jobs(struct aesni_mb_qp *qp, JOB_AES_HMAC *job,
 	unsigned processed_jobs = 0;
 
 	while (job != NULL && processed_jobs < nb_ops) {
-		op = post_process_mb_job(qp, job);
+		op = post_process_mb_job(job);
 
 		if (op) {
 			ops[processed_jobs++] = op;
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
index 3a2683b..fda8296 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -472,24 +472,39 @@ aesni_mb_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a aesni multi-buffer session from a crypto xform chain */
-static void *
+static int
 aesni_mb_pmd_session_configure(struct rte_cryptodev *dev,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
 	struct aesni_mb_private *internals = dev->data->dev_private;
 
 	if (unlikely(sess == NULL)) {
 		MB_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
 	if (aesni_mb_set_session_parameters(&job_ops[internals->vector_mode],
-			sess, xform) != 0) {
+			sess_private_data, xform) != 0) {
 		MB_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index 1ddf6a2..1b9893e 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -549,26 +549,33 @@ get_session(struct armv8_crypto_qp *qp, struct rte_crypto_op *op)
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
 		/* get existing session */
-		if (likely(op->sym->session != NULL)) {
+		if (likely(op->sym->session != NULL))
 			sess = (struct armv8_crypto_session *)
-				op->sym->session->_private;
-		}
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
 	} else {
 		/* provide internal session */
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
-		if (!rte_mempool_get(qp->sess_mp, (void **)&_sess)) {
-			sess = (struct armv8_crypto_session *)
-				((struct rte_cryptodev_sym_session *)_sess)
-				->_private;
-
-			if (unlikely(armv8_crypto_set_session_parameters(
-					sess, op->sym->xform) != 0)) {
-				rte_mempool_put(qp->sess_mp, _sess);
-				sess = NULL;
-			} else
-				op->sym->session = _sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct armv8_crypto_session *)_sess_private_data;
+
+		if (unlikely(armv8_crypto_session_parameters(sess,
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
 		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	if (unlikely(sess == NULL))
@@ -702,7 +709,7 @@ process_op(const struct armv8_crypto_qp *qp, struct rte_crypto_op *op,
 	/* Free session if a session-less crypto op */
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
 		memset(sess, 0, sizeof(struct armv8_crypto_session));
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_ops.c b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
index 2911417..3db420b 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_ops.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd_ops.c
@@ -316,22 +316,37 @@ armv8_crypto_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure the session from a crypto xform chain */
-static void *
-armv8_crypto_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform, void *sess)
+static int
+armv8_crypto_pmd_session_configure(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		ARMV8_CRYPTO_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (armv8_crypto_set_session_parameters(
-			sess, xform) != 0) {
+	if (armv8_crypto_set_session_parameters(sess_private_data, xform) != 0) {
 		ARMV8_CRYPTO_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 70ad07a..0a85690 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -465,7 +465,9 @@ dpaa2_sec_enqueue_burst(void *qp, struct rte_crypto_op **ops,
 			/*Clear the unused FD fields before sending*/
 			memset(&fd_arr[loop], 0, sizeof(struct qbman_fd));
 			sess = (dpaa2_sec_session *)
-				(*ops)->sym->session->_private;
+					get_session_private_data(
+					(*ops)->sym->session,
+					cryptodev_driver_id);
 			mb_pool = (*ops)->sym->m_src->pool;
 			bpid = mempool_to_bpid(mb_pool);
 			ret = build_sec_fd(sess, *ops, &fd_arr[loop], bpid);
@@ -1202,18 +1204,14 @@ dpaa2_sec_aead_init(struct rte_cryptodev *dev,
 	return -1;
 }
 
-static void *
-dpaa2_sec_session_configure(struct rte_cryptodev *dev,
+static int
+dpaa2_sec_set_session_parameters(struct rte_cryptodev *dev,
 			    struct rte_crypto_sym_xform *xform,	void *sess)
 {
 	dpaa2_sec_session *session = sess;
 
 	PMD_INIT_FUNC_TRACE();
 
-	if (unlikely(sess == NULL)) {
-		RTE_LOG(ERR, PMD, "invalid session struct");
-		return NULL;
-	}
 	/* Cipher Only */
 	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
 		session->ctxt_type = DPAA2_SEC_CIPHER;
@@ -1238,10 +1236,39 @@ dpaa2_sec_session_configure(struct rte_cryptodev *dev,
 		dpaa2_sec_aead_init(dev, xform, session);
 	} else {
 		RTE_LOG(ERR, PMD, "Invalid crypto type");
-		return NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+dpaa2_sec_session_configure(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
+{
+	void *sess_private_data;
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	return session;
+	if (dpaa2_sec_set_session_parameters(dev, xform, sess_private_data) != 0) {
+		PMD_DRV_LOG(ERR, "DPAA2 PMD: failed to configure "
+				"session parameters");
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
+	}
+
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index 67f0b06..9bb309d 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -143,23 +143,40 @@ kasumi_set_session_parameters(struct kasumi_session *sess,
 static struct kasumi_session *
 kasumi_get_session(struct kasumi_qp *qp, struct rte_crypto_op *op)
 {
-	struct kasumi_session *sess;
+	struct kasumi_session *sess = NULL;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		sess = (struct kasumi_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct kasumi_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct kasumi_session *)c_sess->_private;
+		sess = (struct kasumi_session *)_sess_private_data;
 
 		if (unlikely(kasumi_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -297,7 +314,7 @@ process_kasumi_hash_op(struct rte_crypto_op **ops,
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
 					ops[i]->sym->auth.digest.length);
-		} else  {
+		} else {
 			dst = ops[i]->sym->auth.digest.data;
 
 			sso_kasumi_f9_1_buffer_user(&session->pKeySched_hash,
@@ -352,7 +369,9 @@ process_ops(struct rte_crypto_op **ops, struct kasumi_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			memset(ops[i]->sym->session, 0,
+					sizeof(struct kasumi_session));
+			rte_cryptodev_sym_session_free(ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
 	}
@@ -404,7 +423,8 @@ process_op_bit(struct rte_crypto_op *op, struct kasumi_session *session,
 
 	/* Free session if a session-less crypto op. */
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct kasumi_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
index 343c9b3..d590b91 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd_ops.c
@@ -291,21 +291,37 @@ kasumi_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a KASUMI session from a crypto xform chain */
-static void *
+static int
 kasumi_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		KASUMI_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (kasumi_set_session_parameters(sess, xform) != 0) {
+	if (kasumi_set_session_parameters(sess_private_data, xform) != 0) {
 		KASUMI_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index 9323874..c4a7219 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -84,6 +84,14 @@ process_op(const struct null_crypto_qp *qp, struct rte_crypto_op *op,
 	/* set status as successful by default */
 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
+	/* Free session if a session-less crypto op. */
+	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
+		memset(op->sym->session, 0,
+				sizeof(struct null_crypto_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
+		op->sym->session = NULL;
+	}
+
 	/*
 	 * if crypto session and operation are valid just enqueue the packet
 	 * in the processed ring
@@ -94,23 +102,34 @@ process_op(const struct null_crypto_qp *qp, struct rte_crypto_op *op,
 static struct null_crypto_session *
 get_session(struct null_crypto_qp *qp, struct rte_crypto_sym_op *op)
 {
-	struct null_crypto_session *sess;
+	struct null_crypto_session *sess = NULL;
 
 	if (op->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->session == NULL))
+		if (likely(op->session != NULL))
+			sess = (struct null_crypto_session *)
+					get_session_private_data(
+					op->session, cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
 			return NULL;
 
-		sess = (struct null_crypto_session *)op->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
-
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct null_crypto_session *)c_sess->_private;
-
-		if (null_crypto_set_session_parameters(sess, op->xform)	!= 0)
-			return NULL;
+		sess = (struct null_crypto_session *)_sess_private_data;
+
+		if (unlikely(null_crypto_set_session_parameters(sess,
+				op->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	return sess;
diff --git a/drivers/crypto/null/null_crypto_pmd_ops.c b/drivers/crypto/null/null_crypto_pmd_ops.c
index a7c891e..04147fe 100644
--- a/drivers/crypto/null/null_crypto_pmd_ops.c
+++ b/drivers/crypto/null/null_crypto_pmd_ops.c
@@ -302,24 +302,37 @@ null_crypto_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a null crypto session from a crypto xform chain */
-static void *
+static int
 null_crypto_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform, void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
 {
-	int retval;
+	void *sess_private_data;
 
 	if (unlikely(sess == NULL)) {
 		NULL_CRYPTO_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
-	retval = null_crypto_set_session_parameters(
-			(struct null_crypto_session *)sess, xform);
-	if (retval != 0) {
+
+	if (null_crypto_set_session_parameters(sess_private_data, xform) != 0) {
 		NULL_CRYPTO_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 3232455..b519ca2 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -452,23 +452,31 @@ get_session(struct openssl_qp *qp, struct rte_crypto_op *op)
 		/* get existing session */
 		if (likely(op->sym->session != NULL))
 			sess = (struct openssl_session *)
-				op->sym->session->_private;
-	} else  {
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
 		/* provide internal session */
 		void *_sess = NULL;
+		void *_sess_private_data = NULL;
 
-		if (!rte_mempool_get(qp->sess_mp, (void **)&_sess)) {
-			sess = (struct openssl_session *)
-				((struct rte_cryptodev_sym_session *)_sess)
-				->_private;
-
-			if (unlikely(openssl_set_session_parameters(
-					sess, op->sym->xform) != 0)) {
-				rte_mempool_put(qp->sess_mp, _sess);
-				sess = NULL;
-			} else
-				op->sym->session = _sess;
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
+			return NULL;
+
+		sess = (struct openssl_session *)_sess_private_data;
+
+		if (unlikely(openssl_set_session_parameters(sess,
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
 		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
 	if (sess == NULL)
@@ -1199,7 +1207,7 @@ process_op(const struct openssl_qp *qp, struct rte_crypto_op *op,
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
 		openssl_reset_session(sess);
 		memset(sess, 0, sizeof(struct openssl_session));
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index f65de53..005855b 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -671,22 +671,38 @@ openssl_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure the session from a crypto xform chain */
-static void *
+static int
 openssl_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		OPENSSL_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
 	if (openssl_set_session_parameters(
-			sess, xform) != 0) {
+			sess_private_data, xform) != 0) {
 		OPENSSL_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+			sess_private_data);
+
+	return 0;
 }
 
 
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index 13bd0b5..845abb4 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -220,7 +220,6 @@ void qat_crypto_sym_clear_session(struct rte_cryptodev *dev,
 		void *session)
 {
 	struct qat_session *sess = session;
-	phys_addr_t cd_paddr;
 
 	PMD_INIT_FUNC_TRACE();
 	if (sess) {
@@ -228,9 +227,7 @@ void qat_crypto_sym_clear_session(struct rte_cryptodev *dev,
 			bpi_cipher_ctx_free(sess->bpi_ctx);
 			sess->bpi_ctx = NULL;
 		}
-		cd_paddr = sess->cd_paddr;
 		memset(sess, 0, qat_crypto_sym_get_session_private_size(dev));
-		sess->cd_paddr = cd_paddr;
 	} else
 		PMD_DRV_LOG(ERR, "NULL session");
 }
@@ -448,9 +445,37 @@ qat_crypto_sym_configure_session_cipher(struct rte_cryptodev *dev,
 	return NULL;
 }
 
-
-void *
+int
 qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
+{
+	void *sess_private_data;
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
+	}
+
+	if (qat_crypto_set_session_parameters(dev, xform, sess_private_data) != 0) {
+		PMD_DRV_LOG(ERR, "Crypto QAT PMD: failed to configure "
+				"session parameters");
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
+	}
+
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
+}
+
+int
+qat_crypto_set_session_parameters(struct rte_cryptodev *dev,
 		struct rte_crypto_sym_xform *xform, void *session_private)
 {
 	struct qat_session *session = session_private;
@@ -458,6 +483,10 @@ qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
 	int qat_cmd_id;
 	PMD_INIT_FUNC_TRACE();
 
+	/* Set context descriptor physical address */
+	session->cd_paddr = rte_mempool_virt2phy(NULL, session) +
+			offsetof(struct qat_session, cd);
+
 	/* Get requested QAT command id */
 	qat_cmd_id = qat_get_cmd_id(xform);
 	if (qat_cmd_id < 0 || qat_cmd_id >= ICP_QAT_FW_LA_CMD_DELIMITER) {
@@ -498,10 +527,10 @@ qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
 		goto error_out;
 	}
 
-	return session;
+	return 0;
 
 error_out:
-	return NULL;
+	return -1;
 }
 
 struct qat_session *
@@ -809,7 +838,10 @@ qat_pmd_dequeue_op_burst(void *qp, struct rte_crypto_op **ops,
 			rx_op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 		} else {
 			struct qat_session *sess = (struct qat_session *)
-						(rx_op->sym->session->_private);
+					get_session_private_data(
+					rx_op->sym->session,
+					cryptodev_qat_driver_id);
+
 			if (sess->bpi_ctx)
 				qat_bpicipher_postprocess(sess, rx_op);
 			rx_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
@@ -914,7 +946,14 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		return -EINVAL;
 	}
 
-	ctx = (struct qat_session *)op->sym->session->_private;
+	ctx = (struct qat_session *)get_session_private_data(
+			op->sym->session, cryptodev_qat_driver_id);
+
+	if (unlikely(ctx == NULL)) {
+		PMD_DRV_LOG(ERR, "Session was not created for this device");
+		return -EINVAL;
+	}
+
 	qat_req = (struct icp_qat_fw_la_bulk_req *)out_msg;
 	rte_mov128((uint8_t *)qat_req, (const uint8_t *)&(ctx->fw_req));
 	qat_req->comn_mid.opaque_data = (uint64_t)(uintptr_t)op;
@@ -1192,17 +1231,6 @@ static inline uint32_t adf_modulo(uint32_t data, uint32_t shift)
 	return data - mult;
 }
 
-void qat_crypto_sym_session_init(struct rte_mempool *mp, void *sym_sess)
-{
-	struct rte_cryptodev_sym_session *sess = sym_sess;
-	struct qat_session *s = (void *)sess->_private;
-
-	PMD_INIT_FUNC_TRACE();
-	s->cd_paddr = rte_mempool_virt2phy(mp, sess) +
-		offsetof(struct qat_session, cd) +
-		offsetof(struct rte_cryptodev_sym_session, _private);
-}
-
 int qat_dev_config(__rte_unused struct rte_cryptodev *dev,
 		__rte_unused struct rte_cryptodev_config *config)
 {
diff --git a/drivers/crypto/qat/qat_crypto.h b/drivers/crypto/qat/qat_crypto.h
index ed27e3b..d5466c2 100644
--- a/drivers/crypto/qat/qat_crypto.h
+++ b/drivers/crypto/qat/qat_crypto.h
@@ -114,11 +114,15 @@ qat_pmd_session_mempool_create(struct rte_cryptodev *dev,
 extern unsigned
 qat_crypto_sym_get_session_private_size(struct rte_cryptodev *dev);
 
-extern void
-qat_crypto_sym_session_init(struct rte_mempool *mempool, void *priv_sess);
-
-extern void *
+extern int
 qat_crypto_sym_configure_session(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool);
+
+
+int
+qat_crypto_set_session_parameters(struct rte_cryptodev *dev,
 		struct rte_crypto_sym_xform *xform, void *session_private);
 
 struct qat_session *
diff --git a/drivers/crypto/qat/rte_qat_cryptodev.c b/drivers/crypto/qat/rte_qat_cryptodev.c
index 1c5ff77..9a710e6 100644
--- a/drivers/crypto/qat/rte_qat_cryptodev.c
+++ b/drivers/crypto/qat/rte_qat_cryptodev.c
@@ -73,7 +73,6 @@ static struct rte_cryptodev_ops crypto_qat_ops = {
 		/* Crypto related operations */
 		.session_get_size	= qat_crypto_sym_get_session_private_size,
 		.session_configure	= qat_crypto_sym_configure_session,
-		.session_initialize	= qat_crypto_sym_session_init,
 		.session_clear		= qat_crypto_sym_clear_session
 };
 
diff --git a/drivers/crypto/scheduler/scheduler_failover.c b/drivers/crypto/scheduler/scheduler_failover.c
index 162a29b..2aa13f8 100644
--- a/drivers/crypto/scheduler/scheduler_failover.c
+++ b/drivers/crypto/scheduler/scheduler_failover.c
@@ -49,57 +49,18 @@ struct fo_scheduler_qp_ctx {
 };
 
 static __rte_always_inline uint16_t
-failover_slave_enqueue(struct scheduler_slave *slave, uint8_t slave_idx,
+failover_slave_enqueue(struct scheduler_slave *slave,
 		struct rte_crypto_op **ops, uint16_t nb_ops)
 {
 	uint16_t i, processed_ops;
-	struct rte_cryptodev_sym_session *sessions[nb_ops];
-	struct scheduler_session *sess0, *sess1, *sess2, *sess3;
 
 	for (i = 0; i < nb_ops && i < 4; i++)
 		rte_prefetch0(ops[i]->sym->session);
 
-	for (i = 0; (i < (nb_ops - 8)) && (nb_ops > 8); i += 4) {
-		rte_prefetch0(ops[i + 4]->sym->session);
-		rte_prefetch0(ops[i + 5]->sym->session);
-		rte_prefetch0(ops[i + 6]->sym->session);
-		rte_prefetch0(ops[i + 7]->sym->session);
-
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sess1 = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
-		sess2 = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
-		sess3 = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
-		sessions[i] = ops[i]->sym->session;
-		sessions[i + 1] = ops[i + 1]->sym->session;
-		sessions[i + 2] = ops[i + 2]->sym->session;
-		sessions[i + 3] = ops[i + 3]->sym->session;
-
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-		ops[i + 1]->sym->session = sess1->sessions[slave_idx];
-		ops[i + 2]->sym->session = sess2->sessions[slave_idx];
-		ops[i + 3]->sym->session = sess3->sessions[slave_idx];
-	}
-
-	for (; i < nb_ops; i++) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sessions[i] = ops[i]->sym->session;
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-	}
-
 	processed_ops = rte_cryptodev_enqueue_burst(slave->dev_id,
 			slave->qp_id, ops, nb_ops);
 	slave->nb_inflight_cops += processed_ops;
 
-	if (unlikely(processed_ops < nb_ops))
-		for (i = processed_ops; i < nb_ops; i++)
-			ops[i]->sym->session = sessions[i];
-
 	return processed_ops;
 }
 
@@ -114,11 +75,11 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		return 0;
 
 	enqueued_ops = failover_slave_enqueue(&qp_ctx->primary_slave,
-			PRIMARY_SLAVE_IDX, ops, nb_ops);
+			ops, nb_ops);
 
 	if (enqueued_ops < nb_ops)
 		enqueued_ops += failover_slave_enqueue(&qp_ctx->secondary_slave,
-				SECONDARY_SLAVE_IDX, &ops[enqueued_ops],
+				&ops[enqueued_ops],
 				nb_ops - enqueued_ops);
 
 	return enqueued_ops;
diff --git a/drivers/crypto/scheduler/scheduler_pkt_size_distr.c b/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
index 6b628df..1dd1bc3 100644
--- a/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
+++ b/drivers/crypto/scheduler/scheduler_pkt_size_distr.c
@@ -67,7 +67,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	struct scheduler_qp_ctx *qp_ctx = qp;
 	struct psd_scheduler_qp_ctx *psd_qp_ctx = qp_ctx->private_qp_ctx;
 	struct rte_crypto_op *sched_ops[NB_PKT_SIZE_SLAVES][nb_ops];
-	struct scheduler_session *sess;
 	uint32_t in_flight_ops[NB_PKT_SIZE_SLAVES] = {
 			psd_qp_ctx->primary_slave.nb_inflight_cops,
 			psd_qp_ctx->secondary_slave.nb_inflight_cops
@@ -97,8 +96,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		rte_prefetch0(ops[i + 7]->sym);
 		rte_prefetch0(ops[i + 7]->sym->session);
 
-		sess = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
 		/* job_len is initialized as cipher data length, once
 		 * it is 0, equals to auth data length
 		 */
@@ -118,11 +115,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i];
-		ops[i]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
 		job_len = ops[i+1]->sym->cipher.data.length;
 		job_len += (ops[i+1]->sym->cipher.data.length == 0) *
 				ops[i+1]->sym->auth.data.length;
@@ -135,11 +129,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+1];
-		ops[i+1]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
 		job_len = ops[i+2]->sym->cipher.data.length;
 		job_len += (ops[i+2]->sym->cipher.data.length == 0) *
 				ops[i+2]->sym->auth.data.length;
@@ -152,12 +143,8 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+2];
-		ops[i+2]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 
-		sess = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
 		job_len = ops[i+3]->sym->cipher.data.length;
 		job_len += (ops[i+3]->sym->cipher.data.length == 0) *
 				ops[i+3]->sym->auth.data.length;
@@ -170,14 +157,10 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i+3];
-		ops[i+3]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 	}
 
 	for (; i < nb_ops; i++) {
-		sess = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-
 		job_len = ops[i]->sym->cipher.data.length;
 		job_len += (ops[i]->sym->cipher.data.length == 0) *
 				ops[i]->sym->auth.data.length;
@@ -190,7 +173,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 		}
 
 		sched_ops[p_enq_op->slave_idx][p_enq_op->pos] = ops[i];
-		ops[i]->sym->session = sess->sessions[p_enq_op->slave_idx];
 		p_enq_op->pos++;
 	}
 
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index b9d8973..6e37efc 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -85,8 +85,10 @@ scheduler_attach_init_slave(struct rte_cryptodev *dev)
 /** Configure device */
 static int
 scheduler_pmd_config(struct rte_cryptodev *dev,
-		struct rte_cryptodev_config *config __rte_unused)
+		struct rte_cryptodev_config *config)
 {
+	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint32_t i;
 	int ret;
 
 	/* although scheduler_attach_init_slave presents multiple times,
@@ -96,6 +98,15 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	if (ret < 0)
 		return ret;
 
+	for (i = 0; i < sched_ctx->nb_slaves; i++) {
+		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
+
+		ret = rte_cryptodev_configure(slave_dev_id, config,
+				dev->data->session_pool);
+		if (ret < 0)
+			break;
+	}
+
 	return ret;
 }
 
@@ -474,67 +485,43 @@ scheduler_pmd_qp_count(struct rte_cryptodev *dev)
 static uint32_t
 scheduler_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 {
-	return sizeof(struct scheduler_session);
-}
-
-static int
-config_slave_sess(struct scheduler_ctx *sched_ctx,
-		struct rte_crypto_sym_xform *xform,
-		struct scheduler_session *sess,
-		uint32_t create)
-{
-	uint32_t i;
+	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint8_t i = 0;
+	uint32_t max_priv_sess_size = 0;
 
+	/* Check what is the maximum private session size for all slaves */
 	for (i = 0; i < sched_ctx->nb_slaves; i++) {
-		struct scheduler_slave *slave = &sched_ctx->slaves[i];
+		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
+		struct rte_cryptodev *dev = &rte_cryptodevs[slave_dev_id];
+		uint32_t priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
 
-		if (sess->sessions[i]) {
-			if (create)
-				continue;
-			/* !create */
-			sess->sessions[i] = rte_cryptodev_sym_session_free(
-					slave->dev_id, sess->sessions[i]);
-		} else {
-			if (!create)
-				continue;
-			/* create */
-			sess->sessions[i] =
-					rte_cryptodev_sym_session_create(
-							slave->dev_id, xform);
-			if (!sess->sessions[i]) {
-				config_slave_sess(sched_ctx, NULL, sess, 0);
-				return -1;
-			}
-		}
+		if (max_priv_sess_size < priv_sess_size)
+			max_priv_sess_size = priv_sess_size;
 	}
 
-	return 0;
-}
-
-/** Clear the memory of session so it doesn't leave key material behind */
-static void
-scheduler_pmd_session_clear(struct rte_cryptodev *dev,
-	void *sess)
-{
-	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
-
-	config_slave_sess(sched_ctx, NULL, sess, 0);
-
-	memset(sess, 0, sizeof(struct scheduler_session));
+	return max_priv_sess_size;
 }
 
-static void *
+static int
 scheduler_pmd_session_configure(struct rte_cryptodev *dev,
-	struct rte_crypto_sym_xform *xform, void *sess)
+	struct rte_crypto_sym_xform *xform,
+	struct rte_cryptodev_sym_session *sess,
+	struct rte_mempool *mempool)
 {
 	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
+	uint32_t i;
+
+	for (i = 0; i < sched_ctx->nb_slaves; i++) {
+		struct scheduler_slave *slave = &sched_ctx->slaves[i];
 
-	if (config_slave_sess(sched_ctx, xform, sess, 1) < 0) {
-		CS_LOG_ERR("unabled to config sym session");
-		return NULL;
+		if (rte_cryptodev_sym_session_init(slave->dev_id, sess,
+					xform, mempool) < 0) {
+			CS_LOG_ERR("unabled to config sym session");
+			return -1;
+		}
 	}
 
-	return sess;
+	return 0;
 }
 
 struct rte_cryptodev_ops scheduler_pmd_ops = {
@@ -556,7 +543,7 @@ struct rte_cryptodev_ops scheduler_pmd_ops = {
 
 		.session_get_size	= scheduler_pmd_session_get_size,
 		.session_configure	= scheduler_pmd_session_configure,
-		.session_clear		= scheduler_pmd_session_clear,
+		.session_clear		= NULL,
 };
 
 struct rte_cryptodev_ops *rte_crypto_scheduler_pmd_ops = &scheduler_pmd_ops;
diff --git a/drivers/crypto/scheduler/scheduler_pmd_private.h b/drivers/crypto/scheduler/scheduler_pmd_private.h
index a78e9a6..a915ef4 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_private.h
+++ b/drivers/crypto/scheduler/scheduler_pmd_private.h
@@ -103,10 +103,6 @@ struct scheduler_qp_ctx {
 	uint32_t seqn;
 } __rte_cache_aligned;
 
-struct scheduler_session {
-	struct rte_cryptodev_sym_session *sessions[
-			RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES];
-};
 
 extern uint8_t cryptodev_driver_id;
 
diff --git a/drivers/crypto/scheduler/scheduler_roundrobin.c b/drivers/crypto/scheduler/scheduler_roundrobin.c
index 0116276..4a84728 100644
--- a/drivers/crypto/scheduler/scheduler_roundrobin.c
+++ b/drivers/crypto/scheduler/scheduler_roundrobin.c
@@ -52,8 +52,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	uint32_t slave_idx = rr_qp_ctx->last_enq_slave_idx;
 	struct scheduler_slave *slave = &rr_qp_ctx->slaves[slave_idx];
 	uint16_t i, processed_ops;
-	struct rte_cryptodev_sym_session *sessions[nb_ops];
-	struct scheduler_session *sess0, *sess1, *sess2, *sess3;
 
 	if (unlikely(nb_ops == 0))
 		return 0;
@@ -61,39 +59,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	for (i = 0; i < nb_ops && i < 4; i++)
 		rte_prefetch0(ops[i]->sym->session);
 
-	for (i = 0; (i < (nb_ops - 8)) && (nb_ops > 8); i += 4) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sess1 = (struct scheduler_session *)
-				ops[i+1]->sym->session->_private;
-		sess2 = (struct scheduler_session *)
-				ops[i+2]->sym->session->_private;
-		sess3 = (struct scheduler_session *)
-				ops[i+3]->sym->session->_private;
-
-		sessions[i] = ops[i]->sym->session;
-		sessions[i + 1] = ops[i + 1]->sym->session;
-		sessions[i + 2] = ops[i + 2]->sym->session;
-		sessions[i + 3] = ops[i + 3]->sym->session;
-
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-		ops[i + 1]->sym->session = sess1->sessions[slave_idx];
-		ops[i + 2]->sym->session = sess2->sessions[slave_idx];
-		ops[i + 3]->sym->session = sess3->sessions[slave_idx];
-
-		rte_prefetch0(ops[i + 4]->sym->session);
-		rte_prefetch0(ops[i + 5]->sym->session);
-		rte_prefetch0(ops[i + 6]->sym->session);
-		rte_prefetch0(ops[i + 7]->sym->session);
-	}
-
-	for (; i < nb_ops; i++) {
-		sess0 = (struct scheduler_session *)
-				ops[i]->sym->session->_private;
-		sessions[i] = ops[i]->sym->session;
-		ops[i]->sym->session = sess0->sessions[slave_idx];
-	}
-
 	processed_ops = rte_cryptodev_enqueue_burst(slave->dev_id,
 			slave->qp_id, ops, nb_ops);
 
@@ -102,12 +67,6 @@ schedule_enqueue(void *qp, struct rte_crypto_op **ops, uint16_t nb_ops)
 	rr_qp_ctx->last_enq_slave_idx += 1;
 	rr_qp_ctx->last_enq_slave_idx %= rr_qp_ctx->nb_slaves;
 
-	/* recover session if enqueue is failed */
-	if (unlikely(processed_ops < nb_ops)) {
-		for (i = processed_ops; i < nb_ops; i++)
-			ops[i]->sym->session = sessions[i];
-	}
-
 	return processed_ops;
 }
 
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index 677849d..b07718a 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -143,23 +143,40 @@ snow3g_set_session_parameters(struct snow3g_session *sess,
 static struct snow3g_session *
 snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
 {
-	struct snow3g_session *sess;
+	struct snow3g_session *sess = NULL;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		sess = (struct snow3g_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct snow3g_session *)
+					get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct snow3g_session *)c_sess->_private;
+		sess = (struct snow3g_session *)_sess_private_data;
 
 		if (unlikely(snow3g_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -286,7 +303,7 @@ process_snow3g_hash_op(struct rte_crypto_op **ops,
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
 					ops[i]->sym->auth.digest.length);
-		} else  {
+		} else {
 			dst = ops[i]->sym->auth.digest.data;
 
 			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
@@ -356,7 +373,9 @@ process_ops(struct rte_crypto_op **ops, struct snow3g_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			memset(ops[i]->sym->session, 0,
+					sizeof(struct snow3g_session));
+			rte_cryptodev_sym_session_free(ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
 	}
@@ -408,7 +427,8 @@ process_op_bit(struct rte_crypto_op *op, struct snow3g_session *session,
 
 	/* Free session if a session-less crypto op. */
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-		rte_mempool_put(qp->sess_mp, op->sym->session);
+		memset(op->sym->session, 0, sizeof(struct snow3g_session));
+		rte_cryptodev_sym_session_free(op->sym->session);
 		op->sym->session = NULL;
 	}
 
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
index 26cc3e9..1967409 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -289,21 +289,37 @@ snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a SNOW 3G session from a crypto xform chain */
-static void *
+static int
 snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		SNOW3G_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (snow3g_set_session_parameters(sess, xform) != 0) {
+	if (snow3g_set_session_parameters(sess_private_data, xform) != 0) {
 		SNOW3G_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index 385e4e5..c1d6310 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -142,23 +142,39 @@ zuc_set_session_parameters(struct zuc_session *sess,
 static struct zuc_session *
 zuc_get_session(struct zuc_qp *qp, struct rte_crypto_op *op)
 {
-	struct zuc_session *sess;
+	struct zuc_session *sess = NULL;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		sess = (struct zuc_session *)op->sym->session->_private;
-	} else  {
-		struct rte_cryptodev_sym_session *c_sess = NULL;
+		if (likely(op->sym->session != NULL))
+			sess = (struct zuc_session *)get_session_private_data(
+					op->sym->session,
+					cryptodev_driver_id);
+	} else {
+		void *_sess = NULL;
+		void *_sess_private_data = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess))
+			return NULL;
 
-		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+		if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
 			return NULL;
 
-		sess = (struct zuc_session *)c_sess->_private;
+		sess = (struct zuc_session *)_sess_private_data;
 
 		if (unlikely(zuc_set_session_parameters(sess,
-				op->sym->xform) != 0))
-			return NULL;
+				op->sym->xform) != 0)) {
+			rte_mempool_put(qp->sess_mp, _sess);
+			rte_mempool_put(qp->sess_mp, _sess_private_data);
+			sess = NULL;
+		}
+		op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
+		set_session_private_data(op->sym->session, cryptodev_driver_id,
+			_sess_private_data);
 	}
 
+	if (unlikely(sess == NULL))
+		op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+
 	return sess;
 }
 
@@ -277,7 +293,7 @@ process_zuc_hash_op(struct rte_crypto_op **ops,
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
 					ops[i]->sym->auth.digest.length);
-		} else  {
+		} else {
 			dst = (uint32_t *)ops[i]->sym->auth.digest.data;
 
 			sso_zuc_eia3_1_buffer(session->pKey_hash,
@@ -332,7 +348,9 @@ process_ops(struct rte_crypto_op **ops, struct zuc_session *session,
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 		/* Free session if a session-less crypto op. */
 		if (ops[i]->sym->sess_type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
-			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			memset(ops[i]->sym->session, 0,
+					sizeof(struct zuc_session));
+			rte_cryptodev_sym_session_free(ops[i]->sym->session);
 			ops[i]->sym->session = NULL;
 		}
 	}
diff --git a/drivers/crypto/zuc/rte_zuc_pmd_ops.c b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
index 645b80c..cdc783f 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd_ops.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd_ops.c
@@ -289,21 +289,37 @@ zuc_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
 }
 
 /** Configure a ZUC session from a crypto xform chain */
-static void *
+static int
 zuc_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
-		struct rte_crypto_sym_xform *xform,	void *sess)
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mempool)
 {
+	void *sess_private_data;
+
 	if (unlikely(sess == NULL)) {
 		ZUC_LOG_ERR("invalid session struct");
-		return NULL;
+		return -1;
+	}
+
+	if (rte_mempool_get(mempool, &sess_private_data)) {
+		CDEV_LOG_ERR(
+			"Couldn't get object from session mempool");
+		return -1;
 	}
 
-	if (zuc_set_session_parameters(sess, xform) != 0) {
+	if (zuc_set_session_parameters(sess_private_data, xform) != 0) {
 		ZUC_LOG_ERR("failed configure session parameters");
-		return NULL;
+
+		/* Return session to mempool */
+		rte_mempool_put(mempool, sess_private_data);
+		return -1;
 	}
 
-	return sess;
+	set_session_private_data(sess, dev->driver_id,
+		sess_private_data);
+
+	return 0;
 }
 
 /** Clear the memory of session so it doesn't leave key material behind */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 4d6c7ce..708eadd 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1242,8 +1242,7 @@ cryptodevs_init(void)
 
 	uint32_t max_sess_sz = 0, sess_sz;
 	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
-		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_sz = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_sz > max_sess_sz)
 			max_sess_sz = sess_sz;
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 048e441..c927344 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -45,7 +45,7 @@
 #include "esp.h"
 
 static inline int
-create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
+create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 {
 	struct rte_cryptodev_info cdev_info;
 	unsigned long cdev_id_qp = 0;
@@ -72,7 +72,10 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 			ipsec_ctx->tbl[cdev_id_qp].qp);
 
 	sa->crypto_session = rte_cryptodev_sym_session_create(
-			ipsec_ctx->tbl[cdev_id_qp].id, sa->xforms);
+			ipsec_ctx->session_pool);
+	rte_cryptodev_sym_session_init(ipsec_ctx->tbl[cdev_id_qp].id,
+			sa->crypto_session, sa->xforms,
+			ipsec_ctx->session_pool);
 
 	rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id, &cdev_info);
 	if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index add9291..9ec8e6f 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -593,6 +593,9 @@ static struct rte_cryptodev_sym_session *
 initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 {
 	struct rte_crypto_sym_xform *first_xform;
+	struct rte_cryptodev_sym_session *session;
+	uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
+	struct rte_mempool *sess_mp = session_pool_socket[socket_id];
 
 	if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH) {
 		first_xform = &options->cipher_xform;
@@ -606,7 +609,16 @@ initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 		first_xform = &options->auth_xform;
 	}
 
-	return rte_cryptodev_sym_session_create(cdev_id, first_xform);
+	session = rte_cryptodev_sym_session_create(sess_mp);
+
+	if (session == NULL)
+		return NULL;
+
+	if (rte_cryptodev_sym_session_init(cdev_id, session,
+				first_xform, sess_mp) < 0)
+		return NULL;
+
+	return session;
 }
 
 static void
@@ -1564,8 +1576,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 	}
 
 	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
-		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(cdev_id);
+		sess_sz = rte_cryptodev_get_private_session_size(cdev_id);
 		if (sess_sz > max_sess_sz)
 			max_sess_sz = sess_sz;
 	}
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 5c7191b..b304a7b 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -69,6 +69,8 @@
 #include "rte_cryptodev.h"
 #include "rte_cryptodev_pmd.h"
 
+static uint8_t nb_drivers;
+
 struct rte_cryptodev rte_crypto_devices[RTE_CRYPTO_MAX_DEVS];
 
 struct rte_cryptodev *rte_cryptodevs = &rte_crypto_devices[0];
@@ -1019,53 +1021,47 @@ rte_cryptodev_pmd_callback_process(struct rte_cryptodev *dev,
 }
 
 
-static void
-rte_cryptodev_sym_session_init(struct rte_mempool *mp,
-		const struct rte_cryptodev *dev,
-		struct rte_cryptodev_sym_session *sess)
+int
+rte_cryptodev_sym_session_init(uint8_t dev_id,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_crypto_sym_xform *xforms,
+		struct rte_mempool *mp)
 {
-	memset(sess, 0, mp->elt_size);
+	struct rte_cryptodev *dev;
+	uint8_t index;
 
-	if (dev->dev_ops->session_initialize)
-		(*dev->dev_ops->session_initialize)(mp, sess);
-}
+	dev = rte_cryptodev_pmd_get_dev(dev_id);
 
+	if (sess == NULL || xforms == NULL || dev == NULL)
+		return -1;
 
-struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_create(uint8_t dev_id,
-		struct rte_crypto_sym_xform *xform)
-{
-	struct rte_cryptodev *dev;
-	struct rte_cryptodev_sym_session *sess;
-	void *_sess;
+	index = dev->driver_id;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
-		return NULL;
+	if (sess->sess_private_data[index] == NULL) {
+		if (dev->dev_ops->session_configure(dev, xforms, sess, mp) < 0) {
+			CDEV_LOG_ERR(
+				"dev_id %d failed to configure session details",
+				dev_id);
+			return -1;
+		}
 	}
 
-	dev = &rte_crypto_devices[dev_id];
+	return 0;
+}
+
+struct rte_cryptodev_sym_session *
+rte_cryptodev_sym_session_create(struct rte_mempool *mp)
+{
+	struct rte_cryptodev_sym_session *sess;
 
 	/* Allocate a session structure from the session pool */
-	if (rte_mempool_get(dev->data->session_pool, &_sess)) {
-		CDEV_LOG_ERR("Couldn't get object from session mempool");
+	if (rte_mempool_get(mp, (void *)&sess)) {
+		CDEV_LOG_ERR("couldn't get object from session mempool");
 		return NULL;
 	}
 
-	sess = _sess;
-
-	rte_cryptodev_sym_session_init(dev->data->session_pool, dev,
-					sess);
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_configure, NULL);
-	if (dev->dev_ops->session_configure(dev, xform, sess->_private) ==
-			NULL) {
-		CDEV_LOG_ERR("dev_id %d failed to configure session details",
-				dev_id);
-
-		/* Return session to mempool */
-		rte_mempool_put(dev->data->session_pool, _sess);
-		return NULL;
-	}
+	/* Clear device session pointer */
+	memset(sess, 0, (sizeof(void *) * nb_drivers));
 
 	return sess;
 }
@@ -1085,7 +1081,10 @@ rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_attach_session, 0);
-	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess->_private)) {
+
+	void *sess_priv = get_session_private_data(sess, dev->driver_id);
+
+	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess_priv)) {
 		CDEV_LOG_ERR("dev_id %d failed to attach qp: %d with session",
 				dev_id, qp_id);
 		return -EPERM;
@@ -1109,7 +1108,10 @@ rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_detach_session, 0);
-	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess->_private)) {
+
+	void *sess_priv = get_session_private_data(sess, dev->driver_id);
+
+	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess_priv)) {
 		CDEV_LOG_ERR("dev_id %d failed to detach qp: %d from session",
 				dev_id, qp_id);
 		return -EPERM;
@@ -1117,34 +1119,45 @@ rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 
 	return 0;
 }
-struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_free(uint8_t dev_id,
-		struct rte_cryptodev_sym_session *sess)
+void
+rte_cryptodev_sym_session_free(struct rte_cryptodev_sym_session *sess)
 {
-	struct rte_cryptodev *dev;
+	uint8_t i;
+	struct rte_mempool *sess_mp;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
-		return sess;
-	}
+	if (sess == NULL)
+		return;
 
-	dev = &rte_crypto_devices[dev_id];
+	void *sess_priv;
 
-	/* Let device implementation clear session material */
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_clear, sess);
-	dev->dev_ops->session_clear(dev, (void *)sess->_private);
+	for (i = 0; i < nb_drivers; i++) {
+		if (sess->sess_private_data[i] != NULL) {
+			sess_priv = get_session_private_data(sess, i);
+			sess_mp = rte_mempool_from_obj(sess_priv);
+			rte_mempool_put(sess_mp, sess_priv);
+		}
+	}
 
 	/* Return session to mempool */
-	struct rte_mempool *mp = rte_mempool_from_obj(sess);
-	rte_mempool_put(mp, (void *)sess);
+	sess_mp = rte_mempool_from_obj(sess);
+	rte_mempool_put(sess_mp, sess);
+}
 
-	return NULL;
+unsigned int
+rte_cryptodev_get_header_session_size(void)
+{
+	/*
+	 * Header contains pointers to the private data
+	 * of all registered drivers
+	 */
+	return (sizeof(void *) * nb_drivers);
 }
 
 unsigned int
 rte_cryptodev_get_private_session_size(uint8_t dev_id)
 {
 	struct rte_cryptodev *dev;
+	unsigned int header_size = sizeof(void *) * nb_drivers;
 	unsigned int priv_sess_size;
 
 	if (!rte_cryptodev_pmd_is_valid_dev(dev_id))
@@ -1157,6 +1170,14 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id)
 
 	priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
 
+	/*
+	 * If size is less than session header size,
+	 * return the latter, as this guarantees that
+	 * sessionless operations will work
+	 */
+	if (priv_sess_size < header_size)
+		return header_size;
+
 	return priv_sess_size;
 
 }
@@ -1272,8 +1293,6 @@ struct cryptodev_driver {
 	uint8_t id;
 };
 
-static uint8_t nb_drivers;
-
 int
 rte_cryptodev_driver_id_get(const char *name)
 {
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 044a4aa..2204982 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -797,50 +797,59 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 /** Cryptodev symmetric crypto session */
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
-	__extension__ char _private[0];
+	__extension__ void *sess_private_data[0];
 	/**< Private session material */
 };
 
 
 /**
- * Initialise a session for symmetric cryptographic operations.
+ * Create symmetric crypto session (generic with no private data)
  *
- * This function is used by the client to initialize immutable
- * parameters of symmetric cryptographic operation.
- * To perform the operation the rte_cryptodev_enqueue_burst function is
- * used.  Each mbuf should contain a reference to the session
- * pointer returned from this function contained within it's crypto_op if a
- * session-based operation is being provisioned. Memory to contain the session
- * information is allocated from within mempool managed by the cryptodev.
- *
- * The rte_cryptodev_session_free must be called to free allocated
- * memory when the session is no longer required.
+ * @param   mempool    Symmetric session mempool to allocate session
+ *                     objects from
+ * @return
+ *  - On success return pointer to sym-session
+ *  - On failure returns NULL
+ */
+struct rte_cryptodev_sym_session *
+rte_cryptodev_sym_session_create(struct rte_mempool *mempool);
+
+/**
+ * Frees symmetric crypto session and all related device type specific
+ * private data objects associated with session
  *
- * @param	dev_id		The device identifier.
- * @param	xform		Crypto transform chain.
+ * @param   session  Session where the private data will be attached to
+ */
+void
+rte_cryptodev_sym_session_free(struct rte_cryptodev_sym_session *session);
 
+/**
+ * Fill out private data for the device id, based on its device type
+ *
+ * @param   dev_id   ID of device that we want the session to be used on
+ * @param   sess     Session where the private data will be attached to
+ * @param   xforms   Symmetric crypto transform operations to apply on flow
+ *                   processed with this session
+ * @param   mempool  Mempool where the private data is allocated.
  *
  * @return
- *  Pointer to the created session or NULL
+ *  - On success, zero.
+ *  - On failure, a negative value.
  */
-extern struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_create(uint8_t dev_id,
-		struct rte_crypto_sym_xform *xform);
+int
+rte_cryptodev_sym_session_init(uint8_t dev_id,
+			struct rte_cryptodev_sym_session *sess,
+			struct rte_crypto_sym_xform *xforms,
+			struct rte_mempool *mempool);
 
 /**
- * Free the memory associated with a previously allocated session.
- *
- * @param	dev_id		The device identifier.
- * @param	session		Session pointer previously allocated by
- *				*rte_cryptodev_sym_session_create*.
+ * Get the size of the header session, for all registered drivers.
  *
  * @return
- *   NULL on successful freeing of session.
- *   Session pointer on failure to free session.
+ *   Size of the header session.
  */
-extern struct rte_cryptodev_sym_session *
-rte_cryptodev_sym_session_free(uint8_t dev_id,
-		struct rte_cryptodev_sym_session *session);
+unsigned int
+rte_cryptodev_get_header_session_size(void);
 
 /**
  * Get the size of the private session data for a device.
diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
index 5911b83..d7cefd8 100644
--- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
+++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
@@ -285,13 +285,16 @@ typedef void (*cryptodev_sym_initialize_session_t)(struct rte_mempool *mempool,
  * @param	dev		Crypto device pointer
  * @param	xform		Single or chain of crypto xforms
  * @param	priv_sess	Pointer to cryptodev's private session structure
+ * @param	mp		Mempool where the private session is allocated
  *
  * @return
- *  - Returns private session structure on success.
- *  - Returns NULL on failure.
+ *  - Returns 0 if private session structure have been created successfully.
+ *  - Returns -1 on failure.
  */
-typedef void * (*cryptodev_sym_configure_session_t)(struct rte_cryptodev *dev,
-		struct rte_crypto_sym_xform *xform, void *session_private);
+typedef int (*cryptodev_sym_configure_session_t)(struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *session,
+		struct rte_mempool *mp);
 
 /**
  * Free Crypto session.
@@ -413,6 +416,19 @@ void rte_cryptodev_pmd_callback_process(struct rte_cryptodev *dev,
 int
 rte_cryptodev_pmd_create_dev_name(char *name, const char *dev_name_prefix);
 
+static inline void *
+get_session_private_data(const struct rte_cryptodev_sym_session *sess,
+		uint8_t driver_id) {
+	return sess->sess_private_data[driver_id];
+}
+
+static inline void
+set_session_private_data(struct rte_cryptodev_sym_session *sess,
+		uint8_t driver_id, void *private_data)
+{
+	sess->sess_private_data[driver_id] = private_data;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_cryptodev/rte_cryptodev_version.map b/lib/librte_cryptodev/rte_cryptodev_version.map
index 8855a34..c117c4f 100644
--- a/lib/librte_cryptodev/rte_cryptodev_version.map
+++ b/lib/librte_cryptodev/rte_cryptodev_version.map
@@ -65,9 +65,11 @@ DPDK_17.08 {
 	rte_cryptodev_device_count_by_driver;
 	rte_cryptodev_driver_id_get;
 	rte_cryptodev_driver_name_get;
+	rte_cryptodev_get_header_session_size;
 	rte_cryptodev_get_private_session_size;
 	rte_cryptodev_pci_generic_probe;
 	rte_cryptodev_pci_generic_remove;
+	rte_cryptodev_sym_session_init;
 	rte_cryptodev_vdev_parse_init_params;
 	rte_cryptodev_vdev_pmd_init;
 
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index cdc1cbf..9d08eb8 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -67,7 +67,6 @@ struct crypto_testsuite_params {
 	struct rte_mempool *large_mbuf_pool;
 	struct rte_mempool *op_mpool;
 	struct rte_mempool *session_mpool;
-	struct rte_mempool *slave_session_mpool;
 	struct rte_cryptodev_config conf;
 	struct rte_cryptodev_qp_conf qp_conf;
 
@@ -384,12 +383,15 @@ testsuite_setup(void)
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
 
-	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
-		rte_cryptodev_get_private_session_size(dev_id);
+	unsigned int session_size = rte_cryptodev_get_private_session_size(dev_id);
 
+	/*
+	 * Create mempool with maximum number of sessions * 2,
+	 * to include the session headers
+	 */
 	ts_params->session_mpool = rte_mempool_create(
 				"test_sess_mp",
-				info.sym.max_nb_sessions,
+				info.sym.max_nb_sessions * 2,
 				session_size,
 				0, 0, NULL, NULL, NULL,
 				NULL, SOCKET_ID_ANY,
@@ -436,11 +438,6 @@ testsuite_teardown(void)
 		rte_mempool_free(ts_params->session_mpool);
 		ts_params->session_mpool = NULL;
 	}
-
-	if (ts_params->slave_session_mpool != NULL) {
-		rte_mempool_free(ts_params->slave_session_mpool);
-		ts_params->slave_session_mpool = NULL;
-	}
 }
 
 static int
@@ -491,8 +488,7 @@ ut_teardown(void)
 
 	/* free crypto session structure */
 	if (ut_params->sess) {
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
-				ut_params->sess);
+		rte_cryptodev_sym_session_free(ut_params->sess);
 		ut_params->sess = NULL;
 	}
 
@@ -1275,10 +1271,13 @@ test_AES_CBC_HMAC_SHA1_encrypt_digest(void)
 	ut_params->auth_xform.auth.key.data = hmac_sha1_key;
 	ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA1;
 
-	/* Create crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0],
-			&ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate crypto op data structure */
@@ -1500,7 +1499,9 @@ test_AES_cipheronly_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1517,7 +1518,9 @@ test_AES_docsis_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_DOCSIS_TYPE);
@@ -1534,7 +1537,9 @@ test_AES_docsis_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_DOCSIS_TYPE);
@@ -1551,7 +1556,9 @@ test_DES_docsis_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_DES_DOCSIS_TYPE);
@@ -1568,7 +1575,9 @@ test_authonly_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1585,7 +1594,9 @@ test_AES_chain_mb_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1604,7 +1615,9 @@ test_AES_cipheronly_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1621,7 +1634,9 @@ test_AES_chain_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1638,7 +1653,9 @@ test_authonly_scheduler_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1657,7 +1674,9 @@ test_AES_chain_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1674,7 +1693,9 @@ test_AES_cipheronly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1691,7 +1712,9 @@ test_AES_chain_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1708,7 +1731,9 @@ test_AES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1725,7 +1750,9 @@ test_AES_chain_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1742,7 +1769,9 @@ test_AES_cipheronly_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_AES_CIPHERONLY_TYPE);
@@ -1759,7 +1788,9 @@ test_authonly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_AUTHONLY_TYPE);
@@ -1776,7 +1807,9 @@ test_AES_chain_armv8_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)),
 		BLKCIPHER_AES_CHAIN_TYPE);
@@ -1796,6 +1829,7 @@ create_wireless_algo_hash_session(uint8_t dev_id,
 {
 	uint8_t hash_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(hash_key, key, key_len);
@@ -1812,8 +1846,12 @@ create_wireless_algo_hash_session(uint8_t dev_id,
 	ut_params->auth_xform.auth.key.data = hash_key;
 	ut_params->auth_xform.auth.digest_length = auth_len;
 	ut_params->auth_xform.auth.add_auth_data_length = aad_len;
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->auth_xform, ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
 }
@@ -1826,6 +1864,7 @@ create_wireless_algo_cipher_session(uint8_t dev_id,
 {
 	uint8_t cipher_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_key, key, key_len);
@@ -1839,12 +1878,14 @@ create_wireless_algo_cipher_session(uint8_t dev_id,
 	ut_params->cipher_xform.cipher.key.data = cipher_key;
 	ut_params->cipher_xform.cipher.key.length = key_len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session */
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-						&ut_params->
-						cipher_xform);
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->cipher_xform, ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
 }
@@ -1955,6 +1996,7 @@ create_wireless_algo_cipher_auth_session(uint8_t dev_id,
 {
 	uint8_t cipher_auth_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_auth_key, key, key_len);
@@ -1980,11 +2022,14 @@ create_wireless_algo_cipher_auth_session(uint8_t dev_id,
 	ut_params->cipher_xform.cipher.key.data = cipher_auth_key;
 	ut_params->cipher_xform.cipher.key.length = key_len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->cipher_xform);
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->cipher_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
@@ -2002,6 +2047,7 @@ create_wireless_cipher_auth_session(uint8_t dev_id,
 	uint8_t cipher_auth_key[key_len];
 
 	struct crypto_unittest_params *ut_params = &unittest_params;
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	const uint8_t *key = tdata->key.data;
 	const uint8_t aad_len = tdata->aad.len;
 	const uint8_t auth_len = tdata->digest.len;
@@ -2029,11 +2075,14 @@ create_wireless_cipher_auth_session(uint8_t dev_id,
 	ut_params->cipher_xform.cipher.key.data = cipher_auth_key;
 	ut_params->cipher_xform.cipher.key.length = key_len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->cipher_xform);
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->cipher_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 	return 0;
@@ -2060,6 +2109,7 @@ create_wireless_algo_auth_cipher_session(uint8_t dev_id,
 {
 	uint8_t auth_cipher_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(auth_cipher_key, key, key_len);
@@ -2082,11 +2132,14 @@ create_wireless_algo_auth_cipher_session(uint8_t dev_id,
 	ut_params->cipher_xform.cipher.key.data = auth_cipher_key;
 	ut_params->cipher_xform.cipher.key.length = key_len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	TEST_HEXDUMP(stdout, "key:", key, key_len);
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform, ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -4700,7 +4753,9 @@ test_3DES_chain_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4717,7 +4772,9 @@ test_DES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_DES_CIPHERONLY_TYPE);
@@ -4734,7 +4791,9 @@ test_DES_docsis_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_DES_DOCSIS_TYPE);
@@ -4751,7 +4810,9 @@ test_3DES_chain_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4768,7 +4829,9 @@ test_3DES_cipheronly_dpaa2_sec_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4785,7 +4848,9 @@ test_3DES_cipheronly_qat_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4802,7 +4867,9 @@ test_3DES_chain_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_3DES_CHAIN_TYPE);
@@ -4819,7 +4886,9 @@ test_3DES_cipheronly_openssl_all(void)
 	int status;
 
 	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
-		ts_params->op_mpool, ts_params->valid_devs[0],
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
 		rte_cryptodev_driver_id_get(
 		RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
 		BLKCIPHER_3DES_CIPHERONLY_TYPE);
@@ -4839,6 +4908,7 @@ create_gcm_session(uint8_t dev_id, enum rte_crypto_cipher_operation op,
 {
 	uint8_t cipher_key[key_len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_key, key, key_len);
@@ -4866,16 +4936,19 @@ create_gcm_session(uint8_t dev_id, enum rte_crypto_cipher_operation op,
 	ut_params->auth_xform.auth.key.length = 0;
 	ut_params->auth_xform.auth.key.data = NULL;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	if (op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
 		ut_params->cipher_xform.next = &ut_params->auth_xform;
 
 		/* Create Crypto session*/
-		ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->cipher_xform);
+		rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->cipher_xform, ts_params->session_mpool);
 	} else {/* Create Crypto session*/
 		ut_params->auth_xform.next = &ut_params->cipher_xform;
-		ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+		rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform, ts_params->session_mpool);
 	}
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
@@ -5773,7 +5846,11 @@ static int MD5_HMAC_create_session(struct crypto_testsuite_params *ts_params,
 	ut_params->auth_xform.auth.key.data = key;
 
 	ut_params->sess = rte_cryptodev_sym_session_create(
-		ts_params->valid_devs[0], &ut_params->auth_xform);
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
 
 	if (ut_params->sess == NULL)
 		return TEST_FAILED;
@@ -5949,9 +6026,13 @@ test_multi_session(void)
 
 	/* Create multiple crypto sessions*/
 	for (i = 0; i < dev_info.sym.max_nb_sessions; i++) {
+
 		sessions[i] = rte_cryptodev_sym_session_create(
-				ts_params->valid_devs[0],
-			&ut_params->auth_xform);
+				ts_params->session_mpool);
+
+		rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+				sessions[i], &ut_params->auth_xform,
+				ts_params->session_mpool);
 		TEST_ASSERT_NOT_NULL(sessions[i],
 				"Session creation failed at session number %u",
 				i);
@@ -5987,14 +6068,14 @@ test_multi_session(void)
 	}
 
 	/* Next session create should fail */
-	sessions[i] = rte_cryptodev_sym_session_create(ts_params->valid_devs[0],
-			&ut_params->auth_xform);
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			sessions[i], &ut_params->auth_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NULL(sessions[i],
 			"Session creation succeeded unexpectedly!");
 
 	for (i = 0; i < dev_info.sym.max_nb_sessions; i++)
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
-				sessions[i]);
+		rte_cryptodev_sym_session_free(sessions[i]);
 
 	rte_free(sessions);
 
@@ -6052,6 +6133,9 @@ test_multi_session_random_usage(void)
 					* dev_info.sym.max_nb_sessions) + 1, 0);
 
 	for (i = 0; i < MB_SESSION_NUMBER; i++) {
+		sessions[i] = rte_cryptodev_sym_session_create(
+				ts_params->session_mpool);
+
 		rte_memcpy(&ut_paramz[i].ut_params, &testsuite_params,
 				sizeof(struct crypto_unittest_params));
 
@@ -6060,9 +6144,11 @@ test_multi_session_random_usage(void)
 				ut_paramz[i].cipher_key, ut_paramz[i].hmac_key);
 
 		/* Create multiple crypto sessions*/
-		sessions[i] = rte_cryptodev_sym_session_create(
+		rte_cryptodev_sym_session_init(
 				ts_params->valid_devs[0],
-				&ut_paramz[i].ut_params.auth_xform);
+				sessions[i],
+				&ut_paramz[i].ut_params.auth_xform,
+				ts_params->session_mpool);
 
 		TEST_ASSERT_NOT_NULL(sessions[i],
 				"Session creation failed at session number %u",
@@ -6106,8 +6192,7 @@ test_multi_session_random_usage(void)
 	}
 
 	for (i = 0; i < MB_SESSION_NUMBER; i++)
-		rte_cryptodev_sym_session_free(ts_params->valid_devs[0],
-				sessions[i]);
+		rte_cryptodev_sym_session_free(sessions[i]);
 
 	rte_free(sessions);
 
@@ -6131,9 +6216,14 @@ test_null_cipher_only_operation(void)
 	ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL;
 	ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+				ut_params->sess,
+				&ut_params->cipher_xform,
+				ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6188,9 +6278,13 @@ test_null_auth_only_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->auth_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6244,9 +6338,13 @@ test_null_cipher_auth_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6310,9 +6408,13 @@ test_null_auth_cipher_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	/* Generate Crypto op data structure */
@@ -6358,6 +6460,7 @@ test_null_invalid_operation(void)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
+	int ret;
 
 	/* Setup Cipher Parameters */
 	ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
@@ -6366,10 +6469,14 @@ test_null_invalid_operation(void)
 	ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
 	ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
-	TEST_ASSERT_NULL(ut_params->sess,
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	ret = rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
+	TEST_ASSERT(ret == -1,
 			"Session creation succeeded unexpectedly");
 
 
@@ -6380,10 +6487,14 @@ test_null_invalid_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->auth_xform);
-	TEST_ASSERT_NULL(ut_params->sess,
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	ret = rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->auth_xform,
+			ts_params->session_mpool);
+	TEST_ASSERT(ret == -1,
 			"Session creation succeeded unexpectedly");
 
 	return TEST_SUCCESS;
@@ -6417,9 +6528,13 @@ test_null_burst_operation(void)
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL;
 	ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(
-			ts_params->valid_devs[0], &ut_params->cipher_xform);
+			ts_params->session_mpool);
+
+	/* Create Crypto session*/
+	rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+			ut_params->sess, &ut_params->cipher_xform,
+			ts_params->session_mpool);
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
 	TEST_ASSERT_EQUAL(rte_crypto_op_bulk_alloc(ts_params->op_mpool,
@@ -6560,6 +6675,7 @@ static int create_gmac_session(uint8_t dev_id,
 {
 	uint8_t cipher_key[tdata->key.len];
 
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct crypto_unittest_params *ut_params = &unittest_params;
 
 	memcpy(cipher_key, tdata->key.data, tdata->key.len);
@@ -6584,8 +6700,12 @@ static int create_gmac_session(uint8_t dev_id,
 
 	ut_params->cipher_xform.next = &ut_params->auth_xform;
 
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-			&ut_params->cipher_xform);
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+			&ut_params->cipher_xform,
+			ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -6915,6 +7035,7 @@ create_auth_session(struct crypto_unittest_params *ut_params,
 		const struct test_crypto_vector *reference,
 		enum rte_crypto_auth_operation auth_op)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	uint8_t auth_key[reference->auth_key.len + 1];
 
 	memcpy(auth_key, reference->auth_key.data, reference->auth_key.len);
@@ -6929,9 +7050,13 @@ create_auth_session(struct crypto_unittest_params *ut_params,
 	ut_params->auth_xform.auth.digest_length = reference->digest.len;
 	ut_params->auth_xform.auth.add_auth_data_length = reference->aad.len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	 rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform,
+				ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -6945,6 +7070,7 @@ create_auth_cipher_session(struct crypto_unittest_params *ut_params,
 		enum rte_crypto_auth_operation auth_op,
 		enum rte_crypto_cipher_operation cipher_op)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	uint8_t cipher_key[reference->cipher_key.len + 1];
 	uint8_t auth_key[reference->auth_key.len + 1];
 
@@ -6970,9 +7096,13 @@ create_auth_cipher_session(struct crypto_unittest_params *ut_params,
 	ut_params->cipher_xform.cipher.key.data = cipher_key;
 	ut_params->cipher_xform.cipher.key.length = reference->cipher_key.len;
 
+	ut_params->sess = rte_cryptodev_sym_session_create(
+			ts_params->session_mpool);
+
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
-				&ut_params->auth_xform);
+	rte_cryptodev_sym_session_init(dev_id, ut_params->sess,
+				&ut_params->auth_xform,
+				ts_params->session_mpool);
 
 	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
 
@@ -7864,30 +7994,32 @@ test_scheduler_attach_slave_op(void)
 			continue;
 
 		/*
-		 * Create a separate mempool for the slaves, as they need different
-		 * session size and then configure them to store the pointer
-		 * to this mempool
+		 * Create the session mempool again, since now there are new devices
+		 * to use the mempool.
 		 */
-		unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
-			rte_cryptodev_get_private_session_size(i);
-
-		if (ts_params->slave_session_mpool == NULL) {
-			ts_params->slave_session_mpool = rte_mempool_create(
-				"test_slave_sess_mp",
-				info.sym.max_nb_sessions,
-				session_size,
-				0, 0, NULL, NULL, NULL, NULL,
-				SOCKET_ID_ANY, 0);
+		if (ts_params->session_mpool) {
+			rte_mempool_free(ts_params->session_mpool);
+			ts_params->session_mpool = NULL;
+		}
+		unsigned int session_size = rte_cryptodev_get_private_session_size(i);
 
-			TEST_ASSERT_NOT_NULL(ts_params->slave_session_mpool,
+		/*
+		 * Create mempool with maximum number of sessions * 2,
+		 * to include the session headers
+		 */
+		if (ts_params->session_mpool == NULL) {
+			ts_params->session_mpool = rte_mempool_create(
+					"test_sess_mp",
+					info.sym.max_nb_sessions * 2,
+					session_size,
+					0, 0, NULL, NULL, NULL,
+					NULL, SOCKET_ID_ANY,
+					0);
+
+			TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
 					"session mempool allocation failed");
 		}
 
-		TEST_ASSERT_SUCCESS(rte_cryptodev_configure(i,
-				&ts_params->conf, ts_params->slave_session_mpool),
-				"Failed to configure cryptodev %u with %u qps",
-				i, ts_params->conf.nb_queue_pairs);
-
 		ret = rte_cryptodev_scheduler_slave_attach(sched_id,
 				(uint8_t)i);
 
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 4bc370d..b2e600f 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -52,6 +52,7 @@ static int
 test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	char *test_msg)
@@ -64,8 +65,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	struct rte_crypto_sym_xform *init_xform = NULL;
 	struct rte_crypto_sym_op *sym_op = NULL;
 	struct rte_crypto_op *op = NULL;
-	struct rte_cryptodev_sym_session *sess = NULL;
 	struct rte_cryptodev_info dev_info;
+	struct rte_cryptodev_sym_session *sess = NULL;
 
 	int status = TEST_SUCCESS;
 	const struct blockcipher_test_data *tdata = t->test_data;
@@ -349,8 +350,10 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 
 	/* create session for sessioned op */
 	if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) {
-		sess = rte_cryptodev_sym_session_create(dev_id,
-			init_xform);
+		sess = rte_cryptodev_sym_session_create(sess_mpool);
+
+		rte_cryptodev_sym_session_init(dev_id, sess, init_xform,
+				sess_mpool);
 		if (!sess) {
 			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
 				"FAILED: %s", __LINE__,
@@ -448,7 +451,6 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 		else
 			auth_res = pktmbuf_mtod_offset(iobuf,
 					tdata->ciphertext.len);
-
 		if (memcmp(auth_res, tdata->digest.data, digest_len)) {
 			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
 				"FAILED: %s", __LINE__, "Generated "
@@ -577,7 +579,7 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 error_exit:
 	if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) {
 		if (sess)
-			rte_cryptodev_sym_session_free(dev_id, sess);
+			rte_cryptodev_sym_session_free(sess);
 		if (cipher_xform)
 			rte_free(cipher_xform);
 		if (auth_xform)
@@ -599,6 +601,7 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 int
 test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	enum blockcipher_test_type test_type)
@@ -690,7 +693,7 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			continue;
 
 		status = test_blockcipher_one_case(tc, mbuf_pool, op_mpool,
-			dev_id, driver_id, test_msg);
+			sess_mpool, dev_id, driver_id, test_msg);
 
 		printf("  %u) TestCase %s %s\n", test_index ++,
 			tc->test_descr, test_msg);
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 22fb420..22b8d20 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -125,6 +125,7 @@ struct blockcipher_test_data {
 int
 test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 	struct rte_mempool *op_mpool,
+	struct rte_mempool *sess_mpool,
 	uint8_t dev_id,
 	int driver_id,
 	enum blockcipher_test_type test_type);
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 753667a..68c5fdd 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -100,6 +100,8 @@ struct symmetric_session_attrs {
 	uint32_t digest_len;
 };
 
+static struct rte_cryptodev_sym_session *test_crypto_session;
+
 #define ALIGN_POW2_ROUNDUP(num, align) \
 	(((num) + (align) - 1) & ~((align) - 1))
 
@@ -148,17 +150,17 @@ struct crypto_unittest_params {
 	uint8_t *digest;
 };
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo);
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo);
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
@@ -478,8 +480,7 @@ ut_teardown(void)
 
 	/* free crypto session structure */
 	if (ut_params->sess)
-		rte_cryptodev_sym_session_free(ts_params->dev_id,
-				ut_params->sess);
+		rte_cryptodev_sym_session_free(ut_params->sess);
 
 	/* free crypto operation structure */
 	if (ut_params->op)
@@ -1958,10 +1959,13 @@ test_perf_crypto_qp_vary_burst_size(uint16_t dev_num)
 	ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA256;
 
 	/* Create Crypto session*/
-	ut_params->sess = rte_cryptodev_sym_session_create(ts_params->dev_id,
-		&ut_params->cipher_xform);
 
-	TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed");
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
+
+	rte_cryptodev_sym_session_init(ts_params->dev_id, test_crypto_session,
+			&ut_params->cipher_xform, ts_params->sess_mp);
+
+	TEST_ASSERT_NOT_NULL(test_crypto_session, "Session creation failed");
 
 	/* Generate Crypto op data structure(s) */
 	for (i = 0; i < num_to_submit ; i++) {
@@ -1983,7 +1987,7 @@ test_perf_crypto_qp_vary_burst_size(uint16_t dev_num)
 				rte_crypto_op_alloc(ts_params->op_mpool,
 						RTE_CRYPTO_OP_TYPE_SYMMETRIC);
 
-		rte_crypto_op_attach_sym_session(op, ut_params->sess);
+		rte_crypto_op_attach_sym_session(op, test_crypto_session);
 
 		op->sym->auth.digest.data = ut_params->digest;
 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
@@ -2101,9 +2105,12 @@ test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_snow3g_session(ts_params->dev_id,
+	if (test_perf_create_snow3g_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate Crypto op data structure(s)*/
@@ -2199,7 +2206,7 @@ test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams)
 		rte_pktmbuf_free(c_ops[i]->sym->m_src);
 		rte_crypto_op_free(c_ops[i]);
 	}
-	rte_cryptodev_sym_session_free(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return TEST_SUCCESS;
 }
@@ -2280,9 +2287,13 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_openssl_session(ts_params->dev_id,
+	if (test_perf_create_openssl_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
+
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate Crypto op data structure(s)*/
@@ -2403,7 +2414,7 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 		rte_pktmbuf_free(c_ops[i]->sym->m_src);
 		rte_crypto_op_free(c_ops[i]);
 	}
-	rte_cryptodev_sym_session_free(ts_params->dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return TEST_SUCCESS;
 }
@@ -2432,9 +2443,12 @@ test_perf_armv8_optimise_cyclecount(struct perf_test_params *pparams)
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_armv8_session(ts_params->dev_id,
+	if (test_perf_create_armv8_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate Crypto op data structure(s)*/
@@ -2646,12 +2660,13 @@ static uint8_t snow3g_hash_key[] = {
 		0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E
 };
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_aes_sha_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -2673,33 +2688,42 @@ test_perf_create_aes_sha_session(uint8_t dev_id, enum chain_mode chain,
 		auth_xform.auth.digest_length =
 					get_auth_digest_length(auth_algo);
 	}
+
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	case CIPHER_ONLY:
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
 #define SNOW3G_CIPHER_IV_LENGTH 16
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo, unsigned cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = {0};
 	struct rte_crypto_sym_xform auth_xform = {0};
 
@@ -2722,36 +2746,46 @@ test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain,
 	auth_xform.auth.key.length =  get_auth_key_max_length(auth_algo);
 	auth_xform.auth.digest_length = get_auth_digest_length(auth_algo);
 
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	case CIPHER_ONLY:
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id, &cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_ONLY:
 		auth_xform.next = NULL;
 		/* Create Crypto session */
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -2771,7 +2805,7 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		cipher_xform.cipher.key.data = aes_key;
 		break;
 	default:
-		return NULL;
+		return -1;
 	}
 
 	cipher_xform.cipher.key.length = cipher_key_len;
@@ -2789,34 +2823,40 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		auth_xform.auth.key.data = NULL;
 		break;
 	default:
-		return NULL;
+		return -1;
 	}
 
 	auth_xform.auth.key.length =  get_auth_key_max_length(auth_algo);
 	auth_xform.auth.digest_length = get_auth_digest_length(auth_algo);
 
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
 		auth_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
-static struct rte_cryptodev_sym_session *
+static int
 test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		enum rte_crypto_cipher_algorithm cipher_algo,
 		unsigned int cipher_key_len,
 		enum rte_crypto_auth_algorithm auth_algo)
 {
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -2829,7 +2869,7 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		cipher_xform.cipher.key.data = aes_cbc_128_key;
 		break;
 	default:
-		return NULL;
+		return -1;
 	}
 
 	cipher_xform.cipher.key.length = cipher_key_len;
@@ -2841,6 +2881,8 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 
 	auth_xform.auth.digest_length = get_auth_digest_length(auth_algo);
 
+	rte_cryptodev_sym_session_create(ts_params->sess_mp);
+
 	switch (chain) {
 	case CIPHER_HASH:
 		cipher_xform.next = &auth_xform;
@@ -2848,16 +2890,20 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 		/* Encrypt and hash the result */
 		cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&cipher_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &cipher_xform,
+				ts_params->sess_mp);
 	case HASH_CIPHER:
 		auth_xform.next = &cipher_xform;
 		cipher_xform.next = NULL;
 		/* Hash encrypted message and decrypt */
 		cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
 		/* Create Crypto session*/
-		return rte_cryptodev_sym_session_create(dev_id,	&auth_xform);
+		return rte_cryptodev_sym_session_init(dev_id,
+				test_crypto_session, &auth_xform,
+				ts_params->sess_mp);
 	default:
-		return NULL;
+		return -1;
 	}
 }
 
@@ -3125,9 +3171,12 @@ test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_aes_sha_session(ts_params->dev_id,
+	if (test_perf_create_aes_sha_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3223,7 +3272,7 @@ test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3259,9 +3308,12 @@ test_perf_snow3g(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_snow3g_session(ts_params->dev_id,
+	if (test_perf_create_snow3g_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3388,7 +3440,7 @@ test_perf_snow3g(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3445,9 +3497,12 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_openssl_session(ts_params->dev_id,
+	if (test_perf_create_openssl_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -3540,7 +3595,7 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	printf("\n");
 	return TEST_SUCCESS;
@@ -3577,9 +3632,12 @@ test_perf_armv8(uint8_t dev_id, uint16_t queue_id,
 	}
 
 	/* Create Crypto session*/
-	sess = test_perf_create_armv8_session(ts_params->dev_id,
+	if (test_perf_create_armv8_session(ts_params->dev_id,
 			pparams->chain, pparams->cipher_algo,
-			pparams->cipher_key_length, pparams->auth_algo);
+			pparams->cipher_key_length, pparams->auth_algo) == 0)
+		sess = test_crypto_session;
+	else
+		sess = NULL;
 	TEST_ASSERT_NOT_NULL(sess, "Session creation failed");
 
 	/* Generate a burst of crypto operations */
@@ -4124,7 +4182,7 @@ test_perf_aes_cbc_vary_burst_size(void)
 static struct rte_cryptodev_sym_session *
 test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams)
 {
-	static struct rte_cryptodev_sym_session *sess;
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform cipher_xform = { 0 };
 	struct rte_crypto_sym_xform auth_xform = { 0 };
 
@@ -4153,19 +4211,20 @@ test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams)
 	auth_xform.auth.digest_length = pparams->session_attrs->digest_len;
 	auth_xform.auth.key.length = pparams->session_attrs->key_auth_len;
 
+	test_crypto_session = rte_cryptodev_sym_session_create(ts_params->sess_mp);
 
 	cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 	if (cipher_xform.cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
 		cipher_xform.next = &auth_xform;
-		sess = rte_cryptodev_sym_session_create(dev_id,
-				&cipher_xform);
+		rte_cryptodev_sym_session_init(dev_id, test_crypto_session,
+				&cipher_xform, ts_params->sess_mp);
 	} else {
 		auth_xform.next = &cipher_xform;
-		sess = rte_cryptodev_sym_session_create(dev_id,
-				&auth_xform);
+		rte_cryptodev_sym_session_init(dev_id, test_crypto_session,
+				&auth_xform, ts_params->sess_mp);
 	}
 
-	return sess;
+	return test_crypto_session;
 }
 
 static inline struct rte_crypto_op *
@@ -4407,7 +4466,7 @@ perf_AES_GCM(uint8_t dev_id, uint16_t queue_id,
 
 	for (i = 0; i < burst; i++)
 		rte_pktmbuf_free(mbufs[i]);
-	rte_cryptodev_sym_session_free(dev_id, sess);
+	rte_cryptodev_sym_session_free(sess);
 
 	return 0;
 }
-- 
2.9.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v3 08/12] cryptodev: remove mempool from session
                       ` (3 preceding siblings ...)
  2017-07-02 15:57  3%   ` [dpdk-dev] [PATCH v3 07/12] cryptodev: remove driver id from session Pablo de Lara
@ 2017-07-02 15:57  4%   ` Pablo de Lara
  2017-07-02 15:57  1%   ` [dpdk-dev] [PATCH v3 09/12] cryptodev: support device independent sessions Pablo de Lara
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Mempool pointer can be obtained from the object itself,
which means that it is not required to actually store the pointer
in the session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 7 +++----
 lib/librte_cryptodev/rte_cryptodev.h   | 6 ------
 3 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index b0657ec..785489a 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -165,6 +165,7 @@ API Changes
     the new parameter ``device id``.
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
   * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
+  * Mempool pointer ``mp`` has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index b0b4816..5c7191b 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1026,8 +1026,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->mp = mp;
-
 	if (dev->dev_ops->session_initialize)
 		(*dev->dev_ops->session_initialize)(mp, sess);
 }
@@ -1065,7 +1063,7 @@ rte_cryptodev_sym_session_create(uint8_t dev_id,
 				dev_id);
 
 		/* Return session to mempool */
-		rte_mempool_put(sess->mp, _sess);
+		rte_mempool_put(dev->data->session_pool, _sess);
 		return NULL;
 	}
 
@@ -1137,7 +1135,8 @@ rte_cryptodev_sym_session_free(uint8_t dev_id,
 	dev->dev_ops->session_clear(dev, (void *)sess->_private);
 
 	/* Return session to mempool */
-	rte_mempool_put(sess->mp, (void *)sess);
+	struct rte_mempool *mp = rte_mempool_from_obj(sess);
+	rte_mempool_put(mp, (void *)sess);
 
 	return NULL;
 }
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 7d574f1..044a4aa 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -797,12 +797,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 /** Cryptodev symmetric crypto session */
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
-	struct {
-		struct rte_mempool *mp;
-		/**< Mempool session allocated from */
-	} __rte_aligned(8);
-	/**< Public symmetric session details */
-
 	__extension__ char _private[0];
 	/**< Private session material */
 };
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v3 07/12] cryptodev: remove driver id from session
                       ` (2 preceding siblings ...)
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 06/12] cryptodev: remove device id from crypto session Pablo de Lara
@ 2017-07-02 15:57  3%   ` Pablo de Lara
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 08/12] cryptodev: remove mempool " Pablo de Lara
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Since crypto session will not be attached to a specific
device or driver, the field driver_id is not required
anymore (only used to check that a session was being
handled by the right device).

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst     | 1 +
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c   | 4 ----
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 5 -----
 drivers/crypto/armv8/rte_armv8_pmd.c       | 4 +---
 drivers/crypto/kasumi/rte_kasumi_pmd.c     | 4 ----
 drivers/crypto/null/null_crypto_pmd.c      | 3 +--
 drivers/crypto/openssl/rte_openssl_pmd.c   | 4 +---
 drivers/crypto/qat/qat_crypto.c            | 6 ------
 drivers/crypto/snow3g/rte_snow3g_pmd.c     | 4 ----
 drivers/crypto/zuc/rte_zuc_pmd.c           | 4 ----
 lib/librte_cryptodev/rte_cryptodev.c       | 5 -----
 lib/librte_cryptodev/rte_cryptodev.h       | 2 --
 12 files changed, 4 insertions(+), 42 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index f401ffb..b0657ec 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -164,6 +164,7 @@ API Changes
     ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
     the new parameter ``device id``.
   * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
+  * ``driver_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index ef290a3..2774b4e 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -146,10 +146,6 @@ aesni_gcm_get_session(struct aesni_gcm_qp *qp, struct rte_crypto_sym_op *op)
 	struct aesni_gcm_session *sess = NULL;
 
 	if (op->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->session->driver_id !=
-				cryptodev_driver_id))
-			return sess;
-
 		sess = (struct aesni_gcm_session *)op->session->_private;
 	} else  {
 		void *_sess;
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 4025978..ec348ab 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -348,11 +348,6 @@ get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *op)
 	struct aesni_mb_session *sess = NULL;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id)) {
-			return NULL;
-		}
-
 		sess = (struct aesni_mb_session *)op->sym->session->_private;
 	} else  {
 		void *_sess = NULL;
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index 9fe781b..1ddf6a2 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -549,9 +549,7 @@ get_session(struct armv8_crypto_qp *qp, struct rte_crypto_op *op)
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
 		/* get existing session */
-		if (likely(op->sym->session != NULL &&
-				op->sym->session->driver_id ==
-				cryptodev_driver_id)) {
+		if (likely(op->sym->session != NULL)) {
 			sess = (struct armv8_crypto_session *)
 				op->sym->session->_private;
 		}
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index a1a33c5..67f0b06 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -146,10 +146,6 @@ kasumi_get_session(struct kasumi_qp *qp, struct rte_crypto_op *op)
 	struct kasumi_session *sess;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct kasumi_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index 50ede06..9323874 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -97,8 +97,7 @@ get_session(struct null_crypto_qp *qp, struct rte_crypto_sym_op *op)
 	struct null_crypto_session *sess;
 
 	if (op->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->session == NULL || op->session->driver_id !=
-				cryptodev_driver_id))
+		if (unlikely(op->session == NULL))
 			return NULL;
 
 		sess = (struct null_crypto_session *)op->session->_private;
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 4e4394f..3232455 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -450,9 +450,7 @@ get_session(struct openssl_qp *qp, struct rte_crypto_op *op)
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
 		/* get existing session */
-		if (likely(op->sym->session != NULL &&
-				op->sym->session->driver_id ==
-				cryptodev_driver_id))
+		if (likely(op->sym->session != NULL))
 			sess = (struct openssl_session *)
 				op->sym->session->_private;
 	} else  {
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index 7c5a9a8..13bd0b5 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -914,12 +914,6 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		return -EINVAL;
 	}
 
-	if (unlikely(op->sym->session->driver_id !=
-			cryptodev_qat_driver_id)) {
-		PMD_DRV_LOG(ERR, "Session was not created for this device");
-		return -EINVAL;
-	}
-
 	ctx = (struct qat_session *)op->sym->session->_private;
 	qat_req = (struct icp_qat_fw_la_bulk_req *)out_msg;
 	rte_mov128((uint8_t *)qat_req, (const uint8_t *)&(ctx->fw_req));
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index 35a2bcd..677849d 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -146,10 +146,6 @@ snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
 	struct snow3g_session *sess;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct snow3g_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index ff8f3b9..385e4e5 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -145,10 +145,6 @@ zuc_get_session(struct zuc_qp *qp, struct rte_crypto_op *op)
 	struct zuc_session *sess;
 
 	if (op->sym->sess_type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
-		if (unlikely(op->sym->session->driver_id !=
-				cryptodev_driver_id))
-			return NULL;
-
 		sess = (struct zuc_session *)op->sym->session->_private;
 	} else  {
 		struct rte_cryptodev_sym_session *c_sess = NULL;
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index aa35b79..b0b4816 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1026,7 +1026,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->driver_id = dev->driver_id;
 	sess->mp = mp;
 
 	if (dev->dev_ops->session_initialize)
@@ -1133,10 +1132,6 @@ rte_cryptodev_sym_session_free(uint8_t dev_id,
 
 	dev = &rte_crypto_devices[dev_id];
 
-	/* Check the session belongs to this device type */
-	if (sess->driver_id != dev->driver_id)
-		return sess;
-
 	/* Let device implementation clear session material */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_clear, sess);
 	dev->dev_ops->session_clear(dev, (void *)sess->_private);
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 77a763d..7d574f1 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -798,8 +798,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
 	struct {
-		uint8_t driver_id;
-		/** Crypto driver identifier session created on */
 		struct rte_mempool *mp;
 		/**< Mempool session allocated from */
 	} __rte_aligned(8);
-- 
2.9.4

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v3 06/12] cryptodev: remove device id from crypto session
    2017-07-02 15:57  2%   ` [dpdk-dev] [PATCH v3 04/12] cryptodev: do not create session mempool internally Pablo de Lara
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
@ 2017-07-02 15:57  4%   ` Pablo de Lara
  2017-07-02 15:57  3%   ` [dpdk-dev] [PATCH v3 07/12] cryptodev: remove driver id from session Pablo de Lara
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Device id is necessary in the crypto session,
as it was only used for the functions that attach/detach
a session to a queue pair.

Since the session is not going to be attached to a device
anymore, this is field is no longer necessary.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst | 1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 1 -
 lib/librte_cryptodev/rte_cryptodev.h   | 2 --
 3 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index c7e58c6..f401ffb 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -163,6 +163,7 @@ API Changes
   * ``rte_cryptodev_queue_pair_attach_sym_session()`` and
     ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
     the new parameter ``device id``.
+  * ``dev_id`` field has been removed from ``rte_cryptodev_sym_session`` structure.
 
 
 ABI Changes
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 477e28f..aa35b79 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1026,7 +1026,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 {
 	memset(sess, 0, mp->elt_size);
 
-	sess->dev_id = dev->data->dev_id;
 	sess->driver_id = dev->driver_id;
 	sess->mp = mp;
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index d3d2794..77a763d 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -798,8 +798,6 @@ rte_cryptodev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
 struct rte_cryptodev_sym_session {
 	RTE_STD_C11
 	struct {
-		uint8_t dev_id;
-		/**< Device Id */
 		uint8_t driver_id;
 		/** Crypto driver identifier session created on */
 		struct rte_mempool *mp;
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v3 05/12] cryptodev: change attach session to queue pair API
    2017-07-02 15:57  2%   ` [dpdk-dev] [PATCH v3 04/12] cryptodev: do not create session mempool internally Pablo de Lara
@ 2017-07-02 15:57  4%   ` Pablo de Lara
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 06/12] cryptodev: remove device id from crypto session Pablo de Lara
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Device id is going to be removed from session,
as the session will be device independent.
Therefore, the functions that attach/dettach a session
to a queue pair need to be updated, to accept the device id
as a parameter, apart from the queue pair id and the session.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 doc/guides/rel_notes/release_17_08.rst |  3 +++
 examples/ipsec-secgw/ipsec.c           |  1 +
 lib/librte_cryptodev/rte_cryptodev.c   | 20 ++++++++++----------
 lib/librte_cryptodev/rte_cryptodev.h   | 10 ++++++----
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 8cc01b2..c7e58c6 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -160,6 +160,9 @@ API Changes
   * ``rte_cryptodev_configure()`` does not create the session mempool
     for the device anymore.
   * Removed ``session_mp`` from ``rte_cryptodev_config``.
+  * ``rte_cryptodev_queue_pair_attach_sym_session()`` and
+    ``rte_cryptodev_queue_pair_dettach_sym_session()`` functions require
+    the new parameter ``device id``.
 
 
 ABI Changes
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index edca5f0..048e441 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -77,6 +77,7 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 	rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id, &cdev_info);
 	if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
 		ret = rte_cryptodev_queue_pair_attach_sym_session(
+				ipsec_ctx->tbl[cdev_id_qp].id,
 				ipsec_ctx->tbl[cdev_id_qp].qp,
 				sa->crypto_session);
 		if (ret < 0) {
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index dd10b99..477e28f 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -1075,23 +1075,23 @@ rte_cryptodev_sym_session_create(uint8_t dev_id,
 }
 
 int
-rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *sess)
 {
 	struct rte_cryptodev *dev;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(sess->dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", sess->dev_id);
+	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
+		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
 		return -EINVAL;
 	}
 
-	dev = &rte_crypto_devices[sess->dev_id];
+	dev = &rte_crypto_devices[dev_id];
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_attach_session, 0);
 	if (dev->dev_ops->qp_attach_session(dev, qp_id, sess->_private)) {
 		CDEV_LOG_ERR("dev_id %d failed to attach qp: %d with session",
-				sess->dev_id, qp_id);
+				dev_id, qp_id);
 		return -EPERM;
 	}
 
@@ -1099,23 +1099,23 @@ rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
 }
 
 int
-rte_cryptodev_queue_pair_detach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *sess)
 {
 	struct rte_cryptodev *dev;
 
-	if (!rte_cryptodev_pmd_is_valid_dev(sess->dev_id)) {
-		CDEV_LOG_ERR("Invalid dev_id=%d", sess->dev_id);
+	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
+		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
 		return -EINVAL;
 	}
 
-	dev = &rte_crypto_devices[sess->dev_id];
+	dev = &rte_crypto_devices[dev_id];
 
 	/* The API is optional, not returning error if driver do not suuport */
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->qp_detach_session, 0);
 	if (dev->dev_ops->qp_detach_session(dev, qp_id, sess->_private)) {
 		CDEV_LOG_ERR("dev_id %d failed to detach qp: %d from session",
-				sess->dev_id, qp_id);
+				dev_id, qp_id);
 		return -EPERM;
 	}
 
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 1afd2d8..d3d2794 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -867,7 +867,8 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id);
 /**
  * Attach queue pair with sym session.
  *
- * @param	qp_id		Queue pair to which session will be attached.
+ * @param	dev_id		Device to which the session will be attached.
+ * @param	qp_id		Queue pair to which the session will be attached.
  * @param	session		Session pointer previously allocated by
  *				*rte_cryptodev_sym_session_create*.
  *
@@ -876,13 +877,14 @@ rte_cryptodev_get_private_session_size(uint8_t dev_id);
  *  - On failure, a negative value.
  */
 int
-rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_attach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *session);
 
 /**
  * Detach queue pair with sym session.
  *
- * @param	qp_id		Queue pair to which session is attached.
+ * @param	dev_id		Device to which the session is attached.
+ * @param	qp_id		Queue pair to which the session is attached.
  * @param	session		Session pointer previously allocated by
  *				*rte_cryptodev_sym_session_create*.
  *
@@ -891,7 +893,7 @@ rte_cryptodev_queue_pair_attach_sym_session(uint16_t qp_id,
  *  - On failure, a negative value.
  */
 int
-rte_cryptodev_queue_pair_detach_sym_session(uint16_t qp_id,
+rte_cryptodev_queue_pair_detach_sym_session(uint8_t dev_id, uint16_t qp_id,
 		struct rte_cryptodev_sym_session *session);
 
 /**
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v3 04/12] cryptodev: do not create session mempool internally
  @ 2017-07-02 15:57  2%   ` Pablo de Lara
  2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02 15:57 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Slawomir Mrozowicz, Pablo de Lara

From: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>

Instead of creating the session mempool while configuring
the crypto device, apps will create the mempool themselves.
This way, it gives flexibility to the user to have a single
mempool for all devices (as long as the objects are big
enough to contain the biggest private session size) or
separate mempools for different drivers.

Also, since the mempool is now created outside the
device configuration function, now it needs to be passed
through this function, which will be eventually passed
when setting up the queue pairs, as ethernet devices do.

Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 app/test-crypto-perf/main.c                  | 91 +++++++++++++++++++++-------
 doc/guides/rel_notes/release_17_08.rst       |  3 +
 drivers/crypto/scheduler/scheduler_pmd_ops.c | 12 +---
 examples/ipsec-secgw/ipsec-secgw.c           | 42 +++++++++++--
 examples/ipsec-secgw/ipsec.h                 |  2 +
 examples/l2fwd-crypto/main.c                 | 65 ++++++++++++++++----
 lib/librte_cryptodev/rte_cryptodev.c         | 77 ++---------------------
 lib/librte_cryptodev/rte_cryptodev.h         |  9 +--
 test/test/test_cryptodev.c                   | 85 ++++++++++++++++++++------
 test/test/test_cryptodev_perf.c              | 24 +++++++-
 10 files changed, 260 insertions(+), 150 deletions(-)

diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 9ec2a4b..e013e82 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -11,6 +11,9 @@
 #include "cperf_test_latency.h"
 #include "cperf_test_verify.h"
 
+#define NUM_SESSIONS 2048
+#define SESS_MEMPOOL_CACHE_SIZE 64
+
 const char *cperf_test_type_strs[] = {
 	[CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
 	[CPERF_TEST_TYPE_LATENCY] = "latency",
@@ -44,9 +47,11 @@ const struct cperf_test cperf_testmap[] = {
 };
 
 static int
-cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
+cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs,
+			struct rte_mempool *session_pool_socket[])
 {
-	uint8_t cdev_id, enabled_cdev_count = 0, nb_lcores;
+	uint8_t enabled_cdev_count = 0, nb_lcores;
+	unsigned int i;
 	int ret;
 
 	enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
@@ -66,40 +71,78 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
 		return -EINVAL;
 	}
 
-	for (cdev_id = 0; cdev_id < enabled_cdev_count &&
-			cdev_id < RTE_CRYPTO_MAX_DEVS; cdev_id++) {
+	/* Create a mempool shared by all the devices */
+	uint32_t max_sess_size = 0, sess_size;
+
+	for (i = 0; i < enabled_cdev_count &&
+			i < RTE_CRYPTO_MAX_DEVS; i++) {
+		uint8_t cdev_id = enabled_cdevs[i];
+		sess_size = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_size > max_sess_size)
+			max_sess_size = sess_size;
+	}
+
+
+	for (i = 0; i < enabled_cdev_count &&
+			i < RTE_CRYPTO_MAX_DEVS; i++) {
+		uint8_t cdev_id = enabled_cdevs[i];
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
 
 		struct rte_cryptodev_config conf = {
 				.nb_queue_pairs = 1,
-				.socket_id = SOCKET_ID_ANY,
-				.session_mp = {
-					.nb_objs = 2048,
-					.cache_size = 64
-				}
-			};
+				.socket_id = socket_id
+		};
+
 		struct rte_cryptodev_qp_conf qp_conf = {
 				.nb_descriptors = 2048
 		};
 
-		ret = rte_cryptodev_configure(enabled_cdevs[cdev_id], &conf);
+
+		if (session_pool_socket[socket_id] == NULL) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+				"sess_mp_%u", socket_id);
+
+			sess_mp = rte_mempool_create(mp_name,
+						NUM_SESSIONS,
+						max_sess_size,
+						SESS_MEMPOOL_CACHE_SIZE,
+						0, NULL, NULL, NULL,
+						NULL, socket_id,
+						0);
+
+			if (sess_mp == NULL) {
+				printf("Cannot create session pool on socket %d\n",
+					socket_id);
+				return -ENOMEM;
+			}
+
+			printf("Allocated session pool on socket %d\n", socket_id);
+			session_pool_socket[socket_id] = sess_mp;
+		}
+
+		ret = rte_cryptodev_configure(cdev_id, &conf,
+				session_pool_socket[socket_id]);
 		if (ret < 0) {
-			printf("Failed to configure cryptodev %u",
-					enabled_cdevs[cdev_id]);
+			printf("Failed to configure cryptodev %u", cdev_id);
 			return -EINVAL;
 		}
 
-		ret = rte_cryptodev_queue_pair_setup(enabled_cdevs[cdev_id], 0,
-				&qp_conf, SOCKET_ID_ANY);
-			if (ret < 0) {
-				printf("Failed to setup queue pair %u on "
-					"cryptodev %u",	0, cdev_id);
-				return -EINVAL;
-			}
+		ret = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
+				socket_id);
+		if (ret < 0) {
+			printf("Failed to setup queue pair %u on "
+				"cryptodev %u",	0, cdev_id);
+			return -EINVAL;
+		}
 
-		ret = rte_cryptodev_start(enabled_cdevs[cdev_id]);
+		ret = rte_cryptodev_start(cdev_id);
 		if (ret < 0) {
 			printf("Failed to start device %u: error %d\n",
-					enabled_cdevs[cdev_id], ret);
+					cdev_id, ret);
 			return -EPERM;
 		}
 	}
@@ -274,6 +317,7 @@ main(int argc, char **argv)
 	struct cperf_op_fns op_fns;
 
 	void *ctx[RTE_MAX_LCORE] = { };
+	struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
 
 	int nb_cryptodevs = 0;
 	uint8_t cdev_id, i;
@@ -309,7 +353,8 @@ main(int argc, char **argv)
 	if (!opts.silent)
 		cperf_options_dump(&opts);
 
-	nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs);
+	nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs,
+			session_pool_socket);
 	if (nb_cryptodevs < 1) {
 		RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
 				"device type\n");
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 1dcd4d7..8cc01b2 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -157,6 +157,9 @@ API Changes
 
   * Device type identification is changed to be based on a unique 1-byte driver id,
     replacing the previous device type enumeration.
+  * ``rte_cryptodev_configure()`` does not create the session mempool
+    for the device anymore.
+  * Removed ``session_mp`` from ``rte_cryptodev_config``.
 
 
 ABI Changes
diff --git a/drivers/crypto/scheduler/scheduler_pmd_ops.c b/drivers/crypto/scheduler/scheduler_pmd_ops.c
index 90e3734..b9d8973 100644
--- a/drivers/crypto/scheduler/scheduler_pmd_ops.c
+++ b/drivers/crypto/scheduler/scheduler_pmd_ops.c
@@ -85,10 +85,8 @@ scheduler_attach_init_slave(struct rte_cryptodev *dev)
 /** Configure device */
 static int
 scheduler_pmd_config(struct rte_cryptodev *dev,
-		struct rte_cryptodev_config *config)
+		struct rte_cryptodev_config *config __rte_unused)
 {
-	struct scheduler_ctx *sched_ctx = dev->data->dev_private;
-	uint32_t i;
 	int ret;
 
 	/* although scheduler_attach_init_slave presents multiple times,
@@ -98,14 +96,6 @@ scheduler_pmd_config(struct rte_cryptodev *dev,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < sched_ctx->nb_slaves; i++) {
-		uint8_t slave_dev_id = sched_ctx->slaves[i].dev_id;
-
-		ret = rte_cryptodev_configure(slave_dev_id, config);
-		if (ret < 0)
-			break;
-	}
-
 	return ret;
 }
 
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 8cbf6ac..4d6c7ce 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -710,10 +710,12 @@ main_loop(__attribute__((unused)) void *dummy)
 	qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
 	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
 	qconf->inbound.cdev_map = cdev_map_in;
+	qconf->inbound.session_pool = socket_ctx[socket_id].session_pool;
 	qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
 	qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
 	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
 	qconf->outbound.cdev_map = cdev_map_out;
+	qconf->outbound.session_pool = socket_ctx[socket_id].session_pool;
 
 	if (qconf->nb_rx_queue == 0) {
 		RTE_LOG(INFO, IPSEC, "lcore %u has nothing to do\n", lcore_id);
@@ -1238,6 +1240,14 @@ cryptodevs_init(void)
 
 	printf("lcore/cryptodev/qp mappings:\n");
 
+	uint32_t max_sess_sz = 0, sess_sz;
+	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
+		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_sz > max_sess_sz)
+			max_sess_sz = sess_sz;
+	}
+
 	idx = 0;
 	/* Start from last cdev id to give HW priority */
 	for (cdev_id = rte_cryptodev_count() - 1; cdev_id >= 0; cdev_id--) {
@@ -1266,11 +1276,33 @@ cryptodevs_init(void)
 
 		dev_conf.socket_id = rte_cryptodev_socket_id(cdev_id);
 		dev_conf.nb_queue_pairs = qp;
-		dev_conf.session_mp.nb_objs = CDEV_MP_NB_OBJS;
-		dev_conf.session_mp.cache_size = CDEV_MP_CACHE_SZ;
 
-		if (rte_cryptodev_configure(cdev_id, &dev_conf))
-			rte_panic("Failed to initialize crypodev %u\n",
+		if (!socket_ctx[dev_conf.socket_id].session_pool) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+					"sess_mp_%u", dev_conf.socket_id);
+			sess_mp = rte_mempool_create(mp_name,
+					CDEV_MP_NB_OBJS,
+					max_sess_sz,
+					CDEV_MP_CACHE_SZ,
+					0, NULL, NULL, NULL,
+					NULL, dev_conf.socket_id,
+					0);
+			if (sess_mp == NULL)
+				rte_exit(EXIT_FAILURE,
+					"Cannot create session pool on socket %d\n",
+					dev_conf.socket_id);
+			else
+				printf("Allocated session pool on socket %d\n",
+					dev_conf.socket_id);
+			socket_ctx[dev_conf.socket_id].session_pool = sess_mp;
+		}
+
+		if (rte_cryptodev_configure(cdev_id, &dev_conf,
+				socket_ctx[dev_conf.socket_id].session_pool))
+			rte_panic("Failed to initialize cryptodev %u\n",
 					cdev_id);
 
 		qp_conf.nb_descriptors = CDEV_QUEUE_DESC;
@@ -1433,7 +1465,7 @@ main(int32_t argc, char **argv)
 
 	nb_lcores = rte_lcore_count();
 
-	/* Replicate each contex per socket */
+	/* Replicate each context per socket */
 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
 		if (rte_lcore_is_enabled(lcore_id) == 0)
 			continue;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 1d63161..593b0a2 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -139,6 +139,7 @@ struct ipsec_ctx {
 	uint16_t nb_qps;
 	uint16_t last_qp;
 	struct cdev_qp tbl[MAX_QP_PER_LCORE];
+	struct rte_mempool *session_pool;
 };
 
 struct cdev_key {
@@ -157,6 +158,7 @@ struct socket_ctx {
 	struct rt_ctx *rt_ip4;
 	struct rt_ctx *rt_ip6;
 	struct rte_mempool *mbuf_pool;
+	struct rte_mempool *session_pool;
 };
 
 struct cnt_blk {
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 779b4fb..add9291 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -88,6 +88,8 @@ enum cdev_type {
 #define MAX_KEY_SIZE 128
 #define MAX_PKT_BURST 32
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+#define MAX_SESSIONS 32
+#define SESSION_POOL_CACHE_SIZE 0
 
 /*
  * Configurable number of RX/TX ring descriptors
@@ -223,6 +225,7 @@ static const struct rte_eth_conf port_conf = {
 
 struct rte_mempool *l2fwd_pktmbuf_pool;
 struct rte_mempool *l2fwd_crypto_op_pool;
+struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
 
 /* Per-port statistics struct */
 struct l2fwd_port_statistics {
@@ -587,8 +590,7 @@ generate_random_key(uint8_t *key, unsigned length)
 }
 
 static struct rte_cryptodev_sym_session *
-initialize_crypto_session(struct l2fwd_crypto_options *options,
-		uint8_t cdev_id)
+initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
 {
 	struct rte_crypto_sym_xform *first_xform;
 
@@ -604,7 +606,6 @@ initialize_crypto_session(struct l2fwd_crypto_options *options,
 		first_xform = &options->auth_xform;
 	}
 
-	/* Setup Cipher Parameters */
 	return rte_cryptodev_sym_session_create(cdev_id, first_xform);
 }
 
@@ -626,6 +627,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 			US_PER_S * BURST_TX_DRAIN_US;
 	struct l2fwd_crypto_params *cparams;
 	struct l2fwd_crypto_params port_cparams[qconf->nb_crypto_devs];
+	struct rte_cryptodev_sym_session *session;
 
 	if (qconf->nb_rx_ports == 0) {
 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
@@ -698,11 +700,13 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 			port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
 		}
 
-		port_cparams[i].session = initialize_crypto_session(options,
+		session = initialize_crypto_session(options,
 				port_cparams[i].dev_id);
+		if (session == NULL)
+			rte_exit(EXIT_FAILURE, "Failed to initialize crypto session\n");
+
+		port_cparams[i].session = session;
 
-		if (port_cparams[i].session == NULL)
-			return;
 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u cryptoid=%u\n", lcore_id,
 				port_cparams[i].dev_id);
 	}
@@ -1550,6 +1554,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 	enum rte_crypto_auth_algorithm opt_auth_algo;
 	enum rte_crypto_cipher_algorithm cap_cipher_algo;
 	enum rte_crypto_cipher_algorithm opt_cipher_algo;
+	unsigned int sess_sz, max_sess_sz = 0;
 	int retval;
 
 	cdev_count = rte_cryptodev_count();
@@ -1558,18 +1563,22 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		return -1;
 	}
 
+	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
+		sess_sz = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(cdev_id);
+		if (sess_sz > max_sess_sz)
+			max_sess_sz = sess_sz;
+	}
+
 	for (cdev_id = 0; cdev_id < cdev_count && enabled_cdev_count < nb_ports;
 			cdev_id++) {
 		struct rte_cryptodev_qp_conf qp_conf;
 		struct rte_cryptodev_info dev_info;
+		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
 
 		struct rte_cryptodev_config conf = {
 			.nb_queue_pairs = 1,
-			.socket_id = SOCKET_ID_ANY,
-			.session_mp = {
-				.nb_objs = 2048,
-				.cache_size = 64
-			}
+			.socket_id = socket_id,
 		};
 
 		if (check_cryptodev_mask(options, (uint8_t)cdev_id))
@@ -1577,6 +1586,35 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 
 		rte_cryptodev_info_get(cdev_id, &dev_info);
 
+		if (session_pool_socket[socket_id] == NULL) {
+			char mp_name[RTE_MEMPOOL_NAMESIZE];
+			struct rte_mempool *sess_mp;
+
+			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
+				"sess_mp_%u", socket_id);
+
+			/*
+			 * Create enough objects for session headers and
+			 * device private data
+			 */
+			sess_mp = rte_mempool_create(mp_name,
+						MAX_SESSIONS * 2,
+						max_sess_sz,
+						SESSION_POOL_CACHE_SIZE,
+						0, NULL, NULL, NULL,
+						NULL, socket_id,
+						0);
+
+			if (sess_mp == NULL) {
+				printf("Cannot create session pool on socket %d\n",
+					socket_id);
+				return -ENOMEM;
+			}
+
+			printf("Allocated session pool on socket %d\n", socket_id);
+			session_pool_socket[socket_id] = sess_mp;
+		}
+
 		/* Set cipher parameters */
 		if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH ||
 				options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER ||
@@ -1797,7 +1835,8 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 						cap->sym.auth.digest_size.min;
 		}
 
-		retval = rte_cryptodev_configure(cdev_id, &conf);
+		retval = rte_cryptodev_configure(cdev_id, &conf,
+				session_pool_socket[socket_id]);
 		if (retval < 0) {
 			printf("Failed to configure cryptodev %u", cdev_id);
 			return -1;
@@ -1806,7 +1845,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
 		qp_conf.nb_descriptors = 2048;
 
 		retval = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
-				SOCKET_ID_ANY);
+				socket_id);
 		if (retval < 0) {
 			printf("Failed to setup queue pair %u on cryptodev %u",
 					0, cdev_id);
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index cb6f5ec..dd10b99 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -683,12 +683,9 @@ rte_cryptodev_queue_pair_stop(uint8_t dev_id, uint16_t queue_pair_id)
 
 }
 
-static int
-rte_cryptodev_sym_session_pool_create(struct rte_cryptodev *dev,
-		unsigned nb_objs, unsigned obj_cache_size, int socket_id);
-
 int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
+		struct rte_mempool *session_pool)
 {
 	struct rte_cryptodev *dev;
 	int diag;
@@ -708,6 +705,8 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
 
+	dev->data->session_pool = session_pool;
+
 	/* Setup new number of queue pairs and reconfigure device. */
 	diag = rte_cryptodev_queue_pairs_config(dev, config->nb_queue_pairs,
 			config->socket_id);
@@ -717,14 +716,6 @@ rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config)
 		return diag;
 	}
 
-	/* Setup Session mempool for device */
-	diag = rte_cryptodev_sym_session_pool_create(dev,
-			config->session_mp.nb_objs,
-			config->session_mp.cache_size,
-			config->socket_id);
-	if (diag != 0)
-		return diag;
-
 	return (*dev->dev_ops->dev_configure)(dev, config);
 }
 
@@ -1043,66 +1034,6 @@ rte_cryptodev_sym_session_init(struct rte_mempool *mp,
 		(*dev->dev_ops->session_initialize)(mp, sess);
 }
 
-static int
-rte_cryptodev_sym_session_pool_create(struct rte_cryptodev *dev,
-		unsigned nb_objs, unsigned obj_cache_size, int socket_id)
-{
-	char mp_name[RTE_CRYPTODEV_NAME_MAX_LEN];
-	unsigned priv_sess_size;
-
-	unsigned n = snprintf(mp_name, sizeof(mp_name), "cdev_%d_sess_mp",
-			dev->data->dev_id);
-	if (n > sizeof(mp_name)) {
-		CDEV_LOG_ERR("Unable to create unique name for session mempool");
-		return -ENOMEM;
-	}
-
-	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->session_get_size, -ENOTSUP);
-	priv_sess_size = (*dev->dev_ops->session_get_size)(dev);
-	if (priv_sess_size == 0) {
-		CDEV_LOG_ERR("%s returned and invalid private session size ",
-						dev->data->name);
-		return -ENOMEM;
-	}
-
-	unsigned elt_size = sizeof(struct rte_cryptodev_sym_session) +
-			priv_sess_size;
-
-	dev->data->session_pool = rte_mempool_lookup(mp_name);
-	if (dev->data->session_pool != NULL) {
-		if ((dev->data->session_pool->elt_size != elt_size) ||
-				(dev->data->session_pool->cache_size <
-				obj_cache_size) ||
-				(dev->data->session_pool->size < nb_objs)) {
-
-			CDEV_LOG_ERR("%s mempool already exists with different"
-					" initialization parameters", mp_name);
-			dev->data->session_pool = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		dev->data->session_pool = rte_mempool_create(
-				mp_name, /* mempool name */
-				nb_objs, /* number of elements*/
-				elt_size, /* element size*/
-				obj_cache_size, /* Cache size*/
-				0, /* private data size */
-				NULL, /* obj initialization constructor */
-				NULL, /* obj initialization constructor arg */
-				NULL, /**< obj constructor*/
-				dev, /* obj constructor arg */
-				socket_id, /* socket id */
-				0); /* flags */
-
-		if (dev->data->session_pool == NULL) {
-			CDEV_LOG_ERR("%s mempool allocation failed", mp_name);
-			return -ENOMEM;
-		}
-	}
-
-	CDEV_LOG_DEBUG("%s mempool created!", mp_name);
-	return 0;
-}
 
 struct rte_cryptodev_sym_session *
 rte_cryptodev_sym_session_create(uint8_t dev_id,
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index d883d8c..1afd2d8 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -428,11 +428,6 @@ struct rte_cryptodev_config {
 	int socket_id;			/**< Socket to allocate resources on */
 	uint16_t nb_queue_pairs;
 	/**< Number of queue pairs to configure on device */
-
-	struct {
-		uint32_t nb_objs;	/**< Number of objects in mempool */
-		uint32_t cache_size;	/**< l-core object cache size */
-	} session_mp;		/**< Session mempool configuration */
 };
 
 /**
@@ -444,13 +439,15 @@ struct rte_cryptodev_config {
  *
  * @param	dev_id		The identifier of the device to configure.
  * @param	config		The crypto device configuration structure.
+ * @param	session_pool	Pointer to device session mempool
  *
  * @return
  *   - 0: Success, device configured.
  *   - <0: Error code returned by the driver configuration function.
  */
 extern int
-rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config);
+rte_cryptodev_configure(uint8_t dev_id, struct rte_cryptodev_config *config,
+		struct rte_mempool *session_pool);
 
 /**
  * Start an device.
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index afa895e..cdc1cbf 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -66,6 +66,8 @@ struct crypto_testsuite_params {
 	struct rte_mempool *mbuf_pool;
 	struct rte_mempool *large_mbuf_pool;
 	struct rte_mempool *op_mpool;
+	struct rte_mempool *session_mpool;
+	struct rte_mempool *slave_session_mpool;
 	struct rte_cryptodev_config conf;
 	struct rte_cryptodev_qp_conf qp_conf;
 
@@ -381,10 +383,23 @@ testsuite_setup(void)
 
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions;
+
+	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+		rte_cryptodev_get_private_session_size(dev_id);
+
+	ts_params->session_mpool = rte_mempool_create(
+				"test_sess_mp",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL,
+				NULL, SOCKET_ID_ANY,
+				0);
+
+	TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
+			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id,
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev %u with %u qps",
 			dev_id, ts_params->conf.nb_queue_pairs);
 
@@ -416,6 +431,16 @@ testsuite_teardown(void)
 		rte_mempool_avail_count(ts_params->op_mpool));
 	}
 
+	/* Free session mempools */
+	if (ts_params->session_mpool != NULL) {
+		rte_mempool_free(ts_params->session_mpool);
+		ts_params->session_mpool = NULL;
+	}
+
+	if (ts_params->slave_session_mpool != NULL) {
+		rte_mempool_free(ts_params->slave_session_mpool);
+		ts_params->slave_session_mpool = NULL;
+	}
 }
 
 static int
@@ -431,10 +456,9 @@ ut_setup(void)
 
 	/* Reconfigure device to default parameters */
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = DEFAULT_NUM_OPS_INFLIGHT;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
@@ -517,20 +541,23 @@ test_device_configure_invalid_dev_id(void)
 	/* Stop the device in case it's started so it can be configured */
 	rte_cryptodev_stop(ts_params->valid_devs[dev_id]);
 
-	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	/* invalid dev_id values */
 	dev_id = num_devs;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure: "
 			"invalid dev_num %u", dev_id);
 
 	dev_id = 0xff;
 
-	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf),
+	TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf,
+				ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure:"
 			"invalid dev_num %u", dev_id);
 
@@ -550,7 +577,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = 1;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
 			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
 
@@ -559,16 +586,17 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE;
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed to configure cryptodev: dev_id %u, qp_id %u",
-			ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs);
+			ts_params->valid_devs[0],
+			ts_params->conf.nb_queue_pairs);
 
 
 	/* invalid - zero queue pairs */
 	ts_params->conf.nb_queue_pairs = 0;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -579,7 +607,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = UINT16_MAX;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -590,7 +618,7 @@ test_device_configure_invalid_queue_pair_ids(void)
 	ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE + 1;
 
 	TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf),
+			&ts_params->conf, ts_params->session_mpool),
 			"Failed test for rte_cryptodev_configure, dev_id %u,"
 			" invalid qps: %u",
 			ts_params->valid_devs[0],
@@ -619,13 +647,11 @@ test_queue_pair_descriptor_setup(void)
 
 	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
 
-	ts_params->conf.session_mp.nb_objs = dev_info.sym.max_nb_sessions;
-
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0],
-			&ts_params->conf), "Failed to configure cryptodev %u",
+			&ts_params->conf, ts_params->session_mpool),
+			"Failed to configure cryptodev %u",
 			ts_params->valid_devs[0]);
 
-
 	/*
 	 * Test various ring sizes on this device. memzones can't be
 	 * freed so are re-used if ring is released and re-created.
@@ -7837,6 +7863,31 @@ test_scheduler_attach_slave_op(void)
 				RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)))
 			continue;
 
+		/*
+		 * Create a separate mempool for the slaves, as they need different
+		 * session size and then configure them to store the pointer
+		 * to this mempool
+		 */
+		unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+			rte_cryptodev_get_private_session_size(i);
+
+		if (ts_params->slave_session_mpool == NULL) {
+			ts_params->slave_session_mpool = rte_mempool_create(
+				"test_slave_sess_mp",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL, NULL,
+				SOCKET_ID_ANY, 0);
+
+			TEST_ASSERT_NOT_NULL(ts_params->slave_session_mpool,
+					"session mempool allocation failed");
+		}
+
+		TEST_ASSERT_SUCCESS(rte_cryptodev_configure(i,
+				&ts_params->conf, ts_params->slave_session_mpool),
+				"Failed to configure cryptodev %u with %u qps",
+				i, ts_params->conf.nb_queue_pairs);
+
 		ret = rte_cryptodev_scheduler_slave_attach(sched_id,
 				(uint8_t)i);
 
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 6553c94..753667a 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -50,6 +50,7 @@
 struct crypto_testsuite_params {
 	struct rte_mempool *mbuf_mp;
 	struct rte_mempool *op_mpool;
+	struct rte_mempool *sess_mp;
 
 	uint16_t nb_queue_pairs;
 
@@ -394,10 +395,23 @@ testsuite_setup(void)
 
 	ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs;
 	ts_params->conf.socket_id = SOCKET_ID_ANY;
-	ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions;
+
+	unsigned int session_size = sizeof(struct rte_cryptodev_sym_session) +
+		rte_cryptodev_get_private_session_size(ts_params->dev_id);
+
+	ts_params->sess_mp = rte_mempool_create(
+				"test_sess_mp_perf",
+				info.sym.max_nb_sessions,
+				session_size,
+				0, 0, NULL, NULL, NULL,
+				NULL, SOCKET_ID_ANY,
+				0);
+
+	TEST_ASSERT_NOT_NULL(ts_params->sess_mp,
+			"session mempool allocation failed");
 
 	TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->dev_id,
-			&ts_params->conf),
+			&ts_params->conf, ts_params->sess_mp),
 			"Failed to configure cryptodev %u",
 			ts_params->dev_id);
 
@@ -426,6 +440,12 @@ testsuite_teardown(void)
 	if (ts_params->op_mpool != NULL)
 		RTE_LOG(DEBUG, USER1, "CRYPTO_PERF_OP POOL count %u\n",
 		rte_mempool_avail_count(ts_params->op_mpool));
+	/* Free session mempool */
+	if (ts_params->sess_mp != NULL) {
+		rte_mempool_free(ts_params->sess_mp);
+		ts_params->sess_mp = NULL;
+	}
+
 }
 
 static int
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

* [dpdk-dev] [PATCH v3 1/7] service cores: header and implementation
  @ 2017-07-02 21:35  1%   ` Harry van Haaren
  0 siblings, 0 replies; 200+ results
From: Harry van Haaren @ 2017-07-02 21:35 UTC (permalink / raw)
  To: dev; +Cc: jerin.jacob, thomas, keith.wiles, bruce.richardson, Harry van Haaren

Add header files, update .map files with new service
functions, and add the service header to the doxygen
for building.

This service header API allows DPDK to use services as
a concept of something that requires CPU cycles. An example
is a PMD that runs in software to schedule events, where a
hardware version exists that does not require a CPU.

The code presented here is based on an initial RFC:
http://dpdk.org/ml/archives/dev/2017-May/065207.html
This was then reworked, and RFC v2 with the changes posted:
http://dpdk.org/ml/archives/dev/2017-June/067194.html

This is the fourth iteration of the service core concept,
with 2 RFCs and this being v2 of the implementation.

Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>

---

v2:
Thanks Jerin for review - below a list your suggested changes;
- Doxygen rename to "service cores" for consistency
- use lcore instead of core for function names
- Fix about 10 typos / seplling msitakse ;)
- Dix doxygen /** comments for functions
- Doxygen @param[out] improvements
- int8_t for socket_id to ordinary int
- Rename MACROS for readability
- Align structs to cache lines
- Allocate fastpath-used data from hugepages
- Added/fixed memory barriers for multi-core scheduling
- Add const to variables, and hoist above loop
- Optimize cmpset atomic if MT_SAFE or only one core mapped
- Statistics collection only when requested
- Add error check for array pointer
- Remove panic() calls from library
- Fix TODO notes from previous patchset

There are also some other changes;
- Checkpatch issues fixed
- .map file updates
- Add rte_service_get_by_name() function
---
 doc/api/doxy-api-index.md                          |   1 +
 lib/librte_eal/bsdapp/eal/Makefile                 |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  28 +
 lib/librte_eal/common/Makefile                     |   1 +
 lib/librte_eal/common/eal_common_lcore.c           |   1 +
 lib/librte_eal/common/include/rte_eal.h            |   4 +
 lib/librte_eal/common/include/rte_lcore.h          |   3 +-
 lib/librte_eal/common/include/rte_service.h        | 298 +++++++++
 .../common/include/rte_service_private.h           | 118 ++++
 lib/librte_eal/common/rte_service.c                | 671 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   1 +
 lib/librte_eal/linuxapp/eal/eal_thread.c           |   9 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  29 +
 13 files changed, 1163 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/common/include/rte_service.h
 create mode 100644 lib/librte_eal/common/include/rte_service_private.h
 create mode 100644 lib/librte_eal/common/rte_service.c

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index f5f1f19..1284402 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -158,6 +158,7 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
+  [service cores]      (@ref rte_service.h),
   [device metrics]     (@ref rte_metrics.h),
   [bitrate statistics] (@ref rte_bitrate.h),
   [latency statistics] (@ref rte_latencystats.h),
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a0f9950..05517a2 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -87,6 +87,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 2e48a73..5493a13 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -193,3 +193,31 @@ DPDK_17.05 {
 	vfio_get_group_no;
 
 } DPDK_17.02;
+
+DPDK_17.08 {
+	global:
+
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_stop;
+	rte_service_unregister;
+
+} DPDK_17.05;
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index a5bd108..2a93397 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -41,6 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
+INC += rte_service.h rte_service_private.h
 
 GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
 GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h
diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
index 84fa0cb..0db1555 100644
--- a/lib/librte_eal/common/eal_common_lcore.c
+++ b/lib/librte_eal/common/eal_common_lcore.c
@@ -81,6 +81,7 @@ rte_eal_cpu_init(void)
 
 		/* By default, each detected core is enabled */
 		config->lcore_role[lcore_id] = ROLE_RTE;
+		lcore_config[lcore_id].core_role = ROLE_RTE;
 		lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
 		lcore_config[lcore_id].socket_id = eal_cpu_socket_id(lcore_id);
 		if (lcore_config[lcore_id].socket_id >= RTE_MAX_NUMA_NODES) {
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
index abf020b..4dd0518 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -61,6 +61,7 @@ extern "C" {
 enum rte_lcore_role_t {
 	ROLE_RTE,
 	ROLE_OFF,
+	ROLE_SERVICE,
 };
 
 /**
@@ -80,6 +81,7 @@ enum rte_proc_type_t {
 struct rte_config {
 	uint32_t master_lcore;       /**< Id of the master lcore */
 	uint32_t lcore_count;        /**< Number of available logical cores. */
+	uint32_t service_lcore_count;/**< Number of available service cores. */
 	enum rte_lcore_role_t lcore_role[RTE_MAX_LCORE]; /**< State of cores. */
 
 	/** Primary or secondary configuration */
@@ -185,6 +187,8 @@ int rte_eal_iopl_init(void);
  *
  *     EPROTO indicates that the PCI bus is either not present, or is not
  *            readable by the eal.
+ *
+ *     ENOEXEC indicates that a service core failed to launch successfully.
  */
 int rte_eal_init(int argc, char **argv);
 
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/common/include/rte_lcore.h
index fe7b586..50e0d0f 100644
--- a/lib/librte_eal/common/include/rte_lcore.h
+++ b/lib/librte_eal/common/include/rte_lcore.h
@@ -73,6 +73,7 @@ struct lcore_config {
 	unsigned core_id;          /**< core number on socket for this lcore */
 	int core_index;            /**< relative index, starting from 0 */
 	rte_cpuset_t cpuset;       /**< cpu set which the lcore affinity to */
+	uint8_t core_role;         /**< role of core eg: OFF, RTE, SERVICE */
 };
 
 /**
@@ -175,7 +176,7 @@ rte_lcore_is_enabled(unsigned lcore_id)
 	struct rte_config *cfg = rte_eal_get_configuration();
 	if (lcore_id >= RTE_MAX_LCORE)
 		return 0;
-	return cfg->lcore_role[lcore_id] != ROLE_OFF;
+	return cfg->lcore_role[lcore_id] == ROLE_RTE;
 }
 
 /**
diff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/common/include/rte_service.h
new file mode 100644
index 0000000..3be59ea
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service.h
@@ -0,0 +1,298 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_H_
+#define _RTE_SERVICE_H_
+
+/**
+ * @file
+ *
+ * Service functions
+ *
+ * The service functionality provided by this header allows a DPDK component
+ * to indicate that it requires a function call in order for it to perform
+ * its processing.
+ *
+ * An example usage of this functionality would be a component that registers
+ * a service to perform a particular packet processing duty: for example the
+ * eventdev software PMD. At startup the application requests all services
+ * that have been registered, and the cores in the service-coremask run the
+ * required services. The EAL removes these number of cores from the available
+ * runtime cores, and dedicates them to performing service-core workloads. The
+ * application has access to the remaining lcores as normal.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include<stdio.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_lcore.h>
+
+/* forward declaration only. Definition in rte_service_private.h */
+struct rte_service_spec;
+
+#define RTE_SERVICE_NAME_MAX 32
+
+/* Capabilities of a service.
+ *
+ * Use the *rte_service_probe_capability* function to check if a service is
+ * capable of a specific capability.
+ */
+/** When set, the service is capable of having multiple threads run it at the
+ *  same time.
+ */
+#define RTE_SERVICE_CAP_MT_SAFE (1 << 0)
+
+/** Return the number of services registered.
+ *
+ * The number of services registered can be passed to *rte_service_get_by_id*,
+ * enabling the application to retrieve the specification of each service.
+ *
+ * @return The number of services registered.
+ */
+uint32_t rte_service_get_count(void);
+
+/** Return the specification of a service by integer id.
+ *
+ * This function provides the specification of a service. This can be used by
+ * the application to understand what the service represents. The service
+ * must not be modified by the application directly, only passed to the various
+ * rte_service_* functions.
+ *
+ * @param id The integer id of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *id* provided.
+ */
+struct rte_service_spec *rte_service_get_by_id(uint32_t id);
+
+/** Return the specification of a service by name.
+ *
+ * This function provides the specification of a service using the service name
+ * as lookup key. This can be used by the application to understand what the
+ * service represents. The service must not be modified by the application
+ * directly, only passed to the various rte_service_* functions.
+ *
+ * @param name The name of the service to retrieve
+ * @retval non-zero A valid pointer to the service_spec
+ * @retval NULL Invalid *name* provided.
+ */
+struct rte_service_spec *rte_service_get_by_name(const char *name);
+
+/** Return the name of the service.
+ *
+ * @return A pointer to the name of the service. The returned pointer remains
+ *         in ownership of the service, and the application must not free it.
+ */
+const char *rte_service_get_name(const struct rte_service_spec *service);
+
+/** Check if a service has a specific capability.
+ *
+ * This function returns if *service* has implements *capability*.
+ * See RTE_SERVICE_CAP_* defines for a list of valid capabilities.
+ * @retval 1 Capability supported by this service instance
+ * @retval 0 Capability not supported by this service instance
+ */
+int32_t rte_service_probe_capability(const struct rte_service_spec *service,
+				     uint32_t capability);
+
+/** Enable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions adds *lcore* to the set of cores that will run *service*.
+ *
+ * If multiple cores are enabled on a service, an atomic is used to ensure that
+ * only one cores runs the service at a time. The exception to this is when
+ * a service indicates that it is multi-thread safe by setting the capability
+ * called RTE_SERVICE_CAP_MT_SAFE. With the multi-thread safe capability set,
+ * the service function can be run on multiple threads at the same time.
+ *
+ * @retval 0 lcore added successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_enable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/** Disable a core to run a service.
+ *
+ * Each core can be added or removed from running specific services. This
+ * functions removes *lcore* to the set of cores that will run *service*.
+ *
+ * @retval 0 Lcore removed successfully
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_disable_on_lcore(struct rte_service_spec *service,
+				   uint32_t lcore);
+
+/** Return if an lcore is enabled for the service.
+ *
+ * This function allows the application to query if *lcore* is currently set to
+ * run *service*.
+ *
+ * @retval 1 Lcore enabled on this lcore
+ * @retval 0 Lcore disabled on this lcore
+ * @retval -EINVAL An invalid service or lcore was provided.
+ */
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore);
+
+
+/** Enable *service* to run.
+ *
+ * This function switches on a service during runtime.
+ * @retval 0 The service was successfully started
+ */
+int32_t rte_service_start(struct rte_service_spec *service);
+
+/** Disable *service*.
+ *
+ * Switch off a service, so it is not run until it is *rte_service_start* is
+ * called on it.
+ * @retval 0 Service successfully switched off
+ */
+int32_t rte_service_stop(struct rte_service_spec *service);
+
+/** Returns if *service* is currently running.
+ *
+ * This function retuns true if the service has been started using
+ * *rte_service_start*, AND a service core is mapped to the service. This
+ * function can be used to ensure that the service will be run.
+ *
+ * @retval 1 Service is currently running, and has a service lcore mapped
+ * @retval 0 Service is currently stopped, or no service lcore is mapped
+ * @retval -EINVAL Invalid service pointer provided
+ */
+int32_t rte_service_is_running(const struct rte_service_spec *service);
+
+/** Start a service core.
+ *
+ * Starting a core makes the core begin polling. Any services assigned to it
+ * will be run as fast as possible.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Failed to start core. The *lcore_id* passed in is not
+ *          currently assigned to be a service core.
+ */
+int32_t rte_service_lcore_start(uint32_t lcore_id);
+
+/** Stop a service core.
+ *
+ * Stopping a core makes the core become idle, but remains  assigned as a
+ * service core.
+ *
+ * @retval 0 Success
+ * @retval -EINVAL Invalid *lcore_id* provided
+ * @retval -EALREADY Already stopped core
+ * @retval -EBUSY Failed to stop core, as it would cause a service to not
+ *          be run, as this is the only core currently running the service.
+ *          The application must stop the service first, and then stop the
+ *          lcore.
+ */
+int32_t rte_service_lcore_stop(uint32_t lcore_id);
+
+/** Adds lcore to the list of service cores.
+ *
+ * This functions can be used at runtime in order to modify the service core
+ * mask.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY lcore is busy, and not available for service core duty
+ * @retval -EALREADY lcore is already added to the service core list
+ * @retval -EINVAL Invalid lcore provided
+ */
+int32_t rte_service_lcore_add(uint32_t lcore);
+
+/** Removes lcore from the list of service cores.
+ *
+ * This can fail if the core is not stopped, see *rte_service_core_stop*.
+ *
+ * @retval 0 Success
+ * @retval -EBUSY Lcore is not stopped, stop service core before removing.
+ * @retval -EINVAL failed to add lcore to service core mask.
+ */
+int32_t rte_service_lcore_del(uint32_t lcore);
+
+/** Retrieve the number of service cores currently available.
+ *
+ * This function returns the integer count of service cores available. The
+ * service core count can be used in mapping logic when creating mappings
+ * from service cores to services.
+ *
+ * See *rte_service_lcore_list* for details on retrieving the lcore_id of each
+ * service core.
+ *
+ * @return The number of service cores currently configured.
+ */
+int32_t rte_service_lcore_count(void);
+
+/** Reset all service core mappings.
+ * @retval 0 Success
+ */
+int32_t rte_service_lcore_reset_all(void);
+
+/** Enable or disable statistics collection.
+ *
+ * This function enables per core, per-service cycle count collection.
+ * @param enabled Zero to turn off statistics collection, non-zero to enable.
+ */
+void rte_service_set_stats_enable(int enabled);
+
+/** Retrieve the list of currently enabled service cores.
+ *
+ * This function fills in an application supplied array, with each element
+ * indicating the lcore_id of a service core.
+ *
+ * Adding and removing service cores can be performed using
+ * *rte_service_lcore_add* and *rte_service_lcore_del*.
+ * @param [out] array An array of at least N items.
+ * @param [out] The size of *array*.
+ * @retval >=0 Number of service cores that have been populated in the array
+ * @retval -ENOMEM The provided array is not large enough to fill in the
+ *          service core list. No items have been populated, call this function
+ *          with a size of at least *rte_service_core_count* items.
+ */
+int32_t rte_service_lcore_list(uint32_t array[], uint32_t n);
+
+/** Dumps any information available about the service. If service is NULL,
+ * dumps info for all services.
+ */
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_SERVICE_H_ */
diff --git a/lib/librte_eal/common/include/rte_service_private.h b/lib/librte_eal/common/include/rte_service_private.h
new file mode 100644
index 0000000..d518b02
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_service_private.h
@@ -0,0 +1,118 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_SERVICE_PRIVATE_H_
+#define _RTE_SERVICE_PRIVATE_H_
+
+/* This file specifies the internal service specification.
+ * Include this file if you are writing a component that requires CPU cycles to
+ * operate, and you wish to run the component using service cores
+ */
+
+#include <rte_service.h>
+
+/**
+ * Signature of callback function to run a service.
+ */
+typedef int32_t (*rte_service_func)(void *args);
+
+/**
+ * The specification of a service.
+ *
+ * This struct contains metadata about the service itself, the callback
+ * function to run one iteration of the service, a userdata pointer, flags etc.
+ */
+struct rte_service_spec {
+	/** The name of the service. This should be used by the application to
+	 * understand what purpose this service provides.
+	 */
+	char name[RTE_SERVICE_NAME_MAX];
+	/** The callback to invoke to run one iteration of the service. */
+	rte_service_func callback;
+	/** The userdata pointer provided to the service callback. */
+	void *callback_userdata;
+	/** Flags to indicate the capabilities of this service. See defines in
+	 * the public header file for values of RTE_SERVICE_CAP_*
+	 */
+	uint32_t capabilities;
+	/** NUMA socket ID that this service is affinitized to */
+	int socket_id;
+};
+
+/** Register a new service.
+ *
+ * A service represents a component that the requires CPU time periodically to
+ * achieve its purpose.
+ *
+ * For example the eventdev SW PMD requires CPU cycles to perform its
+ * scheduling. This can be achieved by registering it as a service, and the
+ * application can then assign CPU resources to it using
+ * *rte_service_set_coremask*.
+ *
+ * @param spec The specification of the service to register
+ * @retval 0 Successfully registered the service.
+ *         -EINVAL Attempted to register an invalid service (eg, no callback
+ *         set)
+ */
+int32_t rte_service_register(const struct rte_service_spec *spec);
+
+/** Unregister a service.
+ *
+ * The service being removed must be stopped before calling this function.
+ *
+ * @retval 0 The service was successfully unregistered.
+ * @retval -EBUSY The service is currently running, stop the service before
+ *          calling unregister. No action has been taken.
+ */
+int32_t rte_service_unregister(struct rte_service_spec *service);
+
+/** Private function to allow EAL to initialized default mappings.
+ *
+ * This function iterates all the services, and maps then to the available
+ * cores. Based on the capabilities of the services, they are set to run on the
+ * available cores in a round-robin manner.
+ *
+ * @retval 0 Success
+ */
+int32_t rte_service_set_default_mapping(void);
+
+/** Initialize the service library.
+ *
+ * In order to use the service library, it must be initialized. EAL initializes
+ * the library at startup.
+ *
+ * @retval 0 Success
+ * @retval -EALREADY Service library is already initialized
+ */
+int32_t rte_service_init(void);
+
+#endif /* _RTE_SERVICE_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c
new file mode 100644
index 0000000..67338db
--- /dev/null
+++ b/lib/librte_eal/common/rte_service.c
@@ -0,0 +1,671 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <rte_service.h>
+#include "include/rte_service_private.h"
+
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_atomic.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+#define RTE_SERVICE_NUM_MAX 64
+
+#define SERVICE_F_REGISTERED 0
+
+/* runstates for services and lcores, denoting if they are active or not */
+#define RUNSTATE_STOPPED 0
+#define RUNSTATE_RUNNING 1
+
+/* internal representation of a service */
+struct rte_service_spec_impl {
+	/* public part of the struct */
+	struct rte_service_spec spec;
+
+	/* atomic lock that when set indicates a service core is currently
+	 * running this service callback. When not set, a core may take the
+	 * lock and then run the service callback.
+	 */
+	rte_atomic32_t execute_lock;
+
+	/* API set/get-able variables */
+	int32_t runstate;
+	uint8_t internal_flags;
+
+	/* per service statistics */
+	uint32_t num_mapped_cores;
+	uint64_t calls;
+	uint64_t cycles_spent;
+} __rte_cache_aligned;
+
+/* the internal values of a service core */
+struct core_state {
+	/* map of services IDs are run on this core */
+	uint64_t service_mask;
+	uint8_t runstate; /* running or stopped */
+	uint8_t is_service_core; /* set if core is currently a service core */
+	uint8_t collect_statistics; /* if set, measure cycle counts */
+
+	/* extreme statistics */
+	uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
+} __rte_cache_aligned;
+
+static uint32_t rte_service_count;
+static struct rte_service_spec_impl *rte_services;
+static struct core_state *cores_state;
+static uint32_t rte_service_library_initialized;
+
+int32_t rte_service_init(void)
+{
+	if (rte_service_library_initialized) {
+		printf("service library init() called, init flag %d\n",
+			rte_service_library_initialized);
+		return -EALREADY;
+	}
+
+	rte_services = rte_calloc("rte_services", RTE_SERVICE_NUM_MAX,
+			sizeof(struct rte_service_spec_impl),
+			RTE_CACHE_LINE_SIZE);
+	if (!rte_services) {
+		printf("error allocating rte services array\n");
+		return -ENOMEM;
+	}
+
+	cores_state = rte_calloc("rte_service_core_states", RTE_MAX_LCORE,
+			sizeof(struct core_state), RTE_CACHE_LINE_SIZE);
+	if (!cores_state) {
+		printf("error allocating core states array\n");
+		return -ENOMEM;
+	}
+
+	int i;
+	int count = 0;
+	struct rte_config *cfg = rte_eal_get_configuration();
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role == ROLE_SERVICE) {
+			if ((unsigned)i == cfg->master_lcore)
+				continue;
+			rte_service_lcore_add(i);
+			count++;
+		}
+	}
+
+	rte_service_library_initialized = 1;
+	return 0;
+}
+
+void rte_service_set_stats_enable(int enabled)
+{
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		cores_state[i].collect_statistics = enabled;
+}
+
+/* returns 1 if service is registered and has not been unregistered
+ * Returns 0 if service never registered, or has been unregistered
+ */
+static inline int
+service_valid(uint32_t id) {
+	return !!(rte_services[id].internal_flags &
+		 (1 << SERVICE_F_REGISTERED));
+}
+
+uint32_t
+rte_service_get_count(void)
+{
+	return rte_service_count;
+}
+
+struct rte_service_spec *
+rte_service_get_by_id(uint32_t id)
+{
+	struct rte_service_spec *service = NULL;
+	if (id < rte_service_count)
+		service = (struct rte_service_spec *)&rte_services[id];
+
+	return service;
+}
+
+struct rte_service_spec *rte_service_get_by_name(const char *name)
+{
+	struct rte_service_spec *service = NULL;
+	int i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (service_valid(i) &&
+				strcmp(name, rte_services[i].spec.name) == 0)
+			service = (struct rte_service_spec *)&rte_services[i];
+			break;
+	}
+
+	return service;
+}
+
+const char *
+rte_service_get_name(const struct rte_service_spec *service)
+{
+	return service->name;
+}
+
+int32_t
+rte_service_probe_capability(const struct rte_service_spec *service,
+			     uint32_t capability)
+{
+	return service->capabilities & capability;
+}
+
+int32_t
+rte_service_is_running(const struct rte_service_spec *spec)
+{
+	const struct rte_service_spec_impl *impl =
+		(const struct rte_service_spec_impl *)spec;
+	if (!impl)
+		return -EINVAL;
+
+	return (impl->runstate == RUNSTATE_RUNNING) &&
+		(impl->num_mapped_cores > 0);
+}
+
+int32_t
+rte_service_register(const struct rte_service_spec *spec)
+{
+	uint32_t i;
+	int32_t free_slot = -1;
+
+	if (spec->callback == NULL || strlen(spec->name) == 0)
+		return -EINVAL;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i)) {
+			free_slot = i;
+			break;
+		}
+	}
+
+	if ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))
+		return -ENOSPC;
+
+	struct rte_service_spec_impl *s = &rte_services[free_slot];
+	s->spec = *spec;
+	s->internal_flags |= (1 << SERVICE_F_REGISTERED);
+
+	rte_smp_wmb();
+	rte_service_count++;
+
+	return 0;
+}
+
+int32_t
+rte_service_unregister(struct rte_service_spec *spec)
+{
+	struct rte_service_spec_impl *s = NULL;
+	struct rte_service_spec_impl *spec_impl =
+		(struct rte_service_spec_impl *)spec;
+
+	uint32_t i;
+	uint32_t service_id;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (&rte_services[i] == spec_impl) {
+			s = spec_impl;
+			service_id = i;
+			break;
+		}
+	}
+
+	if (!s)
+		return -EINVAL;
+
+	rte_service_count--;
+	rte_smp_wmb();
+
+	s->internal_flags &= ~(1 << SERVICE_F_REGISTERED);
+
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		cores_state[i].service_mask &= ~(1 << service_id);
+
+	memset(&rte_services[service_id], 0,
+			sizeof(struct rte_service_spec_impl));
+
+	return 0;
+}
+
+int32_t
+rte_service_start(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_RUNNING;
+	rte_smp_wmb();
+	return 0;
+}
+
+int32_t
+rte_service_stop(struct rte_service_spec *service)
+{
+	struct rte_service_spec_impl *s =
+		(struct rte_service_spec_impl *)service;
+	s->runstate = RUNSTATE_STOPPED;
+	rte_smp_wmb();
+	return 0;
+}
+
+static int32_t
+rte_service_runner_func(void *arg)
+{
+	RTE_SET_USED(arg);
+	uint32_t i;
+	const int lcore = rte_lcore_id();
+	struct core_state *cs = &cores_state[lcore];
+
+	while (cores_state[lcore].runstate == RUNSTATE_RUNNING) {
+		const uint64_t service_mask = cs->service_mask;
+		for (i = 0; i < rte_service_count; i++) {
+			struct rte_service_spec_impl *s = &rte_services[i];
+			if (s->runstate != RUNSTATE_RUNNING ||
+					!(service_mask & (1 << i)))
+				continue;
+
+			/* check if this is the only core mapped, else use
+			 * atomic to serialize cores mapped to this service
+			 */
+			uint32_t *lock = (uint32_t *)&s->execute_lock;
+			if ((s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE) ||
+					(s->num_mapped_cores == 1 ||
+					rte_atomic32_cmpset(lock, 0, 1))) {
+				void *userdata = s->spec.callback_userdata;
+
+				if (cs->collect_statistics) {
+					uint64_t start = rte_rdtsc();
+					s->spec.callback(userdata);
+					uint64_t end = rte_rdtsc();
+					s->cycles_spent += end - start;
+					cs->calls_per_service[i]++;
+					s->calls++;
+				} else {
+					cs->calls_per_service[i]++;
+					s->spec.callback(userdata);
+					s->calls++;
+				}
+
+				rte_atomic32_clear(&s->execute_lock);
+			}
+		}
+	}
+
+	lcore_config[lcore].state = WAIT;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_count(void)
+{
+	int32_t count = 0;
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		count += cores_state[i].is_service_core;
+	return count;
+}
+
+int32_t
+rte_service_lcore_list(uint32_t array[], uint32_t n)
+{
+	uint32_t count = rte_service_lcore_count();
+	if (count > n)
+		return -ENOMEM;
+
+	if (!array)
+		return -EINVAL;
+
+	uint32_t i;
+	uint32_t idx = 0;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct core_state *cs = &cores_state[i];
+		if (cs->is_service_core) {
+			array[idx] = i;
+			idx++;
+		}
+	}
+
+	return count;
+}
+
+int32_t
+rte_service_set_default_mapping(void)
+{
+	/* create a default mapping from cores to services, then start the
+	 * services to make them transparent to unaware applications.
+	 */
+	uint32_t i;
+	int ret;
+	uint32_t count = rte_service_get_count();
+
+	int32_t lcore_iter = 0;
+	uint32_t ids[RTE_MAX_LCORE];
+	int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
+
+	for (i = 0; i < count; i++) {
+		struct rte_service_spec *s = rte_service_get_by_id(i);
+		if (!s)
+			return -EINVAL;
+
+		/* if no lcores available as services cores, don't setup map.
+		 * This means app logic must add cores, and setup mappings
+		 */
+		if (lcore_count > 0) {
+			/* do 1:1 core mapping here, with each service getting
+			 * assigned a single core by default. Adding multiple
+			 * services should multiplex to a single core, or 1:1
+			 * if services == cores
+			 */
+			ret = rte_service_enable_on_lcore(s, ids[lcore_iter]);
+			if (ret)
+				return -ENODEV;
+		}
+
+		lcore_iter++;
+		if (lcore_iter >= lcore_count)
+			lcore_iter = 0;
+
+		ret = rte_service_start(s);
+		if (ret)
+			return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static int32_t
+service_update(struct rte_service_spec *service, uint32_t lcore,
+		uint32_t *set, uint32_t *enabled)
+{
+	uint32_t i;
+	int32_t sid = -1;
+
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if ((struct rte_service_spec *)&rte_services[i] == service &&
+				service_valid(i)) {
+			sid = i;
+			break;
+		}
+	}
+
+	if (sid == -1 || lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (!cores_state[lcore].is_service_core)
+		return -EINVAL;
+
+	if (set) {
+		if (*set) {
+			cores_state[lcore].service_mask |=  (1 << sid);
+			rte_services[sid].num_mapped_cores++;
+		} else {
+			cores_state[lcore].service_mask &= ~(1 << sid);
+			rte_services[sid].num_mapped_cores--;
+		}
+	}
+
+	if (enabled)
+		*enabled = (cores_state[lcore].service_mask & (1 << sid));
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,
+					uint32_t lcore)
+{
+	uint32_t enabled;
+	int ret = service_update(service, lcore, 0, &enabled);
+	if (ret == 0)
+		return enabled;
+	return -EINVAL;
+}
+
+int32_t
+rte_service_enable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t on = 1;
+	return service_update(service, lcore, &on, 0);
+}
+
+int32_t
+rte_service_disable_on_lcore(struct rte_service_spec *service, uint32_t lcore)
+{
+	uint32_t off = 0;
+	return service_update(service, lcore, &off, 0);
+}
+
+int32_t rte_service_lcore_reset_all(void)
+{
+	/* loop over cores, reset all to mask 0 */
+	uint32_t i;
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		cores_state[i].service_mask = 0;
+		cores_state[i].is_service_core = 0;
+		cores_state[i].runstate = RUNSTATE_STOPPED;
+	}
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
+		rte_services[i].num_mapped_cores = 0;
+
+	rte_smp_wmb();
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_add(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+	if (cores_state[lcore].is_service_core)
+		return -EALREADY;
+
+	lcore_config[lcore].core_role = ROLE_SERVICE;
+
+	cores_state[lcore].is_service_core = 1;
+	cores_state[lcore].service_mask = 0;
+	cores_state[lcore].runstate = RUNSTATE_STOPPED;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_del(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &cores_state[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate != RUNSTATE_STOPPED)
+		return -EBUSY;
+
+	lcore_config[lcore].core_role = ROLE_RTE;
+	cores_state[lcore].is_service_core = 0;
+
+	return 0;
+}
+
+int32_t
+rte_service_lcore_start(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	struct core_state *cs = &cores_state[lcore];
+	if (!cs->is_service_core)
+		return -EINVAL;
+
+	if (cs->runstate == RUNSTATE_RUNNING)
+		return -EALREADY;
+
+	/* set core to run state first, and then launch otherwise it will
+	 * return immediately as runstate keeps it in the service poll loop
+	 */
+	cores_state[lcore].runstate = RUNSTATE_RUNNING;
+
+	int ret = rte_eal_remote_launch(rte_service_runner_func, 0, lcore);
+	/* returns -EBUSY if the core is already launched, 0 on success */
+	return ret;
+}
+
+int32_t
+rte_service_lcore_stop(uint32_t lcore)
+{
+	if (lcore >= RTE_MAX_LCORE)
+		return -EINVAL;
+
+	if (cores_state[lcore].runstate == RUNSTATE_STOPPED)
+		return -EALREADY;
+
+	uint32_t i;
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		int32_t enabled = cores_state[i].service_mask & (1 << i);
+		int32_t service_running = rte_services[i].runstate !=
+						RUNSTATE_STOPPED;
+		int32_t only_core = rte_services[i].num_mapped_cores == 1;
+
+		/* if the core is mapped, and the service is running, and this
+		 * is the only core that is mapped, the service would cease to
+		 * run if this core stopped, so fail instead.
+		 */
+		if (enabled && service_running && only_core)
+			return -EBUSY;
+	}
+
+	cores_state[lcore].runstate = RUNSTATE_STOPPED;
+
+	return 0;
+}
+
+static void
+rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,
+		     uint64_t all_cycles, uint32_t reset)
+{
+	/* avoid divide by zero */
+	if (all_cycles == 0)
+		all_cycles = 1;
+
+	int calls = 1;
+	if (s->calls != 0)
+		calls = s->calls;
+
+	float cycles_pct = (((float)s->cycles_spent) / all_cycles) * 100.f;
+	fprintf(f,
+			"  %s : %0.1f %%\tcalls %"PRIu64"\tcycles %"
+			PRIu64"\tavg: %"PRIu64"\n",
+			s->spec.name, cycles_pct, s->calls, s->cycles_spent,
+			s->cycles_spent / calls);
+
+	if (reset) {
+		s->cycles_spent = 0;
+		s->calls = 0;
+	}
+}
+
+static void
+service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)
+{
+	uint32_t i;
+	struct core_state *cs = &cores_state[lcore];
+
+	fprintf(f, "%02d\t", lcore);
+	for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
+		if (!service_valid(i))
+			continue;
+		fprintf(f, "%"PRIu64"\t", cs->calls_per_service[i]);
+		if (reset)
+			cs->calls_per_service[i] = 0;
+	}
+	fprintf(f, "\n");
+}
+
+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service)
+{
+	uint32_t i;
+
+	uint64_t total_cycles = 0;
+	for (i = 0; i < rte_service_count; i++) {
+		if (!service_valid(i))
+			continue;
+		total_cycles += rte_services[i].cycles_spent;
+	}
+
+	int print_no_collect_warning = 0;
+	for (i = 0; i < RTE_MAX_LCORE; i++)
+		if (cores_state[i].collect_statistics == 0)
+			print_no_collect_warning = 1;
+	if (print_no_collect_warning)
+		fprintf(f, "Warning; cycle counts not collectd; refer to rte_service_set_stats_enable\n");
+
+	if (service) {
+		struct rte_service_spec_impl *s =
+			(struct rte_service_spec_impl *)service;
+		fprintf(f, "Service %s Summary\n", s->spec.name);
+		uint32_t reset = 0;
+		rte_service_dump_one(f, s, total_cycles, reset);
+		return 0;
+	}
+
+	fprintf(f, "Services Summary\n");
+	for (i = 0; i < rte_service_count; i++) {
+		uint32_t reset = 1;
+		rte_service_dump_one(f, &rte_services[i], total_cycles, reset);
+	}
+
+	fprintf(f, "Service Cores Summary\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		if (lcore_config[i].core_role != ROLE_SERVICE)
+			continue;
+
+		uint32_t reset = 0;
+		service_dump_calls_per_lcore(f, i, reset);
+	}
+
+	return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 8651e27..e6ab6c3 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -99,6 +99,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c
 
 # from arch dir
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_cpuflags.c
diff --git a/lib/librte_eal/linuxapp/eal/eal_thread.c b/lib/librte_eal/linuxapp/eal/eal_thread.c
index 9f88530..831ba07 100644
--- a/lib/librte_eal/linuxapp/eal/eal_thread.c
+++ b/lib/librte_eal/linuxapp/eal/eal_thread.c
@@ -184,7 +184,14 @@ eal_thread_loop(__attribute__((unused)) void *arg)
 		ret = lcore_config[lcore_id].f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		rte_wmb();
-		lcore_config[lcore_id].state = FINISHED;
+
+		/* when a service core returns, it should go directly to WAIT
+		 * state, because the application will not lcore_wait() for it.
+		 */
+		if (lcore_config[lcore_id].core_role == ROLE_SERVICE)
+			lcore_config[lcore_id].state = WAIT;
+		else
+			lcore_config[lcore_id].state = FINISHED;
 	}
 
 	/* never reached */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 670bab3..830d224 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -198,3 +198,32 @@ DPDK_17.05 {
 	vfio_get_group_no;
 
 } DPDK_17.02;
+
+DPDK_17.08 {
+	global:
+
+	rte_service_disable_on_lcore;
+	rte_service_dump;
+	rte_service_enable_on_lcore;
+	rte_service_get_by_id;
+	rte_service_get_by_name;
+	rte_service_get_count;
+	rte_service_get_enabled_on_lcore;
+	rte_service_is_running;
+	rte_service_lcore_add;
+	rte_service_lcore_count;
+	rte_service_lcore_del;
+	rte_service_lcore_list;
+	rte_service_lcore_reset_all;
+	rte_service_lcore_start;
+	rte_service_lcore_stop;
+	rte_service_probe_capability;
+	rte_service_register;
+	rte_service_reset;
+	rte_service_set_stats_enable;
+	rte_service_start;
+	rte_service_stop;
+	rte_service_unregister;
+
+
+} DPDK_17.05;
-- 
2.7.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v4 26/26] cryptodev: remove AAD from authentication structure
                       ` (2 preceding siblings ...)
  2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 20/26] cryptodev: add AEAD parameters in crypto operation Pablo de Lara
@ 2017-07-02  5:41  4%   ` Pablo de Lara
  3 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02  5:41 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

Now that AAD is only used in AEAD algorithms,
there is no need to keep AAD in the authentication
structure.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
---
 app/test-crypto-perf/cperf_ops.c         |  2 --
 doc/guides/prog_guide/cryptodev_lib.rst  |  6 ------
 doc/guides/rel_notes/release_17_08.rst   |  3 +++
 drivers/crypto/openssl/rte_openssl_pmd.c |  1 -
 lib/librte_cryptodev/rte_crypto_sym.h    | 26 --------------------------
 test/test/test_cryptodev.c               |  4 ----
 test/test/test_cryptodev_perf.c          |  1 -
 7 files changed, 3 insertions(+), 40 deletions(-)

diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 107abb0..d718278 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -422,7 +422,6 @@ cperf_create_session(uint8_t dev_id,
 					test_vector->auth_iv.length;
 		} else {
 			auth_xform.auth.digest_length = 0;
-			auth_xform.auth.add_auth_data_length = 0;
 			auth_xform.auth.key.length = 0;
 			auth_xform.auth.key.data = NULL;
 			auth_xform.auth.iv.length = 0;
@@ -475,7 +474,6 @@ cperf_create_session(uint8_t dev_id,
 					test_vector->auth_key.data;
 		} else {
 			auth_xform.auth.digest_length = 0;
-			auth_xform.auth.add_auth_data_length = 0;
 			auth_xform.auth.key.length = 0;
 			auth_xform.auth.key.data = NULL;
 			auth_xform.auth.iv.length = 0;
diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
index 5048839..f250c00 100644
--- a/doc/guides/prog_guide/cryptodev_lib.rst
+++ b/doc/guides/prog_guide/cryptodev_lib.rst
@@ -567,12 +567,6 @@ chain.
                         uint8_t *data;
                         phys_addr_t phys_addr;
                     } digest; /**< Digest parameters */
-
-                    struct {
-                        uint8_t *data;
-                        phys_addr_t phys_addr;
-                    } aad;
-                    /**< Additional authentication parameters */
                 } auth;
             };
         };
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index 2c6bef5..d29b203 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -176,6 +176,9 @@ API Changes
   * Changed field size of digest length in ``rte_crypto_auth_xform``,
     from uint32_t to uint16_t.
   * Added AEAD structure in ``rte_crypto_sym_op``.
+  * Removed AAD length from ``rte_crypto_auth_xform``.
+  * Removed AAD pointer and physical address from auth structure
+    in ``rte_crypto_sym_op``.
 
 
 ABI Changes
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 7f5c6aa..73e7ff1 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -413,7 +413,6 @@ openssl_set_session_auth_parameters(struct openssl_session *sess,
 		return -EINVAL;
 	}
 
-	sess->auth.aad_length = xform->auth.add_auth_data_length;
 	sess->auth.digest_length = xform->auth.digest_length;
 
 	return 0;
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index dab042b..742dc34 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -326,13 +326,6 @@ struct rte_crypto_auth_xform {
 	 * the result shall be truncated.
 	 */
 
-	uint16_t add_auth_data_length;
-	/**< The length of the additional authenticated data (AAD) in bytes.
-	 * The maximum permitted value is 65535 (2^16 - 1) bytes, unless
-	 * otherwise specified below.
-	 *
-	 */
-
 	struct {
 		uint16_t offset;
 		/**< Starting point for Initialisation Vector or Counter,
@@ -670,25 +663,6 @@ struct rte_crypto_sym_op {
 					phys_addr_t phys_addr;
 					/**< Physical address of digest */
 				} digest; /**< Digest parameters */
-
-				struct {
-					uint8_t *data;
-					/**< Pointer to Additional Authenticated
-					 * Data (AAD) needed for authenticated cipher
-					 * mechanisms (CCM and GCM).
-					 *
-					 * The length of the data pointed to by this
-					 * field is set up for the session in the @ref
-					 * rte_crypto_auth_xform structure as part of
-					 * the @ref rte_cryptodev_sym_session_create
-					 * function call.
-					 * This length must not exceed 65535 (2^16-1)
-					 * bytes.
-					 *
-					 */
-					phys_addr_t phys_addr;	/**< physical address */
-				} aad;
-				/**< Additional authentication parameters */
 			} auth;
 		};
 	};
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 21c6270..db0999e 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -5530,7 +5530,6 @@ static int MD5_HMAC_create_session(struct crypto_testsuite_params *ts_params,
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_MD5_HMAC;
 
 	ut_params->auth_xform.auth.digest_length = MD5_DIGEST_LEN;
-	ut_params->auth_xform.auth.add_auth_data_length = 0;
 	ut_params->auth_xform.auth.key.length = test_case->key.len;
 	ut_params->auth_xform.auth.key.data = key;
 
@@ -6303,7 +6302,6 @@ static int create_gmac_session(uint8_t dev_id,
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_AES_GMAC;
 	ut_params->auth_xform.auth.op = auth_op;
 	ut_params->auth_xform.auth.digest_length = tdata->gmac_tag.len;
-	ut_params->auth_xform.auth.add_auth_data_length = 0;
 	ut_params->auth_xform.auth.key.length = tdata->key.len;
 	ut_params->auth_xform.auth.key.data = auth_key;
 	ut_params->auth_xform.auth.iv.offset = IV_OFFSET;
@@ -6683,7 +6681,6 @@ create_auth_session(struct crypto_unittest_params *ut_params,
 	ut_params->auth_xform.auth.key.length = reference->auth_key.len;
 	ut_params->auth_xform.auth.key.data = auth_key;
 	ut_params->auth_xform.auth.digest_length = reference->digest.len;
-	ut_params->auth_xform.auth.add_auth_data_length = reference->aad.len;
 
 	/* Create Crypto session*/
 	ut_params->sess = rte_cryptodev_sym_session_create(dev_id,
@@ -6721,7 +6718,6 @@ create_auth_cipher_session(struct crypto_unittest_params *ut_params,
 		ut_params->auth_xform.auth.iv.length = reference->iv.len;
 	} else {
 		ut_params->auth_xform.next = &ut_params->cipher_xform;
-		ut_params->auth_xform.auth.add_auth_data_length = reference->aad.len;
 
 		/* Setup Cipher Parameters */
 		ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 557aba9..d4ab1a4 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -2936,7 +2936,6 @@ test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 	if (chain == CIPHER_ONLY) {
 		op->sym->auth.digest.data = NULL;
 		op->sym->auth.digest.phys_addr = 0;
-		op->sym->auth.aad.data = NULL;
 		op->sym->auth.data.offset = 0;
 		op->sym->auth.data.length = 0;
 	} else {
-- 
2.9.4

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v4 20/26] cryptodev: add AEAD parameters in crypto operation
    2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 16/26] cryptodev: remove AAD length from crypto op Pablo de Lara
  2017-07-02  5:41  1%   ` [dpdk-dev] [PATCH v4 17/26] cryptodev: remove digest " Pablo de Lara
@ 2017-07-02  5:41  2%   ` Pablo de Lara
  2017-07-02  5:41  4%   ` [dpdk-dev] [PATCH v4 26/26] cryptodev: remove AAD from authentication structure Pablo de Lara
  3 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02  5:41 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

AEAD operation parameters can be set in the new
aead structure, in the crypto operation.
This structure is within a union with the cipher
and authentication parameters, since operations can be:
- AEAD: using the aead structure

- Cipher only: using only the cipher structure

- Auth only: using only the authentication structure

- Cipher-then-auth/Auth-then-cipher: using both cipher
  and authentication structures

Therefore, all three cannot be used at the same time.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
---
 doc/guides/prog_guide/cryptodev_lib.rst |  70 +++---
 doc/guides/rel_notes/release_17_08.rst  |   1 +
 lib/librte_cryptodev/rte_crypto_sym.h   | 375 ++++++++++++++++++++------------
 3 files changed, 279 insertions(+), 167 deletions(-)

diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
index b888554..5048839 100644
--- a/doc/guides/prog_guide/cryptodev_lib.rst
+++ b/doc/guides/prog_guide/cryptodev_lib.rst
@@ -431,7 +431,6 @@ operations, as well as also supporting AEAD operations.
 
 
 Session and Session Management
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Session are used in symmetric cryptographic processing to store the immutable
 data defined in a cryptographic transform which is used in the operation
@@ -465,9 +464,6 @@ operation and its parameters. See the section below for details on transforms.
    struct rte_cryptodev_sym_session * rte_cryptodev_sym_session_create(
           uint8_t dev_id, struct rte_crypto_sym_xform *xform);
 
-**Note**: For AEAD operations the algorithm selected for authentication and
-ciphering must aligned, eg AES_GCM.
-
 
 Transforms and Transform Chaining
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -533,30 +529,54 @@ chain.
             /**< Session-less API Crypto operation parameters */
         };
 
-        struct {
-            struct {
-                uint32_t offset;
-                uint32_t length;
-            } data;   /**< Data offsets and length for ciphering */
-        } cipher;
-
-        struct {
-            struct {
-                uint32_t offset;
-                uint32_t length;
-            } data;   /**< Data offsets and length for authentication */
-
+        union {
             struct {
-                uint8_t *data;
-                phys_addr_t phys_addr;
-            } digest; /**< Digest parameters */
+                struct {
+                    uint32_t offset;
+                    uint32_t length;
+                } data; /**< Data offsets and length for AEAD */
+
+                struct {
+                    uint8_t *data;
+                    phys_addr_t phys_addr;
+                } digest; /**< Digest parameters */
+
+                struct {
+                    uint8_t *data;
+                    phys_addr_t phys_addr;
+                } aad;
+                /**< Additional authentication parameters */
+            } aead;
 
             struct {
-                uint8_t *data;
-                phys_addr_t phys_addr;
-            } aad;    /**< Additional authentication parameters */
-        } auth;
-    }
+                struct {
+                    struct {
+                        uint32_t offset;
+                        uint32_t length;
+                    } data; /**< Data offsets and length for ciphering */
+                } cipher;
+
+                struct {
+                    struct {
+                        uint32_t offset;
+                        uint32_t length;
+                    } data;
+                    /**< Data offsets and length for authentication */
+
+                    struct {
+                        uint8_t *data;
+                        phys_addr_t phys_addr;
+                    } digest; /**< Digest parameters */
+
+                    struct {
+                        uint8_t *data;
+                        phys_addr_t phys_addr;
+                    } aad;
+                    /**< Additional authentication parameters */
+                } auth;
+            };
+        };
+    };
 
 
 Asymmetric Cryptography
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index b920142..2c6bef5 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -175,6 +175,7 @@ API Changes
   * Removed digest length from ``rte_crypto_sym_op``.
   * Changed field size of digest length in ``rte_crypto_auth_xform``,
     from uint32_t to uint16_t.
+  * Added AEAD structure in ``rte_crypto_sym_op``.
 
 
 ABI Changes
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index db3957e..f03d2fd 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -556,151 +556,242 @@ struct rte_crypto_sym_op {
 		/**< Session-less API crypto operation parameters */
 	};
 
-	struct {
-		struct {
-			uint32_t offset;
-			 /**< Starting point for cipher processing, specified
-			  * as number of bytes from start of data in the source
-			  * buffer. The result of the cipher operation will be
-			  * written back into the output buffer starting at
-			  * this location.
-			  *
-			  * @note
-			  * For SNOW 3G @ RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
-			  * KASUMI @ RTE_CRYPTO_CIPHER_KASUMI_F8
-			  * and ZUC @ RTE_CRYPTO_CIPHER_ZUC_EEA3,
-			  * this field should be in bits.
-			  */
-
-			uint32_t length;
-			 /**< The message length, in bytes, of the source buffer
-			  * on which the cryptographic operation will be
-			  * computed. This must be a multiple of the block size
-			  * if a block cipher is being used. This is also the
-			  * same as the result length.
-			  *
-			  * @note
-			  * In the case of CCM @ref RTE_CRYPTO_AUTH_AES_CCM,
-			  * this value should not include the length of the
-			  * padding or the length of the MAC; the driver will
-			  * compute the actual number of bytes over which the
-			  * encryption will occur, which will include these
-			  * values.
-			  *
-			  * @note
-			  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UEA2,
-			  * KASUMI @ RTE_CRYPTO_CIPHER_KASUMI_F8
-			  * and ZUC @ RTE_CRYPTO_CIPHER_ZUC_EEA3,
-			  * this field should be in bits.
-			  */
-		} data; /**< Data offsets and length for ciphering */
-
-	} cipher;
-
-	struct {
-		struct {
-			uint32_t offset;
-			 /**< Starting point for hash processing, specified as
-			  * number of bytes from start of packet in source
-			  * buffer.
-			  *
-			  * @note
-			  * For CCM and GCM modes of operation, this field is
-			  * ignored. The field @ref aad field
-			  * should be set instead.
-			  *
-			  * @note
-			  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UIA2,
-			  * KASUMI @ RTE_CRYPTO_AUTH_KASUMI_F9
-			  * and ZUC @ RTE_CRYPTO_AUTH_ZUC_EIA3,
-			  * this field should be in bits.
-			  */
-
-			uint32_t length;
-			 /**< The message length, in bytes, of the source
-			  * buffer that the hash will be computed on.
-			  *
-			  * @note
-			  * For CCM and GCM modes of operation, this field is
-			  * ignored. The field @ref aad field should be set
-			  * instead.
-			  *
-			  * @note
-			  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UIA2,
-			  * KASUMI @ RTE_CRYPTO_AUTH_KASUMI_F9
-			  * and ZUC @ RTE_CRYPTO_AUTH_ZUC_EIA3,
-			  * this field should be in bits.
-			  */
-		} data; /**< Data offsets and length for authentication */
-
+	union {
 		struct {
-			uint8_t *data;
-			/**< This points to the location where the digest result
-			 * should be inserted (in the case of digest generation)
-			 * or where the purported digest exists (in the case of
-			 * digest verification).
-			 *
-			 * At session creation time, the client specified the
-			 * digest result length with the digest_length member
-			 * of the @ref rte_crypto_auth_xform structure. For
-			 * physical crypto devices the caller must allocate at
-			 * least digest_length of physically contiguous memory
-			 * at this location.
-			 *
-			 * For digest generation, the digest result will
-			 * overwrite any data at this location.
-			 *
-			 * @note
-			 * For GCM (@ref RTE_CRYPTO_AUTH_AES_GCM), for
-			 * "digest result" read "authentication tag T".
-			 */
-			phys_addr_t phys_addr;
-			/**< Physical address of digest */
-		} digest; /**< Digest parameters */
+			struct {
+				uint32_t offset;
+				 /**< Starting point for AEAD processing, specified as
+				  * number of bytes from start of packet in source
+				  * buffer.
+				  */
+				uint32_t length;
+				 /**< The message length, in bytes, of the source buffer
+				  * on which the cryptographic operation will be
+				  * computed. This must be a multiple of the block size
+				  */
+			} data; /**< Data offsets and length for AEAD */
+			struct {
+				uint8_t *data;
+				/**< This points to the location where the digest result
+				 * should be inserted (in the case of digest generation)
+				 * or where the purported digest exists (in the case of
+				 * digest verification).
+				 *
+				 * At session creation time, the client specified the
+				 * digest result length with the digest_length member
+				 * of the @ref rte_crypto_auth_xform structure. For
+				 * physical crypto devices the caller must allocate at
+				 * least digest_length of physically contiguous memory
+				 * at this location.
+				 *
+				 * For digest generation, the digest result will
+				 * overwrite any data at this location.
+				 *
+				 * @note
+				 * For GCM (@ref RTE_CRYPTO_AEAD_AES_GCM), for
+				 * "digest result" read "authentication tag T".
+				 */
+				phys_addr_t phys_addr;
+				/**< Physical address of digest */
+			} digest; /**< Digest parameters */
+			struct {
+				uint8_t *data;
+				/**< Pointer to Additional Authenticated Data (AAD)
+				 * needed for authenticated cipher mechanisms (CCM and
+				 * GCM)
+				 *
+				 * Specifically for CCM (@ref RTE_CRYPTO_AEAD_AES_CCM),
+				 * the caller should setup this field as follows:
+				 *
+				 * - the nonce should be written starting at an offset
+				 * of one byte into the array, leaving room for the
+				 * implementation to write in the flags to the first
+				 * byte.
+				 *
+				 * - the additional  authentication data itself should
+				 * be written starting at an offset of 18 bytes into
+				 * the array, leaving room for the length encoding in
+				 * the first two bytes of the second block.
+				 *
+				 * - the array should be big enough to hold the above
+				 *  fields, plus any padding to round this up to the
+				 *  nearest multiple of the block size (16 bytes).
+				 *  Padding will be added by the implementation.
+				 *
+				 * Finally, for GCM (@ref RTE_CRYPTO_AEAD_AES_GCM), the
+				 * caller should setup this field as follows:
+				 *
+				 * - the AAD is written in starting at byte 0
+				 * - the array must be big enough to hold the AAD, plus
+				 * any space to round this up to the nearest multiple
+				 * of the block size (16 bytes).
+				 *
+				 */
+				phys_addr_t phys_addr;	/**< physical address */
+			} aad;
+			/**< Additional authentication parameters */
+		} aead;
 
 		struct {
-			uint8_t *data;
-			/**< Pointer to Additional Authenticated Data (AAD)
-			 * needed for authenticated cipher mechanisms (CCM and
-			 * GCM).
-			 *
-			 * The length of the data pointed to by this field is
-			 * set up for the session in the @ref
-			 * rte_crypto_auth_xform structure as part of the @ref
-			 * rte_cryptodev_sym_session_create function call.
-			 * This length must not exceed 65535 (2^16-1) bytes.
-			 *
-			 * Specifically for CCM (@ref RTE_CRYPTO_AUTH_AES_CCM),
-			 * the caller should setup this field as follows:
-			 *
-			 * - the nonce should be written starting at an offset
-			 * of one byte into the array, leaving room for the
-			 * implementation to write in the flags to the first
-			 *  byte.
-			 *
-			 * - the additional  authentication data itself should
-			 * be written starting at an offset of 18 bytes into
-			 * the array, leaving room for the length encoding in
-			 * the first two bytes of the second block.
-			 *
-			 * - the array should be big enough to hold the above
-			 *  fields, plus any padding to round this up to the
-			 *  nearest multiple of the block size (16 bytes).
-			 *  Padding will be added by the implementation.
-			 *
-			 * Finally, for GCM (@ref RTE_CRYPTO_AUTH_AES_GCM), the
-			 * caller should setup this field as follows:
-			 *
-			 * - the AAD is written in starting at byte 0
-			 * - the array must be big enough to hold the AAD, plus
-			 * any space to round this up to the nearest multiple
-			 * of the block size (16 bytes).
-			 *
-			 */
-			phys_addr_t phys_addr;	/**< physical address */
-		} aad;
-		/**< Additional authentication parameters */
-	} auth;
+			struct {
+				struct {
+					uint32_t offset;
+					 /**< Starting point for cipher processing,
+					  * specified as number of bytes from start
+					  * of data in the source buffer.
+					  * The result of the cipher operation will be
+					  * written back into the output buffer
+					  * starting at this location.
+					  *
+					  * @note
+					  * For SNOW 3G @ RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+					  * KASUMI @ RTE_CRYPTO_CIPHER_KASUMI_F8
+					  * and ZUC @ RTE_CRYPTO_CIPHER_ZUC_EEA3,
+					  * this field should be in bits.
+					  */
+					uint32_t length;
+					 /**< The message length, in bytes, of the
+					  * source buffer on which the cryptographic
+					  * operation will be computed.
+					  * This must be a multiple of the block size
+					  * if a block cipher is being used. This is
+					  * also the same as the result length.
+					  *
+					  * @note
+					  * In the case of CCM
+					  * @ref RTE_CRYPTO_AUTH_AES_CCM, this value
+					  * should not include the length of the padding
+					  * or the length of the MAC; the driver will
+					  * compute the actual number of bytes over
+					  * which the encryption will occur, which will
+					  * include these values.
+					  *
+					  * @note
+					  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UEA2,
+					  * KASUMI @ RTE_CRYPTO_CIPHER_KASUMI_F8
+					  * and ZUC @ RTE_CRYPTO_CIPHER_ZUC_EEA3,
+					  * this field should be in bits.
+					  */
+				} data; /**< Data offsets and length for ciphering */
+			} cipher;
+
+			struct {
+				struct {
+					uint32_t offset;
+					 /**< Starting point for hash processing,
+					  * specified as number of bytes from start of
+					  * packet in source buffer.
+					  *
+					  * @note
+					  * For CCM and GCM modes of operation,
+					  * this field is ignored.
+					  * The field @ref aad field should be set
+					  * instead.
+					  *
+					  * @note
+					  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+					  * KASUMI @ RTE_CRYPTO_AUTH_KASUMI_F9
+					  * and ZUC @ RTE_CRYPTO_AUTH_ZUC_EIA3,
+					  * this field should be in bits.
+					  */
+					uint32_t length;
+					 /**< The message length, in bytes, of the source
+					  * buffer that the hash will be computed on.
+					  *
+					  * @note
+					  * For CCM and GCM modes of operation,
+					  * this field is ignored. The field @ref aad
+					  * field should be set instead.
+					  *
+					  * @note
+					  * For SNOW 3G @ RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+					  * KASUMI @ RTE_CRYPTO_AUTH_KASUMI_F9
+					  * and ZUC @ RTE_CRYPTO_AUTH_ZUC_EIA3,
+					  * this field should be in bits.
+					  */
+				} data;
+				/**< Data offsets and length for authentication */
+
+				struct {
+					uint8_t *data;
+					/**< This points to the location where
+					 * the digest result should be inserted
+					 * (in the case of digest generation)
+					 * or where the purported digest exists
+					 * (in the case of digest verification).
+					 *
+					 * At session creation time, the client
+					 * specified the digest result length with
+					 * the digest_length member of the
+					 * @ref rte_crypto_auth_xform structure.
+					 * For physical crypto devices the caller
+					 * must allocate at least digest_length of
+					 * physically contiguous memory at this
+					 * location.
+					 *
+					 * For digest generation, the digest result
+					 * will overwrite any data at this location.
+					 *
+					 * @note
+					 * For GCM (@ref RTE_CRYPTO_AUTH_AES_GCM), for
+					 * "digest result" read "authentication tag T".
+					 */
+					phys_addr_t phys_addr;
+					/**< Physical address of digest */
+				} digest; /**< Digest parameters */
+
+				struct {
+					uint8_t *data;
+					/**< Pointer to Additional Authenticated
+					 * Data (AAD) needed for authenticated cipher
+					 * mechanisms (CCM and GCM).
+					 *
+					 * The length of the data pointed to by this
+					 * field is set up for the session in the @ref
+					 * rte_crypto_auth_xform structure as part of
+					 * the @ref rte_cryptodev_sym_session_create
+					 * function call.
+					 * This length must not exceed 65535 (2^16-1)
+					 * bytes.
+					 *
+					 * Specifically for CCM
+					 * (@ref RTE_CRYPTO_AUTH_AES_CCM),
+					 * the caller should setup this field as follows:
+					 *
+					 * - the nonce should be written starting at
+					 * an offset of one byte into the array,
+					 * leaving room for the implementation to
+					 * write in the flags to the first byte.
+					 *
+					 * - the additional authentication data
+					 * itself should be written starting at
+					 * an offset of 18 bytes into the array,
+					 * leaving room for the length encoding in
+					 * the first two bytes of the second block.
+					 *
+					 * - the array should be big enough to hold
+					 * the above fields, plus any padding to
+					 * round this up to the nearest multiple of
+					 * the block size (16 bytes).
+					 * Padding will be added by the implementation.
+					 *
+					 * Finally, for GCM
+					 * (@ref RTE_CRYPTO_AUTH_AES_GCM), the
+					 * caller should setup this field as follows:
+					 *
+					 * - the AAD is written in starting at byte 0
+					 * - the array must be big enough to hold
+					 * the AAD, plus any space to round this up to
+					 * the nearest multiple of the block size
+					 * (16 bytes).
+					 *
+					 */
+					phys_addr_t phys_addr;	/**< physical address */
+				} aad;
+				/**< Additional authentication parameters */
+			} auth;
+		};
+	};
 };
 
 
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

* [dpdk-dev] [PATCH v4 17/26] cryptodev: remove digest length from crypto op
    2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 16/26] cryptodev: remove AAD length from crypto op Pablo de Lara
@ 2017-07-02  5:41  1%   ` Pablo de Lara
  2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 20/26] cryptodev: add AEAD parameters in crypto operation Pablo de Lara
  2017-07-02  5:41  4%   ` [dpdk-dev] [PATCH v4 26/26] cryptodev: remove AAD from authentication structure Pablo de Lara
  3 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02  5:41 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

Digest length was duplicated in the authentication transform
and the crypto operation structures.

Since digest length is not expected to change in a same
session, it is removed from the crypto operation.

Also, the length has been shrunk to 16 bits,
which should be sufficient for any digest.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
---
 app/test-crypto-perf/cperf_ops.c                 |  7 ---
 doc/guides/prog_guide/cryptodev_lib.rst          |  1 -
 doc/guides/rel_notes/release_17_08.rst           |  3 ++
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c         | 34 +++++++-------
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h |  2 +
 drivers/crypto/armv8/rte_armv8_pmd.c             |  9 ++--
 drivers/crypto/armv8/rte_armv8_pmd_private.h     |  2 +
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c      | 34 +++++++-------
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h        |  1 +
 drivers/crypto/kasumi/rte_kasumi_pmd.c           | 18 ++++----
 drivers/crypto/openssl/rte_openssl_pmd.c         |  7 +--
 drivers/crypto/openssl/rte_openssl_pmd_private.h |  2 +
 drivers/crypto/qat/qat_adf/qat_algs.h            |  1 +
 drivers/crypto/qat/qat_crypto.c                  |  3 +-
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 18 ++++----
 drivers/crypto/zuc/rte_zuc_pmd.c                 | 18 ++++----
 examples/ipsec-secgw/esp.c                       |  2 -
 examples/l2fwd-crypto/main.c                     |  1 -
 lib/librte_cryptodev/rte_crypto_sym.h            |  6 +--
 test/test/test_cryptodev.c                       | 34 +++++---------
 test/test/test_cryptodev_blockcipher.c           |  5 +--
 test/test/test_cryptodev_perf.c                  | 56 ++++++++----------------
 22 files changed, 119 insertions(+), 145 deletions(-)

diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 9405cef..401f85e 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -161,7 +161,6 @@ cperf_set_ops_auth(struct rte_crypto_op **ops,
 			sym_op->auth.digest.data = test_vector->digest.data;
 			sym_op->auth.digest.phys_addr =
 					test_vector->digest.phys_addr;
-			sym_op->auth.digest.length = options->auth_digest_sz;
 		} else {
 
 			uint32_t offset = options->test_buffer_size;
@@ -183,7 +182,6 @@ cperf_set_ops_auth(struct rte_crypto_op **ops,
 					uint8_t *, offset);
 			sym_op->auth.digest.phys_addr =
 					rte_pktmbuf_mtophys_offset(buf,	offset);
-			sym_op->auth.digest.length = options->auth_digest_sz;
 			sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
 			sym_op->auth.aad.data = test_vector->aad.data;
 
@@ -246,7 +244,6 @@ cperf_set_ops_cipher_auth(struct rte_crypto_op **ops,
 			sym_op->auth.digest.data = test_vector->digest.data;
 			sym_op->auth.digest.phys_addr =
 					test_vector->digest.phys_addr;
-			sym_op->auth.digest.length = options->auth_digest_sz;
 		} else {
 
 			uint32_t offset = options->test_buffer_size;
@@ -268,7 +265,6 @@ cperf_set_ops_cipher_auth(struct rte_crypto_op **ops,
 					uint8_t *, offset);
 			sym_op->auth.digest.phys_addr =
 					rte_pktmbuf_mtophys_offset(buf,	offset);
-			sym_op->auth.digest.length = options->auth_digest_sz;
 			sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
 			sym_op->auth.aad.data = test_vector->aad.data;
 		}
@@ -337,7 +333,6 @@ cperf_set_ops_aead(struct rte_crypto_op **ops,
 			sym_op->auth.digest.data = test_vector->digest.data;
 			sym_op->auth.digest.phys_addr =
 					test_vector->digest.phys_addr;
-			sym_op->auth.digest.length = options->auth_digest_sz;
 		} else {
 
 			uint32_t offset = sym_op->cipher.data.length +
@@ -360,8 +355,6 @@ cperf_set_ops_aead(struct rte_crypto_op **ops,
 					uint8_t *, offset);
 			sym_op->auth.digest.phys_addr =
 					rte_pktmbuf_mtophys_offset(buf,	offset);
-
-			sym_op->auth.digest.length = options->auth_digest_sz;
 		}
 
 		sym_op->auth.data.length = options->test_buffer_size;
diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
index ea8fc00..e036611 100644
--- a/doc/guides/prog_guide/cryptodev_lib.rst
+++ b/doc/guides/prog_guide/cryptodev_lib.rst
@@ -547,7 +547,6 @@ chain.
             struct {
                 uint8_t *data;
                 phys_addr_t phys_addr;
-                uint16_t length;
             } digest; /**< Digest parameters */
 
             struct {
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index e633d73..a544639 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -166,6 +166,9 @@ API Changes
   * Removed Additional Authentication Data (AAD) length from ``rte_crypto_sym_op``.
   * Changed field size of AAD length in ``rte_crypto_auth_xform``,
     from uint32_t to uint16_t.
+  * Removed digest length from ``rte_crypto_sym_op``.
+  * Changed field size of digest length in ``rte_crypto_auth_xform``,
+    from uint32_t to uint16_t.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index f6136ba..fcf0f8b 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -78,6 +78,7 @@ aesni_gcm_set_session_parameters(struct aesni_gcm_session *sess,
 {
 	const struct rte_crypto_sym_xform *auth_xform;
 	const struct rte_crypto_sym_xform *cipher_xform;
+	uint16_t digest_length;
 
 	if (xform->next == NULL || xform->next->next != NULL) {
 		GCM_LOG_ERR("Two and only two chained xform required");
@@ -128,6 +129,8 @@ aesni_gcm_set_session_parameters(struct aesni_gcm_session *sess,
 		return -EINVAL;
 	}
 
+	digest_length = auth_xform->auth.digest_length;
+
 	/* Check key length and calculate GCM pre-compute. */
 	switch (cipher_xform->cipher.key.length) {
 	case 16:
@@ -146,6 +149,14 @@ aesni_gcm_set_session_parameters(struct aesni_gcm_session *sess,
 	}
 
 	sess->aad_length = auth_xform->auth.add_auth_data_length;
+	/* Digest check */
+	if (digest_length != 16 &&
+			digest_length != 12 &&
+			digest_length != 8) {
+		GCM_LOG_ERR("digest");
+		return -EINVAL;
+	}
+	sess->digest_length = digest_length;
 
 	return 0;
 }
@@ -245,13 +256,6 @@ process_gcm_crypto_op(struct rte_crypto_op *op,
 		*iv_padd = rte_bswap32(1);
 	}
 
-	if (sym_op->auth.digest.length != 16 &&
-			sym_op->auth.digest.length != 12 &&
-			sym_op->auth.digest.length != 8) {
-		GCM_LOG_ERR("digest");
-		return -1;
-	}
-
 	if (session->op == AESNI_GCM_OP_AUTHENTICATED_ENCRYPTION) {
 
 		aesni_gcm_enc[session->key].init(&session->gdata,
@@ -281,11 +285,11 @@ process_gcm_crypto_op(struct rte_crypto_op *op,
 
 		aesni_gcm_enc[session->key].finalize(&session->gdata,
 				sym_op->auth.digest.data,
-				(uint64_t)sym_op->auth.digest.length);
+				(uint64_t)session->digest_length);
 	} else { /* session->op == AESNI_GCM_OP_AUTHENTICATED_DECRYPTION */
 		uint8_t *auth_tag = (uint8_t *)rte_pktmbuf_append(sym_op->m_dst ?
 				sym_op->m_dst : sym_op->m_src,
-				sym_op->auth.digest.length);
+				session->digest_length);
 
 		if (!auth_tag) {
 			GCM_LOG_ERR("auth_tag");
@@ -319,7 +323,7 @@ process_gcm_crypto_op(struct rte_crypto_op *op,
 
 		aesni_gcm_dec[session->key].finalize(&session->gdata,
 				auth_tag,
-				(uint64_t)sym_op->auth.digest.length);
+				(uint64_t)session->digest_length);
 	}
 
 	return 0;
@@ -349,21 +353,21 @@ post_process_gcm_crypto_op(struct rte_crypto_op *op)
 	if (session->op == AESNI_GCM_OP_AUTHENTICATED_DECRYPTION) {
 
 		uint8_t *tag = rte_pktmbuf_mtod_offset(m, uint8_t *,
-				m->data_len - op->sym->auth.digest.length);
+				m->data_len - session->digest_length);
 
 #ifdef RTE_LIBRTE_PMD_AESNI_GCM_DEBUG
 		rte_hexdump(stdout, "auth tag (orig):",
-				op->sym->auth.digest.data, op->sym->auth.digest.length);
+				op->sym->auth.digest.data, session->digest_length);
 		rte_hexdump(stdout, "auth tag (calc):",
-				tag, op->sym->auth.digest.length);
+				tag, session->digest_length);
 #endif
 
 		if (memcmp(tag, op->sym->auth.digest.data,
-				op->sym->auth.digest.length) != 0)
+				session->digest_length) != 0)
 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 
 		/* trim area used for digest from mbuf */
-		rte_pktmbuf_trim(m, op->sym->auth.digest.length);
+		rte_pktmbuf_trim(m, session->digest_length);
 	}
 }
 
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
index bfd4d1c..05fabe6 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
@@ -95,6 +95,8 @@ struct aesni_gcm_session {
 		uint16_t offset;
 	} iv;
 	/**< IV parameters */
+	uint16_t digest_length;
+	/**< Digest length */
 	enum aesni_gcm_operation op;
 	/**< GCM operation type */
 	enum aesni_gcm_key key;
diff --git a/drivers/crypto/armv8/rte_armv8_pmd.c b/drivers/crypto/armv8/rte_armv8_pmd.c
index dac4fc3..4a23ff1 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd.c
+++ b/drivers/crypto/armv8/rte_armv8_pmd.c
@@ -452,6 +452,9 @@ armv8_crypto_set_session_chained_parameters(struct armv8_crypto_session *sess,
 		return -EINVAL;
 	}
 
+	/* Set the digest length */
+	sess->auth.digest_length = auth_xform->auth.digest_length;
+
 	/* Verify supported key lengths and extract proper algorithm */
 	switch (cipher_xform->cipher.key.length << 3) {
 	case 128:
@@ -649,7 +652,7 @@ process_armv8_chained_op
 		}
 	} else {
 		adst = (uint8_t *)rte_pktmbuf_append(m_asrc,
-				op->sym->auth.digest.length);
+				sess->auth.digest_length);
 	}
 
 	arg.cipher.iv = rte_crypto_op_ctod_offset(op, uint8_t *,
@@ -667,12 +670,12 @@ process_armv8_chained_op
 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 	if (sess->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY) {
 		if (memcmp(adst, op->sym->auth.digest.data,
-				op->sym->auth.digest.length) != 0) {
+				sess->auth.digest_length) != 0) {
 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 		}
 		/* Trim area used for digest from mbuf. */
 		rte_pktmbuf_trim(m_asrc,
-				op->sym->auth.digest.length);
+				sess->auth.digest_length);
 	}
 }
 
diff --git a/drivers/crypto/armv8/rte_armv8_pmd_private.h b/drivers/crypto/armv8/rte_armv8_pmd_private.h
index 75bde9f..09d32f2 100644
--- a/drivers/crypto/armv8/rte_armv8_pmd_private.h
+++ b/drivers/crypto/armv8/rte_armv8_pmd_private.h
@@ -199,6 +199,8 @@ struct armv8_crypto_session {
 				/**< HMAC key (max supported length)*/
 			} hmac;
 		};
+		uint16_t digest_length;
+		/* Digest length */
 	} auth;
 
 } __rte_cache_aligned;
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 3930794..8ee6ece 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -84,7 +84,7 @@ build_authenc_fd(dpaa2_sec_session *sess,
 	struct sec_flow_context *flc;
 	uint32_t auth_only_len = sym_op->auth.data.length -
 				sym_op->cipher.data.length;
-	int icv_len = sym_op->auth.digest.length;
+	int icv_len = sess->digest_length;
 	uint8_t *old_icv;
 	uint32_t mem_len = (7 * sizeof(struct qbman_fle)) + icv_len;
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
@@ -135,7 +135,7 @@ build_authenc_fd(dpaa2_sec_session *sess,
 		   "cipher_off: 0x%x/length %d, iv-len=%d data_off: 0x%x\n",
 		   sym_op->auth.data.offset,
 		   sym_op->auth.data.length,
-		   sym_op->auth.digest.length,
+		   sess->digest_length,
 		   sym_op->cipher.data.offset,
 		   sym_op->cipher.data.length,
 		   sess->iv.length,
@@ -161,7 +161,7 @@ build_authenc_fd(dpaa2_sec_session *sess,
 		sge++;
 		DPAA2_SET_FLE_ADDR(sge,
 				DPAA2_VADDR_TO_IOVA(sym_op->auth.digest.data));
-		sge->length = sym_op->auth.digest.length;
+		sge->length = sess->digest_length;
 		DPAA2_SET_FD_LEN(fd, (sym_op->auth.data.length +
 					sess->iv.length));
 	}
@@ -177,7 +177,7 @@ build_authenc_fd(dpaa2_sec_session *sess,
 	fle->length = (sess->dir == DIR_ENC) ?
 			(sym_op->auth.data.length + sess->iv.length) :
 			(sym_op->auth.data.length + sess->iv.length +
-			 sym_op->auth.digest.length);
+			 sess->digest_length);
 
 	/* Configure Input SGE for Encap/Decap */
 	DPAA2_SET_FLE_ADDR(sge, DPAA2_VADDR_TO_IOVA(iv_ptr));
@@ -192,12 +192,12 @@ build_authenc_fd(dpaa2_sec_session *sess,
 		sge++;
 		old_icv = (uint8_t *)(sge + 1);
 		memcpy(old_icv,	sym_op->auth.digest.data,
-		       sym_op->auth.digest.length);
-		memset(sym_op->auth.digest.data, 0, sym_op->auth.digest.length);
+		       sess->digest_length);
+		memset(sym_op->auth.digest.data, 0, sess->digest_length);
 		DPAA2_SET_FLE_ADDR(sge, DPAA2_VADDR_TO_IOVA(old_icv));
-		sge->length = sym_op->auth.digest.length;
+		sge->length = sess->digest_length;
 		DPAA2_SET_FD_LEN(fd, (sym_op->auth.data.length +
-				 sym_op->auth.digest.length +
+				 sess->digest_length +
 				 sess->iv.length));
 	}
 	DPAA2_SET_FLE_FIN(sge);
@@ -217,7 +217,7 @@ build_auth_fd(dpaa2_sec_session *sess, struct rte_crypto_op *op,
 	uint32_t mem_len = (sess->dir == DIR_ENC) ?
 			   (3 * sizeof(struct qbman_fle)) :
 			   (5 * sizeof(struct qbman_fle) +
-			    sym_op->auth.digest.length);
+			    sess->digest_length);
 	struct sec_flow_context *flc;
 	struct ctxt_priv *priv = sess->ctxt;
 	uint8_t *old_digest;
@@ -251,7 +251,7 @@ build_auth_fd(dpaa2_sec_session *sess, struct rte_crypto_op *op,
 	DPAA2_SET_FD_FLC(fd, DPAA2_VADDR_TO_IOVA(flc));
 
 	DPAA2_SET_FLE_ADDR(fle, DPAA2_VADDR_TO_IOVA(sym_op->auth.digest.data));
-	fle->length = sym_op->auth.digest.length;
+	fle->length = sess->digest_length;
 
 	DPAA2_SET_FD_ADDR(fd, DPAA2_VADDR_TO_IOVA(fle));
 	DPAA2_SET_FD_COMPOUND_FMT(fd);
@@ -282,17 +282,17 @@ build_auth_fd(dpaa2_sec_session *sess, struct rte_crypto_op *op,
 				     sym_op->m_src->data_off);
 
 		DPAA2_SET_FD_LEN(fd, sym_op->auth.data.length +
-				 sym_op->auth.digest.length);
+				 sess->digest_length);
 		sge->length = sym_op->auth.data.length;
 		sge++;
 		old_digest = (uint8_t *)(sge + 1);
 		rte_memcpy(old_digest, sym_op->auth.digest.data,
-			   sym_op->auth.digest.length);
-		memset(sym_op->auth.digest.data, 0, sym_op->auth.digest.length);
+			   sess->digest_length);
+		memset(sym_op->auth.digest.data, 0, sess->digest_length);
 		DPAA2_SET_FLE_ADDR(sge, DPAA2_VADDR_TO_IOVA(old_digest));
-		sge->length = sym_op->auth.digest.length;
+		sge->length = sess->digest_length;
 		fle->length = sym_op->auth.data.length +
-				sym_op->auth.digest.length;
+				sess->digest_length;
 		DPAA2_SET_FLE_FIN(sge);
 	}
 	DPAA2_SET_FLE_FIN(fle);
@@ -912,6 +912,8 @@ dpaa2_sec_auth_init(struct rte_cryptodev *dev,
 	authdata.key_enc_flags = 0;
 	authdata.key_type = RTA_DATA_IMM;
 
+	session->digest_length = xform->auth.digest_length;
+
 	switch (xform->auth.algo) {
 	case RTE_CRYPTO_AUTH_SHA1_HMAC:
 		authdata.algtype = OP_ALG_ALGSEL_SHA1;
@@ -1064,6 +1066,8 @@ dpaa2_sec_aead_init(struct rte_cryptodev *dev,
 	authdata.key_enc_flags = 0;
 	authdata.key_type = RTA_DATA_IMM;
 
+	session->digest_length = auth_xform->digest_length;
+
 	switch (auth_xform->algo) {
 	case RTE_CRYPTO_AUTH_SHA1_HMAC:
 		authdata.algtype = OP_ALG_ALGSEL_SHA1;
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index ff3be70..eda2eec 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -191,6 +191,7 @@ typedef struct dpaa2_sec_session_entry {
 		uint16_t length; /**< IV length in bytes */
 		uint16_t offset; /**< IV offset in bytes */
 	} iv;
+	uint16_t digest_length;
 	uint8_t status;
 	union {
 		struct dpaa2_sec_cipher_ctxt cipher_ctxt;
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index 3a3ffa4..6ece58c 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -132,6 +132,12 @@ kasumi_set_session_parameters(struct kasumi_session *sess,
 		/* Only KASUMI F9 supported */
 		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_KASUMI_F9)
 			return -EINVAL;
+
+		if (auth_xform->auth.digest_length != KASUMI_DIGEST_LENGTH) {
+			KASUMI_LOG_ERR("Wrong digest length");
+			return -EINVAL;
+		}
+
 		sess->auth_op = auth_xform->auth.op;
 
 		sess->auth_iv_offset = auth_xform->auth.iv.offset;
@@ -261,12 +267,6 @@ process_kasumi_hash_op(struct rte_crypto_op **ops,
 	uint8_t direction;
 
 	for (i = 0; i < num_ops; i++) {
-		if (unlikely(ops[i]->sym->auth.digest.length != KASUMI_DIGEST_LENGTH)) {
-			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
-			KASUMI_LOG_ERR("digest");
-			break;
-		}
-
 		/* Data must be byte aligned */
 		if ((ops[i]->sym->auth.data.offset % BYTE_LEN) != 0) {
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
@@ -288,19 +288,19 @@ process_kasumi_hash_op(struct rte_crypto_op **ops,
 
 		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
 			dst = (uint8_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					KASUMI_DIGEST_LENGTH);
 
 			sso_kasumi_f9_1_buffer_user(&session->pKeySched_hash,
 					iv, src,
 					length_in_bits,	dst, direction);
 			/* Verify digest. */
 			if (memcmp(dst, ops[i]->sym->auth.digest.data,
-					ops[i]->sym->auth.digest.length) != 0)
+					KASUMI_DIGEST_LENGTH) != 0)
 				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					KASUMI_DIGEST_LENGTH);
 		} else  {
 			dst = ops[i]->sym->auth.digest.data;
 
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 9de4c68..46b1dd8 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -371,6 +371,7 @@ openssl_set_session_auth_parameters(struct openssl_session *sess,
 	}
 
 	sess->auth.aad_length = xform->auth.add_auth_data_length;
+	sess->auth.digest_length = xform->auth.digest_length;
 
 	return 0;
 }
@@ -1130,7 +1131,7 @@ process_openssl_auth_op
 
 	if (sess->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY)
 		dst = (uint8_t *)rte_pktmbuf_append(mbuf_src,
-				op->sym->auth.digest.length);
+				sess->auth.digest_length);
 	else {
 		dst = op->sym->auth.digest.data;
 		if (dst == NULL)
@@ -1158,11 +1159,11 @@ process_openssl_auth_op
 
 	if (sess->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY) {
 		if (memcmp(dst, op->sym->auth.digest.data,
-				op->sym->auth.digest.length) != 0) {
+				sess->auth.digest_length) != 0) {
 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 		}
 		/* Trim area used for digest from mbuf. */
-		rte_pktmbuf_trim(mbuf_src, op->sym->auth.digest.length);
+		rte_pktmbuf_trim(mbuf_src, sess->auth.digest_length);
 	}
 
 	if (status != 0)
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_private.h b/drivers/crypto/openssl/rte_openssl_pmd_private.h
index 045e532..4c9be05 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_private.h
+++ b/drivers/crypto/openssl/rte_openssl_pmd_private.h
@@ -165,6 +165,8 @@ struct openssl_session {
 
 		uint16_t aad_length;
 		/**< AAD length */
+		uint16_t digest_length;
+		/**< digest length */
 	} auth;
 
 } __rte_cache_aligned;
diff --git a/drivers/crypto/qat/qat_adf/qat_algs.h b/drivers/crypto/qat/qat_adf/qat_algs.h
index f70c6cb..b13d90b 100644
--- a/drivers/crypto/qat/qat_adf/qat_algs.h
+++ b/drivers/crypto/qat/qat_adf/qat_algs.h
@@ -135,6 +135,7 @@ struct qat_session {
 		uint16_t offset;
 		uint16_t length;
 	} auth_iv;
+	uint16_t digest_length;
 	rte_spinlock_t lock;	/* protects this struct */
 };
 
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index 5969688..3a43faa 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -606,6 +606,7 @@ qat_crypto_sym_configure_session_auth(struct rte_cryptodev *dev,
 				auth_xform->op))
 			goto error_out;
 	}
+	session->digest_length = auth_xform->digest_length;
 	return session;
 
 error_out:
@@ -1200,7 +1201,7 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 						ctx->auth_iv.length);
 		}
 		rte_hexdump(stdout, "digest:", op->sym->auth.digest.data,
-				op->sym->auth.digest.length);
+				ctx->digest_length);
 		rte_hexdump(stdout, "aad:", op->sym->auth.aad.data,
 				ctx->aad_len);
 	}
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index afb5e92..fbdccd1 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -132,6 +132,12 @@ snow3g_set_session_parameters(struct snow3g_session *sess,
 		/* Only SNOW 3G UIA2 supported */
 		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2)
 			return -EINVAL;
+
+		if (auth_xform->auth.digest_length != SNOW3G_DIGEST_LENGTH) {
+			SNOW3G_LOG_ERR("Wrong digest length");
+			return -EINVAL;
+		}
+
 		sess->auth_op = auth_xform->auth.op;
 
 		if (auth_xform->auth.iv.length != SNOW3G_IV_LENGTH) {
@@ -252,12 +258,6 @@ process_snow3g_hash_op(struct rte_crypto_op **ops,
 	uint8_t *iv;
 
 	for (i = 0; i < num_ops; i++) {
-		if (unlikely(ops[i]->sym->auth.digest.length != SNOW3G_DIGEST_LENGTH)) {
-			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
-			SNOW3G_LOG_ERR("digest");
-			break;
-		}
-
 		/* Data must be byte aligned */
 		if ((ops[i]->sym->auth.data.offset % BYTE_LEN) != 0) {
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
@@ -274,19 +274,19 @@ process_snow3g_hash_op(struct rte_crypto_op **ops,
 
 		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
 			dst = (uint8_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					SNOW3G_DIGEST_LENGTH);
 
 			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
 					iv, src,
 					length_in_bits,	dst);
 			/* Verify digest. */
 			if (memcmp(dst, ops[i]->sym->auth.digest.data,
-					ops[i]->sym->auth.digest.length) != 0)
+					SNOW3G_DIGEST_LENGTH) != 0)
 				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					SNOW3G_DIGEST_LENGTH);
 		} else  {
 			dst = ops[i]->sym->auth.digest.data;
 
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index c79ea6e..80ddd5a 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -131,6 +131,12 @@ zuc_set_session_parameters(struct zuc_session *sess,
 		/* Only ZUC EIA3 supported */
 		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_ZUC_EIA3)
 			return -EINVAL;
+
+		if (auth_xform->auth.digest_length != ZUC_DIGEST_LENGTH) {
+			ZUC_LOG_ERR("Wrong digest length");
+			return -EINVAL;
+		}
+
 		sess->auth_op = auth_xform->auth.op;
 
 		if (auth_xform->auth.iv.length != ZUC_IV_KEY_LENGTH) {
@@ -249,12 +255,6 @@ process_zuc_hash_op(struct rte_crypto_op **ops,
 	uint8_t *iv;
 
 	for (i = 0; i < num_ops; i++) {
-		if (unlikely(ops[i]->sym->auth.digest.length != ZUC_DIGEST_LENGTH)) {
-			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
-			ZUC_LOG_ERR("digest");
-			break;
-		}
-
 		/* Data must be byte aligned */
 		if ((ops[i]->sym->auth.data.offset % BYTE_LEN) != 0) {
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
@@ -271,19 +271,19 @@ process_zuc_hash_op(struct rte_crypto_op **ops,
 
 		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
 			dst = (uint32_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					ZUC_DIGEST_LENGTH);
 
 			sso_zuc_eia3_1_buffer(session->pKey_hash,
 					iv, src,
 					length_in_bits,	dst);
 			/* Verify digest. */
 			if (memcmp(dst, ops[i]->sym->auth.digest.data,
-					ops[i]->sym->auth.digest.length) != 0)
+					ZUC_DIGEST_LENGTH) != 0)
 				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 
 			/* Trim area used for digest from mbuf. */
 			rte_pktmbuf_trim(ops[i]->sym->m_src,
-					ops[i]->sym->auth.digest.length);
+					ZUC_DIGEST_LENGTH);
 		} else  {
 			dst = (uint32_t *)ops[i]->sym->auth.digest.data;
 
diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 571c2c6..d544a3c 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -140,7 +140,6 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
-	sym_cop->auth.digest.length = sa->digest_len;
 
 	return 0;
 }
@@ -368,7 +367,6 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
-	sym_cop->auth.digest.length = sa->digest_len;
 
 	return 0;
 }
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index 6fe829e..6d88937 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -481,7 +481,6 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
 
 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
 				rte_pktmbuf_pkt_len(m) - cparams->digest_length);
-		op->sym->auth.digest.length = cparams->digest_length;
 
 		/* For wireless algorithms, offset/length must be in bits */
 		if (cparams->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2 ||
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index b964a56..de4031a 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -354,7 +354,7 @@ struct rte_crypto_auth_xform {
 	 * (for example RFC 2104, FIPS 198a).
 	 */
 
-	uint32_t digest_length;
+	uint16_t digest_length;
 	/**< Length of the digest to be returned. If the verify option is set,
 	 * this specifies the length of the digest to be compared for the
 	 * session.
@@ -604,10 +604,6 @@ struct rte_crypto_sym_op {
 			 */
 			phys_addr_t phys_addr;
 			/**< Physical address of digest */
-			uint16_t length;
-			/**< Length of digest. This must be the same value as
-			 * @ref rte_crypto_auth_xform.digest_length.
-			 */
 		} digest; /**< Digest parameters */
 
 		struct {
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 7acfa24..4698f26 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -1307,7 +1307,6 @@ test_AES_CBC_HMAC_SHA1_encrypt_digest(void)
 	sym_op->auth.digest.data = ut_params->digest;
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, QUOTE_512_BYTES);
-	sym_op->auth.digest.length = DIGEST_BYTE_LENGTH_SHA1;
 
 	sym_op->auth.data.offset = 0;
 	sym_op->auth.data.length = QUOTE_512_BYTES;
@@ -1459,7 +1458,6 @@ test_AES_CBC_HMAC_SHA512_decrypt_perform(struct rte_cryptodev_sym_session *sess,
 	sym_op->auth.digest.data = ut_params->digest;
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, QUOTE_512_BYTES);
-	sym_op->auth.digest.length = DIGEST_BYTE_LENGTH_SHA512;
 
 	sym_op->auth.data.offset = 0;
 	sym_op->auth.data.length = QUOTE_512_BYTES;
@@ -2102,7 +2100,6 @@ create_wireless_algo_hash_operation(const uint8_t *auth_tag,
 	ut_params->digest = sym_op->auth.digest.data;
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, data_pad_len);
-	sym_op->auth.digest.length = auth_tag_len;
 	if (op == RTE_CRYPTO_AUTH_OP_GENERATE)
 		memset(sym_op->auth.digest.data, 0, auth_tag_len);
 	else
@@ -2110,7 +2107,7 @@ create_wireless_algo_hash_operation(const uint8_t *auth_tag,
 
 	TEST_HEXDUMP(stdout, "digest:",
 		sym_op->auth.digest.data,
-		sym_op->auth.digest.length);
+		auth_tag_len);
 
 	sym_op->auth.data.length = auth_len;
 	sym_op->auth.data.offset = auth_offset;
@@ -2159,7 +2156,6 @@ create_wireless_cipher_hash_operation(const struct wireless_test_data *tdata,
 	ut_params->digest = sym_op->auth.digest.data;
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, data_pad_len);
-	sym_op->auth.digest.length = auth_tag_len;
 	if (op == RTE_CRYPTO_AUTH_OP_GENERATE)
 		memset(sym_op->auth.digest.data, 0, auth_tag_len);
 	else
@@ -2167,7 +2163,7 @@ create_wireless_cipher_hash_operation(const struct wireless_test_data *tdata,
 
 	TEST_HEXDUMP(stdout, "digest:",
 		sym_op->auth.digest.data,
-		sym_op->auth.digest.length);
+		auth_tag_len);
 
 	/* Copy cipher and auth IVs at the end of the crypto operation */
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op, uint8_t *,
@@ -2227,7 +2223,6 @@ create_wireless_algo_cipher_hash_operation(const uint8_t *auth_tag,
 	ut_params->digest = sym_op->auth.digest.data;
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, data_pad_len);
-	sym_op->auth.digest.length = auth_tag_len;
 	if (op == RTE_CRYPTO_AUTH_OP_GENERATE)
 		memset(sym_op->auth.digest.data, 0, auth_tag_len);
 	else
@@ -2235,7 +2230,7 @@ create_wireless_algo_cipher_hash_operation(const uint8_t *auth_tag,
 
 	TEST_HEXDUMP(stdout, "digest:",
 		sym_op->auth.digest.data,
-		sym_op->auth.digest.length);
+		auth_tag_len);
 
 	/* Copy cipher and auth IVs at the end of the crypto operation */
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op, uint8_t *,
@@ -2286,13 +2281,12 @@ create_wireless_algo_auth_cipher_operation(unsigned int auth_tag_len,
 
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, data_pad_len);
-	sym_op->auth.digest.length = auth_tag_len;
 
 	memset(sym_op->auth.digest.data, 0, auth_tag_len);
 
 	TEST_HEXDUMP(stdout, "digest:",
 			sym_op->auth.digest.data,
-			sym_op->auth.digest.length);
+			auth_tag_len);
 
 	/* Copy cipher and auth IVs at the end of the crypto operation */
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op, uint8_t *,
@@ -4824,7 +4818,6 @@ create_gcm_operation(enum rte_crypto_cipher_operation op,
 						ut_params->ibuf,
 						plaintext_pad_len +
 						aad_pad_len);
-		sym_op->auth.digest.length = tdata->auth_tag.len;
 	} else {
 		sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append(
 				ut_params->ibuf, tdata->auth_tag.len);
@@ -4833,13 +4826,12 @@ create_gcm_operation(enum rte_crypto_cipher_operation op,
 		sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 				ut_params->ibuf,
 				plaintext_pad_len + aad_pad_len);
-		sym_op->auth.digest.length = tdata->auth_tag.len;
 
 		rte_memcpy(sym_op->auth.digest.data, tdata->auth_tag.data,
 			tdata->auth_tag.len);
 		TEST_HEXDUMP(stdout, "digest:",
 			sym_op->auth.digest.data,
-			sym_op->auth.digest.length);
+			tdata->auth_tag.len);
 	}
 
 	sym_op->cipher.data.length = tdata->plaintext.len;
@@ -5614,7 +5606,6 @@ static int MD5_HMAC_create_op(struct crypto_unittest_params *ut_params,
 			"no room to append digest");
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, plaintext_pad_len);
-	sym_op->auth.digest.length = MD5_DIGEST_LEN;
 
 	if (ut_params->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_VERIFY) {
 		rte_memcpy(sym_op->auth.digest.data, test_case->auth_tag.data,
@@ -6325,14 +6316,13 @@ create_gmac_operation(enum rte_crypto_auth_operation op,
 
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, aad_pad_len);
-	sym_op->auth.digest.length = tdata->gmac_tag.len;
 
 	if (op == RTE_CRYPTO_AUTH_OP_VERIFY) {
 		rte_memcpy(sym_op->auth.digest.data, tdata->gmac_tag.data,
 				tdata->gmac_tag.len);
 		TEST_HEXDUMP(stdout, "digest:",
 				sym_op->auth.digest.data,
-				sym_op->auth.digest.length);
+				tdata->gmac_tag.len);
 	}
 
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op,
@@ -6810,7 +6800,6 @@ create_auth_operation(struct crypto_testsuite_params *ts_params,
 
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, reference->plaintext.len);
-	sym_op->auth.digest.length = reference->digest.len;
 
 	if (auth_generate)
 		memset(sym_op->auth.digest.data, 0, reference->digest.len);
@@ -6821,7 +6810,7 @@ create_auth_operation(struct crypto_testsuite_params *ts_params,
 
 	TEST_HEXDUMP(stdout, "digest:",
 			sym_op->auth.digest.data,
-			sym_op->auth.digest.length);
+			reference->digest.len);
 
 	sym_op->auth.data.length = reference->plaintext.len;
 	sym_op->auth.data.offset = 0;
@@ -6868,7 +6857,6 @@ create_auth_GMAC_operation(struct crypto_testsuite_params *ts_params,
 
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, reference->ciphertext.len);
-	sym_op->auth.digest.length = reference->digest.len;
 
 	if (auth_generate)
 		memset(sym_op->auth.digest.data, 0, reference->digest.len);
@@ -6879,7 +6867,7 @@ create_auth_GMAC_operation(struct crypto_testsuite_params *ts_params,
 
 	TEST_HEXDUMP(stdout, "digest:",
 			sym_op->auth.digest.data,
-			sym_op->auth.digest.length);
+			reference->digest.len);
 
 	rte_memcpy(rte_crypto_op_ctod_offset(ut_params->op, uint8_t *, IV_OFFSET),
 			reference->iv.data, reference->iv.len);
@@ -6922,7 +6910,6 @@ create_cipher_auth_operation(struct crypto_testsuite_params *ts_params,
 
 	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 			ut_params->ibuf, reference->ciphertext.len);
-	sym_op->auth.digest.length = reference->digest.len;
 
 	if (auth_generate)
 		memset(sym_op->auth.digest.data, 0, reference->digest.len);
@@ -6933,7 +6920,7 @@ create_cipher_auth_operation(struct crypto_testsuite_params *ts_params,
 
 	TEST_HEXDUMP(stdout, "digest:",
 			sym_op->auth.digest.data,
-			sym_op->auth.digest.length);
+			reference->digest.len);
 
 	rte_memcpy(rte_crypto_op_ctod_offset(ut_params->op, uint8_t *, IV_OFFSET),
 			reference->iv.data, reference->iv.len);
@@ -7170,14 +7157,13 @@ create_gcm_operation_SGL(enum rte_crypto_cipher_operation op,
 			"no room to append digest");
 
 	sym_op->auth.digest.phys_addr = digest_phys;
-	sym_op->auth.digest.length = auth_tag_len;
 
 	if (op == RTE_CRYPTO_CIPHER_OP_DECRYPT) {
 		rte_memcpy(sym_op->auth.digest.data, tdata->auth_tag.data,
 				auth_tag_len);
 		TEST_HEXDUMP(stdout, "digest:",
 				sym_op->auth.digest.data,
-				sym_op->auth.digest.length);
+				auth_tag_len);
 	}
 
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op,
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 9faf088..446ab4f 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -324,7 +324,6 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 
 		sym_op->auth.data.offset = 0;
 		sym_op->auth.data.length = tdata->ciphertext.len;
-		sym_op->auth.digest.length = digest_len;
 	}
 
 	/* create session for sessioned op */
@@ -474,7 +473,7 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 						sym_op->auth.data.offset;
 			changed_len = sym_op->auth.data.length;
 			if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN)
-				changed_len += sym_op->auth.digest.length;
+				changed_len += digest_len;
 		} else {
 			/* cipher-only */
 			head_unchanged_len = rte_pktmbuf_headroom(mbuf) +
@@ -516,7 +515,7 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 		}
 
 		if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN)
-			changed_len += sym_op->auth.digest.length;
+			changed_len += digest_len;
 
 		if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) {
 			/* white-box test: PMDs use some of the
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 7239976..3bd9351 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -168,20 +168,19 @@ static struct rte_mbuf *
 test_perf_create_pktmbuf(struct rte_mempool *mpool, unsigned buf_sz);
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_snow3g(struct rte_crypto_op *op, struct rte_mbuf *m,
-		struct rte_cryptodev_sym_session *sess, unsigned data_len,
-		unsigned digest_len);
+		struct rte_cryptodev_sym_session *sess, unsigned int data_len);
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain);
+		enum chain_mode chain);
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain __rte_unused);
+		enum chain_mode chain __rte_unused);
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_3des(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain __rte_unused);
+		enum chain_mode chain __rte_unused);
 static uint32_t get_auth_digest_length(enum rte_crypto_auth_algorithm algo);
 
 
@@ -1979,7 +1978,6 @@ test_perf_crypto_qp_vary_burst_size(uint16_t dev_num)
 		op->sym->auth.digest.data = ut_params->digest;
 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
 				data_params[0].length);
-		op->sym->auth.digest.length = DIGEST_BYTE_LENGTH_SHA256;
 
 		op->sym->auth.data.offset = 0;
 		op->sym->auth.data.length = data_params[0].length;
@@ -2102,8 +2100,7 @@ test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams)
 						RTE_CRYPTO_OP_TYPE_SYMMETRIC);
 		TEST_ASSERT_NOT_NULL(op, "Failed to allocate op");
 
-		op = test_perf_set_crypto_op_snow3g(op, m, sess, pparams->buf_size,
-					get_auth_digest_length(pparams->auth_algo));
+		op = test_perf_set_crypto_op_snow3g(op, m, sess, pparams->buf_size);
 		TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session");
 
 		c_ops[i] = op;
@@ -2252,11 +2249,9 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 	static struct rte_crypto_op *(*test_perf_set_crypto_op)
 			(struct rte_crypto_op *, struct rte_mbuf *,
 					struct rte_cryptodev_sym_session *,
-					unsigned int, unsigned int,
+					unsigned int,
 					enum chain_mode);
 
-	unsigned int digest_length = get_auth_digest_length(pparams->auth_algo);
-
 	if (rte_cryptodev_count() == 0) {
 		printf("\nNo crypto devices found. Is PMD build configured?\n");
 		return TEST_FAILED;
@@ -2298,7 +2293,7 @@ test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams)
 		}
 
 		op = test_perf_set_crypto_op(op, m, sess, pparams->buf_size,
-				digest_length, pparams->chain);
+				pparams->chain);
 		TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session");
 
 		c_ops[i] = op;
@@ -2407,8 +2402,6 @@ test_perf_armv8_optimise_cyclecount(struct perf_test_params *pparams)
 
 	static struct rte_cryptodev_sym_session *sess;
 
-	unsigned int digest_length = get_auth_digest_length(pparams->auth_algo);
-
 	if (rte_cryptodev_count() == 0) {
 		printf("\nNo crypto devices found. Is PMD build configured?\n");
 		return TEST_FAILED;
@@ -2433,7 +2426,7 @@ test_perf_armv8_optimise_cyclecount(struct perf_test_params *pparams)
 		TEST_ASSERT_NOT_NULL(op, "Failed to allocate op");
 
 		op = test_perf_set_crypto_op_aes(op, m, sess, pparams->buf_size,
-				digest_length, pparams->chain);
+				pparams->chain);
 		TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session");
 
 		c_ops[i] = op;
@@ -2875,7 +2868,7 @@ test_perf_create_pktmbuf(struct rte_mempool *mpool, unsigned buf_sz)
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain)
+		enum chain_mode chain)
 {
 	if (rte_crypto_op_attach_sym_session(op, sess) != 0) {
 		rte_crypto_op_free(op);
@@ -2886,7 +2879,6 @@ test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 	if (chain == CIPHER_ONLY) {
 		op->sym->auth.digest.data = NULL;
 		op->sym->auth.digest.phys_addr = 0;
-		op->sym->auth.digest.length = 0;
 		op->sym->auth.aad.data = NULL;
 		op->sym->auth.data.offset = 0;
 		op->sym->auth.data.length = 0;
@@ -2895,7 +2887,6 @@ test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 				 uint8_t *, data_len);
 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
 				data_len);
-		op->sym->auth.digest.length = digest_len;
 		op->sym->auth.data.offset = 0;
 		op->sym->auth.data.length = data_len;
 	}
@@ -2917,7 +2908,7 @@ test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain __rte_unused)
+		enum chain_mode chain __rte_unused)
 {
 	if (rte_crypto_op_attach_sym_session(op, sess) != 0) {
 		rte_crypto_op_free(op);
@@ -2929,7 +2920,6 @@ test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m,
 					(m->data_off + data_len);
 	op->sym->auth.digest.phys_addr =
 				rte_pktmbuf_mtophys_offset(m, data_len);
-	op->sym->auth.digest.length = digest_len;
 	op->sym->auth.aad.data = aes_gcm_aad;
 
 	/* Copy IV at the end of the crypto operation */
@@ -2950,8 +2940,7 @@ test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m,
 
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_snow3g(struct rte_crypto_op *op, struct rte_mbuf *m,
-		struct rte_cryptodev_sym_session *sess, unsigned data_len,
-		unsigned digest_len)
+		struct rte_cryptodev_sym_session *sess, unsigned int data_len)
 {
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op,
 			uint8_t *, IV_OFFSET);
@@ -2968,7 +2957,6 @@ test_perf_set_crypto_op_snow3g(struct rte_crypto_op *op, struct rte_mbuf *m,
 						(m->data_off + data_len);
 	op->sym->auth.digest.phys_addr =
 				rte_pktmbuf_mtophys_offset(m, data_len);
-	op->sym->auth.digest.length = digest_len;
 
 	/* Data lengths/offsets Parameters */
 	op->sym->auth.data.offset = 0;
@@ -3015,8 +3003,7 @@ static inline struct rte_crypto_op *
 test_perf_set_crypto_op_snow3g_hash(struct rte_crypto_op *op,
 		struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess,
-		unsigned data_len,
-		unsigned digest_len)
+		unsigned int data_len)
 {
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op,
 			uint8_t *, IV_OFFSET);
@@ -3036,7 +3023,6 @@ test_perf_set_crypto_op_snow3g_hash(struct rte_crypto_op *op,
 	op->sym->auth.digest.phys_addr =
 				rte_pktmbuf_mtophys_offset(m, data_len +
 					SNOW3G_CIPHER_IV_LENGTH);
-	op->sym->auth.digest.length = digest_len;
 
 	/* Data lengths/offsets Parameters */
 	op->sym->auth.data.offset = 0;
@@ -3051,7 +3037,7 @@ test_perf_set_crypto_op_snow3g_hash(struct rte_crypto_op *op,
 static inline struct rte_crypto_op *
 test_perf_set_crypto_op_3des(struct rte_crypto_op *op, struct rte_mbuf *m,
 		struct rte_cryptodev_sym_session *sess, unsigned int data_len,
-		unsigned int digest_len, enum chain_mode chain __rte_unused)
+		enum chain_mode chain __rte_unused)
 {
 	if (rte_crypto_op_attach_sym_session(op, sess) != 0) {
 		rte_crypto_op_free(op);
@@ -3063,7 +3049,6 @@ test_perf_set_crypto_op_3des(struct rte_crypto_op *op, struct rte_mbuf *m,
 					(m->data_off + data_len);
 	op->sym->auth.digest.phys_addr =
 				rte_pktmbuf_mtophys_offset(m, data_len);
-	op->sym->auth.digest.length = digest_len;
 
 	/* Copy IV at the end of the crypto operation */
 	rte_memcpy(rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET),
@@ -3156,7 +3141,7 @@ test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id,
 				ops[i] = test_perf_set_crypto_op_aes(ops[i],
 					mbufs[i + (pparams->burst_size *
 						(j % NUM_MBUF_SETS))],
-					sess, pparams->buf_size, digest_length,
+					sess, pparams->buf_size,
 					pparams->chain);
 
 			/* enqueue burst */
@@ -3298,7 +3283,7 @@ test_perf_snow3g(uint8_t dev_id, uint16_t queue_id,
 					mbufs[i +
 					  (pparams->burst_size * (j % NUM_MBUF_SETS))],
 					sess,
-					pparams->buf_size, digest_length);
+					pparams->buf_size);
 				else if (pparams->chain == CIPHER_ONLY)
 					ops[i+op_offset] =
 					test_perf_set_crypto_op_snow3g_cipher(ops[i+op_offset],
@@ -3394,8 +3379,6 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 	uint64_t processed = 0, failed_polls = 0, retries = 0;
 	uint64_t tsc_start = 0, tsc_end = 0;
 
-	unsigned int digest_length = get_auth_digest_length(pparams->auth_algo);
-
 	struct rte_crypto_op *ops[pparams->burst_size];
 	struct rte_crypto_op *proc_ops[pparams->burst_size];
 
@@ -3408,7 +3391,7 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 	static struct rte_crypto_op *(*test_perf_set_crypto_op)
 			(struct rte_crypto_op *, struct rte_mbuf *,
 					struct rte_cryptodev_sym_session *,
-					unsigned int, unsigned int,
+					unsigned int,
 					enum chain_mode);
 
 	switch (pparams->cipher_algo) {
@@ -3470,7 +3453,7 @@ test_perf_openssl(uint8_t dev_id, uint16_t queue_id,
 				ops[i] = test_perf_set_crypto_op(ops[i],
 					mbufs[i + (pparams->burst_size *
 						(j % NUM_MBUF_SETS))],
-					sess, pparams->buf_size, digest_length,
+					sess, pparams->buf_size,
 					pparams->chain);
 
 			/* enqueue burst */
@@ -3548,8 +3531,6 @@ test_perf_armv8(uint8_t dev_id, uint16_t queue_id,
 	uint64_t processed = 0, failed_polls = 0, retries = 0;
 	uint64_t tsc_start = 0, tsc_end = 0;
 
-	unsigned int digest_length = get_auth_digest_length(pparams->auth_algo);
-
 	struct rte_crypto_op *ops[pparams->burst_size];
 	struct rte_crypto_op *proc_ops[pparams->burst_size];
 
@@ -3604,7 +3585,7 @@ test_perf_armv8(uint8_t dev_id, uint16_t queue_id,
 				ops[i] = test_perf_set_crypto_op_aes(ops[i],
 					mbufs[i + (pparams->burst_size *
 						(j % NUM_MBUF_SETS))], sess,
-					pparams->buf_size, digest_length,
+					pparams->buf_size,
 					pparams->chain);
 
 			/* enqueue burst */
@@ -4179,7 +4160,6 @@ perf_gcm_set_crypto_op(struct rte_crypto_op *op, struct rte_mbuf *m,
 					  params->session_attrs->aad_len +
 					  params->symmetric_op->p_len);
 
-	op->sym->auth.digest.length = params->symmetric_op->t_len;
 
 	op->sym->auth.aad.data = m_hlp->aad;
 	op->sym->auth.aad.phys_addr = rte_pktmbuf_mtophys(m);
-- 
2.9.4

^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v4 16/26] cryptodev: remove AAD length from crypto op
  @ 2017-07-02  5:41  2%   ` Pablo de Lara
  2017-07-02  5:41  1%   ` [dpdk-dev] [PATCH v4 17/26] cryptodev: remove digest " Pablo de Lara
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 200+ results
From: Pablo de Lara @ 2017-07-02  5:41 UTC (permalink / raw)
  To: declan.doherty, zbigniew.bodek, jerin.jacob, akhil.goyal,
	hemant.agrawal, fiona.trahe, john.griffin, deepak.k.jain
  Cc: dev, Pablo de Lara

Additional authenticated data (AAD) information was duplicated
in the authentication transform and in the crypto
operation structures.

Since AAD length is not meant to be changed in a same session,
it is removed from the crypto operation structure.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
---
 app/test-crypto-perf/cperf_ops.c                 |  3 ---
 doc/guides/prog_guide/cryptodev_lib.rst          |  1 -
 doc/guides/rel_notes/release_17_08.rst           |  3 +++
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c         |  6 +++--
 drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h |  2 ++
 drivers/crypto/openssl/rte_openssl_pmd.c         |  4 ++-
 drivers/crypto/openssl/rte_openssl_pmd_private.h |  3 +++
 drivers/crypto/qat/qat_adf/qat_algs_build_desc.c |  1 +
 drivers/crypto/qat/qat_crypto.c                  |  4 +--
 examples/ipsec-secgw/esp.c                       |  2 --
 examples/l2fwd-crypto/main.c                     |  4 ---
 lib/librte_cryptodev/rte_crypto_sym.h            |  6 +----
 test/test/test_cryptodev.c                       | 10 +++-----
 test/test/test_cryptodev_perf.c                  | 31 +++++++++++++-----------
 14 files changed, 39 insertions(+), 41 deletions(-)

diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 60d55a0..9405cef 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -186,7 +186,6 @@ cperf_set_ops_auth(struct rte_crypto_op **ops,
 			sym_op->auth.digest.length = options->auth_digest_sz;
 			sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
 			sym_op->auth.aad.data = test_vector->aad.data;
-			sym_op->auth.aad.length = options->auth_aad_sz;
 
 		}
 
@@ -272,7 +271,6 @@ cperf_set_ops_cipher_auth(struct rte_crypto_op **ops,
 			sym_op->auth.digest.length = options->auth_digest_sz;
 			sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
 			sym_op->auth.aad.data = test_vector->aad.data;
-			sym_op->auth.aad.length = options->auth_aad_sz;
 		}
 
 		if (options->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2 ||
@@ -333,7 +331,6 @@ cperf_set_ops_aead(struct rte_crypto_op **ops,
 
 		sym_op->auth.aad.data = rte_pktmbuf_mtod(bufs_in[i], uint8_t *);
 		sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys(bufs_in[i]);
-		sym_op->auth.aad.length = options->auth_aad_sz;
 
 		/* authentication parameters */
 		if (options->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
index 68890ff..ea8fc00 100644
--- a/doc/guides/prog_guide/cryptodev_lib.rst
+++ b/doc/guides/prog_guide/cryptodev_lib.rst
@@ -553,7 +553,6 @@ chain.
             struct {
                 uint8_t *data;
                 phys_addr_t phys_addr;
-                uint16_t length;
             } aad;    /**< Additional authentication parameters */
         } auth;
     }
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index eabf3dd..e633d73 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -163,6 +163,9 @@ API Changes
     ``rte_crypto_cipher_xform``.
   * Added authentication IV parameters (offset and length) in
     ``rte_crypto_auth_xform``.
+  * Removed Additional Authentication Data (AAD) length from ``rte_crypto_sym_op``.
+  * Changed field size of AAD length in ``rte_crypto_auth_xform``,
+    from uint32_t to uint16_t.
 
 
 ABI Changes
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index 414f22b..f6136ba 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -145,6 +145,8 @@ aesni_gcm_set_session_parameters(struct aesni_gcm_session *sess,
 		return -EINVAL;
 	}
 
+	sess->aad_length = auth_xform->auth.add_auth_data_length;
+
 	return 0;
 }
 
@@ -255,7 +257,7 @@ process_gcm_crypto_op(struct rte_crypto_op *op,
 		aesni_gcm_enc[session->key].init(&session->gdata,
 				iv_ptr,
 				sym_op->auth.aad.data,
-				(uint64_t)sym_op->auth.aad.length);
+				(uint64_t)session->aad_length);
 
 		aesni_gcm_enc[session->key].update(&session->gdata, dst, src,
 				(uint64_t)part_len);
@@ -293,7 +295,7 @@ process_gcm_crypto_op(struct rte_crypto_op *op,
 		aesni_gcm_dec[session->key].init(&session->gdata,
 				iv_ptr,
 				sym_op->auth.aad.data,
-				(uint64_t)sym_op->auth.aad.length);
+				(uint64_t)session->aad_length);
 
 		aesni_gcm_dec[session->key].update(&session->gdata, dst, src,
 				(uint64_t)part_len);
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
index 2ed96f8..bfd4d1c 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd_private.h
@@ -99,6 +99,8 @@ struct aesni_gcm_session {
 	/**< GCM operation type */
 	enum aesni_gcm_key key;
 	/**< GCM key type */
+	uint16_t aad_length;
+	/**< AAD length */
 	struct gcm_data gdata __rte_cache_aligned;
 	/**< GCM parameters */
 };
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 970c735..9de4c68 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -370,6 +370,8 @@ openssl_set_session_auth_parameters(struct openssl_session *sess,
 		return -EINVAL;
 	}
 
+	sess->auth.aad_length = xform->auth.add_auth_data_length;
+
 	return 0;
 }
 
@@ -934,7 +936,7 @@ process_openssl_combined_op
 			sess->iv.offset);
 	ivlen = sess->iv.length;
 	aad = op->sym->auth.aad.data;
-	aadlen = op->sym->auth.aad.length;
+	aadlen = sess->auth.aad_length;
 
 	tag = op->sym->auth.digest.data;
 	if (tag == NULL)
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_private.h b/drivers/crypto/openssl/rte_openssl_pmd_private.h
index 3a64853..045e532 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_private.h
+++ b/drivers/crypto/openssl/rte_openssl_pmd_private.h
@@ -162,6 +162,9 @@ struct openssl_session {
 				/**< pointer to EVP context structure */
 			} hmac;
 		};
+
+		uint16_t aad_length;
+		/**< AAD length */
 	} auth;
 
 } __rte_cache_aligned;
diff --git a/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c b/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
index 5bf9c86..4df57aa 100644
--- a/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
+++ b/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
@@ -817,6 +817,7 @@ int qat_alg_aead_session_create_content_desc_auth(struct qat_session *cdesc,
 					ICP_QAT_HW_GALOIS_128_STATE1_SZ +
 					ICP_QAT_HW_GALOIS_H_SZ);
 		*aad_len = rte_bswap32(add_auth_data_length);
+		cdesc->aad_len = add_auth_data_length;
 		break;
 	case ICP_QAT_HW_AUTH_ALGO_SNOW_3G_UIA2:
 		qat_proto_flag = QAT_CRYPTO_PROTO_FLAG_SNOW3G;
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index 7fc8239..5969688 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -1175,7 +1175,7 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 			cipher_param->cipher_length = 0;
 			cipher_param->cipher_offset = 0;
 			auth_param->u1.aad_adr = 0;
-			auth_param->auth_len = op->sym->auth.aad.length;
+			auth_param->auth_len = ctx->aad_len;
 			auth_param->auth_off = op->sym->auth.data.offset;
 			auth_param->u2.aad_sz = 0;
 		}
@@ -1202,7 +1202,7 @@ qat_write_hw_desc_entry(struct rte_crypto_op *op, uint8_t *out_msg,
 		rte_hexdump(stdout, "digest:", op->sym->auth.digest.data,
 				op->sym->auth.digest.length);
 		rte_hexdump(stdout, "aad:", op->sym->auth.aad.data,
-				op->sym->auth.aad.length);
+				ctx->aad_len);
 	}
 #endif
 	return 0;
diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 9e12782..571c2c6 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -129,7 +129,6 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		sym_cop->auth.aad.data = aad;
 		sym_cop->auth.aad.phys_addr = rte_pktmbuf_mtophys_offset(m,
 				aad - rte_pktmbuf_mtod(m, uint8_t *));
-		sym_cop->auth.aad.length = 8;
 		break;
 	default:
 		RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
@@ -358,7 +357,6 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		sym_cop->auth.aad.data = aad;
 		sym_cop->auth.aad.phys_addr = rte_pktmbuf_mtophys_offset(m,
 				aad - rte_pktmbuf_mtod(m, uint8_t *));
-		sym_cop->auth.aad.length = 8;
 		break;
 	default:
 		RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index ba5aef7..6fe829e 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -497,11 +497,9 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
 		if (cparams->aad.length) {
 			op->sym->auth.aad.data = cparams->aad.data;
 			op->sym->auth.aad.phys_addr = cparams->aad.phys_addr;
-			op->sym->auth.aad.length = cparams->aad.length;
 		} else {
 			op->sym->auth.aad.data = NULL;
 			op->sym->auth.aad.phys_addr = 0;
-			op->sym->auth.aad.length = 0;
 		}
 	}
 
@@ -709,8 +707,6 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 					options->auth_xform.auth.digest_length;
 			if (options->auth_xform.auth.add_auth_data_length) {
 				port_cparams[i].aad.data = options->aad.data;
-				port_cparams[i].aad.length =
-					options->auth_xform.auth.add_auth_data_length;
 				port_cparams[i].aad.phys_addr = options->aad.phys_addr;
 				if (!options->aad_param)
 					generate_random_key(port_cparams[i].aad.data,
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index 3ccb6fd..b964a56 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -365,7 +365,7 @@ struct rte_crypto_auth_xform {
 	 * the result shall be truncated.
 	 */
 
-	uint32_t add_auth_data_length;
+	uint16_t add_auth_data_length;
 	/**< The length of the additional authenticated data (AAD) in bytes.
 	 * The maximum permitted value is 65535 (2^16 - 1) bytes, unless
 	 * otherwise specified below.
@@ -653,10 +653,6 @@ struct rte_crypto_sym_op {
 			 * operation, this field is used to pass plaintext.
 			 */
 			phys_addr_t phys_addr;	/**< physical address */
-			uint16_t length;
-			/**< Length of additional authenticated data (AAD)
-			 * in bytes
-			 */
 		} aad;
 		/**< Additional authentication parameters */
 	} auth;
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 853e3bd..7acfa24 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -4637,7 +4637,7 @@ test_3DES_cipheronly_openssl_all(void)
 static int
 create_gcm_session(uint8_t dev_id, enum rte_crypto_cipher_operation op,
 		const uint8_t *key, const uint8_t key_len,
-		const uint8_t aad_len, const uint8_t auth_len,
+		const uint16_t aad_len, const uint8_t auth_len,
 		uint8_t iv_len,
 		enum rte_crypto_auth_operation auth_op)
 {
@@ -4751,12 +4751,11 @@ create_gcm_operation(enum rte_crypto_cipher_operation op,
 	TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data,
 			"no room to append aad");
 
-	sym_op->auth.aad.length = tdata->aad.len;
 	sym_op->auth.aad.phys_addr =
 			rte_pktmbuf_mtophys(ut_params->ibuf);
 	memcpy(sym_op->auth.aad.data, tdata->aad.data, tdata->aad.len);
 	TEST_HEXDUMP(stdout, "aad:", sym_op->auth.aad.data,
-		sym_op->auth.aad.length);
+		tdata->aad.len);
 
 	/* Append IV at the end of the crypto operation*/
 	uint8_t *iv_ptr = rte_crypto_op_ctod_offset(ut_params->op,
@@ -6315,7 +6314,6 @@ create_gmac_operation(enum rte_crypto_auth_operation op,
 	TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data,
 			"no room to append aad");
 
-	sym_op->auth.aad.length = tdata->aad.len;
 	sym_op->auth.aad.phys_addr =
 			rte_pktmbuf_mtophys(ut_params->ibuf);
 	memcpy(sym_op->auth.aad.data, tdata->aad.data, tdata->aad.len);
@@ -6380,7 +6378,7 @@ static int create_gmac_session(uint8_t dev_id,
 	ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_AES_GMAC;
 	ut_params->auth_xform.auth.op = auth_op;
 	ut_params->auth_xform.auth.digest_length = tdata->gmac_tag.len;
-	ut_params->auth_xform.auth.add_auth_data_length = 0;
+	ut_params->auth_xform.auth.add_auth_data_length = tdata->aad.len;
 	ut_params->auth_xform.auth.key.length = 0;
 	ut_params->auth_xform.auth.key.data = NULL;
 
@@ -6860,7 +6858,6 @@ create_auth_GMAC_operation(struct crypto_testsuite_params *ts_params,
 	TEST_HEXDUMP(stdout, "AAD:", sym_op->auth.aad.data, reference->aad.len);
 
 	sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf);
-	sym_op->auth.aad.length = reference->aad.len;
 
 	/* digest */
 	sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append(
@@ -7194,7 +7191,6 @@ create_gcm_operation_SGL(enum rte_crypto_cipher_operation op,
 			"no room to prepend aad");
 	sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys(
 			ut_params->ibuf);
-	sym_op->auth.aad.length = aad_len;
 
 	memset(sym_op->auth.aad.data, 0, aad_len);
 	rte_memcpy(sym_op->auth.aad.data, tdata->aad.data, aad_len);
diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c
index 1d204fd..7239976 100644
--- a/test/test/test_cryptodev_perf.c
+++ b/test/test/test_cryptodev_perf.c
@@ -45,6 +45,7 @@
 
 #define AES_CIPHER_IV_LENGTH 16
 #define TRIPLE_DES_CIPHER_IV_LENGTH 8
+#define AES_GCM_AAD_LENGTH 16
 
 #define PERF_NUM_OPS_INFLIGHT		(128)
 #define DEFAULT_NUM_REQS_TO_SUBMIT	(10000000)
@@ -70,7 +71,6 @@ enum chain_mode {
 
 struct symmetric_op {
 	const uint8_t *aad_data;
-	uint32_t aad_len;
 
 	const uint8_t *p_data;
 	uint32_t p_len;
@@ -97,6 +97,7 @@ struct symmetric_session_attrs {
 
 	const uint8_t *iv_data;
 	uint16_t iv_len;
+	uint16_t aad_len;
 	uint32_t digest_len;
 };
 
@@ -2779,6 +2780,7 @@ test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain,
 		break;
 	case RTE_CRYPTO_AUTH_AES_GCM:
 		auth_xform.auth.key.data = NULL;
+		auth_xform.auth.add_auth_data_length = AES_GCM_AAD_LENGTH;
 		break;
 	default:
 		return NULL;
@@ -2855,8 +2857,6 @@ test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain,
 	}
 }
 
-#define AES_GCM_AAD_LENGTH 16
-
 static struct rte_mbuf *
 test_perf_create_pktmbuf(struct rte_mempool *mpool, unsigned buf_sz)
 {
@@ -2888,7 +2888,6 @@ test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m,
 		op->sym->auth.digest.phys_addr = 0;
 		op->sym->auth.digest.length = 0;
 		op->sym->auth.aad.data = NULL;
-		op->sym->auth.aad.length = 0;
 		op->sym->auth.data.offset = 0;
 		op->sym->auth.data.length = 0;
 	} else {
@@ -2932,7 +2931,6 @@ test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m,
 				rte_pktmbuf_mtophys_offset(m, data_len);
 	op->sym->auth.digest.length = digest_len;
 	op->sym->auth.aad.data = aes_gcm_aad;
-	op->sym->auth.aad.length = AES_GCM_AAD_LENGTH;
 
 	/* Copy IV at the end of the crypto operation */
 	rte_memcpy(rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET),
@@ -2999,9 +2997,14 @@ test_perf_set_crypto_op_snow3g_cipher(struct rte_crypto_op *op,
 	rte_memcpy(rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET),
 			snow3g_iv, SNOW3G_CIPHER_IV_LENGTH);
 
+	/* Cipher Parameters */
 	op->sym->cipher.data.offset = 0;
 	op->sym->cipher.data.length = data_len << 3;
 
+	rte_memcpy(rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET),
+			snow3g_iv,
+			SNOW3G_CIPHER_IV_LENGTH);
+
 	op->sym->m_src = m;
 
 	return op;
@@ -4137,6 +4140,7 @@ test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams)
 	auth_xform.auth.op = pparams->session_attrs->auth;
 	auth_xform.auth.algo = pparams->session_attrs->auth_algorithm;
 
+	auth_xform.auth.add_auth_data_length = pparams->session_attrs->aad_len;
 	auth_xform.auth.digest_length = pparams->session_attrs->digest_len;
 	auth_xform.auth.key.length = pparams->session_attrs->key_auth_len;
 
@@ -4172,17 +4176,16 @@ perf_gcm_set_crypto_op(struct rte_crypto_op *op, struct rte_mbuf *m,
 	op->sym->auth.digest.data = m_hlp->digest;
 	op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
 					  m,
-					  params->symmetric_op->aad_len +
+					  params->session_attrs->aad_len +
 					  params->symmetric_op->p_len);
 
 	op->sym->auth.digest.length = params->symmetric_op->t_len;
 
 	op->sym->auth.aad.data = m_hlp->aad;
-	op->sym->auth.aad.length = params->symmetric_op->aad_len;
 	op->sym->auth.aad.phys_addr = rte_pktmbuf_mtophys(m);
 
 	rte_memcpy(op->sym->auth.aad.data, params->symmetric_op->aad_data,
-		       params->symmetric_op->aad_len);
+		       params->session_attrs->aad_len);
 
 	rte_memcpy(iv_ptr, params->session_attrs->iv_data,
 		       params->session_attrs->iv_len);
@@ -4190,11 +4193,11 @@ perf_gcm_set_crypto_op(struct rte_crypto_op *op, struct rte_mbuf *m,
 		iv_ptr[15] = 1;
 
 	op->sym->auth.data.offset =
-			params->symmetric_op->aad_len;
+			params->session_attrs->aad_len;
 	op->sym->auth.data.length = params->symmetric_op->p_len;
 
 	op->sym->cipher.data.offset =
-			params->symmetric_op->aad_len;
+			params->session_attrs->aad_len;
 	op->sym->cipher.data.length = params->symmetric_op->p_len;
 
 	op->sym->m_src = m;
@@ -4208,7 +4211,7 @@ test_perf_create_pktmbuf_fill(struct rte_mempool *mpool,
 		unsigned buf_sz, struct crypto_params *m_hlp)
 {
 	struct rte_mbuf *m = rte_pktmbuf_alloc(mpool);
-	uint16_t aad_len = params->symmetric_op->aad_len;
+	uint16_t aad_len = params->session_attrs->aad_len;
 	uint16_t digest_size = params->symmetric_op->t_len;
 	char *p;
 
@@ -4344,14 +4347,14 @@ perf_AES_GCM(uint8_t dev_id, uint16_t queue_id,
 				TEST_ASSERT_BUFFERS_ARE_EQUAL(
 					pparams->symmetric_op->c_data,
 					pkt +
-					pparams->symmetric_op->aad_len,
+					pparams->session_attrs->aad_len,
 					pparams->symmetric_op->c_len,
 					"GCM Ciphertext data not as expected");
 
 				TEST_ASSERT_BUFFERS_ARE_EQUAL(
 					pparams->symmetric_op->t_data,
 					pkt +
-					pparams->symmetric_op->aad_len +
+					pparams->session_attrs->aad_len +
 					pparams->symmetric_op->c_len,
 					pparams->symmetric_op->t_len,
 					"GCM MAC data not as expected");
@@ -4423,13 +4426,13 @@ test_perf_AES_GCM(int continual_buf_len, int continual_size)
 			RTE_CRYPTO_AUTH_OP_GENERATE;
 		session_attrs[i].key_auth_data = NULL;
 		session_attrs[i].key_auth_len = 0;
+		session_attrs[i].aad_len = gcm_test->aad.len;
 		session_attrs[i].digest_len =
 				gcm_test->auth_tag.len;
 		session_attrs[i].iv_len = gcm_test->iv.len;
 		session_attrs[i].iv_data = gcm_test->iv.data;
 
 		ops_set[i].aad_data = gcm_test->aad.data;
-		ops_set[i].aad_len = gcm_test->aad.len;
 		ops_set[i].p_data = gcm_test->plaintext.data;
 		ops_set[i].p_len = buf_lengths[i];
 		ops_set[i].c_data = gcm_test->ciphertext.data;
-- 
2.9.4

^ permalink raw reply	[relevance 2%]

Results 10801-11000 of ~18000   |  | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2017-05-22 14:32     [dpdk-dev] [PATCH 1/3] drivers/net: add support for IF-MIB and EtherLike-MIB for e1000 Michal Jastrzebski
2017-06-26  9:42     ` [dpdk-dev] [PATCH v2] " Radu Nicolau
2017-06-27 22:26       ` Stephen Hemminger
2017-07-06 11:48  3%     ` Pattan, Reshma
2017-05-30 16:44     [dpdk-dev] [RFC 2/3] ethdev: add new rte_mtr API for traffic metering and policing Cristian Dumitrescu
2017-08-26  0:06     ` [dpdk-dev] [PATCH 0/3] rte_mtr: generic ethdev API for " Cristian Dumitrescu
2017-08-26  0:06  2%   ` [dpdk-dev] [PATCH 2/3] ethdev: add new rte_mtr API for traffic " Cristian Dumitrescu
2017-06-07 10:36     [dpdk-dev] [PATCH] cryptodev: fix cryptodev start return value Pavan Nikhilesh
2017-06-07 15:54     ` Trahe, Fiona
2017-06-08  8:12       ` Pavan Nikhilesh Bhagavatula
2017-07-11 14:08  0%     ` De Lara Guarch, Pablo
2017-06-21 17:32     [dpdk-dev] [PATCH 0/4] Infrastructure to support octeontx HW mempool manager Santosh Shukla
2017-06-21 17:32     ` [dpdk-dev] [PATCH 1/4] mempool: get the external mempool capability Santosh Shukla
2017-07-03 16:37       ` Olivier Matz
2017-07-05  6:41  3%     ` santosh
2017-07-10 13:55  0%       ` Olivier Matz
2017-07-10 16:09  0%         ` santosh
2017-06-27 10:52     [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki
2017-07-10 12:44     ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki
2017-07-10 12:44       ` [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki
2017-08-30 20:07  4%     ` Bruce Richardson
2017-06-29 11:23     [dpdk-dev] [PATCH v2 0/5] service cores: cover letter Harry van Haaren
2017-07-02 21:35     ` [dpdk-dev] [PATCH v3 0/7] " Harry van Haaren
2017-07-02 21:35  1%   ` [dpdk-dev] [PATCH v3 1/7] service cores: header and implementation Harry van Haaren
2017-07-07 16:41     ` [dpdk-dev] [PATCH v4 0/7] service cores: cover letter Harry van Haaren
2017-07-07 16:41  1%   ` [dpdk-dev] [PATCH v4 1/7] service cores: header and implementation Harry van Haaren
2017-07-11  8:29  0%     ` Jerin Jacob
2017-07-11  9:54           ` Thomas Monjalon
2017-07-11 12:32  3%         ` Van Haaren, Harry
2017-07-11 12:44  0%           ` Jerin Jacob
2017-07-11 14:19       ` [dpdk-dev] [PATCH v5 0/7] service cores: cover letter Harry van Haaren
2017-07-11 14:19  1%     ` [dpdk-dev] [PATCH v5 1/7] service cores: header and implementation Harry van Haaren
2017-06-29 11:34     [dpdk-dev] [PATCH v3 00/26] Crypto operation restructuring Pablo de Lara
2017-07-02  5:41     ` [dpdk-dev] [PATCH v4 " Pablo de Lara
2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 16/26] cryptodev: remove AAD length from crypto op Pablo de Lara
2017-07-02  5:41  1%   ` [dpdk-dev] [PATCH v4 17/26] cryptodev: remove digest " Pablo de Lara
2017-07-02  5:41  2%   ` [dpdk-dev] [PATCH v4 20/26] cryptodev: add AEAD parameters in crypto operation Pablo de Lara
2017-07-02  5:41  4%   ` [dpdk-dev] [PATCH v4 26/26] cryptodev: remove AAD from authentication structure Pablo de Lara
2017-06-30 14:26     [dpdk-dev] [RFC] ring: relax alignment constraint on ring structure Olivier Matz
2017-07-20  8:52  0% ` Olivier Matz
2017-06-30 17:09     [dpdk-dev] [PATCH v2 00/11] Device independent crypto sessions Pablo de Lara
2017-07-02 15:57     ` [dpdk-dev] [PATCH v3 00/12] " Pablo de Lara
2017-07-02 15:57  2%   ` [dpdk-dev] [PATCH v3 04/12] cryptodev: do not create session mempool internally Pablo de Lara
2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 06/12] cryptodev: remove device id from crypto session Pablo de Lara
2017-07-02 15:57  3%   ` [dpdk-dev] [PATCH v3 07/12] cryptodev: remove driver id from session Pablo de Lara
2017-07-02 15:57  4%   ` [dpdk-dev] [PATCH v3 08/12] cryptodev: remove mempool " Pablo de Lara
2017-07-02 15:57  1%   ` [dpdk-dev] [PATCH v3 09/12] cryptodev: support device independent sessions Pablo de Lara
2017-07-02 15:57  2%   ` [dpdk-dev] [PATCH v3 10/12] cryptodev: add mempool pointer in queue pair setup Pablo de Lara
2017-07-05  5:26       ` [dpdk-dev] [PATCH v4 00/12] Device independent crypto sessions Pablo de Lara
2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 04/12] cryptodev: do not create session mempool internally Pablo de Lara
2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 05/12] cryptodev: change attach session to queue pair API Pablo de Lara
2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 06/12] cryptodev: remove device id from crypto session Pablo de Lara
2017-07-05  5:26  3%     ` [dpdk-dev] [PATCH v4 07/12] cryptodev: remove driver id from session Pablo de Lara
2017-07-05  5:26  4%     ` [dpdk-dev] [PATCH v4 08/12] cryptodev: remove mempool " Pablo de Lara
2017-07-05  5:26  1%     ` [dpdk-dev] [PATCH v4 09/12] cryptodev: support device independent sessions Pablo de Lara
2017-07-05  5:26  2%     ` [dpdk-dev] [PATCH v4 10/12] cryptodev: add mempool pointer in queue pair setup Pablo de Lara
2017-07-03 13:21  4% [dpdk-dev] [PATCH v1] doc: add libnuma to the dpdk dependencies John McNamara
2017-07-04 16:13     [dpdk-dev] [PATCH v10 00/20] Userspace Network Control Interface (UNCI) Ferruh Yigit
2017-07-04 16:13     ` [dpdk-dev] [PATCH v10 20/20] ethdev: add control interface support Ferruh Yigit
2017-07-08  6:28  3%   ` Yuanhan Liu
2017-07-20 14:55  0%     ` Ferruh Yigit
2017-07-05 16:55     [dpdk-dev] [PATCH v3 0/3] pci: handle 32 bit domain values Stephen Hemminger
2017-07-05 16:55  3% ` [dpdk-dev] [PATCH v3 2/3] eal: PCI domain should be 32 bits Stephen Hemminger
2017-07-05 17:58  3% [dpdk-dev] RFC - increasing the size of ethenet device name Stephen Hemminger
2017-07-05 23:20  0% ` Thomas Monjalon
2017-07-06  9:23  4% [dpdk-dev] [PATCH] doc: release notes 17.08, API change description Radu Nicolau
2017-07-06  9:29  4% ` [dpdk-dev] [PATCH v2] " Radu Nicolau
2017-07-07  9:21  4%   ` [dpdk-dev] [PATCH v3] " Radu Nicolau
2017-07-08 16:23  0%     ` Thomas Monjalon
2017-07-10  9:15  4%     ` [dpdk-dev] [PATCH v4] " Radu Nicolau
2017-07-10  9:18  4%       ` [dpdk-dev] [PATCH v5] " Radu Nicolau
2017-07-10 11:39  4%         ` [dpdk-dev] [PATCH v6] " Radu Nicolau
2017-07-09  9:28  3% [dpdk-dev] [PATCH 0/2] devargs changes / deprecation notice Jan Blunck
2017-07-09  9:28 11% ` [dpdk-dev] [PATCH 2/2] eal: deprecate 17.08 devargs API/ABI Jan Blunck
2017-07-09 12:25  4%   ` Shreyansh Jain
2017-08-07 23:03  4%   ` Thomas Monjalon
2017-07-11  6:30  3% [dpdk-dev] [PATCH] cryptodev: remove AAD size in auth capabilities Pablo de Lara
2017-07-11 10:01  8% [dpdk-dev] [PATCH] eal: add notice to make DPDK IOVA aware Jerin Jacob
2017-07-21  6:41  0% ` santosh
2017-08-04  3:41  0% ` santosh
2017-08-04  5:25  0%   ` Hemant Agrawal
2017-08-06 21:22  0%     ` Olivier MATZ
2017-08-08  0:04  0%       ` Thomas Monjalon
2017-07-11 23:24     [dpdk-dev] [PATCH 00/13] devargs fixes Jan Blunck
2017-07-11 23:25  5% ` [dpdk-dev] [PATCH 03/13] devargs: deprecate enum rte_devtype based functions Jan Blunck
2017-08-07 23:02  0%   ` Thomas Monjalon
2017-07-14 21:11     ` [dpdk-dev] [PATCH v2 00/15] devargs fixes Jan Blunck
2017-07-14 21:12  5%   ` [dpdk-dev] [PATCH v2 04/15] devargs: deprecate enum rte_devtype based functions Jan Blunck
2017-07-12  7:58 13% [dpdk-dev] [PATCH] doc: announce API and ABI change for ethdev Zhiyong Yang
2017-08-04  1:12  4% ` Tan, Jianfeng
2017-08-04  4:07  9% ` Yuanhan Liu
2017-08-04  4:13  4%   ` Jerin Jacob
2017-08-04  5:36  4%   ` Yang, Zhiyong
2017-08-04  5:27 13% ` [dpdk-dev] [PATCH v2] " Zhiyong Yang
2017-08-04  6:56  7%   ` Remy Horton
2017-08-05 10:34  4%     ` Yang, Zhiyong
2017-08-07  3:07  4%       ` Yang, Zhiyong
2017-08-07 11:04  4%         ` Thomas Monjalon
2017-08-07 15:20  4%     ` Shahaf Shuler
2017-08-07 12:42 13%   ` [dpdk-dev] [PATCH v3] " Zhiyong Yang
2017-08-08  4:02  4%     ` Yang, Zhiyong
2017-08-08  9:35  4%       ` Thomas Monjalon
2017-07-12  7:59     [dpdk-dev] [PATCH 0/2] cryptodev vdev changes for -rc2 Jan Blunck
2017-07-12 19:58     ` [dpdk-dev] [PATCH v2 0/4] " Jan Blunck
2017-07-19 13:31       ` De Lara Guarch, Pablo
2017-07-27 19:31  3%     ` Jan Blunck
2017-08-01 10:39  4%       ` De Lara Guarch, Pablo
2017-07-12  9:25  4% [dpdk-dev] [PATCH] doc: notify callback process API change Bernard Iremonger
2017-07-13  9:12  7% [dpdk-dev] [PATCH] mempool: add notice to change mempool API/ABI Santosh Shukla
2017-07-20  8:46  7% ` Olivier Matz
2017-07-20  9:27  4%   ` santosh
2017-07-20 11:26  7%     ` Thomas Monjalon
2017-07-20 10:29  7% ` [dpdk-dev] [PATCH v2] doc: announce API/ABI changes for mempool Santosh Shukla
2017-07-21  6:26  4%   ` santosh
2017-08-03 14:21  4%   ` Jerin Jacob
2017-08-03 14:30  4%     ` santosh
2017-08-05 20:24  4%     ` Olivier MATZ
2017-08-08  0:10  4%       ` Thomas Monjalon
2017-07-17  8:29  6% [dpdk-dev] [PATCH 1/3] cryptodev: modify some field sizes Pablo de Lara
2017-07-17 15:25  4% [dpdk-dev] [PATCH] cryptodev: remove crypto operation status value Kirill Rybalchenko
2017-07-20 13:47     [dpdk-dev] [PATCH v3 0/6] Infrastructure to support octeontx HW mempool manager Santosh Shukla
2017-08-15  6:07     ` [dpdk-dev] [PATCH v4 0/7] " Santosh Shukla
2017-08-15  6:07  4%   ` [dpdk-dev] [PATCH v4 3/7] doc: remove mempool api change notice Santosh Shukla
2017-07-24 20:51  3% [dpdk-dev] [PATCH] net/i40e: new API to add VF MAC address from PF Wenzhuo Lu
2017-07-25 14:09  3% ` [dpdk-dev] [PATCH v2] " Wenzhuo Lu
2017-08-17 13:05  0%   ` Ferruh Yigit
2017-08-17 13:36  0%     ` Lu, Wenzhuo
2017-07-25 10:18  3% [dpdk-dev] 17.11 Intel Roadmap O'Driscoll, Tim
2017-07-25 13:51  0% ` O'Driscoll, Tim
2017-07-25 15:46  0% ` Alejandro Lucero
2017-07-31  2:30     [dpdk-dev] [PATCH] cryptodev: fix NULL pointer dereference Pablo de Lara
2017-07-31 19:33     ` [dpdk-dev] [PATCH v2] " Thomas Monjalon
2017-08-01  8:13       ` Sergio Gonzalez Monroy
2017-08-01  9:35         ` Thomas Monjalon
2017-08-01 10:17  3%       ` Sergio Gonzalez Monroy
2017-08-01 10:48  4%         ` De Lara Guarch, Pablo
2017-08-01 12:36  3%           ` Thomas Monjalon
2017-07-31  9:18     Pablo de Lara
2017-08-16  2:41  3% ` [dpdk-dev] [PATCH v3] cryptodev: allocate driver structure statically Pablo de Lara
2017-08-03 12:21     [dpdk-dev] [RFC] ethdev: add ioctl-like API to control device specific features Chilikin, Andrey
2017-08-03 13:21     ` Bruce Richardson
2017-08-03 16:15  3%   ` Stephen Hemminger
2017-08-03 19:53  0%     ` Thomas Monjalon
2017-08-04  9:59  0%       ` Chilikin, Andrey
2017-08-04 10:08  0%         ` Thomas Monjalon
2017-08-04 11:58  0%       ` Ferruh Yigit
2017-08-04 12:56  0%         ` Bruce Richardson
2017-08-08  8:32  0%           ` Ferruh Yigit
2017-08-08 15:27  3%             ` Stephen Hemminger
2017-08-08 17:23  2%         ` Wiles, Keith
2017-08-08 17:28  0%         ` Wiles, Keith
2017-08-08 18:02  0%           ` Stephen Hemminger
2017-08-08 18:21  0%             ` Wiles, Keith
2017-08-03 14:49  5% [dpdk-dev] [PATCH] doc: deprecate Xen dom0 support Thomas Monjalon
2017-08-03 15:33  0% ` Tan, Jianfeng
2017-08-03 20:38  5% ` [dpdk-dev] [PATCH v2] doc: deprecate Xen support Jianfeng Tan
2017-08-03 15:32  4% [dpdk-dev] [PATCH] doc: announce ABI change for cryptodev and ethdev Akhil Goyal
2017-08-04  5:26  4% ` Hemant Agrawal
2017-08-07 17:41  7%   ` Thomas Monjalon
2017-08-07 18:07  4%     ` Boris Pismenny
2017-08-08  5:03  4%       ` Shahaf Shuler
2017-08-08 10:00  4%         ` Thomas Monjalon
2017-08-04  9:28  4% ` De Lara Guarch, Pablo
2017-08-04 15:25  4% ` De Lara Guarch, Pablo
2017-08-08  6:54  7%   ` Akhil Goyal
2017-08-08  7:09  7% ` [dpdk-dev] [PATCH v2] " Akhil Goyal
2017-08-08  8:08  4%   ` De Lara Guarch, Pablo
2017-08-08  8:42  4%     ` Akhil Goyal
2017-08-03 15:55  4% [dpdk-dev] [PATCH] doc: move keepalive to multicore API section Thomas Monjalon
2017-08-03 15:56  4% [dpdk-dev] [PATCH] doc: move metrics libs to device " Thomas Monjalon
2017-08-04 13:29  5% [dpdk-dev] [PATCH] doc: remove planned devargs changes for v17.08 Gaetan Rivet
2017-08-04 13:29  5% [dpdk-dev] [PATCH] doc: announce rte_devargs changes in 17.11 Gaetan Rivet
2017-08-07 23:18  0% ` Thomas Monjalon
2017-08-04 14:20  6% [dpdk-dev] [PATCH v1] doc: update release notes for 17.08 John McNamara
2017-08-07 10:54  4% [dpdk-dev] [RFC PATCH 0/4] ethdev new offloads API Shahaf Shuler
2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 2/4] ethdev: introduce Rx queue " Shahaf Shuler
2017-08-23 12:21  0%   ` Ananyev, Konstantin
2017-08-23 13:06  0%     ` Shahaf Shuler
2017-08-23 21:48  0%   ` Thomas Monjalon
2017-08-29 12:50  0%   ` Ferruh Yigit
2017-08-30  6:22  0%     ` Shahaf Shuler
2017-08-29 13:11  0%   ` Ferruh Yigit
2017-08-07 10:54  3% ` [dpdk-dev] [RFC PATCH 3/4] ethdev: introduce Tx " Shahaf Shuler
2017-08-23  6:39  0% ` [dpdk-dev] [RFC PATCH 0/4] ethdev new " Shahaf Shuler
2017-08-25 10:31  0% ` Jerin Jacob
2017-08-07 17:39     [dpdk-dev] [PATCH v3] ethdev: add return code to rte_eth_stats_reset() David Harton
2017-08-08  9:02  5% ` Van Haaren, Harry
2017-08-08 11:01  0%   ` David Harton (dharton)
2017-08-08 11:03  4%   ` Christian Ehrhardt
2017-08-08 13:13  3%     ` Thomas Monjalon
2017-08-10 13:29     ` [dpdk-dev] [PATCH v4 1/2] " David Harton
2017-08-10 13:29 13%   ` [dpdk-dev] [PATCH v4 2/2] doc: Update ABI Change for rte_eth_stats_reset David Harton
     [not found]     <20170706150751.27251-1-stephen@networkplumber.org>
2017-08-07 22:19  0% ` [dpdk-dev] [PATCH] ethdev: add notice for planned name size change Yongseok Koh
2017-08-08  4:56  0%   ` Shahaf Shuler
2017-08-08  9:47  0%     ` Thomas Monjalon
2017-08-08 12:31  6% [dpdk-dev] [PATCH v1] doc: add template release notes for 17.11 John McNamara
2017-08-09  8:22  6% ` [dpdk-dev] [PATCH v2] " John McNamara
2017-08-08 14:26  4% [dpdk-dev] [PATCH] eal: bump ABI version for PCI, bus and devargs work Gaetan Rivet
2017-08-08 17:26  4% ` Thomas Monjalon
2017-08-08 14:26  9% [dpdk-dev] [PATCH] doc: notify EAL ABI change Gaetan Rivet
2017-08-08 17:27  4% ` Thomas Monjalon
2017-08-08 14:48     [dpdk-dev] [PATCH 1/2] doc: fix v17.05 release note Jerin Jacob
2017-08-08 14:48  3% ` [dpdk-dev] [PATCH 2/2] eventdev: bump library version Jerin Jacob
2017-08-08 17:45  0%   ` Thomas Monjalon
2017-08-09  8:42  3% [dpdk-dev] [PATCH 0/2] increase port_id range Zhiyong Yang
2017-08-09  9:00  4% ` De Lara Guarch, Pablo
2017-08-09  9:17  0%   ` Yang, Zhiyong
2017-08-09 13:30     [dpdk-dev] [PATCH] kvargs: return error if key not find in kvlist Keith Wiles
2017-08-09 13:53     ` Ananyev, Konstantin
2017-08-09 14:35  3%   ` Wiles, Keith
2017-08-09 14:47  0%     ` Ananyev, Konstantin
2017-08-09 20:21     [dpdk-dev] Announcement of SSE requirement change in dpdk Neil Horman
2017-08-11 20:29     ` Bruce Richardson
2017-08-12 18:19  3%   ` Neil Horman
2017-08-14  9:32  3%     ` Bruce Richardson
2017-08-14 10:50  0%       ` Neil Horman
2017-08-14 10:58  0%         ` Bruce Richardson
2017-08-14 11:23  4%           ` Neil Horman
2017-08-14 15:15     [dpdk-dev] [PATCH v1 0/4] make dpdk iova aware Santosh Shukla
2017-08-14 15:15 15% ` [dpdk-dev] [PATCH v1 4/4] doc: remove dpdk iova aware notice Santosh Shukla
2017-08-15 12:32     [dpdk-dev] [PATCH 0/8] service: rework for usability Harry van Haaren
2017-08-16 11:16  3% ` Neil Horman
2017-08-16 11:31  4%   ` Van Haaren, Harry
2017-08-16 12:07  0%     ` Van Haaren, Harry
2017-08-16 13:27  0%       ` Neil Horman
2017-08-21 12:58     ` [dpdk-dev] [PATCH v2 00/15] service: API improvements and updates Harry van Haaren
2017-08-21 12:58  4%   ` [dpdk-dev] [PATCH v2 15/15] docs: add notes on service cores API updates Harry van Haaren
2017-08-21  9:34  3% [dpdk-dev] [PATCH] vhost: added user callbacks for socket open/close Dariusz Stojaczyk
2017-08-21 15:00  0% ` Jens Freimann
2017-08-22 16:24  3% ` [dpdk-dev] [PATCH v2] " Dariusz Stojaczyk
2017-08-25  9:22  0%   ` Jens Freimann
2017-08-29  6:08  3%     ` Stojaczyk, DariuszX
2017-08-30  6:33  0%       ` Jens Freimann
2017-08-30 10:50  3%   ` [dpdk-dev] [PATCH v3] rte_vhost: " Dariusz Stojaczyk
2017-08-23  1:19     [dpdk-dev] [PATCH] ethdev: stop overriding rx_nombuf by rte_eth_stats_get David Harton
2017-08-23  2:55     ` [dpdk-dev] [PATCH v2 1/2] " David Harton
2017-08-23  7:51       ` Thomas Monjalon
2017-08-23 12:18  4%     ` David Harton (dharton)
2017-08-23 13:24  0%       ` Thomas Monjalon
2017-08-23 21:27  0%         ` David Harton (dharton)
2017-08-23 21:35  0%           ` Thomas Monjalon
2017-08-24 16:20     [dpdk-dev] [PATCH 00/16] nfp: add pf support Alejandro Lucero
2017-08-24 16:20 10% ` [dpdk-dev] [PATCH 02/16] nfp: add specific pf probe function Alejandro Lucero
2017-08-28 16:42  0%   ` Ferruh Yigit
2017-08-24 16:20  6% ` [dpdk-dev] [PATCH 11/16] nfp: allocate eth_dev from " Alejandro Lucero
2017-08-24 23:18  4% [dpdk-dev] [PATCH] ethdev: modifiy vlan_offload_set_t to return int David Harton
2017-08-25 13:33  4% ` [dpdk-dev] [PATCH v2] " David Harton
2017-08-25 13:47  4%   ` [dpdk-dev] [PATCH v3] " David Harton
2017-08-25  9:40     [dpdk-dev] [PATCH 00/12] support to run vdev in the secondary process Jianfeng Tan
2017-08-25  9:40     ` [dpdk-dev] [PATCH 04/12] vdev: move to drivers/bus Jianfeng Tan
2017-08-29 13:04  3%   ` Gaëtan Rivet
2017-08-29 22:47  0%     ` Tan, Jianfeng
2017-08-27 13:24     [dpdk-dev] [dpdk-techboard] next techboard meeting (29th, August) Jerin Jacob
2017-08-28 15:04  3% ` Bruce Richardson
2017-08-29 15:30  0%   ` Jerin Jacob
2017-08-30 13:51 27% [dpdk-dev] [PATCH] devtools: rework abi checker script Olivier Matz
2017-08-30 18:10     [dpdk-dev] [PATCH 0/6] remove xen dom0 support in DPDK Jianfeng Tan
2017-08-30 18:10  1% ` [dpdk-dev] [PATCH 5/6] eal: remove xen dom0 support Jianfeng Tan
2017-08-30 18:10  3% ` [dpdk-dev] [PATCH 6/6] eal: remove API rte_mem_phy2mch Jianfeng Tan

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