diff mbox

[dpdk-dev] eal: allow virtual devices to be white/black listed

Message ID 1416173215-27533-1-git-send-email-nicolas.pernas.maradei@emutex.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Nicolás Pernas Maradei Nov. 16, 2014, 9:26 p.m. UTC
From: Nicolás Pernas Maradei <nico@emutex.com>

Virtual and physical devices are now treated the same in terms of
white/black listing. Virtual devices can be defined using --vdev as
before and also whitelisted (using -w vdev_name) or blacklisted (using -b
vdev_name). This allows the user to have only a virtual device (port) in
use.

Signed-off-by: Nicolás Pernas Maradei <nico@emutex.com>
---
 app/test-pmd/cmdline.c                      |   5 +-
 app/test/commands.c                         |   4 +-
 app/test/test_devargs.c                     |  69 +++++-----
 app/test/test_pci.c                         |   3 +-
 lib/librte_eal/bsdapp/eal/eal.c             |   8 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c         |   2 +-
 lib/librte_eal/common/eal_common_dev.c      |  24 ++--
 lib/librte_eal/common/eal_common_devargs.c  | 196 ++++++++++++++++++++--------
 lib/librte_eal/common/eal_common_options.c  |  11 +-
 lib/librte_eal/common/eal_common_pci.c      |  11 +-
 lib/librte_eal/common/include/rte_devargs.h | 124 +++++++++++++-----
 lib/librte_eal/linuxapp/eal/eal.c           |   8 +-
 lib/librte_eal/linuxapp/eal/eal_pci.c       |   2 +-
 13 files changed, 319 insertions(+), 148 deletions(-)

Comments

Neil Horman Nov. 17, 2014, 2:10 p.m. UTC | #1
On Sun, Nov 16, 2014 at 09:26:55PM +0000, Nicolás Pernas Maradei wrote:
> From: Nicolás Pernas Maradei <nico@emutex.com>
> 
> Virtual and physical devices are now treated the same in terms of
> white/black listing. Virtual devices can be defined using --vdev as
> before and also whitelisted (using -w vdev_name) or blacklisted (using -b
> vdev_name). This allows the user to have only a virtual device (port) in
> use.
> 
> Signed-off-by: Nicolás Pernas Maradei <nico@emutex.com>
> ---
>  app/test-pmd/cmdline.c                      |   5 +-
>  app/test/commands.c                         |   4 +-
>  app/test/test_devargs.c                     |  69 +++++-----
>  app/test/test_pci.c                         |   3 +-
>  lib/librte_eal/bsdapp/eal/eal.c             |   8 +-
>  lib/librte_eal/bsdapp/eal/eal_pci.c         |   2 +-
>  lib/librte_eal/common/eal_common_dev.c      |  24 ++--
>  lib/librte_eal/common/eal_common_devargs.c  | 196 ++++++++++++++++++++--------
>  lib/librte_eal/common/eal_common_options.c  |  11 +-
>  lib/librte_eal/common/eal_common_pci.c      |  11 +-
>  lib/librte_eal/common/include/rte_devargs.h | 124 +++++++++++++-----
>  lib/librte_eal/linuxapp/eal/eal.c           |   8 +-
>  lib/librte_eal/linuxapp/eal/eal_pci.c       |   2 +-
>  13 files changed, 319 insertions(+), 148 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 4c3fc76..f6ba4fe 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -6844,6 +6844,8 @@ static void cmd_dump_parsed(void *parsed_result,
>  		rte_mempool_list_dump(stdout);
>  	else if (!strcmp(res->dump, "dump_devargs"))
>  		rte_eal_devargs_dump(stdout);
> +	else if (!strcmp(res->dump, "dump_vdevargs"))
> +		rte_eal_vdevargs_dump(stdout);
>  }
>  
>  cmdline_parse_token_string_t cmd_dump_dump =
> @@ -6854,7 +6856,8 @@ cmdline_parse_token_string_t cmd_dump_dump =
>  		"dump_struct_sizes#"
>  		"dump_ring#"
>  		"dump_mempool#"
> -		"dump_devargs");
> +		"dump_devargs#"
> +		"dump_vdevargs");
>  
>  cmdline_parse_inst_t cmd_dump = {
>  	.f = cmd_dump_parsed,  /* function to call */
> diff --git a/app/test/commands.c b/app/test/commands.c
> index 92a17ed..6799d63 100644
> --- a/app/test/commands.c
> +++ b/app/test/commands.c
> @@ -161,13 +161,15 @@ static void cmd_dump_parsed(void *parsed_result,
>  		rte_mempool_list_dump(stdout);
>  	else if (!strcmp(res->dump, "dump_devargs"))
>  		rte_eal_devargs_dump(stdout);
> +	else if (!strcmp(res->dump, "dump_vdevargs"))
> +		rte_eal_vdevargs_dump(stdout);
>  }
>  
>  cmdline_parse_token_string_t cmd_dump_dump =
>  	TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump,
>  				 "dump_physmem#dump_memzone#dump_log_history#"
>  				 "dump_struct_sizes#dump_ring#dump_mempool#"
> -				 "dump_devargs");
> +				 "dump_devargs#dump_vdevargs");
>  
>  cmdline_parse_inst_t cmd_dump = {
>  	.f = cmd_dump_parsed,  /* function to call */
> diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> index f0acf8e..8fb93df 100644
> --- a/app/test/test_devargs.c
> +++ b/app/test/test_devargs.c
> @@ -52,52 +52,60 @@ static void free_devargs_list(void)
>  	}
>  }
>  
> +/* clear vdevargs list that was modified by the test */
> +static void free_vdevargs_list(void)
> +{
> +	struct rte_vdevargs *vdevargs;
> +
> +	while (!TAILQ_EMPTY(&vdevargs_list)) {
> +		vdevargs = TAILQ_FIRST(&vdevargs_list);
> +		TAILQ_REMOVE(&vdevargs_list, vdevargs, next);
> +		free(vdevargs);
> +	}
> +}
> +
>  static int
>  test_devargs(void)
>  {
>  	struct rte_devargs_list save_devargs_list;
> +	struct rte_vdevargs_list save_vdevargs_list;
>  	struct rte_devargs *devargs;
> +	struct rte_vdevargs *vdevargs;
>  
>  	/* save the real devargs_list, it is restored at the end of the test */
>  	save_devargs_list = devargs_list;
> +	save_vdevargs_list = vdevargs_list;
>  	TAILQ_INIT(&devargs_list);
> +	TAILQ_INIT(&vdevargs_list);
>  
>  	/* test valid cases */
> -	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "08:00.1") < 0)
> -		goto fail;
> -	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "0000:5:00.0") < 0)
> -		goto fail;
> -	if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "04:00.0,arg=val") < 0)
> -		goto fail;
> -	if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "0000:01:00.1") < 0)
> +	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "08:00.1") < 0)
>  		goto fail;
> -	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 2)
> +	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "0000:5:00.0") < 0)
>  		goto fail;
> -	if (rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 2)
> +	if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, "04:00.0") < 0)
>  		goto fail;
> -	if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 0)
> +	if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, "0000:01:00.1") < 0)
>  		goto fail;
What are the above pci bus/device/function tuples?

