[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 14/14] Add support for network device detach



qemu network devices are hot-unplugged in two stages - first the PCI NIC
is removed using 'pci_del <pci_addr>' and then the backend is removed
using 'host_net_remove <vlan> <name>'.

In order to perform these operations we need to have retained the
PCI address, backend name and vlan number.

* src/qemu_driver.c: add qemudDomainDetachNetDevice()
---
 src/qemu_driver.c |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index a3bb650..4fa946c 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4906,6 +4906,96 @@ cleanup:
     return ret;
 }
 
+static int
+qemudDomainDetachNetDevice(virConnectPtr conn,
+                           virDomainObjPtr vm,
+                           virDomainDeviceDefPtr dev)
+{
+    int i, ret = -1;
+    char *cmd = NULL;
+    char *reply = NULL;
+    virDomainNetDefPtr detach = NULL;
+
+    for (i = 0 ; i < vm->def->nnets ; i++) {
+        virDomainNetDefPtr net = vm->def->nets[i];
+
+        if (!memcmp(net->mac, dev->data.net->mac,  sizeof(net->mac))) {
+            detach = net;
+            break;
+        }
+    }
+
+    if (!detach) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("network device %02x:%02x:%02x:%02x:%02x:%02x not found"),
+                         detach->mac[0], detach->mac[1], detach->mac[2],
+                         detach->mac[3], detach->mac[4], detach->mac[5]);
+        goto cleanup;
+    }
+
+    if (!detach->pci_addr || !detach->vlan || !detach->hostnet_name) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("network device cannot be detached - device state missing"));
+        goto cleanup;
+    }
+
+    if (virAsprintf(&cmd, "pci_del pci_addr=%s", detach->pci_addr) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
+    }
+
+    if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                          _("network device dettach command '%s' failed"), cmd);
+        goto cleanup;
+    }
+
+    DEBUG("%s: pci_del reply: %s", vm->def->name,  reply);
+
+    /* If the command fails due to a wrong PCI address qemu prints
+     * 'invalid pci address'; nothing is printed on success */
+    if (strstr(reply, "Invalid pci address")) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("failed to detach network device: invalid PCI address %s: %s"),
+                         detach->pci_addr, reply);
+        goto cleanup;
+    }
+
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+
+    if (virAsprintf(&cmd, "host_net_remove %d %s",
+                    detach->vlan, detach->hostnet_name) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
+    }
+
+    if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                          _("network device dettach command '%s' failed"), cmd);
+        goto cleanup;
+    }
+
+    DEBUG("%s: host_net_remove reply: %s", vm->def->name,  reply);
+
+    if (vm->def->nnets > 1) {
+        vm->def->nets[i] = vm->def->nets[--vm->def->nnets];
+        if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
+            virReportOOMError(conn);
+            goto cleanup;
+        }
+    } else {
+        VIR_FREE(vm->def->nets[0]);
+        vm->def->nnets = 0;
+    }
+    ret = 0;
+
+cleanup:
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+    return ret;
+}
+
 static int qemudDomainDetachDevice(virDomainPtr dom,
                                    const char *xml) {
     struct qemud_driver *driver = dom->conn->privateData;
@@ -4944,8 +5034,9 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
             driver->securityDriver->domainRestoreSecurityImageLabel(dom->conn, dev->data.disk);
         if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
             VIR_WARN0("Fail to restore disk device ownership");
-    }
-    else
+    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+        ret = qemudDomainDetachNetDevice(dom->conn, vm, dev);
+    } else
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                          "%s", _("only SCSI or virtio disk device can be detached dynamically"));
 
-- 
1.6.2.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]