The VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION event will be triggered whenever VIR_DOMAIN_JOB_MEMORY_ITERATION changes its value, i.e., whenever a new iteration over guest memory pages is started during migration. Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- daemon/remote.c | 32 ++++++++++++++++++ include/libvirt/libvirt-domain.h | 22 +++++++++++++ src/conf/domain_event.c | 71 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_event.h | 8 +++++ src/libvirt_private.syms | 2 ++ src/remote/remote_driver.c | 33 +++++++++++++++++++ src/remote/remote_protocol.x | 14 +++++++- src/remote_protocol-structs | 6 ++++ tools/virsh-domain.c | 18 ++++++++++ 9 files changed, 205 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 3a3eb09..370f442 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1079,6 +1079,37 @@ remoteRelayDomainEventDeviceAdded(virConnectPtr conn, } +static int +remoteRelayDomainEventMigrationIteration(virConnectPtr conn, + virDomainPtr dom, + int iteration, + void *opaque) +{ + daemonClientEventCallbackPtr callback = opaque; + remote_domain_event_callback_migration_iteration_msg data; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + VIR_DEBUG("Relaying domain migration pass event %s %d, " + "callback %d, iteration %d", + dom->name, dom->id, callback->callbackID, iteration); + + /* build return data */ + memset(&data, 0, sizeof(data)); + data.callbackID = callback->callbackID; + make_nonnull_domain(&data.dom, dom); + + data.iteration = iteration; + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION, + (xdrproc_t)xdr_remote_domain_event_callback_migration_iteration_msg, + &data); + + return 0; +} static virConnectDomainEventGenericCallback domainEventCallbacks[] = { @@ -1102,6 +1133,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index d26faa5..65f1618 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -3284,6 +3284,27 @@ typedef void (*virConnectDomainEventDeviceAddedCallback)(virConnectPtr conn, void *opaque); /** + * virConnectDomainEventMigrationIterationCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @iteration: current iteration over domain's memory + * @opaque: application specific data + * + * This callback occurs during live migration when a new iteration over + * domain's memory starts. The @iteration value is increased by one every + * time a new iteration is started to transfer memory pages dirtied since + * the last iteration. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION with + * virConnectDomainEventRegisterAny(). + */ +typedef void (*virConnectDomainEventMigrationIterationCallback)(virConnectPtr conn, + virDomainPtr dom, + int iteration, + void *opaque); + +/** * VIR_DOMAIN_TUNABLE_CPU_VCPUPIN: * * Macro represents formatted pinning for one vcpu specified by id which is @@ -3566,6 +3587,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_TUNABLE = 17, /* virConnectDomainEventTunableCallback */ VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE = 18,/* virConnectDomainEventAgentLifecycleCallback */ VIR_DOMAIN_EVENT_ID_DEVICE_ADDED = 19, /* virConnectDomainEventDeviceAddedCallback */ + VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION = 20, /* virConnectDomainEventMigrationIterationCallback */ # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 20d66e1..5cb3ccd 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -56,6 +56,7 @@ static virClassPtr virDomainQemuMonitorEventClass; static virClassPtr virDomainEventTunableClass; static virClassPtr virDomainEventAgentLifecycleClass; static virClassPtr virDomainEventDeviceAddedClass; +static virClassPtr virDomainEventMigrationIterationClass; static void virDomainEventDispose(void *obj); @@ -74,6 +75,7 @@ static void virDomainQemuMonitorEventDispose(void *obj); static void virDomainEventTunableDispose(void *obj); static void virDomainEventAgentLifecycleDispose(void *obj); static void virDomainEventDeviceAddedDispose(void *obj); +static void virDomainEventMigrationIterationDispose(void *obj); static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -236,6 +238,14 @@ struct _virDomainEventAgentLifecycle { typedef struct _virDomainEventAgentLifecycle virDomainEventAgentLifecycle; typedef virDomainEventAgentLifecycle *virDomainEventAgentLifecyclePtr; +struct _virDomainEventMigrationIteration { + virDomainEvent parent; + + int iteration; +}; +typedef struct _virDomainEventMigrationIteration virDomainEventMigrationIteration; +typedef virDomainEventMigrationIteration *virDomainEventMigrationIterationPtr; + static int virDomainEventsOnceInit(void) @@ -336,6 +346,12 @@ virDomainEventsOnceInit(void) sizeof(virDomainEventAgentLifecycle), virDomainEventAgentLifecycleDispose))) return -1; + if (!(virDomainEventMigrationIterationClass = + virClassNew(virDomainEventClass, + "virDomainEventMigrationIteration", + sizeof(virDomainEventMigrationIteration), + virDomainEventMigrationIterationDispose))) + return -1; return 0; } @@ -496,6 +512,13 @@ virDomainEventAgentLifecycleDispose(void *obj) VIR_DEBUG("obj=%p", event); }; +static void +virDomainEventMigrationIterationDispose(void *obj) +{ + virDomainEventMigrationIterationPtr event = obj; + VIR_DEBUG("obj=%p", event); +}; + static void * virDomainEventNew(virClassPtr klass, @@ -1334,6 +1357,43 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom, state, reason); } +static virObjectEventPtr +virDomainEventMigrationIterationNew(int id, + const char *name, + const unsigned char *uuid, + int iteration) +{ + virDomainEventMigrationIterationPtr ev; + + if (virDomainEventsInitialize() < 0) + return NULL; + + if (!(ev = virDomainEventNew(virDomainEventMigrationIterationClass, + VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, + id, name, uuid))) + return NULL; + + ev->iteration = iteration; + + return (virObjectEventPtr)ev; +} + +virObjectEventPtr +virDomainEventMigrationIterationNewFromObj(virDomainObjPtr obj, + int iteration) +{ + return virDomainEventMigrationIterationNew(obj->def->id, obj->def->name, + obj->def->uuid, iteration); +} + +virObjectEventPtr +virDomainEventMigrationIterationNewFromDom(virDomainPtr dom, + int iteration) +{ + return virDomainEventMigrationIterationNew(dom->id, dom->name, dom->uuid, + iteration); +} + /* This function consumes the params so caller don't have to care about * freeing it even if error occurs. The reason is to not have to do deep @@ -1614,6 +1674,17 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, goto cleanup; } + case VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION: + { + virDomainEventMigrationIterationPtr ev; + + ev = (virDomainEventMigrationIterationPtr) event; + ((virConnectDomainEventMigrationIterationCallback)cb)(conn, dom, + ev->iteration, + cbopaque); + goto cleanup; + } + case VIR_DOMAIN_EVENT_ID_LAST: break; } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index afbed89..b7cddb5 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -209,6 +209,14 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom, int state, int reason); +virObjectEventPtr +virDomainEventMigrationIterationNewFromObj(virDomainObjPtr obj, + int iteration); + +virObjectEventPtr +virDomainEventMigrationIterationNewFromDom(virDomainPtr dom, + int iteration); + int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 83f6e2c..5e05a98 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -514,6 +514,8 @@ virDomainEventLifecycleNew; virDomainEventLifecycleNewFromDef; virDomainEventLifecycleNewFromDom; virDomainEventLifecycleNewFromObj; +virDomainEventMigrationIterationNewFromDom; +virDomainEventMigrationIterationNewFromObj; virDomainEventPMSuspendDiskNewFromDom; virDomainEventPMSuspendDiskNewFromObj; virDomainEventPMSuspendNewFromDom; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a1dd640..d9d7ec8 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -342,6 +342,11 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog, void *evdata, void *opaque); static void +remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + +static void remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, void *evdata, void *opaque); @@ -504,6 +509,10 @@ static virNetClientProgramEvent remoteEvents[] = { remoteDomainBuildEventCallbackDeviceAdded, sizeof(remote_domain_event_callback_device_added_msg), (xdrproc_t)xdr_remote_domain_event_callback_device_added_msg }, + { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION, + remoteDomainBuildEventCallbackMigrationIteration, + sizeof(remote_domain_event_callback_migration_iteration_msg), + (xdrproc_t)xdr_remote_domain_event_callback_migration_iteration_msg }, }; @@ -5513,6 +5522,30 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog ATTRIBU remoteEventQueue(priv, event, msg->callbackID); } + +static void +remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, + void *opaque) +{ + virConnectPtr conn = opaque; + remote_domain_event_callback_migration_iteration_msg *msg = evdata; + struct private_data *priv = conn->privateData; + virDomainPtr dom; + virObjectEventPtr event = NULL; + + if (!(dom = get_nonnull_domain(conn, msg->dom))) + return; + + event = virDomainEventMigrationIterationNewFromDom(dom, msg->iteration); + + virObjectUnref(dom); + + remoteEventQueue(priv, event, msg->callbackID); +} + + static void remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 9f131f8..bfdbce7 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3222,6 +3222,12 @@ struct remote_domain_rename_ret { int retcode; }; +struct remote_domain_event_callback_migration_iteration_msg { + int callbackID; + remote_nonnull_domain dom; + int iteration; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -5694,5 +5700,11 @@ enum remote_procedure { * @acl: domain:write * @acl: domain:save */ - REMOTE_PROC_DOMAIN_RENAME = 358 + REMOTE_PROC_DOMAIN_RENAME = 358, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION = 359 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index ff99c00..dff54e8 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2692,6 +2692,11 @@ struct remote_domain_rename_args { struct remote_domain_rename_ret { int retcode; }; +struct remote_domain_event_callback_migration_iteration_msg { + int callbackID; + remote_nonnull_domain dom; + int iteration; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3051,4 +3056,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DEL_IOTHREAD = 356, REMOTE_PROC_DOMAIN_SET_USER_PASSWORD = 357, REMOTE_PROC_DOMAIN_RENAME = 358, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION = 359, }; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 62acecb..6d04b71 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11924,6 +11924,22 @@ virshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, virshEventPrint(opaque, &buf); } +static void +virshEventMigrationIterationPrint(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int iteration, + void *opaque) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'migration-iteration' for domain %s: " + "iteration: '%d'\n"), + virDomainGetName(dom), + iteration); + + virshEventPrint(opaque, &buf); +} + static vshEventCallback vshEventCallbacks[] = { { "lifecycle", VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), }, @@ -11963,6 +11979,8 @@ static vshEventCallback vshEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(virshEventAgentLifecyclePrint), }, { "device-added", VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceAddedPrint), }, + { "migration-iteration", + VIR_DOMAIN_EVENT_CALLBACK(virshEventMigrationIterationPrint), }, }; verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks)); -- 2.7.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list