eal: enable hotplug on multi-process
authorQi Zhang <qi.z.zhang@intel.com>
Tue, 16 Oct 2018 00:16:28 +0000 (08:16 +0800)
committerThomas Monjalon <thomas@monjalon.net>
Wed, 17 Oct 2018 08:16:18 +0000 (10:16 +0200)
We are going to introduce the solution to handle hotplug in
multi-process, it includes the below scenario:

1. Attach a device from the primary
2. Detach a device from the primary
3. Attach a device from a secondary
4. Detach a device from a secondary

In the primary-secondary process model, we assume devices are shared
by default. that means attaches or detaches a device on any process
will broadcast to all other processes through mp channel then device
information will be synchronized on all processes.

Any failure during attaching/detaching process will cause inconsistent
status between processes, so proper rollback action should be considered.

This patch covers the implementation of case 1,2.
Case 3,4 will be implemented on a separate patch.

IPC scenario for Case 1, 2:

attach a device
a) primary attach the new device if failed goto h).
b) primary send attach sync request to all secondary.
c) secondary receive request and attach the device and send a reply.
d) primary check the reply if all success goes to i).
e) primary send attach rollback sync request to all secondary.
f) secondary receive the request and detach the device and send a reply.
g) primary receive the reply and detach device as rollback action.
h) attach fail
i) attach success

detach a device
a) primary send detach sync request to all secondary
b) secondary detach the device and send reply
c) primary check the reply if all success goes to f).
d) primary send detach rollback sync request to all secondary.
e) secondary receive the request and attach back device. goto g)
f) primary detach the device if success goto g), else goto d)
g) detach fail.
h) detach success.

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
doc/guides/rel_notes/release_18_11.rst
lib/librte_eal/bsdapp/eal/Makefile
lib/librte_eal/common/eal_common_dev.c
lib/librte_eal/common/eal_private.h
lib/librte_eal/common/hotplug_mp.c [new file with mode: 0644]
lib/librte_eal/common/hotplug_mp.h [new file with mode: 0644]
lib/librte_eal/common/include/rte_dev.h
lib/librte_eal/common/include/rte_eal.h
lib/librte_eal/common/meson.build
lib/librte_eal/linuxapp/eal/Makefile
lib/librte_eal/linuxapp/eal/eal.c

index c13ea82..2467d04 100644 (file)
@@ -65,6 +65,13 @@ New Features
   ``rte_dev_hotplug_handle_enable`` and ``rte_dev_hotplug_handle_disable`` are
   for enabling or disabling hotplug handle mechanism.
 
+* **Support device multi-process hotplug.**
+
+  Hotplug and hot-unplug for devices will now be supported in multiprocessing
+  scenario. Any ethdev devices created in the primary process will be regarded
+  as shared and will be available for all DPDK processes. Synchronization
+  between processes will be done using DPDK IPC.
+
 * **Added new Flow API actions to rewrite fields in packet headers.**
 
   Added new Flow API actions to:
@@ -199,6 +206,11 @@ API Changes
 * eal: The parameters of the function ``rte_devargs_remove()`` have changed
   from bus and device names to ``struct rte_devargs``.
 
+* eal: The scope of ``rte_eal_hotplug_add()``/``rte_dev_probe()``
+  and ``rte_eal_hotplug_remove()``/``rte_dev_remove()`` is extended.
+  In multi-process model, they will guarantee that the device is
+  attached or detached on all processes.
+
 * mbuf: The ``__rte_mbuf_raw_free()`` and ``__rte_pktmbuf_prefree_seg()``
   functions were deprecated since 17.05 and are replaced by
   ``rte_mbuf_raw_free()`` and ``rte_pktmbuf_prefree_seg()``.
index 97bff48..6e9bc02 100644 (file)
@@ -62,6 +62,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_proc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_fbarray.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_uuid.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += hotplug_mp.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_mp.c
index 1c82f40..631e174 100644 (file)
 #include <rte_log.h>
 #include <rte_spinlock.h>
 #include <rte_malloc.h>
+#include <rte_string_fns.h>
 
 #include "eal_private.h"
