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