Neil
Nicolás Pernas Maradei Nov. 17, 2014, 2:58 p.m. UTC | #2
On 17/11/14 14:10, Neil Horman wrote:
> What are the above pci bus/device/function tuples?
>
> Neil

Hi,

I'm not sure if I understand the question. If you mean what kind of 
devices those are, as in physical or virtual, they are physical. 
rte_eal_devargs_add() would parse the string as a PCI ID. If it succeed 
it'd add them as physical devices having the field is_vdev = 0.

Please let me know if I answered your question.

Thanks,
Nico.
Neil Horman Nov. 17, 2014, 4 p.m. UTC | #3
On Mon, Nov 17, 2014 at 02:52:18PM +0000, Nicolas Pernas Maradei wrote:
> 
> On 17/11/14 14:10, Neil Horman wrote:
> >What are the above pci bus/device/function tuples?
> Hi,
> 
> I'm not sure if I understand the question. If you mean what kind of devices
> those are, as in physical or virtual, they are physical.
> rte_eal_devargs_add() would parse the string as a PCI ID. If it succeed it'd
> add them as physical devices having the field is_vdev = 0.
> 
> Please let me know if I answered your question.
> 
I get that, I was more asking, why those values?  They seem a bit magic to me,
and might benefit from some descriptive macros or comments so they make more
sense
Neil

> Thanks,
> Nico.
>
Nicolás Pernas Maradei Nov. 17, 2014, 4:40 p.m. UTC | #4
On 17/11/14 16:00, Neil Horman wrote:
> I get that, I was more asking, why those values?  They seem a bit magic to me,
> and might benefit from some descriptive macros or comments so they make more
> sense
> Neil
OK, I get you now.

Maybe the diff is not very clear. I just left the original calls to 
rte_eal_devargs_add() with the original values which they looked clear 
to me but I don't mind improving the comments a bit and as you 
suggested, adding in some macros.

I'll wait for some more feedback before submitting a second version of 
the patch.

Thanks,
Nico.
Bruce Richardson Nov. 17, 2014, 4:52 p.m. UTC | #5
On Mon, Nov 17, 2014 at 04:40:19PM +0000, Nicolas Pernas Maradei wrote:
> 
> On 17/11/14 16:00, Neil Horman wrote:
> >I get that, I was more asking, why those values?  They seem a bit magic to me,
> >and might benefit from some descriptive macros or comments so they make more
> >sense
> >Neil
> OK, I get you now.
> 
> Maybe the diff is not very clear. I just left the original calls to
> rte_eal_devargs_add() with the original values which they looked clear to me
> but I don't mind improving the comments a bit and as you suggested, adding
> in some macros.
> 
> I'll wait for some more feedback before submitting a second version of the
> patch.
>

Those are just example values for testing the parsing functionality. I'm don't
think descriptive macros are particularly needed, though maybe a short comment
or two might help out. The specific numeric values themselves aren't really important,
they are just examples of different patterns.

/Bruce
Neil Horman Nov. 17, 2014, 9:17 p.m. UTC | #6
On Mon, Nov 17, 2014 at 04:52:50PM +0000, Bruce Richardson wrote:
> On Mon, Nov 17, 2014 at 04:40:19PM +0000, Nicolas Pernas Maradei wrote:
> > 
> > On 17/11/14 16:00, Neil Horman wrote:
> > >I get that, I was more asking, why those values?  They seem a bit magic to me,
> > >and might benefit from some descriptive macros or comments so they make more
> > >sense
> > >Neil
> > OK, I get you now.
> > 
> > Maybe the diff is not very clear. I just left the original calls to
> > rte_eal_devargs_add() with the original values which they looked clear to me
> > but I don't mind improving the comments a bit and as you suggested, adding
> > in some macros.
> > 
> > I'll wait for some more feedback before submitting a second version of the
> > patch.
> >
> 
> Those are just example values for testing the parsing functionality. I'm don't
> think descriptive macros are particularly needed, though maybe a short comment
> or two might help out. The specific numeric values themselves aren't really important,
> they are just examples of different patterns.
> 
> /Bruce
> 
> 

Agreed, if they're just arbitrary bus/dev/func values, Marcos aren't needed,
just a comment calling them out as such.

Thanks!
Neil
diff mbox

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4c3fc76..f6ba4fe 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6844,6 +6844,8 @@  static void cmd_dump_parsed(void *parsed_result,
 		rte_mempool_list_dump(stdout);
 	else if (!strcmp(res->dump, "dump_devargs"))
 		rte_eal_devargs_dump(stdout);
+	else if (!strcmp(res->dump, "dump_vdevargs"))
+		rte_eal_vdevargs_dump(stdout);
 }
 
 cmdline_parse_token_string_t cmd_dump_dump =
@@ -6854,7 +6856,8 @@  cmdline_parse_token_string_t cmd_dump_dump =
 		"dump_struct_sizes#"
 		"dump_ring#"
 		"dump_mempool#"
-		"dump_devargs");
+		"dump_devargs#"
+		"dump_vdevargs");
 
 cmdline_parse_inst_t cmd_dump = {
 	.f = cmd_dump_parsed,  /* function to call */
diff --git a/app/test/commands.c b/app/test/commands.c
index 92a17ed..6799d63 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -161,13 +161,15 @@  static void cmd_dump_parsed(void *parsed_result,
 		rte_mempool_list_dump(stdout);
 	else if (!strcmp(res->dump, "dump_devargs"))
 		rte_eal_devargs_dump(stdout);
+	else if (!strcmp(res->dump, "dump_vdevargs"))
+		rte_eal_vdevargs_dump(stdout);
 }
 
 cmdline_parse_token_string_t cmd_dump_dump =
 	TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump,
 				 "dump_physmem#dump_memzone#dump_log_history#"
 				 "dump_struct_sizes#dump_ring#dump_mempool#"
-				 "dump_devargs");
+				 "dump_devargs#dump_vdevargs");
 
 cmdline_parse_inst_t cmd_dump = {
 	.f = cmd_dump_parsed,  /* function to call */
diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
index f0acf8e..8fb93df 100644
--- a/app/test/test_devargs.c
+++ b/app/test/test_devargs.c
@@ -52,52 +52,60 @@  static void free_devargs_list(void)
 	}
 }
 
+/* clear vdevargs list that was modified by the test */
+static void free_vdevargs_list(void)
+{
+	struct rte_vdevargs *vdevargs;
+
+	while (!TAILQ_EMPTY(&vdevargs_list)) {
+		vdevargs = TAILQ_FIRST(&vdevargs_list);
+		TAILQ_REMOVE(&vdevargs_list, vdevargs, next);
+		free(vdevargs);
+	}
+}
+
 static int
 test_devargs(void)
 {
 	struct rte_devargs_list save_devargs_list;
+	struct rte_vdevargs_list save_vdevargs_list;
 	struct rte_devargs *devargs;
+	struct rte_vdevargs *vdevargs;
 
 	/* save the real devargs_list, it is restored at the end of the test */
 	save_devargs_list = devargs_list;
+	save_vdevargs_list = vdevargs_list;
 	TAILQ_INIT(&devargs_list);
+	TAILQ_INIT(&vdevargs_list);
 
 	/* test valid cases */
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "08:00.1") < 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "0000:5:00.0") < 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "04:00.0,arg=val") < 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "0000:01:00.1") < 0)
+	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "08:00.1") < 0)
 		goto fail;
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 2)
+	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "0000:5:00.0") < 0)
 		goto fail;
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 2)
+	if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, "04:00.0") < 0)
 		goto fail;
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 0)
+	if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, "0000:01:00.1") < 0)
 		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "eth_ring0") < 0)
+	if (rte_eal_devargs_type_count(RTE_DEV_WHITELISTED) != 2)
 		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "eth_ring1,key=val,k2=val2") < 0)
-		goto fail;
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 2)
+	if (rte_eal_devargs_type_count(RTE_DEV_BLACKLISTED) != 2)
 		goto fail;
 	free_devargs_list();
 
 	/* check virtual device with argument parsing */
