Until now, users could detach interface by MAC address, which is not
sufficient in cases when MAC is not unique. Therefore we need to
support detaching via PCI address as well. Or in case when domain has
exactly one interface users does not need to specify any MAC/PCI
address at all.
---
src/qemu/qemu_driver.c | 3 ++-
src/qemu/qemu_hotplug.c | 46 ++++++++++++++++++++++++++++++++++------------
2 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dac2bf2..3bf5d2e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4293,7 +4293,8 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
}
dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
- VIR_DOMAIN_XML_INACTIVE);
+ VIR_DOMAIN_XML_INACTIVE |
+ VIR_DOMAIN_PARSE_NO_GENERATE);
if (dev == NULL)
goto endjob;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d8a8e5d..4175d2c 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1470,7 +1470,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
virDomainDeviceDefPtr dev,
virBitmapPtr qemuCaps)
{
- int i, ret = -1;
+ int i, interface_num = 0, ret = -1;
virDomainNetDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
int vlan;
@@ -1478,19 +1478,41 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
for (i = 0 ; i < vm->def->nnets ; i++) {
virDomainNetDefPtr net = vm->def->nets[i];
-
- if (!memcmp(net->mac, dev->data.net->mac, VIR_MAC_BUFLEN)) {
+ virDomainDevicePCIAddress pci[2] = {net->info.addr.pci,
+ dev->data.net->info.addr.pci};
+
+ if ( ((dev->data.net->mac != NULL) &&
+ !memcmp(net->mac, dev->data.net->mac, VIR_MAC_BUFLEN)) ||
+ ((dev->data.net->mac == NULL) && (vm->def->nnets == 1))
||
+ ((pci[0].domain == pci[1].domain) &&
+ (pci[0].bus == pci[1].bus) &&
+ (pci[0].slot == pci[1].slot) &&
+ (pci[0].function == pci[1].function)) ) {
+ if (detach) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("ambiguous device specification. "
+ "Use <mac> and/or <address>"));
+ goto cleanup;
+ }
detach = net;
- break;
+ interface_num = i;
}
}
if (!detach) {
- qemuReportError(VIR_ERR_OPERATION_FAILED,
- _("network device %02x:%02x:%02x:%02x:%02x:%02x not
found"),
- dev->data.net->mac[0], dev->data.net->mac[1],
- dev->data.net->mac[2], dev->data.net->mac[3],
- dev->data.net->mac[4], dev->data.net->mac[5]);
+ if (vm->def->nnets == 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("domain has no device to detach"));
+ } else if (dev->data.net->mac) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("network device %02x:%02x:%02x:%02x:%02x:%02x not
found"),
+ dev->data.net->mac[0], dev->data.net->mac[1],
+ dev->data.net->mac[2], dev->data.net->mac[3],
+ dev->data.net->mac[4], dev->data.net->mac[5]);
+ } else {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("network device not found. Use <mac> and/or
<address>"));
+ }
goto cleanup;
}
@@ -1571,10 +1593,10 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
}
if (vm->def->nnets > 1) {
- memmove(vm->def->nets + i,
- vm->def->nets + i + 1,
+ memmove(vm->def->nets + interface_num,
+ vm->def->nets + interface_num + 1,
sizeof(*vm->def->nets) *
- (vm->def->nnets - (i + 1)));
+ (vm->def->nnets - (interface_num + 1)));
vm->def->nnets--;
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
/* ignore, harmless */
--
1.7.4