+#include "hotplug_mp.h"
 
 /**
  * The device event callback description.
@@ -127,37 +129,58 @@ int rte_eal_dev_detach(struct rte_device *dev)
        return ret;
 }
 
-int
-rte_eal_hotplug_add(const char *busname, const char *devname,
-                   const char *drvargs)
+/* helper function to build devargs, caller should free the memory */
+static int
+build_devargs(const char *busname, const char *devname,
+             const char *drvargs, char **devargs)
 {
-       int ret;
-       char *devargs = NULL;
        int length;
 
        length = snprintf(NULL, 0, "%s:%s,%s", busname, devname, drvargs);
        if (length < 0)
                return -EINVAL;
-       devargs = malloc(length + 1);
-       if (devargs == NULL)
+
+       *devargs = malloc(length + 1);
+       if (*devargs == NULL)
                return -ENOMEM;
-       ret = snprintf(devargs, length + 1, "%s:%s,%s", busname, devname, drvargs);
-       if (ret < 0)
+
+       length = snprintf(*devargs, length + 1, "%s:%s,%s",
+                       busname, devname, drvargs);
+       if (length < 0) {
+               free(*devargs);
                return -EINVAL;
+       }
 
-       ret = rte_dev_probe(devargs);
+       return 0;
+}
 
+int
+rte_eal_hotplug_add(const char *busname, const char *devname,
+                   const char *drvargs)
+{
+
+       char *devargs;
+       int ret;
+
+       ret = build_devargs(busname, devname, drvargs, &devargs);
+       if (ret != 0)
+               return ret;
+
+       ret = rte_dev_probe(devargs);
        free(devargs);
+
        return ret;
 }
 
-int __rte_experimental
-rte_dev_probe(const char *devargs)
+/* probe device at local process. */
+int
+local_dev_probe(const char *devargs, struct rte_device **new_dev)
 {
        struct rte_device *dev;
        struct rte_devargs *da;
        int ret;
 
+       *new_dev = NULL;
        da = calloc(1, sizeof(*da));
        if (da == NULL)
                return -ENOMEM;
@@ -200,6 +223,8 @@ rte_dev_probe(const char *devargs)
                        dev->name);
                goto err_devarg;
        }
+
+       *new_dev = dev;
        return 0;
 
 err_devarg:
@@ -210,6 +235,99 @@ err_devarg:
        return ret;
 }
 
+int __rte_experimental
+rte_dev_probe(const char *devargs)
+{
+       struct eal_dev_mp_req req;
+       struct rte_device *dev;
+       int ret;
+
+       memset(&req, 0, sizeof(req));
+       req.t = EAL_DEV_REQ_TYPE_ATTACH;
+       strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
+
+       if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+               /**
+                * If in secondary process, just send IPC request to
+                * primary process.
+                */
+               ret = eal_dev_hotplug_request_to_primary(&req);
+               if (ret != 0) {
+                       RTE_LOG(ERR, EAL,
+                               "Failed to send hotplug request to primary\n");
+                       return -ENOMSG;
+               }
+               if (req.result != 0)
+                       RTE_LOG(ERR, EAL,
+                               "Failed to hotplug add device\n");
+               return req.result;
+       }
+
+       /* attach a shared device from primary start from here: */
+
+       /* primary attach the new device itself. */
+       ret = local_dev_probe(devargs, &dev);
+
+       if (ret != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to attach device on primary process\n");
+
+               /**
+                * it is possible that secondary process failed to attached a
+                * device that primary process have during initialization,
+                * so for -EEXIST case, we still need to sync with secondary
+                * process.
+                */
+               if (ret != -EEXIST)
+                       return ret;
+       }
+
+       /* primary send attach sync request to secondary. */
+       ret = eal_dev_hotplug_request_to_secondary(&req);
+
+       /* if any communication error, we need to rollback. */
+       if (ret != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to send hotplug add request to secondary\n");
+               ret = -ENOMSG;
+               goto rollback;
+       }
+
+       /**
+        * if any secondary failed to attach, we need to consider if rollback
+        * is necessary.
+        */
+       if (req.result != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to attach device on secondary process\n");
+               ret = req.result;
+
+               /* for -EEXIST, we don't need to rollback. */
+               if (ret == -EEXIST)
+                       return ret;
+               goto rollback;
+       }
+
+       return 0;
+
+rollback:
+       req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
+
+       /* primary send rollback request to secondary. */
+       if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+               RTE_LOG(WARNING, EAL,
+                       "Failed to rollback device attach on secondary."
+                       "Devices in secondary may not sync with primary\n");
+
+       /* primary rollback itself. */
+       if (local_dev_remove(dev) != 0)
+               RTE_LOG(WARNING, EAL,
+                       "Failed to rollback device attach on primary."
+                       "Devices in secondary may not sync with primary\n");
+
+       return ret;
+}
+
 int
 rte_eal_hotplug_remove(const char *busname, const char *devname)
 {
@@ -231,8 +349,9 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
        return rte_dev_remove(dev);
 }
 
