[libvirt] [PATCH 11/14] Support for JSON mode monitor

Daniel P. Berrange berrange at redhat.com
Thu Nov 26 18:27:29 UTC 2009


Initial support for the new QEMU monitor protocol  using JSON
as the data encoding format instead of plain text

* po/POTFILES.in: Add src/qemu/qemu_monitor_json.c
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Hack to turn on QMP
  mode. Replace with a version number check on >= 0.12 later
* src/qemu/qemu_monitor.c: Delegate to json monitor if enabled
* src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h: Add
  impl of QMP protocol
* src/Makefile.am: Add src/qemu/qemu_monitor_json.{c,h}
---
 po/POTFILES.in               |    1 +
 src/Makefile.am              |    2 +
 src/qemu/qemu_conf.c         |    7 +
 src/qemu/qemu_conf.h         |    3 +
 src/qemu/qemu_driver.c       |   16 +-
 src/qemu/qemu_monitor.c      |  260 +++++++--
 src/qemu/qemu_monitor.h      |    4 +
 src/qemu/qemu_monitor_json.c | 1423 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h |  156 +++++
 tests/qemuxml2argvtest.c     |    2 +-
 10 files changed, 1825 insertions(+), 49 deletions(-)
 create mode 100644 src/qemu/qemu_monitor_json.c
 create mode 100644 src/qemu/qemu_monitor_json.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9864259..f8e9130 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -29,6 +29,7 @@ src/qemu/qemu_bridge_filter.c
 src/qemu/qemu_conf.c
 src/qemu/qemu_driver.c
 src/qemu/qemu_monitor.c
+src/qemu/qemu_monitor_json.c
 src/qemu/qemu_monitor_text.c
 src/remote/remote_driver.c
 src/secret/secret_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index b0775a8..043ca6b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -188,6 +188,8 @@ QEMU_DRIVER_SOURCES =						\
 		qemu/qemu_monitor.c qemu/qemu_monitor.h		\
 		qemu/qemu_monitor_text.c			\
 		qemu/qemu_monitor_text.h			\
+		qemu/qemu_monitor_json.c			\
+		qemu/qemu_monitor_json.h			\
 		qemu/qemu_driver.c qemu/qemu_driver.h        	\
 		qemu/qemu_bridge_filter.c 			\
 		qemu/qemu_bridge_filter.h
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 8f8d490..7d41b5d 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -942,6 +942,9 @@ static unsigned int qemudComputeCmdFlags(const char *help,
     if (version >= 10000)
         flags |= QEMUD_CMD_FLAG_0_10;
 
+    if (version >= 12000)
+        flags |= QEMUD_CMD_FLAG_0_12;
+
     return flags;
 }
 
@@ -1584,6 +1587,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainDefPtr def,
                           virDomainChrDefPtr monitor_chr,
+                          int monitor_json,
                           unsigned int qemuCmdFlags,
                           const char ***retargv,
                           const char ***retenv,
@@ -1858,6 +1862,9 @@ int qemudBuildCommandLine(virConnectPtr conn,
     if (monitor_chr) {
         virBuffer buf = VIR_BUFFER_INITIALIZER;
 
+        if (monitor_json)
+            virBufferAddLit(&buf, "control,");
+
         qemudBuildCommandLineChrDevStr(monitor_chr, &buf);
         if (virBufferError(&buf))
             goto error;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 1bf3e16..248677a 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -74,6 +74,8 @@ enum qemud_cmd_flags {
     QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX = (1 << 21), /* Does qemu support unix domain sockets for migration? */
     QEMUD_CMD_FLAG_CHARDEV       = (1 << 22), /* Is the new -chardev arg available */
     QEMUD_CMD_FLAG_ENABLE_KVM    = (1 << 23), /* Is the -enable-kvm flag available to "enable KVM full virtualization support" */
+    QEMUD_CMD_FLAG_0_12          = (1 << 24),
+    QEMUD_CMD_FLAG_MONITOR_JSON  = QEMUD_CMD_FLAG_0_12, /* JSON mode for monitor */
 };
 
 /* Main driver state */
@@ -168,6 +170,7 @@ int         qemudBuildCommandLine       (virConnectPtr conn,
                                          struct qemud_driver *driver,
                                          virDomainDefPtr def,
                                          virDomainChrDefPtr monitor_chr,
+                                         int monitor_json,
                                          unsigned int qemuCmdFlags,
                                          const char ***retargv,
                                          const char ***retenv,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 468e0ab..e3759bf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -87,6 +87,7 @@ struct _qemuDomainObjPrivate {
 
     qemuMonitorPtr mon;
     virDomainChrDefPtr monConfig;
+    int monJSON;
 
     int nvcpupids;
     int *vcpupids;
@@ -173,6 +174,8 @@ static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
         }
 
         virBufferEscapeString(buf, "  <monitor path='%s'", monitorpath);
+        if (priv->monJSON)
+            virBufferAddLit(buf, " json='1'");
         virBufferVSprintf(buf, " type='%s'/>\n",
                           virDomainChrTypeToString(priv->monConfig->type));
     }
@@ -217,6 +220,9 @@ static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
         priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
     VIR_FREE(tmp);
 
+    if (virXPathBoolean(NULL, "int(./monitor[1]/@json)", ctxt))
+        priv->monJSON = 1;
+
     switch (priv->monConfig->type) {
     case VIR_DOMAIN_CHR_TYPE_PTY:
         priv->monConfig->data.file.path = monitorpath;
@@ -780,6 +786,7 @@ qemuConnectMonitor(virDomainObjPtr vm)
 
     if ((priv->mon = qemuMonitorOpen(vm,
                                      priv->monConfig,
+                                     priv->monJSON,
                                      qemuHandleMonitorEOF)) == NULL) {
         VIR_ERROR(_("Failed to connect monitor for %s\n"), vm->def->name);
         return -1;
@@ -2328,6 +2335,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     if (qemuPrepareMonitorChr(conn, driver, priv->monConfig, vm->def->name) < 0)
         goto cleanup;
 
+#if HAVE_YAJL
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
+        priv->monJSON = 1;
+#endif
+
     if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
         virReportSystemError(conn, ret,
                              _("Cannot remove stale PID file for %s"),
@@ -2343,7 +2355,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
 
     vm->def->id = driver->nextvmid++;
     if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
-                              qemuCmdFlags, &argv, &progenv,
+                              priv->monJSON, qemuCmdFlags, &argv, &progenv,
                               &tapfds, &ntapfds, migrateFrom) < 0)
         goto cleanup;
 
@@ -4418,7 +4430,7 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
         goto cleanup;
 
     if (qemudBuildCommandLine(conn, driver, def,
-                              &monConfig, qemuCmdFlags,
+                              &monConfig, 0, qemuCmdFlags,
                               &retargv, &retenv,
                               NULL, NULL, /* Don't want it to create TAP devices */
                               NULL) < 0) {
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 6c4dfde..502b389 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -30,6 +30,7 @@
 
 #include "qemu_monitor.h"
 #include "qemu_monitor_text.h"
+#include "qemu_monitor_json.h"
 #include "qemu_conf.h"
 #include "event.h"
 #include "virterror_internal.h"
@@ -74,6 +75,7 @@ struct _qemuMonitor {
     /* If the monitor is in process of shutting down */
     unsigned closed: 1;
 
+    unsigned json: 1;
 };
 
 
@@ -283,9 +285,14 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
         msg = mon->msg;
 
     VIR_DEBUG("Process %d", (int)mon->bufferOffset);
-    len = qemuMonitorTextIOProcess(mon,
-                                   mon->buffer, mon->bufferOffset,
-                                   msg);
+    if (mon->json)
+        len = qemuMonitorJSONIOProcess(mon,
+                                       mon->buffer, mon->bufferOffset,
+                                       msg);
+    else
+        len = qemuMonitorTextIOProcess(mon,
+                                       mon->buffer, mon->bufferOffset,
+                                       msg);
 
     if (len < 0) {
         mon->lastErrno = errno;
@@ -534,6 +541,7 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
 qemuMonitorPtr
 qemuMonitorOpen(virDomainObjPtr vm,
                 virDomainChrDefPtr config,
+                int json,
                 qemuMonitorEOFNotify eofCB)
 {
     qemuMonitorPtr mon;
@@ -560,6 +568,7 @@ qemuMonitorOpen(virDomainObjPtr vm,
     mon->refs = 1;
     mon->vm = vm;
     mon->eofCB = eofCB;
+    mon->json = json;
     qemuMonitorLock(mon);
     virDomainObjRef(vm);
 
@@ -699,43 +708,68 @@ int
 qemuMonitorStartCPUs(qemuMonitorPtr mon,
                      virConnectPtr conn)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextStartCPUs(mon, conn);
+    if (mon->json)
+        ret = qemuMonitorJSONStartCPUs(mon, conn);
+    else
+        ret = qemuMonitorTextStartCPUs(mon, conn);
+    return ret;
 }
 
 
 int
 qemuMonitorStopCPUs(qemuMonitorPtr mon)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextStopCPUs(mon);
+    if (mon->json)
+        ret = qemuMonitorJSONStopCPUs(mon);
+    else
+        ret = qemuMonitorTextStopCPUs(mon);
+    return ret;
 }
 
 
 int qemuMonitorSystemPowerdown(qemuMonitorPtr mon)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextSystemPowerdown(mon);
+    if (mon->json)
+        ret = qemuMonitorJSONSystemPowerdown(mon);
+    else
+        ret = qemuMonitorTextSystemPowerdown(mon);
+    return ret;
 }
 
 
 int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
                           int **pids)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextGetCPUInfo(mon, pids);
+    if (mon->json)
+        ret = qemuMonitorJSONGetCPUInfo(mon, pids);
+    else
+        ret = qemuMonitorTextGetCPUInfo(mon, pids);
+    return ret;
 }
 
 int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
                               unsigned long *currmem)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextGetBalloonInfo(mon, currmem);
+    if (mon->json)
+        ret = qemuMonitorJSONGetBalloonInfo(mon, currmem);
+    else
+        ret = qemuMonitorTextGetBalloonInfo(mon, currmem);
+    return ret;
 }
 
 
