For now only for PCI devices. Mostly copy-paste from old xen driver. --- src/libxl/libxl_driver.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 40a7a6b..011edf8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -42,6 +42,7 @@ #include "libxl.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "node_device_conf.h" #include "xen_xm.h" #include "virtypedparam.h" #include "viruri.h" @@ -3666,6 +3667,195 @@ libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, return libxlDomainModifyDeviceFlags(dom, xml, flags, LIBXL_DEVICE_UPDATE); } +static int +libxlNodeDeviceGetPciInfo(virNodeDevicePtr dev, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDeviceDefPtr def = NULL; + virNodeDevCapsDefPtr cap; + char *xml = NULL; + int ret = -1; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto out; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto out; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), dev->name); + goto out; + } + + ret = 0; +out: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceDetach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceAssignedDomainId(virNodeDevicePtr dev) +{ + int numdomains; + int numpcidevs; + int ret = -1, i, j; + int *ids = NULL; + char *bdf = NULL; + char *xref = NULL; + unsigned int domain, bus, slot, function; + libxl_device_pci *pcidevs = NULL; + virConnectPtr conn = dev->conn; + libxlDriverPrivatePtr driver = conn->privateData; + + /* Get active domains */ + numdomains = libxlNumDomains(conn); + if (numdomains < 0) { + return ret; + } + if (numdomains > 0){ + if (VIR_ALLOC_N(ids, numdomains) < 0) { + virReportOOMError(); + goto out; + } + if ((numdomains = libxlListDomains(conn, &ids[0], numdomains)) < 0) { + goto out; + } + } + + /* Get pci bdf */ + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + goto out; + + if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x", + domain, bus, slot, function) < 0) { + virReportOOMError(); + goto out; + } + + libxlDriverLock(driver); + /* Check if bdf is assigned to one of active domains */ + for (i = 0; i < numdomains; i++) { + pcidevs = libxl_device_pci_list(driver->ctx, ids[i], &numpcidevs); + if (pcidevs == NULL) { + continue; + } else { + for (j = 0; j < numpcidevs; j++) { + if (pcidevs[j].bus == bus && pcidevs[j].dev == slot && pcidevs[j].func == function) { + ret = ids[i]; + break; + } + } + VIR_FREE(pcidevs); + } + } + libxlDriverUnlock(driver); + + VIR_FREE(xref); + VIR_FREE(bdf); +out: + VIR_FREE(ids); + + return ret; +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + int domid; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + /* Check if device is assigned to an active guest */ + if ((domid = libxlNodeDeviceAssignedDomainId(dev)) >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device %s has been assigned to guest %d"), + dev->name, domid); + goto out; + } + + if (virPCIDeviceReattach(pci, NULL, NULL, "pciback") < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain, bus, slot, function; + int ret = -1; + + if (libxlNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) + return -1; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + return -1; + + if (virPCIDeviceReset(pci, NULL, NULL) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); + return ret; +} + static unsigned long long libxlNodeGetFreeMemory(virConnectPtr conn) { @@ -4233,6 +4423,9 @@ static virDriver libxlDriver = { .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */ .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.0.4 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.0.4 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.0.4 */ .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */ .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */ .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */ -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list