Starting with commit f8e712fe, if you start a domain that has an <interface type='hostdev' (or that has <interface type='network'> where the network is a pool of devices for hostdev assignment), when you later try to add *another* interface (of any kind) with hotplug, the function qemuAssignDeviceNetAlias() fails as soon as it sees a "hostdevN" alias in the list of interfaces), causing the attach to fail. This is because (starting with f8e712fe) the device alias names are assigned during the new function qemuProcessPrepareDomain(), which is called *before* networkAllocateActualDevice() (which is called from qemuProcessPrepareHost(), which is called from qemuProcessLaunch()). Prior to that commit, networkAllocateActualDevice() was called first. The problem with this is that the alias for interfaces that are really a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just like other hostdevs), while other interfaces are "netN". But if you don't know that the interface is going to be a hostdev at the time you assign the alias name, you can't name it differently. (As far as I've seen so far, the change in name by itself wouldn't have been a problem (other than just an outwardly noticeable change in behavior) except for the abovementioned failure to attach/detach new interfaces. Rather than take the chance that there may be other not-yet-revealed problems associated with changing the alias name, this patch changes the way that aliases are assigned to restore the old behavior. Old: In the past, assigning an alias to an interface was skipped if it was seen that the interface was type='hostdev' - we knew that the hostdev part of the interface was also in the list of hostdevs (that's part of what happens in networkAllocateActualDevice()) and it would be assigned when all the other hostdev aliases were assigned. New: When assigning an alias to an interface, we haven't yet called networkAllocateActualDevice() to construct the hostdev part of the interface, so we can't just wait for the loop that creates aliases for all the hostdevs (there's nothing on that list for this device yet!). Instead we handle it immediately in the loop creating interface aliases, by calling the new function networkGetActualType() to determine if it is going to be hostdev, and if so calling qemuAssignDeviceHostdevAlias() instead. Some adjustments have to be made to both qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to accommodate this. In both of them, an error return from qemuDomainDeviceAliasIndex() is no longer considered an error; instead it's just ignored (because it almost certainly means that the alias string for the device was "net" when we expected "hostdev" or vice versa). in qemuAssignDeviceHostdevAlias() we have to look at all interface aliases for hostdevN in addition to looking at all hostdev aliases (this wasn't necessary in the past, because both the interface entry and the hostdev entry for the device already pointed at the device info; no longer the case since the hostdev entry hasn't yet been setup). Fortunately the buggy behavior hasn't yet been in any official release of libvirt. --- src/qemu/qemu_alias.c | 56 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index fc0653c..010d6b9 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -27,6 +27,7 @@ #include "viralloc.h" #include "virlog.h" #include "virstring.h" +#include "network/bridge_driver.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -293,14 +294,22 @@ qemuAssignDeviceHostdevAlias(virDomainDefPtr def, { if (idx == -1) { size_t i; + idx = 0; for (i = 0; i < def->nhostdevs; i++) { int thisidx; - if ((thisidx = qemuDomainDeviceAliasIndex(def->hostdevs[i]->info, "hostdev")) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine device index for hostdev device")); - return -1; - } + + if ((thisidx = qemuDomainDeviceAliasIndex(def->hostdevs[i]->info, "hostdev")) < 0) + continue; /* error just means the alias wasn't "hostdevN", but something else */ + if (thisidx >= idx) + idx = thisidx + 1; + } + /* network interfaces can also have a hostdevN alias */ + for (i = 0; i < def->nnets; i++) { + int thisidx; + + if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "hostdev")) < 0) + continue; if (thisidx >= idx) idx = thisidx + 1; } @@ -318,22 +327,23 @@ qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx) { + + /* <interface type='hostdev'> uses "hostdevN" as the alias + * We must use "-1" as the index because the caller doesn't know + * that we're now looking for a unique hostdevN rather than netN + */ + if (networkGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) + return qemuAssignDeviceHostdevAlias(def, &net->info.alias, -1); + if (idx == -1) { size_t i; + idx = 0; for (i = 0; i < def->nnets; i++) { int thisidx; - if (virDomainNetGetActualType(def->nets[i]) - == VIR_DOMAIN_NET_TYPE_HOSTDEV) { - /* type='hostdev' interfaces have a hostdev%d alias */ - continue; - } - if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine device index for network device")); - return -1; - } + if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) + continue; /* failure could be due to "hostdevN" */ if (thisidx >= idx) idx = thisidx + 1; } @@ -392,14 +402,8 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) return -1; } for (i = 0; i < def->nnets; i++) { - /* type='hostdev' interfaces are also on the hostdevs list, - * and will have their alias assigned with other hostdevs. - */ - if (virDomainNetGetActualType(def->nets[i]) - != VIR_DOMAIN_NET_TYPE_HOSTDEV && - qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0) { + if (qemuAssignDeviceNetAlias(def, def->nets[i], -1) < 0) return -1; - } } if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) @@ -414,7 +418,13 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) return -1; } for (i = 0; i < def->nhostdevs; i++) { - if (qemuAssignDeviceHostdevAlias(def, &def->hostdevs[i]->info->alias, i) < 0) + /* we can't start assigning at 0, since netdevs may have used + * up some hostdevN entries already. Also if the HostdevDef is + * linked to a NetDef, they will share an info and the alias + * will already be set, so don't try to set it again. + */ + if (!def->hostdevs[i]->info->alias && + qemuAssignDeviceHostdevAlias(def, &def->hostdevs[i]->info->alias, -1) < 0) return -1; } for (i = 0; i < def->nredirdevs; i++) { -- 2.5.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list