@@ -747,38 +781,61 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  long long *wr_bytes,
                                  long long *errs)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d dev=%s", mon, mon->fd, devname);
 
-    return qemuMonitorTextGetBlockStatsInfo(mon, devname,
-                                            rd_req, rd_bytes,
-                                            wr_req, wr_bytes,
-                                            errs);
+    if (mon->json)
+        ret = qemuMonitorJSONGetBlockStatsInfo(mon, devname,
+                                               rd_req, rd_bytes,
+                                               wr_req, wr_bytes,
+                                               errs);
+    else
+        ret = qemuMonitorTextGetBlockStatsInfo(mon, devname,
+                                               rd_req, rd_bytes,
+                                               wr_req, wr_bytes,
+                                               errs);
+    return ret;
 }
 
 
 int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
                               const char *password)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextSetVNCPassword(mon, password);
+    if (mon->json)
+        ret = qemuMonitorJSONSetVNCPassword(mon, password);
+    else
+        ret = qemuMonitorTextSetVNCPassword(mon, password);
+    return ret;
 }
 
 
 int qemuMonitorSetBalloon(qemuMonitorPtr mon,
                           unsigned long newmem)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d newmem=%lu", mon, mon->fd, newmem);
 
-    return qemuMonitorTextSetBalloon(mon, newmem);
+    if (mon->json)
+        ret = qemuMonitorJSONSetBalloon(mon, newmem);
+    else
+        ret = qemuMonitorTextSetBalloon(mon, newmem);
+    return ret;
 }
 
 int qemuMonitorEjectMedia(qemuMonitorPtr mon,
                           const char *devname)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d devname=%s", mon, mon->fd, devname);
 
-    return qemuMonitorTextEjectMedia(mon, devname);
+    if (mon->json)
+        ret = qemuMonitorJSONEjectMedia(mon, devname);
+    else
+        ret = qemuMonitorTextEjectMedia(mon, devname);
+    return ret;
 }
 
 
@@ -787,10 +844,15 @@ int qemuMonitorChangeMedia(qemuMonitorPtr mon,
                            const char *newmedia,
                            const char *format)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d devname=%s newmedia=%s format=%s",
           mon, mon->fd, devname, newmedia, format);
 
-    return qemuMonitorTextChangeMedia(mon, devname, newmedia, format);
+    if (mon->json)
+        ret = qemuMonitorJSONChangeMedia(mon, devname, newmedia, format);
+    else
+        ret = qemuMonitorTextChangeMedia(mon, devname, newmedia, format);
+    return ret;
 }
 
 
@@ -799,10 +861,15 @@ int qemuMonitorSaveVirtualMemory(qemuMonitorPtr mon,
                                  size_t length,
                                  const char *path)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d offset=%llu length=%zu path=%s",
           mon, mon->fd, offset, length, path);
 
-    return qemuMonitorTextSaveVirtualMemory(mon, offset, length, path);
+    if (mon->json)
+        ret = qemuMonitorJSONSaveVirtualMemory(mon, offset, length, path);
+    else
+        ret = qemuMonitorTextSaveVirtualMemory(mon, offset, length, path);
+    return ret;
 }
 
 int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
