* Re: [PATCH v2 3/7] pci: Pass rte_pci_addr to functions instead of separate args
From: Walker, Benjamin @ 2016-12-02 16:16 UTC (permalink / raw)
To: shreyansh.jain@nxp.com; +Cc: dev@dpdk.org
In-Reply-To: <abed91f3-d6e7-d850-1fd5-3fc3de4f7595@nxp.com>
On Thu, 2016-12-01 at 11:56 +0530, Shreyansh Jain wrote:
> Hello Ben,
>
> On Thursday 24 November 2016 01:37 AM, Ben Walker wrote:
> >
> > Instead of passing domain, bus, devid, func, just pass
> > an rte_pci_addr.
> >
> > Signed-off-by: Ben Walker <benjamin.walker@intel.com>
> > ---
> > lib/librte_eal/linuxapp/eal/eal_pci.c | 32 +++++++++++++-------------------
> > 1 file changed, 13 insertions(+), 19 deletions(-)
> >
> > diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c
> > b/lib/librte_eal/linuxapp/eal/eal_pci.c
> > index 876ba38..073af5f 100644
> > --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
> > +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
> > @@ -267,8 +267,7 @@ pci_parse_sysfs_resource(const char *filename, struct
> > rte_pci_device *dev)
> >
> > /* Scan one pci sysfs entry, and fill the devices list from it. */
> > static int
> > -pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
> > - uint8_t devid, uint8_t function)
> > +pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
> > {
> > char filename[PATH_MAX];
> > unsigned long tmp;
> > @@ -281,10 +280,7 @@ pci_scan_one(const char *dirname, uint16_t domain,
> > uint8_t bus,
> > return -1;
> >
> > memset(dev, 0, sizeof(*dev));
> > - dev->addr.domain = domain;
> > - dev->addr.bus = bus;
> > - dev->addr.devid = devid;
> > - dev->addr.function = function;
> > + dev->addr = *addr;
> >
> > /* get vendor id */
> > snprintf(filename, sizeof(filename), "%s/vendor", dirname);
> > @@ -429,16 +425,14 @@ pci_update_device(const struct rte_pci_addr *addr)
> > pci_get_sysfs_path(), addr->domain, addr->bus, addr-
> > >devid,
> > addr->function);
> >
> > - return pci_scan_one(filename, addr->domain, addr->bus, addr->devid,
> > - addr->function);
> > + return pci_scan_one(filename, addr);
> > }
> >
> > /*
> > * split up a pci address into its constituent parts.
> > */
> > static int
> > -parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
> > - uint8_t *bus, uint8_t *devid, uint8_t *function)
> > +parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr
> > *addr)
> > {
> > /* first split on ':' */
> > union splitaddr {
> > @@ -466,10 +460,10 @@ parse_pci_addr_format(const char *buf, int bufsize,
> > uint16_t *domain,
> >
> > /* now convert to int values */
> > errno = 0;
> > - *domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
> > - *bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
> > - *devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
> > - *function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
> > + addr->domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
> > + addr->bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
> > + addr->devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
> > + addr->function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
> > if (errno != 0)
> > goto error;
> >
> > @@ -490,8 +484,7 @@ rte_eal_pci_scan(void)
> > struct dirent *e;
> > DIR *dir;
> > char dirname[PATH_MAX];
> > - uint16_t domain;
> > - uint8_t bus, devid, function;
> > + struct rte_pci_addr addr;
> >
> > dir = opendir(pci_get_sysfs_path());
> > if (dir == NULL) {
> > @@ -500,20 +493,21 @@ rte_eal_pci_scan(void)
> > return -1;
> > }
> >
> > +
> > while ((e = readdir(dir)) != NULL) {
> > if (e->d_name[0] == '.')
> > continue;
> >
> > - if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
> > &domain,
> > - &bus, &devid, &function) != 0)
> > + if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
> > &addr) != 0)
> > continue;
> >
> > snprintf(dirname, sizeof(dirname), "%s/%s",
> > pci_get_sysfs_path(), e->d_name);
> > - if (pci_scan_one(dirname, domain, bus, devid, function) <
> > 0)
> > + if (pci_scan_one(dirname, &addr) < 0)
> > goto error;
> > }
> > closedir(dir);
> > +
> > return 0;
> >
> > error:
> >
>
> Do you mind if I use this patch directly as part of my patchset for bus
> Model? I was doing a similar change to make the pci_scan_one simpler
> (and pass along a new argument)..
Sure, go ahead.
>
> -
> Shreyansh
^ permalink raw reply
* Re: [PATCH v12 1/6] ethdev: add Tx preparation
From: Ananyev, Konstantin @ 2016-12-02 16:17 UTC (permalink / raw)
To: Olivier Matz; +Cc: Thomas Monjalon, Kulasek, TomaszX, dev@dpdk.org
In-Reply-To: <20161202092425.13752e2f@platinum>
Hi Olivier,
> -----Original Message-----
> From: Olivier Matz [mailto:olivier.matz@6wind.com]
> Sent: Friday, December 2, 2016 8:24 AM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Cc: Thomas Monjalon <thomas.monjalon@6wind.com>; Kulasek, TomaszX <tomaszx.kulasek@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v12 1/6] ethdev: add Tx preparation
>
> Hi Konstantin,
>
> On Fri, 2 Dec 2016 01:06:30 +0000, "Ananyev, Konstantin"
> <konstantin.ananyev@intel.com> wrote:
> > >
> > > 2016-11-23 18:36, Tomasz Kulasek:
> > > > +/**
> > > > + * Process a burst of output packets on a transmit queue of an
> > > > Ethernet device.
> > > > + *
> > > > + * The rte_eth_tx_prepare() function is invoked to prepare
> > > > output packets to be
> > > > + * transmitted on the output queue *queue_id* of the Ethernet
> > > > device designated
> > > > + * by its *port_id*.
> > > > + * The *nb_pkts* parameter is the number of packets to be
> > > > prepared which are
> > > > + * supplied in the *tx_pkts* array of *rte_mbuf* structures,
> > > > each of them
> > > > + * allocated from a pool created with rte_pktmbuf_pool_create().
> > > > + * For each packet to send, the rte_eth_tx_prepare() function
> > > > performs
> > > > + * the following operations:
> > > > + *
> > > > + * - Check if packet meets devices requirements for tx offloads.
> > > > + *
> > > > + * - Check limitations about number of segments.
> > > > + *
> > > > + * - Check additional requirements when debug is enabled.
> > > > + *
> > > > + * - Update and/or reset required checksums when tx offload is
> > > > set for packet.
> > > > + *
> > > > + * Since this function can modify packet data, provided mbufs
> > > > must be safely
> > > > + * writable (e.g. modified data cannot be in shared segment).
> > >
> > > I think we will have to remove this limitation in next releases.
> > > As we don't know how it could affect the API, I suggest to declare
> > > this API EXPERIMENTAL.
> >
> > While I don't really mind to mart it as experimental, I don't really
> > understand the reasoning: Why " this function can modify packet data,
> > provided mbufs must be safely writable" suddenly becomes a problem?
> > That seems like and obvious limitation to me and let say tx_burst()
> > has the same one. Second, I don't see how you are going to remove it
> > without introducing a heavy performance impact. Konstantin
> >
>
> About tx_burst(), I don't think we should force the user to provide a
> writable mbuf. There are many use cases where passing a clone
> already works as of today and it avoids duplicating the mbuf data. For
> instance: traffic generator, multicast, bridging/tap, etc...
>
> Moreover, this requirement would be inconsistent with the model you are
> proposing in case of pipeline:
> - tx_prepare() on core X, may update the data
> - tx_burst() on core Y, should not touch the data to avoid cache misses
>
Probably I wasn't very clear in my previous mail.
I am not saying that we should force the user to pass a writable mbuf.
What I am saying that for tx_burst() current expectation is that
after mbuf is handled to tx_burst() user shouldn't try to modify its buffer contents
till TX engine is done with the buffer (mbuf_free() is called by TX func for it).
For tx_prep(), I think, it is the same though restrictions are a bit more strict:
user should not try to read/write to the mbuf while tx_prep() is not finished with it.
What puzzles me is that why that should be the reason to mark tx_prep() as experimental.
Konstantin
^ permalink raw reply
* Re: [PATCH] Scheduler: add driver for scheduler crypto pmd
From: Declan Doherty @ 2016-12-02 16:22 UTC (permalink / raw)
To: Bruce Richardson, Thomas Monjalon; +Cc: Fan Zhang, dev
In-Reply-To: <20161202145730.GA322432@bricha3-MOBL3.ger.corp.intel.com>
On 02/12/16 14:57, Bruce Richardson wrote:
> On Fri, Dec 02, 2016 at 03:31:24PM +0100, Thomas Monjalon wrote:
>> 2016-12-02 14:15, Fan Zhang:
>>> This patch provides the initial implementation of the scheduler poll mode
>>> driver using DPDK cryptodev framework.
>>>
>>> Scheduler PMD is used to schedule and enqueue the crypto ops to the
>>> hardware and/or software crypto devices attached to it (slaves). The
>>> dequeue operation from the slave(s), and the possible dequeued crypto op
>>> reordering, are then carried out by the scheduler.
>>>
>>> The scheduler PMD can be used to fill the throughput gap between the
>>> physical core and the existing cryptodevs to increase the overall
>>> performance. For example, if a physical core has higher crypto op
>>> processing rate than a cryptodev, the scheduler PMD can be introduced to
>>> attach more than one cryptodevs.
>>>
>>> This initial implementation is limited to supporting the following
>>> scheduling modes:
>>>
>>> - CRYPTO_SCHED_SW_ROUND_ROBIN_MODE (round robin amongst attached software
>>> slave cryptodevs, to set this mode, the scheduler should have been
>>> attached 1 or more software cryptodevs.
>>>
>>> - CRYPTO_SCHED_HW_ROUND_ROBIN_MODE (round robin amongst attached hardware
>>> slave cryptodevs (QAT), to set this mode, the scheduler should have
>>> been attached 1 or more QATs.
>>
>> Could it be implemented on top of the eventdev API?
>>
> Not really. The eventdev API is for different types of scheduling
> between multiple sources that are all polling for packets, compared to
> this, which is more analgous - as I understand it - to the bonding PMD
> for ethdev.
>
> To make something like this work with an eventdev API you would need to
> use one of the following models:
> * have worker cores for offloading packets to the different crypto
> blocks pulling from the eventdev APIs. This would make it difficult to
> do any "smart" scheduling of crypto operations between the blocks,
> e.g. that one crypto instance may be better at certain types of
> operations than another.
> * move the logic in this driver into an existing eventdev instance,
> which uses the eventdev api rather than the crypto APIs and so has an
> extra level of "structure abstraction" that has to be worked though.
> It's just not really a good fit.
>
> So for this workload, I believe the pseudo-cryptodev instance is the
> best way to go.
>
> /Bruce
>
As Bruce says this is much more analogous to the ethdev bonding driver,
the main idea is to allow different crypto op scheduling mechanisms to
be defined transparently to an application. This could be load-balancing
across multiple hw crypto devices, or having a software crypto device to
act as a backup device for a hw accelerator if it becomes
oversubscribed. I think the main advantage of a crypto-scheduler
approach means that the data path of the application doesn't need to
have any knowledge that scheduling is happening at all, it is just using
a different crypto device id, which is then manages the distribution of
crypto work.
^ permalink raw reply
* [PATCH] igb_uio: deprecate iomem and ioport mapping
From: Jianfeng Tan @ 2016-12-02 16:28 UTC (permalink / raw)
To: dev; +Cc: david.marchand, ferruh.yigit, stephen, Jianfeng Tan
In-Reply-To: <1472696197-37614-1-git-send-email-jianfeng.tan@intel.com>
Previously in igb_uio, iomem is mapped, and both ioport and io mem
are recorded into uio framework, which is duplicated and makes the
code too complex.
For iomem, DPDK user space code never opens or reads files under
/sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/maps/. Instead,
/sys/pci/bus/devices/xxxx:xx:xx.x/resourceY are used to map device
memory.
For ioport, non-x86 platforms cannot read from files under
/sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/portio/ directly, because
non-x86 platforms need to map port region for access in user space,
see non-x86 version pci_uio_ioport_map(). x86 platforms can use the
the same way as uio_pci_generic.
This patch deprecates iomem and ioport mapping in igb_uio kernel
module, and adjusts the iomem implementation in both igb_uio and
uio_pci_generic:
- for x86 platform, get ports info from /proc/ioports;
- for non-x86 platform, map and get ports info by pci_uio_ioport_map().
Note: this will affect those applications who are using files under
/sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/maps/ and
/sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/portio/.
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
lib/librte_eal/linuxapp/eal/eal_pci.c | 4 -
lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 56 +-------------
lib/librte_eal/linuxapp/igb_uio/igb_uio.c | 119 ++----------------------------
3 files changed, 9 insertions(+), 170 deletions(-)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 876ba38..2110ad8 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -645,8 +645,6 @@ rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
break;
#endif
case RTE_KDRV_IGB_UIO:
- ret = pci_uio_ioport_map(dev, bar, p);
- break;
case RTE_KDRV_UIO_GENERIC:
#if defined(RTE_ARCH_X86)
ret = pci_ioport_map(dev, bar, p);
@@ -734,8 +732,6 @@ rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
break;
#endif
case RTE_KDRV_IGB_UIO:
- ret = pci_uio_ioport_unmap(p);
- break;
case RTE_KDRV_UIO_GENERIC:
#if defined(RTE_ARCH_X86)
ret = 0;
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 1786b75..28d09ed 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -370,53 +370,7 @@ pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
return -1;
}
-#if defined(RTE_ARCH_X86)
-int
-pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
- struct rte_pci_ioport *p)
-{
- char dirname[PATH_MAX];
- char filename[PATH_MAX];
- int uio_num;
- unsigned long start;
-
- uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
- if (uio_num < 0)
- return -1;
-
- /* get portio start */
- snprintf(filename, sizeof(filename),
- "%s/portio/port%d/start", dirname, bar);
- if (eal_parse_sysfs_value(filename, &start) < 0) {
- RTE_LOG(ERR, EAL, "%s(): cannot parse portio start\n",
- __func__);
- return -1;
- }
- /* ensure we don't get anything funny here, read/write will cast to
- * uin16_t */
- if (start > UINT16_MAX)
- return -1;
-
- /* FIXME only for primary process ? */
- if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
-
- snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
- dev->intr_handle.fd = open(filename, O_RDWR);
- if (dev->intr_handle.fd < 0) {
- RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
- filename, strerror(errno));
- return -1;
- }
- dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
- }
-
- RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
-
- p->base = start;
- p->len = 0;
- return 0;
-}
-#else
+#if !defined(RTE_ARCH_X86)
int
pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
struct rte_pci_ioport *p)
@@ -553,14 +507,10 @@ pci_uio_ioport_write(struct rte_pci_ioport *p,
}
}
+#if !defined(RTE_ARCH_X86)
int
pci_uio_ioport_unmap(struct rte_pci_ioport *p)
{
-#if defined(RTE_ARCH_X86)
- RTE_SET_USED(p);
- /* FIXME close intr fd ? */
- return 0;
-#else
return munmap((void *)(uintptr_t)p->base, p->len);
-#endif
}
+#endif
diff --git a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
index df41e45..e9d78fb 100644
--- a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
+++ b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
@@ -216,107 +216,6 @@ igbuio_dom0_pci_mmap(struct uio_info *info, struct vm_area_struct *vma)
}
#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,
- int n, int pci_bar, const char *name)
-{
- unsigned long addr, len;
- void *internal_addr;
-
- if (n >= ARRAY_SIZE(info->mem))
- return -EINVAL;
-
- addr = pci_resource_start(dev, pci_bar);
- len = pci_resource_len(dev, pci_bar);
- if (addr == 0 || len == 0)
- return -1;
- internal_addr = ioremap(addr, len);
- if (internal_addr == NULL)
- return -1;
- info->mem[n].name = name;
- info->mem[n].addr = addr;
- info->mem[n].internal_addr = internal_addr;
- info->mem[n].size = len;
- info->mem[n].memtype = UIO_MEM_PHYS;
- return 0;
-}
-
-/* Get pci port io resources described by bar #pci_bar in uio resource n. */
-static int
-igbuio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info,
- int n, int pci_bar, const char *name)
-{
- unsigned long addr, len;
-
- if (n >= ARRAY_SIZE(info->port))
- return -EINVAL;
-
- addr = pci_resource_start(dev, pci_bar);
- len = pci_resource_len(dev, pci_bar);
- if (addr == 0 || len == 0)
- return -EINVAL;
-
- info->port[n].name = name;
- info->port[n].start = addr;
- info->port[n].size = len;
- info->port[n].porttype = UIO_PORT_X86;
-
- return 0;
-}
-
-/* Unmap previously ioremap'd resources */
-static void
-igbuio_pci_release_iomem(struct uio_info *info)
-{
- int i;
-
- for (i = 0; i < MAX_UIO_MAPS; i++) {
- if (info->mem[i].internal_addr)
- iounmap(info->mem[i].internal_addr);
- }
-}
-
-static int
-igbuio_setup_bars(struct pci_dev *dev, struct uio_info *info)
-{
- int i, iom, iop, ret;
- unsigned long flags;
- static const char *bar_names[PCI_STD_RESOURCE_END + 1] = {
- "BAR0",
- "BAR1",
- "BAR2",
- "BAR3",
- "BAR4",
- "BAR5",
- };
-
- iom = 0;
- iop = 0;
-
- for (i = 0; i < ARRAY_SIZE(bar_names); i++) {
- if (pci_resource_len(dev, i) != 0 &&
- pci_resource_start(dev, i) != 0) {
- flags = pci_resource_flags(dev, i);
- if (flags & IORESOURCE_MEM) {
- ret = igbuio_pci_setup_iomem(dev, info, iom,
- i, bar_names[i]);
- if (ret != 0)
- return ret;
- iom++;
- } else if (flags & IORESOURCE_IO) {
- ret = igbuio_pci_setup_ioport(dev, info, iop,
- i, bar_names[i]);
- if (ret != 0)
- return ret;
- iop++;
- }
- }
- }
-
- return (iom != 0) ? ret : -ENOENT;
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
static int __devinit
#else
@@ -345,22 +244,17 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* enable bus mastering on the device */
pci_set_master(dev);
- /* remap IO memory */
- err = igbuio_setup_bars(dev, &udev->info);
- if (err != 0)
- goto fail_release_iomem;
-
/* set 64-bit DMA mask */
err = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
if (err != 0) {
dev_err(&dev->dev, "Cannot set DMA mask\n");
- goto fail_release_iomem;
+ goto fail_disable_dev;
}
err = pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64));
if (err != 0) {
dev_err(&dev->dev, "Cannot set consistent DMA mask\n");
- goto fail_release_iomem;
+ goto fail_disable_dev;
}
/* fill uio infos */
@@ -406,12 +300,12 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
dev_err(&dev->dev, "invalid IRQ mode %u",
igbuio_intr_mode_preferred);
err = -EINVAL;
- goto fail_release_iomem;
+ goto fail_disable_dev;
}
err = sysfs_create_group(&dev->dev.kobj, &dev_attr_grp);
if (err != 0)
- goto fail_release_iomem;
+ goto fail_disable_irq;
/* register uio driver */
err = uio_register_device(&dev->dev, &udev->info);
@@ -427,10 +321,10 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
fail_remove_group:
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
-fail_release_iomem:
- igbuio_pci_release_iomem(&udev->info);
+fail_disable_irq:
if (udev->mode == RTE_INTR_MODE_MSIX)
pci_disable_msix(udev->pdev);
+fail_disable_dev:
pci_disable_device(dev);
fail_free:
kfree(udev);
@@ -445,7 +339,6 @@ igbuio_pci_remove(struct pci_dev *dev)
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
uio_unregister_device(&udev->info);
- igbuio_pci_release_iomem(&udev->info);
if (udev->mode == RTE_INTR_MODE_MSIX)
pci_disable_msix(dev);
pci_disable_device(dev);
--
2.7.4
^ permalink raw reply related
* Re: Proposal for a new Committer model
From: Mcnamara, John @ 2016-12-02 16:41 UTC (permalink / raw)
To: Mcnamara, John, Neil Horman; +Cc: dev@dpdk.org
In-Reply-To: <B27915DBBA3421428155699D51E4CFE20266B822@IRSMSX103.ger.corp.intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Mcnamara, John
> Sent: Wednesday, November 30, 2016 9:59 AM
> To: Neil Horman <nhorman@tuxdriver.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] Proposal for a new Committer model
>
> > -----Original Message-----
> > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > Sent: Tuesday, November 29, 2016 7:12 PM
> > To: Mcnamara, John <john.mcnamara@intel.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] Proposal for a new Committer model
> >
> > > ...
> > >
> > > B) Designate alternates to serve as backups for the maintainer when
> > > they are unavailable. This provides high-availablility, and sounds
> > > very much like your proposal, but in the interests of clarity, there
> > > is still a single maintainer at any one time, it just may change to
> > > ensure the continued merging of patches, if the primary maintainer
> > > isn't
> > available.
> > > Ideally however, those backup alternates arent needed, because most
> > > of the primary maintainers work in merging pull requests, which are
> > > done based on the trust of the submaintainer, and done during a very
> > > limited window of time. This also partially addreses multi-vendor
> > > fairness if your subtree maintainers come from multiple
> > > participating
> > companies.
> > >
> > > Regards
> > > Neil
> > >
> > >
> > >
> >
> > Soo, I feel like we're wandering away from this thread. Are you going
> > to make a change to the comitter model?
>
> Hi,
>
> Yes. I think we have consensus on the main parts. I'll re-draft a proposal
> that we can discuss and then add to the contributors guide.
>
> John
>
I'll submit a draft update to the DPDK Code Contributors guide shortly.
John
^ permalink raw reply
* [PATCH v1] doc: add details of sub-trees and maintainers
From: John McNamara @ 2016-12-02 16:44 UTC (permalink / raw)
To: dev; +Cc: John McNamara
Add a new section to the Code Contributors Guide to outline
the roles of tree and component maintainers and how they
can be added and removed.
Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
doc/guides/contributing/patches.rst | 66 ++++++++++++++++++++++++++++++++-----
1 file changed, 58 insertions(+), 8 deletions(-)
diff --git a/doc/guides/contributing/patches.rst b/doc/guides/contributing/patches.rst
index fabddbe..3b5746b 100644
--- a/doc/guides/contributing/patches.rst
+++ b/doc/guides/contributing/patches.rst
@@ -12,7 +12,7 @@ The rationale for many of the DPDK guidelines is explained in greater detail in
The DPDK Development Process
------------------------------
+----------------------------
The DPDK development process has the following features:
@@ -21,13 +21,9 @@ The DPDK development process has the following features:
* There are maintainers for hierarchical components.
* Patches are reviewed publicly on the mailing list.
* Successfully reviewed patches are merged to the repository.
-
-|
-
-* There are main repository ``dpdk`` and sub-repositories ``dpdk-next-*``.
-* A patch should be sent for its target repository. Like net drivers should be on top of dpdk-next-net repository.
-* All sub-repositories are merged into main repository for -rc1 and -rc2 versions of the release.
-* After -rc2 release all patches should target main repository.
+* Patches should be sent to the target repository or sub-tree, see below.
+* All sub-repositories are merged into main repository for ``-rc1`` and ``-rc2`` versions of the release.
+* After the ``-rc2`` release all patches should target the main repository.
The mailing list for DPDK development is `dev@dpdk.org <http://dpdk.org/ml/archives/dev/>`_.
Contributors will need to `register for the mailing list <http://dpdk.org/ml/listinfo/dev>`_ in order to submit patches.
@@ -37,6 +33,60 @@ The development process requires some familiarity with the ``git`` version contr
Refer to the `Pro Git Book <http://www.git-scm.com/book/>`_ for further information.
+Maintainers and Sub-trees
+-------------------------
+
+The DPDK maintenance hierarchy is divided into a main repository ``dpdk`` and sub-repositories ``dpdk-next-*``.
+
+There are maintainers for the trees and for components within the tree.
+
+Trees and maintainers are listed in the ``MAINTAINERS`` file. For example::
+
+ Crypto Drivers
+ --------------
+ M: Some Name <some.name@email.com>
+ T: git://dpdk.org/next/dpdk-next-crypto
+
+ Intel AES-NI GCM PMD
+ M: Another Name <another.name@email.com>
+ F: drivers/crypto/aesni_gcm/
+ F: doc/guides/cryptodevs/aesni_gcm.rst
+
+Where:
+
+* ``M`` is a tree or component maintainer.
+* ``T`` is a repository tree.
+* ``F`` is a maintained file or directory.
+
+Additional details are given in the ``MAINTAINERS`` file.
+
+The role of the component maintainers is to:
+
+* Review patches for the component or delegate the review.
+ This should be done, ideally, within 1-2 weeks of submission to the mailing list.
+* Add an ``acked-by`` to patches, or patchsets, that they agree are ready for committing to a tree.
+
+Component maintainers can be added or removed by submitting a patch to the ``MAINTAINERS`` file.
+Maintainers should have demonstrated a reasonable level of contributions to the component area or to a similar area.
+This should be confirmed by an ``ack`` from an established contributor.
+There can be more than one component maintainer if desired.
+
+The role of the tree maintainers is to:
+
+* Maintain the overall quality of their tree.
+ This can entail additional review, compilation checks or other tests deemed necessary by the maintainer.
+* Commit reviewed patches.
+* Prepare the tree for integration.
+
+Tree maintainers can be added or removed by submitting a patch to the ``MAINTAINERS`` file.
+The proposer should justify the need for a new sub-tree and should have demonstrated a sufficient level of contributions in the area or to a similar area.
+This should be confirmed by 3 ``acks`` from established contributors.
+Disagreements on trees or maintainers can be brought to the Technical Steering Committee.
+
+Tree backup maintainers, when required, can be selected from the active tree maintainers.
+This can be agreed and coordinated by the tree maintainers.
+
+
Getting the Source Code
-----------------------
--
2.7.4
^ permalink raw reply related
* [PATCH] igb_uio: stop device when closing /dev/uioX
From: Jianfeng Tan @ 2016-12-02 16:45 UTC (permalink / raw)
To: dev
Cc: thomas.monjalon, david.marchand, ferruh.yigit, stephen,
jing.d.chen, Jianfeng Tan
In-Reply-To: <1480696111-116651-1-git-send-email-jianfeng.tan@intel.com>
Depends-on: http://dpdk.org/dev/patchwork/patch/17493/
When a DPDK application grab a PCI device, device and driver work
together to Rx/Tx packets. If the DPDK app crashes or gets killed,
there's no chance for DPDK driver to stop the device, which means
rte_eth_dev_stop() will not be called.
This could result in problems. In virtio's case, the device (the
vhost backend), will keep working. If packets come, the vhost will
copy them into the vring, which is negotiated with the previous DPDK
app. But the resources, especially hugepages, are recycled by VM
kernel. What's worse, the memory could be allocated for other usage,
and re-written. This leads to an uncertain situation. Like this post
has reported, https://bugs.launchpad.net/qemu/+bug/1558175, QEMU's
vhost finds out wrong value, and exits the whole QEMU process.
To make it right, we need to restart (or reset) the device and make
the device go into the initial state, when uio-generic or igb_uio
recycles the PCI device. There's a chance in uio framework to disable
devices when /dev/uioX gets closed. Here we enable the pci device
in open() hook and disable it in release() hook.
However, if device is not enabled in probe() phase any more, we can
not register irq in probe() through uio_register_device(). To address
that, we invoke request_irq() to register callback directly.
Similar change needs to be done in uio-generic driver. And vfio-pci
seems to have done that already.
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
lib/librte_eal/linuxapp/igb_uio/igb_uio.c | 171 +++++++++++++++++++-----------
1 file changed, 108 insertions(+), 63 deletions(-)
diff --git a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
index e9d78fb..048390d 100644
--- a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
+++ b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c
@@ -157,8 +157,10 @@ igbuio_pci_irqcontrol(struct uio_info *info, s32 irq_state)
* If yes, disable it here and will be enable later.
*/
static irqreturn_t
-igbuio_pci_irqhandler(int irq, struct uio_info *info)
+igbuio_pci_irqhandler(int irq, void *dev_id)
{
+ struct uio_device *idev = (struct uio_device *)dev_id;
+ struct uio_info *info = idev->info;
struct rte_uio_pci_dev *udev = info->priv;
/* Legacy mode need to mask in hardware */
@@ -166,6 +168,8 @@ igbuio_pci_irqhandler(int irq, struct uio_info *info)
!pci_check_and_mask_intx(udev->pdev))
return IRQ_NONE;
+ uio_event_notify(info);
+
/* Message signal mode, no share IRQ and automasked */
return IRQ_HANDLED;
}
@@ -216,20 +220,58 @@ igbuio_dom0_pci_mmap(struct uio_info *info, struct vm_area_struct *vma)
}
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
-static int __devinit
-#else
static int
-#endif
-igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+igbuio_intr_init(struct uio_info *info)
{
- struct rte_uio_pci_dev *udev;
+ struct rte_uio_pci_dev *udev = info->priv;
+ struct pci_dev *dev = udev->pdev;
struct msix_entry msix_entry;
- int err;
+ int ret = 0;
- udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);
- if (!udev)
- return -ENOMEM;
+ switch (igbuio_intr_mode_preferred) {
+ case RTE_INTR_MODE_MSIX:
+ /* Only 1 msi-x vector needed */
+ msix_entry.entry = 0;
+ if (pci_enable_msix(dev, &msix_entry, 1) == 0) {
+ dev_dbg(&dev->dev, "using MSI-X");
+ info->irq = msix_entry.vector;
+ udev->mode = RTE_INTR_MODE_MSIX;
+ break;
+ }
+ /* fall back to INTX */
+ case RTE_INTR_MODE_LEGACY:
+ if (pci_intx_mask_supported(dev)) {
+ dev_dbg(&dev->dev, "using INTX");
+ info->irq_flags = IRQF_SHARED;
+ info->irq = dev->irq;
+ udev->mode = RTE_INTR_MODE_LEGACY;
+ break;
+ }
+ dev_notice(&dev->dev, "PCI INTX mask not supported\n");
+ ret = -EOPNOTSUPP;
+ /* fall back to no IRQ */
+ default:
+ udev->mode = RTE_INTR_MODE_NONE;
+ info->irq = 0;
+ }
+
+ if (info->irq) {
+ ret = request_irq(info->irq, igbuio_pci_irqhandler,
+ info->irq_flags, info->name,
+ info->uio_dev);
+ if (ret && udev->mode == RTE_INTR_MODE_MSIX)
+ pci_disable_msix(udev->pdev);
+ }
+
+ return ret;
+}
+
+static int
+igbuio_pci_open(struct uio_info *info, struct inode *inode)
+{
+ struct rte_uio_pci_dev *udev = info->priv;
+ struct pci_dev *dev = udev->pdev;
+ int err;
/*
* enable device: ask low-level code to enable I/O and
@@ -238,30 +280,77 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
err = pci_enable_device(dev);
if (err != 0) {
dev_err(&dev->dev, "Cannot enable PCI device\n");
- goto fail_free;
+ return err;
}
/* enable bus mastering on the device */
pci_set_master(dev);
/* set 64-bit DMA mask */
- err = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
- if (err != 0) {
+ err = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
+ if (err) {
dev_err(&dev->dev, "Cannot set DMA mask\n");
- goto fail_disable_dev;
+ goto error;
}
err = pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64));
- if (err != 0) {
+ if (err) {
dev_err(&dev->dev, "Cannot set consistent DMA mask\n");
- goto fail_disable_dev;
+ goto error;
+ }
+
+ err = igbuio_intr_init(info);
+ if (err) {
+ dev_err(&dev->dev, "Enable interrupt fails\n");
+ goto error;
+ } else {
+ dev_info(&dev->dev, "uio device registered with irq %lx\n",
+ udev->info.irq);
+ }
+
+ return 0;
+error:
+ pci_disable_device(dev);
+ return err;
+}
+
+static int
+igbuio_pci_release(struct uio_info *info, struct inode *inode)
+{
+ struct rte_uio_pci_dev *udev = info->priv;
+ struct pci_dev *dev = udev->pdev;
+
+ dev_info(&udev->pdev->dev, "will be disable\n");
+ if (info->irq) {
+ free_irq(info->irq, info->uio_dev);
+ info->irq = 0;
}
+ if (udev->mode == RTE_INTR_MODE_MSIX)
+ pci_disable_msix(dev);
+ pci_disable_device(udev->pdev);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+static int __devinit
+#else
+static int
+#endif
+igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct rte_uio_pci_dev *udev;
+ int err;
+
+ udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);
+ if (!udev)
+ return -ENOMEM;
/* fill uio infos */
udev->info.name = "igb_uio";
udev->info.version = "0.1";
- udev->info.handler = igbuio_pci_irqhandler;
udev->info.irqcontrol = igbuio_pci_irqcontrol;
+ udev->info.release = igbuio_pci_release;
+ udev->info.open = igbuio_pci_open;
#ifdef CONFIG_XEN_DOM0
/* check if the driver run on Xen Dom0 */
if (xen_initial_domain())
@@ -270,42 +359,9 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
udev->info.priv = udev;
udev->pdev = dev;
- switch (igbuio_intr_mode_preferred) {
- case RTE_INTR_MODE_MSIX:
- /* Only 1 msi-x vector needed */
- msix_entry.entry = 0;
- if (pci_enable_msix(dev, &msix_entry, 1) == 0) {
- dev_dbg(&dev->dev, "using MSI-X");
- udev->info.irq = msix_entry.vector;
- udev->mode = RTE_INTR_MODE_MSIX;
- break;
- }
- /* fall back to INTX */
- case RTE_INTR_MODE_LEGACY:
- if (pci_intx_mask_supported(dev)) {
- dev_dbg(&dev->dev, "using INTX");
- udev->info.irq_flags = IRQF_SHARED;
- udev->info.irq = dev->irq;
- udev->mode = RTE_INTR_MODE_LEGACY;
- break;
- }
- dev_notice(&dev->dev, "PCI INTX mask not supported\n");
- /* fall back to no IRQ */
- case RTE_INTR_MODE_NONE:
- udev->mode = RTE_INTR_MODE_NONE;
- udev->info.irq = 0;
- break;
-
- default:
- dev_err(&dev->dev, "invalid IRQ mode %u",
- igbuio_intr_mode_preferred);
- err = -EINVAL;
- goto fail_disable_dev;
- }
-
err = sysfs_create_group(&dev->dev.kobj, &dev_attr_grp);
if (err != 0)
- goto fail_disable_irq;
+ goto fail_free;
/* register uio driver */
err = uio_register_device(&dev->dev, &udev->info);
@@ -314,18 +370,10 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, udev);
- dev_info(&dev->dev, "uio device registered with irq %lx\n",
- udev->info.irq);
-
return 0;
fail_remove_group:
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
-fail_disable_irq:
- if (udev->mode == RTE_INTR_MODE_MSIX)
- pci_disable_msix(udev->pdev);
-fail_disable_dev:
- pci_disable_device(dev);
fail_free:
kfree(udev);
@@ -339,9 +387,6 @@ igbuio_pci_remove(struct pci_dev *dev)
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
uio_unregister_device(&udev->info);
- if (udev->mode == RTE_INTR_MODE_MSIX)
- pci_disable_msix(dev);
- pci_disable_device(dev);
pci_set_drvdata(dev, NULL);
kfree(udev);
}
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 00/22] Generic flow API (rte_flow)
From: Ferruh Yigit @ 2016-12-02 16:58 UTC (permalink / raw)
To: Adrien Mazarguil, dev; +Cc: Thomas Monjalon, Pablo de Lara, Olivier Matz
In-Reply-To: <cover.1479309719.git.adrien.mazarguil@6wind.com>
Hi Adrien,
On 11/16/2016 4:23 PM, Adrien Mazarguil wrote:
> As previously discussed in RFC v1 [1], RFC v2 [2], with changes
> described in [3] (also pasted below), here is the first non-draft series
> for this new API.
>
> Its capabilities are so generic that its name had to be vague, it may be
> called "Generic flow API", "Generic flow interface" (possibly shortened
> as "GFI") to refer to the name of the new filter type, or "rte_flow" from
> the prefix used for its public symbols. I personally favor the latter.
>
> While it is currently meant to supersede existing filter types in order for
> all PMDs to expose a common filtering/classification interface, it may
> eventually evolve to cover the following ideas as well:
>
> - Rx/Tx offloads configuration through automatic offloads for specific
> packets, e.g. performing checksum on TCP packets could be expressed with
> an egress rule with a TCP pattern and a kind of checksum action.
>
> - RSS configuration (already defined actually). Could be global or per rule
> depending on hardware capabilities.
>
> - Switching configuration for devices with many physical ports; rules doing
> both ingress and egress could even be used to completely bypass software
> if supported by hardware.
>
> [1] http://dpdk.org/ml/archives/dev/2016-July/043365.html
> [2] http://dpdk.org/ml/archives/dev/2016-August/045383.html
> [3] http://dpdk.org/ml/archives/dev/2016-November/050044.html
>
> Changes since RFC v2:
>
> - New separate VLAN pattern item (previously part of the ETH definition),
> found to be much more convenient.
>
> - Removed useless "any" field from VF pattern item, the same effect can be
> achieved by not providing a specification structure.
>
> - Replaced bit-fields from the VXLAN pattern item to avoid endianness
> conversion issues on 24-bit fields.
>
> - Updated struct rte_flow_item with a new "last" field to create inclusive
> ranges. They are defined as the interval between (spec & mask) and
> (last & mask). All three parameters are optional.
>
> - Renamed ID action MARK.
>
> - Renamed "queue" fields in actions QUEUE and DUP to "index".
>
> - "rss_conf" field in RSS action is now const.
>
> - VF action now uses a 32 bit ID like its pattern item counterpart.
>
> - Removed redundant struct rte_flow_pattern, API functions now expect
> struct
> rte_flow_item lists terminated by END items.
>
> - Replaced struct rte_flow_actions for the same reason, with struct
> rte_flow_action lists terminated by END actions.
>
> - Error types (enum rte_flow_error_type) have been updated and the cause
> pointer in struct rte_flow_error is now const.
>
> - Function prototypes (rte_flow_create, rte_flow_validate) have also been
> updated for clarity.
>
> Additions:
>
> - Public wrapper functions rte_flow_{validate|create|destroy|flush|query}
> are now implemented in rte_flow.c, with their symbols exported and
> versioned. Related filter type RTE_ETH_FILTER_GENERIC has been added.
>
> - A separate header (rte_flow_driver.h) has been added for driver-side
> functionality, in particular struct rte_flow_ops which contains PMD
> callbacks returned by RTE_ETH_FILTER_GENERIC query.
>
> - testpmd now exposes most of this API through the new "flow" command.
>
> What remains to be done:
>
> - Using endian-aware integer types (rte_beX_t) where necessary for clarity.
>
> - API documentation (based on RFC).
>
> - testpmd flow command documentation (although context-aware command
> completion should already help quite a bit in this regard).
>
> - A few pattern item / action properties cannot be configured yet
> (e.g. rss_conf parameter for RSS action) and a few completions
> (e.g. possible queue IDs) should be added.
>
<...>
I was trying to check driver filter API patches, but hit a few compiler
errors with this patchset.
[1] clang complains about variable bitfield value changed from -1 to 1.
Which is correct, but I guess that is intentional, but I don't know how
to tell this to clang?
[2] shred library compilation error, because of missing rte_flow_flush
in rte_ether_version.map file
[3] bunch of icc compilation errors, almost all are same type:
error #188: enumerated type mixed with another type
Thanks,
ferruh
[1]
=============================
.../app/test-pmd/cmdline_flow.c:944:16: error: implicit truncation from
'int' to bitfield changes value from -1 to 1
[-Werror,-Wbitfield-constant-conversion]
.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
relative)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:282:42: note: expanded from macro
'ARGS_ENTRY_BF'
.mask = (const void *)&(const s){ .f = -1 }, \
^~
.../app/test-pmd/cmdline_flow.c:269:49: note: expanded from macro 'ARGS'
#define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
^~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:950:16: error: implicit truncation from
'int' to bitfield changes value from -1 to 1
[-Werror,-Wbitfield-constant-conversion]
.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
search)),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:282:42: note: expanded from macro
'ARGS_ENTRY_BF'
.mask = (const void *)&(const s){ .f = -1 }, \
^~
.../app/test-pmd/cmdline_flow.c:269:49: note: expanded from macro 'ARGS'
#define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
^~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:1293:16: error: implicit truncation from
'int' to bitfield changes value from -1 to 1
[-Werror,-Wbitfield-constant-conversion]
.args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:282:42: note: expanded from macro
'ARGS_ENTRY_BF'
.mask = (const void *)&(const s){ .f = -1 }, \
^~
.../app/test-pmd/cmdline_flow.c:269:49: note: expanded from macro 'ARGS'
#define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
^~~~~~~~~~~
.../app/test-pmd/cmdline_flow.c:1664:26: error: duplicate 'const'
declaration specifier [-Werror,-Wduplicate-decl-specifier]
static const enum index const next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
^
4 errors generated.
[2]
=============================
LD testpmd
config.o: In function `port_flow_flush':
config.c:(.text+0x2231): undefined reference to `rte_flow_flush'
collect2: error: ld returned 1 exit status
[3]
=============================
.../app/test-pmd/cmdline_flow.c(364): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(370): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(376): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(385): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(406): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(413): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(419): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(425): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(435): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(443): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(450): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(457): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(464): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(471): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(478): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(485): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(492): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(498): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(514): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(520): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(526): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(532): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(538): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(545): error #188: enumerated type mixed
with another type
0,
^
.../app/test-pmd/cmdline_flow.c(619): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(FLOW)),
^
.../app/test-pmd/cmdline_flow.c(716): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY
^
.../app/test-pmd/cmdline_flow.c(729): error #188: enumerated type mixed
with another type
.next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(736): error #188: enumerated type mixed
with another type
.next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(743): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(743): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(750): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(757): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(QUERY_ACTION),
^
.../app/test-pmd/cmdline_flow.c(757): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(QUERY_ACTION),
^
.../app/test-pmd/cmdline_flow.c(757): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(QUERY_ACTION),
^
.../app/test-pmd/cmdline_flow.c(768): error #188: enumerated type mixed
with another type
.next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
^
.../app/test-pmd/cmdline_flow.c(776): error #188: enumerated type mixed
with another type
.next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
^
.../app/test-pmd/cmdline_flow.c(792): error #188: enumerated type mixed
with another type
.next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
^
.../app/test-pmd/cmdline_flow.c(800): error #188: enumerated type mixed
with another type
.next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
^
.../app/test-pmd/cmdline_flow.c(807): error #188: enumerated type mixed
with another type
.next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
^
.../app/test-pmd/cmdline_flow.c(864): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTIONS)),
^
.../app/test-pmd/cmdline_flow.c(871): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(878): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(891): error #188: enumerated type mixed
with another type
.next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(897): error #188: enumerated type mixed
with another type
.next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(904): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(917): error #188: enumerated type mixed
with another type
.next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(930): error #188: enumerated type mixed
with another type
.next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(943): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
^
.../app/test-pmd/cmdline_flow.c(949): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
^
.../app/test-pmd/cmdline_flow.c(955): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
^
.../app/test-pmd/cmdline_flow.c(961): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(967): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw,
^
.../app/test-pmd/cmdline_flow.c(967): error #188: enumerated type mixed
with another type
.next = NEXT(item_raw,
^
.../app/test-pmd/cmdline_flow.c(987): error #188: enumerated type mixed
with another type
.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(993): error #188: enumerated type mixed
with another type
.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(999): error #188: enumerated type mixed
with another type
.next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1012): error #188: enumerated type mixed
with another type
.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1018): error #188: enumerated type mixed
with another type
.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1031): error #188: enumerated type mixed
with another type
.next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(1038): error #188: enumerated type mixed
with another type
.next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(1052): error #188: enumerated type mixed
with another type
.next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(1059): error #188: enumerated type mixed
with another type
.next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
^
.../app/test-pmd/cmdline_flow.c(1073): error #188: enumerated type mixed
with another type
.next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1080): error #188: enumerated type mixed
with another type
.next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1094): error #188: enumerated type mixed
with another type
.next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1101): error #188: enumerated type mixed
with another type
.next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1115): error #188: enumerated type mixed
with another type
.next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1122): error #188: enumerated type mixed
with another type
.next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1136): error #188: enumerated type mixed
with another type
.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1143): error #188: enumerated type mixed
with another type
.next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1157): error #188: enumerated type mixed
with another type
.next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
^
.../app/test-pmd/cmdline_flow.c(1182): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1189): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1202): error #188: enumerated type mixed
with another type
.next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
^
.../app/test-pmd/cmdline_flow.c(1210): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1224): error #188: enumerated type mixed
with another type
.next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
^
.../app/test-pmd/cmdline_flow.c(1232): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1239): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1252): error #188: enumerated type mixed
with another type
.next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)),
^
.../app/test-pmd/cmdline_flow.c(1266): error #188: enumerated type mixed
with another type
.next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
^
.../app/test-pmd/cmdline_flow.c(1279): error #188: enumerated type mixed
with another type
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
^
.../app/test-pmd/cmdline_flow.c(1292): error #188: enumerated type mixed
with another type
.next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
^
.../app/test-pmd/cmdline_flow.c(1300): error #188: enumerated type mixed
with another type
.next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
^
.../app/test-pmd/cmdline_flow.c(1599): error #188: enumerated type mixed
with another type
ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
^
.../app/test-pmd/cmdline_flow.c(1664): error #83: type qualifier
specified more than once
static const enum index const next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
^
.../app/test-pmd/cmdline_flow.c(1664): error #188: enumerated type mixed
with another type
static const enum index const next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
^
.../app/test-pmd/cmdline_flow.c(2302): error #188: enumerated type mixed
with another type
ctx->curr = 0;
^
.../app/test-pmd/cmdline_flow.c(2303): error #188: enumerated type mixed
with another type
ctx->prev = 0;
^
^ permalink raw reply
* [PATCH 0/4] Chained Mbufs support in SW PMDs
From: Tomasz Kulasek @ 2016-12-02 17:07 UTC (permalink / raw)
To: dev
This patch set adds support of scattered-gather list for SW PMDs.
As of now, application needs to reserve continuous block of memory for
mbufs which is not always the case. Hence needed to support chaining of
mbufs which are smaller in size but can be used if chained.
Above work involves:
a) Create mbuf functions to coalesce mbuf chains into a single mbuf.
b) For each software poll mode driver code to detect chained mbufs
support and coalesce these before preforming crypto.
c) Add relevant unit tests to test the functionality.
Tomasz Kulasek (4):
rte_mbuf: add rte_pktmbuf_coalesce
test: add rte_pktmbuf_coalesce unit tests
crypto: add sgl support for sw PMDs
test: add sgl unit tests for crypto devices
app/test/test_cryptodev.c | 456 ++++++++++++++++++++++++++++
app/test/test_cryptodev.h | 111 +++++++
app/test/test_cryptodev_aes_test_vectors.h | 32 +-
app/test/test_cryptodev_blockcipher.c | 170 +++++++----
app/test/test_cryptodev_blockcipher.h | 1 +
app/test/test_mbuf.c | 134 ++++++++
drivers/crypto/aesni_gcm/aesni_gcm_pmd.c | 14 +
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 19 +-
drivers/crypto/kasumi/rte_kasumi_pmd.c | 13 +
drivers/crypto/null/null_crypto_pmd.c | 3 +-
drivers/crypto/openssl/rte_openssl_pmd.c | 11 +
drivers/crypto/snow3g/rte_snow3g_pmd.c | 15 +
drivers/crypto/zuc/rte_zuc_pmd.c | 13 +
lib/librte_cryptodev/rte_cryptodev.c | 4 +-
lib/librte_cryptodev/rte_cryptodev.h | 3 +-
lib/librte_mbuf/rte_mbuf.h | 34 +++
16 files changed, 966 insertions(+), 67 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/4] rte_mbuf: add rte_pktmbuf_coalesce
From: Tomasz Kulasek @ 2016-12-02 17:07 UTC (permalink / raw)
To: dev
In-Reply-To: <1480698466-17620-1-git-send-email-tomaszx.kulasek@intel.com>
This patch adds function rte_pktmbuf_coalesce to let crypto PMD coalesce
chained mbuf before crypto operation and extend their capabilities to
support segmented mbufs when device cannot handle them natively.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
lib/librte_mbuf/rte_mbuf.h | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index ead7c6e..f048681 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -1647,6 +1647,40 @@ static inline int rte_pktmbuf_chain(struct rte_mbuf *head, struct rte_mbuf *tail
}
/**
+ * Coalesce data from mbuf to the continuous buffer.
+ *
+ * @param mbuf_dst
+ * Contiguous destination mbuf
+ * @param mbuf_src
+ * Uncontiguous source mbuf
+ *
+ * @return
+ * - 0, on success
+ * - -EINVAL, on error
+ */
+
+#include <rte_hexdump.h>
+
+static inline int
+rte_pktmbuf_coalesce(struct rte_mbuf *mbuf_dst, struct rte_mbuf *mbuf_src)
+{
+ char *dst;
+
+ if (!rte_pktmbuf_is_contiguous(mbuf_dst) ||
+ rte_pktmbuf_data_len(mbuf_dst) >=
+ rte_pktmbuf_pkt_len(mbuf_src))
+ return -EINVAL;
+
+ dst = rte_pktmbuf_mtod(mbuf_dst, char *);
+
+ if (!__rte_pktmbuf_read(mbuf_src, 0, rte_pktmbuf_pkt_len(mbuf_src),
+ dst))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* Dump an mbuf structure to a file.
*
* Dump all fields for the given packet mbuf and all its associated
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/4] test: add rte_pktmbuf_coalesce unit tests
From: Tomasz Kulasek @ 2016-12-02 17:07 UTC (permalink / raw)
To: dev
In-Reply-To: <1480698466-17620-1-git-send-email-tomaszx.kulasek@intel.com>
This patch tests rte_pktmbuf_coalesce functionality:
1) Creates banch of segmented mbufs with different size and number of
segments.
2) Generates pkt_len bytes of random data.
3) Fills noncontigouos mbuf with randomly generated data.
4) Uses rte_pktmbuf_coalesce to coalesce segmented buffer into one
contiguous.
5) Verifies data in destination buffer.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/test_mbuf.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 134 insertions(+)
diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index c0823ea..e3c7657 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -930,6 +930,135 @@
return 0;
}
+static int
+test_mbuf_coalesce(int pkt_len, int nb_segs) {
+
+ struct rte_mbuf *m = NULL, *mbuf_src = NULL, *mbuf_dst = NULL;
+ uint8_t data[pkt_len], *src, *dst;
+ int data_len = 0;
+ int i, size;
+ int t_len;
+
+ if (pkt_len < 1) {
+ printf("Packet size must be 1 or more (is %d)\n", pkt_len);
+ return -1;
+ }
+
+ if (nb_segs < 1) {
+ printf("Number of segments must be 1 or more (is %d)\n",
+ nb_segs);
+ return -1;
+ }
+
+ /* Setup buffer */
+ for (i = 0; i < pkt_len; i++)
+ data[i] = (uint8_t) rte_rand();
+
+ t_len = pkt_len >= nb_segs ? pkt_len / nb_segs : 1;
+ src = data;
+ size = pkt_len;
+
+ /* Create chained mbuf_src and fill it generated data */
+ for (i = 0; size > 0; i++) {
+
+ m = rte_pktmbuf_alloc(pktmbuf_pool);
+ if (i == 0)
+ mbuf_src = m;
+
+ if (!m) {
+ printf("Cannot create segment for source mbuf");
+ goto fail;
+ }
+
+ /* Make sure if tailroom is zeroed */
+ memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
+ rte_pktmbuf_tailroom(m));
+
+ data_len = size > t_len ? t_len : size;
+ dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
+ if (!dst) {
+ printf("Cannot append %d bytes to the mbuf\n",
+ data_len);
+ goto fail;
+ }
+
+ rte_memcpy(dst, src, data_len);
+ src += data_len;
+
+ if (mbuf_src != m)
+ rte_pktmbuf_chain(mbuf_src, m);
+
+ size -= data_len;
+
+ }
+
+ /* Create destination buffer to store coalesced data */
+ mbuf_dst = rte_pktmbuf_alloc(pktmbuf_pool);
+ if (!mbuf_dst) {
+ printf("Cannot create destination buffer\n");
+ goto fail;
+ }
+
+ dst = (uint8_t *)rte_pktmbuf_append(m, rte_pktmbuf_pkt_len(mbuf_dst));
+
+ if (rte_pktmbuf_coalesce(mbuf_dst, mbuf_src)) {
+ printf("Mbuf coalesce failed\n");
+ goto fail;
+ }
+
+ if (!rte_pktmbuf_is_contiguous(mbuf_dst)) {
+ printf("Destination buffer should be contiguous\n");
+ goto fail;
+ }
+
+ dst = rte_pktmbuf_mtod(mbuf_dst, uint8_t *);
+
+ if (memcmp(dst, data, rte_pktmbuf_pkt_len(mbuf_src))) {
+ printf("Incorrect data in coalesced mbuf\n");
+ goto fail;
+ }
+
+ if (mbuf_src)
+ rte_pktmbuf_free(mbuf_src);
+ if (mbuf_dst)
+ rte_pktmbuf_free(mbuf_dst);
+ return 0;
+
+fail:
+ if (mbuf_src)
+ rte_pktmbuf_free(mbuf_src);
+ if (mbuf_dst)
+ rte_pktmbuf_free(mbuf_dst);
+ return -1;
+}
+
+static int
+test_mbuf_coalesce_check(void)
+{
+ struct test_mbuf_array {
+ int size;
+ int nb_segs;
+ } mbuf_array[5] = {
+ { 128, 2 },
+ { 64, 64 },
+ { 512, 10 },
+ { 250, 11 },
+ { 123, 8 },
+ };
+ unsigned i;
+
+ printf("Test mbuf coalesce API\n");
+
+ for (i = 0; i < RTE_DIM(mbuf_array); i++)
+ if (test_mbuf_coalesce(mbuf_array[i].size,
+ mbuf_array[i].nb_segs)) {
+ printf("Test failed for %d, %d\n", mbuf_array[i].size,
+ mbuf_array[i].nb_segs);
+ return -1;
+ }
+
+ return 0;
+}
static int
test_mbuf(void)
@@ -1023,6 +1152,11 @@
printf("test_failing_mbuf_sanity_check() failed\n");
return -1;
}
+
+ if (test_mbuf_coalesce_check() < 0) {
+ printf("test_mbuf_coalesce_check() failed\n");
+ return -1;
+ }
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/4] crypto: add sgl support for sw PMDs
From: Tomasz Kulasek @ 2016-12-02 17:07 UTC (permalink / raw)
To: dev
In-Reply-To: <1480698466-17620-1-git-send-email-tomaszx.kulasek@intel.com>
This patch introduces RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER feature flag
informing that selected crypto device supports segmented mbufs natively
and doesn't need to be coalesced before crypto operation.
While using segmented buffers in crypto devices may have unpredictable
results, for PMDs which doesn't support it natively, additional check is
made for debug compilation.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
drivers/crypto/aesni_gcm/aesni_gcm_pmd.c | 14 ++++++++++++++
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 19 ++++++++++++++++---
drivers/crypto/kasumi/rte_kasumi_pmd.c | 13 +++++++++++++
drivers/crypto/null/null_crypto_pmd.c | 3 ++-
drivers/crypto/openssl/rte_openssl_pmd.c | 11 +++++++++++
drivers/crypto/snow3g/rte_snow3g_pmd.c | 15 +++++++++++++++
drivers/crypto/zuc/rte_zuc_pmd.c | 13 +++++++++++++
lib/librte_cryptodev/rte_cryptodev.c | 4 ++--
lib/librte_cryptodev/rte_cryptodev.h | 3 ++-
9 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index dba5e15..1a6120c 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -375,6 +375,20 @@
break;
}
+#ifdef RTE_LIBRTE_PMD_AESNI_GCM_DEBUG
+ if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+ (ops[i]->sym->m_dst != NULL &&
+ !rte_pktmbuf_is_contiguous(
+ ops[i]->sym->m_dst))) {
+ ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+ GCM_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", ops[i]);
+ qp->qp_stats.enqueue_err_count++;
+ break;
+ }
+#endif
+
retval = process_gcm_crypto_op(qp, ops[i]->sym, sess);
if (retval < 0) {
ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index f07cd07..b5e115e 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -529,15 +529,28 @@
int i, processed_jobs = 0;
for (i = 0; i < nb_ops; i++) {
-#ifdef RTE_LIBRTE_AESNI_MB_DEBUG
- if (unlikely(op->type != RTE_CRYPTO_OP_TYPE_SYMMETRIC)) {
+#ifdef RTE_LIBRTE_PMD_AESNI_MB_DEBUG
+ if (unlikely(ops[i]->type != RTE_CRYPTO_OP_TYPE_SYMMETRIC)) {
MB_LOG_ERR("PMD only supports symmetric crypto "
"operation requests, op (%p) is not a "
- "symmetric operation.", op);
+ "symmetric operation.", ops[i]);
+ qp->stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+ (ops[i]->sym->m_dst != NULL &&
+ !rte_pktmbuf_is_contiguous(
+ ops[i]->sym->m_dst))) {
+ MB_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", ops[i]);
+ ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
qp->stats.enqueue_err_count++;
goto flush_jobs;
}
#endif
+
sess = get_session(qp, ops[i]);
if (unlikely(sess == NULL)) {
qp->stats.enqueue_err_count++;
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index b119da2..4bdd7bb 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -455,6 +455,19 @@
for (i = 0; i < nb_ops; i++) {
curr_c_op = ops[i];
+#ifdef RTE_LIBRTE_PMD_KASUMI_DEBUG
+ if (!rte_pktmbuf_is_contiguous(curr_c_op->sym->m_src) ||
+ (curr_c_op->sym->m_dst != NULL &&
+ !rte_pktmbuf_is_contiguous(
+ curr_c_op->sym->m_dst))) {
+ KASUMI_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", curr_c_op);
+ curr_c_op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+ break;
+ }
+#endif
+
/* Set status as enqueued (not processed yet) by default. */
curr_c_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index c69606b..c37d3d6 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -216,7 +216,8 @@
dev->enqueue_burst = null_crypto_pmd_enqueue_burst;
dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
- RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING;
+ RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+ RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER;
internals = dev->data->dev_private;
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 5f8fa33..b57588e 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -868,6 +868,17 @@
msrc = op->sym->m_src;
mdst = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+#ifdef RTE_LIBRTE_PMD_OPENSSL_DEBUG
+ if (!rte_pktmbuf_is_contiguous(msrc) ||
+ !rte_pktmbuf_is_contiguous(mdst)) {
+ OPENSSL_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", op);
+ op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+ return -1;
+ }
+#endif
+
op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
switch (sess->chain_order) {
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index 3b4292a..9a6f16d 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -330,6 +330,21 @@
unsigned i;
unsigned enqueued_ops, processed_ops;
+#ifdef RTE_LIBRTE_PMD_SNOW3G_DEBUG
+ for (i = 0; i < num_ops; i++) {
+ if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+ (ops[i]->sym->m_dst != NULL &&
+ !rte_pktmbuf_is_contiguous(
+ ops[i]->sym->m_dst))) {
+ SNOW3G_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", ops[i]);
+ ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+ return 0;
+ }
+ }
+#endif
+
switch (session->op) {
case SNOW3G_OP_ONLY_CIPHER:
processed_ops = process_snow3g_cipher_op(ops,
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index 3849119..bf53f76 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -211,6 +211,19 @@
break;
}
+#ifdef RTE_LIBRTE_PMD_ZUC_DEBUG
+ if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+ (ops[i]->sym->m_dst != NULL &&
+ !rte_pktmbuf_is_contiguous(
+ ops[i]->sym->m_dst))) {
+ ZUC_LOG_ERR("PMD supports only contiguous mbufs, "
+ "op (%p) provides noncontiguous mbuf as "
+ "source/destination buffer.\n", ops[i]);
+ ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+ break;
+ }
+#endif
+
src[i] = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
(ops[i]->sym->cipher.data.offset >> 3);
dst[i] = ops[i]->sym->m_dst ?
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 127e8d0..ebbb822 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -211,13 +211,13 @@ struct rte_cryptodev_callback {
return "CPU_AESNI";
case RTE_CRYPTODEV_FF_HW_ACCELERATED:
return "HW_ACCELERATED";
-
+ case RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER:
+ return "MBUF_SCATTER_GATHER";
default:
return NULL;
}
}
-
int
rte_cryptodev_create_vdev(const char *name, const char *args)
{
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 8f63e8f..70ff7fc 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -225,7 +225,8 @@ struct rte_cryptodev_capabilities {
/**< Utilises CPU AES-NI instructions */
#define RTE_CRYPTODEV_FF_HW_ACCELERATED (1ULL << 7)
/**< Operations are off-loaded to an external hardware accelerator */
-
+#define RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER (1ULL << 8)
+/**< Scatter-gather mbufs are supported */
/**
* Get the name of a crypto device feature flag
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/4] test: add sgl unit tests for crypto devices
From: Tomasz Kulasek @ 2016-12-02 17:07 UTC (permalink / raw)
To: dev; +Cc: Daniel Mrzyglod
In-Reply-To: <1480698466-17620-1-git-send-email-tomaszx.kulasek@intel.com>
This patch provides unit tests for set of cipher/hash combinations covering
currently implemented crypto PMD's and allowing to verify scatter gather
support.
Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/test_cryptodev.c | 456 ++++++++++++++++++++++++++++
app/test/test_cryptodev.h | 111 +++++++
app/test/test_cryptodev_aes_test_vectors.h | 32 +-
app/test/test_cryptodev_blockcipher.c | 170 +++++++----
app/test/test_cryptodev_blockcipher.h | 1 +
5 files changed, 710 insertions(+), 60 deletions(-)
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index 872f8b4..613dae9 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -1688,6 +1688,10 @@ struct crypto_unittest_params {
TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv");
+ /* For OOP operation both buffers must have the same size */
+ if (ut_params->obuf)
+ rte_pktmbuf_prepend(ut_params->obuf, iv_pad_len);
+
memset(sym_op->cipher.iv.data, 0, iv_pad_len);
sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf);
sym_op->cipher.iv.length = iv_pad_len;
@@ -2509,6 +2513,84 @@ struct crypto_unittest_params {
}
static int
+test_kasumi_encryption_sgl(const struct kasumi_test_data *tdata)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+
+ int retval;
+
+ unsigned plaintext_pad_len;
+ unsigned plaintext_len;
+
+ uint8_t buffer[10000];
+ const uint8_t *ciphertext;
+
+ struct rte_cryptodev_info dev_info;
+
+ rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+ if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+
+ /* Create KASUMI session */
+ retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ RTE_CRYPTO_CIPHER_KASUMI_F8,
+ tdata->key.data, tdata->key.len);
+ if (retval < 0)
+ return retval;
+
+ plaintext_len = ceil_byte_length(tdata->plaintext.len);
+
+
+ /* Append data which is padded to a multiple */
+ /* of the algorithms block size */
+ plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+ ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 10);
+
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+ /* Create KASUMI operation */
+ retval = create_wireless_algo_cipher_operation(tdata->iv.data,
+ tdata->iv.len,
+ tdata->plaintext.len,
+ tdata->validCipherOffsetLenInBits.len,
+ RTE_CRYPTO_CIPHER_KASUMI_F8);
+ if (retval < 0)
+ return retval;
+
+ ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+ ut_params->op);
+ TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+ ut_params->obuf = ut_params->op->sym->m_dst;
+
+ if (ut_params->obuf)
+ ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+ plaintext_len, buffer);
+ else
+ ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+ plaintext_len, buffer);
+
+ /* Validate obuf */
+ TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+ /* Validate obuf */
+ TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+ ciphertext,
+ tdata->ciphertext.data,
+ tdata->validCipherLenInBits.len,
+ "KASUMI Ciphertext data not as expected");
+ return 0;
+}
+
+
+static int
test_kasumi_encryption_oop(const struct kasumi_test_data *tdata)
{
struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -2577,6 +2659,81 @@ struct crypto_unittest_params {
}
static int
+test_kasumi_encryption_oop_sgl(const struct kasumi_test_data *tdata)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+
+ int retval;
+ unsigned plaintext_pad_len;
+ unsigned plaintext_len;
+
+ const uint8_t *ciphertext;
+ uint8_t buffer[2048];
+
+ struct rte_cryptodev_info dev_info;
+
+ rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+ if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+
+ /* Create KASUMI session */
+ retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ RTE_CRYPTO_CIPHER_KASUMI_F8,
+ tdata->key.data, tdata->key.len);
+ if (retval < 0)
+ return retval;
+
+ plaintext_len = ceil_byte_length(tdata->plaintext.len);
+ /* Append data which is padded to a multiple */
+ /* of the algorithms block size */
+ plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+ ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 10);
+ ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 3);
+
+ /* Append data which is padded to a multiple */
+ /* of the algorithms block size */
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+ /* Create KASUMI operation */
+ retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data,
+ tdata->iv.len,
+ tdata->plaintext.len,
+ tdata->validCipherOffsetLenInBits.len,
+ RTE_CRYPTO_CIPHER_KASUMI_F8);
+ if (retval < 0)
+ return retval;
+
+ ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+ ut_params->op);
+ TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+ ut_params->obuf = ut_params->op->sym->m_dst;
+ if (ut_params->obuf)
+ ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+ plaintext_pad_len, buffer);
+ else
+ ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+ plaintext_pad_len, buffer);
+
+ /* Validate obuf */
+ TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+ ciphertext,
+ tdata->ciphertext.data,
+ tdata->validCipherLenInBits.len,
+ "KASUMI Ciphertext data not as expected");
+ return 0;
+}
+
+
+static int
test_kasumi_decryption_oop(const struct kasumi_test_data *tdata)
{
struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -2849,6 +3006,85 @@ struct crypto_unittest_params {
return 0;
}
+static int
+test_snow3g_encryption_oop_sgl(const struct snow3g_test_data *tdata)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+
+ int retval;
+ unsigned plaintext_pad_len;
+ unsigned plaintext_len;
+ uint8_t buffer[10000];
+ const uint8_t *ciphertext;
+
+ struct rte_cryptodev_info dev_info;
+
+ rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+ if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+
+ /* Create SNOW 3G session */
+ retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+ tdata->key.data, tdata->key.len);
+ if (retval < 0)
+ return retval;
+
+ plaintext_len = ceil_byte_length(tdata->plaintext.len);
+ /* Append data which is padded to a multiple of */
+ /* the algorithms block size */
+ plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16);
+
+ ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 10);
+ ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 3);
+
+ TEST_ASSERT_NOT_NULL(ut_params->ibuf,
+ "Failed to allocate input buffer in mempool");
+ TEST_ASSERT_NOT_NULL(ut_params->obuf,
+ "Failed to allocate output buffer in mempool");
+
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+ /* Create SNOW 3G operation */
+ retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data,
+ tdata->iv.len,
+ tdata->validCipherLenInBits.len,
+ tdata->validCipherOffsetLenInBits.len,
+ RTE_CRYPTO_CIPHER_SNOW3G_UEA2);
+ if (retval < 0)
+ return retval;
+
+ ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+ ut_params->op);
+ TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+ ut_params->obuf = ut_params->op->sym->m_dst;
+ if (ut_params->obuf)
+ ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+ plaintext_len, buffer);
+ else
+ ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+ plaintext_len, buffer);
+
+ TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+ /* Validate obuf */
+ TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+ ciphertext,
+ tdata->ciphertext.data,
+ tdata->validDataLenInBits.len,
+ "SNOW 3G Ciphertext data not as expected");
+
+ return 0;
+}
+
/* Shift right a buffer by "offset" bits, "offset" < 8 */
static void
buffer_shift_right(uint8_t *buffer, uint32_t length, uint8_t offset)
@@ -3504,6 +3740,84 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_zuc_encryption_sgl(const struct zuc_test_data *tdata)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+
+ int retval;
+
+ unsigned plaintext_pad_len;
+ unsigned plaintext_len;
+ const uint8_t *ciphertext;
+ uint8_t ciphertext_buffer[2048];
+ struct rte_cryptodev_info dev_info;
+
+ rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+ if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+
+ plaintext_len = ceil_byte_length(tdata->plaintext.len);
+
+ /* Append data which is padded to a multiple */
+ /* of the algorithms block size */
+ plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+ ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 10);
+
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len,
+ tdata->plaintext.data);
+
+ /* Create ZUC session */
+ retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ RTE_CRYPTO_CIPHER_ZUC_EEA3,
+ tdata->key.data, tdata->key.len);
+ if (retval < 0)
+ return retval;
+
+ /* Clear mbuf payload */
+
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+ /* Create ZUC operation */
+ retval = create_wireless_algo_cipher_operation(tdata->iv.data,
+ tdata->iv.len, tdata->plaintext.len,
+ tdata->validCipherOffsetLenInBits.len,
+ RTE_CRYPTO_CIPHER_ZUC_EEA3);
+ if (retval < 0)
+ return retval;
+
+ ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+ ut_params->op);
+ TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+ ut_params->obuf = ut_params->op->sym->m_dst;
+ if (ut_params->obuf)
+ ciphertext = rte_pktmbuf_read(ut_params->obuf,
+ tdata->iv.len, plaintext_len, ciphertext_buffer);
+ else
+ ciphertext = rte_pktmbuf_read(ut_params->ibuf,
+ tdata->iv.len, plaintext_len, ciphertext_buffer);
+
+ /* Validate obuf */
+ TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+ /* Validate obuf */
+ TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+ ciphertext,
+ tdata->ciphertext.data,
+ tdata->validCipherLenInBits.len,
+ "ZUC Ciphertext data not as expected");
+
+ return 0;
+}
+
+static int
test_zuc_authentication(const struct zuc_hash_test_data *tdata)
{
struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -3571,12 +3885,24 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_kasumi_encryption_test_case_1_sgl(void)
+{
+ return test_kasumi_encryption_sgl(&kasumi_test_case_1);
+}
+
+static int
test_kasumi_encryption_test_case_1_oop(void)
{
return test_kasumi_encryption_oop(&kasumi_test_case_1);
}
static int
+test_kasumi_encryption_test_case_1_oop_sgl(void)
+{
+ return test_kasumi_encryption_oop_sgl(&kasumi_test_case_1);
+}
+
+static int
test_kasumi_encryption_test_case_2(void)
{
return test_kasumi_encryption(&kasumi_test_case_2);
@@ -3648,6 +3974,13 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_snow3g_encryption_test_case_1_oop_sgl(void)
+{
+ return test_snow3g_encryption_oop_sgl(&snow3g_test_case_1);
+}
+
+
+static int
test_snow3g_encryption_test_case_1_offset_oop(void)
{
return test_snow3g_encryption_offset_oop(&snow3g_test_case_1);
@@ -3767,6 +4100,12 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_zuc_encryption_test_case_6_sgl(void)
+{
+ return test_zuc_encryption_sgl(&zuc_test_case_1);
+}
+
+static int
test_zuc_hash_generate_test_case_1(void)
{
return test_zuc_authentication(&zuc_hash_test_case_1);
@@ -4085,6 +4424,104 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_mb_AES_GCM_authenticated_encryption_sgl(const struct gcm_test_data *tdata)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+ int retval;
+
+ unsigned plaintext_len;
+ uint16_t plaintext_pad_len;
+ uint8_t ciphertext_buffer[2048], auth_tag_buffer[2048];
+ const uint8_t *ciphertext, *auth_tag;
+
+ struct rte_cryptodev_info dev_info;
+
+ rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+ if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+
+ /* Create GCM session */
+ retval = create_gcm_session(ts_params->valid_devs[0],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ tdata->key.data, tdata->key.len,
+ tdata->aad.len, tdata->auth_tag.len,
+ RTE_CRYPTO_AUTH_OP_GENERATE);
+ if (retval < 0)
+ return retval;
+
+ plaintext_len = tdata->plaintext.len;
+
+ /* Append data which is padded to a multiple */
+ /* of the algorithms block size */
+ plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16);
+
+ ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+ plaintext_pad_len, 10);
+ pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+ /* Create GCM opertaion */
+ retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ tdata->auth_tag.data, tdata->auth_tag.len,
+ tdata->iv.data, tdata->iv.len,
+ tdata->aad.data, tdata->aad.len,
+ tdata->plaintext.len, plaintext_pad_len);
+ if (retval < 0) {
+ printf("create operation failed\n");
+ return retval;
+ }
+
+ rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess);
+
+ ut_params->op->sym->m_src = ut_params->ibuf;
+
+ /* Process crypto operation */
+ TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0],
+ ut_params->op), "failed to process sym crypto op");
+
+ TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS,
+ "crypto op processing failed");
+
+ /* Validate obuf */
+ if (ut_params->op->sym->m_dst) {
+ ciphertext = rte_pktmbuf_read(ut_params->op->sym->m_dst,
+ tdata->iv.len, plaintext_pad_len,
+ ciphertext_buffer);
+ auth_tag = rte_pktmbuf_read(ut_params->op->sym->m_dst,
+ plaintext_pad_len, tdata->auth_tag.len,
+ auth_tag_buffer);
+ } else {
+ ciphertext = rte_pktmbuf_read(ut_params->op->sym->m_src,
+ RTE_ALIGN_CEIL(tdata->iv.len, 16) +
+ ALIGN_POW2_ROUNDUP(tdata->aad.len, 16),
+ plaintext_pad_len, ciphertext_buffer);
+ auth_tag = rte_pktmbuf_read(ut_params->op->sym->m_src,
+ plaintext_pad_len +
+ RTE_ALIGN_CEIL(tdata->iv.len, 16) +
+ ALIGN_POW2_ROUNDUP(tdata->aad.len, 16),
+ tdata->auth_tag.len, auth_tag_buffer);
+ }
+
+ TEST_ASSERT_BUFFERS_ARE_EQUAL(
+ ciphertext,
+ tdata->ciphertext.data,
+ tdata->ciphertext.len,
+ "GCM Ciphertext data not as expected");
+
+ TEST_ASSERT_BUFFERS_ARE_EQUAL(
+ auth_tag,
+ tdata->auth_tag.data,
+ tdata->auth_tag.len,
+ "GCM Generated auth tag not as expected");
+
+ return 0;
+
+}
+
+static int
test_mb_AES_GCM_authenticated_encryption_test_case_1(void)
{
return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_1);
@@ -4127,6 +4564,12 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
}
static int
+test_mb_AES_GCM_authenticated_encryption_test_case_8(void)
+{
+ return test_mb_AES_GCM_authenticated_encryption_sgl(&gcm_test_case_2);
+}
+
+static int
test_mb_AES_GCM_authenticated_decryption(const struct gcm_test_data *tdata)
{
struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -6297,6 +6740,9 @@ struct test_crypto_vector {
test_mb_AES_GCM_authenticated_encryption_test_case_6),
TEST_CASE_ST(ut_setup, ut_teardown,
test_mb_AES_GCM_authenticated_encryption_test_case_7),
+ /** chained mbuf encrypt tests **/
+ TEST_CASE_ST(ut_setup, ut_teardown,
+ test_mb_AES_GCM_authenticated_encryption_test_case_8),
/** AES GCM Authenticated Decryption */
TEST_CASE_ST(ut_setup, ut_teardown,
@@ -6327,6 +6773,8 @@ struct test_crypto_vector {
TEST_CASE_ST(ut_setup, ut_teardown,
test_kasumi_encryption_test_case_1),
TEST_CASE_ST(ut_setup, ut_teardown,
+ test_kasumi_encryption_test_case_1_sgl),
+ TEST_CASE_ST(ut_setup, ut_teardown,
test_kasumi_encryption_test_case_2),
TEST_CASE_ST(ut_setup, ut_teardown,
test_kasumi_encryption_test_case_3),
@@ -6349,6 +6797,10 @@ struct test_crypto_vector {
TEST_CASE_ST(ut_setup, ut_teardown,
test_kasumi_encryption_test_case_1_oop),
TEST_CASE_ST(ut_setup, ut_teardown,
+ test_kasumi_encryption_test_case_1_oop_sgl),
+
+
+ TEST_CASE_ST(ut_setup, ut_teardown,
test_kasumi_decryption_test_case_1_oop),
/** KASUMI hash only (UIA1) */
@@ -6401,6 +6853,8 @@ struct test_crypto_vector {
TEST_CASE_ST(ut_setup, ut_teardown,
test_snow3g_encryption_test_case_1_oop),
TEST_CASE_ST(ut_setup, ut_teardown,
+ test_snow3g_encryption_test_case_1_oop_sgl),
+ TEST_CASE_ST(ut_setup, ut_teardown,
test_snow3g_decryption_test_case_1_oop),
TEST_CASE_ST(ut_setup, ut_teardown,
@@ -6478,6 +6932,8 @@ struct test_crypto_vector {
test_zuc_hash_generate_test_case_4),
TEST_CASE_ST(ut_setup, ut_teardown,
test_zuc_hash_generate_test_case_5),
+ TEST_CASE_ST(ut_setup, ut_teardown,
+ test_zuc_encryption_test_case_6_sgl),
TEST_CASES_END() /**< NULL terminate unit test array */
}
};
diff --git a/app/test/test_cryptodev.h b/app/test/test_cryptodev.h
index a9089aa..f68ad0a 100644
--- a/app/test/test_cryptodev.h
+++ b/app/test/test_cryptodev.h
@@ -71,4 +71,115 @@
#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA384 (24)
#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA512 (32)
+/**
+ * Write (spread) data from buffer to mbuf data
+ *
+ * @param mbuf
+ * Destination mbuf
+ * @param offset
+ * Start offset in mbuf
+ * @param len
+ * Number of bytes to copy
+ * @param buffer
+ * Continuous source buffer
+ */
+static inline void
+pktmbuf_write(struct rte_mbuf *mbuf, int offset, int len, const uint8_t *buffer)
+{
+ int n = len;
+ int l;
+ struct rte_mbuf *m;
+ char *dst;
+
+ for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next)
+ offset -= m->data_len;
+
+ l = m->data_len - offset;
+
+ /* copy data from first segment */
+ dst = rte_pktmbuf_mtod_offset(m, char *, offset);
+ if (len <= l) {
+ rte_memcpy(dst, buffer, len);
+ return;
+ }
+
+ rte_memcpy(dst, buffer, l);
+ buffer += l;
+ n -= l;
+
+ for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+ dst = rte_pktmbuf_mtod(m, char *);
+ l = m->data_len;
+ if (n < l) {
+ rte_memcpy(dst, buffer, n);
+ return;
+ }
+ rte_memcpy(dst, buffer, l);
+ buffer += l;
+ n -= l;
+ }
+}
+
+static inline struct rte_mbuf *
+create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len,
+ int nb_segs) {
+
+ struct rte_mbuf *m = NULL, *mbuf = NULL;
+ uint8_t *dst;
+ int data_len = 0;
+ int i, size;
+ int t_len;
+
+ if (pkt_len < 1) {
+ printf("Packet size must be 1 or more (is %d)\n", pkt_len);
+ return NULL;
+ }
+
+ if (nb_segs < 1) {
+ printf("Number of segments must be 1 or more (is %d)\n",
+ nb_segs);
+ return NULL;
+ }
+
+ t_len = pkt_len >= nb_segs ? pkt_len / nb_segs : 1;
+ size = pkt_len;
+
+ /* Create chained mbuf_src and fill it generated data */
+ for (i = 0; size > 0; i++) {
+
+ m = rte_pktmbuf_alloc(mbuf_pool);
+ if (i == 0)
+ mbuf = m;
+
+ if (!m) {
+ printf("Cannot create segment for source mbuf");
+ goto fail;
+ }
+
+ /* Make sure if tailroom is zeroed */
+ memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
+ rte_pktmbuf_tailroom(m));
+
+ data_len = size > t_len ? t_len : size;
+ dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
+ if (!dst) {
+ printf("Cannot append %d bytes to the mbuf\n",
+ data_len);
+ goto fail;
+ }
+
+ if (mbuf != m)
+ rte_pktmbuf_chain(mbuf, m);
+
+ size -= data_len;
+
+ }
+ return mbuf;
+
+fail:
+ if (mbuf)
+ rte_pktmbuf_free(mbuf);
+ return NULL;
+}
+
#endif /* TEST_CRYPTODEV_H_ */
diff --git a/app/test/test_cryptodev_aes_test_vectors.h b/app/test/test_cryptodev_aes_test_vectors.h
index 1c68f93..ed63c0a 100644
--- a/app/test/test_cryptodev_aes_test_vectors.h
+++ b/app/test/test_cryptodev_aes_test_vectors.h
@@ -883,6 +883,17 @@
BLOCKCIPHER_TEST_TARGET_PMD_QAT
},
{
+ .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
+ "Scatter Gather",
+ .test_data = &aes_test_data_4,
+ .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
+ .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG,
+ .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+ BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+ BLOCKCIPHER_TEST_TARGET_PMD_QAT
+
+ },
+ {
.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
"Verify",
.test_data = &aes_test_data_4,
@@ -926,6 +937,17 @@
BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
},
{
+ .test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
+ "Scatter Gather Sessionless",
+ .test_data = &aes_test_data_6,
+ .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
+ .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS |
+ BLOCKCIPHER_TEST_FEATURE_SG |
+ BLOCKCIPHER_TEST_FEATURE_OOP,
+ .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+ BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+ },
+ {
.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
"Verify",
.test_data = &aes_test_data_6,
@@ -1033,9 +1055,17 @@
.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
},
{
- .test_descr = "AES-192-CBC Encryption",
+ .test_descr = "AES-192-CBC",
+ .test_data = &aes_test_data_10,
+ .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+ .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+ },
+ {
+ .test_descr = "AES-192-CBC Encryption Scater gather",
.test_data = &aes_test_data_10,
.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+ .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG |
+ BLOCKCIPHER_TEST_FEATURE_OOP,
.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
},
{
diff --git a/app/test/test_cryptodev_blockcipher.c b/app/test/test_cryptodev_blockcipher.c
index 37b10cf..9933ca3 100644
--- a/app/test/test_cryptodev_blockcipher.c
+++ b/app/test/test_cryptodev_blockcipher.c
@@ -41,6 +41,7 @@
#include <rte_cryptodev_pmd.h>
#include "test.h"
+#include "test_cryptodev.h"
#include "test_cryptodev_blockcipher.h"
#include "test_cryptodev_aes_test_vectors.h"
#include "test_cryptodev_des_test_vectors.h"
@@ -63,6 +64,7 @@
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;
int status = TEST_SUCCESS;
const struct blockcipher_test_data *tdata = t->test_data;
@@ -72,6 +74,19 @@
uint32_t digest_len = 0;
char *buf_p = NULL;
+ int nb_segs = 3;
+ int nb_segs_oop = 1;
+
+ if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
+ rte_cryptodev_info_get(dev_id, &dev_info);
+ if (!(dev_info.feature_flags &
+ RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+ printf("Device doesn't support scatter-gather. "
+ "Test Skipped.\n");
+ return 0;
+ }
+ }
+
if (tdata->cipher_key.len)
memcpy(cipher_key, tdata->cipher_key.data,
tdata->cipher_key.len);
@@ -96,72 +111,112 @@
}
/* preparing data */
- ibuf = rte_pktmbuf_alloc(mbuf_pool);
- if (!ibuf) {
- snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
- "line %u FAILED: %s",
- __LINE__, "Allocation of rte_mbuf failed");
- status = TEST_FAILED;
- goto error_exit;
- }
- if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER)
- buf_len += tdata->iv.len;
- if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH)
- buf_len += digest_len;
+ if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
- buf_p = rte_pktmbuf_append(ibuf, buf_len);
- if (!buf_p) {
- snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
- "line %u FAILED: %s",
- __LINE__, "No room to append mbuf");
- status = TEST_FAILED;
- goto error_exit;
- }
-
- if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
- rte_memcpy(buf_p, tdata->iv.data, tdata->iv.len);
- buf_p += tdata->iv.len;
- }
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
+ ibuf = create_segmented_mbuf(mbuf_pool,
+ tdata->plaintext.len, nb_segs);
+ pktmbuf_write(ibuf, 0, tdata->plaintext.len,
+ tdata->plaintext.data);
+ } else {
+ ibuf = create_segmented_mbuf(mbuf_pool,
+ tdata->ciphertext.len, nb_segs);
+ pktmbuf_write(ibuf, 0, tdata->ciphertext.len,
+ tdata->ciphertext.data);
+ }
- /* only encryption requires plaintext.data input,
- * decryption/(digest gen)/(digest verify) use ciphertext.data
- * to be computed
- */
- if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
- rte_memcpy(buf_p, tdata->plaintext.data,
- tdata->plaintext.len);
- buf_p += tdata->plaintext.len;
- } else {
- rte_memcpy(buf_p, tdata->ciphertext.data,
- tdata->ciphertext.len);
- buf_p += tdata->ciphertext.len;
- }
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
+ rte_memcpy(rte_pktmbuf_prepend(ibuf, tdata->iv.len),
+ tdata->iv.data, tdata->iv.len);
+ }
- if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
- rte_memcpy(buf_p, tdata->digest.data, digest_len);
- else
- memset(buf_p, 0, digest_len);
+ buf_p = rte_pktmbuf_append(ibuf, digest_len);
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
+ rte_memcpy(buf_p, tdata->digest.data, digest_len);
+ else
+ memset(buf_p, 0, digest_len);
- if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) {
- obuf = rte_pktmbuf_alloc(mbuf_pool);
- if (!obuf) {
- snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
- "FAILED: %s", __LINE__,
- "Allocation of rte_mbuf failed");
+ } else {
+ ibuf = rte_pktmbuf_alloc(mbuf_pool);
+ if (!ibuf) {
+ snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+ "line %u FAILED: %s",
+ __LINE__,
+ "Allocation of rte_mbuf failed");
status = TEST_FAILED;
goto error_exit;
}
- buf_p = rte_pktmbuf_append(obuf, buf_len);
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER)
+ buf_len += tdata->iv.len;
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH)
+ buf_len += digest_len;
+
+ buf_p = rte_pktmbuf_append(ibuf, buf_len);
if (!buf_p) {
- snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
- "FAILED: %s", __LINE__,
- "No room to append mbuf");
+ snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+ "line %u FAILED: %s",
+ __LINE__, "No room to append mbuf");
status = TEST_FAILED;
goto error_exit;
}
- memset(buf_p, 0, buf_len);
+
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
+ rte_memcpy(buf_p, tdata->iv.data, tdata->iv.len);
+ buf_p += tdata->iv.len;
+ }
+
+ /* only encryption requires plaintext.data input,
+ * decryption/(digest gen)/(digest verify) use ciphertext.data
+ * to be computed
+ */
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
+ rte_memcpy(buf_p, tdata->plaintext.data,
+ tdata->plaintext.len);
+ buf_p += tdata->plaintext.len;
+ } else {
+ rte_memcpy(buf_p, tdata->ciphertext.data,
+ tdata->ciphertext.len);
+ buf_p += tdata->ciphertext.len;
+ }
+
+ if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
+ rte_memcpy(buf_p, tdata->digest.data, digest_len);
+ else
+ memset(buf_p, 0, digest_len);
+ }
+
+ if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) {
+ if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
+ obuf = create_segmented_mbuf(mbuf_pool, buf_len,
+ nb_segs_oop);
+ if (!obuf) {
+ snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+ "line %u FAILED: %s", __LINE__,
+ "Allocation of rte_mbuf failed");
+ status = TEST_FAILED;
+ goto error_exit;
+ }
+ } else {
+ obuf = rte_pktmbuf_alloc(mbuf_pool);
+ if (!obuf) {
+ snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+ "line %u FAILED: %s", __LINE__,
+ "Allocation of rte_mbuf failed");
+ status = TEST_FAILED;
+ goto error_exit;
+ }
+ buf_p = rte_pktmbuf_append(obuf, buf_len);
+ if (!buf_p) {
+ snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+ "line %u FAILED: %s", __LINE__,
+ "No room to append mbuf");
+ status = TEST_FAILED;
+ goto error_exit;
+ }
+ memset(buf_p, 0, buf_len);
+ }
}
/* Generate Crypto op data structure */
@@ -176,7 +231,6 @@
}
sym_op = op->sym;
-
sym_op->m_src = ibuf;
if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) {
@@ -386,13 +440,10 @@
}
if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
- uint8_t *crypto_res;
+ uint8_t buffer[2048];
const uint8_t *compare_ref;
uint32_t compare_len;
- crypto_res = rte_pktmbuf_mtod_offset(iobuf, uint8_t *,
- tdata->iv.len);
-
if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
compare_ref = tdata->ciphertext.data;
compare_len = tdata->ciphertext.len;
@@ -401,7 +452,8 @@
compare_len = tdata->plaintext.len;
}
- if (memcmp(crypto_res, compare_ref, compare_len)) {
+ if (memcmp(rte_pktmbuf_read(iobuf, tdata->iv.len, compare_len,
+ buffer), compare_ref, compare_len)) {
snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
"FAILED: %s", __LINE__,
"Crypto data not as expected");
diff --git a/app/test/test_cryptodev_blockcipher.h b/app/test/test_cryptodev_blockcipher.h
index 04ff1ee..87a0683 100644
--- a/app/test/test_cryptodev_blockcipher.h
+++ b/app/test/test_cryptodev_blockcipher.h
@@ -45,6 +45,7 @@
#define BLOCKCIPHER_TEST_FEATURE_OOP 0x01
#define BLOCKCIPHER_TEST_FEATURE_SESSIONLESS 0x02
#define BLOCKCIPHER_TEST_FEATURE_STOPPER 0x04 /* stop upon failing */
+#define BLOCKCIPHER_TEST_FEATURE_SG 0x08 /* Scatter Gather */
#define BLOCKCIPHER_TEST_TARGET_PMD_MB 0x0001 /* Multi-buffer flag */
#define BLOCKCIPHER_TEST_TARGET_PMD_QAT 0x0002 /* QAT flag */
--
1.7.9.5
^ permalink raw reply related
* ixgbevf: support multicast packets from PF to VF
From: Dey, Souvik @ 2016-12-02 17:26 UTC (permalink / raw)
To: dev@dpdk.org
Hi All,
I am trying to support multicast packet over SRIOV using kernel PF + DPDK VF(ixgbevf) drivers for ipv6. I am currently using 2.1 DPDK and found that there was a patch in 16.04 for "ixgbe: support multicast promiscuous mode on VF". So I have backported the patch to the 2.1 DPDK but still multicast packets were not coming up to the DPDK app. Then I tried to enable the rte_eth_dev_set_mc_addr_list and with the the packets were coming up properly. Now I have some doubts :
1. Do we have to use both rte_eth_dev_set_mc_addr_list and rte_eth_allmulticast_enable to get the multicast packets.
2. How do we get the mc_addr_list dynamically as I don't see we are using the kni_net_set_rx_mode in rte_kni. Without this the DPDK app will not have any idea to update the mc_addr_list in the PF.
3. Is there any other patches which I should be using to get this functionality working.
I am using : DPDK -2.1
Host kernel - 4.4 ( ubuntu)
Guest kernel - 3.2 (Debian)
Drivers - ixgbe ( for both pf and vf).
Thanks in advance for the help and support.
--
Regards,
Souvik
^ permalink raw reply
* Re: ixgbevf: support multicast packets from PF to VF
From: Dey, Souvik @ 2016-12-02 17:27 UTC (permalink / raw)
To: dev@dpdk.org, wenzhuo.lu@intel.com
Adding wenzhuo.lu@intel.com<mailto:wenzhuo.lu@intel.com>
From: Dey, Souvik
Sent: Friday, December 2, 2016 12:27 PM
To: 'dev@dpdk.org' <dev@dpdk.org>
Subject: ixgbevf: support multicast packets from PF to VF
Hi All,
I am trying to support multicast packet over SRIOV using kernel PF + DPDK VF(ixgbevf) drivers for ipv6. I am currently using 2.1 DPDK and found that there was a patch in 16.04 for "ixgbe: support multicast promiscuous mode on VF". So I have backported the patch to the 2.1 DPDK but still multicast packets were not coming up to the DPDK app. Then I tried to enable the rte_eth_dev_set_mc_addr_list and with the the packets were coming up properly. Now I have some doubts :
1. Do we have to use both rte_eth_dev_set_mc_addr_list and rte_eth_allmulticast_enable to get the multicast packets.
2. How do we get the mc_addr_list dynamically as I don't see we are using the kni_net_set_rx_mode in rte_kni. Without this the DPDK app will not have any idea to update the mc_addr_list in the PF.
3. Is there any other patches which I should be using to get this functionality working.
I am using : DPDK -2.1
Host kernel - 4.4 ( ubuntu)
Guest kernel - 3.2 (Debian)
Drivers - ixgbe ( for both pf and vf).
Thanks in advance for the help and support.
--
Regards,
Souvik
^ permalink raw reply
* [PATCH v4] eal: restrict cores auto detection
From: Jianfeng Tan @ 2016-12-02 17:48 UTC (permalink / raw)
To: dev; +Cc: david.marchand, pmatilai, bruce.richardson, Jianfeng Tan
In-Reply-To: <1472693507-11369-1-git-send-email-jianfeng.tan@intel.com>
This patch uses pthread_getaffinity_np() to narrow down used
cores when none of below options is specified:
* coremask (-c)
* corelist (-l)
* and coremap (--lcores)
The purpose of this patch is to leave out these core related options
when DPDK applications are deployed under container env, so that
users do not need decide the core related parameters when developing
applications. Instead, when applications are deployed in containers,
use cpu-set to constrain which cores can be used inside this container
instance. And DPDK application inside containers just rely on this
auto detect mechanism to start polling threads.
Note: previously, some users are using isolated CPUs, which could
be excluded by default. Please add commands like taskset to use
those cores.
Test example:
$ taskset 0xc0000 ./examples/helloworld/build/helloworld -m 1024
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
---
v4:
- Address Bruce's comment: only enable this auto detection
mechanism when none of core options is specified.
- More detailed use case on how it helps in containers.
v3:
- Choose a more descriptive variable name, and remove comments
as suggested by Stephen Hemminger.
v2:
- Make it as default instead of adding the new options.
---
lib/librte_eal/common/eal_common_options.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 6ca8af1..d192de1 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -126,6 +126,7 @@ static const char dpdk_solib_path[] __attribute__((used)) =
static int master_lcore_parsed;
static int mem_parsed;
+static int core_specified;
void
eal_reset_internal_config(struct internal_config *internal_cfg)
@@ -797,6 +798,7 @@ eal_parse_common_option(int opt, const char *optarg,
RTE_LOG(ERR, EAL, "invalid coremask\n");
return -1;
}
+ core_specified = 1;
break;
/* corelist */
case 'l':
@@ -804,6 +806,7 @@ eal_parse_common_option(int opt, const char *optarg,
RTE_LOG(ERR, EAL, "invalid core list\n");
return -1;
}
+ core_specified = 1;
break;
/* size of memory */
case 'm':
@@ -912,6 +915,7 @@ eal_parse_common_option(int opt, const char *optarg,
OPT_LCORES "\n");
return -1;
}
+ core_specified = 1;
break;
/* don't know what to do, leave this to caller */
@@ -923,12 +927,38 @@ eal_parse_common_option(int opt, const char *optarg,
return 0;
}
+static void
+eal_auto_detect_cores(struct rte_config *cfg)
+{
+ unsigned int lcore_id;
+ unsigned int removed = 0;
+ rte_cpuset_t affinity_set;
+ pthread_t tid = pthread_self();
+
+ if (pthread_getaffinity_np(tid, sizeof(rte_cpuset_t),
+ &affinity_set) < 0)
+ CPU_ZERO(&affinity_set);
+
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+ if (cfg->lcore_role[lcore_id] == ROLE_RTE &&
+ !CPU_ISSET(lcore_id, &affinity_set)) {
+ cfg->lcore_role[lcore_id] = ROLE_OFF;
+ removed++;
+ }
+ }
+
+ cfg->lcore_count -= removed;
+}
+
int
eal_adjust_config(struct internal_config *internal_cfg)
{
int i;
struct rte_config *cfg = rte_eal_get_configuration();
+ if (!core_specified)
+ eal_auto_detect_cores(cfg);
+
if (internal_config.process_type == RTE_PROC_AUTO)
internal_config.process_type = eal_proc_type_detect();
--
2.7.4
^ permalink raw reply related
* [PATCH v2] net/i40evf: fix reporting of imissed packets
From: Tom Crugnale @ 2016-12-02 18:23 UTC (permalink / raw)
To: helin.zhang@intel.com, jingjing.wu@intel.com; +Cc: dev@dpdk.org, Tom Crugnale
In-Reply-To: <1480702174-5980-1-git-send-email-tcrugnale@sandvine.com>
Missed packets on RX were erroneously being assigned to the ierrors
struct member. Change it to be assigned to imissed.
Fixes: 4861cde4 ("i40e: new poll mode driver")
Signed-off-by: Tom Crugnale <tcrugnale@sandvine.com>
---
v2:
* Fixed line breaks in original patch submission
---
drivers/net/i40e/i40e_ethdev_vf.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index aa306d6..90876c8 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -952,7 +952,7 @@ i40evf_update_stats(struct rte_eth_dev *dev, struct i40e_eth_stats **pstats)
}
static int
-i40evf_get_statics(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+i40evf_get_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
{
int ret;
struct i40e_eth_stats *pstats = NULL;
@@ -965,7 +965,7 @@ i40evf_get_statics(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
pstats->rx_broadcast;
stats->opackets = pstats->tx_broadcast + pstats->tx_multicast +
pstats->tx_unicast;
- stats->ierrors = pstats->rx_discards;
+ stats->imissed = pstats->rx_discards;
stats->oerrors = pstats->tx_errors + pstats->tx_discards;
stats->ibytes = pstats->rx_bytes;
stats->obytes = pstats->tx_bytes;
@@ -2277,8 +2277,8 @@ i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
static void
i40evf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
{
- if (i40evf_get_statics(dev, stats))
- PMD_DRV_LOG(ERR, "Get statics failed");
+ if (i40evf_get_stats(dev, stats))
+ PMD_DRV_LOG(ERR, "Get stats failed");
}
static void
--
2.7.4
^ permalink raw reply related
* [RFC PATCH] EventDev buffered enqueue API
From: Gage Eads @ 2016-12-02 19:45 UTC (permalink / raw)
To: jerin.jacob
Cc: dev, bruce.richardson, harry.van.haaren, hemant.agrawal,
Gage Eads
This patch extends the currently proposed libeventdev API with support
for buffered enqueue operations.
This functionality can improve application performance when using event
devices that benefit from bulk enqueue operations, but due to its
architecture the application cannot easily combine its enqueue
operations.
For instance, consider a network application that dequeues a burst of
events and then processes them individually, where each event may be
processed and enqueued in a different codepath depending on its layer-3
or layer-4 protocol type. To take advantage of burst enqueues with the
current eventdev API, the application would have to be modified with an
ad-hoc buffering solution.
This functionality can be achieved fairly simply in the eventdev itself,
and in doing so reduces the amount of boilerplate code repeated among
applications of the sort described.
This patch applies on top of Jerin Jacob's eventdev API patchset[1].
[1] http://dpdk.org/ml/archives/dev/2016-November/050355.html
Gage Eads (1):
eventdev: add buffered enqueue and flush APIs
lib/librte_eventdev/rte_eventdev.c | 29 ++++++++++
lib/librte_eventdev/rte_eventdev.h | 106 +++++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
--
1.9.1
^ permalink raw reply
* [RFC PATCH] eventdev: add buffered enqueue and flush APIs
From: Gage Eads @ 2016-12-02 19:45 UTC (permalink / raw)
To: jerin.jacob
Cc: dev, bruce.richardson, harry.van.haaren, hemant.agrawal,
Gage Eads
In-Reply-To: <1480707956-17187-1-git-send-email-gage.eads@intel.com>
This commit adds buffered enqueue functionality to the eventdev API.
It is conceptually similar to the ethdev API's tx buffering, however
with a smaller API surface and no dropping of events.
Signed-off-by: Gage Eads <gage.eads@intel.com>
---
lib/librte_eventdev/rte_eventdev.c | 29 ++++++++++
lib/librte_eventdev/rte_eventdev.h | 106 +++++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
index 17ce5c3..564573f 100644
--- a/lib/librte_eventdev/rte_eventdev.c
+++ b/lib/librte_eventdev/rte_eventdev.c
@@ -219,6 +219,7 @@
uint16_t *links_map;
uint8_t *ports_dequeue_depth;
uint8_t *ports_enqueue_depth;
+ struct rte_eventdev_enqueue_buffer *port_buffers;
unsigned int i;
EDEV_LOG_DEBUG("Setup %d ports on device %u", nb_ports,
@@ -272,6 +273,19 @@
"nb_ports %u", nb_ports);
return -(ENOMEM);
}
+
+ /* Allocate memory to store port enqueue buffers */
+ dev->data->port_buffers =
+ rte_zmalloc_socket("eventdev->port_buffers",
+ sizeof(dev->data->port_buffers[0]) * nb_ports,
+ RTE_CACHE_LINE_SIZE, dev->data->socket_id);
+ if (dev->data->port_buffers == NULL) {
+ dev->data->nb_ports = 0;
+ EDEV_LOG_ERR("failed to get memory for port enq"
+ " buffers, nb_ports %u", nb_ports);
+ return -(ENOMEM);
+ }
+
} else if (dev->data->ports != NULL && nb_ports != 0) {/* re-config */
RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release, -ENOTSUP);
@@ -279,6 +293,7 @@
ports_dequeue_depth = dev->data->ports_dequeue_depth;
ports_enqueue_depth = dev->data->ports_enqueue_depth;
links_map = dev->data->links_map;
+ port_buffers = dev->data->port_buffers;
for (i = nb_ports; i < old_nb_ports; i++)
(*dev->dev_ops->port_release)(ports[i]);
@@ -324,6 +339,17 @@
return -(ENOMEM);
}
+ /* Realloc memory to store port enqueue buffers */
+ port_buffers = rte_realloc(dev->data->port_buffers,
+ sizeof(dev->data->port_buffers[0]) * nb_ports,
+ RTE_CACHE_LINE_SIZE);
+ if (port_buffers == NULL) {
+ dev->data->nb_ports = 0;
+ EDEV_LOG_ERR("failed to realloc mem for port enq"
+ " buffers, nb_ports %u", nb_ports);
+ return -(ENOMEM);
+ }
+
if (nb_ports > old_nb_ports) {
uint8_t new_ps = nb_ports - old_nb_ports;
@@ -336,12 +362,15 @@
memset(links_map +
(old_nb_ports * RTE_EVENT_MAX_QUEUES_PER_DEV),
0, sizeof(ports_enqueue_depth[0]) * new_ps);
+ memset(port_buffers + old_nb_ports, 0,
+ sizeof(port_buffers[0]) * new_ps);
}
dev->data->ports = ports;
dev->data->ports_dequeue_depth = ports_dequeue_depth;
dev->data->ports_enqueue_depth = ports_enqueue_depth;
dev->data->links_map = links_map;
+ dev->data->port_buffers = port_buffers;
} else if (dev->data->ports != NULL && nb_ports == 0) {
RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release, -ENOTSUP);
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index 778d6dc..3f24342 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -246,6 +246,7 @@
#include <rte_dev.h>
#include <rte_memory.h>
#include <rte_errno.h>
+#include <rte_memcpy.h>
#define EVENTDEV_NAME_SKELETON_PMD event_skeleton
/**< Skeleton event device PMD name */
@@ -965,6 +966,26 @@ typedef uint16_t (*event_dequeue_burst_t)(void *port, struct rte_event ev[],
#define RTE_EVENTDEV_NAME_MAX_LEN (64)
/**< @internal Max length of name of event PMD */
+#define RTE_EVENT_BUF_MAX 16
+/**< Maximum number of events in an enqueue buffer. */
+
+/**
+ * @internal
+ * An enqueue buffer for each port.
+ *
+ * The reason this struct is in the header is for inlining the function calls
+ * to enqueue, as doing a function call per packet would incur significant
+ * performance overhead.
+ *
+ * \see rte_event_enqueue_buffer(), rte_event_enqueue_buffer_flush()
+ */
+struct rte_eventdev_enqueue_buffer {
+ /**> Count of events in this buffer */
+ uint16_t count;
+ /**> Array of events in this buffer */
+ struct rte_event events[RTE_EVENT_BUF_MAX];
+} __rte_cache_aligned;
+
/**
* @internal
* The data part, with no function pointers, associated with each device.
@@ -983,6 +1004,8 @@ struct rte_eventdev_data {
/**< Number of event ports. */
void **ports;
/**< Array of pointers to ports. */
+ struct rte_eventdev_enqueue_buffer *port_buffers;
+ /**< Array of port enqueue buffers. */
uint8_t *ports_dequeue_depth;
/**< Array of port dequeue depth. */
uint8_t *ports_enqueue_depth;
@@ -1132,6 +1155,89 @@ struct rte_eventdev {
}
/**
+ * Flush the enqueue buffer of the event port specified by *port_id*, in the
+ * event device specified by *dev_id*.
+ *
+ * This function attempts to flush as many of the buffered events as possible,
+ * and returns the number of flushed events. Any unflushed events remain in
+ * the buffer.
+ *
+ * @param dev_id
+ * The identifier of the device.
+ * @param port_id
+ * The identifier of the event port.
+ *
+ * @return
+ * The number of event objects actually flushed to the event device.
+ *
+ * \see rte_event_enqueue_buffer(), rte_event_enqueue_burst()
+ * \see rte_event_port_enqueue_depth()
+ */
+static inline int
+rte_event_enqueue_buffer_flush(uint8_t dev_id, uint8_t port_id)
+{
+ struct rte_eventdev *dev = &rte_eventdevs[dev_id];
+ struct rte_eventdev_enqueue_buffer *buf =
+ &dev->data->port_buffers[port_id];
+ int n;
+
+ n = rte_event_enqueue_burst(dev_id, port_id, buf->events, buf->count);
+
+ if (n != buf->count)
+ memmove(buf->events, &buf->events[n], buf->count - n);
+
+ buf->count -= n;
+
+ return n;
+}
+
+/**
+ * Buffer an event object supplied in *rte_event* structure for future
+ * enqueueing on an event device designated by its *dev_id* through the event
+ * port specified by *port_id*.
+ *
+ * This function takes a single event and buffers it for later enqueuing to the
+ * queue specified in the event structure. If the buffer is full, the
+ * function will attempt to flush the buffer before buffering the event.
+ * If the flush operation fails, the previously buffered events remain in the
+ * buffer and an error is returned to the user to indicate that *ev* was not
+ * buffered.
+ *
+ * @param dev_id
+ * The identifier of the device.
+ * @param port_id
+ * The identifier of the event port.
+ * @param ev
+ * Pointer to struct rte_event
+ *
+ * @return
+ * - 0 on success
+ * - <0 on failure. Failure can occur if the event port's output queue is
+ * backpressured, for instance.
+ *
+ * \see rte_event_enqueue_buffer_flush(), rte_event_enqueue_burst()
+ * \see rte_event_port_enqueue_depth()
+ */
+static inline int
+rte_event_enqueue_buffer(uint8_t dev_id, uint8_t port_id, struct rte_event *ev)
+{
+ struct rte_eventdev *dev = &rte_eventdevs[dev_id];
+ struct rte_eventdev_enqueue_buffer *buf =
+ &dev->data->port_buffers[port_id];
+ int ret;
+
+ /* If necessary, flush the enqueue buffer to make space for ev. */
+ if (buf->count == RTE_EVENT_BUF_MAX) {
+ ret = rte_event_enqueue_buffer_flush(dev_id, port_id);
+ if (ret == 0)
+ return -ENOSPC;
+ }
+
+ rte_memcpy(&buf->events[buf->count++], ev, sizeof(struct rte_event));
+ return 0;
+}
+
+/**
* Converts nanoseconds to *wait* value for rte_event_dequeue()
*
* If the device is configured with RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT flag then
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 01/22] ethdev: introduce generic flow API
From: Kevin Traynor @ 2016-12-02 21:06 UTC (permalink / raw)
To: Adrien Mazarguil
Cc: dev, Thomas Monjalon, Pablo de Lara, Olivier Matz,
sugesh.chandran
In-Reply-To: <20161201083652.GI10340@6wind.com>
On 12/01/2016 08:36 AM, Adrien Mazarguil wrote:
> Hi Kevin,
>
> On Wed, Nov 30, 2016 at 05:47:17PM +0000, Kevin Traynor wrote:
>> Hi Adrien,
>>
>> On 11/16/2016 04:23 PM, Adrien Mazarguil wrote:
>>> This new API supersedes all the legacy filter types described in
>>> rte_eth_ctrl.h. It is slightly higher level and as a result relies more on
>>> PMDs to process and validate flow rules.
>>>
>>> Benefits:
>>>
>>> - A unified API is easier to program for, applications do not have to be
>>> written for a specific filter type which may or may not be supported by
>>> the underlying device.
>>>
>>> - The behavior of a flow rule is the same regardless of the underlying
>>> device, applications do not need to be aware of hardware quirks.
>>>
>>> - Extensible by design, API/ABI breakage should rarely occur if at all.
>>>
>>> - Documentation is self-standing, no need to look up elsewhere.
>>>
>>> Existing filter types will be deprecated and removed in the near future.
>>
>> I'd suggest to add a deprecation notice to deprecation.rst, ideally with
>> a target release.
>
> Will do, not a sure about the target release though. It seems a bit early
> since no PMD really supports this API yet.
>
> [...]
>>> diff --git a/lib/librte_ether/rte_flow.c b/lib/librte_ether/rte_flow.c
>>> new file mode 100644
>>> index 0000000..064963d
>>> --- /dev/null
>>> +++ b/lib/librte_ether/rte_flow.c
>>> @@ -0,0 +1,159 @@
>>> +/*-
>>> + * BSD LICENSE
>>> + *
>>> + * Copyright 2016 6WIND S.A.
>>> + * Copyright 2016 Mellanox.
>>
>> There's Mellanox copyright but you are the only signed-off-by - is that
>> right?
>
> Yes, I'm the primary maintainer for Mellanox PMDs and this API was designed
> on their behalf to expose several features from mlx4/mlx5 as the existing
> filter types had too many limitations.
>
> [...]
>>> +/* Get generic flow operations structure from a port. */
>>> +const struct rte_flow_ops *
>>> +rte_flow_ops_get(uint8_t port_id, struct rte_flow_error *error)
>>> +{
>>> + struct rte_eth_dev *dev = &rte_eth_devices[port_id];
>>> + const struct rte_flow_ops *ops;
>>> + int code;
>>> +
>>> + if (unlikely(!rte_eth_dev_is_valid_port(port_id)))
>>> + code = ENODEV;
>>> + else if (unlikely(!dev->dev_ops->filter_ctrl ||
>>> + dev->dev_ops->filter_ctrl(dev,
>>> + RTE_ETH_FILTER_GENERIC,
>>> + RTE_ETH_FILTER_GET,
>>> + &ops) ||
>>> + !ops))
>>> + code = ENOTSUP;
>>> + else
>>> + return ops;
>>> + rte_flow_error_set(error, code, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
>>> + NULL, rte_strerror(code));
>>> + return NULL;
>>> +}
>>> +
>>
>> Is it expected that the application or pmd will provide locking between
>> these functions if required? I think it's going to have to be the app.
>
> Locking is indeed expected to be performed by applications. This API only
> documents places where locking would make sense if necessary and expected
> behavior.
>
> Like all control path APIs, this one assumes a single control thread.
> Applications must take the necessary precautions.
If you look at OVS now it's quite possible that you have 2 rx queues
serviced by different threads, that would also install the flow rules in
the software flow caches - possibly that could extend to adding hardware
flows. There could also be another thread that is querying for stats. So
anything that can be done to minimise the locking would be helpful -
maybe query() could be atomic and not require any locking?
>
> [...]
>>> +/**
>>> + * Flow rule attributes.
>>> + *
>>> + * Priorities are set on two levels: per group and per rule within groups.
>>> + *
>>> + * Lower values denote higher priority, the highest priority for both levels
>>> + * is 0, so that a rule with priority 0 in group 8 is always matched after a
>>> + * rule with priority 8 in group 0.
>>> + *
>>> + * Although optional, applications are encouraged to group similar rules as
>>> + * much as possible to fully take advantage of hardware capabilities
>>> + * (e.g. optimized matching) and work around limitations (e.g. a single
>>> + * pattern type possibly allowed in a given group).
>>> + *
>>> + * Group and priority levels are arbitrary and up to the application, they
>>> + * do not need to be contiguous nor start from 0, however the maximum number
>>> + * varies between devices and may be affected by existing flow rules.
>>> + *
>>> + * If a packet is matched by several rules of a given group for a given
>>> + * priority level, the outcome is undefined. It can take any path, may be
>>> + * duplicated or even cause unrecoverable errors.
>>
>> I get what you are trying to do here wrt supporting multiple
>> pmds/hardware implementations and it's a good idea to keep it flexible.
>>
>> Given that the outcome is undefined, it would be nice that the
>> application has a way of finding the specific effects for verification
>> and debugging.
>
> Right, however it was deemed a bit difficult to manage in many cases hence
> the vagueness.
>
> For example, suppose two rules with the same group and priority, one
> matching any IPv4 header, the other one any UDP header:
>
> - TCPv4 packets => rule #1.
> - UDPv6 packets => rule #2.
> - UDPv4 packets => both?
>
> That last one is perhaps invalid, checking that some unspecified protocol
> combination does not overlap is expensive and may miss corner cases, even
> assuming this is not an issue, what if the application guarantees that no
> UDPv4 packets can ever hit that rule?
that's fine - I don't expect the software to be able to know what the
hardware will do with those rules. It's more about trying to get a dump
from the hardware if something goes wrong. Anyway covered in comment later.
>
> Suggestions are welcome though, perhaps we can refine the description
>
>>> + *
>>> + * Note that support for more than a single group and priority level is not
>>> + * guaranteed.
>>> + *
>>> + * Flow rules can apply to inbound and/or outbound traffic (ingress/egress).
>>> + *
>>> + * Several pattern items and actions are valid and can be used in both
>>> + * directions. Those valid for only one direction are described as such.
>>> + *
>>> + * Specifying both directions at once is not recommended but may be valid in
>>> + * some cases, such as incrementing the same counter twice.
>>> + *
>>> + * Not specifying any direction is currently an error.
>>> + */
>>> +struct rte_flow_attr {
>>> + uint32_t group; /**< Priority group. */
>>> + uint32_t priority; /**< Priority level within group. */
>>> + uint32_t ingress:1; /**< Rule applies to ingress traffic. */
>>> + uint32_t egress:1; /**< Rule applies to egress traffic. */
>>> + uint32_t reserved:30; /**< Reserved, must be zero. */
>>> +};
> [...]
>>> +/**
>>> + * RTE_FLOW_ITEM_TYPE_VF
>>> + *
>>> + * Matches packets addressed to a virtual function ID of the device.
>>> + *
>>> + * If the underlying device function differs from the one that would
>>> + * normally receive the matched traffic, specifying this item prevents it
>>> + * from reaching that device unless the flow rule contains a VF
>>> + * action. Packets are not duplicated between device instances by default.
>>> + *
>>> + * - Likely to return an error or never match any traffic if this causes a
>>> + * VF device to match traffic addressed to a different VF.
>>> + * - Can be specified multiple times to match traffic addressed to several
>>> + * specific VFs.
>>> + * - Can be combined with a PF item to match both PF and VF traffic.
>>> + *
>>> + * A zeroed mask can be used to match any VF.
>>
>> can you refer explicitly to id
>
> If you mean "VF" to "VF ID" then yes, will do it for v2.
>
>>> + */
>>> +struct rte_flow_item_vf {
>>> + uint32_t id; /**< Destination VF ID. */
>>> +};
> [...]
>>> +/**
>>> + * Matching pattern item definition.
>>> + *
>>> + * A pattern is formed by stacking items starting from the lowest protocol
>>> + * layer to match. This stacking restriction does not apply to meta items
>>> + * which can be placed anywhere in the stack with no effect on the meaning
>>> + * of the resulting pattern.
>>> + *
>>> + * A stack is terminated by a END item.
>>> + *
>>> + * The spec field should be a valid pointer to a structure of the related
>>> + * item type. It may be set to NULL in many cases to use default values.
>>> + *
>>> + * Optionally, last can point to a structure of the same type to define an
>>> + * inclusive range. This is mostly supported by integer and address fields,
>>> + * may cause errors otherwise. Fields that do not support ranges must be set
>>> + * to the same value as their spec counterparts.
>>> + *
>>> + * By default all fields present in spec are considered relevant.* This
>>
>> typo "*"
>
> No, that's an asterisk for a footnote below. Perhaps it is a bit unusual,
> would something like "[1]" look better?
oh, I thought it was the start of a comment line gone astray. Maybe "See
note below", no big deal though.
>
>>> + * behavior can be altered by providing a mask structure of the same type
>>> + * with applicable bits set to one. It can also be used to partially filter
>>> + * out specific fields (e.g. as an alternate mean to match ranges of IP
>>> + * addresses).
>>> + *
>>> + * Note this is a simple bit-mask applied before interpreting the contents
>>> + * of spec and last, which may yield unexpected results if not used
>>> + * carefully. For example, if for an IPv4 address field, spec provides
>>> + * 10.1.2.3, last provides 10.3.4.5 and mask provides 255.255.0.0, the
>>> + * effective range is 10.1.0.0 to 10.3.255.255.
>>> + *
>
> See footnote below:
>
>>> + * * The defaults for data-matching items such as IPv4 when mask is not
>>> + * specified actually depend on the underlying implementation since only
>>> + * recognized fields can be taken into account.
>>> + */
>>> +struct rte_flow_item {
>>> + enum rte_flow_item_type type; /**< Item type. */
>>> + const void *spec; /**< Pointer to item specification structure. */
>>> + const void *last; /**< Defines an inclusive range (spec to last). */
>>> + const void *mask; /**< Bit-mask applied to spec and last. */
>>> +};
>>> +
>>> +/**
>>> + * Action types.
>>> + *
>>> + * Each possible action is represented by a type. Some have associated
>>> + * configuration structures. Several actions combined in a list can be
>>> + * affected to a flow rule. That list is not ordered.
>>> + *
>>> + * They fall in three categories:
>>> + *
>>> + * - Terminating actions (such as QUEUE, DROP, RSS, PF, VF) that prevent
>>> + * processing matched packets by subsequent flow rules, unless overridden
>>> + * with PASSTHRU.
>>> + *
>>> + * - Non terminating actions (PASSTHRU, DUP) that leave matched packets up
>>> + * for additional processing by subsequent flow rules.
>>> + *
>>> + * - Other non terminating meta actions that do not affect the fate of
>>> + * packets (END, VOID, MARK, FLAG, COUNT).
>>> + *
>>> + * When several actions are combined in a flow rule, they should all have
>>> + * different types (e.g. dropping a packet twice is not possible). The
>>> + * defined behavior is for PMDs to only take into account the last action of
>>> + * a given type found in the list. PMDs still perform error checking on the
>>> + * entire list.
>>
>> why do you define that the pmd will interpret multiple same type rules
>> in this way...would it not make more sense for the pmd to just return
>> EINVAL for an invalid set of rules? It seems more transparent for the
>> application.
>
> Well, I had to define something as a default. The reason is that any number
> of VOID actions may specified and did not want that to be a special case in
> order to keep PMD parsers as simple as possible. I'll settle for EINVAL (or
> some other error) if at least one PMD maintainer other than Nelio who
> intends to implement this API is not convinced by this explanation, all
> right?
>From an API perspective I think it's cleaner to pass or fail with the
input rather than change it. But yes, please take pmd maintainers input
as to what is reasonable to check also.
>
> [...]
>>> +/**
>>> + * RTE_FLOW_ACTION_TYPE_MARK
>>> + *
>>> + * Attaches a 32 bit value to packets.
>>> + *
>>> + * This value is arbitrary and application-defined. For compatibility with
>>> + * FDIR it is returned in the hash.fdir.hi mbuf field. PKT_RX_FDIR_ID is
>>> + * also set in ol_flags.
>>> + */
>>> +struct rte_flow_action_mark {
>>> + uint32_t id; /**< 32 bit value to return with packets. */
>>> +};
>>
>> One use case I thought we would be able to do for OVS is classification
>> in hardware and the unique flow id is sent with the packet to software.
>> But in OVS the ufid is 128 bits, so it means we can't and there is still
>> the miniflow extract overhead. I'm not sure if there is a practical way
>> around this.
>>
>> Sugesh (cc'd) has looked at this before and may be able to comment or
>> correct me.
>
> Yes, we settled on 32 bit because currently no known hardware implementation
> supports more than this. If that changes, another action with a larger type
> shall be provided (no ABI breakage).
>
> Also since even 64 bit would not be enough for the use case you mention,
> there is no choice but use this as an indirect value (such as an array or
> hash table index/value).
ok, cool. I think Sugesh has other ideas anyway!
>
> [...]
>>> +/**
>>> + * RTE_FLOW_ACTION_TYPE_RSS
>>> + *
>>> + * Similar to QUEUE, except RSS is additionally performed on packets to
>>> + * spread them among several queues according to the provided parameters.
>>> + *
>>> + * Note: RSS hash result is normally stored in the hash.rss mbuf field,
>>> + * however it conflicts with the MARK action as they share the same
>>> + * space. When both actions are specified, the RSS hash is discarded and
>>> + * PKT_RX_RSS_HASH is not set in ol_flags. MARK has priority. The mbuf
>>> + * structure should eventually evolve to store both.
>>> + *
>>> + * Terminating by default.
>>> + */
>>> +struct rte_flow_action_rss {
>>> + const struct rte_eth_rss_conf *rss_conf; /**< RSS parameters. */
>>> + uint16_t queues; /**< Number of entries in queue[]. */
>>> + uint16_t queue[]; /**< Queues indices to use. */
>>
>> I'd try and avoid queue and queues - someone will say "huh?" when
>> reading code. s/queues/num ?
>
> Agreed, will update for v2.
>
>>> +};
>>> +
>>> +/**
>>> + * RTE_FLOW_ACTION_TYPE_VF
>>> + *
>>> + * Redirects packets to a virtual function (VF) of the current device.
>>> + *
>>> + * Packets matched by a VF pattern item can be redirected to their original
>>> + * VF ID instead of the specified one. This parameter may not be available
>>> + * and is not guaranteed to work properly if the VF part is matched by a
>>> + * prior flow rule or if packets are not addressed to a VF in the first
>>> + * place.
>>
>> Not clear what you mean by "not guaranteed to work if...". Please return
>> fail when this action is used if this is not going to work.
>
> Again, this is a case where it is difficult for a PMD to determine if the
> entire list of flow rules makes sense. Perhaps it does, perhaps whatever
> goes through has already been filtered out of possible issues.
>
> Here the documentation states the precautions an application should take to
> guarantee it will work as intended. Perhaps it can be reworded (any
> suggestion?), but a PMD can certainly not provide any strong guarantee.
I see your point. Maybe for easy check things the pmd would return fail,
but for more complex I agree it's too difficult.
>
>>> + *
>>> + * Terminating by default.
>>> + */
>>> +struct rte_flow_action_vf {
>>> + uint32_t original:1; /**< Use original VF ID if possible. */
>>> + uint32_t reserved:31; /**< Reserved, must be zero. */
>>> + uint32_t id; /**< VF ID to redirect packets to. */
>>> +};
> [...]
>>> +/**
>>> + * Check whether a flow rule can be created on a given port.
>>> + *
>>> + * While this function has no effect on the target device, the flow rule is
>>> + * validated against its current configuration state and the returned value
>>> + * should be considered valid by the caller for that state only.
>>> + *
>>> + * The returned value is guaranteed to remain valid only as long as no
>>> + * successful calls to rte_flow_create() or rte_flow_destroy() are made in
>>> + * the meantime and no device parameter affecting flow rules in any way are
>>> + * modified, due to possible collisions or resource limitations (although in
>>> + * such cases EINVAL should not be returned).
>>> + *
>>> + * @param port_id
>>> + * Port identifier of Ethernet device.
>>> + * @param[in] attr
>>> + * Flow rule attributes.
>>> + * @param[in] pattern
>>> + * Pattern specification (list terminated by the END pattern item).
>>> + * @param[in] actions
>>> + * Associated actions (list terminated by the END action).
>>> + * @param[out] error
>>> + * Perform verbose error reporting if not NULL.
>>> + *
>>> + * @return
>>> + * 0 if flow rule is valid and can be created. A negative errno value
>>> + * otherwise (rte_errno is also set), the following errors are defined:
>>> + *
>>> + * -ENOSYS: underlying device does not support this functionality.
>>> + *
>>> + * -EINVAL: unknown or invalid rule specification.
>>> + *
>>> + * -ENOTSUP: valid but unsupported rule specification (e.g. partial
>>> + * bit-masks are unsupported).
>>> + *
>>> + * -EEXIST: collision with an existing rule.
>>> + *
>>> + * -ENOMEM: not enough resources.
>>> + *
>>> + * -EBUSY: action cannot be performed due to busy device resources, may
>>> + * succeed if the affected queues or even the entire port are in a stopped
>>> + * state (see rte_eth_dev_rx_queue_stop() and rte_eth_dev_stop()).
>>> + */
>>> +int
>>> +rte_flow_validate(uint8_t port_id,
>>> + const struct rte_flow_attr *attr,
>>> + const struct rte_flow_item pattern[],
>>> + const struct rte_flow_action actions[],
>>> + struct rte_flow_error *error);
>>
>> Why not just use rte_flow_create() and get an error? Is it less
>> disruptive to do a validate and find the rule cannot be created, than
>> using a create directly?
>
> The rationale can be found in the original RFC, which I'll convert to actual
> documentation in v2. In short:
>
> - Calling rte_flow_validate() before rte_flow_create() is useless since
> rte_flow_create() also performs validation.
>
> - We cannot possibly express a full static set of allowed flow rules, even
> if we could, it usually depends on the current hardware configuration
> therefore would not be static.
>
> - rte_flow_validate() is thus provided as a replacement for capability
> flags. It can be used to determine during initialization if the underlying
> device can support the typical flow rules an application might want to
> provide later and do something useful with that information (e.g. always
> use software fallback due to HW limitations).
>
> - rte_flow_validate() being a subset of rte_flow_create(), it is essentially
> free to expose.
make sense now, thanks.
>
>>> +
>>> +/**
>>> + * Create a flow rule on a given port.
>>> + *
>>> + * @param port_id
>>> + * Port identifier of Ethernet device.
>>> + * @param[in] attr
>>> + * Flow rule attributes.
>>> + * @param[in] pattern
>>> + * Pattern specification (list terminated by the END pattern item).
>>> + * @param[in] actions
>>> + * Associated actions (list terminated by the END action).
>>> + * @param[out] error
>>> + * Perform verbose error reporting if not NULL.
>>> + *
>>> + * @return
>>> + * A valid handle in case of success, NULL otherwise and rte_errno is set
>>> + * to the positive version of one of the error codes defined for
>>> + * rte_flow_validate().
>>> + */
>>> +struct rte_flow *
>>> +rte_flow_create(uint8_t port_id,
>>> + const struct rte_flow_attr *attr,
>>> + const struct rte_flow_item pattern[],
>>> + const struct rte_flow_action actions[],
>>> + struct rte_flow_error *error);
>>
>> General question - are these functions threadsafe? In the OVS example
>> you could have several threads wanting to create flow rules at the same
>> time for same or different ports.
>
> No they aren't, applications have to perform their own locking. The RFC (to
> be converted to actual documentation in v2) says that:
>
> - API operations are synchronous and blocking (``EAGAIN`` cannot be
> returned).
>
> - There is no provision for reentrancy/multi-thread safety, although nothing
> should prevent different devices from being configured at the same
> time. PMDs may protect their control path functions accordingly.
other comment above wrt locking.
>
>>> +
>>> +/**
>>> + * Destroy a flow rule on a given port.
>>> + *
>>> + * Failure to destroy a flow rule handle may occur when other flow rules
>>> + * depend on it, and destroying it would result in an inconsistent state.
>>> + *
>>> + * This function is only guaranteed to succeed if handles are destroyed in
>>> + * reverse order of their creation.
>>
>> How can the application find this information out on error?
>
> Without maintaining a list, they cannot. The specified case is the only
> possible guarantee. That does not mean PMDs should not do their best to
> destroy flow rules, only that ordering must remain consistent in case of
> inability to destroy one.
>
> What do you suggest?
I think if the app cannot remove a specific rule it may want to remove
all rules and deal with flows in software for a time. So once the app
knows it fails that should be enough.
>
>>> + *
>>> + * @param port_id
>>> + * Port identifier of Ethernet device.
>>> + * @param flow
>>> + * Flow rule handle to destroy.
>>> + * @param[out] error
>>> + * Perform verbose error reporting if not NULL.
>>> + *
>>> + * @return
>>> + * 0 on success, a negative errno value otherwise and rte_errno is set.
>>> + */
>>> +int
>>> +rte_flow_destroy(uint8_t port_id,
>>> + struct rte_flow *flow,
>>> + struct rte_flow_error *error);
>>> +
>>> +/**
>>> + * Destroy all flow rules associated with a port.
>>> + *
>>> + * In the unlikely event of failure, handles are still considered destroyed
>>> + * and no longer valid but the port must be assumed to be in an inconsistent
>>> + * state.
>>> + *
>>> + * @param port_id
>>> + * Port identifier of Ethernet device.
>>> + * @param[out] error
>>> + * Perform verbose error reporting if not NULL.
>>> + *
>>> + * @return
>>> + * 0 on success, a negative errno value otherwise and rte_errno is set.
>>> + */
>>> +int
>>> +rte_flow_flush(uint8_t port_id,
>>> + struct rte_flow_error *error);
>>
>> rte_flow_destroy_all() would be more descriptive (but breaks your style)
>
> There are enough underscores as it is. I like flush, if enough people
> complain we'll change it but it has to occur before the first public
> release.
>
>>> +
>>> +/**
>>> + * Query an existing flow rule.
>>> + *
>>> + * This function allows retrieving flow-specific data such as counters.
>>> + * Data is gathered by special actions which must be present in the flow
>>> + * rule definition.
>>
>> re last sentence, it would be good if you can put a link to
>> RTE_FLOW_ACTION_TYPE_COUNT
>
> Will do, I did not know how until very recently.
>
>>> + *
>>> + * @param port_id
>>> + * Port identifier of Ethernet device.
>>> + * @param flow
>>> + * Flow rule handle to query.
>>> + * @param action
>>> + * Action type to query.
>>> + * @param[in, out] data
>>> + * Pointer to storage for the associated query data type.
>>
>> can this be anything other than rte_flow_query_count?
>
> Likely in the future. I've only defined this one as a counterpart for
> existing API functionality and because we wanted to expose it in mlx5.
>
>>> + * @param[out] error
>>> + * Perform verbose error reporting if not NULL.
>>> + *
>>> + * @return
>>> + * 0 on success, a negative errno value otherwise and rte_errno is set.
>>> + */
>>> +int
>>> +rte_flow_query(uint8_t port_id,
>>> + struct rte_flow *flow,
>>> + enum rte_flow_action_type action,
>>> + void *data,
>>> + struct rte_flow_error *error);
>>> +
>>> +#ifdef __cplusplus
>>> +}
>>> +#endif
>>
>> I don't see a way to dump all the rules for a port out. I think this is
>> neccessary for degbugging. You could have a look through dpif.h in OVS
>> and see how dpif_flow_dump_next() is used, it might be a good reference.
>
> DPDK does not maintain flow rules and, depending on hardware capabilities
> and level of compliance, PMDs do not necessarily do it either, particularly
> since it requires space and application probably have a better method to
> store these pointers for their own needs.
understood
>
> What you see here is only a PMD interface. Depending on applications needs,
> generic helper functions built on top of these may be added to manage flow
> rules in the future.
I'm thinking of the case where something goes wrong and I want to get a
dump of all the flow rules from hardware, not query the rules I think I
have. I don't see a way to do it or something to build a helper on top of?
>
>> Also, it would be nice if there were an api that would allow a test
>> packet to be injected and traced for debugging - although I'm not
>> exactly sure how well it could be traced. For reference:
>> http://developers.redhat.com/blog/2016/10/12/tracing-packets-inside-open-vswitch/
>
> Thanks for the link, I'm not sure how you'd do this either. Remember, as
> generic as it looks, this interface is only meant to configure the
> underlying device. You need to see it as one big offload, everything else
> is left to applications.
>
^ permalink raw reply
* Re: [RFC PATCH] eventdev: add buffered enqueue and flush APIs
From: Jerin Jacob @ 2016-12-02 21:18 UTC (permalink / raw)
To: Gage Eads; +Cc: dev, bruce.richardson, harry.van.haaren, hemant.agrawal
In-Reply-To: <1480707956-17187-2-git-send-email-gage.eads@intel.com>
On Fri, Dec 02, 2016 at 01:45:56PM -0600, Gage Eads wrote:
> This commit adds buffered enqueue functionality to the eventdev API.
> It is conceptually similar to the ethdev API's tx buffering, however
> with a smaller API surface and no dropping of events.
Hello Gage,
Different implementation may have different strategies to hold the buffers.
and some does not need to hold the buffers if it is DDR backed.
IHMO, This may not be the candidate for common code. I guess you can move this
to driver side and abstract under SW driver's enqueue_burst.
>
> Signed-off-by: Gage Eads <gage.eads@intel.com>
> ---
> lib/librte_eventdev/rte_eventdev.c | 29 ++++++++++
> lib/librte_eventdev/rte_eventdev.h | 106 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 135 insertions(+)
>
> diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
> index 17ce5c3..564573f 100644
> --- a/lib/librte_eventdev/rte_eventdev.c
> +++ b/lib/librte_eventdev/rte_eventdev.c
> @@ -219,6 +219,7 @@
> uint16_t *links_map;
> uint8_t *ports_dequeue_depth;
> uint8_t *ports_enqueue_depth;
> + struct rte_eventdev_enqueue_buffer *port_buffers;
> unsigned int i;
>
> EDEV_LOG_DEBUG("Setup %d ports on device %u", nb_ports,
> @@ -272,6 +273,19 @@
> "nb_ports %u", nb_ports);
> return -(ENOMEM);
> }
> +
> + /* Allocate memory to store port enqueue buffers */
> + dev->data->port_buffers =
> + rte_zmalloc_socket("eventdev->port_buffers",
> + sizeof(dev->data->port_buffers[0]) * nb_ports,
> + RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> + if (dev->data->port_buffers == NULL) {
> + dev->data->nb_ports = 0;
> + EDEV_LOG_ERR("failed to get memory for port enq"
> + " buffers, nb_ports %u", nb_ports);
> + return -(ENOMEM);
> + }
> +
> } else if (dev->data->ports != NULL && nb_ports != 0) {/* re-config */
> RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release, -ENOTSUP);
>
> @@ -279,6 +293,7 @@
> ports_dequeue_depth = dev->data->ports_dequeue_depth;
> ports_enqueue_depth = dev->data->ports_enqueue_depth;
> links_map = dev->data->links_map;
> + port_buffers = dev->data->port_buffers;
>
> for (i = nb_ports; i < old_nb_ports; i++)
> (*dev->dev_ops->port_release)(ports[i]);
> @@ -324,6 +339,17 @@
> return -(ENOMEM);
> }
>
> + /* Realloc memory to store port enqueue buffers */
> + port_buffers = rte_realloc(dev->data->port_buffers,
> + sizeof(dev->data->port_buffers[0]) * nb_ports,
> + RTE_CACHE_LINE_SIZE);
> + if (port_buffers == NULL) {
> + dev->data->nb_ports = 0;
> + EDEV_LOG_ERR("failed to realloc mem for port enq"
> + " buffers, nb_ports %u", nb_ports);
> + return -(ENOMEM);
> + }
> +
> if (nb_ports > old_nb_ports) {
> uint8_t new_ps = nb_ports - old_nb_ports;
>
> @@ -336,12 +362,15 @@
> memset(links_map +
> (old_nb_ports * RTE_EVENT_MAX_QUEUES_PER_DEV),
> 0, sizeof(ports_enqueue_depth[0]) * new_ps);
> + memset(port_buffers + old_nb_ports, 0,
> + sizeof(port_buffers[0]) * new_ps);
> }
>
> dev->data->ports = ports;
> dev->data->ports_dequeue_depth = ports_dequeue_depth;
> dev->data->ports_enqueue_depth = ports_enqueue_depth;
> dev->data->links_map = links_map;
> + dev->data->port_buffers = port_buffers;
> } else if (dev->data->ports != NULL && nb_ports == 0) {
> RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release, -ENOTSUP);
>
> diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
> index 778d6dc..3f24342 100644
> --- a/lib/librte_eventdev/rte_eventdev.h
> +++ b/lib/librte_eventdev/rte_eventdev.h
> @@ -246,6 +246,7 @@
> #include <rte_dev.h>
> #include <rte_memory.h>
> #include <rte_errno.h>
> +#include <rte_memcpy.h>
>
> #define EVENTDEV_NAME_SKELETON_PMD event_skeleton
> /**< Skeleton event device PMD name */
> @@ -965,6 +966,26 @@ typedef uint16_t (*event_dequeue_burst_t)(void *port, struct rte_event ev[],
> #define RTE_EVENTDEV_NAME_MAX_LEN (64)
> /**< @internal Max length of name of event PMD */
>
> +#define RTE_EVENT_BUF_MAX 16
> +/**< Maximum number of events in an enqueue buffer. */
> +
> +/**
> + * @internal
> + * An enqueue buffer for each port.
> + *
> + * The reason this struct is in the header is for inlining the function calls
> + * to enqueue, as doing a function call per packet would incur significant
> + * performance overhead.
> + *
> + * \see rte_event_enqueue_buffer(), rte_event_enqueue_buffer_flush()
> + */
> +struct rte_eventdev_enqueue_buffer {
> + /**> Count of events in this buffer */
> + uint16_t count;
> + /**> Array of events in this buffer */
> + struct rte_event events[RTE_EVENT_BUF_MAX];
> +} __rte_cache_aligned;
> +
> /**
> * @internal
> * The data part, with no function pointers, associated with each device.
> @@ -983,6 +1004,8 @@ struct rte_eventdev_data {
> /**< Number of event ports. */
> void **ports;
> /**< Array of pointers to ports. */
> + struct rte_eventdev_enqueue_buffer *port_buffers;
> + /**< Array of port enqueue buffers. */
> uint8_t *ports_dequeue_depth;
> /**< Array of port dequeue depth. */
> uint8_t *ports_enqueue_depth;
> @@ -1132,6 +1155,89 @@ struct rte_eventdev {
> }
>
> /**
> + * Flush the enqueue buffer of the event port specified by *port_id*, in the
> + * event device specified by *dev_id*.
> + *
> + * This function attempts to flush as many of the buffered events as possible,
> + * and returns the number of flushed events. Any unflushed events remain in
> + * the buffer.
> + *
> + * @param dev_id
> + * The identifier of the device.
> + * @param port_id
> + * The identifier of the event port.
> + *
> + * @return
> + * The number of event objects actually flushed to the event device.
> + *
> + * \see rte_event_enqueue_buffer(), rte_event_enqueue_burst()
> + * \see rte_event_port_enqueue_depth()
> + */
> +static inline int
> +rte_event_enqueue_buffer_flush(uint8_t dev_id, uint8_t port_id)
> +{
> + struct rte_eventdev *dev = &rte_eventdevs[dev_id];
> + struct rte_eventdev_enqueue_buffer *buf =
> + &dev->data->port_buffers[port_id];
> + int n;
> +
> + n = rte_event_enqueue_burst(dev_id, port_id, buf->events, buf->count);
> +
> + if (n != buf->count)
> + memmove(buf->events, &buf->events[n], buf->count - n);
> +
> + buf->count -= n;
> +
> + return n;
> +}
> +
> +/**
> + * Buffer an event object supplied in *rte_event* structure for future
> + * enqueueing on an event device designated by its *dev_id* through the event
> + * port specified by *port_id*.
> + *
> + * This function takes a single event and buffers it for later enqueuing to the
> + * queue specified in the event structure. If the buffer is full, the
> + * function will attempt to flush the buffer before buffering the event.
> + * If the flush operation fails, the previously buffered events remain in the
> + * buffer and an error is returned to the user to indicate that *ev* was not
> + * buffered.
> + *
> + * @param dev_id
> + * The identifier of the device.
> + * @param port_id
> + * The identifier of the event port.
> + * @param ev
> + * Pointer to struct rte_event
> + *
> + * @return
> + * - 0 on success
> + * - <0 on failure. Failure can occur if the event port's output queue is
> + * backpressured, for instance.
> + *
> + * \see rte_event_enqueue_buffer_flush(), rte_event_enqueue_burst()
> + * \see rte_event_port_enqueue_depth()
> + */
> +static inline int
> +rte_event_enqueue_buffer(uint8_t dev_id, uint8_t port_id, struct rte_event *ev)
> +{
> + struct rte_eventdev *dev = &rte_eventdevs[dev_id];
> + struct rte_eventdev_enqueue_buffer *buf =
> + &dev->data->port_buffers[port_id];
> + int ret;
> +
> + /* If necessary, flush the enqueue buffer to make space for ev. */
> + if (buf->count == RTE_EVENT_BUF_MAX) {
> + ret = rte_event_enqueue_buffer_flush(dev_id, port_id);
> + if (ret == 0)
> + return -ENOSPC;
> + }
> +
> + rte_memcpy(&buf->events[buf->count++], ev, sizeof(struct rte_event));
> + return 0;
> +}
> +
> +/**
> * Converts nanoseconds to *wait* value for rte_event_dequeue()
> *
> * If the device is configured with RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT flag then
> --
> 1.9.1
>
^ permalink raw reply
* Question about IXGBEVF reset
From: Ruslan Nikolaev @ 2016-12-02 22:28 UTC (permalink / raw)
To: dev
Hi
I was having a discussion on the IXGBE mailing list regarding RESET due to lost link mailbox message and its handling in DPDK:
http://lists.osuosl.org/pipermail/intel-wired-lan/Week-of-Mon-20161128/007389.html
I was wondering what can be done regarding this issue. Particularly, the patch
http://dpdk.org/dev/patchwork/patch/14009/
does seem to have an assumption that a link will be up sooner or later.
The problem with that is the link may go down for arbitrarily long time (and the ixgbe driver will issue the reset mailbox message due to ’Tx work pending’). We can call ixgbevf_dev_stop at this point but we cannot safely run ixgbevf_dev_start. Do you have any suggestion how to handle this case? Also, is there any better (more recent) patch to handle this?
Thanks,
Ruslan Nikolaev
^ permalink raw reply
* Re: [RFC] igb_uio: deprecate iomem and ioport mapping
From: Stephen Hemminger @ 2016-12-02 23:47 UTC (permalink / raw)
To: Jianfeng Tan; +Cc: dev, david.marchand, ferruh.yigit
In-Reply-To: <1472696197-37614-1-git-send-email-jianfeng.tan@intel.com>
On Thu, 1 Sep 2016 02:16:37 +0000
Jianfeng Tan <jianfeng.tan@intel.com> wrote:
> Previously in igb_uio, iomem is mapped, and both ioport and io mem
> are recorded into uio framework, which is duplicated and makes the
> code too complex.
>
> For iomem, DPDK user space code never opens or reads files under
> /sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/maps/. Instead,
> /sys/pci/bus/devices/xxxx:xx:xx.x/resourceY are used to map device
> memory.
>
> For ioport, non-x86 platforms cannot read from files under
> /sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/portio/ directly, because
> non-x86 platforms need to map port region for access in user space,
> see non-x86 version pci_uio_ioport_map(). x86 platforms can use the
> the same way as uio_pci_generic.
>
> This patch deprecates iomem and ioport mapping in igb_uio kernel
> module, and adjusts the iomem implementation in both igb_uio and
> uio_pci_generic:
> - for x86 platform, get ports info from /proc/ioports;
> - for non-x86 platform, map and get ports info by pci_uio_ioport_map().
>
> Note: this will affect those applications who are using files under
> /sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/maps/ and
> /sys/pci/bus/devices/xxxx:xx:xx.x/uio/uioY/portio/.
>
> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
What about people using older kernels with the new DPDK EAL and
vice versa? It makes sense to make igb_uio generic for non DPDK
usage, so it should probably follow the other UIO drivers.
^ permalink raw reply
* Re: [PATCH v12 0/6] add Tx preparation
From: Yong Wang @ 2016-12-02 23:55 UTC (permalink / raw)
To: Thomas Monjalon, Ananyev, Konstantin
Cc: Harish Patil, dev@dpdk.org, Rahul Lakkireddy, Stephen Hurd,
Jan Medala, Jakub Palider, John Daley, Adrien Mazarguil,
Alejandro Lucero, Rasesh Mody, Jacob, Jerin, Yuanhan Liu,
Kulasek, TomaszX, olivier.matz@6wind.com
In-Reply-To: <3517413.XL3bTbAyaC@xps13>
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, November 30, 2016 10:27 AM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Cc: Harish Patil <harish.patil@qlogic.com>; dev@dpdk.org; Rahul Lakkireddy
> <rahul.lakkireddy@chelsio.com>; Stephen Hurd
> <stephen.hurd@broadcom.com>; Jan Medala <jan@semihalf.com>; Jakub
> Palider <jpa@semihalf.com>; John Daley <johndale@cisco.com>; Adrien
> Mazarguil <adrien.mazarguil@6wind.com>; Alejandro Lucero
> <alejandro.lucero@netronome.com>; Rasesh Mody
> <rasesh.mody@qlogic.com>; Jacob, Jerin <Jerin.Jacob@cavium.com>;
> Yuanhan Liu <yuanhan.liu@linux.intel.com>; Yong Wang
> <yongwang@vmware.com>; Kulasek, TomaszX
> <tomaszx.kulasek@intel.com>; olivier.matz@6wind.com
> Subject: Re: [dpdk-dev] [PATCH v12 0/6] add Tx preparation
>
> 2016-11-30 17:42, Ananyev, Konstantin:
> > > >Please, we need a comment for each driver saying
> > > >"it is OK, we do not need any checksum preparation for TSO"
> > > >or
> > > >"yes we have to implement tx_prepare or TSO will not work in this
> mode"
> > > >
> > >
> > > qede PMD doesn’t currently support TSO yet, it only supports Tx
> TCP/UDP/IP
> > > csum offloads.
> > > So Tx preparation isn’t applicable. So as of now -
> > > "it is OK, we do not need any checksum preparation for TSO"
> >
> > Thanks for the answer.
> > Though please note that it not only for TSO.
>
> Oh yes, sorry, my wording was incorrect.
> We need to know if any checksum preparation is needed prior
> offloading its final computation to the hardware or driver.
> So the question applies to TSO and simple checksum offload.
>
> We are still waiting answers for
> bnxt, cxgbe, ena, nfp, thunderx, virtio and vmxnet3.
The case for a virtual device is a little bit more complicated as packets offloaded from a virtual device can eventually be delivered to another virtual NIC or different physical NICs that have different offload requirements. In ESX, the hypervisor will enforce that the packets offloaded will be something that the hardware expects. The contract for vmxnet3 is that the guest needs to fill in pseudo header checksum for both l4 checksum only and TSO + l4 checksum offload cases.
> > This is for any TX offload for which the upper layer SW would have
> > to modify the contents of the packet.
> > Though as I can see for qede neither PKT_TX_IP_CKSUM or
> PKT_TX_TCP_CKSUM
> > exhibits any extra requirements for the user.
> > Is that correct?
^ permalink raw reply
* [PATCH 00/31] net/i40e: base code update
From: Jingjing Wu @ 2016-12-03 1:18 UTC (permalink / raw)
To: dev; +Cc: jingjing.wu, helin.zhang
i40e base code upate. The main changes are:
- add clause22 and clause45 implementation for PHY registers accessing
- replace existing legacy memcpy() calls with i40e_memcpy() calls.
- use BIT() macro instead of bit fields
- add clear all WoL filters implementation
- add ERROR state for NVM update state machine
- add broadcast promiscuous control per VLAN
- remove unused X722_SUPPORT and I40E_NDIS_SUPPORT MARCOs
Jingjing Wu (31):
net/i40e/base: add encap csum VF offload flag
net/i40e/base: preserve extended PHY type field
net/i40e/base: remove unnecessary code
net/i40e/base: fix bit test mask
net/i40e/base: group base mode VF offload flags
net/i40e/base: fix long link down notification time
net/i40e/base: add media type detection for 25G link
net/i40e/base: add clause22 and clause45 implementation
net/i40e/base: add bus number info
net/i40e/base: add protocols when discover capabilities
net/i40e/base: pass unknown PHY type for unknown PHYs
net/i40e/base: replace memcpy
net/i40e/base: deprecating unused macro
net/i40e/base: remove FPK HyperV VF device ID
net/i40e/base: add FEC bits to PHY capabilities
net/i40e/base: use BIT() macro instead of bit fields
net/i40e/base: adjust 25G PHY type values
net/i40e/base: implement clear all WoL filters
net/i40e/base: implement set VSI full promisc mode
net/i40e/base: add defines for new aq command
net/i40e/base: save link FEC info from link up event
net/i40e/base: acquire NVM lock before reads on all devices
net/i40e/base: change shift values to hex
net/i40e/base: comment that udp port must be in Host order
net/i40e/base: remove duplicate definitions
net/i40e/base: add ERROR state for NVM update state machine
net/i40e/base: add broadcast promiscuous control per VLAN
net/i40e/base: avoid division by zero
net/i40e/base: fix byte order
net/i40e/base: remove unused marco
net/i40e: remove unused marco from PMD
drivers/net/i40e/Makefile | 2 +-
drivers/net/i40e/base/i40e_adminq.c | 4 +-
drivers/net/i40e/base/i40e_adminq_cmd.h | 51 ++--
drivers/net/i40e/base/i40e_common.c | 425 ++++++++++++++++++++++++++------
drivers/net/i40e/base/i40e_devids.h | 3 -
drivers/net/i40e/base/i40e_lan_hmc.c | 5 -
drivers/net/i40e/base/i40e_nvm.c | 52 ++--
drivers/net/i40e/base/i40e_prototype.h | 30 ++-
drivers/net/i40e/base/i40e_register.h | 2 -
drivers/net/i40e/base/i40e_type.h | 94 +++----
drivers/net/i40e/base/i40e_virtchnl.h | 5 +
drivers/net/i40e/i40e_ethdev.c | 40 ---
drivers/net/i40e/i40e_ethdev_vf.c | 1 -
13 files changed, 467 insertions(+), 247 deletions(-)
--
2.4.11
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox