diff --git a/app/test/Makefile b/app/test/Makefile index 28f1f62ed7..b49785eaa8 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -93,6 +93,7 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_power.c SRCS-$(CONFIG_RTE_APP_TEST) += test_common.c SRCS-$(CONFIG_RTE_APP_TEST) += test_timer_perf.c SRCS-$(CONFIG_RTE_APP_TEST) += test_ivshmem.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_devargs.c ifeq ($(CONFIG_RTE_APP_TEST),y) SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c diff --git a/app/test/commands.c b/app/test/commands.c index a1530265c5..7595b4c76a 100644 --- a/app/test/commands.c +++ b/app/test/commands.c @@ -178,6 +178,8 @@ static void cmd_autotest_parsed(void *parsed_result, ret = test_common(); if (!strcmp(res->autotest, "ivshmem_autotest")) ret = test_ivshmem(); + if (!strcmp(res->autotest, "devargs_autotest")) + ret = test_devargs(); #ifdef RTE_LIBRTE_PMD_RING if (!strcmp(res->autotest, "ring_pmd_autotest")) ret = test_pmd_ring(); @@ -223,6 +225,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest = "red_autotest#meter_autotest#sched_autotest#" "memcpy_perf_autotest#kni_autotest#" "pm_autotest#ivshmem_autotest#" + "devargs_autotest#" #ifdef RTE_LIBRTE_ACL "acl_autotest#" #endif diff --git a/app/test/test.h b/app/test/test.h index bc001b9d7a..1945d29c24 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -93,6 +93,7 @@ int test_common(void); int test_pmd_ring(void); int test_ivshmem(void); int test_kvargs(void); +int test_devargs(void); int test_pci_run; diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c new file mode 100644 index 0000000000..035ed59f3d --- /dev/null +++ b/app/test/test_devargs.c @@ -0,0 +1,131 @@ +/*- + * BSD LICENSE + * + * Copyright 2014 6WIND S.A. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of 6WIND S.A nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include + +#include "test.h" + +/* clear devargs list that was modified by the test */ +static void free_devargs_list(void) +{ + struct rte_devargs *devargs; + + while (!TAILQ_EMPTY(&devargs_list)) { + devargs = TAILQ_FIRST(&devargs_list); + TAILQ_REMOVE(&devargs_list, devargs, next); + free(devargs); + } +} + +int +test_devargs(void) +{ + struct rte_devargs_list save_devargs_list; + struct rte_devargs *devargs; + + /* save the real devargs_list, it is restored at the end of the test */ + save_devargs_list = devargs_list; + TAILQ_INIT(&devargs_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) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 2) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 2) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "eth_ring0") < 0) + 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) + 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) + goto fail; + devargs = TAILQ_FIRST(&devargs_list); + if (strncmp(devargs->virtual.drv_name, "eth_ring1", + sizeof(devargs->virtual.drv_name) != 0)) + goto fail; + if (strncmp(devargs->args, "k1=val;k2=val2", sizeof(devargs->args) != 0)) + goto fail; + free_devargs_list(); + + /* check PCI device with empty argument parsing */ + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "04:00.1") < 0) + goto fail; + devargs = TAILQ_FIRST(&devargs_list); + if (devargs->pci.addr.domain != 0 || + devargs->pci.addr.bus != 4 || + 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) + 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) + goto fail; + + devargs_list = save_devargs_list; + return 0; + + fail: + free_devargs_list(); + devargs_list = save_devargs_list; + return -1; +} diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile index f7b581e10f..b9f3b8880f 100644 --- a/lib/librte_eal/common/Makefile +++ b/lib/librte_eal/common/Makefile @@ -38,7 +38,7 @@ INC += rte_pci_dev_ids.h rte_per_lcore.h rte_prefetch.h rte_random.h INC += rte_rwlock.h rte_spinlock.h rte_tailq.h rte_interrupts.h rte_alarm.h INC += rte_string_fns.h rte_cpuflags.h rte_version.h rte_tailq_elem.h INC += rte_eal_memconfig.h rte_malloc_heap.h -INC += rte_hexdump.h +INC += rte_hexdump.h rte_devargs.h ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y) INC += rte_warnings.h diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c new file mode 100644 index 0000000000..52f5cc7669 --- /dev/null +++ b/lib/librte_eal/common/eal_common_devargs.c @@ -0,0 +1,152 @@ +/*- + * BSD LICENSE + * + * Copyright 2014 6WIND S.A. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of 6WIND S.A nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This file manages the list of devices and their arguments, as given + * by the user at startup */ + +#include + +#include +#include +#include +#include "eal_private.h" + +/** Global list of user devices */ +struct rte_devargs_list devargs_list = + TAILQ_HEAD_INITIALIZER(devargs_list); + +/* store a whitelist parameter for later parsing */ +int +rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str) +{ + struct rte_devargs *devargs; + char buf[RTE_DEVARGS_LEN]; + char *sep; + int ret; + + ret = snprintf(buf, sizeof(buf), "%s", devargs_str); + if (ret < 0 || ret >= (int)sizeof(buf)) { + RTE_LOG(ERR, EAL, "user device args too large: <%s>\n", + devargs_str); + return -1; + } + + /* use malloc instead of rte_malloc as it's called early at init */ + devargs = malloc(sizeof(*devargs)); + if (devargs == NULL) { + RTE_LOG(ERR, EAL, "cannot allocate devargs\n"); + return -1; + } + memset(devargs, 0, sizeof(*devargs)); + devargs->type = devtype; + + /* 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); + } + + 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; + } + + TAILQ_INSERT_TAIL(&devargs_list, devargs, next); + return 0; +} + +/* count the number of devices of a specified type */ +unsigned int +rte_eal_devargs_type_count(enum rte_devtype devtype) +{ + struct rte_devargs *devargs; + unsigned int count = 0; + + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->type != devtype) + continue; + count++; + } + return count; +} + +/* dump the user devices on the console */ +void +rte_eal_devargs_dump(void) +{ + struct rte_devargs *devargs; + + printf("User device white list:\n"); + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->type == RTE_DEVTYPE_WHITELISTED_PCI) + printf(" 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) + printf(" 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) + printf(" VIRTUAL %s %s\n", + devargs->virtual.drv_name, + devargs->args); + else + printf(" UNKNOWN %s\n", devargs->args); + } +} diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h new file mode 100644 index 0000000000..2e6e1f39e9 --- /dev/null +++ b/lib/librte_eal/common/include/rte_devargs.h @@ -0,0 +1,145 @@ +/*- + * BSD LICENSE + * + * Copyright 2014 6WIND S.A. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of 6WIND S.A nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTE_DEVARGS_H_ +#define _RTE_DEVARGS_H_ + +/** + * @file + * + * RTE devargs: list of devices and their user arguments + * + * This file stores a list of devices and their arguments given by + * the user when a DPDK application is started. These devices can be PCI + * devices or virtual devices. These devices are stored at startup in a + * list of rte_devargs structures. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** + * Type of generic device + */ +enum rte_devtype { + RTE_DEVTYPE_WHITELISTED_PCI, + RTE_DEVTYPE_BLACKLISTED_PCI, + RTE_DEVTYPE_VIRTUAL, +}; + +/** + * Structure that stores a device given by the user with its arguments + * + * 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. + */ +struct rte_devargs { + /** Next in list. */ + TAILQ_ENTRY(rte_devargs) next; + /** Type of device. */ + enum rte_devtype type; + union { + /** Used if type is RTE_DEVTYPE_*_PCI. */ + struct { + /** PCI location. */ + struct rte_pci_addr addr; + } pci; + /** Used if type is RTE_DEVTYPE_VIRTUAL. */ + struct { + /** Driver name. */ + char drv_name[32]; + } 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); + +/** Global list of user devices */ +extern struct rte_devargs_list devargs_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 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. + * + * @param devtype + * The type of the device. + * @param devargs_list + * 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); + +/** + * Count the number of user devices of a specified type + * + * @param devtype + * The type of the devices to counted. + * + * @return + * The number of devices. + */ +unsigned int +rte_eal_devargs_type_count(enum rte_devtype devtype); + +/** + * This function dumps the list of user device and their arguments. + */ +void rte_eal_devargs_dump(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_DEVARGS_H_ */ diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index b5251307b3..f57fda5872 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -77,6 +77,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_errno.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_cpuflags.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_hexdump.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_whitelist.c +SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_devargs.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_nonpci_devs.c CFLAGS_eal.o := -D_GNU_SOURCE