From: "D. Herrendoerfer" <d.herrendoerfer(a)herrendoerfer.name>
When libvirtd is restarted, also restart the netlink event
message callbacks for existing VEPA connections and send
a message to lldpad for these existing links, so it learns
the new libvirtd pid.
This patch includes the nits sent by Laine Stump, and it tests out ok.
Signed-off-by: D. Herrendoerfer <d.herrendoerfer(a)herrendoerfer.name>
---
src/qemu/qemu_driver.c | 31 ++++++++++
src/util/virnetdevmacvlan.c | 129 +++++++++++++++++++++++++++++++++---------
src/util/virnetdevmacvlan.h | 9 +++
src/util/virnetlink.c | 6 ++-
4 files changed, 146 insertions(+), 29 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 538a419..8e6663c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -412,6 +412,35 @@ cleanup:
virDomainObjUnlock(vm);
}
+
+static void qemuDomainNetsRestart(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ int i;
+ virDomainObjPtr vm = (virDomainObjPtr)payload;
+ virDomainDefPtr def = vm->def;
+
+ virDomainObjLock(vm);
+
+ for (i = 0; i < def->nnets; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT &&
+ virDomainNetGetActualDirectMode(net) == VIR_NETDEV_MACVLAN_MODE_VEPA) {
+ VIR_DEBUG("VEPA mode device %s active in domain %s.
Reassociating.",
+ net->ifname, def->name);
+ ignore_value(virNetDevMacVLanRestartWithVPortProfile(net->ifname,
+ net->mac,
+
virDomainNetGetActualDirectDev(net),
+ def->uuid,
+
virDomainNetGetActualVirtPortProfile(net),
+
VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
+ }
+ }
+
+ virDomainObjUnlock(vm);
+}
+
/**
* qemudStartup:
*
@@ -668,6 +697,8 @@ qemudStartup(int privileged) {
NULL, NULL) < 0)
goto error;
+ virHashForEach(qemu_driver->domains.objs, qemuDomainNetsRestart, NULL);
+
conn = virConnectOpen(qemu_driver->privileged ?
"qemu:///system" :
"qemu:///session");
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 647679f..90888b0 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -769,6 +769,50 @@ virNetDevMacVLanVPortProfileDestroyCallback(int watch
ATTRIBUTE_UNUSED,
virNetlinkCallbackDataFree((virNetlinkCallbackDataPtr)opaque);
}
+static int
+virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+{
+ virNetlinkCallbackDataPtr calld = NULL;
+
+ if (virtPortProfile && virNetlinkEventServiceIsRunning()) {
+ if (VIR_ALLOC(calld) < 0)
+ goto memory_error;
+ if ((calld->cr_ifname = strdup(ifname)) == NULL)
+ goto memory_error;
+ if (VIR_ALLOC(calld->virtPortProfile) < 0)
+ goto memory_error;
+ memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
+ if (VIR_ALLOC_N(calld->macaddress, VIR_MAC_BUFLEN) < 0)
+ goto memory_error;
+ memcpy(calld->macaddress, macaddress, VIR_MAC_BUFLEN);
+ if ((calld->linkdev = strdup(linkdev)) == NULL)
+ goto memory_error;
+ if (VIR_ALLOC_N(calld->vmuuid, VIR_UUID_BUFLEN) < 0)
+ goto memory_error;
+ memcpy(calld->vmuuid, vmuuid, VIR_UUID_BUFLEN);
+
+ calld->vmOp = vmOp;
+
+ if (virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
+ virNetDevMacVLanVPortProfileDestroyCallback,
+ calld, macaddress) < 0)
+ goto error;
+ }
+
+ return 0;
+
+memory_error:
+ virReportOOMError();
+error:
+ virNetlinkCallbackDataFree(calld);
+ return -1;
+}
+
/**
* virNetDevMacVLanCreateWithVPortProfile:
@@ -810,7 +854,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
int retries, do_retry = 0;
uint32_t macvtapMode;
const char *cr_ifname;
- virNetlinkCallbackDataPtr calld = NULL;
int ret;
int vf = -1;
@@ -917,36 +960,12 @@ create_name:
goto disassociate_exit;
}
- if (virtPortProfile && virNetlinkEventServiceIsRunning()) {
- if (VIR_ALLOC(calld) < 0)
- goto memory_error;
- if ((calld->cr_ifname = strdup(cr_ifname)) == NULL)
- goto memory_error;
- if (VIR_ALLOC(calld->virtPortProfile) < 0)
- goto memory_error;
- memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
- if (VIR_ALLOC_N(calld->macaddress, VIR_MAC_BUFLEN) < 0)
- goto memory_error;
- memcpy(calld->macaddress, macaddress, VIR_MAC_BUFLEN);
- if ((calld->linkdev = strdup(linkdev)) == NULL)
- goto memory_error;
- if (VIR_ALLOC_N(calld->vmuuid, VIR_UUID_BUFLEN) < 0)
- goto memory_error;
- memcpy(calld->vmuuid, vmuuid, VIR_UUID_BUFLEN);
-
- calld->vmOp = vmOp;
-
- virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
- virNetDevMacVLanVPortProfileDestroyCallback,
- calld, macaddress);
- }
+ if (virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
+ linkdev, vmuuid, virtPortProfile, vmOp) < 0
)
+ goto disassociate_exit;
return rc;
- memory_error:
- virReportOOMError();
- virNetlinkCallbackDataFree(calld);
-
disassociate_exit:
ignore_value(virNetDevVPortProfileDisassociate(cr_ifname,
virtPortProfile,
@@ -1003,6 +1022,48 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
return ret;
}
+/**
+ * virNetDevMacVLanRestartWithVPortProfile:
+ * Register a port profile callback handler for a VM that
+ * is already running
+ * .
+ * @cr_ifname: Interface name that the macvtap has.
+ * @macaddress: The MAC address for the macvtap device
+ * @linkdev: The interface name of the NIC to connect to the external bridge
+ * @vmuuid: The UUID of the VM the macvtap belongs to
+ * @virtPortProfile: pointer to object holding the virtual port profile data
+ * @vmOp: Operation to use during setup of the association
+ *
+ * Returns 0; returns -1 on error.
+ */
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+{
+ int rc = 0;
+
+ rc = virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
+ linkdev, vmuuid,
+ virtPortProfile, vmOp);
+ if (rc < 0)
+ goto error;
+
+ ignore_value(virNetDevVPortProfileAssociate(cr_ifname,
+ virtPortProfile,
+ macaddress,
+ linkdev,
+ -1,
+ vmuuid,
+ vmOp, true));
+
+error:
+ return rc;
+
+}
+
#else /* ! WITH_MACVTAP */
int virNetDevMacVLanCreate(const char *ifname ATTRIBUTE_UNUSED,
const char *type ATTRIBUTE_UNUSED,
@@ -1052,4 +1113,16 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname
ATTRIBUTE_UNUSED,
_("Cannot create macvlan devices on this platform"));
return -1;
}
+
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname ATTRIBUTE_UNUSED,
+ const unsigned char *macaddress
ATTRIBUTE_UNUSED,
+ const char *linkdev ATTRIBUTE_UNUSED,
+ const unsigned char *vmuuid ATTRIBUTE_UNUSED,
+ virNetDevVPortProfilePtr virtPortProfile
ATTRIBUTE_UNUSED,
+ enum virNetDevVPortProfileOp vmOp
ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Cannot create macvlan devices on this platform"));
+ return -1;
+}
#endif /* ! WITH_MACVTAP */
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 130ecea..14640cf 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -75,4 +75,13 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(6) ATTRIBUTE_RETURN_CHECK;
+int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
+ const unsigned char *macaddress,
+ const char *linkdev,
+ const unsigned char *vmuuid,
+ virNetDevVPortProfilePtr virtPortProfile,
+ enum virNetDevVPortProfileOp vmOp)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK;
+
#endif /* __UTIL_MACVTAP_H__ */
diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c
index 59f3e39..2cb3656 100644
--- a/src/util/virnetlink.c
+++ b/src/util/virnetlink.c
@@ -428,8 +428,11 @@ virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB,
int i, r, ret = -1;
virNetlinkEventSrvPrivatePtr srv = server;
- if (handleCB == NULL)
+ if (handleCB == NULL) {
+ netlinkError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid NULL callback provided"));
return -1;
+ }
virNetlinkEventServerLock(srv);
@@ -449,6 +452,7 @@ virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB,
srv->handlesAlloc, NETLINK_EVENT_ALLOC_EXTENT);
if (VIR_RESIZE_N(srv->handles, srv->handlesAlloc,
srv->handlesCount, NETLINK_EVENT_ALLOC_EXTENT) < 0) {
+ virReportOOMError();
goto error;
}
}
--
1.7.7.6