---
daemon/remote.c | 32 +++++++++++++
include/libvirt/libvirt.h.in | 18 ++++++++
python/libvirt-override-virConnect.py | 9 ++++
python/libvirt-override.c | 52 ++++++++++++++++++++-
src/conf/domain_event.c | 85 +++++++++++++++++++++++++++--------
src/conf/domain_event.h | 5 +++
src/libvirt_private.syms | 2 +
src/remote/remote_driver.c | 32 +++++++++++++
src/remote/remote_protocol.x | 13 +++++-
src/remote_protocol-structs | 5 +++
10 files changed, 233 insertions(+), 20 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 5847e60..a10a308 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -600,6 +600,37 @@ static int remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn
ATTRIBUTE_UNUS
return 0;
}
+static int
+remoteRelayDomainEventDeviceRemoved(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_device_removed_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain device removed event %s %d %s",
+ dom->name, dom->id, devAlias);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ return -1;
+
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
+ (xdrproc_t)xdr_remote_domain_event_device_removed_msg,
+ &data);
+
+ return 0;
+}
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
@@ -617,6 +648,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] =
{
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index b87255a..bd7417f 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -4851,6 +4851,23 @@ typedef void
(*virConnectDomainEventPMSuspendDiskCallback)(virConnectPtr conn,
int reason,
void *opaque);
+/**
+ * virConnectDomainEventDeviceRemovedCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @devAlias: device alias
+ * @opaque: application specified data
+ *
+ * This callback occurs when a device is removed from the domain.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventDeviceRemovedCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque);
+
/**
* VIR_DOMAIN_EVENT_CALLBACK:
@@ -4877,6 +4894,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_PMSUSPEND = 12, /* virConnectDomainEventPMSuspendCallback
*/
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /*
virConnectDomainEventBalloonChangeCallback */
VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK = 14, /*
virConnectDomainEventPMSuspendDiskCallback */
+ VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED = 15, /*
virConnectDomainEventDeviceRemovedCallback */
#ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_ID_LAST
diff --git a/python/libvirt-override-virConnect.py
b/python/libvirt-override-virConnect.py
index 5495b70..f2b4b23 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -179,6 +179,15 @@
cb(self, virDomain(self, _obj=dom), reason, opaque)
return 0
+ def _dispatchDomainEventDeviceRemovedCallback(self, dom, devAlias, cbData):
+ """Dispatches event to python user domain device removed event
callbacks
+ """
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), devAlias, opaque)
+ return 0
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 01c941e..2e94de9 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -6225,6 +6225,51 @@ libvirt_virConnectDomainEventPMSuspendDiskCallback(virConnectPtr
conn ATTRIBUTE_
return ret;
}
+static int
+libvirt_virConnectDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque)
+{
+ PyObject *pyobj_cbData = (PyObject*)opaque;
+ PyObject *pyobj_dom;
+ PyObject *pyobj_ret;
+ PyObject *pyobj_conn;
+ PyObject *dictKey;
+ int ret = -1;
+
+ LIBVIRT_ENSURE_THREAD_STATE;
+ /* Create a python instance of this virDomainPtr */
+ virDomainRef(dom);
+
+ pyobj_dom = libvirt_virDomainPtrWrap(dom);
+ Py_INCREF(pyobj_cbData);
+
+ dictKey = libvirt_constcharPtrWrap("conn");
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+ Py_DECREF(dictKey);
+
+ /* Call the Callback Dispatcher */
+ pyobj_ret = PyObject_CallMethod(pyobj_conn,
+
(char*)"_dispatchDomainEventDeviceRemovedCallback",
+ (char*)"OsO",
+ pyobj_dom, devAlias, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if (!pyobj_ret) {
+ DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
static PyObject *
libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
PyObject * args)
@@ -6254,7 +6299,7 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject *
self,
else
dom = PyvirDomain_Get(pyobj_dom);
- switch (eventID) {
+ switch ((virDomainEventID) eventID) {
case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventLifecycleCallback);
break;
@@ -6300,6 +6345,11 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject
* self,
case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
cb =
VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventPMSuspendDiskCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED:
+ cb =
VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventDeviceRemovedCallback);
+
+ case VIR_DOMAIN_EVENT_ID_LAST:
+ break;
}
if (!cb) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index fde24be..640463c 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -122,6 +122,9 @@ struct _virDomainEvent {
/* In unit of 1024 bytes */
unsigned long long actual;
} balloonChange;
+ struct {
+ char *devAlias;
+ } deviceRemoved;
} data;
};
@@ -1157,6 +1160,44 @@ virDomainEventPtr
virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj,
return ev;
}
+static virDomainEventPtr
+virDomainEventDeviceRemovedNew(int id,
+ const char *name,
+ unsigned char *uuid,
+ const char *devAlias)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED,
+ id, name, uuid);
+
+ if (ev) {
+ if (VIR_STRDUP(ev->data.deviceRemoved.devAlias, devAlias) < 0)
+ goto error;
+ }
+
+ return ev;
+
+error:
+ virDomainEventFree(ev);
+ return NULL;
+}
+
+virDomainEventPtr
+virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj,
+ const char *devAlias)
+{
+ return virDomainEventDeviceRemovedNew(obj->def->id, obj->def->name,
+ obj->def->uuid, devAlias);
+}
+
+virDomainEventPtr
+virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom,
+ const char *devAlias)
+{
+ return virDomainEventDeviceRemovedNew(dom->id, dom->name, dom->uuid,
+ devAlias);
+}
+
/**
* virDomainEventQueuePush:
* @evtQueue: the dom event queue
@@ -1204,30 +1245,30 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
return;
dom->id = event->dom.id;
- switch (event->eventID) {
+ switch ((virDomainEventID) event->eventID) {
case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
((virConnectDomainEventCallback)cb)(conn, dom,
event->data.lifecycle.type,
event->data.lifecycle.detail,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_REBOOT:
(cb)(conn, dom,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_RTC_CHANGE:
((virConnectDomainEventRTCChangeCallback)cb)(conn, dom,
event->data.rtcChange.offset,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_WATCHDOG:
((virConnectDomainEventWatchdogCallback)cb)(conn, dom,
event->data.watchdog.action,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_IO_ERROR:
((virConnectDomainEventIOErrorCallback)cb)(conn, dom,
@@ -1235,7 +1276,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
event->data.ioError.devAlias,
event->data.ioError.action,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
((virConnectDomainEventIOErrorReasonCallback)cb)(conn, dom,
@@ -1244,7 +1285,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
event->data.ioError.action,
event->data.ioError.reason,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_GRAPHICS:
((virConnectDomainEventGraphicsCallback)cb)(conn, dom,
@@ -1254,12 +1295,12 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
event->data.graphics.authScheme,
event->data.graphics.subject,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
(cb)(conn, dom,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
((virConnectDomainEventBlockJobCallback)cb)(conn, dom,
@@ -1267,7 +1308,7 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
event->data.blockJob.type,
event->data.blockJob.status,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
((virConnectDomainEventDiskChangeCallback)cb)(conn, dom,
@@ -1276,38 +1317,46 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
event->data.diskChange.devAlias,
event->data.diskChange.reason,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_TRAY_CHANGE:
((virConnectDomainEventTrayChangeCallback)cb)(conn, dom,
event->data.trayChange.devAlias,
event->data.trayChange.reason,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_PMWAKEUP:
((virConnectDomainEventPMWakeupCallback)cb)(conn, dom, 0, cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_PMSUSPEND:
((virConnectDomainEventPMSuspendCallback)cb)(conn, dom, 0, cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
((virConnectDomainEventBalloonChangeCallback)cb)(conn, dom,
event->data.balloonChange.actual,
cbopaque);
- break;
+ goto cleanup;
case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
((virConnectDomainEventPMSuspendDiskCallback)cb)(conn, dom, 0, cbopaque);
- break;
+ goto cleanup;
- default:
- VIR_WARN("Unexpected event ID %d", event->eventID);
+ case VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED:
+ ((virConnectDomainEventDeviceRemovedCallback)cb)(conn, dom,
+
event->data.deviceRemoved.devAlias,
+ cbopaque);
+ goto cleanup;
+
+ case VIR_DOMAIN_EVENT_ID_LAST:
break;
}
+ VIR_WARN("Unexpected event ID %d", event->eventID);
+
+cleanup:
virDomainFree(dom);
}
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 5f64a47..f6b957d 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -132,6 +132,11 @@ virDomainEventPtr
virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, uns
virDomainEventPtr virDomainEventPMSuspendDiskNewFromObj(virDomainObjPtr obj);
virDomainEventPtr virDomainEventPMSuspendDiskNewFromDom(virDomainPtr dom);
+virDomainEventPtr virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj,
+ const char *devAlias);
+virDomainEventPtr virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom,
+ const char *devAlias);
+
void virDomainEventFree(virDomainEventPtr event);
void virDomainEventStateFree(virDomainEventStatePtr state);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0ab7632..49f07c1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -405,6 +405,8 @@ virDomainEventBlockJobNewFromDom;
virDomainEventBlockJobNewFromObj;
virDomainEventControlErrorNewFromDom;
virDomainEventControlErrorNewFromObj;
+virDomainEventDeviceRemovedNewFromDom;
+virDomainEventDeviceRemovedNewFromObj;
virDomainEventDiskChangeNewFromDom;
virDomainEventDiskChangeNewFromObj;
virDomainEventFree;
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 81ecef1..b4bb926 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -268,6 +268,11 @@ remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
remoteDomainBuildEventRTCChange,
@@ -329,6 +334,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventPMSuspendDisk,
sizeof(remote_domain_event_pmsuspend_disk_msg),
(xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
+ remoteDomainBuildEventDeviceRemoved,
+ sizeof(remote_domain_event_device_removed_msg),
+ (xdrproc_t)xdr_remote_domain_event_device_removed_msg },
};
enum virDrvOpenRemoteFlags {
@@ -4695,6 +4704,29 @@ remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED
}
+static void
+remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_device_removed_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventDeviceRemovedNewFromDom(dom, msg->devAlias);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+
static virDrvOpenStatus ATTRIBUTE_NONNULL(1)
remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth,
unsigned int flags)
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 2e9dc1d..d42e5af 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2808,6 +2808,11 @@ struct remote_domain_migrate_confirm3_params_args {
int cancelled;
};
+struct remote_domain_event_device_removed_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string devAlias;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@@ -4944,6 +4949,12 @@ enum remote_procedure {
* @generate: none
* @acl: domain:migrate
*/
- REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307
+ REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 308
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index e38d24a..8d064fe 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2293,6 +2293,10 @@ struct remote_domain_migrate_confirm3_params_args {
u_int flags;
int cancelled;
};
+struct remote_domain_event_device_removed_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string devAlias;
+};
enum remote_procedure {
REMOTE_PROC_CONNECT_OPEN = 1,
REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -2601,4 +2605,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS = 305,
REMOTE_PROC_DOMAIN_MIGRATE_FINISH3_PARAMS = 306,
REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307,
+ REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 308,
};
--
1.8.3.2