return 0;
}
-int virDomainNetIndexByMac(virDomainDefPtr def, const virMacAddrPtr mac)
+/* virDomainNetFindIdx: search according to mac address and guest side
+ * PCI address (if specified)
+ *
+ * Return: index of match if unique match found
+ * -1 if not found
+ * -2 if multiple matches
+ */
+int
+virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
{
- int i;
+ int ii, matchidx = -1;
+ bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
- for (i = 0; i < def->nnets; i++)
- if (!virMacAddrCmp(&def->nets[i]->mac, mac))
- return i;
- return -1;
+ for (ii = 0 ; ii < def->nnets ; ii++) {
+ if (virMacAddrCmp(&def->nets[ii]->mac, &net->mac))
+ continue;
+
+ if ((matchidx >= 0) && !PCIAddrSpecified) {
+ /* there were multiple matches on mac address, and no
+ * qualifying guest-side PCI address was given, so we must
+ * fail (NB: a USB address isn't adequate, since it may
+ * specify only vendor and product ID, and there may be
+ * multiples of those.
+ */
+ matchidx = -2; /* indicates "multiple matches" to caller */
+ break;
+ }
+ if (PCIAddrSpecified) {
+ if (virDevicePCIAddressEqual(&def->nets[ii]->info.addr.pci,
+ &net->info.addr.pci)) {
+ /* exit early if the pci address was specified and
+ * it matches, as this guarantees no duplicates.
+ */
+ matchidx = ii;
+ break;
+ }
+ } else {
+ /* no PCI address given, so there may be multiple matches */
+ matchidx = ii;
+ }
+ }
+ return matchidx;
}
virDomainNetDefPtr
return net;
}
-virDomainNetDefPtr
-virDomainNetRemoveByMac(virDomainDefPtr def, const virMacAddrPtr mac)
-{
- int i = virDomainNetIndexByMac(def, mac);
-
- if (i < 0)
- return NULL;
- return virDomainNetRemove(def, i);
-}
-
-
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller)
{
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name);
-int virDomainNetIndexByMac(virDomainDefPtr def, const virMacAddrPtr mac);
+int virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net);
+virDomainNetDefPtr virDomainNetFind(virDomainDefPtr def, const char *device);
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net);
-virDomainNetDefPtr
-virDomainNetRemove(virDomainDefPtr def, size_t i);
-virDomainNetDefPtr
-virDomainNetRemoveByMac(virDomainDefPtr def, const virMacAddrPtr mac);
+virDomainNetDefPtr virDomainNetRemove(virDomainDefPtr def, size_t i);
int virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev);
virDomainHostdevDefPtr
VIR_ENUM_DECL(virDomainStartupPolicy)
-virDomainNetDefPtr virDomainNetFind(virDomainDefPtr def,
- const char *device);
-
# define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \
(VIR_CONNECT_LIST_DOMAINS_ACTIVE | \
VIR_CONNECT_LIST_DOMAINS_INACTIVE)
virDomainMemDumpTypeToString;
virDomainNetDefFree;
virDomainNetFind;
+virDomainNetFindIdx;
virDomainNetGetActualBandwidth;
virDomainNetGetActualBridgeName;
virDomainNetGetActualDirectDev;
virDomainNetGetActualType;
virDomainNetGetActualVirtPortProfile;
virDomainNetGetActualVlan;
-virDomainNetIndexByMac;
virDomainNetInsert;
virDomainNetRemove;
-virDomainNetRemoveByMac;
virDomainNetTypeToString;
virDomainNostateReasonTypeFromString;
virDomainNostateReasonTypeToString;
case VIR_DOMAIN_DEVICE_NET:
net = dev->data.net;
- if (virDomainNetIndexByMac(vmdef, &net->mac) >= 0) {
- char macbuf[VIR_MAC_STRING_BUFLEN];
-
- virMacAddrFormat(&net->mac, macbuf);
- virReportError(VIR_ERR_INVALID_ARG,
- _("mac %s already exists"), macbuf);
- return -1;
- }
if (virDomainNetInsert(vmdef, net)) {
virReportOOMError();
return -1;
virDomainDeviceDefPtr dev)
{
virDomainDiskDefPtr disk, det_disk;
- virDomainNetDefPtr net, det_net;
+ virDomainNetDefPtr net;
virDomainHostdevDefPtr hostdev, det_hostdev;
virDomainLeaseDefPtr lease, det_lease;
virDomainControllerDefPtr cont, det_cont;
int idx;
+ char mac[VIR_MAC_STRING_BUFLEN];
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
case VIR_DOMAIN_DEVICE_NET:
net = dev->data.net;
- if (!(det_net = virDomainNetRemoveByMac(vmdef, &net->mac))) {
- char macbuf[VIR_MAC_STRING_BUFLEN];
-
- virMacAddrFormat(&net->mac, macbuf);
- virReportError(VIR_ERR_INVALID_ARG,
- _("no nic of mac %s"), macbuf);
+ idx = virDomainNetFindIdx(vmdef, net);
+ if (idx == -2) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("multiple devices matching mac address %s found"),
+ virMacAddrFormat(&net->mac, mac));
+ return -1;
+ } else if (idx < 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("no matching network device was found"));
return -1;
}
- virDomainNetDefFree(det_net);
+ /* this is guaranteed to succeed */
+ virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
break;
case VIR_DOMAIN_DEVICE_HOSTDEV: {
virDomainDiskDefPtr orig, disk;
virDomainNetDefPtr net;
int pos;
+ char mac[VIR_MAC_STRING_BUFLEN];
+
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
case VIR_DOMAIN_DEVICE_NET:
net = dev->data.net;
- if ((pos = virDomainNetIndexByMac(vmdef, &net->mac)) < 0) {
- char macbuf[VIR_MAC_STRING_BUFLEN];
-
- virMacAddrFormat(&net->mac, macbuf);
- virReportError(VIR_ERR_INVALID_ARG,
- _("mac %s doesn't exist"), macbuf);
+ pos = virDomainNetFindIdx(vmdef, net);
+ if (pos == -2) {
+ virMacAddrFormat(&net->mac, mac);
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("couldn't find matching device "
+ "with mac address %s"), mac);
+ return -1;
+ } else if (pos < 0) {
+ virMacAddrFormat(&net->mac, mac);
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("couldn't find matching device "
+ "with mac address %s"), mac);
return -1;
}
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
- int i, ret = -1;
+ int detachidx, ret = -1;
virDomainNetDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
int vlan;
char *hostnet_name = NULL;
+ char mac[VIR_MAC_STRING_BUFLEN];
virNetDevVPortProfilePtr vport = NULL;
- for (i = 0 ; i < vm->def->nnets ; i++) {
- virDomainNetDefPtr net = vm->def->nets[i];
-
- if (!virMacAddrCmp(&net->mac, &dev->data.net->mac)) {
- detach = net;
- break;
+ detachidx = virDomainNetFindIdx(vm->def, dev->data.net);
+ if (detachidx == -2) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("multiple devices matching mac address %s found"),
+ virMacAddrFormat(&dev->data.net->mac, mac));
+ goto cleanup;
}
- }
-
- if (!detach) {
+ else if (detachidx < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
- _("network device %02x:%02x:%02x:%02x:%02x:%02x not found"),
- dev->data.net->mac.addr[0], dev->data.net->mac.addr[1],
- dev->data.net->mac.addr[2], dev->data.net->mac.addr[3],
- dev->data.net->mac.addr[4], dev->data.net->mac.addr[5]);
+ _("network device %s not found"),
+ virMacAddrFormat(&dev->data.net->mac, mac));
goto cleanup;
}
+ detach = vm->def->nets[detachidx];
if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
ret = qemuDomainDetachThisHostDevice(driver, vm,
cleanup:
if (!ret) {
networkReleaseActualDevice(detach);
- virDomainNetRemove(vm->def, i);
+ virDomainNetRemove(vm->def, detachidx);
virDomainNetDefFree(detach);
}
VIR_FREE(hostnet_name);
xmlDocPtr xml = NULL;
xmlXPathObjectPtr obj=NULL;
xmlXPathContextPtr ctxt = NULL;
- xmlNodePtr cur = NULL;
+ xmlNodePtr cur = NULL, matchNode = NULL;
xmlBufferPtr xml_buf = NULL;
const char *mac =NULL, *type = NULL;
char *doc;
goto cleanup;
}
- if (!mac)
+ if (!mac) {
+ matchNode = obj->nodesetval->nodeTab[0];
goto hit;
+ }
- /* search mac */
+ /* multiple possibilities, so search for matching mac */
for (; i < obj->nodesetval->nodeNr; i++) {
cur = obj->nodesetval->nodeTab[i]->children;
while (cur != NULL) {
diff_mac = virMacAddrCompare(tmp_mac, mac);
VIR_FREE(tmp_mac);
if (!diff_mac) {
- goto hit;
+ if (matchNode) {
+ /* this is the 2nd match, so it's ambiguous */
+ vshError(ctl, _("Domain has multiple interfaces matching "
+ "MAC address %s. You must use detach-device and "
+ "specify the device pci address to remove it."),
+ mac);
+ goto cleanup;
+ }
+ matchNode = obj->nodesetval->nodeTab[i];
}
}
cur = cur->next;
}
}
- vshError(ctl, _("No found interface whose MAC address is %s"), mac);
- goto cleanup;
+ if (!matchNode) {
+ vshError(ctl, _("No interface with MAC address %s was found"), mac);
+ goto cleanup;
+ }
hit:
xml_buf = xmlBufferCreate();
goto cleanup;
}
- if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
+ if (xmlNodeDump(xml_buf, xml, matchNode, 0, 0) < 0) {
vshError(ctl, "%s", _("Failed to create XML"));
goto cleanup;
}