@@ -810,19 +877,29 @@ int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
                                   size_t length,
                                   const char *path)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d offset=%llu length=%zu path=%s",
           mon, mon->fd, offset, length, path);
 
-    return qemuMonitorTextSavePhysicalMemory(mon, offset, length, path);
+    if (mon->json)
+        ret = qemuMonitorJSONSavePhysicalMemory(mon, offset, length, path);
+    else
+        ret = qemuMonitorTextSavePhysicalMemory(mon, offset, length, path);
+    return ret;
 }
 
 
 int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
                                  unsigned long bandwidth)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d bandwidth=%lu", mon, mon->fd, bandwidth);
 
-    return qemuMonitorTextSetMigrationSpeed(mon, bandwidth);
+    if (mon->json)
+        ret = qemuMonitorJSONSetMigrationSpeed(mon, bandwidth);
+    else
+        ret = qemuMonitorTextSetMigrationSpeed(mon, bandwidth);
+    return ret;
 }
 
 int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
@@ -831,12 +908,20 @@ int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
                                   unsigned long long *remaining,
                                   unsigned long long *total)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextGetMigrationStatus(mon, status,
-                                             transferred,
-                                             remaining,
-                                             total);
+    if (mon->json)
+        ret = qemuMonitorJSONGetMigrationStatus(mon, status,
+                                                transferred,
+                                                remaining,
+                                                total);
+    else
+        ret = qemuMonitorTextGetMigrationStatus(mon, status,
+                                                transferred,
+                                                remaining,
+                                                total);
+    return ret;
 }
 
 
@@ -845,10 +930,15 @@ int qemuMonitorMigrateToHost(qemuMonitorPtr mon,
                              const char *hostname,
                              int port)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d hostname=%s port=%d",
           mon, mon->fd, hostname, port);
 
-    return qemuMonitorTextMigrateToHost(mon, background, hostname, port);
+    if (mon->json)
+        ret = qemuMonitorJSONMigrateToHost(mon, background, hostname, port);
+    else
+        ret = qemuMonitorTextMigrateToHost(mon, background, hostname, port);
+    return ret;
 }
 
 
@@ -857,35 +947,55 @@ int qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
                                 const char * const *argv,
                                 const char *target)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d argv=%p target=%s",
           mon, mon->fd, argv, target);
 
-    return qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+    if (mon->json)
+        ret = qemuMonitorJSONMigrateToCommand(mon, background, argv, target);
+    else
+        ret = qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+    return ret;
 }
 
 int qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
                              int background,
                              const char *unixfile)
 {
+    int ret;
     DEBUG("mon=%p fd=%d unixfile=%s",
           mon, mon->fd, unixfile);
 
-    return qemuMonitorTextMigrateToUnix(mon, background, unixfile);
+    if (mon->json)
+        ret = qemuMonitorJSONMigrateToUnix(mon, background, unixfile);
+    else
+        ret = qemuMonitorTextMigrateToUnix(mon, background, unixfile);
+    return ret;
 }
 
 int qemuMonitorMigrateCancel(qemuMonitorPtr mon)
 {
+    int ret;
     DEBUG("mon=%p fd=%d", mon, mon->fd);
 
-    return qemuMonitorTextMigrateCancel(mon);
+    if (mon->json)
+        ret = qemuMonitorJSONMigrateCancel(mon);
+    else
+        ret = qemuMonitorTextMigrateCancel(mon);
+    return ret;
 }
 
 int qemuMonitorAddUSBDisk(qemuMonitorPtr mon,
                           const char *path)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d path=%s", mon, mon->fd, path);
 
-    return qemuMonitorTextAddUSBDisk(mon, path);
+    if (mon->json)
+        ret = qemuMonitorJSONAddUSBDisk(mon, path);
+    else
+        ret = qemuMonitorTextAddUSBDisk(mon, path);
+    return ret;
 }
 
 
@@ -893,19 +1003,29 @@ int qemuMonitorAddUSBDeviceExact(qemuMonitorPtr mon,
                                  int bus,
                                  int dev)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d bus=%d dev=%d", mon, mon->fd, bus, dev);
 
-    return qemuMonitorTextAddUSBDeviceExact(mon, bus, dev);
+    if (mon->json)
+        ret = qemuMonitorJSONAddUSBDeviceExact(mon, bus, dev);
+    else
+        ret = qemuMonitorTextAddUSBDeviceExact(mon, bus, dev);
+    return ret;
 }
 
 int qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon,
                                  int vendor,
                                  int product)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d vendor=%d product=%d",
           mon, mon->fd, vendor, product);
 
-    return qemuMonitorTextAddUSBDeviceMatch(mon, vendor, product);
+    if (mon->json)
+        ret = qemuMonitorJSONAddUSBDeviceMatch(mon, vendor, product);
+    else
+        ret = qemuMonitorTextAddUSBDeviceMatch(mon, vendor, product);
+    return ret;
 }
 
 
@@ -918,16 +1038,26 @@ int qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon,
                                 unsigned *guestBus,
                                 unsigned *guestSlot)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d domain=%d bus=%d slot=%d function=%d",
           mon, mon->fd,
           hostDomain, hostBus, hostSlot, hostFunction);
 
-    return qemuMonitorTextAddPCIHostDevice(mon, hostDomain,
-                                           hostBus, hostSlot,
-                                           hostFunction,
-                                           guestDomain,
-                                           guestBus,
-                                           guestSlot);
+    if (mon->json)
+        ret = qemuMonitorJSONAddPCIHostDevice(mon, hostDomain,
+                                              hostBus, hostSlot,
+                                              hostFunction,
+                                              guestDomain,
+                                              guestBus,
+                                              guestSlot);
+    else
+        ret = qemuMonitorTextAddPCIHostDevice(mon, hostDomain,
+                                              hostBus, hostSlot,
+                                              hostFunction,
+                                              guestDomain,
+                                              guestBus,
+                                              guestSlot);
+    return ret;
 }
 
 
@@ -938,11 +1068,17 @@ int qemuMonitorAddPCIDisk(qemuMonitorPtr mon,
                           unsigned *guestBus,
                           unsigned *guestSlot)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d path=%s bus=%s",
           mon, mon->fd, path, bus);
 
-    return qemuMonitorTextAddPCIDisk(mon, path, bus,
-                                     guestDomain, guestBus, guestSlot);
+    if (mon->json)
+        ret = qemuMonitorJSONAddPCIDisk(mon, path, bus,
+                                        guestDomain, guestBus, guestSlot);
+    else
+        ret = qemuMonitorTextAddPCIDisk(mon, path, bus,
+                                        guestDomain, guestBus, guestSlot);
+    return ret;
 }
 
 