-	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "eth_ring1,k1=val,k2=val2") < 0)
+	if (rte_eal_vdevargs_add("eth_ring1,k1=val,k2=val2") < 0)
 		goto fail;
-	devargs = TAILQ_FIRST(&devargs_list);
-	if (strncmp(devargs->virtual.drv_name, "eth_ring1",
-			sizeof(devargs->virtual.drv_name) != 0))
+	vdevargs = TAILQ_FIRST(&vdevargs_list);
+	if (strncmp(vdevargs->drv_name, "eth_ring1",
+			sizeof(vdevargs->drv_name) != 0))
 		goto fail;
-	if (strncmp(devargs->args, "k1=val,k2=val2", sizeof(devargs->args) != 0))
+	if (strncmp(vdevargs->args, "k1=val,k2=val2", sizeof(vdevargs->args) != 0))
 		goto fail;
-	free_devargs_list();
+	free_vdevargs_list();
 
 	/* check PCI device with empty argument parsing */
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "04:00.1") < 0)
+	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "04:00.1") < 0)
 		goto fail;
 	devargs = TAILQ_FIRST(&devargs_list);
 	if (devargs->pci.addr.domain != 0 ||
@@ -105,28 +113,25 @@  test_devargs(void)
 		devargs->pci.addr.devid != 0 ||
 		devargs->pci.addr.function != 1)
 		goto fail;
-	if (strncmp(devargs->args, "", sizeof(devargs->args) != 0))
-		goto fail;
 	free_devargs_list();
 
-	/* test error case: bad PCI address */
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "08:1") == 0)
+	/* Check that virtual devices can be also whitelisted */
+	if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, "eth_pcap0") < 0)
 		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "00.1") == 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "foo") == 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, ",") == 0)
-		goto fail;
-	if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "000f:0:0") == 0)
+	devargs = TAILQ_FIRST(&devargs_list);
+	if (strncmp(devargs->virtual.drv_name, "eth_pcap0",
+		sizeof(devargs->virtual.drv_name)) != 0)
 		goto fail;
 
 	devargs_list = save_devargs_list;
+	vdevargs_list = save_vdevargs_list;
 	return 0;
 
  fail:
 	free_devargs_list();
+	free_vdevargs_list();
 	devargs_list = save_devargs_list;
+	vdevargs_list = save_vdevargs_list;
 	return -1;
 }
 
diff --git a/app/test/test_pci.c b/app/test/test_pci.c
index 4f0169a..308abb9 100644
--- a/app/test/test_pci.c
+++ b/app/test/test_pci.c
@@ -126,8 +126,7 @@  blacklist_all_devices(void)
 		snprintf(pci_addr_str, sizeof(pci_addr_str), PCI_PRI_FMT,
 			dev->addr.domain, dev->addr.bus, dev->addr.devid,
 			dev->addr.function);
