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