@@ -952,10 +1088,16 @@ int qemuMonitorAddPCINetwork(qemuMonitorPtr mon,
                              unsigned *guestBus,
                              unsigned *guestSlot)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d nicstr=%s", mon, mon->fd, nicstr);
 
-    return qemuMonitorTextAddPCINetwork(mon, nicstr, guestDomain,
-                                        guestBus, guestSlot);
+    if (mon->json)
+        ret = qemuMonitorJSONAddPCINetwork(mon, nicstr, guestDomain,
+                                           guestBus, guestSlot);
+    else
+        ret = qemuMonitorTextAddPCINetwork(mon, nicstr, guestDomain,
+                                           guestBus, guestSlot);
+    return ret;
 }
 
 
@@ -964,11 +1106,17 @@ int qemuMonitorRemovePCIDevice(qemuMonitorPtr mon,
                                unsigned guestBus,
                                unsigned guestSlot)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d domain=%d bus=%d slot=%d",
           mon, mon->fd, guestDomain, guestBus, guestSlot);
 
-    return qemuMonitorTextRemovePCIDevice(mon, guestDomain,
-                                          guestBus, guestSlot);
+    if (mon->json)
+        ret = qemuMonitorJSONRemovePCIDevice(mon, guestDomain,
+                                             guestBus, guestSlot);
+    else
+        ret = qemuMonitorTextRemovePCIDevice(mon, guestDomain,
+                                             guestBus, guestSlot);
+    return ret;
 }
 
 
@@ -976,30 +1124,45 @@ int qemuMonitorSendFileHandle(qemuMonitorPtr mon,
                               const char *fdname,
                               int fd)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d fdname=%s fd=%d",
           mon, mon->fd, fdname, fd);
 
-    return qemuMonitorTextSendFileHandle(mon, fdname, fd);
+    if (mon->json)
+        ret = qemuMonitorJSONSendFileHandle(mon, fdname, fd);
+    else
+        ret = qemuMonitorTextSendFileHandle(mon, fdname, fd);
+    return ret;
 }
 
 
 int qemuMonitorCloseFileHandle(qemuMonitorPtr mon,
                                const char *fdname)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d fdname=%s",
           mon, mon->fd, fdname);
 
-    return qemuMonitorTextCloseFileHandle(mon, fdname);
+    if (mon->json)
+        ret = qemuMonitorJSONCloseFileHandle(mon, fdname);
+    else
+        ret = qemuMonitorTextCloseFileHandle(mon, fdname);
+    return ret;
 }
 
 
 int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
                               const char *netstr)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d netstr=%s",
           mon, mon->fd, netstr);
 
-    return qemuMonitorTextAddHostNetwork(mon, netstr);
+    if (mon->json)
+        ret = qemuMonitorJSONAddHostNetwork(mon, netstr);
+    else
+        ret = qemuMonitorTextAddHostNetwork(mon, netstr);
+    return ret;
 }
 
 
@@ -1007,8 +1170,13 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
                                  int vlan,
                                  const char *netname)
 {
+    int ret;
     DEBUG("mon=%p, fd=%d netname=%s",
           mon, mon->fd, netname);
 
-    return qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
+    if (mon->json)
+        ret = qemuMonitorJSONRemoveHostNetwork(mon, vlan, netname);
+    else
+        ret = qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
+    return ret;
 }
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 5f1a65d..0d9e315 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -80,6 +80,7 @@ char *qemuMonitorEscapeShell(const char *in);
 
 qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
                                virDomainChrDefPtr config,
+                               int json,
                                qemuMonitorEOFNotify eofCB);
 
 int qemuMonitorClose(qemuMonitorPtr mon);