-int __rte_experimental
-rte_dev_remove(struct rte_device *dev)
+/* remove device at local process. */
+int
+local_dev_remove(struct rte_device *dev)
 {
        int ret;
 
@@ -248,10 +367,106 @@ rte_dev_remove(struct rte_device *dev)
        }
 
        ret = dev->bus->unplug(dev);
-       if (ret)
+       if (ret) {
                RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n",
                        dev->name);
+               return ret;
+       }
+
        rte_devargs_remove(dev->devargs);
+
+       return 0;
+}
+
+int __rte_experimental
+rte_dev_remove(struct rte_device *dev)
+{
+       struct eal_dev_mp_req req;
+       char *devargs;
+       int ret;
+
+       ret = build_devargs(dev->devargs->bus->name, dev->name, "", &devargs);
+       if (ret != 0)
+               return ret;
+
+       memset(&req, 0, sizeof(req));
+       req.t = EAL_DEV_REQ_TYPE_DETACH;
+       strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
+       free(devargs);
+
+       if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+               /**
+                * If in secondary process, just send IPC request to
+                * primary process.
+                */
+               ret = eal_dev_hotplug_request_to_primary(&req);
+               if (ret != 0) {
+                       RTE_LOG(ERR, EAL,
+                               "Failed to send hotplug request to primary\n");
+                       return -ENOMSG;
+               }
+               if (req.result != 0)
+                       RTE_LOG(ERR, EAL,
+                               "Failed to hotplug remove device\n");
+               return req.result;
+       }
+
+       /* detach a device from primary start from here: */
+
+       /* primary send detach sync request to secondary */
+       ret = eal_dev_hotplug_request_to_secondary(&req);
+
+       /**
+        * if communication error, we need to rollback, because it is possible
+        * part of the secondary processes still detached it successfully.
+        */
+       if (ret != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to send device detach request to secondary\n");
+               ret = -ENOMSG;
+               goto rollback;
+       }
+
+       /**
+        * if any secondary failed to detach, we need to consider if rollback
+        * is necessary.
+        */
+       if (req.result != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to detach device on secondary process\n");
+               ret = req.result;
+               /**
+                * if -ENOENT, we don't need to rollback, since devices is
+                * already detached on secondary process.
+                */
+               if (ret != -ENOENT)
+                       goto rollback;
+       }
+
+       /* primary detach the device itself. */
+       ret = local_dev_remove(dev);
+
+       /* if primary failed, still need to consider if rollback is necessary */
+       if (ret != 0) {
+               RTE_LOG(ERR, EAL,
+                       "Failed to detach device on primary process\n");
+               /* if -ENOENT, we don't need to rollback */
+               if (ret == -ENOENT)
+                       return ret;
+               goto rollback;
+       }
+
+       return 0;
+
+rollback:
+       req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
+
+       /* primary send rollback request to secondary. */
+       if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+               RTE_LOG(WARNING, EAL,
+                       "Failed to rollback device detach on secondary."
+                       "Devices in secondary may not sync with primary\n");
+
        return ret;
 }
 
