[dpdk-dev,5/5] uio: integrate MSI-X support

Message ID 1431970814-25951-6-git-send-email-stephen@networkplumber.org (mailing list archive)
State Rejected, archived
Headers

Commit Message

Stephen Hemminger May 18, 2015, 5:40 p.m. UTC
  Add the new uio_msi as a supported driver model.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/librte_eal/common/include/rte_pci.h            |  1 +
 lib/librte_eal/linuxapp/eal/eal_interrupts.c       | 94 +++++++++++++++++++---
 lib/librte_eal/linuxapp/eal/eal_pci.c              |  4 +
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          | 59 ++++++++++++--
 lib/librte_eal/linuxapp/eal/eal_uio_msi.h          | 26 ++++++
 .../linuxapp/eal/include/exec-env/rte_interrupts.h |  1 +
 lib/librte_ether/rte_ethdev.c                      |  1 +
 tools/dpdk_nic_bind.py                             |  2 +-
 8 files changed, 166 insertions(+), 22 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/eal_uio_msi.h
  

Comments

Cunming Liang May 25, 2015, 8:55 a.m. UTC | #1
On 5/19/2015 1:40 AM, Stephen Hemminger wrote:
> +/* enable MSI-X interrupts */
> +static int
> +uio_msix_enable(struct rte_intr_handle *intr_handle)
> +{
> +	int i, max_intr;
> +
> +	if (!intr_handle->max_intr ||
> +	    intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
> +		max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
> +	else
> +		max_intr = intr_handle->max_intr;
> +
> +	/* Actual number of MSI-X interrupts might be less than requested */
> +	for (i = 0; i < max_intr; i++) {
> +		struct uio_msi_irq_set irqs = {
> +			.vec = i,
> +			.fd = intr_handle->efds[i],
> +		};
> +
> +		if (i == max_intr - 1)
> +			irqs.fd = intr_handle->fd;
> +
> +		if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {
It would be strange if using vfio_dev_fd in 'uio_msix_' related function.
> +			RTE_LOG(ERR, EAL,
> +				"Error enabling MSI-X event %u fd %d (%s)\n",
> +				irqs.vec, irqs.fd, strerror(errno));
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
>   /* map the PCI resource of a PCI device in virtual memory */
>   int
>   pci_uio_map_resource(struct rte_pci_device *dev)
>   {
> -	int i, map_idx;
> +	int i, fd, map_idx;
>   	char dirname[PATH_MAX];
> -	char cfgname[PATH_MAX];
>   	char devname[PATH_MAX]; /* contains the /dev/uioX */
>   	void *mapaddr;
>   	int uio_num;
> @@ -274,11 +304,15 @@ pci_uio_map_resource(struct rte_pci_device *dev)
>   	struct mapped_pci_resource *uio_res;
>   	struct mapped_pci_res_list *uio_res_list = RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
>   	struct pci_map *maps;
> +	char cfgname[PATH_MAX];
>   
>   	dev->intr_handle.fd = -1;
> -	dev->intr_handle.uio_cfg_fd = -1;
> +	dev->intr_handle.vfio_dev_fd = -1;
>   	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
>   
> +	for (i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++)
> +		dev->intr_handle.efds[i] = -1;
> +
>   	/* secondary processes - use already recorded details */
>   	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
>   		return pci_uio_map_secondary(dev);
> @@ -293,15 +327,15 @@ pci_uio_map_resource(struct rte_pci_device *dev)
>   	snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
>   
>   	/* save fd if in primary process */
> -	dev->intr_handle.fd = open(devname, O_RDWR);
> -	if (dev->intr_handle.fd < 0) {
> +	fd = open(devname, O_RDWR);
> +	if (fd < 0) {
>   		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
>   			devname, strerror(errno));
>   		return -1;
>   	}
>   
>   	snprintf(cfgname, sizeof(cfgname),
> -			"/sys/class/uio/uio%u/device/config", uio_num);
> +		 "/sys/class/uio/uio%u/device/config", uio_num);
>   	dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
>   	if (dev->intr_handle.uio_cfg_fd < 0) {
>   		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
> @@ -309,9 +343,17 @@ pci_uio_map_resource(struct rte_pci_device *dev)
>   		return -1;
>   	}
>   
> -	if (dev->kdrv == RTE_KDRV_IGB_UIO)
> +	if (dev->kdrv == RTE_KDRV_UIO_MSIX) {
> +		dev->intr_handle.vfio_dev_fd = fd;
I understand now uio_cfg_fd is used for uio configure and intx, so one 
additional event fd required by uio_msi for msi/msix other cause intr.
What about store it in epfd[max_intr - 1] or define a new 'uio_msi_efd' 
so as to avoid using vfio_dev_fd.
As uio_msi defines only to support msi/msix mode, while igb_uio support 
either intx or msix(one intr vector).
It makes confusing for user to choose which to insmod.
The ideal way probably be one uio kernel module support all mode, by new 
added ioctl it can configure which intr mode {intx, msi, msix}(by new 
eal option --uio-intr or merge with --vfio-intr to an unify --intr-mode) 
user app expect to use.

> +		dev->intr_handle.type = RTE_INTR_HANDLE_UIO_MSIX;
> +		if (pci_uio_msix_init(dev) < 0)
> +			return -1;
> +	} else if (dev->kdrv == RTE_KDRV_IGB_UIO) {
> +		dev->intr_handle.fd = fd;
>   		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
> -	else {
> +	} else {
> +
> +		dev->intr_handle.fd = fd;
>   		dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
>   
>   		/* set bus master that is not done by uio_pci_generic */
> @@ -460,6 +502,7 @@ pci_uio_unmap_resource(struct rte_pci_device *dev)
>   
>   	/* close fd if in primary process */
>   	close(dev->intr_handle.fd);
> +	close(dev->intr_handle.uio_cfg_fd);
>   
>   	dev->intr_handle.fd = -1;
>   	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
>
  
Stephen Hemminger May 25, 2015, 5:42 p.m. UTC | #2
On Mon, 25 May 2015 16:55:23 +0800
"Liang, Cunming" <cunming.liang@intel.com> wrote:

> > +			irqs.fd = intr_handle->fd;
> > +
> > +		if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {  
> It would be strange if using vfio_dev_fd in 'uio_msix_' related function.

Just minor variable name. The whole set of fd's etc, probably need better names..
  

Patch

diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 223d3cd..106f4f7 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -147,6 +147,7 @@  enum rte_kernel_driver {
 	RTE_KDRV_IGB_UIO,
 	RTE_KDRV_VFIO,
 	RTE_KDRV_UIO_GENERIC,
+	RTE_KDRV_UIO_MSIX,
 };
 
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index fd97fc4..8cdab58 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -66,6 +66,7 @@ 
 
 #include "eal_private.h"
 #include "eal_vfio.h"
+#include "eal_uio_msi.h"
 
 #define EAL_INTR_EPOLL_WAIT_FOREVER (-1)
 
@@ -89,9 +90,7 @@  union intr_pipefds{
  */
 union rte_intr_read_buffer {
 	int uio_intr_count;              /* for uio device */
-#ifdef VFIO_PRESENT
-	uint64_t vfio_intr_count;        /* for vfio device */
-#endif
+	uint64_t eventfd_count;		 /* for vfio and uio-msi */
 	uint64_t timerfd_num;            /* for timerfd */
 	char charbuf[16];                /* for others */
 };
@@ -356,6 +355,67 @@  vfio_disable_msix(struct rte_intr_handle *intr_handle) {
 }
 #endif
 
+/* enable MSI-X interrupts */
+static int
+uio_msix_enable(struct rte_intr_handle *intr_handle)
+{
+	int i, max_intr;
+
+	if (!intr_handle->max_intr ||
+	    intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
+		max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
+	else
+		max_intr = intr_handle->max_intr;
+
+	/* Actual number of MSI-X interrupts might be less than requested */
+	for (i = 0; i < max_intr; i++) {
+		struct uio_msi_irq_set irqs = {
+			.vec = i,
+			.fd = intr_handle->efds[i],
+		};
+
+		if (i == max_intr - 1)
+			irqs.fd = intr_handle->fd;
+
+		if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {
+			RTE_LOG(ERR, EAL,
+				"Error enabling MSI-X event %u fd %d (%s)\n",
+				irqs.vec, irqs.fd, strerror(errno));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* disable MSI-X interrupts */
+static int
+uio_msix_disable(struct rte_intr_handle *intr_handle)
+{
+	int i, max_intr;
+
+	if (!intr_handle->max_intr ||
+	    intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
+		max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
+	else
+		max_intr = intr_handle->max_intr;
+
+	for (i = 0; i < max_intr; i++) {
+		struct uio_msi_irq_set irqs = {
+			.vec = i,
+			.fd = -1,
+		};
+
+		if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {
+			RTE_LOG(ERR, EAL,
+				"Error disabling MSI-X event %u (%s)\n",
+				i, strerror(errno));
+			return -1;
+		}
+	}
+	return 0;
+}
+
 static int
 uio_intx_intr_disable(struct rte_intr_handle *intr_handle)
 {
@@ -584,6 +644,10 @@  rte_intr_enable(struct rte_intr_handle *intr_handle)
 		if (uio_intx_intr_enable(intr_handle))
 			return -1;
 		break;
+	case RTE_INTR_HANDLE_UIO_MSIX:
+		if (uio_msix_enable(intr_handle))
+			return -1;
+		break;
 	/* not used at this moment */
 	case RTE_INTR_HANDLE_ALARM:
 		return -1;
@@ -628,6 +692,10 @@  rte_intr_disable(struct rte_intr_handle *intr_handle)
 		if (uio_intx_intr_disable(intr_handle))
 			return -1;
 		break;
+	case RTE_INTR_HANDLE_UIO_MSIX:
+		if (uio_msix_disable(intr_handle))
+			return -1;
+		break;
 	/* not used at this moment */
 	case RTE_INTR_HANDLE_ALARM:
 		return -1;
@@ -696,16 +764,19 @@  eal_intr_process_interrupts(struct epoll_event *events, int nfds)
 		case RTE_INTR_HANDLE_UIO:
 			bytes_read = sizeof(buf.uio_intr_count);
 			break;
+
 		case RTE_INTR_HANDLE_ALARM:
 			bytes_read = sizeof(buf.timerfd_num);
 			break;
-#ifdef VFIO_PRESENT
+
+		case RTE_INTR_HANDLE_UIO_MSIX:
+#ifdef RTE_EAL_VFIO
 		case RTE_INTR_HANDLE_VFIO_MSIX:
 		case RTE_INTR_HANDLE_VFIO_MSI:
 		case RTE_INTR_HANDLE_VFIO_LEGACY:
-			bytes_read = sizeof(buf.vfio_intr_count);
-			break;
 #endif
+			bytes_read = sizeof(buf.eventfd_count);
+			break;
 		default:
 			bytes_read = 1;
 			break;
@@ -895,17 +966,14 @@  static void
 eal_intr_proc_rxtx_intr(int fd, struct rte_intr_handle *intr_handle)
 {
 	union rte_intr_read_buffer buf;
-	int bytes_read = 1;
+	int bytes_read = sizeof(buf.eventfd_count);
 
-	if (intr_handle->type != RTE_INTR_HANDLE_VFIO_MSIX) {
-		RTE_LOG(ERR, EAL, "intr type should be VFIO_MSIX\n");
+	if (intr_handle->type != RTE_INTR_HANDLE_VFIO_MSIX &&
+	    intr_handle->type != RTE_INTR_HANDLE_UIO_MSIX) {
+		RTE_LOG(ERR, EAL, "intr type should be VFIO_MSIX or UIO_MSIX\n");
 		return;
 	}
 
-#ifdef VFIO_PRESENT
-	bytes_read = sizeof(buf.vfio_intr_count);
-#endif
-
 	/**
 	 * read out to clear the ready-to-be-read flag
 	 * for epoll_wait.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index d2adc66..814dc7c 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -345,6 +345,8 @@  pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 			dev->kdrv = RTE_KDRV_IGB_UIO;
 		else if (!strcmp(driver, "uio_pci_generic"))
 			dev->kdrv = RTE_KDRV_UIO_GENERIC;
+		else if (!strcmp(driver, "uio_msi"))
+			dev->kdrv = RTE_KDRV_UIO_MSIX;
 		else
 			dev->kdrv = RTE_KDRV_UNKNOWN;
 	} else if (ret < 0) {
@@ -576,6 +578,7 @@  pci_map_device(struct rte_pci_device *dev)
 			ret = pci_vfio_map_resource(dev);
 #endif
 		break;
+	case RTE_KDRV_UIO_MSIX:
 	case RTE_KDRV_IGB_UIO:
 	case RTE_KDRV_UIO_GENERIC:
 		/* map resources for devices that use uio */
@@ -603,6 +606,7 @@  pci_unmap_device(struct rte_pci_device *dev)
 	case RTE_KDRV_VFIO:
 		RTE_LOG(ERR, EAL, "Hotplug doesn't support vfio yet\n");
 		break;
+	case RTE_KDRV_UIO_MSIX:
 	case RTE_KDRV_IGB_UIO:
 	case RTE_KDRV_UIO_GENERIC:
 		/* unmap resources for devices that use uio */
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index b5116a7..7eee828 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -38,6 +38,7 @@ 
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <linux/pci_regs.h>
+#include <sys/eventfd.h>
 
 #include <rte_log.h>
 #include <rte_pci.h>
@@ -259,13 +260,42 @@  pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
 	return uio_num;
 }
 
+static int
+pci_uio_msix_init(struct rte_pci_device *dev)
+{
+	int i, fd;
+
+	/* set up an eventfd for interrupts */
+	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+	if (fd < 0) {
+		RTE_LOG(ERR, EAL, "  cannot set up irq eventfd (%s)\n",
+			strerror(errno));
+		return -1;
+	}
+	dev->intr_handle.fd = fd;
+
+	/* an additional eventfd for each vector */
+	for (i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++) {
+		fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
+		if (fd < 0) {
+			RTE_LOG(ERR, EAL,
+				" cannot set up eventfd (%s)\n",
+				strerror(errno));
+			return -1;
+		}
+
+		dev->intr_handle.efds[i] = fd;
+	}
+
+	return 0;
+}
+
 /* map the PCI resource of a PCI device in virtual memory */
 int
 pci_uio_map_resource(struct rte_pci_device *dev)
 {
-	int i, map_idx;
+	int i, fd, map_idx;
 	char dirname[PATH_MAX];
-	char cfgname[PATH_MAX];
 	char devname[PATH_MAX]; /* contains the /dev/uioX */
 	void *mapaddr;
 	int uio_num;
@@ -274,11 +304,15 @@  pci_uio_map_resource(struct rte_pci_device *dev)
 	struct mapped_pci_resource *uio_res;
 	struct mapped_pci_res_list *uio_res_list = RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
 	struct pci_map *maps;
+	char cfgname[PATH_MAX];
 
 	dev->intr_handle.fd = -1;
-	dev->intr_handle.uio_cfg_fd = -1;
+	dev->intr_handle.vfio_dev_fd = -1;
 	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
 
+	for (i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++)
+		dev->intr_handle.efds[i] = -1;
+
 	/* secondary processes - use already recorded details */
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return pci_uio_map_secondary(dev);
@@ -293,15 +327,15 @@  pci_uio_map_resource(struct rte_pci_device *dev)
 	snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
 
 	/* save fd if in primary process */
-	dev->intr_handle.fd = open(devname, O_RDWR);
-	if (dev->intr_handle.fd < 0) {
+	fd = open(devname, O_RDWR);
+	if (fd < 0) {
 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
 			devname, strerror(errno));
 		return -1;
 	}
 
 	snprintf(cfgname, sizeof(cfgname),
-			"/sys/class/uio/uio%u/device/config", uio_num);
+		 "/sys/class/uio/uio%u/device/config", uio_num);
 	dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
 	if (dev->intr_handle.uio_cfg_fd < 0) {
 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
@@ -309,9 +343,17 @@  pci_uio_map_resource(struct rte_pci_device *dev)
 		return -1;
 	}
 
-	if (dev->kdrv == RTE_KDRV_IGB_UIO)
+	if (dev->kdrv == RTE_KDRV_UIO_MSIX) {
+		dev->intr_handle.vfio_dev_fd = fd;
+		dev->intr_handle.type = RTE_INTR_HANDLE_UIO_MSIX;
+		if (pci_uio_msix_init(dev) < 0)
+			return -1;
+	} else if (dev->kdrv == RTE_KDRV_IGB_UIO) {
+		dev->intr_handle.fd = fd;
 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
-	else {
+	} else {
+
+		dev->intr_handle.fd = fd;
 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
 
 		/* set bus master that is not done by uio_pci_generic */
@@ -460,6 +502,7 @@  pci_uio_unmap_resource(struct rte_pci_device *dev)
 
 	/* close fd if in primary process */
 	close(dev->intr_handle.fd);
+	close(dev->intr_handle.uio_cfg_fd);
 
 	dev->intr_handle.fd = -1;
 	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
diff --git a/lib/librte_eal/linuxapp/eal/eal_uio_msi.h b/lib/librte_eal/linuxapp/eal/eal_uio_msi.h
new file mode 100644
index 0000000..f01f302
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/eal_uio_msi.h
@@ -0,0 +1,26 @@ 
+/*
+ * UIO_MSI API definition
+ *
+ * Copyright (c) 2015 by Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef EAL_UIO_MSI_H
+#define EAL_UIO_MSI_H
+
+/* Driver is not upstream yet. */
+
+#include <sys/ioctl.h>
+
+struct uio_msi_irq_set {
+	uint32_t vec;
+	int fd;
+};
+
+#define UIO_MSI_BASE	0x86
+#define UIO_MSI_IRQ_SET	_IOW('I', UIO_MSI_BASE+1, struct uio_msi_irq_set)
+
+#endif
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 9843001..d3cf680 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -44,6 +44,7 @@  enum rte_intr_handle_type {
 	RTE_INTR_HANDLE_UNKNOWN = 0,
 	RTE_INTR_HANDLE_UIO,          /**< uio device handle */
 	RTE_INTR_HANDLE_UIO_INTX,     /**< uio generic handle */
+	RTE_INTR_HANDLE_UIO_MSIX,     /**< uio with MSI-X support */
 	RTE_INTR_HANDLE_VFIO_LEGACY,  /**< vfio device handle (legacy) */
 	RTE_INTR_HANDLE_VFIO_MSI,     /**< vfio device handle (MSI) */
 	RTE_INTR_HANDLE_VFIO_MSIX,    /**< vfio device handle (MSIX) */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index cf9a79a..3fbc4a1 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -515,6 +515,7 @@  rte_eth_dev_is_detachable(uint8_t port_id)
 		switch (rte_eth_devices[port_id].pci_dev->kdrv) {
 		case RTE_KDRV_IGB_UIO:
 		case RTE_KDRV_UIO_GENERIC:
+		case RTE_KDRV_UIO_MSIX:
 			break;
 		case RTE_KDRV_VFIO:
 		default:
diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py
index 8523f82..20b4b06 100755
--- a/tools/dpdk_nic_bind.py
+++ b/tools/dpdk_nic_bind.py
@@ -43,7 +43,7 @@  ETHERNET_CLASS = "0200"
 # Each device within this is itself a dictionary of device properties
 devices = {}
 # list of supported DPDK drivers
-dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic" ]
+dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic", "uio_msi" ]
 
 # command-line arg flags
 b_flag = None