Add a new domain event for completed vCPU removal. Wire the event through the internal event framework and extend the remote protocol so remote clients can receive it. Update virsh and the event-test example accordingly. The event is not emitted anywhere yet. Signed-off-by: Akash Kulhalli <akash.kulhalli@oracle.com> --- examples/c/misc/event-test.c | 12 ++++++ include/libvirt/libvirt-domain.h | 22 ++++++++++ src/conf/domain_event.c | 66 +++++++++++++++++++++++++++++ src/conf/domain_event.h | 6 +++ src/libvirt_private.syms | 2 + src/remote/remote_daemon_dispatch.c | 26 ++++++++++++ src/remote/remote_driver.c | 29 +++++++++++++ src/remote/remote_protocol.x | 14 +++++- src/remote_protocol-structs | 6 +++ tools/virsh-domain-event.c | 16 +++++++ 10 files changed, 198 insertions(+), 1 deletion(-) diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c index 2ce82ca9e088..f9e65c55f064 100644 --- a/examples/c/misc/event-test.c +++ b/examples/c/misc/event-test.c @@ -1039,6 +1039,17 @@ myDomainEventDeviceRemovalFailedCallback(virConnectPtr conn G_GNUC_UNUSED, return 0; } +static int +myDomainEventVcpuRemovedCallback(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + unsigned int vcpuid, + void *opaque G_GNUC_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) vcpu removed: %u\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), vcpuid); + return 0; +} + static const char * metadataTypeToStr(int status) @@ -1183,6 +1194,7 @@ struct domainEventData domainEvents[] = { DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFailureCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE, myDomainEventMemoryDeviceSizeChangeCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_NIC_MAC_CHANGE, myDomainEventNICMACChangeCallback), + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_VCPU_REMOVED, myDomainEventVcpuRemovedCallback), }; struct storagePoolEventData { diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4a8e3114b35d..92d5ecb32d65 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -6965,6 +6965,27 @@ typedef void (*virConnectDomainEventDeviceRemovalFailedCallback)(virConnectPtr c const char *devAlias, void *opaque); +/** + * virConnectDomainEventVcpuRemovedCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @vcpuid: libvirt XML vCPU id + * @opaque: application specified data + * + * This callback occurs when a vCPU is removed from the domain. + * + * The @vcpuid value matches the ``<vcpu id='...'>`` value from the domain XML. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_VCPU_REMOVED with virConnectDomainEventRegisterAny(). + * + * Since: 12.3.0 + */ +typedef void (*virConnectDomainEventVcpuRemovedCallback)(virConnectPtr conn, + virDomainPtr dom, + unsigned int vcpuid, + void *opaque); + /** * virConnectDomainEventMetadataChangeCallback: * @conn: connection object @@ -7617,6 +7638,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE = 25, /* virConnectDomainEventMemoryFailureCallback (Since: 6.9.0) */ VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE = 26, /* virConnectDomainEventMemoryDeviceSizeChangeCallback (Since: 7.9.0) */ VIR_DOMAIN_EVENT_ID_NIC_MAC_CHANGE = 27, /* virConnectDomainEventNICMACChangeCallback (Since: 11.2.0) */ + VIR_DOMAIN_EVENT_ID_VCPU_REMOVED = 28, /* virConnectDomainEventVcpuRemovedCallback (Since: 12.3.0) */ # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 88087bad4f21..17ad4a0d2c91 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -53,6 +53,7 @@ static virClass *virDomainEventDeviceAddedClass; static virClass *virDomainEventMigrationIterationClass; static virClass *virDomainEventJobCompletedClass; static virClass *virDomainEventDeviceRemovalFailedClass; +static virClass *virDomainEventVcpuRemovedClass; static virClass *virDomainEventMetadataChangeClass; static virClass *virDomainEventBlockThresholdClass; static virClass *virDomainEventMemoryFailureClass; @@ -78,6 +79,7 @@ static void virDomainEventDeviceAddedDispose(void *obj); static void virDomainEventMigrationIterationDispose(void *obj); static void virDomainEventJobCompletedDispose(void *obj); static void virDomainEventDeviceRemovalFailedDispose(void *obj); +static void virDomainEventVcpuRemovedDispose(void *obj); static void virDomainEventMetadataChangeDispose(void *obj); static void virDomainEventBlockThresholdDispose(void *obj); static void virDomainEventMemoryFailureDispose(void *obj); @@ -251,6 +253,13 @@ struct _virDomainEventDeviceRemovalFailed { }; typedef struct _virDomainEventDeviceRemovalFailed virDomainEventDeviceRemovalFailed; +struct _virDomainEventVcpuRemoved { + virDomainEvent parent; + + unsigned int vcpuid; +}; +typedef struct _virDomainEventVcpuRemoved virDomainEventVcpuRemoved; + struct _virDomainEventMetadataChange { virDomainEvent parent; @@ -337,6 +346,8 @@ virDomainEventsOnceInit(void) return -1; if (!VIR_CLASS_NEW(virDomainEventDeviceRemovalFailed, virDomainEventClass)) return -1; + if (!VIR_CLASS_NEW(virDomainEventVcpuRemoved, virDomainEventClass)) + return -1; if (!VIR_CLASS_NEW(virDomainEventMetadataChange, virDomainEventClass)) return -1; if (!VIR_CLASS_NEW(virDomainEventBlockThreshold, virDomainEventClass)) @@ -484,6 +495,13 @@ virDomainEventDeviceRemovalFailedDispose(void *obj) g_free(event->devAlias); } +static void +virDomainEventVcpuRemovedDispose(void *obj) +{ + virDomainEventVcpuRemoved *event = obj; + VIR_DEBUG("obj=%p", event); +} + static void virDomainEventPMDispose(void *obj) @@ -1382,6 +1400,43 @@ virDomainEventDeviceRemovalFailedNewFromDom(virDomainPtr dom, devAlias); } +static virObjectEvent * +virDomainEventVcpuRemovedNew(int id, + const char *name, + unsigned char *uuid, + unsigned int vcpuid) +{ + virDomainEventVcpuRemoved *ev; + + if (virDomainEventsInitialize() < 0) + return NULL; + + if (!(ev = virDomainEventNew(virDomainEventVcpuRemovedClass, + VIR_DOMAIN_EVENT_ID_VCPU_REMOVED, + id, name, uuid))) + return NULL; + + ev->vcpuid = vcpuid; + + return (virObjectEvent *)ev; +} + +virObjectEvent * +virDomainEventVcpuRemovedNewFromObj(virDomainObj *obj, + unsigned int vcpuid) +{ + return virDomainEventVcpuRemovedNew(obj->def->id, obj->def->name, + obj->def->uuid, vcpuid); +} + +virObjectEvent * +virDomainEventVcpuRemovedNewFromDom(virDomainPtr dom, + unsigned int vcpuid) +{ + return virDomainEventVcpuRemovedNew(dom->id, dom->name, dom->uuid, + vcpuid); +} + static virObjectEvent * virDomainEventAgentLifecycleNew(int id, @@ -2134,6 +2189,17 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, goto cleanup; } + case VIR_DOMAIN_EVENT_ID_VCPU_REMOVED: + { + virDomainEventVcpuRemoved *vcpuRemovedEvent; + + vcpuRemovedEvent = (virDomainEventVcpuRemoved *)event; + ((virConnectDomainEventVcpuRemovedCallback)cb)(conn, dom, + vcpuRemovedEvent->vcpuid, + 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 f31cfb9e42ad..1b1b16095a77 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -192,6 +192,12 @@ virDomainEventDeviceRemovalFailedNewFromObj(virDomainObj *obj, virObjectEvent * virDomainEventDeviceRemovalFailedNewFromDom(virDomainPtr dom, const char *devAlias); +virObjectEvent * +virDomainEventVcpuRemovedNewFromObj(virDomainObj *obj, + unsigned int vcpuid); +virObjectEvent * +virDomainEventVcpuRemovedNewFromDom(virDomainPtr dom, + unsigned int vcpuid); virObjectEvent * virDomainEventTunableNewFromObj(virDomainObj *obj, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cf0e71cc6af1..f22b5895db12 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -811,6 +811,8 @@ virDomainEventTrayChangeNewFromDom; virDomainEventTrayChangeNewFromObj; virDomainEventTunableNewFromDom; virDomainEventTunableNewFromObj; +virDomainEventVcpuRemovedNewFromDom; +virDomainEventVcpuRemovedNewFromObj; virDomainEventWatchdogNewFromDom; virDomainEventWatchdogNewFromObj; virDomainQemuMonitorEventNew; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 7e74ff063f5b..81b0ed00da1a 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1322,6 +1322,31 @@ remoteRelayDomainEventMemoryDeviceSizeChange(virConnectPtr conn, return 0; } +static int +remoteRelayDomainEventVcpuRemoved(virConnectPtr conn, + virDomainPtr dom, + unsigned int vcpuid, + void *opaque) +{ + daemonClientEventCallback *callback = opaque; + remote_domain_event_vcpu_removed_msg data; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + memset(&data, 0, sizeof(data)); + data.callbackID = callback->callbackID; + data.vcpuid = vcpuid; + make_nonnull_domain(&data.dom, dom); + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_VCPU_REMOVED, + (xdrproc_t)xdr_remote_domain_event_vcpu_removed_msg, + &data); + return 0; +} + static int remoteRelayDomainEventNICMACChange(virConnectPtr conn, @@ -1383,6 +1408,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryDeviceSizeChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventNICMACChange), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventVcpuRemoved), }; G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ec71eaed8762..c8a4e3f6da98 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -428,6 +428,10 @@ remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog, virNetClient *client, void *evdata, void *opaque); static void +remoteDomainBuildEventVcpuRemoved(virNetClientProgram *prog, + virNetClient *client, + void *evdata, void *opaque); +static void remoteConnectNotifyEventConnectionClosed(virNetClientProgram *prog G_GNUC_UNUSED, virNetClient *client G_GNUC_UNUSED, void *evdata, void *opaque); @@ -659,6 +663,10 @@ static virNetClientProgramEvent remoteEvents[] = { remoteDomainBuildEventNICMACChange, sizeof(remote_domain_event_nic_mac_change_msg), (xdrproc_t)xdr_remote_domain_event_nic_mac_change_msg }, + { REMOTE_PROC_DOMAIN_EVENT_VCPU_REMOVED, + remoteDomainBuildEventVcpuRemoved, + sizeof(remote_domain_event_vcpu_removed_msg), + (xdrproc_t)xdr_remote_domain_event_vcpu_removed_msg }, }; static void @@ -5138,6 +5146,27 @@ remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog G_GNUC_UN virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackID); } +static void +remoteDomainBuildEventVcpuRemoved(virNetClientProgram *prog G_GNUC_UNUSED, + virNetClient *client G_GNUC_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + remote_domain_event_vcpu_removed_msg *msg = evdata; + struct private_data *priv = conn->privateData; + virDomainPtr dom; + virObjectEvent *event = NULL; + + if (!(dom = get_nonnull_domain(conn, msg->dom))) + return; + + event = virDomainEventVcpuRemovedNewFromDom(dom, msg->vcpuid); + + virObjectUnref(dom); + + virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackID); +} + static void remoteDomainBuildEventNICMACChange(virNetClientProgram *prog G_GNUC_UNUSED, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 38a83c64eadb..23699e99a60a 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3981,6 +3981,12 @@ struct remote_domain_event_memory_device_size_change_msg { unsigned hyper size; }; +struct remote_domain_event_vcpu_removed_msg { + int callbackID; + remote_nonnull_domain dom; + unsigned int vcpuid; +}; + struct remote_domain_fd_associate_args { remote_nonnull_domain dom; @@ -7120,5 +7126,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453 + REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_VCPU_REMOVED = 454 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0f87d13a5ae1..75c3d0cb2e06 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3315,6 +3315,11 @@ struct remote_domain_event_memory_device_size_change_msg { remote_nonnull_string alias; uint64_t size; }; +struct remote_domain_event_vcpu_removed_msg { + int callbackID; + remote_nonnull_domain dom; + u_int vcpuid; +}; struct remote_domain_fd_associate_args { remote_nonnull_domain dom; remote_nonnull_string name; @@ -3791,4 +3796,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP = 451, REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP = 452, REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453, + REMOTE_PROC_DOMAIN_EVENT_VCPU_REMOVED = 454, }; diff --git a/tools/virsh-domain-event.c b/tools/virsh-domain-event.c index b9d1cdf019ca..4a9a831b4525 100644 --- a/tools/virsh-domain-event.c +++ b/tools/virsh-domain-event.c @@ -705,6 +705,20 @@ virshEventDeviceRemovalFailedPrint(virConnectPtr conn G_GNUC_UNUSED, virshEventPrint(opaque, &buf); } +static void +virshEventVcpuRemovedPrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + unsigned int vcpuid, + void *opaque) +{ + g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, + _("event 'vcpu-removed' for domain '%1$s': vcpu %2$u\n"), + virDomainGetName(dom), vcpuid); + virshEventPrint(opaque, &buf); +} + VIR_ENUM_DECL(virshEventMetadataChangeType); VIR_ENUM_IMPL(virshEventMetadataChangeType, VIR_DOMAIN_METADATA_LAST, @@ -873,6 +887,8 @@ virshDomainEventCallback virshDomainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), }, { "nic-mac-change", VIR_DOMAIN_EVENT_CALLBACK(virshEventNICMACChangePrint), }, + { "vcpu-removed", + VIR_DOMAIN_EVENT_CALLBACK(virshEventVcpuRemovedPrint), }, }; G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks)); -- 2.47.3