[dpdk-dev,v9,13/14] eal/pci: Add rte_eal_dev_attach/detach() functions
Commit Message
These functions are used for attaching or detaching a port.
When rte_eal_dev_attach() is called, the function tries to realize the
device name as pci address. If this is done successfully,
rte_eal_dev_attach() will attach physical device port. If not, attaches
virtual devive port.
When rte_eal_dev_detach() is called, the function gets the device type
of this port to know whether the port is come from physical or virtual.
And then specific detaching function will be called.
v9:
- Fix comments.
- Use strcmp() instead of strncmp().
- Remove RTE_EAL_INVOKE_TYPE_PROBE/CLOSE.
- Change definition of rte_dev_uninit_t.
(Thanks to Thomas Monjalon and Maxime Leroy)
v8:
- Add missing symbol in version map.
(Thanks to Qiu, Michael and Iremonger, Bernard)
v7:
- Fix typo of warning messages.
(Thanks to Qiu, Michael)
v5:
- Change function names like below.
rte_eal_dev_find_and_invoke() to rte_eal_vdev_find_and_invoke().
rte_eal_dev_invoke() to rte_eal_vdev_invoke().
- Add code to handle a return value of rte_eal_devargs_remove().
- Fix pci address format in rte_eal_dev_detach().
v4:
- Fix comment.
- Add error checking.
- Fix indent of 'if' statement.
- Change function name.
Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
lib/librte_eal/common/eal_common_dev.c | 307 ++++++++++++++++++++++++
lib/librte_eal/common/eal_private.h | 11 +
lib/librte_eal/common/include/rte_dev.h | 33 +++
lib/librte_eal/linuxapp/eal/Makefile | 1 +
lib/librte_eal/linuxapp/eal/eal_pci.c | 6 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 2 +
6 files changed, 357 insertions(+), 3 deletions(-)
Comments
2015-02-19 11:49, Tetsuya Mukawa:
> +/* attach the new virtual device, then store port_id of the device */
> +static int
> +rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
> +{
> + char *args;
> + uint8_t new_port_id;
> + struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
> +
> + if ((vdevargs == NULL) || (port_id == NULL))
> + goto err0;
> +
> + args = strdup(vdevargs);
> + if (args == NULL)
> + goto err0;
> +
> + /* save current port status */
> + if (rte_eth_dev_save(devs, sizeof(devs)))
> + goto err1;
> + /* add the vdevargs to devargs_list */
> + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
> + goto err1;
Could you explain why you store devargs in a list?
> + /* parse vdevargs, then retrieve device name */
> + get_vdev_name(args);
> + /* walk around dev_driver_list to find the driver of the device,
> + * then invoke probe function o the driver */
> + if (rte_eal_vdev_find_and_init(args))
TODO: get port_id from init.
> + goto err2;
> + /* get port_id enabled by above procedures */
> + if (rte_eth_dev_get_changed_port(devs, &new_port_id))
> + goto err2;
[...]
> --- a/lib/librte_eal/common/include/rte_dev.h
> +++ b/lib/librte_eal/common/include/rte_dev.h
> @@ -47,6 +47,7 @@ extern "C" {
> #endif
>
> #include <sys/queue.h>
> +#include <rte_pci.h>
>
> /** Double linked list of device drivers. */
> TAILQ_HEAD(rte_driver_list, rte_driver);
> @@ -57,6 +58,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
> typedef int (rte_dev_init_t)(const char *name, const char *args);
>
> /**
> + * Uninitilization function called for each device driver once.
> + */
> +typedef int (rte_dev_uninit_t)(const char *name);
Why using name as parameter and not port_id?
[...]
> --- a/lib/librte_eal/linuxapp/eal/Makefile
> +++ b/lib/librte_eal/linuxapp/eal/Makefile
> @@ -45,6 +45,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
> CFLAGS += -I$(RTE_SDK)/lib/librte_ring
> CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
> CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
> +CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
Why do you need mbuf?
[...]
> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> @@ -21,6 +21,8 @@ DPDK_2.0 {
> rte_eal_alarm_cancel;
> rte_eal_alarm_set;
> rte_eal_dev_init;
> + rte_eal_dev_attach;
> + rte_eal_dev_detach;
Please keep alphabetical order.
On 2015/02/19 21:10, Thomas Monjalon wrote:
> 2015-02-19 11:49, Tetsuya Mukawa:
>> +/* attach the new virtual device, then store port_id of the device */
>> +static int
>> +rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
>> +{
>> + char *args;
>> + uint8_t new_port_id;
>> + struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
>> +
>> + if ((vdevargs == NULL) || (port_id == NULL))
>> + goto err0;
>> +
>> + args = strdup(vdevargs);
>> + if (args == NULL)
>> + goto err0;
>> +
>> + /* save current port status */
>> + if (rte_eth_dev_save(devs, sizeof(devs)))
>> + goto err1;
>> + /* add the vdevargs to devargs_list */
>> + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
>> + goto err1;
> Could you explain why you store devargs in a list?
I try to do same behavior when rte_eal_init() is called.
If only hotplug doesn't do this, someone may be confused when they try
to realize devargs_list.
>> + /* parse vdevargs, then retrieve device name */
>> + get_vdev_name(args);
>> + /* walk around dev_driver_list to find the driver of the device,
>> + * then invoke probe function o the driver */
>> + if (rte_eal_vdev_find_and_init(args))
> TODO: get port_id from init.
Yes, I will.
I also add comment about it.
>> + goto err2;
>> + /* get port_id enabled by above procedures */
>> + if (rte_eth_dev_get_changed_port(devs, &new_port_id))
>> + goto err2;
> [...]
>> --- a/lib/librte_eal/common/include/rte_dev.h
>> +++ b/lib/librte_eal/common/include/rte_dev.h
>> @@ -47,6 +47,7 @@ extern "C" {
>> #endif
>>
>> #include <sys/queue.h>
>> +#include <rte_pci.h>
>>
>> /** Double linked list of device drivers. */
>> TAILQ_HEAD(rte_driver_list, rte_driver);
>> @@ -57,6 +58,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
>> typedef int (rte_dev_init_t)(const char *name, const char *args);
>>
>> /**
>> + * Uninitilization function called for each device driver once.
>> + */
>> +typedef int (rte_dev_uninit_t)(const char *name);
> Why using name as parameter and not port_id?
This function pointer will be implemented in PMDs.
For example, in pcap PMD, rte_pmd_pcap_devuninit() is the function.
static struct rte_driver pmd_pcap_drv = {
.name = "eth_pcap",
.type = PMD_VDEV,
.init = rte_pmd_pcap_devinit,
.uninit = rte_pmd_pcap_devuninit,
};
"port_id" isn't needed in PMD.
>
> [...]
>> --- a/lib/librte_eal/linuxapp/eal/Makefile
>> +++ b/lib/librte_eal/linuxapp/eal/Makefile
>> @@ -45,6 +45,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
>> CFLAGS += -I$(RTE_SDK)/lib/librte_ring
>> CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
>> CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
>> +CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
> Why do you need mbuf?
To include rte_ethdev.h in this code, rte_mbuf.h is also needed.
> [...]
>> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
>> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
>> @@ -21,6 +21,8 @@ DPDK_2.0 {
>> rte_eal_alarm_cancel;
>> rte_eal_alarm_set;
>> rte_eal_dev_init;
>> + rte_eal_dev_attach;
>> + rte_eal_dev_detach;
> Please keep alphabetical order.
>
Sure, I will.
Thanks,
Tetsuya
On 2015/02/19 22:30, Tetsuya Mukawa wrote:
> On 2015/02/19 21:10, Thomas Monjalon wrote:
>> 2015-02-19 11:49, Tetsuya Mukawa:
>>> +/* attach the new virtual device, then store port_id of the device */
>>> +static int
>>> +rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
>>> +{
>>> + char *args;
>>> + uint8_t new_port_id;
>>> + struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
>>> +
>>> + if ((vdevargs == NULL) || (port_id == NULL))
>>> + goto err0;
>>> +
>>> + args = strdup(vdevargs);
>>> + if (args == NULL)
>>> + goto err0;
>>> +
>>> + /* save current port status */
>>> + if (rte_eth_dev_save(devs, sizeof(devs)))
>>> + goto err1;
>>> + /* add the vdevargs to devargs_list */
>>> + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
>>> + goto err1;
>> Could you explain why you store devargs in a list?
> I try to do same behavior when rte_eal_init() is called.
Sorry for lack of explanation.
"vdevargs" of rte_eal_dev_attach_vdev() will be same format of "--vdev"
option.
And when rte_eal_init() is called, such a "--vdev" option value will be
stored in devargs_list.
So I try to same thing here.
> If only hotplug doesn't do this, someone may be confused when they try
> to realize devargs_list.
>
>>> + /* parse vdevargs, then retrieve device name */
>>> + get_vdev_name(args);
>>> + /* walk around dev_driver_list to find the driver of the device,
>>> + * then invoke probe function o the driver */
>>> + if (rte_eal_vdev_find_and_init(args))
>> TODO: get port_id from init.
> Yes, I will.
> I also add comment about it.
>
>>> + goto err2;
>>> + /* get port_id enabled by above procedures */
>>> + if (rte_eth_dev_get_changed_port(devs, &new_port_id))
>>> + goto err2;
>> [...]
>>> --- a/lib/librte_eal/common/include/rte_dev.h
>>> +++ b/lib/librte_eal/common/include/rte_dev.h
>>> @@ -47,6 +47,7 @@ extern "C" {
>>> #endif
>>>
>>> #include <sys/queue.h>
>>> +#include <rte_pci.h>
>>>
>>> /** Double linked list of device drivers. */
>>> TAILQ_HEAD(rte_driver_list, rte_driver);
>>> @@ -57,6 +58,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
>>> typedef int (rte_dev_init_t)(const char *name, const char *args);
>>>
>>> /**
>>> + * Uninitilization function called for each device driver once.
>>> + */
>>> +typedef int (rte_dev_uninit_t)(const char *name);
>> Why using name as parameter and not port_id?
> This function pointer will be implemented in PMDs.
> For example, in pcap PMD, rte_pmd_pcap_devuninit() is the function.
>
> static struct rte_driver pmd_pcap_drv = {
> .name = "eth_pcap",
> .type = PMD_VDEV,
> .init = rte_pmd_pcap_devinit,
> .uninit = rte_pmd_pcap_devuninit,
> };
>
> "port_id" isn't needed in PMD.
>
>> [...]
>>> --- a/lib/librte_eal/linuxapp/eal/Makefile
>>> +++ b/lib/librte_eal/linuxapp/eal/Makefile
>>> @@ -45,6 +45,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
>>> CFLAGS += -I$(RTE_SDK)/lib/librte_ring
>>> CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
>>> CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
>>> +CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
>> Why do you need mbuf?
> To include rte_ethdev.h in this code, rte_mbuf.h is also needed.
>
>> [...]
>>> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
>>> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
>>> @@ -21,6 +21,8 @@ DPDK_2.0 {
>>> rte_eal_alarm_cancel;
>>> rte_eal_alarm_set;
>>> rte_eal_dev_init;
>>> + rte_eal_dev_attach;
>>> + rte_eal_dev_detach;
>> Please keep alphabetical order.
>>
> Sure, I will.
>
> Thanks,
> Tetsuya
>
@@ -32,10 +32,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdio.h>
+#include <limits.h>
#include <string.h>
#include <inttypes.h>
#include <sys/queue.h>
+#include <rte_ethdev.h>
#include <rte_dev.h>
#include <rte_devargs.h>
#include <rte_debug.h>
@@ -107,3 +110,307 @@ rte_eal_dev_init(void)
}
return 0;
}
+
+/* So far, DPDK hotplug function only supports linux */
+#ifdef RTE_LIBRTE_EAL_HOTPLUG
+static int
+rte_eal_vdev_find_and_init(const char *name)
+{
+ struct rte_devargs *devargs;
+ struct rte_driver *driver;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ /* find the specified device and call init function */
+ TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+ if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+ continue;
+
+ if (strcmp(name, devargs->virtual.drv_name))
+ continue;
+
+ TAILQ_FOREACH(driver, &dev_driver_list, next) {
+ if (driver->type != PMD_VDEV)
+ continue;
+
+ /*
+ * search a driver prefix in virtual device name.
+ * For example, if the driver is pcap PMD, driver->name
+ * will be "eth_pcap", but devargs->virtual.drv_name
+ * will be "eth_pcapN". So use strncmp to compare.
+ */
+ if (!strncmp(driver->name, devargs->virtual.drv_name,
+ strlen(driver->name))) {
+ driver->init(devargs->virtual.drv_name,
+ devargs->args);
+ break;
+ }
+ }
+
+ if (driver == NULL) {
+ RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+ devargs->virtual.drv_name);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int
+rte_eal_vdev_find_and_uninit(const char *name)
+{
+ struct rte_devargs *devargs;
+ struct rte_driver *driver;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ /* find the specified device and call uninit function */
+ TAILQ_FOREACH(devargs, &devargs_list, next) {
+
+ if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+ continue;
+
+ if (strcmp(name, devargs->virtual.drv_name))
+ continue;
+
+ TAILQ_FOREACH(driver, &dev_driver_list, next) {
+ if (driver->type != PMD_VDEV)
+ continue;
+
+ /*
+ * search a driver prefix in virtual device name.
+ * For example, if the driver is pcap PMD, driver->name
+ * will be "eth_pcap", but devargs->virtual.drv_name
+ * will be "eth_pcapN". So use strncmp to compare.
+ */
+ if (!strncmp(driver->name, devargs->virtual.drv_name,
+ strlen(driver->name))) {
+ driver->uninit(devargs->virtual.drv_name);
+ break;
+ }
+ }
+
+ if (driver == NULL) {
+ RTE_LOG(WARNING, EAL, "no driver found for %s\n",
+ devargs->virtual.drv_name);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/* attach the new physical device, then store port_id of the device */
+static int
+rte_eal_dev_attach_pdev(struct rte_pci_addr *addr, uint8_t *port_id)
+{
+ uint8_t new_port_id;
+ struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+ if ((addr == NULL) || (port_id == NULL))
+ goto err;
+
+ /* save current port status */
+ if (rte_eth_dev_save(devs, sizeof(devs)))
+ goto err;
+ /* re-construct pci_device_list */
+ if (rte_eal_pci_scan())
+ goto err;
+ /* invoke probe func of the driver can handle the new device */
+ if (rte_eal_pci_probe_one(addr))
+ goto err;
+ /* get port_id enabled by above procedures */
+ if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+ goto err;
+
+ *port_id = new_port_id;
+ return 0;
+err:
+ RTE_LOG(ERR, EAL, "Driver, cannot attach the device\n");
+ return -1;
+}
+
+/* detach the new physical device, then store pci_addr of the device */
+static int
+rte_eal_dev_detach_pdev(uint8_t port_id, struct rte_pci_addr *addr)
+{
+ struct rte_pci_addr freed_addr;
+ struct rte_pci_addr vp;
+
+ if (addr == NULL)
+ goto err;
+
+ /* check whether the driver supports detach feature, or not */
+ if (rte_eth_dev_is_detachable(port_id))
+ goto err;
+
+ /* get pci address by port id */
+ if (rte_eth_dev_get_addr_by_port(port_id, &freed_addr))
+ goto err;
+
+ /* Zerod pci addr means the port comes from virtual device */
+ vp.domain = vp.bus = vp.devid = vp.function = 0;
+ if (rte_eal_compare_pci_addr(&vp, &freed_addr) == 0)
+ goto err;
+
+ /* invoke close func of the driver,
+ * also remove the device from pci_device_list */
+ if (rte_eal_pci_close_one(&freed_addr))
+ goto err;
+
+ *addr = freed_addr;
+ return 0;
+err:
+ RTE_LOG(ERR, EAL, "Driver, cannot detach the device\n");
+ return -1;
+}
+
+static void
+get_vdev_name(char *vdevargs)
+{
+ char *sep;
+
+ if (vdevargs == NULL)
+ return;
+
+ /* set the first ',' to '\0' to split name and arguments */
+ sep = strchr(vdevargs, ',');
+ if (sep != NULL)
+ sep[0] = '\0';
+}
+
+/* attach the new virtual device, then store port_id of the device */
+static int
+rte_eal_dev_attach_vdev(const char *vdevargs, uint8_t *port_id)
+{
+ char *args;
+ uint8_t new_port_id;
+ struct rte_eth_dev devs[RTE_MAX_ETHPORTS];
+
+ if ((vdevargs == NULL) || (port_id == NULL))
+ goto err0;
+
+ args = strdup(vdevargs);
+ if (args == NULL)
+ goto err0;
+
+ /* save current port status */
+ if (rte_eth_dev_save(devs, sizeof(devs)))
+ goto err1;
+ /* add the vdevargs to devargs_list */
+ if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, args))
+ goto err1;
+ /* parse vdevargs, then retrieve device name */
+ get_vdev_name(args);
+ /* walk around dev_driver_list to find the driver of the device,
+ * then invoke probe function o the driver */
+ if (rte_eal_vdev_find_and_init(args))
+ goto err2;
+ /* get port_id enabled by above procedures */
+ if (rte_eth_dev_get_changed_port(devs, &new_port_id))
+ goto err2;
+
+ free(args);
+ *port_id = new_port_id;
+ return 0;
+err2:
+ rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, args);
+err1:
+ free(args);
+err0:
+ RTE_LOG(ERR, EAL, "Driver, cannot attach the device\n");
+ return -1;
+}
+
+/* detach the new virtual device, then store the name of the device */
+static int
+rte_eal_dev_detach_vdev(uint8_t port_id, char *vdevname)
+{
+ char name[RTE_ETH_NAME_MAX_LEN];
+
+ if (vdevname == NULL)
+ goto err;
+
+ /* check whether the driver supports detach feature, or not */
+ if (rte_eth_dev_is_detachable(port_id))
+ goto err;
+
+ /* get device name by port id */
+ if (rte_eth_dev_get_name_by_port(port_id, name))
+ goto err;
+ /* walk around dev_driver_list to find the driver of the device,
+ * then invoke close function o the driver */
+ if (rte_eal_vdev_find_and_uninit(name))
+ goto err;
+ /* remove the vdevname from devargs_list */
+ if (rte_eal_devargs_remove(RTE_DEVTYPE_VIRTUAL, name))
+ goto err;
+
+ strncpy(vdevname, name, sizeof(name));
+ return 0;
+err:
+ RTE_LOG(ERR, EAL, "Driver, cannot detach the device\n");
+ return -1;
+}
+
+/* attach the new device, then store port_id of the device */
+int
+rte_eal_dev_attach(const char *devargs, uint8_t *port_id)
+{
+ struct rte_pci_addr addr;
+
+ if ((devargs == NULL) || (port_id == NULL))
+ return -EINVAL;
+
+ if (eal_parse_pci_DomBDF(devargs, &addr) == 0)
+ return rte_eal_dev_attach_pdev(&addr, port_id);
+ else
+ return rte_eal_dev_attach_vdev(devargs, port_id);
+}
+
+/* detach the device, then store the name of the device */
+int
+rte_eal_dev_detach(uint8_t port_id, char *name)
+{
+ struct rte_pci_addr addr;
+ int ret;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ if (rte_eth_dev_get_device_type(port_id) == RTE_ETH_DEV_PCI) {
+ ret = rte_eth_dev_get_addr_by_port(port_id, &addr);
+ if (ret < 0)
+ return ret;
+
+ ret = rte_eal_dev_detach_pdev(port_id, &addr);
+ if (ret == 0)
+ snprintf(name, RTE_ETH_NAME_MAX_LEN,
+ "%04x:%02x:%02x.%d",
+ addr.domain, addr.bus,
+ addr.devid, addr.function);
+
+ return ret;
+ } else
+ return rte_eal_dev_detach_vdev(port_id, name);
+}
+#else /* RTE_LIBRTE_EAL_HOTPLUG */
+int
+rte_eal_dev_attach(const char *devargs __rte_unused,
+ uint8_t *port_id __rte_unused)
+{
+ RTE_LOG(ERR, EAL, "Hotplug support isn't enabled\n");
+ return -1;
+}
+
+/* detach the device, then store the name of the device */
+int
+rte_eal_dev_detach(uint8_t port_id __rte_unused,
+ char *name __rte_unused)
+{
+ RTE_LOG(ERR, EAL, "Hotplug support isn't enabled\n");
+ return -1;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG */
@@ -154,6 +154,17 @@ struct rte_pci_driver;
struct rte_pci_device;
/**
+ * Scan the content of the PCI bus, and the devices in the devices
+ * list
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ * 0 on success, negative on error
+ */
+int rte_eal_pci_scan(void);
+
+/**
* Mmap memory for single PCI device
*
* This function is private to EAL.
@@ -47,6 +47,7 @@ extern "C" {
#endif
#include <sys/queue.h>
+#include <rte_pci.h>
/** Double linked list of device drivers. */
TAILQ_HEAD(rte_driver_list, rte_driver);
@@ -57,6 +58,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
typedef int (rte_dev_init_t)(const char *name, const char *args);
/**
+ * Uninitilization function called for each device driver once.
+ */
+typedef int (rte_dev_uninit_t)(const char *name);
+
+/**
* Driver type enumeration
*/
enum pmd_type {
@@ -72,6 +78,7 @@ struct rte_driver {
enum pmd_type type; /**< PMD Driver type */
const char *name; /**< Driver name. */
rte_dev_init_t *init; /**< Device init. function. */
+ rte_dev_uninit_t *uninit; /**< Device uninit. function. */
};
/**
@@ -93,6 +100,32 @@ void rte_eal_driver_register(struct rte_driver *driver);
void rte_eal_driver_unregister(struct rte_driver *driver);
/**
+ * Attach a new device.
+ *
+ * @param devargs
+ * A pointer to a strings array describing the new device
+ * to be attached. The strings should be a pci address like
+ * '0000:01:00.0' or virtual device name like 'eth_pcap0'.
+ * @param port_id
+ * A pointer to a port identifier actually attached.
+ * @return
+ * 0 on success and port_id is filled, negative on error
+ */
+int rte_eal_dev_attach(const char *devargs, uint8_t *port_id);
+
+/**
+ * Detach a device.
+ *
+ * @param port_id
+ * The port identifier of the device to detach.
+ * @param addr
+ * A pointer to a device name actually detached.
+ * @return
+ * 0 on success and devname is filled, negative on error
+ */
+int rte_eal_dev_detach(uint8_t port_id, char *devname);
+
+/**
* Initalize all the registered drivers in this process
*/
int rte_eal_dev_init(void);
@@ -45,6 +45,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
CFLAGS += -I$(RTE_SDK)/lib/librte_ring
CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
+CFLAGS += -I$(RTE_SDK)/lib/librte_mbuf
CFLAGS += -I$(RTE_SDK)/lib/librte_ether
CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
@@ -441,8 +441,8 @@ error:
* Scan the content of the PCI bus, and the devices in the devices
* list
*/
-static int
-pci_scan(void)
+int
+rte_eal_pci_scan(void)
{
struct dirent *e;
DIR *dir;
@@ -774,7 +774,7 @@ rte_eal_pci_init(void)
if (internal_config.no_pci)
return 0;
- if (pci_scan() < 0) {
+ if (rte_eal_pci_scan() < 0) {
RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__);
return -1;
}
@@ -21,6 +21,8 @@ DPDK_2.0 {
rte_eal_alarm_cancel;
rte_eal_alarm_set;
rte_eal_dev_init;
+ rte_eal_dev_attach;
+ rte_eal_dev_detach;
rte_eal_devargs_add;
rte_eal_devargs_dump;
rte_eal_devargs_type_count;