[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl

Roger Pau Monne
Wed, 30 May 2012 13:07:54 -0000

Since most of the needed work is already done in previous patches,
this patch only contains the necessary code to call hotplug scripts
for nic devices, that should be called when the device is added or
removed from a guest.

Added another parameter to libxl__get_hotplug_script_info, that is
used to know the number of times hotplug scripts have been called for
that device. This is currently used by IOEMU nics on Linux.

Changes since v4:

 * Add num_exec to NetBSD dummy function.

 * Better comment in the prototype of libxl__get_hotplug_script_info.

 * Remove nasty use of goto.

Changes since v2:

 * Change libxl__nic_type to return the value in a parameter passed by
   the caller.

 * Rename vif_execute to num_exec, to represent the number of times
   hotplug scripts have been called for that device.

Changes since v1:

 * Move event code to libxl_device.c (as in previous patch).

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/hotplug/Linux/xen-backend.rules |    6 +-
 tools/libxl/libxl_device.c            |   46 +++++++++++++++++-
 tools/libxl/libxl_internal.h          |   14 +++++-
 tools/libxl/libxl_linux.c             |   84 +++++++++++++++++++++++++++++++-
 tools/libxl/libxl_netbsd.c            |    3 +-
 5 files changed, 144 insertions(+), 9 deletions(-)

diff --git a/tools/hotplug/Linux/xen-backend.rules
b/tools/hotplug/Linux/xen-backend.rules
index d55ff11..c591a3f 100644
--- a/tools/hotplug/Linux/xen-backend.rules
+++ b/tools/hotplug/Linux/xen-backend.rules
@@ -2,8 +2,8 @@ SUBSYSTEM=="xen-backend", KERNEL=="tap*",
ENV{UDEV_CALL}="1", RUN+="/etc/xen/scr
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*",
ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/block
$env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*",
RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif2-*",
RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*",
ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online
type_if=vif"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*",
ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline
type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*",
ENV{UDEV_CALL}="1", ACTION=="online",
RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*",
ENV{UDEV_CALL}="1", ACTION=="offline",
RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*",
RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
 SUBSYSTEM=="xen-backend", ACTION=="remove",
ENV{UDEV_CALL}="1",
RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
@@ -13,4 +13,4 @@ KERNEL=="blktap-control",
NAME="xen/blktap-2/control", MODE="0600"
 KERNEL=="gntdev", NAME="xen/%k", MODE="0600"
 KERNEL=="pci_iomul", NAME="xen/%k", MODE="0600"
 KERNEL=="tapdev[a-z]*", NAME="xen/blktap-2/tapdev%m",
MODE="0600"
-SUBSYSTEM=="net", KERNEL=="vif*-emu",
ACTION=="add", RUN+="/etc/xen/scripts/vif-setup $env{ACTION}
type_if=tap"
+SUBSYSTEM=="net", KERNEL=="vif*-emu",
ACTION=="add", ENV{UDEV_CALL}="1",
RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap"
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 7db379a..841f9ac 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -100,6 +100,29 @@ out:
     return numdevs;
 }

+int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
+{
+    char *snictype, *be_path;
+    int rc = 0;
+
+    be_path = libxl__device_backend_path(gc, dev);
+    snictype = libxl__xs_read(gc, XBT_NULL,
+                              GCSPRINTF("%s/%s", be_path,
"type"));
+    if (!snictype) {
+        LOGE(ERROR, "unable to read nictype from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = libxl_nic_type_from_string(snictype, nictype);
+    if (rc) {
+        LOGE(ERROR, "unable to parse nictype from %s", be_path);
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
 int libxl__device_generic_add(libxl__gc *gc, libxl__device *device,
                              char **bents, char **fents)
 {
@@ -715,7 +738,8 @@ static void device_hotplug(libxl__egc *egc, libxl__ao_device
*aodev)
     /* Check if we have to execute hotplug scripts for this device
      * and return the necessary args/env vars for execution */
     hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args,
&env,
-                                             aodev->action);
+                                             aodev->action,
+                                             aodev->num_exec);
     switch (hotplug) {
     case 0:
         /* no hotplug script to execute */
@@ -776,6 +800,8 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
 {
     libxl__ao_device *aodev = CONTAINER_OF(child, *aodev, child);
     STATE_AO_GC(aodev->ao);
+    libxl_nic_type nictype;
+    int rc;

     libxl__ev_time_deregister(gc, &aodev->ev);

@@ -784,7 +810,25 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
                                                      : LIBXL__LOG_WARNING,
                                       aodev->what, pid, status);
         aodev->rc = ERROR_FAIL;
+        goto out;
     }
+
+    if (aodev->dev->backend_kind == LIBXL__DEVICE_KIND_VIF &&
+        aodev->num_exec == 0) {
+        rc = libxl__nic_type(gc, aodev->dev, &nictype);
+        if (rc) {
+            LOG(ERROR, "unable to get type of nic device");
+            aodev->rc = rc;
+            goto out;
+        }
+        if (nictype == LIBXL_NIC_TYPE_IOEMU) {
+            aodev->num_exec++;
+            device_hotplug(egc, aodev);
+            return;
+        }
+    }
+
+out:
     aodev->callback(egc, aodev);
 }

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 9dd2404..b938756 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -821,6 +821,8 @@ _hidden int libxl__parse_backend_path(libxl__gc *gc, const
char *path,
                                       libxl__device *dev);
 _hidden int libxl__device_destroy(libxl__gc *gc, libxl__device *dev);
 _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state);
+_hidden int libxl__nic_type(libxl__gc *gc, libxl__device *dev,
+                            libxl_nic_type *nictype);

 /*
  * For each aggregate type which can be used as an input we provide:
@@ -1849,6 +1851,7 @@ struct libxl__ao_device {
     void *base;
     /* device hotplug execution */
     char *what;
+    int num_exec;
     libxl__ev_time ev;
     libxl__ev_child child;
 };
