]> xenbits.xensource.com Git - xen.git/commitdiff
libxl: call hotplug scripts for nic devices from libxl
authorRoger Pau Monne <roger.pau@citrix.com>
Thu, 26 Jul 2012 15:47:35 +0000 (16:47 +0100)
committerRoger Pau Monne <roger.pau@citrix.com>
Thu, 26 Jul 2012 15:47:35 +0000 (16:47 +0100)
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.

Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
Acked-by: Ian Jackson<ian.jackson@eu.citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
tools/hotplug/Linux/xen-backend.rules
tools/libxl/libxl_device.c
tools/libxl/libxl_internal.h
tools/libxl/libxl_linux.c
tools/libxl/libxl_netbsd.c

index d55ff113090d22ee86813bacd3c79ded31307198..c591a3ff03b704464367f46a2bbdd527f7e01f58 100644 (file)
@@ -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"
index a80dee846f27829ee8025a5ff75df8a928b23d39..da0c3ea7c87404d2a316f72d2eb652cf2ab04b28 100644 (file)
@@ -102,6 +102,31 @@ 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;
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
 int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t,
         libxl__device *device, char **bents, char **fents)
 {
@@ -638,6 +663,8 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
 
 static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
 
+static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev);
+
 void libxl__wait_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
@@ -850,7 +877,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 */
@@ -930,6 +958,8 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
     char *be_path = libxl__device_backend_path(gc, aodev->dev);
     char *hotplug_error;
 
+    device_hotplug_clean(gc, aodev);
+
     if (status) {
         libxl_report_child_exitstatus(CTX, LIBXL__LOG_ERROR,
                                       aodev->what, pid, status);
@@ -938,8 +968,25 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
         if (hotplug_error)
             LOG(ERROR, "script: %s", hotplug_error);
         aodev->rc = ERROR_FAIL;
+        if (aodev->action == DEVICE_CONNECT)
+            /*
+             * Only fail on device connection, on disconnection
+             * ignore error, and continue with the remove process
+             */
+             goto error;
     }
 
+    /* Increase num_exec and call hotplug scripts again if necessary
+     * If no more executions are needed, device_hotplug will call
+     * device_hotplug_done breaking the loop.
+     */
+    aodev->num_exec++;
+    device_hotplug(egc, aodev);
+
+    return;
+
+error:
+    assert(aodev->rc);
     device_hotplug_done(egc, aodev);
 }
 
@@ -951,9 +998,7 @@ static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
     xs_transaction_t t = 0;
     int rc;
 
-    /* Clean events and check reentrancy */
-    libxl__ev_time_deregister(gc, &aodev->timeout);
-    assert(!libxl__ev_child_inuse(&aodev->child));
+    device_hotplug_clean(gc, aodev);
 
     /* Clean xenstore if it's a disconnection */
     if (aodev->action == DEVICE_DISCONNECT) {
@@ -975,6 +1020,13 @@ out:
     return;
 }
 
+static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev)
+{
+    /* Clean events and check reentrancy */
+    libxl__ev_time_deregister(gc, &aodev->timeout);
+    assert(!libxl__ev_child_inuse(&aodev->child));
+}
+
 static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs,
                                     int rc)
 {
index 2567c4d38aa3a44b90a76eb09f73bfd2c8e57488..cf5ab712ad52b570e63d07ce5996848398b510c3 100644 (file)
@@ -920,6 +920,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:
@@ -1840,6 +1842,7 @@ struct libxl__ao_device {
     libxl__ao_devices *aodevs;
     /* device hotplug execution */
     const char *what;
+    int num_exec;
     libxl__ev_child child;
 };
 
@@ -1979,10 +1982,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.
+ *
+ * The main body of libxl will, for each device, keep calling
+ * libxl__get_hotplug_script_info, with incrementing values of
+ * num_exec, and executing the resulting script accordingly,
+ * until libxl__get_hotplug_script_info returns<=0.
  */
 _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);
 
 /*----- local disk attach: attach a disk locally to run the bootloader -----*/
 
index 97b3fd4a64553854edf4324bac090b2f073086e9..9ae0b4b88f8f54bae34afbc23ad5164b32b2c483 100644 (file)
@@ -87,6 +87,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"));
@@ -95,24 +96,106 @@ 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;
     env[nr++] = "XENBUS_TYPE";
-    env[nr++] = libxl__strdup(gc, type);
+    env[nr++] = (char *) type;
     env[nr++] = "XENBUS_PATH";
     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_VIF_IOEMU:
+            env[nr++] = "INTERFACE";
+            env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
+                                                    dev->devid,
+                                                    LIBXL_NIC_TYPE_VIF_IOEMU);
+            /*
+             * We need to fall through because for PV_IOEMU nic types we need
+             * to execute both the vif and the tap hotplug script, and we
+             * don't know which one we are executing in this call, so provide
+             * both env variables.
+             */
+        case LIBXL_NIC_TYPE_VIF:
+            env[nr++] = "vif";
+            env[nr++] = (char *) 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;
+    }
+    if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) {
+        rc = 0;
+        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_VIF_IOEMU && num_exec) {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "add" : "remove";
+        (*args)[nr++] = "type_if=tap";
+        (*args)[nr++] = NULL;
+    } else {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "online" : "offline";
+        (*args)[nr++] = "type_if=vif";
+        (*args)[nr++] = NULL;
+    }
+    assert(nr == arraysize);
+    rc = 1;
+
+out:
+    return rc;
+}
+
 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
                                char ***args, char ***env,
                                libxl__device_action action)
@@ -150,7 +233,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;
@@ -163,8 +247,24 @@ int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
 
     switch (dev->backend_kind) {
     case LIBXL__DEVICE_KIND_VBD:
+        if (num_exec != 0) {
+            rc = 0;
+            goto out;
+        }
         rc = libxl__hotplug_disk(gc, dev, args, env, action);
         break;
+    case LIBXL__DEVICE_KIND_VIF:
+        /*
+         * If domain has a stubdom we don't have to execute hotplug scripts
+         * for emulated interfaces
+         */
+        if ((num_exec > 1) ||
+            (libxl_get_stubdom_id(CTX, dev->domid) && num_exec)) {
+            rc = 0;
+            goto out;
+        }
+        rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
+        break;
     default:
         /* No need to execute any hotplug scripts */
         rc = 0;
index a2f8d3f0c5a98b38e04bd1a943c15aeb0f63db03..28cdf21d73d39daada558bf60825ba0a64d18cec 100644 (file)
@@ -34,7 +34,8 @@ char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
 /* Hotplug scripts caller functions */
 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;
 }