Initial support for the new QEMU monitor protocol using JSON as the data encoding format instead of plain text * src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Hack to turn on QMP mode * 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 | 10 +- src/qemu/qemu_conf.h | 3 + src/qemu/qemu_monitor.c | 260 +++++++++++--- src/qemu/qemu_monitor_json.c | 817 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 155 ++++++++ 7 files changed, 1201 insertions(+), 47 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 5b9a364..2fcb9bf 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -27,6 +27,7 @@ src/phyp/phyp_driver.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 9660a99..dce5792 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -186,6 +186,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 UML_DRIVER_SOURCES = \ diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index b01fddc..d03d522 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1748,10 +1748,18 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-nographic"); if (monitor_chr) { + /* XXX gross hack for testing */ +#if QEMU_WITH_JSON + char buf[4096] = "control,"; + + if (qemudBuildCommandLineChrDevStr(monitor_chr, buf + 8, sizeof(buf)-8) < 0) + goto error; +#else char buf[4096]; - if (qemudBuildCommandLineChrDevStr(monitor_chr, buf, sizeof(buf)) < 0) + if (qemudBuildCommandLineChrDevStr(monitor_chr, buf, sizeof(buf)-8) < 0) goto error; +#endif ADD_ARG_LIT("-monitor"); ADD_ARG_LIT(buf); diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index f9a970f..336e30d 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -39,6 +39,9 @@ #define qemudDebug(fmt, ...) do {} while(0) +/* XXX gross hack for testing purposes */ +#define QEMU_WITH_JSON 0 + #define QEMUD_CPUMASK_LEN CPU_SETSIZE /* Internal flags to keep track of qemu command line capabilities */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 501cb3f..573bee9 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" @@ -71,6 +72,8 @@ struct _qemuMonitor { unsigned eofcb: 1; /* If the monitor callback should free the closed monitor */ unsigned closed: 1; + + unsigned json: 1; }; void qemuMonitorLock(qemuMonitorPtr mon) @@ -180,9 +183,14 @@ qemuMonitorIOProcess(qemuMonitorPtr mon) msg = mon->msg; VIR_DEBUG("Process %d", 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; @@ -455,6 +463,7 @@ qemuMonitorOpen(virDomainObjPtr vm, mon->fd = -1; mon->vm = vm; mon->eofCB = eofCB; + mon->json = QEMU_WITH_JSON; qemuMonitorLock(mon); switch (vm->monitor_chr->type) { @@ -595,43 +604,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; } @@ -643,38 +677,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; } @@ -682,10 +739,15 @@ int qemuMonitorChangeMedia(qemuMonitorPtr mon, const char *devname, const char *newmedia) { + int ret; DEBUG("mon=%p, fd=%d devname=%s newmedia=%s", mon, mon->fd, devname, newmedia); - return qemuMonitorTextChangeMedia(mon, devname, newmedia); + if (mon->json) + ret = qemuMonitorJSONChangeMedia(mon, devname, newmedia); + else + ret = qemuMonitorTextChangeMedia(mon, devname, newmedia); + return ret; } @@ -694,10 +756,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, @@ -705,19 +772,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, @@ -726,12 +803,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; } @@ -740,10 +825,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; } @@ -752,35 +842,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; } @@ -788,19 +898,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; } @@ -813,16 +933,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; } @@ -833,11 +963,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; } @@ -847,10 +983,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; } @@ -859,11 +1001,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; } @@ -871,30 +1019,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; } @@ -902,8 +1065,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_json.c b/src/qemu/qemu_monitor_json.c new file mode 100644 index 0000000..95f74fa --- /dev/null +++ b/src/qemu/qemu_monitor_json.c @@ -0,0 +1,817 @@ +/* + * 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@xxxxxxxxxx> + */ + +#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 "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) +{ + json_t *obj = NULL; + json_t *val; + int ret = -1; + + VIR_DEBUG("Line [%s]", line); + + if (json_parse_document(&obj, line) != JSON_OK) { + VIR_DEBUG0("Parsing JSON string failed"); + errno = EINVAL; + goto cleanup; + } + + if (obj->type != JSON_OBJECT) { + VIR_DEBUG0("Parsed JSON string isn't an object"); + errno = EINVAL; + } + + if (json_find_first_label(obj, "QMP", &val) == JSON_OK) { + VIR_DEBUG0("Got QMP capabilities data"); + ret = 0; + goto cleanup; + } + + if (json_find_first_label(obj, "event", &val) == JSON_OK) { + 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: + if (obj) + json_free_value(&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); + + if (qemuMonitorJSONIOProcessLine(mon, line, msg) < 0) { + VIR_FREE(line); + return -1; + } + + VIR_FREE(line); + } else { + break; + } + } + + VIR_DEBUG("Total used %d", used); + return used; +} + +static int +qemuMonitorCommandWithFd(qemuMonitorPtr mon, + json_t *cmd, + int scm_fd, + json_t **reply) +{ + int ret = -1; + qemuMonitorMessage msg; + char *cmdstr = NULL; + + *reply = NULL; + + memset(&msg, 0, sizeof msg); + + if (json_tree_to_string(cmd, &cmdstr) != JSON_OK) { + 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); + + + /* To make life safer for callers, already ensure there's at least an empty string */ + if (msg.rxBuffer && ret == 0) { + if (json_parse_document(reply, msg.rxBuffer) != JSON_OK) { + 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 +qemuMonitorCommand(qemuMonitorPtr mon, + json_t *cmd, + json_t **reply) { + return qemuMonitorCommandWithFd(mon, cmd, -1, reply); +} + + +static json_t * +qemuMonitorJSONMakeCommand(const char *cmdname, + ...) +{ + json_t *obj; + json_t *jargs = NULL; + va_list args; + char *key; + char *val; + + va_start(args, cmdname); + + if (!(obj = json_new_object())) + goto no_memory; + + if (json_insert_string_pair_into_object(obj, "execute", cmdname) != JSON_OK) + goto no_memory; + + while ((key = va_arg(args, char *)) != NULL) { + val = va_arg(args, char *); + if (!val) + goto error; + + if (!jargs && + !(jargs = json_new_object())) + goto no_memory; + + if (json_insert_string_pair_into_object(obj, key, val) != JSON_OK) + goto no_memory; + } + + if (jargs && + json_insert_pair_into_object(obj, "arguments", jargs) != JSON_OK) + goto no_memory; + + va_end(args); + + return obj; + +no_memory: + virReportOOMError(NULL); +error: + if (obj) + json_free_value(&obj); + if (jargs) + json_free_value(&jargs); + va_end(args); + return NULL; +} + + +int +qemuMonitorJSONStartCPUs(qemuMonitorPtr mon, + virConnectPtr conn ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("cont", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int +qemuMonitorJSONStopCPUs(qemuMonitorPtr mon) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("stop", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("system_powerdown", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon, + int **pids) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("info", "type", "cpus", NULL); + json_t *reply = NULL; + + *pids = NULL; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&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; + json_t *cmd = qemuMonitorJSONMakeCommand("info", "type", "balloon", NULL); + json_t *reply = NULL; + + *currmem = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon, + const char *devname ATTRIBUTE_UNUSED, + long long *rd_req, + long long *rd_bytes, + long long *wr_req, + long long *wr_bytes, + long long *errs) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("info", "type", "blockstats", NULL); + json_t *reply = NULL; + + *rd_req = *rd_bytes = *wr_req = *wr_bytes = *errs = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon, + const char *password) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("change", "type", "vnc", "password", password, NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&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 ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("balloon", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon, + const char *devname) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("eject", "device", devname, NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon, + const char *devname, + const char *newmedia) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("change", "device", devname, "media", newmedia, NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +static int qemuMonitorJSONSaveMemory(qemuMonitorPtr mon, + const char *cmdtype, + unsigned long long offset ATTRIBUTE_UNUSED, + size_t length ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand(cmdtype, NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&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 ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("migrate_set_speed", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon, + int *status, + unsigned long long *transferred, + unsigned long long *remaining, + unsigned long long *total) { + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("info migration", NULL); + json_t *reply = NULL; + + *status = 0; + *transferred = *remaining = *total = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONMigrateToHost(qemuMonitorPtr mon, + int background ATTRIBUTE_UNUSED, + const char *hostname ATTRIBUTE_UNUSED, + int port ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("migrate", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon, + int background ATTRIBUTE_UNUSED, + const char * const *argv ATTRIBUTE_UNUSED, + const char *target ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("migrate", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon, + int background ATTRIBUTE_UNUSED, + const char *unixfile ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("migrate", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("migrate", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + +int qemuMonitorJSONAddUSBDisk(qemuMonitorPtr mon, + const char *path) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("usb_add", "type", "disk", "path", path, NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONAddUSBDeviceExact(qemuMonitorPtr mon, + int bus ATTRIBUTE_UNUSED, + int dev ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("usb_add", "type", "host", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; + +} + +int qemuMonitorJSONAddUSBDeviceMatch(qemuMonitorPtr mon, + int vendor ATTRIBUTE_UNUSED, + int product ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("usb_add", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONAddPCIHostDevice(qemuMonitorPtr mon, + unsigned hostDomain ATTRIBUTE_UNUSED, + unsigned hostBus ATTRIBUTE_UNUSED, + unsigned hostSlot ATTRIBUTE_UNUSED, + unsigned hostFunction ATTRIBUTE_UNUSED, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("pci_add", NULL); + json_t *reply = NULL; + + *guestDomain = *guestBus = *guestSlot = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONAddPCIDisk(qemuMonitorPtr mon, + const char *path ATTRIBUTE_UNUSED, + const char *bus ATTRIBUTE_UNUSED, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) { + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("pci_add", NULL); + json_t *reply = NULL; + + *guestDomain = *guestBus = *guestSlot = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon, + const char *nicstr ATTRIBUTE_UNUSED, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("pci_add", NULL); + json_t *reply = NULL; + + *guestDomain = *guestBus = *guestSlot = 0; + + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon, + unsigned guestDomain ATTRIBUTE_UNUSED, + unsigned guestBus ATTRIBUTE_UNUSED, + unsigned guestSlot ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("pci_del", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon, + const char *fdname ATTRIBUTE_UNUSED, + int fd) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("getfd", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommandWithFd(mon, cmd, fd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon, + const char *fdname ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("closefd", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONAddHostNetwork(qemuMonitorPtr mon, + const char *netstr ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("host_net_add", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&reply); + return ret; +} + + +int qemuMonitorJSONRemoveHostNetwork(qemuMonitorPtr mon, + int vlan ATTRIBUTE_UNUSED, + const char *netname ATTRIBUTE_UNUSED) +{ + int ret; + json_t *cmd = qemuMonitorJSONMakeCommand("host_net_remove", NULL); + json_t *reply = NULL; + if (!cmd) + return -1; + + ret = qemuMonitorCommand(mon, cmd, &reply); + + json_free_value(&cmd); + if (reply) + json_free_value(&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..a44158a --- /dev/null +++ b/src/qemu/qemu_monitor_json.h @@ -0,0 +1,155 @@ +/* + * 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@xxxxxxxxxx> + */ + + +#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); + + +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 */ -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list