From: ShaoHe Feng <shaohef@xxxxxxxxxxxxxxxxxx> Signed-off-by: ShaoHe Feng <shaohef@xxxxxxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list