aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/hotplug/Linux/xen-backend.rules6
-rw-r--r--tools/libxl/libxl_device.c60
-rw-r--r--tools/libxl/libxl_internal.h14
-rw-r--r--tools/libxl/libxl_linux.c108
-rw-r--r--tools/libxl/libxl_netbsd.c3
5 files changed, 178 insertions, 13 deletions
diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules
index d55ff11309..c591a3ff03 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 a80dee846f..da0c3ea7c8 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -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)
{
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2567c4d38a..cf5ab712ad 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -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 -----*/
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 97b3fd4a64..9ae0b4b88f 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -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;
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index a2f8d3f0c5..28cdf21d73 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -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;
}