@@ -1894,10 +1897,19 @@ _hidden void libxl__initiate_device_remove(libxl__egc
*egc,
  * < 0: Error
  * 0: No need to execute hotplug script
  * 1: Execute hotplug script
+ *
+ * The last parameter, "num_exec" refeers to the number of times
hotplug
+ * scripts have been called for this device. This is currently used for
+ * IOEMU nic interfaces on Linux, since we need to call hotplug scripts twice
+ * for the same device, the first one to add the vif interface, and the second
+ * time to add the tap interface, so:
+ * num_exec == 0: execute hotplug for vif interface.
+ * num_exec == 1: execute hotplug for the associated tap interface.
  */
 _hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                            char ***args, char ***env,
-                                           libxl__device_action action);
+                                           libxl__device_action action,
+                                           int num_exec);

 /*----- Domain destruction -----*/

diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 60a966f..3cd8f40 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -35,6 +35,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device
*dev)
     const char *type = libxl__device_kind_to_string(dev->backend_kind);
     char **env;
     int nr = 0;
+    libxl_nic_type nictype;

     script = libxl__xs_read(gc, XBT_NULL,
                             GCSPRINTF("%s/%s", be_path,
"script"));
@@ -43,7 +44,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device
*dev)
         return NULL;
     }

-    const int arraysize = 9;
+    const int arraysize = 13;
     GCNEW_ARRAY(env, arraysize);
     env[nr++] = "script";
     env[nr++] = script;
@@ -53,14 +54,86 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device
*dev)
     env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid,
dev->devid);
     env[nr++] = "XENBUS_BASE_PATH";
     env[nr++] = "backend";
+    if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
+        if (libxl__nic_type(gc, dev, &nictype)) {
+            LOG(ERROR, "unable to get nictype");
+            return NULL;
+        }
+        switch (nictype) {
+        case LIBXL_NIC_TYPE_IOEMU:
+            env[nr++] = "INTERFACE";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid,
dev->devid,
+                                                      LIBXL_NIC_TYPE_IOEMU));
+        case LIBXL_NIC_TYPE_VIF:
+            env[nr++] = "vif";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid,
dev->devid,
+                                                      LIBXL_NIC_TYPE_VIF));
+            break;
+        default:
+            return NULL;
+        }
+    }
+
     env[nr++] = NULL;
-    assert(nr == arraysize);
+    assert(nr <= arraysize);

     return env;
 }

 /* Hotplug scripts caller functions */

+static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
+                               char ***args, char ***env,
+                               libxl__device_action action, int num_exec)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    int nr = 0, rc = 0;
+    libxl_nic_type nictype;
+
+    script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
+
"script"));
+    if (!script) {
+        LOGE(ERROR, "unable to read script from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__nic_type(gc, dev, &nictype);
+    if (rc) {
+        LOG(ERROR, "error when fetching nic type");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    *env = get_hotplug_env(gc, dev);
+    if (!env) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    const int arraysize = 4;
+    GCNEW_ARRAY(*args, arraysize);
+    (*args)[nr++] = script;
+
+    if (nictype == LIBXL_NIC_TYPE_IOEMU && num_exec) {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "add" :
"remove";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=tap");
+        (*args)[nr++] = NULL;
+    } else {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "online" :
"offline";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=vif");
+        (*args)[nr++] = NULL;
+    }
+    assert(nr == arraysize);
+    rc = 0;
+
+out:
+    return rc;
+}
+
 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
                                char ***args, char ***env,
                                libxl__device_action action)
@@ -98,7 +171,8 @@ error:

 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
     int rc;
@@ -114,6 +188,10 @@ int libxl__get_hotplug_script_info(libxl__gc *gc,
libxl__device *dev,
         rc = libxl__hotplug_disk(gc, dev, args, env, action);
         if (!rc) rc = 1;
         break;
+    case LIBXL__DEVICE_KIND_VIF:
+        rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
+        if (!rc) rc = 1;
+        break;
     default:
         /* If no need to execute any hotplug scripts,
          * call the callback manually
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index d41a046..702eb1e 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -29,7 +29,8 @@ int libxl__try_phy_backend(mode_t st_mode)

 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     return 0;
 }
--
1.7.7.5 (Apple Git-26)