[libvirt] [PATCH 1/2] Define public API for receiving guest memory balloon events

Daniel P. Berrange berrange at redhat.com
Wed May 16 14:35:38 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

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
Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 daemon/remote.c                                    |   27 +++++++++++
 examples/domain-events/events-c/event-test.c       |   29 +++++++++++-
 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                            |   34 +++++++++++++
 src/conf/domain_event.h                            |    3 +
 src/libvirt_private.syms                           |    2 +
 src/remote/remote_driver.c                         |   31 ++++++++++++
 src/remote/remote_protocol.x                       |    9 +++-
 11 files changed, 212 insertions(+), 2 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 16a8a05..7826059 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -582,6 +582,32 @@ 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 ballon 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 +622,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..2991acb 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -222,6 +222,25 @@ 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)
+{
+    char *str = NULL;
+    /* HACK: use asprintf since we have gnulib's wrapper for %lld on Win32
+     * but don't have a printf() replacement with %lld */
+    if (asprintf(&str, "%s EVENT: Domain %s(%d) balloon change %lld KB\n",
+                 __func__, virDomainGetName(dom),
+                 virDomainGetID(dom), actual) < 0)
+        return 0;
+
+    printf("%s", str);
+    free(str);
+
+    return 0;
+}
+
 static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                          virDomainPtr dom,
                                          int action,
@@ -391,6 +410,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 +496,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 +511,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 +540,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..bd42c76 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 myDomainEventRTCChangeCallback(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 ac5df95..c1ee67b 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3780,6 +3780,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 kilobytes
+ * @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:
  *
@@ -3803,6 +3819,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 811e16b..badd69d 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 130e702..8ca3a91 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5199,6 +5199,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)
@@ -5268,6 +5315,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 923c58d..2ff2cc1 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -121,6 +121,9 @@ struct _virDomainEvent {
             char *devAlias;
             int reason;
         } trayChange;
+        struct {
+            unsigned long long actual;
+        } balloonChange;
     } data;
 };
 
@@ -1144,6 +1147,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
@@ -1282,6 +1310,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 f7776c7..15745b5 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 f5c2184..b10beb5 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -494,6 +494,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 5c87561..63dcdc0 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 {
@@ -3826,6 +3834,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 2d57247..3e1204c 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;
@@ -2782,7 +2787,9 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_PM_WAKEUP = 267, /* autogen autogen */
     REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE = 268, /* autogen autogen */
     REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP = 269, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270 /* autogen autogen */
+    REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270, /* autogen autogen */
+
+    REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 271 /* autogen autogen */
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
-- 
1.7.7.6




More information about the libvir-list mailing list