/* * Copyright (C) 2014 * Author Roger Pau Monne * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 only. with the special * exception on linking described in file LICENSE. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ #include "libxl_osdeps.h" /* must come before any other headers */ #include "libxl_internal.h" int libxl__try_phy_backend(mode_t st_mode) { if (S_ISREG(st_mode) || S_ISBLK(st_mode) || S_ISCHR(st_mode)) return 1; return 0; } char *libxl__devid_to_localdev(libxl__gc *gc, int devid) { /* This translation table has been copied from the FreeBSD blkfront code. */ const static struct vdev_info { int major; int shift; int base; const char *name; } info[] = { {3, 6, 0, "ada"}, /* ide0 */ {22, 6, 2, "ada"}, /* ide1 */ {33, 6, 4, "ada"}, /* ide2 */ {34, 6, 6, "ada"}, /* ide3 */ {56, 6, 8, "ada"}, /* ide4 */ {57, 6, 10, "ada"}, /* ide5 */ {88, 6, 12, "ada"}, /* ide6 */ {89, 6, 14, "ada"}, /* ide7 */ {90, 6, 16, "ada"}, /* ide8 */ {91, 6, 18, "ada"}, /* ide9 */ {8, 4, 0, "da"}, /* scsi disk0 */ {65, 4, 16, "da"}, /* scsi disk1 */ {66, 4, 32, "da"}, /* scsi disk2 */ {67, 4, 48, "da"}, /* scsi disk3 */ {68, 4, 64, "da"}, /* scsi disk4 */ {69, 4, 80, "da"}, /* scsi disk5 */ {70, 4, 96, "da"}, /* scsi disk6 */ {71, 4, 112, "da"}, /* scsi disk7 */ {128, 4, 128, "da"}, /* scsi disk8 */ {129, 4, 144, "da"}, /* scsi disk9 */ {130, 4, 160, "da"}, /* scsi disk10 */ {131, 4, 176, "da"}, /* scsi disk11 */ {132, 4, 192, "da"}, /* scsi disk12 */ {133, 4, 208, "da"}, /* scsi disk13 */ {134, 4, 224, "da"}, /* scsi disk14 */ {135, 4, 240, "da"}, /* scsi disk15 */ {202, 4, 0, "xbd"}, /* xbd */ {0, 0, 0, NULL}, }; int major = devid >> 8; int minor = devid & 0xff; int i; if (devid & (1 << 28)) return GCSPRINTF("%s%d", "xbd", (devid & ((1 << 28) - 1)) >> 8); for (i = 0; info[i].major; i++) if (info[i].major == major) return GCSPRINTF("%s%d", info[i].name, info[i].base + (minor >> info[i].shift)); return GCSPRINTF("%s%d", "xbd", minor >> 4); } /* Hotplug scripts caller functions */ static int libxl__hotplug_env_nic(libxl__gc *gc, libxl__device *dev, char ***env, int num_exec) { int nr = 0; const int arraysize = 5; libxl_nic_type type; assert(dev->backend_kind == LIBXL__DEVICE_KIND_VIF); /* * On the first pass the PV interface is added to the bridge, * on the second pass the tap interface will also be added. */ type = num_exec == 0 ? LIBXL_NIC_TYPE_VIF : LIBXL_NIC_TYPE_VIF_IOEMU; GCNEW_ARRAY(*env, arraysize); (*env)[nr++] = "iface_dev"; (*env)[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid, dev->devid, type); (*env)[nr++] = "emulated"; (*env)[nr++] = type == LIBXL_NIC_TYPE_VIF_IOEMU ? "1" : "0"; (*env)[nr++] = NULL; assert(nr == arraysize); return 0; } static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev, char ***args, char ***env, libxl__device_action action, int num_exec) { libxl_nic_type nictype; char *be_path = libxl__device_backend_path(gc, dev); char *script; int nr = 0, rc; rc = libxl__nic_type(gc, dev, &nictype); if (rc) { LOGD(ERROR, dev->domid, "error when fetching nic type"); rc = ERROR_FAIL; goto out; } /* * For PV domains only one pass is needed (because there's no emulated * interface). For HVM domains two passes are needed in order to add * both the PV and the tap interfaces to the bridge. */ if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) { rc = 0; goto out; } rc = libxl__hotplug_env_nic(gc, dev, env, num_exec); if (rc) goto out; script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path, "script")); if (!script) { LOGEVD(ERROR, errno, dev->domid, "unable to read script from %s", be_path); rc = ERROR_FAIL; goto out; } const int arraysize = 4; GCNEW_ARRAY(*args, arraysize); (*args)[nr++] = script; (*args)[nr++] = be_path; (*args)[nr++] = (char *) libxl__device_action_to_string(action); (*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) { char *be_path = libxl__device_backend_path(gc, dev); char *script; int nr = 0, rc; script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path, "script")); if (!script) { LOGEVD(ERROR, errno, dev->domid, "unable to read script from %s", be_path); rc = ERROR_FAIL; goto out; } const int arraysize = 4; GCNEW_ARRAY(*args, arraysize); (*args)[nr++] = script; (*args)[nr++] = be_path; (*args)[nr++] = (char *) libxl__device_action_to_string(action); (*args)[nr++] = NULL; assert(nr == arraysize); rc = 1; out: return rc; } int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev, char ***args, char ***env, libxl__device_action action, int num_exec) { int rc; switch (dev->backend_kind) { 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; case LIBXL__DEVICE_KIND_VBD: if (num_exec != 0) { rc = 0; goto out; } rc = libxl__hotplug_disk(gc, dev, args, env, action); break; default: /* No need to execute any hotplug scripts */ rc = 0; break; } out: return rc; } int libxl__pci_numdevs(libxl__gc *gc) { return ERROR_NI; } int libxl__pci_topology_init(libxl__gc *gc, physdev_pci_device_t *devs, int num_devs) { return ERROR_NI; } int libxl__local_dm_preexec_restrict(libxl__gc *gc) { return 0; }