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

Guannan Ren gren at redhat.com
Thu Jul 12 15:45:56 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                                    |   28 +++++++++++
 examples/domain-events/events-c/event-test.c       |   43 +++++++++++++----
 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                       |    9 +++-
 11 files changed, 218 insertions(+), 12 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..9072281 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -208,16 +208,29 @@ static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           long long offset,
                                           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) rtc change %lld\n",
-                 __func__, virDomainGetName(dom),
-                 virDomainGetID(dom), offset) < 0)
-        return 0;
-
-    printf("%s", str);
-    free(str);
+#ifdef WIN32
+    printf("%s EVENT: Domain %s(%d) rtc change %I64d\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom), offset);
+#else
+    printf("%s EVENT: Domain %s(%d) rtc change %lld\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom), offset);
+#endif
+
+    return 0;
+}
+
+static int myDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                              virDomainPtr dom,
+                                              unsigned long long actual,
+                                              void *opaque ATTRIBUTE_UNUSED)
+{
+#ifdef WIN32
+    printf("%s EVENT: Domain %s(%d) balloon change %I64d KB\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom), actual);
+#else
+    printf("%s EVENT: Domain %s(%d) balloon change %lld KB\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom), actual);
+#endif
 
     return 0;
 }
@@ -391,6 +404,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 +490,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 +505,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 +534,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..91ea9c5 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,9 @@ 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 ?
-- 
1.7.7.5




More information about the libvir-list mailing list