-		if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI,
-				pci_addr_str) < 0) {
+		if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, pci_addr_str) < 0) {
 			printf("Error: cannot blacklist <%s>", pci_addr_str);
 			break;
 		}
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index ca99cb9..c59c203 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -429,14 +429,18 @@  eal_parse_args(int argc, char **argv)
 		return -1;
 	}
 
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 0 &&
-		rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 0) {
+	if (rte_eal_devargs_type_count(RTE_DEV_WHITELISTED) != 0 &&
+		rte_eal_devargs_type_count(RTE_DEV_BLACKLISTED) != 0) {
 		RTE_LOG(ERR, EAL, "Error: blacklist [-b] and whitelist "
 			"[-w] options cannot be used at the same time\n");
 		eal_usage(prgname);
 		return -1;
 	}
 
+	/* Check if all white/black listed virtual devices were also defined */
+	if (rte_eal_check_vdevs_definition() < 0)
+		return -1;
+
 	if (optind >= 0)
 		argv[optind-1] = prgname;
 
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 74ecce7..df179eb 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -462,7 +462,7 @@  rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 
 		/* no initialization when blacklisted, return without error */
 		if (dev->devargs != NULL &&
-			dev->devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI) {
+			dev->devargs->select == RTE_DEV_BLACKLISTED) {
 
 			RTE_LOG(DEBUG, EAL, "  Device is blacklisted, not initializing\n");
 			return 0;
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..5181ba8 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -64,8 +64,11 @@  rte_eal_driver_unregister(struct rte_driver *driver)
 int
 rte_eal_dev_init(void)
 {
-	struct rte_devargs *devargs;
+	struct rte_vdevargs *vdevargs;
 	struct rte_driver *driver;
+	int whitelisted_devs;
+
+	whitelisted_devs = rte_eal_devargs_type_count(RTE_DEV_WHITELISTED);
 
 	/*
 	 * Note that the dev_driver_list is populated here
@@ -74,9 +77,13 @@  rte_eal_dev_init(void)
 	 */
 
 	/* call the init function for each virtual device */
-	TAILQ_FOREACH(devargs, &devargs_list, next) {
+	TAILQ_FOREACH(vdevargs, &vdevargs_list, next) {
+
+		if (rte_eal_vdevargs_is(vdevargs, RTE_DEV_BLACKLISTED))
+			continue;
 
-		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+		if (whitelisted_devs
+		        && !rte_eal_vdevargs_is(vdevargs, RTE_DEV_WHITELISTED))
 			continue;
 
 		TAILQ_FOREACH(driver, &dev_driver_list, next) {
@@ -84,18 +91,15 @@  rte_eal_dev_init(void)
 				continue;
 
 			/* search a driver prefix in virtual device name */
-			if (!strncmp(driver->name, devargs->virtual.drv_name,
+			if (!strncmp(driver->name, vdevargs->drv_name,
 					strlen(driver->name))) {
-				driver->init(devargs->virtual.drv_name,
-					devargs->args);
+				driver->init(vdevargs->drv_name, vdevargs->args);
 				break;
 			}
 		}
 
-		if (driver == NULL) {
-			rte_panic("no driver found for %s\n",
-				  devargs->virtual.drv_name);
-		}
+		if (driver == NULL)
+			rte_panic("no driver found for %s\n", vdevargs->drv_name);
 	}
 
 	/* Once the vdevs are initalized, start calling all the pdev drivers */
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 4c7d11a..4171654 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -43,14 +43,15 @@ 
 /** Global list of user devices */
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
+struct rte_vdevargs_list vdevargs_list =
+	TAILQ_HEAD_INITIALIZER(vdevargs_list);
 
 /* store a whitelist parameter for later parsing */
 int
-rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
+rte_eal_devargs_add(enum rte_devselect devselect, const char *devargs_str)
 {
 	struct rte_devargs *devargs;
-	char buf[RTE_DEVARGS_LEN];
-	char *sep;
+	char buf[RTE_VDEV_NAME_LEN];
 	int ret;
 
 	ret = snprintf(buf, sizeof(buf), "%s", devargs_str);
@@ -67,86 +68,177 @@  rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 		return -1;
 	}
 	memset(devargs, 0, sizeof(*devargs));
-	devargs->type = devtype;
+	devargs->select = devselect;
+
+	/* try to parse short PCI identifier */
+	if (eal_parse_pci_BDF(buf, &devargs->pci.addr) == 0)
+		goto done;
+
+	/* try to parse long PCI identifier */
+	if (eal_parse_pci_DomBDF(buf, &devargs->pci.addr) == 0)
+		goto done;
+
+	/* If device ID is not a valid PCI ID assume is a virtual driver name */
+	devargs->is_vdev = 1;
+	ret = snprintf(devargs->virtual.drv_name, sizeof(devargs->virtual.drv_name), "%s", buf);
+	if (ret < 0 || ret >= (int)sizeof(devargs->virtual.drv_name)) {
+		RTE_LOG(ERR, EAL, "driver name too large: <%s>\n", buf);
+		free(devargs);
+		return -1;
+	}
+
+done:
+	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
+	return 0;
+}
+
+int
+rte_eal_vdevargs_add(const char *vdevargs_str)
+{
+	struct rte_vdevargs *vdevargs;
+	char buf[RTE_VDEVARGS_LEN];
+	char *sep;
+	int ret;
+
+	ret = snprintf(buf, sizeof(buf), "%s", vdevargs_str);
+	if (ret < 0 || ret >= (int)sizeof(buf)) {
+		RTE_LOG(ERR, EAL, "user device args too large: <%s>\n", vdevargs_str);
+		return -1;
+	}
+
+	/* use malloc instead of rte_malloc as it's called early at init */
+	vdevargs = malloc(sizeof(*vdevargs));
+	if (vdevargs == NULL) {
+		RTE_LOG(ERR, EAL, "cannot allocate vdevargs\n");
+		return -1;
+	}
+	memset(vdevargs, 0, sizeof(*vdevargs));
 
 	/* set the first ',' to '\0' to split name and arguments */
 	sep = strchr(buf, ',');
 	if (sep != NULL) {
 		sep[0] = '\0';
-		snprintf(devargs->args, sizeof(devargs->args), "%s", sep + 1);
+		snprintf(vdevargs->args, sizeof(vdevargs->args), "%s", sep + 1);
 	}
 
-	switch (devargs->type) {
-	case RTE_DEVTYPE_WHITELISTED_PCI:
-	case RTE_DEVTYPE_BLACKLISTED_PCI:
-		/* try to parse pci identifier */
-		if (eal_parse_pci_BDF(buf, &devargs->pci.addr) != 0 &&
-			eal_parse_pci_DomBDF(buf, &devargs->pci.addr) != 0) {
-			RTE_LOG(ERR, EAL,
-				"invalid PCI identifier <%s>\n", buf);
-			free(devargs);
-			return -1;
-		}
-		break;
-	case RTE_DEVTYPE_VIRTUAL:
-		/* save driver name */
-		ret = snprintf(devargs->virtual.drv_name,
-			sizeof(devargs->virtual.drv_name), "%s", buf);
-		if (ret < 0 || ret >= (int)sizeof(devargs->virtual.drv_name)) {
-			RTE_LOG(ERR, EAL,
-				"driver name too large: <%s>\n", buf);
-			free(devargs);
-			return -1;
-		}
-		break;
+	/* save driver name */
+	ret = snprintf(vdevargs->drv_name, sizeof(vdevargs->drv_name), "%s", buf);
+	if (ret < 0 || ret >= (int)sizeof(vdevargs->drv_name)) {
+		RTE_LOG(ERR, EAL, "driver name too large: <%s>\n", buf);
+		free(vdevargs);
+		return -1;
 	}
 
-	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
+	TAILQ_INSERT_TAIL(&vdevargs_list, vdevargs, next);
 	return 0;
 }
 
 /* count the number of devices of a specified type */
 unsigned int
-rte_eal_devargs_type_count(enum rte_devtype devtype)
+rte_eal_devargs_type_count(enum rte_devselect devselect)
 {
 	struct rte_devargs *devargs;
 	unsigned int count = 0;
 
 	TAILQ_FOREACH(devargs, &devargs_list, next) {
-		if (devargs->type != devtype)
+		if (devargs->select != devselect)
 			continue;
 		count++;
 	}
 	return count;
 }
 
-/* dump the user devices on the console */
+int
+rte_eal_vdevargs_is(struct rte_vdevargs *vdevargs, enum rte_devselect devselect)
+{
+	struct rte_devargs *devargs;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		if (!devargs->is_vdev)
+			continue;
+
+		if (!strncmp(vdevargs->drv_name, devargs->virtual.drv_name,
+				sizeof(vdevargs->drv_name)))
+			return !!(devargs->select == devselect);
+	}
+	return 0;
+}
+
+/* dump the user selected devices on the console */
 void
 rte_eal_devargs_dump(FILE *f)
 {
 	struct rte_devargs *devargs;
 
-	fprintf(f, "User device white list:\n");
+	fprintf(f, "User selected devices list:\n");
 	TAILQ_FOREACH(devargs, &devargs_list, next) {
-		if (devargs->type == RTE_DEVTYPE_WHITELISTED_PCI)
-			fprintf(f, "  PCI whitelist " PCI_PRI_FMT " %s\n",
-			       devargs->pci.addr.domain,
-			       devargs->pci.addr.bus,
-			       devargs->pci.addr.devid,
-			       devargs->pci.addr.function,
-			       devargs->args);
-		else if (devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI)
-			fprintf(f, "  PCI blacklist " PCI_PRI_FMT " %s\n",
-			       devargs->pci.addr.domain,
-			       devargs->pci.addr.bus,
-			       devargs->pci.addr.devid,
-			       devargs->pci.addr.function,
-			       devargs->args);
-		else if (devargs->type == RTE_DEVTYPE_VIRTUAL)
-			fprintf(f, "  VIRTUAL %s %s\n",
-			       devargs->virtual.drv_name,
-			       devargs->args);
+		if (devargs->select == RTE_DEV_WHITELISTED)
+			fprintf(f, "  PCI whitelist ");
+		else if (devargs->select == RTE_DEV_BLACKLISTED)
+			fprintf(f, "  PCI blacklist ");
+		else
+			fprintf(f, "  UNKNOWN ");
+
+		if (devargs->is_vdev)
+			fprintf(f, "(VIRTUAL) %s %s\n", devargs->virtual.vdev->drv_name,
+				devargs->virtual.vdev->args);
 		else
-			fprintf(f, "  UNKNOWN %s\n", devargs->args);
+			fprintf(f, PCI_PRI_FMT "\n",
+				devargs->pci.addr.domain,
+				devargs->pci.addr.bus,
+				devargs->pci.addr.devid,
+				devargs->pci.addr.function);
+	}
+}
+
+/* dump the user virtual devices on the console */
+void
+rte_eal_vdevargs_dump(FILE *f)
+{
+	struct rte_vdevargs *vdevargs;
+
+	fprintf(f, "User virtual devices list:\n");
+	TAILQ_FOREACH(vdevargs, &vdevargs_list, next) {
+		fprintf(f, "  VIRTUAL %s %s\n",
+			vdevargs->drv_name,
+			vdevargs->args);
+	}
+}
+
+int
+rte_eal_check_vdevs_definition(void)
+{
+	struct rte_devargs *devargs;
+	struct rte_vdevargs *vdevargs;
+	int found;
+
+	/* Go through all white/black listed devices */
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+		/* Only check the virtual ones */
+		if (!devargs->is_vdev)
+			continue;
+
+		/* Search for the virtual device definition */
+		found = 0;
+		TAILQ_FOREACH(vdevargs, &vdevargs_list, next) {
+			if (!strncmp(vdevargs->drv_name, devargs->virtual.drv_name,
+					sizeof(vdevargs->drv_name))) {
+				found = 1;
+				devargs->virtual.vdev = vdevargs;
+			}
+		}
+
+		/* If the virtual device was not defined return an error */
+		if (!found) {
+			RTE_LOG(ERR, EAL, "Virtual device %s is %slisted but not defined. "
+					"Use '--vdev=%s,...' to define it.\n",
+					devargs->virtual.drv_name,
+					devargs->select == RTE_DEV_WHITELISTED ? "white" : "black",
+					devargs->virtual.drv_name);
+			return -1;
+		}
 	}
+
+	return 0;
 }
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 7a5d55e..e044a51 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -244,17 +244,13 @@  eal_parse_common_option(int opt, const char *optarg,
 	switch (opt) {
 	/* blacklist */
 	case 'b':
-		if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI,
-				optarg) < 0) {
+		if (rte_eal_devargs_add(RTE_DEV_BLACKLISTED, optarg) < 0)
 			return -1;
-		}
 		break;
 	/* whitelist */
 	case 'w':
-		if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI,
-				optarg) < 0) {
+		if (rte_eal_devargs_add(RTE_DEV_WHITELISTED, optarg) < 0)
 			return -1;
-		}
 		break;
 	/* coremask */
 	case 'c':
@@ -321,8 +317,7 @@  eal_parse_common_option(int opt, const char *optarg,
 		break;
 
 	case OPT_VDEV_NUM:
-		if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL,
-				optarg) < 0) {
+		if (rte_eal_vdevargs_add(optarg) < 0) {
 			return -1;
 		}
 		break;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index f3c7f71..19b3ce4 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -85,13 +85,14 @@ 
 struct pci_driver_list pci_driver_list;
 struct pci_device_list pci_device_list;
 
-static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
+static struct rte_devargs *
+pci_devargs_lookup(struct rte_pci_device *dev)
 {
 	struct rte_devargs *devargs;
 
 	TAILQ_FOREACH(devargs, &devargs_list, next) {
-		if (devargs->type != RTE_DEVTYPE_BLACKLISTED_PCI &&
-			devargs->type != RTE_DEVTYPE_WHITELISTED_PCI)
+		if (devargs->select != RTE_DEV_BLACKLISTED &&
+			devargs->select != RTE_DEV_WHITELISTED)
 			continue;
 		if (!memcmp(&dev->addr, &devargs->pci.addr, sizeof(dev->addr)))
 			return devargs;
@@ -136,7 +137,7 @@  rte_eal_pci_probe(void)
 	int probe_all = 0;
 	int ret = 0;
 
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) == 0)
+	if (rte_eal_devargs_type_count(RTE_DEV_WHITELISTED) == 0)
 		probe_all = 1;
 
 	TAILQ_FOREACH(dev, &pci_device_list, next) {
@@ -150,7 +151,7 @@  rte_eal_pci_probe(void)
 		if (probe_all)
 			ret = pci_probe_all_drivers(dev);
 		else if (devargs != NULL &&
-			devargs->type == RTE_DEVTYPE_WHITELISTED_PCI)
+			devargs->select == RTE_DEV_WHITELISTED)
 			ret = pci_probe_all_drivers(dev);
 		if (ret < 0)
 			rte_exit(EXIT_FAILURE, "Requested device " PCI_PRI_FMT
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 9f9c98f..b6599ef 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -52,96 +52,158 @@  extern "C" {
 #include <sys/queue.h>
 #include <rte_pci.h>
 
+#define RTE_VDEV_NAME_LEN 32
+
 /**
- * Type of generic device
+ * Type of device selection
  */
-enum rte_devtype {
-	RTE_DEVTYPE_WHITELISTED_PCI,
-	RTE_DEVTYPE_BLACKLISTED_PCI,
-	RTE_DEVTYPE_VIRTUAL,
+enum rte_devselect {
+	RTE_DEV_WHITELISTED,
+	RTE_DEV_BLACKLISTED,
 };
 
 /**
- * Structure that stores a device given by the user with its arguments
+ * Structure that stores a virtual device given by the user with its arguments
+ *
+ * The structure stores the configuration of the device and its name which
+ * contains its driver name
+ */
+struct rte_vdevargs {
+	/** Next in list. */
+	TAILQ_ENTRY(rte_vdevargs) next;
+	/** Driver name. */
+	char drv_name[RTE_VDEV_NAME_LEN];
+#define RTE_VDEVARGS_LEN 256
+	char args[RTE_VDEVARGS_LEN]; /**< Arguments string as given by user. */
+};
+
+/**
+ * Structure that stores the user selected devices.
  *
  * A user device is a physical or a virtual device given by the user to
  * the DPDK application at startup through command line arguments.
  *
- * The structure stores the configuration of the device, its PCI
- * identifier if it's a PCI device or the driver name if it's a virtual
- * device.
+ * The devices can be whitelisted or blacklisted independently if they are
+ * physical or virtual devices.
  */
 struct rte_devargs {
 	/** Next in list. */
 	TAILQ_ENTRY(rte_devargs) next;
-	/** Type of device. */
-	enum rte_devtype type;
+	/** Type of device selection. */
+	enum rte_devselect select;
+	int is_vdev;
 	union {
-		/** Used if type is RTE_DEVTYPE_*_PCI. */
+		/** Used if physical device. */
 		struct {
 			/** PCI location. */
 			struct rte_pci_addr addr;
 		} pci;
-		/** Used if type is RTE_DEVTYPE_VIRTUAL. */
+		/** Used if virtual device. */
 		struct {
 			/** Driver name. */
-			char drv_name[32];
+			char drv_name[RTE_VDEV_NAME_LEN];
+			struct rte_vdevargs *vdev;
 		} virtual;
 	};
-#define RTE_DEVARGS_LEN 256
-	char args[RTE_DEVARGS_LEN]; /**< Arguments string as given by user. */
 };
 
 /** user device double-linked queue type definition */
 TAILQ_HEAD(rte_devargs_list, rte_devargs);
+TAILQ_HEAD(rte_vdevargs_list, rte_vdevargs);
 
 /** Global list of user devices */
 extern struct rte_devargs_list devargs_list;
 
+/** Global list of virtual devices */
+extern struct rte_vdevargs_list vdevargs_list;
+
 /**
  * Add a device to the user device list
  *
- * For PCI devices, the format of arguments string is "PCI_ADDR" or
- * "PCI_ADDR,key=val,key2=val2,...". Examples: "08:00.1", "0000:5:00.0",
- * "04:00.0,arg=val".
+ * For PCI devices, the format of arguments string is "PCI_ADDR"
+ * Examples: "08:00.1", "0000:5:00.0".
  *
- * For virtual devices, the format of arguments string is "DRIVER_NAME*"
- * or "DRIVER_NAME*,key=val,key2=val2,...". Examples: "eth_ring",
- * "eth_ring0", "eth_pmdAnything,arg=0:arg2=1". The validity of the
- * driver name is not checked by this function, it is done when probing
- * the drivers.
+ * For virtual devices, the format of arguments string is "DRIVER_NAME".
+ * Examples: "eth_ring", "eth_ring0", "eth_pmdAnything". This function does not
+ * validate if the driver name is valid or if it was already defined with
+ * --vdev.
  *
- * @param devtype
- *   The type of the device.
- * @param devargs_list
+ * @param devselect
+ *   Whether the device is black or white listed.
+ * @param devargs_str
  *   The arguments as given by the user.
  *
  * @return
  *   - 0 on success
  *   - A negative value on error
  */
-int rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str);
+int rte_eal_devargs_add(enum rte_devselect devselect, const char *devargs_str);
 
 /**
  * Count the number of user devices of a specified type
  *
- * @param devtype
+ * @param devselect
  *   The type of the devices to counted.
  *
  * @return
  *   The number of devices.
  */
 unsigned int
-rte_eal_devargs_type_count(enum rte_devtype devtype);
+rte_eal_devargs_type_count(enum rte_devselect devselect);
 
 /**
- * This function dumps the list of user device and their arguments.
+ * This function dumps the list of user selected devices.
  *
  * @param f
  *   A pointer to a file for output
  */
 void rte_eal_devargs_dump(FILE *f);
 
+/**
+ * This function dumps the list of user virtual devices and their arguments.
+ *
+ * @param f
+ *   A pointer to a file for output
+ */
+void rte_eal_vdevargs_dump(FILE *f);
+
+/**
+ * Add a virtual device
+ *
+ * The format of arguments string is "DRIVER_NAME*"
+ * or "DRIVER_NAME*,key=val,key2=val2,...". Examples: "eth_ring",
+ * "eth_ring0", "eth_pmdAnything,arg=0:arg2=1". The validity of the
+ * driver name is not checked by this function, it is done when probing
+ * the drivers.
+ *
+ * @param devargs_str
+ *   The arguments as given by the user.
+ *
+ * @return
+ *   - 0 on success
+ *   - A negative value on error
+ */
+int rte_eal_vdevargs_add(const char *devargs_str);
+
+/**
+ * Check if the white/black-listed virtual devices have been defined
+ *
+ * @return
+ *   - 0 on success
+ *   - A negative value on error
+ */
+int rte_eal_check_vdevs_definition(void);
+
+/**
+ * Check if the virtual device is white/black-listed
+ *
+ * @return
+ *   - 1 if the device is white/black-listed.
+ *   - 0 otherwise.
+ */
+int rte_eal_vdevargs_is(struct rte_vdevargs *vdevargs,
+		enum rte_devselect devselect);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 7a1d087..e898688 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -696,14 +696,18 @@  eal_parse_args(int argc, char **argv)
 		return -1;
 	}
 
-	if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 0 &&
-		rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 0) {
+	if (rte_eal_devargs_type_count(RTE_DEV_WHITELISTED) != 0 &&
+		rte_eal_devargs_type_count(RTE_DEV_BLACKLISTED) != 0) {
 		RTE_LOG(ERR, EAL, "Error: blacklist [-b] and whitelist "
 			"[-w] options cannot be used at the same time\n");
 		eal_usage(prgname);
 		return -1;
 	}
 
+	/* Check if all white/black listed virtual devices were also defined */
+	if (rte_eal_check_vdevs_definition() < 0)
+		return -1;
+
 	if (optind >= 0)
 		argv[optind-1] = prgname;
 
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index ddb0535..b49722e 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -544,7 +544,7 @@  rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 
 		/* no initialization when blacklisted, return without error */
 		if (dev->devargs != NULL &&
-			dev->devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI) {
+			dev->devargs->select == RTE_DEV_BLACKLISTED) {
 			RTE_LOG(DEBUG, EAL, "  Device is blacklisted, not initializing\n");
 			return 1;
 		}