index 535a715..b189d67 100644 (file)
@@ -292,6 +292,28 @@ int
 rte_devargs_layers_parse(struct rte_devargs *devargs,
                         const char *devstr);
 
+/*
+ * probe a device at local process.
+ *
+ * @param devargs
+ *   Device arguments including bus, class and driver properties.
+ * @param new_dev
+ *   new device be probed as output.
+ * @return
+ *   0 on success, negative on error.
+ */
+int local_dev_probe(const char *devargs, struct rte_device **new_dev);
+
+/**
+ * Hotplug remove a given device from a specific bus at local process.
+ *
+ * @param dev
+ *   Data structure of the device to remove.
+ * @return
+ *   0 on success, negative on error.
+ */
+int local_dev_remove(struct rte_device *dev);
+
 /**
  * Iterate over all buses to find the corresponding bus to handle the sigbus
  * error.
diff --git a/lib/librte_eal/common/hotplug_mp.c b/lib/librte_eal/common/hotplug_mp.c
new file mode 100644 (file)
index 0000000..92d8f50
--- /dev/null
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_string_fns.h>
+#include <rte_devargs.h>
+
+#include "hotplug_mp.h"
+#include "eal_private.h"
+
+#define MP_TIMEOUT_S 5 /**< 5 seconds timeouts */
+
+static int cmp_dev_name(const struct rte_device *dev, const void *_name)
+{
+       const char *name = _name;
+
+       return strcmp(dev->name, name);
+}
+
+struct mp_reply_bundle {
+       struct rte_mp_msg msg;
+       void *peer;
+};
+
+static int
+handle_secondary_request(const struct rte_mp_msg *msg, const void *peer)
+{
+       RTE_SET_USED(msg);
+       RTE_SET_USED(peer);
+       return -ENOTSUP;
+}
+
+static void __handle_primary_request(void *param)
+{
+       struct mp_reply_bundle *bundle = param;
+       struct rte_mp_msg *msg = &bundle->msg;
+       const struct eal_dev_mp_req *req =
+               (const struct eal_dev_mp_req *)msg->param;
+       struct rte_mp_msg mp_resp;
+       struct eal_dev_mp_req *resp =
+               (struct eal_dev_mp_req *)mp_resp.param;
+       struct rte_devargs *da;
+       struct rte_device *dev;
+       struct rte_bus *bus;
+       int ret = 0;
+
+       memset(&mp_resp, 0, sizeof(mp_resp));
+
+       switch (req->t) {
+       case EAL_DEV_REQ_TYPE_ATTACH:
+       case EAL_DEV_REQ_TYPE_DETACH_ROLLBACK:
+               ret = local_dev_probe(req->devargs, &dev);
+               break;
+       case EAL_DEV_REQ_TYPE_DETACH:
+       case EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK:
+               da = calloc(1, sizeof(*da));
+               if (da == NULL) {
+                       ret = -ENOMEM;
+                       goto quit;
+               }
+
+               ret = rte_devargs_parse(da, req->devargs);
+               if (ret != 0)
+                       goto quit;
+
+               bus = rte_bus_find_by_name(da->bus->name);
+               if (bus == NULL) {
+                       RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", da->bus->name);
+                       ret = -ENOENT;
+                       goto quit;
+               }
+
+               dev = bus->find_device(NULL, cmp_dev_name, da->name);
+               if (dev == NULL) {
+                       RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", da->name);
+                       ret = -ENOENT;
+                       goto quit;
+               }
+
+               ret = local_dev_remove(dev);
+quit:
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
+       mp_resp.len_param = sizeof(*req);
+       memcpy(resp, req, sizeof(*resp));
+       resp->result = ret;
+       if (rte_mp_reply(&mp_resp, bundle->peer) < 0)
+               RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
+
+       free(bundle->peer);
+       free(bundle);
+}
+
+static int
+handle_primary_request(const struct rte_mp_msg *msg, const void *peer)
+{
+       struct rte_mp_msg mp_resp;
+       const struct eal_dev_mp_req *req =
+               (const struct eal_dev_mp_req *)msg->param;
+       struct eal_dev_mp_req *resp =
+               (struct eal_dev_mp_req *)mp_resp.param;
+       struct mp_reply_bundle *bundle;
+       int ret = 0;
+
+       memset(&mp_resp, 0, sizeof(mp_resp));
+       strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
+       mp_resp.len_param = sizeof(*req);
+       memcpy(resp, req, sizeof(*resp));
+
+       bundle = calloc(1, sizeof(*bundle));
+       if (bundle == NULL) {
+               resp->result = -ENOMEM;
+               ret = rte_mp_reply(&mp_resp, peer);
+               if (ret)
+                       RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
+               return ret;
+       }
+
+       bundle->msg = *msg;
+       /**
+        * We need to send reply on interrupt thread, but peer can't be
+        * parsed directly, so this is a temporal hack, need to be fixed
+        * when it is ready.
+        */
+       bundle->peer = (void *)strdup(peer);
+
+       /**
+        * We are at IPC callback thread, sync IPC is not allowed due to
+        * dead lock, so we delegate the task to interrupt thread.
+        */
+       ret = rte_eal_alarm_set(1, __handle_primary_request, bundle);
+       if (ret != 0) {
+               resp->result = ret;
+               ret = rte_mp_reply(&mp_resp, peer);
+               if  (ret != 0) {
+                       RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+int eal_dev_hotplug_request_to_primary(struct eal_dev_mp_req *req)
+{
+       RTE_SET_USED(req);
+       return -ENOTSUP;
+}
+
+int eal_dev_hotplug_request_to_secondary(struct eal_dev_mp_req *req)
+{
+       struct rte_mp_msg mp_req;
+       struct rte_mp_reply mp_reply;
+       struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
+       int ret;
+       int i;
+
+       memset(&mp_req, 0, sizeof(mp_req));
+       memcpy(mp_req.param, req, sizeof(*req));
+       mp_req.len_param = sizeof(*req);
+       strlcpy(mp_req.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_req.name));
+
+       ret = rte_mp_request_sync(&mp_req, &mp_reply, &ts);
+       if (ret != 0) {
+               RTE_LOG(ERR, EAL, "rte_mp_request_sync failed\n");
+               return ret;
+       }
+
+       if (mp_reply.nb_sent != mp_reply.nb_received) {
+               RTE_LOG(ERR, EAL, "not all secondary reply\n");
+               return -1;
+       }
+
+       req->result = 0;
+       for (i = 0; i < mp_reply.nb_received; i++) {
+               struct eal_dev_mp_req *resp =
+                       (struct eal_dev_mp_req *)mp_reply.msgs[i].param;
+               if (resp->result != 0) {
+                       req->result = resp->result;
+                       if (req->t == EAL_DEV_REQ_TYPE_ATTACH &&
+                               req->result != -EEXIST)
+                               break;
+                       if (req->t == EAL_DEV_REQ_TYPE_DETACH &&
+                               req->result != -ENOENT)
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+int rte_mp_dev_hotplug_init(void)
+{
+       int ret;
+
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+               ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
+                                       handle_secondary_request);
+               if (ret != 0) {
+                       RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
+                               EAL_DEV_MP_ACTION_REQUEST);
+                       return ret;
+               }
+       } else {
+               ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
+                                       handle_primary_request);
+               if (ret != 0) {
+                       RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
+                               EAL_DEV_MP_ACTION_REQUEST);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
diff --git a/lib/librte_eal/common/hotplug_mp.h b/lib/librte_eal/common/hotplug_mp.h
new file mode 100644 (file)
index 0000000..597fde3
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _HOTPLUG_MP_H_
+#define _HOTPLUG_MP_H_
+
+#include "rte_dev.h"
+#include "rte_bus.h"
+
+#define EAL_DEV_MP_ACTION_REQUEST      "eal_dev_mp_request"
+#define EAL_DEV_MP_ACTION_RESPONSE     "eal_dev_mp_response"
+
+#define EAL_DEV_MP_DEV_NAME_MAX_LEN RTE_DEV_NAME_MAX_LEN
+#define EAL_DEV_MP_BUS_NAME_MAX_LEN 32
+#define EAL_DEV_MP_DEV_ARGS_MAX_LEN 128
+
+enum eal_dev_req_type {
+       EAL_DEV_REQ_TYPE_ATTACH,
+       EAL_DEV_REQ_TYPE_DETACH,
+       EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK,
+       EAL_DEV_REQ_TYPE_DETACH_ROLLBACK,
+};
+
+struct eal_dev_mp_req {
+       enum eal_dev_req_type t;
+       char devargs[EAL_DEV_MP_DEV_ARGS_MAX_LEN];
+       int result;
+};
+
+/**
+ * This is a synchronous wrapper for secondary process send
+ * request to primary process, this is invoked when an attach
+ * or detach request is issued from primary process.
+ */
+int eal_dev_hotplug_request_to_primary(struct eal_dev_mp_req *req);
+
+/**
+ * this is a synchronous wrapper for primary process send
+ * request to secondary process, this is invoked when an attach
+ * or detach request issued from secondary process.
+ */
+int eal_dev_hotplug_request_to_secondary(struct eal_dev_mp_req *req);
+
+
+#endif /* _HOTPLUG_MP_H_ */
index 9b9c98b..b174bf4 100644 (file)
@@ -192,6 +192,9 @@ int rte_eal_dev_detach(struct rte_device *dev);
 /**
  * Hotplug add a given device to a specific bus.
  *
+ * In multi-process, it will request other processes to add the same device.
+ * A failure, in any process, will rollback the action
+ *
  * @param busname
  *   The bus name the device is added to.
  * @param devname
@@ -211,6 +214,9 @@ int rte_eal_hotplug_add(const char *busname, const char *devname,
  *
  * Add matching devices.
  *
+ * In multi-process, it will request other processes to add the same device.
+ * A failure, in any process, will rollback the action
+ *
  * @param devargs
  *   Device arguments including bus, class and driver properties.
  * @return
@@ -221,6 +227,9 @@ int __rte_experimental rte_dev_probe(const char *devargs);
 /**
  * Hotplug remove a given device from a specific bus.
  *
+ * In multi-process, it will request other processes to remove the same device.
+ * A failure, in any process, will rollback the action
+ *
  * @param busname
  *   The bus name the device is removed from.
  * @param devname
@@ -236,6 +245,9 @@ int rte_eal_hotplug_remove(const char *busname, const char *devname);
  *
  * Remove one device.
  *
+ * In multi-process, it will request other processes to remove the same device.
+ * A failure, in any process, will rollback the action
+ *
  * @param dev
  *   Data structure of the device to remove.
  * @return
index e114dcb..3ee897c 100644 (file)
@@ -377,6 +377,15 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
 int __rte_experimental
 rte_mp_reply(struct rte_mp_msg *msg, const char *peer);
 
+/**
+ * Register all mp action callbacks for hotplug.
+ *
+ * @return
+ *   0 on success, negative on error.
+ */
+int __rte_experimental
+rte_mp_dev_hotplug_init(void);
+
 /**
  * Usage function typedef used by the application usage function.
  *
index b7fc984..04c4143 100644 (file)
@@ -28,6 +28,7 @@ common_sources = files(
        'eal_common_thread.c',
        'eal_common_timer.c',
        'eal_common_uuid.c',
+       'hotplug_mp.c',
        'malloc_elem.c',
        'malloc_heap.c',
        'malloc_mp.c',
index 5c16bc4..736bc65 100644 (file)
@@ -70,6 +70,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_proc.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_fbarray.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_uuid.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += hotplug_mp.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_mp.c
index 950f33f..d342a04 100644 (file)
@@ -888,6 +888,12 @@ rte_eal_init(int argc, char **argv)
                }
        }
 
+       /* register multi-process action callbacks for hotplug */
+       if (rte_mp_dev_hotplug_init() < 0) {
+               rte_eal_init_alert("failed to register mp callback for hotplug\n");
+               return -1;
+       }
+
        if (rte_bus_scan()) {
                rte_eal_init_alert("Cannot scan the buses for devices\n");
                rte_errno = ENODEV;