From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> When the guest changes its memory balloon applications may want to know what the new value is, without having to periodically poll on XML / domain info. Introduce a "balloon change" event to let apps see this * include/libvirt/libvirt.h.in: Define the virConnectDomainEventBalloonChangeCallback callback and VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE constant * python/libvirt-override-virConnect.py, python/libvirt-override.c: Wire up helpers for new event * daemon/remote.c: Helper for serializing balloon event * examples/domain-events/events-c/event-test.c, examples/domain-events/events-python/event-test.py: Add example of balloon event usage * src/conf/domain_event.c, src/conf/domain_event.h: Handling of balloon events * src/remote/remote_driver.c: Add handler of balloon events * src/remote/remote_protocol.x: Define wire protocol for balloon events * src/remote_protocol-structs: Likewise. Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> --- daemon/remote.c | 28 +++++++++++ examples/domain-events/events-c/event-test.c | 22 ++++++++- examples/domain-events/events-python/event-test.py | 3 + include/libvirt/libvirt.h.in | 17 +++++++ python/libvirt-override-virConnect.py | 9 ++++ python/libvirt-override.c | 50 ++++++++++++++++++++ src/conf/domain_event.c | 35 ++++++++++++++ src/conf/domain_event.h | 3 + src/libvirt_private.syms | 2 + src/remote/remote_driver.c | 31 ++++++++++++ src/remote/remote_protocol.x | 8 +++- src/remote_protocol-structs | 5 ++ 12 files changed, 211 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 095d854..9334221 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -582,6 +582,33 @@ static int remoteRelayDomainEventPMSuspend(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int +remoteRelayDomainEventBalloonChange(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + unsigned long long actual, + void *opaque) +{ + virNetServerClientPtr client = opaque; + remote_domain_event_balloon_change_msg data; + + if (!client) + return -1; + + VIR_DEBUG("Relaying domain balloon change event %s %d %lld", dom->name, dom->id, actual); + + /* build return data */ + memset(&data, 0, sizeof(data)); + make_nonnull_domain(&data.dom, dom); + data.actual = actual; + + remoteDispatchDomainEventSend(client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE, + (xdrproc_t)xdr_remote_domain_event_balloon_change_msg, &data); + + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -596,6 +623,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTrayChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange), }; verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c index c54778f..ef6e77a 100644 --- a/examples/domain-events/events-c/event-test.c +++ b/examples/domain-events/events-c/event-test.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <string.h> #include <signal.h> +#include <inttypes.h> #include <libvirt/libvirt.h> #include <libvirt/virterror.h> @@ -222,6 +223,17 @@ static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int myDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + unsigned long long actual, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual); + + return 0; +} + static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int action, @@ -391,6 +403,7 @@ int main(int argc, char **argv) int callback10ret = -1; int callback11ret = -1; int callback12ret = -1; + int callback13ret = -1; struct sigaction action_stop; memset(&action_stop, 0, sizeof(action_stop)); @@ -476,6 +489,11 @@ int main(int argc, char **argv) VIR_DOMAIN_EVENT_ID_PMSUSPEND, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendCallback), strdup("pmsuspend"), myFreeFunc); + callback13ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback), + strdup("callback balloonchange"), myFreeFunc); if ((callback1ret != -1) && (callback2ret != -1) && (callback3ret != -1) && @@ -486,7 +504,8 @@ int main(int argc, char **argv) (callback9ret != -1) && (callback10ret != -1) && (callback11ret != -1) && - (callback12ret != -1)) { + (callback12ret != -1) && + (callback13ret != -1)) { if (virConnectSetKeepAlive(dconn, 5, 3) < 0) { virErrorPtr err = virGetLastError(); fprintf(stderr, "Failed to start keepalive protocol: %s\n", @@ -514,6 +533,7 @@ int main(int argc, char **argv) virConnectDomainEventDeregisterAny(dconn, callback10ret); virConnectDomainEventDeregisterAny(dconn, callback11ret); virConnectDomainEventDeregisterAny(dconn, callback12ret); + virConnectDomainEventDeregisterAny(dconn, callback13ret); if (callback8ret != -1) virConnectDomainEventDeregisterAny(dconn, callback8ret); } diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py index 96dc268..137c31c 100644 --- a/examples/domain-events/events-python/event-test.py +++ b/examples/domain-events/events-python/event-test.py @@ -483,6 +483,8 @@ def myDomainEventPMWakeupCallback(conn, dom, reason, opaque): def myDomainEventPMSuspendCallback(conn, dom, reason, opaque): print "myDomainEventPMSuspendCallback: Domain %s(%s) system pmsuspend" % ( dom.name(), dom.ID()) +def myDomainEventBalloonChangeCallback(conn, dom, utcoffset, actual): + print "myDomainEventBalloonChangeCallback: Domain %s(%s) %d" % (dom.name(), dom.ID(), actual) def usage(out=sys.stderr): print >>out, "usage: "+os.path.basename(sys.argv[0])+" [-hdl] [uri]" print >>out, " uri will default to qemu:///system" @@ -544,6 +546,7 @@ def main(): vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, myDomainEventTrayChangeCallback, None) vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback, None) vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback, None) + vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, None) vc.setKeepAlive(5, 3) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 6e8d5dd..e34438c 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3861,6 +3861,22 @@ typedef void (*virConnectDomainEventPMSuspendCallback)(virConnectPtr conn, int reason, void *opaque); + +/** + * virConnectDomainEventBalloonChangeCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @actual: the new balloon level measured in kibibytes(blocks of 1024 bytes) + * @opaque: application specified data + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE with virConnectDomainEventRegisterAny() + */ +typedef void (*virConnectDomainEventBalloonChangeCallback)(virConnectPtr conn, + virDomainPtr dom, + unsigned long long actual, + void *opaque); + /** * VIR_DOMAIN_EVENT_CALLBACK: * @@ -3884,6 +3900,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_TRAY_CHANGE = 10, /* virConnectDomainEventTrayChangeCallback */ VIR_DOMAIN_EVENT_ID_PMWAKEUP = 11, /* virConnectDomainEventPMWakeupCallback */ VIR_DOMAIN_EVENT_ID_PMSUSPEND = 12, /* virConnectDomainEventPMSuspendCallback */ + VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /* virConnectDomainEventBalloonChangeCallback */ #ifdef VIR_ENUM_SENTINELS /* diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index ecb5680..50177ab 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -161,6 +161,15 @@ cb(self, virDomain(self, _obj=dom), reason, opaque) return 0; + def _dispatchDomainEventBalloonChangeCallback(self, dom, actual, cbData): + """Dispatches events to python user domain balloon change event callbacks + """ + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(self, virDomain(self, _obj=dom), actual, 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 8ef9fa0..8b41dff 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -5352,6 +5352,53 @@ libvirt_virConnectDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUS return ret; } +static int +libvirt_virConnectDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + unsigned long long actual, + 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*)"_dispatchDomainEventBalloonChangeCallback", + (char*)"OLO", + pyobj_dom, + (PY_LONG_LONG)actual, + 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) @@ -5421,6 +5468,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self, case VIR_DOMAIN_EVENT_ID_PMSUSPEND: cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventPMSuspendCallback); break; + case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE: + cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBalloonChangeCallback); + break; } if (!cb) { diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 3cfd940..8517fb4 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -121,6 +121,10 @@ struct _virDomainEvent { char *devAlias; int reason; } trayChange; + struct { + /* In unit of 1024 bytes */ + unsigned long long actual; + } balloonChange; } data; }; @@ -1109,6 +1113,31 @@ virDomainEventPMSuspendNewFromDom(virDomainPtr dom) return virDomainEventPMSuspendNew(dom->id, dom->name, dom->uuid); } +virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom, + unsigned long long actual) +{ + virDomainEventPtr ev = + virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, + dom->id, dom->name, dom->uuid); + + if (ev) + ev->data.balloonChange.actual = actual; + + return ev; +} +virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, + unsigned long long actual) +{ + virDomainEventPtr ev = + virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, + obj->def->id, obj->def->name, obj->def->uuid); + + if (ev) + ev->data.balloonChange.actual = actual; + + return ev; +} + /** * virDomainEventQueuePush: * @evtQueue: the dom event queue @@ -1247,6 +1276,12 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, ((virConnectDomainEventPMSuspendCallback)cb)(conn, dom, 0, cbopaque); break; + case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE: + ((virConnectDomainEventBalloonChangeCallback)cb)(conn, dom, + event->data.balloonChange.actual, + cbopaque); + break; + default: VIR_WARN("Unexpected event ID %d", event->eventID); break; diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index d381aec..1274751 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -125,6 +125,9 @@ virDomainEventPtr virDomainEventPMWakeupNewFromDom(virDomainPtr dom); virDomainEventPtr virDomainEventPMSuspendNewFromObj(virDomainObjPtr obj); virDomainEventPtr virDomainEventPMSuspendNewFromDom(virDomainPtr dom); +virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom, unsigned long long actual); +virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, unsigned long long actual); + void virDomainEventFree(virDomainEventPtr event); void virDomainEventStateFree(virDomainEventStatePtr state); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b173590..7373281 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -500,6 +500,8 @@ virDomainWatchdogModelTypeToString; # domain_event.h +virDomainEventBalloonChangeNewFromDom; +virDomainEventBalloonChangeNewFromObj; virDomainEventBlockJobNewFromObj; virDomainEventBlockJobNewFromDom; virDomainEventControlErrorNewFromDom; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index eac50e6..3314f80 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -253,6 +253,10 @@ static void remoteDomainBuildEventPMSuspend(virNetClientProgramPtr prog, virNetClientPtr client, void *evdata, void *opaque); +static void +remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); static virNetClientProgramEvent remoteDomainEvents[] = { { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE, @@ -307,6 +311,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = { remoteDomainBuildEventPMSuspend, sizeof(remote_domain_event_pmsuspend_msg), (xdrproc_t)xdr_remote_domain_event_pmsuspend_msg }, + { REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE, + remoteDomainBuildEventBalloonChange, + sizeof(remote_domain_event_balloon_change_msg), + (xdrproc_t)xdr_remote_domain_event_balloon_change_msg }, }; enum virDrvOpenRemoteFlags { @@ -3889,6 +3897,29 @@ remoteDomainBuildEventPMSuspend(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, remoteDomainEventQueue(priv, event); } + +static void +remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_balloon_change_msg *msg = evdata; + virDomainPtr dom; + virDomainEventPtr event = NULL; + + dom = get_nonnull_domain(conn, msg->dom); + if (!dom) + return; + + event = virDomainEventBalloonChangeNewFromDom(dom, msg->actual); + 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 1da9f3e..8f1d9b5 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2192,6 +2192,11 @@ struct remote_domain_event_pmsuspend_msg { remote_nonnull_domain dom; }; +struct remote_domain_event_balloon_change_msg { + remote_nonnull_domain dom; + unsigned hyper actual; +}; + struct remote_domain_managed_save_args { remote_nonnull_domain dom; unsigned int flags; @@ -2838,7 +2843,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_HAS_METADATA = 272, /* autogen autogen */ REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS = 273, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, /* skipgen skipgen priority:high */ - REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275 /* skipgen skipgen priority:high */ + REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */ + REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276 /* autogen autogen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index b667527..511284c 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1661,6 +1661,10 @@ struct remote_domain_event_pmwakeup_msg { struct remote_domain_event_pmsuspend_msg { remote_nonnull_domain dom; }; +struct remote_domain_event_balloon_change_msg { + remote_nonnull_domain dom; + uint64_t actual; +}; struct remote_domain_managed_save_args { remote_nonnull_domain dom; u_int flags; @@ -2246,4 +2250,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS = 273, REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, + REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, }; -- 1.7.7.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list