]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf,remote: add vcpu-removed domain event
authorAkash Kulhalli via Devel <devel@lists.libvirt.org>
Wed, 29 Apr 2026 12:13:25 +0000 (17:43 +0530)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 12 May 2026 11:39:07 +0000 (13:39 +0200)
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>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
examples/c/misc/event-test.c
include/libvirt/libvirt-domain.h
src/conf/domain_event.c
src/conf/domain_event.h
src/libvirt_private.syms
src/remote/remote_daemon_dispatch.c
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
tools/virsh-domain-event.c

index 2ce82ca9e0887cf369558e93493ede67beece42e..f9e65c55f0647b8810037be6bd1838ef5bf4a15c 100644 (file)
@@ -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 {
index 4a8e3114b35d6c0011ac680c6dbcc5b563ee01a2..21336df85bd8ff2850f91a56874cf2097a904761 100644 (file)
@@ -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.4.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.4.0) */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
index 88087bad4f21da1151c6631ccde675367ecd90ad..17ad4a0d2c917b400f30b186022b417914add3b8 100644 (file)
@@ -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;
     }
index f31cfb9e42ad1eebe068973a60c09eaadb04aab4..1b1b16095a7764803ddb2c228e93bae35647bfcf 100644 (file)
@@ -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,
index cf0e71cc6af1f90a7d0b3e2e4b4dbca853bd379c..f22b5895db12966737585c8611421ceb24ea703b 100644 (file)
@@ -811,6 +811,8 @@ virDomainEventTrayChangeNewFromDom;
 virDomainEventTrayChangeNewFromObj;
 virDomainEventTunableNewFromDom;
 virDomainEventTunableNewFromObj;
+virDomainEventVcpuRemovedNewFromDom;
+virDomainEventVcpuRemovedNewFromObj;
 virDomainEventWatchdogNewFromDom;
 virDomainEventWatchdogNewFromObj;
 virDomainQemuMonitorEventNew;
index 7e74ff063f5b6eb093824b2db33fbcf2288b95c8..81b0ed00da1a5a8a2dbcba15797d5ebcf715ee43 100644 (file)
@@ -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);
index 8a0f5d30ac1335e6fb95bd711ed23bdeed130134..000c1b5324c34fec1f5b3c9a9b5917de6947c2bc 100644 (file)
@@ -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
@@ -5137,6 +5145,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,
index 38a83c64eadb8bc00f0d310a2657c85d56551234..23699e99a60aaf1cfd5d7df3f136781c26e201a6 100644 (file)
@@ -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
 };
index 0f87d13a5ae142401b8ec0d83366499ffb95baf6..75c3d0cb2e06bf786f6b1d9900fc2c53edffe744 100644 (file)
@@ -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,
 };
index b9d1cdf019cab13eba5c5083f9940ff8d16b360f..4a9a831b4525b307d330a1fc012d00e10ee09534 100644 (file)
@@ -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));