diff --git a/daemon/remote.c b/daemon/remote.c index daa4b601e40880e30ed84ab0fa1772f52bd651bc..ddd510c169d0420a1054624f688ca06535be2689 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -110,6 +110,13 @@ remoteDeserializeTypedParameters(remote_typed_param *args_params_val, int limit, int *nparams); +static int +remoteSerializeTypedParameters(virTypedParameterPtr params, + int nparams, + remote_typed_param **ret_params_val, + u_int *ret_params_len, + unsigned int flags); + static int remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors, int nerrors, @@ -969,6 +976,43 @@ remoteRelayDomainEventBlockJob2(virConnectPtr conn, } +static int +remoteRelayDomainEventTunable(virConnectPtr conn, + virDomainPtr dom, + virTypedParameterPtr params, + int nparams, + void *opaque) +{ + daemonClientEventCallbackPtr callback = opaque; + remote_domain_event_callback_tunable_msg data; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + VIR_DEBUG("Relaying domain tunable event %s %d, callback %d", + dom->name, dom->id, callback->callbackID); + + /* build return data */ + memset(&data, 0, sizeof(data)); + data.callbackID = callback->callbackID; + make_nonnull_domain(&data.dom, dom); + + if (remoteSerializeTypedParameters(params, nparams, + &data.params.params_val, + &data.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return -1; + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE, + (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg, + &data); + + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -987,6 +1031,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 6371b7ba4adbff2fa962dd604597a59b9d2ff245..86be86ffaef096a58ca029568937b39434fbca65 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -5203,6 +5203,27 @@ typedef void (*virConnectDomainEventDeviceRemovedCallback)(virConnectPtr conn, const char *devAlias, void *opaque); +/** + * virConnectDomainEventTunableCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @params: changed tunable values stored as array of virTypedParameter + * @nparams: size of the array + * @opaque: application specified data + * + * This callback occurs when tunable values are updated. The params must not + * be freed in the callback handler as it's done internally after the callback + * handler is executed. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_TUNABLE with virConnectDomainEventRegisterAny() + */ +typedef void (*virConnectDomainEventTunableCallback)(virConnectPtr conn, + virDomainPtr dom, + virTypedParameterPtr params, + int nparams, + void *opaque); + /** * VIR_DOMAIN_EVENT_CALLBACK: @@ -5238,6 +5259,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK = 14, /* virConnectDomainEventPMSuspendDiskCallback */ VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED = 15, /* virConnectDomainEventDeviceRemovedCallback */ VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2 = 16, /* virConnectDomainEventBlockJobCallback */ + VIR_DOMAIN_EVENT_ID_TUNABLE = 17, /* virConnectDomainEventTunableCallback */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 73ae2894b82d4dd22ae4e5ba82271aca96e9f5f3..bf187cd361df0d702c2c9e1796f478b423e82b90 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -34,6 +34,7 @@ #include "viralloc.h" #include "virerror.h" #include "virstring.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -52,6 +53,7 @@ static virClassPtr virDomainEventBalloonChangeClass; static virClassPtr virDomainEventDeviceRemovedClass; static virClassPtr virDomainEventPMClass; static virClassPtr virDomainQemuMonitorEventClass; +static virClassPtr virDomainEventTunableClass; static void virDomainEventDispose(void *obj); @@ -67,6 +69,7 @@ static void virDomainEventBalloonChangeDispose(void *obj); static void virDomainEventDeviceRemovedDispose(void *obj); static void virDomainEventPMDispose(void *obj); static void virDomainQemuMonitorEventDispose(void *obj); +static void virDomainEventTunableDispose(void *obj); static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -203,6 +206,15 @@ struct _virDomainQemuMonitorEvent { typedef struct _virDomainQemuMonitorEvent virDomainQemuMonitorEvent; typedef virDomainQemuMonitorEvent *virDomainQemuMonitorEventPtr; +struct _virDomainEventTunable { + virDomainEvent parent; + + virTypedParameterPtr params; + int nparams; +}; +typedef struct _virDomainEventTunable virDomainEventTunable; +typedef virDomainEventTunable *virDomainEventTunablePtr; + static int virDomainEventsOnceInit(void) @@ -285,6 +297,12 @@ virDomainEventsOnceInit(void) sizeof(virDomainQemuMonitorEvent), virDomainQemuMonitorEventDispose))) return -1; + if (!(virDomainEventTunableClass = + virClassNew(virDomainEventClass, + "virDomainEventTunable", + sizeof(virDomainEventTunable), + virDomainEventTunableDispose))) + return -1; return 0; } @@ -420,6 +438,15 @@ virDomainQemuMonitorEventDispose(void *obj) VIR_FREE(event->details); } +static void +virDomainEventTunableDispose(void *obj) +{ + virDomainEventTunablePtr event = obj; + VIR_DEBUG("obj=%p", event); + + virTypedParamsFree(event->params, event->nparams); +} + static void * virDomainEventNew(virClassPtr klass, @@ -1175,6 +1202,61 @@ virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, devAlias); } +/* This function consumes the params so caller don't have to care about + * freeing it even if error occurs. The reason is to not have to do deep + * copy of params. + */ +static virObjectEventPtr +virDomainEventTunableNew(int id, + const char *name, + unsigned char *uuid, + virTypedParameterPtr params, + int nparams) +{ + virDomainEventTunablePtr ev; + + if (virDomainEventsInitialize() < 0) + goto error; + + if (!(ev = virDomainEventNew(virDomainEventTunableClass, + VIR_DOMAIN_EVENT_ID_TUNABLE, + id, name, uuid))) + goto error; + + ev->params = params; + ev->nparams = nparams; + + return (virObjectEventPtr)ev; + + error: + virTypedParamsFree(params, nparams); + return NULL; +} + +virObjectEventPtr +virDomainEventTunableNewFromObj(virDomainObjPtr obj, + virTypedParameterPtr params, + int nparams) +{ + return virDomainEventTunableNew(obj->def->id, + obj->def->name, + obj->def->uuid, + params, + nparams); +} + +virObjectEventPtr +virDomainEventTunableNewFromDom(virDomainPtr dom, + virTypedParameterPtr params, + int nparams) +{ + return virDomainEventTunableNew(dom->id, + dom->name, + dom->uuid, + params, + nparams); +} + static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -1366,6 +1448,17 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, goto cleanup; } + case VIR_DOMAIN_EVENT_ID_TUNABLE: + { + virDomainEventTunablePtr tunableEvent; + tunableEvent = (virDomainEventTunablePtr)event; + ((virConnectDomainEventTunableCallback)cb)(conn, dom, + tunableEvent->params, + tunableEvent->nparams, + 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 a3330ca804fda4b85995956e98b8cc7d7b5c176d..dc0109cf67286d3406029552059fe06a9232ae9f 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -184,6 +184,15 @@ virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj, virObjectEventPtr virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, const char *devAlias); +virObjectEventPtr +virDomainEventTunableNewFromObj(virDomainObjPtr obj, + virTypedParameterPtr params, + int nparams); +virObjectEventPtr +virDomainEventTunableNewFromDom(virDomainPtr dom, + virTypedParameterPtr params, + int nparams); + int virDomainEventStateRegister(virConnectPtr conn, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 51a692b39ba30ff037a35af949aafea8f00a9d6e..a339ced69dad931ddc08d88703e0ec605b822e0f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -473,6 +473,8 @@ virDomainEventStateRegister; virDomainEventStateRegisterID; virDomainEventTrayChangeNewFromDom; virDomainEventTrayChangeNewFromObj; +virDomainEventTunableNewFromDom; +virDomainEventTunableNewFromObj; virDomainEventWatchdogNewFromDom; virDomainEventWatchdogNewFromObj; virDomainQemuMonitorEventNew; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 75a3a7b4f46887c6bf63f2bdf84efb388bfb0758..dbf7c04330e496f48c5da9eab97d7030764e8b54 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -330,6 +330,11 @@ remoteDomainBuildEventBlockJob2(virNetClientProgramPtr prog, virNetClientPtr client, void *evdata, void *opaque); +static void +remoteDomainBuildEventCallbackTunable(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + static void remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, @@ -481,6 +486,10 @@ static virNetClientProgramEvent remoteEvents[] = { remoteDomainBuildEventBlockJob2, sizeof(remote_domain_event_block_job_2_msg), (xdrproc_t)xdr_remote_domain_event_block_job_2_msg }, + { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE, + remoteDomainBuildEventCallbackTunable, + sizeof(remote_domain_event_callback_tunable_msg), + (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg }, }; @@ -5513,6 +5522,39 @@ remoteDomainBuildEventCallbackDeviceRemoved(virNetClientProgramPtr prog ATTRIBUT } +static void +remoteDomainBuildEventCallbackTunable(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + remote_domain_event_callback_tunable_msg *msg = evdata; + struct private_data *priv = conn->privateData; + virDomainPtr dom; + virTypedParameterPtr params = NULL; + int nparams = 0; + virObjectEventPtr event = NULL; + + if (remoteDeserializeTypedParameters(msg->params.params_val, + msg->params.params_len, + REMOTE_DOMAIN_EVENT_TUNABLE_MAX, + ¶ms, &nparams) < 0) + return; + + dom = get_nonnull_domain(conn, msg->dom); + if (!dom) { + virTypedParamsFree(params, nparams); + return; + } + + event = virDomainEventTunableNewFromDom(dom, params, nparams); + + virDomainFree(dom); + + remoteEventQueue(priv, event, msg->callbackID); +} + + static void remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index a4ca0c3421f91aa826753d9252125d831d9358a2..0c6a91ebabc2d00911b13825b16faf2f5e8fef2d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -247,6 +247,9 @@ const REMOTE_NETWORK_DHCP_LEASES_MAX = 65536; /* Upper limit on count of parameters returned via bulk stats API */ const REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX = 4096; +/* Upper limit of message size for tunable event. */ +const REMOTE_DOMAIN_EVENT_TUNABLE_MAX = 8388608; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2990,6 +2993,12 @@ struct remote_domain_event_block_job_2_msg { int status; }; +struct remote_domain_event_callback_tunable_msg { + int callbackID; + remote_nonnull_domain dom; + remote_typed_param params; +}; + struct remote_connect_get_cpu_model_names_args { remote_nonnull_string arch; int need_results; @@ -5472,5 +5481,11 @@ enum remote_procedure { * @generate: both * @acl: domain:block_write */ - REMOTE_PROC_DOMAIN_BLOCK_COPY = 345 + REMOTE_PROC_DOMAIN_BLOCK_COPY = 345, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE = 346 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index e9604159fb1aa27d7ba332ca456e186444b7e4f9..6128a856f1f5b98a4ce816c98dfc41ba700751ef 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2445,6 +2445,14 @@ struct remote_domain_event_block_job_2_msg { int type; int status; }; +struct remote_domain_event_callback_tunable_msg { + int callbackID; + remote_nonnull_domain dom; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; +}; struct remote_connect_get_cpu_model_names_args { remote_nonnull_string arch; int need_results; @@ -2901,4 +2909,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD = 343, REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS = 344, REMOTE_PROC_DOMAIN_BLOCK_COPY = 345, + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE = 346, }; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index a6ced5f28f9bce1c8d6f187462550a17dac04609..ce5940623d8d3449ab4b0e9c52786b5b8ff14f1e 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11454,6 +11454,37 @@ vshEventDeviceRemovedPrint(virConnectPtr conn ATTRIBUTE_UNUSED, vshEventDone(data->ctl); } +static void +vshEventTunablePrint(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + virTypedParameterPtr params, + int nparams, + void *opaque) +{ + vshDomEventData *data = opaque; + size_t i; + char *value = NULL; + + if (!data->loop && *data->count) + return; + + vshPrint(data->ctl, + _("event 'tunable' for domain %s:\n"), + virDomainGetName(dom)); + + for (i = 0; i < nparams; i++) { + value = virTypedParameterToString(¶ms[i]); + if (value) { + vshPrint(data->ctl, _("\t%s: %s\n"), params[i].field, value); + VIR_FREE(value); + } + } + + (*data->count)++; + if (!data->loop) + vshEventDone(data->ctl); +} + static vshEventCallback vshEventCallbacks[] = { { "lifecycle", VIR_DOMAIN_EVENT_CALLBACK(vshEventLifecyclePrint), }, @@ -11487,6 +11518,8 @@ static vshEventCallback vshEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(vshEventDeviceRemovedPrint), }, { "block-job-2", VIR_DOMAIN_EVENT_CALLBACK(vshEventBlockJobPrint), }, + { "tunable", + VIR_DOMAIN_EVENT_CALLBACK(vshEventTunablePrint), }, }; verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));