From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
daemon/libvirtd.h | 10 +++
daemon/remote.c | 172 +++++++++++++++++++++++++++++++++++++++++-
src/remote/qemu_protocol.x | 29 +++++++-
src/remote/remote_driver.c | 162 ++++++++++++++++++++++++++++++++++++++-
src/remote/remote_protocol.x | 6 ++
src/remote_protocol-structs | 5 +
6 files changed, 376 insertions(+), 8 deletions(-)
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index c8d3ca2..fab7290 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -38,6 +38,15 @@
# endif
# include "virnetserverprogram.h"
+/* limit the number unknow event of an conncet can register */
+#define VIR_DOMAIN_EVENT_NAME_LAST 512
+struct domainEventNameCallBackStatus {
+ /* counter the number of unknow event registered */
+ int eventNameCallBackCounter;
+ /* Stores the ID of the unknow event registered */
+ int eventNameCallback[VIR_DOMAIN_EVENT_NAME_LAST];
+};
+typedef struct domainEventNameCallBackStatus domainEventNameCallBackStatus;
typedef struct daemonClientStream daemonClientStream;
typedef daemonClientStream *daemonClientStreamPtr;
typedef struct daemonClientPrivate daemonClientPrivate;
@@ -49,6 +58,7 @@ struct daemonClientPrivate {
virMutex lock;
int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
+ domainEventNameCallBackStatus domainEventNameCallBack;
# if HAVE_SASL
virNetSASLSessionPtr sasl;
diff --git a/daemon/remote.c b/daemon/remote.c
index e1d208c..f444c3d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -421,6 +421,53 @@ mem_error:
return -1;
}
+static int remoteRelayDomainEventUnknown(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *eventName, /* The JSON event name
*/
+ const char *eventArgs, /* The JSON string of
args */
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ qemu_domain_events_unknown_event_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain: %s id: %d, unknown event: %s arguments: %s",
+ dom->name, dom->id, eventName, eventArgs);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ if (eventName == NULL)
+ goto mem_error3;
+ data.eventName = (char *)strdup(eventName);
+ if (data.eventName == NULL)
+ goto mem_error2;
+ if (eventArgs != NULL) {
+ data.eventArgs = (char *)strdup(eventArgs);
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ else {
+ data.eventArgs = (char *)strdup("NULL");
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ make_nonnull_domain(&data.dom, dom);
+ remoteDispatchDomainEventSend(client, qemuProgram,
+ QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT,
+ (xdrproc_t)xdr_qemu_domain_events_unknown_event_msg,
&data);
+
+ return 0;
+
+mem_error1:
+ VIR_FREE(data.eventArgs);
+mem_error2:
+ VIR_FREE(data.eventName);
+mem_error3:
+ virReportOOMError();
+ return -1;
+}
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
@@ -509,6 +556,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] =
{
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventUnknown),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
@@ -526,10 +574,21 @@ static void remoteClientFreeFunc(void *data)
/* Deregister event delivery callback */
if (priv->conn) {
- int i;
+ int i, j;
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
- if (priv->domainEventCallbackID[i] != -1) {
+ if (i == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN &&
priv->domainEventCallbackID[i] != -1) {
+ for (j = 0 ; j < VIR_DOMAIN_EVENT_NAME_LAST ; j++){
+ if (priv->domainEventNameCallBack.eventNameCallback[j] != -1) {
+ VIR_DEBUG("Deregistering to relay remote events %d",
i);
+ virConnectDomainQemuEventDeregister(priv->conn,
+
priv->domainEventNameCallBack.eventNameCallback[j]);
+ }
+ priv->domainEventNameCallBack.eventNameCallback[j] == -1;
+ }
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ }
+ else if (priv->domainEventCallbackID[i] != -1) {
VIR_DEBUG("Deregistering to relay remote events %d", i);
virConnectDomainEventDeregisterAny(priv->conn,
priv->domainEventCallbackID[i]);
@@ -572,6 +631,10 @@ int remoteClientInitHook(virNetServerPtr srv ATTRIBUTE_UNUSED,
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
priv->domainEventCallbackID[i] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ for (i = 0 ; i < VIR_DOMAIN_EVENT_NAME_LAST ; i++)
+ priv->domainEventNameCallBack.eventNameCallback[i] = -1;
+
virNetServerClientSetPrivateData(client, priv,
remoteClientFreeFunc);
virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
@@ -2991,6 +3054,111 @@ cleanup:
}
static int
+qemuDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_register_args *args,
+ qemu_domain_events_register_ret *ret ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->eventName == NULL) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("event Name is NULL"));
+ goto cleanup;
+ }
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter >=
VIR_DOMAIN_EVENT_NAME_LAST) {
+ virNetError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event %s is not registered, the register number has
exceeded limit number %d"),
+ args->eventName,
+ VIR_DOMAIN_EVENT_NAME_LAST);
+ goto cleanup;
+ }
+
+ if ((callbackID = virConnectDomainQemuEventRegister(priv->conn,
+ NULL,
+ args->eventName,
+
(virConnectDomainQemuEventCallback)remoteRelayDomainEventUnknown,
+ client,
+ NULL)) < 0)
+ goto cleanup;
+
+ for (eventIdx = 0 ; eventIdx < VIR_DOMAIN_EVENT_NAME_LAST ; eventIdx++) {
+ if (priv->domainEventNameCallBack.eventNameCallback[eventIdx] == -1) {
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] = callbackID;
+ priv->domainEventNameCallBack.eventNameCallBackCounter++;
+ ret->callbackID = eventIdx;
+ break;
+ }
+ }
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = callbackID;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+qemuDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_deregister_args *args,
+ qemu_domain_events_deregister_ret *ret
ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = args->callbackID;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (eventIdx >= VIR_DOMAIN_EVENT_NAME_LAST ||
+ (callbackID = priv->domainEventNameCallBack.eventNameCallback[eventIdx]) <
0) {
+
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("callbakcID %d is not register"),
eventIdx);
+ goto cleanup;
+ }
+
+ if (virConnectDomainQemuEventDeregister(priv->conn, callbackID) < 0)
+ goto cleanup;
+ ret->callbackID = callbackID;
+
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter--;
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter == 0)
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = -1;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
index 39f9adf..54f5734 100644
--- a/src/remote/qemu_protocol.x
+++ b/src/remote/qemu_protocol.x
@@ -47,6 +47,30 @@ struct qemu_domain_attach_ret {
remote_nonnull_domain dom;
};
+struct qemu_domain_events_register_args {
+ remote_nonnull_string eventName;
+};
+
+struct qemu_domain_events_deregister_args {
+ remote_nonnull_string eventName;
+ int callbackID;
+};
+
+struct qemu_domain_events_register_ret {
+ int callbackID;
+};
+
+struct qemu_domain_events_deregister_ret {
+ int callbackID;
+};
+
+struct qemu_domain_events_unknown_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
+
/* Define the program number, protocol version and procedure numbers here. */
const QEMU_PROGRAM = 0x20008087;
const QEMU_PROTOCOL_VERSION = 1;
@@ -61,5 +85,8 @@ enum qemu_procedure {
* are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
* be marked as high priority. If in doubt, it's safe to choose low. */
QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
- QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_ATTACH = 2, /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_REGISTER = 3, /* skipgen skipgen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_DEREGISTER = 4, /* skipgen skipgen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT = 5 /* skipgen skipgen */
};
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index ff2d4b4..a347eb2 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -238,6 +238,10 @@ static void
remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
@@ -281,7 +285,12 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
sizeof(remote_domain_event_disk_change_msg),
(xdrproc_t)xdr_remote_domain_event_disk_change_msg },
};
-
+static virNetClientProgramEvent qemuDomainEvents[] = {
+ { QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT,
+ remoteQemuDomainBuildEventDefaultEvent,
+ sizeof(qemu_domain_events_unknown_event_msg),
+ (xdrproc_t)xdr_qemu_domain_events_unknown_event_msg},
+};
enum virDrvOpenRemoteFlags {
VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
VIR_DRV_OPEN_REMOTE_USER = (1 << 1), /* Use the per-user socket path */
@@ -663,9 +672,9 @@ doRemoteOpen (virConnectPtr conn,
goto failed;
if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM,
QEMU_PROTOCOL_VERSION,
- NULL,
- 0,
- NULL)))
+ qemuDomainEvents,
+
ARRAY_CARDINALITY(remoteDomainEvents),
+ conn)))
goto failed;
if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 ||
@@ -3345,6 +3354,29 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
}
static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ //remote_domain_event_default_event_msg *msg = evdata;
+ qemu_domain_events_unknown_event_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventUnknownNewFromDom(dom, msg->eventName, msg->eventArgs);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
@@ -3800,7 +3832,6 @@ done:
return rv;
}
-
static int remoteDomainEventDeregisterAny(virConnectPtr conn,
int callbackID)
{
@@ -3843,6 +3874,125 @@ done:
return rv;
}
+static int
+remoteDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ int rv = -1;
+ struct private_data *priv = conn->privateData;
+ qemu_domain_events_register_args args;
+ qemu_domain_events_register_ret ret;
+ int callbackID;
+
+ remoteDriverLock(priv);
+
+ if (priv->domainEventState->timer < 0) {
+ remoteError(VIR_ERR_NO_SUPPORT, "%s", _("no event
support"));
+ goto done;
+ }
+
+ if ((callbackID = virDomainEventCallbackListAddName(conn,
+
priv->domainEventState->callbacks,
+ dom, eventName,
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ callback, opaque, freecb)) < 0)
{
+ remoteError(VIR_ERR_RPC, "%s", _("adding cb to list"));
+ goto done;
+ }
+
+ /* If this is the first callback for this eventID, we need to enable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+ priv->domainEventState->callbacks,
+ eventName) == 1) {
+ args.eventName= (char *)eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_REGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_register_args, (char *) &args,
+ (xdrproc_t) xdr_qemu_domain_events_register_ret, (char *) &ret) ==
-1) {
+ virDomainEventCallbackListRemoveID(conn,
+ priv->domainEventState->callbacks,
+ callbackID);
+ goto done;
+ }
+ }
+ virDomainEventCallbackListAddQemuCallbackID(conn,
+ priv->domainEventState->callbacks,
+ callbackID,
+ ret.callbackID);
+ rv = callbackID;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+static int remoteDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+ struct private_data *priv = conn->privateData;
+ int rv = -1;
+ qemu_domain_events_deregister_args args;
+ qemu_domain_events_deregister_ret ret;
+ char *eventName = NULL;
+ ret.callbackID = -1;
+
+ remoteDriverLock(priv);
+
+ if ((eventName = (char *)virDomainEventCallbackListEventName(conn,
+
priv->domainEventState->callbacks,
+ callbackID)) == NULL) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"),
callbackID);
+ goto done;
+ }
+ eventName = strdup(eventName);
+ if (eventName == NULL)
+ goto done;
+
+ if ((args.callbackID = virDomainEventCallbackListEventQemuCallbackID(conn,
+
priv->domainEventState->callbacks,
+ callbackID)) == -1) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"),
callbackID);
+ goto done;
+ }
+
+ if (virDomainQemuEventStateDeregister(conn,
+ priv->domainEventState,
+ callbackID) < 0)
+ goto done;
+
+ /* If that was the last callback for this eventName, we need to disable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+ priv->domainEventState->callbacks,
+ eventName) == 0) {
+ args.eventName = eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_DEREGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_args, (char *)
&args,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_ret, (char *) &ret)
== -1) {
+ goto done;
+ }
+
+ if ( ret.callbackID == -1 ) {
+ remoteError(VIR_ERR_RPC, _("remote sever deregeiter remote
callbackID:%d, and the client callbackID%d"),
+ args.callbackID,
+ callbackID);
+ goto done;
+ }
+ rv = ret.callbackID;
+ }
+
+
+done:
+ remoteDriverUnlock(priv);
+ VIR_FREE(eventName);
+ return rv;
+}
/*----------------------------------------------------------------------*/
@@ -4627,6 +4777,8 @@ static virDriver remote_driver = {
.nodeGetFreeMemory = remoteNodeGetFreeMemory, /* 0.3.3 */
.domainEventRegister = remoteDomainEventRegister, /* 0.5.0 */
.domainEventDeregister = remoteDomainEventDeregister, /* 0.5.0 */
+ .qemuDomainQemuEventRegister = remoteDomainQemuEventRegister, /* 0.9.9 */
+ .qemuDomainQemuEventDeregister = remoteDomainQemuEventDeregister, /* 0.9.9 */
.domainMigratePrepare2 = remoteDomainMigratePrepare2, /* 0.5.0 */
.domainMigrateFinish2 = remoteDomainMigrateFinish2, /* 0.5.0 */
.nodeDeviceDettach = remoteNodeDeviceDettach, /* 0.6.1 */
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 509a20b..02154bc 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2049,6 +2049,12 @@ struct remote_domain_event_disk_change_msg {
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index a9d4296..17b3896 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1546,6 +1546,10 @@ struct remote_domain_event_disk_change_msg {
remote_nonnull_string devAlias;
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string rawEvent;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -2044,4 +2048,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251,
REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252,
REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253,
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254,
};
--
1.7.5.4