@@ -132,6 +133,9 @@ int qemuMonitorSetBalloon(qemuMonitorPtr mon,
 /* XXX should we pass the virDomainDiskDefPtr instead
  * and hide devname details inside monitor. Reconsider
  * this when doing the QMP implementation
+ *
+ * XXXX 'eject' has gained a 'force' flag we might like
+ * to make use of...
  */
 int qemuMonitorEjectMedia(qemuMonitorPtr mon,
                           const char *devname);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
new file mode 100644
index 0000000..9d71826
--- /dev/null
+++ b/src/qemu/qemu_monitor_json.c
@@ -0,0 +1,1423 @@
+/*
+ * qemu_monitor_json.c: interaction with QEMU monitor console
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "qemu_monitor_json.h"
+#include "qemu_conf.h"
+#include "memory.h"
+#include "logging.h"
+#include "driver.h"
+#include "datatypes.h"
+#include "virterror_internal.h"
+#include "json.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+
+#define LINE_ENDING "\r\n"
+
+static int
+qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+                             const char *line,
+                             qemuMonitorMessagePtr msg)
+{
+    virJSONValuePtr obj = NULL;
+    int ret = -1;
+
+    VIR_DEBUG("Line [%s]", line);
+
+    if (!(obj = virJSONValueFromString(line))) {
+        VIR_DEBUG0("Parsing JSON string failed");
+        errno = EINVAL;
+        goto cleanup;
+    }
+
+    if (obj->type != VIR_JSON_TYPE_OBJECT) {
+        VIR_DEBUG0("Parsed JSON string isn't an object");
+        errno = EINVAL;
+    }
+
+    if (virJSONValueObjectHasKey(obj, "QMP") == 1) {
+        VIR_DEBUG0("Got QMP capabilities data");
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (virJSONValueObjectHasKey(obj, "event") == 1) {
+        VIR_DEBUG0("Got an event");
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (msg) {
+        msg->rxBuffer = strdup(line);
+        msg->rxLength = strlen(line);
+        msg->finished = 1;
+    } else {
+        VIR_DEBUG("Ignoring unexpected JSON message [%s]", line);
+    }
+
+    ret = 0;
+
+cleanup:
+    virJSONValueFree(obj);
+    return ret;
+}
+
+int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
+                             const char *data,
+                             size_t len,
+                             qemuMonitorMessagePtr msg)
+{
+    int used = 0;
+    /*VIR_DEBUG("Data %d bytes [%s]", len, data);*/
+
+    while (used < len) {
+        char *nl = strstr(data + used, LINE_ENDING);
+
+        if (nl) {
+            int got = nl - (data + used);
+            char *line = strndup(data + used, got);
+            used += got + strlen(LINE_ENDING);
+            line[got] = '\0'; /* kill \n */
+            if (qemuMonitorJSONIOProcessLine(mon, line, msg) < 0) {
+                VIR_FREE(line);
+                return -1;
+            }
+
+            VIR_FREE(line);
+        } else {
+            break;
+        }
+    }
+
+    VIR_DEBUG("Total used %d bytes out of %d available in buffer", used, len);
+    return used;
+}
+
+static int
+qemuMonitorJSONCommandWithFd(qemuMonitorPtr mon,
+                             virJSONValuePtr cmd,
+                             int scm_fd,
+                             virJSONValuePtr *reply)
+{
+    int ret = -1;
+    qemuMonitorMessage msg;
+    char *cmdstr = NULL;
+
+    *reply = NULL;
+
+    memset(&msg, 0, sizeof msg);
+
+    if (!(cmdstr = virJSONValueToString(cmd))) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+    if (virAsprintf(&msg.txBuffer, "%s\r\n", cmdstr) < 0) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+    msg.txLength = strlen(msg.txBuffer);
+    msg.txFD = scm_fd;
+
+    VIR_DEBUG("Send command '%s' for write with FD %d", cmdstr, scm_fd);
+
+    ret = qemuMonitorSend(mon, &msg);
+
+    VIR_DEBUG("Receive command reply ret=%d errno=%d %d bytes '%s'",
+              ret, msg.lastErrno, msg.rxLength, msg.rxBuffer);
+
+
+    /* If we got ret==0, but not reply data something rather bad
+     * went wrong, so lets fake an EIO error */
+    if (!msg.rxBuffer && ret == 0) {
+        msg.lastErrno = EIO;
+        ret = -1;
+    }
+
+    if (ret == 0) {
+        if (!((*reply) = virJSONValueFromString(msg.rxBuffer))) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot parse JSON doc '%s'"), msg.rxBuffer);
+            goto cleanup;
+        }
+    }
+
+    if (ret < 0)
+        virReportSystemError(NULL, msg.lastErrno,
+                             _("cannot send monitor command '%s'"), cmdstr);
+
+cleanup:
+    VIR_FREE(cmdstr);
+    VIR_FREE(msg.txBuffer);
+    VIR_FREE(msg.rxBuffer);
+
+    return ret;
+}
+
+
+static int
+qemuMonitorJSONCommand(qemuMonitorPtr mon,
+                       virJSONValuePtr cmd,
+                       virJSONValuePtr *reply) {
+    return qemuMonitorJSONCommandWithFd(mon, cmd, -1, reply);
+}
+
+/* Ignoring OOM in this method, since we're already reporting
+ * a more important error
+ *
+ * XXX see qerror.h for different klasses & fill out useful params
+ */
+static char *qemuMonitorJSONStringifyError(virJSONValuePtr error)
+{
+    char *klass = virJSONValueObjectGetString(error, "class");
+
+    if (klass) {
+        return strdup(klass);
+    } else {
+        return strdup(_("Missing QEMU error klass"));
+    }
+}
+
+static int
+qemuMonitorJSONCheckError(virJSONValuePtr cmd,
+                          virJSONValuePtr reply)
+{
+    if (virJSONValueObjectHasKey(reply, "error")) {
+        virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
+        char *cmdstr = virJSONValueToString(cmd);
+        char *replystr = virJSONValueToString(reply);
+
+        if (!error) {
+            VIR_DEBUG("Saw a JSON error, but value is null for %s: %s",
+                      cmdstr, replystr);
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("error running QEMU command '%s': '%s'"),
+                             cmdstr, replystr);
+        } else {
+            VIR_DEBUG("Got a JSON error set for %s", cmdstr);
+            char *detail = qemuMonitorJSONStringifyError(error);
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("error running QEMU command '%s': %s ('%s')"),
+                             cmdstr, detail, replystr);
+            VIR_FREE(detail);
+        }
+        VIR_FREE(cmdstr);
+        VIR_FREE(replystr);
+        return -1;
+    } else if (!virJSONValueObjectHasKey(reply, "return")) {
+        char *cmdstr = virJSONValueToString(cmd);
+        char *replystr = virJSONValueToString(reply);
+
+        VIR_DEBUG("Neither 'return' nor 'error' is set in the JSON reply %s: %s",
+                  cmdstr, replystr);
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("error running QEMU command '%s': '%s'"), cmdstr, replystr);
+        VIR_FREE(cmdstr);
+        VIR_FREE(replystr);
+        return -1;
+    }
+    return 0;
+}
+
+
+static int
+qemuMonitorJSONHasError(virJSONValuePtr reply,
+                        const char *klass)
+{
+    virJSONValuePtr error;
+    char *thisklass;
+
+    if (!virJSONValueObjectHasKey(reply, "error"))
+        return 0;
+
+    error = virJSONValueObjectGet(reply, "error");
+    if (!error)
+        return 0;
+
+    if (!virJSONValueObjectHasKey(error, "class"))
+        return 0;
+
+    thisklass = virJSONValueObjectGetString(error, "class");
+
+    if (!thisklass)
+        return 0;
+
+    return STREQ(klass, thisklass);
+}
+
+static int
+qemuMonitorJSONCommandAddTimestamp(virJSONValuePtr obj)
+{
+    struct timeval tv;
+    virJSONValuePtr timestamp = NULL;
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        virReportSystemError(NULL, errno, "%s",
+                             _("cannot query time of day"));
+        return -1;
+    }
+
+    if (!(timestamp = virJSONValueNewObject()))
+        goto no_memory;
+
+    if (virJSONValueObjectAppendNumberLong(timestamp, "seconds", tv.tv_sec) < 0)
+        goto no_memory;
+    if (virJSONValueObjectAppendNumberLong(timestamp, "microseconds", tv.tv_usec) < 0)
+        goto no_memory;
+
+    if (virJSONValueObjectAppend(obj, "timestamp", timestamp) < 0)
+        goto no_memory;
+
+    return 0;
+
+no_memory:
+    virReportOOMError(NULL);
+    virJSONValueFree(timestamp);
+    return -1;
+}
+
+static virJSONValuePtr
+qemuMonitorJSONMakeCommand(const char *cmdname,
+                           ...)
+{
+    virJSONValuePtr obj;
+    virJSONValuePtr jargs = NULL;
+    va_list args;
+    char *key;
+
+    va_start(args, cmdname);
+
+    if (!(obj = virJSONValueNewObject()))
+        goto no_memory;
+
+    if (virJSONValueObjectAppendString(obj, "execute", cmdname) < 0)
+        goto no_memory;
+
+    if (qemuMonitorJSONCommandAddTimestamp(obj) < 0)
+        goto error;
+
+    while ((key = va_arg(args, char *)) != NULL) {
+        int ret;
+        char type;
+
+        if (strlen(key) < 3) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("argument key '%s' is too short, missing type prefix"),
+                             key);
+            goto error;
+        }
+
+        /* Keys look like   s:name  the first letter is a type code */
+        type = key[0];
+        key += 2;
+
+        if (!jargs &&
+            !(jargs = virJSONValueNewObject()))
+            goto no_memory;
+
+        /* This doesn't supports maps/arrays.  This hasn't
+         * proved to be a problem..... yet :-)  */
+        switch (type) {
+        case 's': {
+            char *val = va_arg(args, char *);
+            ret = virJSONValueObjectAppendString(jargs, key, val);
+        }   break;
+        case 'i': {
+            int val = va_arg(args, int);
+            ret = virJSONValueObjectAppendNumberInt(jargs, key, val);
+        }   break;
+        case 'u': {
+            unsigned int val = va_arg(args, unsigned int);
+            ret = virJSONValueObjectAppendNumberUint(jargs, key, val);
+        }   break;
+        case 'I': {
+            long long val = va_arg(args, long long);
+            ret = virJSONValueObjectAppendNumberLong(jargs, key, val);
+        }   break;
+        case 'U': {
+            unsigned long long val = va_arg(args, unsigned long long);
+            ret = virJSONValueObjectAppendNumberUlong(jargs, key, val);
+        }   break;
+        case 'd': {
+            double val = va_arg(args, double);
+            ret = virJSONValueObjectAppendNumberDouble(jargs, key, val);
+        }   break;
+        case 'b': {
+            int val = va_arg(args, int);
+            ret = virJSONValueObjectAppendBoolean(jargs, key, val);
+        }   break;
+        case 'n': {
+            ret = virJSONValueObjectAppendNull(jargs, key);
+        }   break;
+        default:
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("unsupported data type '%c' for arg '%s'"), type, key - 2);
+            goto error;
+        }
+        if (ret < 0)
+            goto no_memory;
+    }
+
+    if (jargs &&
+        virJSONValueObjectAppend(obj, "arguments", jargs) < 0)
+        goto no_memory;
+
+    va_end(args);
+
+    return obj;
+
+no_memory:
+    virReportOOMError(NULL);
+error:
+    virJSONValueFree(obj);
+    virJSONValueFree(jargs);
+    va_end(args);
+    return NULL;
+}
+
+
+int
+qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
+                         virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("cont", NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int
+qemuMonitorJSONStopCPUs(qemuMonitorPtr mon)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("stop", NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_powerdown", NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
+                              int **pids)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+                                                     "s:item", "cpus",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    *pids = NULL;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    /* XXX extract PIDs if present - QEMU hasn't implement this yet :-( */
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+/*
+ * Returns: 0 if balloon not supported, +1 if balloon query worked
+ * or -1 on failure
+ */
+int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
+                                  unsigned long *currmem)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+                                                     "s:item", "balloon",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    *currmem = 0;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        /* See if balloon soft-failed */
+        if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+            qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+            goto cleanup;
+
+        /* See if any other fatal error occurred */
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+        /* Success */
+        if (ret == 0) {
+            unsigned long long mem;
+
+            if (virJSONValueObjectGetNumberUlong(reply, "return", &mem) < 0) {
+                qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("info balloon reply was missing mem return data"));
+                ret = -1;
+                goto cleanup;
+            }
+
+            *currmem = mem;
+            ret = 1;
+        }
+    }
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
+                                     const char *devname,
+                                     long long *rd_req,
+                                     long long *rd_bytes,
+                                     long long *wr_req,
+                                     long long *wr_bytes,
+                                     long long *errs)
+{
+    int ret;
+    int i;
+    int found = 0;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+                                                     "s:item", "blockstats",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr devices;
+
+    *rd_req = *rd_bytes = *wr_req = *wr_bytes = *errs = 0;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+        if (ret < 0)
+            goto cleanup;
+    }
+    ret = -1;
+
+    devices = virJSONValueObjectGet(reply, "return");
+    if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("blockstats reply was missing device list"));
+        goto cleanup;
+    }
+
+    for (i = 0 ; i < virJSONValueArraySize(devices) ; i++) {
+        virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+        virJSONValuePtr stats;
+        const char *thisdev;
+        if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("blockstats device entry was not in expected format"));
+            goto cleanup;
+        }
+
+        if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("blockstats device entry was not in expected format"));
+            goto cleanup;
+        }
+
+        if (STRNEQ(thisdev, devname))
+            continue;
+
+        found = 1;
+        if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
+            stats->type != VIR_JSON_TYPE_OBJECT) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("blockstats stats entry was not in expected format"));
+            goto cleanup;
+        }
+
+        if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", rd_bytes) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot read %s statistic"),
+                             "rd_bytes");
+            goto cleanup;
+        }
+        if (virJSONValueObjectGetNumberLong(stats, "rd_operations", rd_req) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot read %s statistic"),
+                             "rd_operations");
+            goto cleanup;
+        }
+        if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", wr_bytes) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot read %s statistic"),
+                             "wr_bytes");
+            goto cleanup;
+        }
+        if (virJSONValueObjectGetNumberLong(stats, "wr_operations", wr_req) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot read %s statistic"),
+                             "wr_operations");
+            goto cleanup;
+        }
+    }
+
+    if (!found) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("cannot find statistics for device '%s'"), devname);
+        goto cleanup;
+    }
+    ret = 0;
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
+                                  const char *password)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("change",
+                                                     "s:device", "vnc",
+                                                     "s:target", "password",
+                                                     "s:arg", password,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+/*
+ * Returns: 0 if balloon not supported, +1 if balloon adjust worked
+ * or -1 on failure
+ */
+int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
+                              unsigned long newmem)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon",
+                                                     "U:value", (unsigned long long)newmem,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        /* See if balloon soft-failed */
+        if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+            qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+            goto cleanup;
+
+        /* See if any other fatal error occurred */
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+        /* Real success */
+        if (ret == 0)
+            ret = 1;
+    }
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
+                              const char *devname)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("eject",
+                                                     "s:device", devname,
+                                                     "i:force", 0,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon,
+                               const char *devname,
+                               const char *newmedia,
+                               const char *format)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    if (format)
+        cmd = qemuMonitorJSONMakeCommand("change",
+                                         "s:device", devname,
+                                         "s:target", newmedia,
+                                         "s:arg", format,
+                                         NULL);
+    else
+        cmd = qemuMonitorJSONMakeCommand("change",
+                                         "s:device", devname,
+                                         "s:target", newmedia,
+                                         NULL);
+
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+static int qemuMonitorJSONSaveMemory(qemuMonitorPtr mon,
+                                     const char *cmdtype,
+                                     unsigned long long offset,
+                                     size_t length,
+                                     const char *path)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand(cmdtype,
+                                                     "U:val", offset,
+                                                     "u:size", length,
+                                                     "s:filename", path,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONSaveVirtualMemory(qemuMonitorPtr mon,
+                                     unsigned long long offset,
+                                     size_t length,
+                                     const char *path)
+{
+    return qemuMonitorJSONSaveMemory(mon, "memsave", offset, length, path);
+}
+
+int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon,
+                                      unsigned long long offset,
+                                      size_t length,
+                                      const char *path)
+{
+    return qemuMonitorJSONSaveMemory(mon, "pmemsave", offset, length, path);
+}
+
+
+int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon,
+                                     unsigned long bandwidth)
+{
+    int ret;
+    char *bandwidthstr;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    if (virAsprintf(&bandwidthstr, "%lum", bandwidth) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+    cmd = qemuMonitorJSONMakeCommand("migrate_set_speed",
+                                     "s:value", bandwidthstr,
+                                     NULL);
+    VIR_FREE(bandwidthstr);
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+static int
+qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply,
+                                       int *status,
+                                       unsigned long long *transferred,
+                                       unsigned long long *remaining,
+                                       unsigned long long *total)
+{
+    virJSONValuePtr ret;
+    char *statusstr;
+
+    if (!(ret = virJSONValueObjectGet(reply, "return"))) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("info migration reply was missing return data"));
+        return -1;
+    }
+
+    if (!(statusstr = virJSONValueObjectGetString(ret, "status"))) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("info migration reply was missing return status"));
+        return -1;
+    }
+
+    if ((*status = qemuMonitorMigrationStatusTypeFromString(statusstr)) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("unexpected migration status in %s"), statusstr);
+        return -1;
+    }
+
+    if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) {
+        virJSONValuePtr ram = virJSONValueObjectGet(ret, "ram");
+        if (!ram) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("migration was active, but no RAM info was set"));
+            return -1;
+        }
+
+        if (virJSONValueObjectGetNumberUlong(ram, "transferred", transferred) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("migration was active, but RAM 'transferred' data was missing"));
+            return -1;
+        }
+        if (virJSONValueObjectGetNumberUlong(ram, "remaining", remaining) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("migration was active, but RAM 'remaining' data was missing"));
+            return -1;
+        }
+        if (virJSONValueObjectGetNumberUlong(ram, "total", total) < 0) {
+            qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("migration was active, but RAM 'total' data was missing"));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
+                                      int *status,
+                                      unsigned long long *transferred,
+                                      unsigned long long *remaining,
+                                      unsigned long long *total)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("info",
+                                                     "s:item", "migration",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    *status = 0;
+    *transferred = *remaining = *total = 0;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    if (ret == 0 &&
+        qemuMonitorJSONGetMigrationStatusReply(reply,
+                                               status,
+                                               transferred,
+                                               remaining,
+                                               total) < 0)
+        ret = -1;
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+static int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
+                                  int background,
+                                  const char *uri)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("migrate",
+                                                     "i:detach", background ? 1 : 0,
+                                                     "s:uri", uri,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONMigrateToHost(qemuMonitorPtr mon,
+                                 int background,
+                                 const char *hostname,
+                                 int port)
+{
+    char *uri = NULL;
+    int ret;
+
+    if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    ret = qemuMonitorJSONMigrate(mon, background, uri);
+
+    VIR_FREE(uri);
+
+    return ret;
+}
+
+
+int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
+                                    int background,
+                                    const char * const *argv,
+                                    const char *target)
+{
+    char *argstr;
+    char *dest = NULL;
+    int ret = -1;
+    char *safe_target = NULL;
+
+    argstr = virArgvToString(argv);
+    if (!argstr) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    /* Migrate to file */
+    safe_target = qemuMonitorEscapeShell(target);
+    if (!safe_target) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    ret = qemuMonitorJSONMigrate(mon, background, dest);
+
+cleanup:
+    VIR_FREE(safe_target);
+    VIR_FREE(argstr);
+    VIR_FREE(dest);
+    return ret;
+}
+
+int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon,
+                                 int background,
+                                 const char *unixfile)
+{
+    char *dest = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&dest, "unix:%s", unixfile) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    ret = qemuMonitorJSONMigrate(mon, background, dest);
+
+    VIR_FREE(dest);
+
+    return ret;
+}
+
+
+int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("migrate_cancel", NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+static int qemuMonitorJSONAddUSB(qemuMonitorPtr mon,
+                                 const char *dev)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("usb_add",
+                                                     "s:devname", dev,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDisk(qemuMonitorPtr mon,
+                              const char *path)
+{
+    int ret;
+    char *disk;
+
+    if (virAsprintf(&disk, "disk:%s", path) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    ret = qemuMonitorJSONAddUSB(mon, disk);
+
+    VIR_FREE(disk);
+
+    return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDeviceExact(qemuMonitorPtr mon,
+                                     int bus ATTRIBUTE_UNUSED,
+                                     int dev ATTRIBUTE_UNUSED)
+{
+    int ret;
+    char *addr;
+
+    if (virAsprintf(&addr, "host:%.3d.%.3d", bus, dev) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    ret = qemuMonitorJSONAddUSB(mon, addr);
+
+    VIR_FREE(addr);
+    return ret;
+}
+
+
+int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon,
+                                     int vendor ATTRIBUTE_UNUSED,
+                                     int product ATTRIBUTE_UNUSED)
+{
+    int ret;
+    char *addr;
+
+    if (virAsprintf(&addr, "host:%.4x:%.4x", vendor, product) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    ret = qemuMonitorJSONAddUSB(mon, addr);
+
+    VIR_FREE(addr);
+    return ret;
+}
+
+
+/* XXX qemu also returns a 'function' number now */
+static int
+qemuMonitorJSONGetGuestAddress(virJSONValuePtr reply,
+                               unsigned *guestDomain,
+                               unsigned *guestBus,
+                               unsigned *guestSlot)
+{
+    virJSONValuePtr addr;
+
+    addr = virJSONValueObjectGet(reply, "return");
+    if (!addr || addr->type != VIR_JSON_TYPE_OBJECT) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("pci_add reply was missing device address"));
+        return -1;
+    }
+
+    if (virJSONValueObjectGetNumberUint(addr, "domain", guestDomain) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("pci_add reply was missing device domain number"));
+        return -1;
+    }
+
+    if (virJSONValueObjectGetNumberUint(addr, "bus", guestBus) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("pci_add reply was missing device bus number"));
+        return -1;
+    }
+
+    if (virJSONValueObjectGetNumberUint(addr, "slot", guestSlot) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("pci_add reply was missing device slot number"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon,
+                                    unsigned hostDomain ATTRIBUTE_UNUSED,
+                                    unsigned hostBus,
+                                    unsigned hostSlot,
+                                    unsigned hostFunction,
+                                    unsigned *guestDomain,
+                                    unsigned *guestBus,
+                                    unsigned *guestSlot)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    char *dev;
+
+    *guestDomain = *guestBus = *guestSlot = 0;
+
+    /* XXX hostDomain */
+    if (virAsprintf(&dev, "host=%.2x:%.2x.%.1x",
+                    hostBus, hostSlot, hostFunction) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    cmd = qemuMonitorJSONMakeCommand("pci_add",
+                                     "s:pci_addr", "auto"
+                                     "s:type", "host",
+                                     "s:opts", dev,
+                                     NULL);
+    VIR_FREE(dev);
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    if (ret == 0 &&
+        qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+        ret = -1;
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon,
+                              const char *path,
+                              const char *bus,
+                              unsigned *guestDomain,
+                              unsigned *guestBus,
+                              unsigned *guestSlot) {
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    char *dev;
+
+    *guestDomain = *guestBus = *guestSlot = 0;
+
+    if (virAsprintf(&dev, "file=%s,if=%s", path, bus) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    cmd = qemuMonitorJSONMakeCommand("pci_add",
+                                     "s:pci_addr", "auto",
+                                     "s:type", "storage",
+                                     "s:opts", dev,
+                                     NULL);
+    VIR_FREE(dev);
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    if (ret == 0 &&
+        qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+        ret = -1;
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon,
+                                 const char *nicstr,
+                                 unsigned *guestDomain,
+                                 unsigned *guestBus,
+                                 unsigned *guestSlot)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("pci_add",
+                                                     "s:pci_addr", "auto",
+                                                     "s:type", "nic",
+                                                     "s:opts", nicstr,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    *guestDomain = *guestBus = *guestSlot = 0;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    if (ret == 0 &&
+        qemuMonitorJSONGetGuestAddress(reply, guestDomain, guestBus, guestSlot) < 0)
+        ret = -1;
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon,
+                                   unsigned guestDomain,
+                                   unsigned guestBus,
+                                   unsigned guestSlot)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    char *addr;
+
+    if (virAsprintf(&addr, "%.4x:%.2x:%.2x",
+                    guestDomain, guestBus, guestSlot) < 0) {
+        virReportOOMError(NULL);
+        return -1;
+    }
+
+    cmd = qemuMonitorJSONMakeCommand("pci_del",
+                                     "s:pci_addr", addr,
+                                     NULL);
+    VIR_FREE(addr);
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
+                                  const char *fdname,
+                                  int fd)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("getfd",
+                                                     "s:fdname", fdname,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommandWithFd(mon, cmd, fd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon,
+                                   const char *fdname)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("closefd",
+                                                     "s:fdname", fdname,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONAddHostNetwork(qemuMonitorPtr mon,
+                                  const char *netstr)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("host_net_add",
+                                                     "s:device", netstr,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
+int qemuMonitorJSONRemoveHostNetwork(qemuMonitorPtr mon,
+                                     int vlan,
+                                     const char *netname)
+{
+    int ret;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("host_net_remove",
+                                                     "i:vlan", vlan,
+                                                     "s:device", netname,
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
new file mode 100644
index 0000000..62a88c0
--- /dev/null
+++ b/src/qemu/qemu_monitor_json.h
@@ -0,0 +1,156 @@
+/*
+ * qemu_monitor_json.h: interaction with QEMU monitor console
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+
+#ifndef QEMU_MONITOR_JSON_H
+#define QEMU_MONITOR_JSON_H
+
+#include "internal.h"
+
+#include "qemu_monitor.h"
+
+int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
+                             const char *data,
+                             size_t len,
+                             qemuMonitorMessagePtr msg);
+
+int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
+                             virConnectPtr conn);
+int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
+
+int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
+
+int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
+                              int **pids);
+int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
+                                  unsigned long *currmem);
+int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
+                                     const char *devname,
+                                     long long *rd_req,
+                                     long long *rd_bytes,
+                                     long long *wr_req,
+                                     long long *wr_bytes,
+                                     long long *errs);
+
+
+int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
+                                  const char *password);
+int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
+                              unsigned long newmem);
+
+int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
+                              const char *devname);
+int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon,
+                               const char *devname,
+                               const char *newmedia,
+                               const char *format);
+
+
+int qemuMonitorJSONSaveVirtualMemory(qemuMonitorPtr mon,
+                                     unsigned long long offset,
+                                     size_t length,
+                                     const char *path);
+int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon,
+                                      unsigned long long offset,
+                                      size_t length,
+                                      const char *path);
+
+int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon,
+                                     unsigned long bandwidth);
+
+int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
+                                      int *status,
+                                      unsigned long long *transferred,
+                                      unsigned long long *remaining,
+                                      unsigned long long *total);
+
+int qemuMonitorJSONMigrateToHost(qemuMonitorPtr mon,
+                                 int background,
+                                 const char *hostname,
+                                 int port);
+
+int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
+                                    int background,
+                                    const char * const *argv,
+                                    const char *target);
+
+int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon,
+                                 int background,
+                                 const char *unixfile);
+
+int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon);
+
+int qemuMonitorJSONAddUSBDisk(qemuMonitorPtr mon,
+                              const char *path);
+
+int qemuMonitorJSONAddUSBDeviceExact(qemuMonitorPtr mon,
+                                     int bus,
+                                     int dev);
+int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon,
+                                     int vendor,
+                                     int product);
+
+
+int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon,
+                                    unsigned hostDomain,
+                                    unsigned hostBus,
+                                    unsigned hostSlot,
+                                    unsigned hostFunction,
+                                    unsigned *guestDomain,
+                                    unsigned *guestBus,
+                                    unsigned *guestSlot);
+
+int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon,
+                              const char *path,
+                              const char *bus,
+                              unsigned *guestDomain,
+                              unsigned *guestBus,
+                              unsigned *guestSlot);
+
+int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon,
+                                 const char *nicstr,
+                                 unsigned *guestDomain,
+                                 unsigned *guestBus,
+                                 unsigned *guestSlot);
+
+int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon,
+                                   unsigned guestDomain,
+                                   unsigned guestBus,
+                                   unsigned guestSlot);
+
+
+int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
+                                  const char *fdname,
+                                  int fd);
+
+int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon,
+                                   const char *fdname);
+
+int qemuMonitorJSONAddHostNetwork(qemuMonitorPtr mon,
+                                  const char *netstr);
+
+int qemuMonitorJSONRemoveHostNetwork(qemuMonitorPtr mon,
+                                     int vlan,
+                                     const char *netname);
+
+#endif /* QEMU_MONITOR_JSON_H */
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 677c5b4..c39cbbc 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -60,7 +60,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
         goto fail;
 
     if (qemudBuildCommandLine(NULL, &driver,
-                              vmdef, &monitor_chr, flags,
+                              vmdef, &monitor_chr, 0, flags,
                               &argv, &qenv,
                               NULL, NULL, migrateFrom) < 0)
         goto fail;
-- 
1.6.5.2




More information about the libvir-list mailing list