Before the refactoring that properly separated the network driver from the hypervisor driver and forced all interaction to go through public APIs, all network usage counters were zeroed when the network driver was initialized, and the network driver's now-deprecated "semi-private" API networkNotifyActualDevice() was called for every interface of every domain as each hypervisor "reconnected" its domains during a libvirtd restart, and this would refresh the usage count for each network. Post-driver-split, during libvirtd restart/reconnection of the running domains, the function virDomainNetNotifyActualDevice() is called by each hypervisor driver for every interface of every domain restart, and this function has code to re-register interfaces, but it only calls into the network driver to re-register those ports that don't already have a valid portid (ie. one that is not simply all 0), assuming that those with valid portids are already known (and counted) by the network driver. commit 7ab9bdd47 recently modified the network driver so that, in most cases, it properly resyncs each network's connection count during libvirtd (or maybe virtnetworkd) restart by iterating through the network's port list. This doesn't account for the case where a network is destroyed and restarted while there are running domains that have active ports on the network. In that case, the entire port list and connection count for that network is lost, and now even a restart of libvirtd/virtnetworkd/virtqemud, which in the past would resync the connection count, doesn't help (the network driver thinks there are no active ports, while the hypervisor driver knows about all the active ports, but mistakenly believes that the network driver also knows). The solution to this is to not just bypass valid portids during the call to virDomainNetworkNotifyActualDevice(). Instead, we query the network driver about the portid that was preserved in the domain status, and if it is not registered, we register it. (NB: while it would technically be correct to just generate a new portid for these cases, it makes for less churn in portids (and thus may make troubleshooting simpler) if we make the small fix to virDomainNetDefActualToNetworkPort() that preserves existing valid portids rather than unconditionally generating a new one.) Signed-off-by: Laine Stump <laine@xxxxxxxxxx> --- src/conf/domain_conf.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b6fa802523..d1e7ac84e8 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30749,8 +30749,9 @@ virDomainNetDefActualToNetworkPort(virDomainDefPtr dom, if (VIR_ALLOC(port) < 0) return NULL; - /* Bad - we need to preserve original port uuid */ - if (virUUIDGenerate(port->uuid) < 0) { + if (virUUIDIsValid(iface->data.network.portid)) { + memcpy(port->uuid, iface->data.network.portid, VIR_UUID_BUFLEN); + } else if (virUUIDGenerate(port->uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to generate UUID")); goto error; @@ -30883,6 +30884,23 @@ virDomainNetCreatePort(virConnectPtr conn, return -1; if (flags & VIR_NETWORK_PORT_CREATE_RECLAIM) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char macstr[VIR_MAC_STRING_BUFLEN]; + + virUUIDFormat(iface->data.network.portid, uuidstr); + virMacAddrFormat(&iface->mac, macstr); + + /* if the port is already registered, then we are done */ + if (virUUIDIsValid(iface->data.network.portid) && + (port = virNetworkPortLookupByUUID(net, iface->data.network.portid))) { + VIR_DEBUG("network: %s domain: %s mac: %s port: %s - already registered, skipping", + iface->data.network.name, dom->name, macstr, uuidstr); + return 0; + } + + /* otherwise we need to create a new port */ + VIR_DEBUG("network: %s domain: %s mac: %s port: %s - not found, reclaiming", + iface->data.network.name, dom->name, macstr, uuidstr); if (!(portdef = virDomainNetDefActualToNetworkPort(dom, iface))) return -1; } else { @@ -30931,10 +30949,9 @@ virDomainNetNotifyActualDevice(virConnectPtr conn, { virDomainNetType actualType = virDomainNetGetActualType(iface); - if (!virUUIDIsValid(iface->data.network.portid)) { - if (virDomainNetCreatePort(conn, dom, iface, - VIR_NETWORK_PORT_CREATE_RECLAIM) < 0) - return; + if (virDomainNetCreatePort(conn, dom, iface, + VIR_NETWORK_PORT_CREATE_RECLAIM) < 0) { + return; } if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list