All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol
@ 2009-11-19 15:13 Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 01/15] monitor: Introduce MONITOR_USE_CONTROL flag Luiz Capitulino
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

 Hi,

 This is not stable yet, it has a few bugs and a number of things to
be done, but I'm sending it now so that it can get an initial review
while I'm working on it.

 At the end of the series there are two simple Python scripts which are
able to talk to QEMU by using QMP.

 Main issues are:

o Not all errors are being detected/handled correctly
o Not using the stream parser to read the input

 If you want to try this, you need at least the latest version of QError,
and the conversions series to make this really useful.

 Thanks.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 01/15] monitor: Introduce MONITOR_USE_CONTROL flag
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode Luiz Capitulino
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

This flag will be set when Monitor enters "control mode", in
which the output will be defined by the QEMU Monitor Protocol.

This also introduces a macro to check if the flag is set.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |    6 ++++++
 monitor.h |    1 +
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/monitor.c b/monitor.c
index 45ab883..e7c6451 100644
--- a/monitor.c
+++ b/monitor.c
@@ -119,6 +119,12 @@ Monitor *cur_mon = NULL;
 static void monitor_command_cb(Monitor *mon, const char *cmdline,
                                void *opaque);
 
+/* Return true if in control mode, false otherwise */
+static inline int monitor_ctrl_mode(const Monitor *mon)
+{
+    return (mon->flags & MONITOR_USE_CONTROL);
+}
+
 static void monitor_read_command(Monitor *mon, int show_prompt)
 {
     readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
diff --git a/monitor.h b/monitor.h
index c7d2d0b..6cb1d4b 100644
--- a/monitor.h
+++ b/monitor.h
@@ -11,6 +11,7 @@ extern Monitor *cur_mon;
 /* flags for monitor_init */
 #define MONITOR_IS_DEFAULT    0x01
 #define MONITOR_USE_READLINE  0x02
+#define MONITOR_USE_CONTROL   0x04
 
 void monitor_init(CharDriverState *chr, int flags);
 
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 01/15] monitor: Introduce MONITOR_USE_CONTROL flag Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-22 18:06   ` Anthony Liguori
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 03/15] monitor: Move handler calling code to its own function Luiz Capitulino
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

This commit adds a flag called 'control' to the '-monitor'
command-line option. This flag enables control mode.

The syntax is:

qemu [...] -monitor control,<device>

Where <device> is a chardev (excluding 'vc', for obvious reasons).

For example:

$ qemu [...] -monitor control,tcp:localhost:4444,server

Will run QEMU in control mode, waiting for a client TCP connection
on localhost port 4444.

TODO: Update manpage.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   18 ++++++++++++++++++
 monitor.h |    1 +
 vl.c      |   11 +++++++----
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/monitor.c b/monitor.c
index e7c6451..a98dc42 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3616,6 +3616,24 @@ static void monitor_event(void *opaque, int event)
  * End:
  */
 
+const char *monitor_cmdline_parse(const char *cmdline, int *flags)
+{
+    const char *dev;
+
+    if (strstart(cmdline, "control,", &dev)) {
+        if (strstart(dev, "vc", NULL)) {
+            fprintf(stderr, "qemu: control mode is for low-level interaction ");
+            fprintf(stderr, "cannot be used with device 'vc'\n");
+            exit(1);
+        }
+        *flags &= ~MONITOR_USE_READLINE;
+        *flags |= MONITOR_USE_CONTROL;
+        return dev;
+    }
+
+    return cmdline;
+}
+
 void monitor_init(CharDriverState *chr, int flags)
 {
     static int is_first_init = 1;
diff --git a/monitor.h b/monitor.h
index 6cb1d4b..556507c 100644
--- a/monitor.h
+++ b/monitor.h
@@ -13,6 +13,7 @@ extern Monitor *cur_mon;
 #define MONITOR_USE_READLINE  0x02
 #define MONITOR_USE_CONTROL   0x04
 
+const char *monitor_cmdline_parse(const char *cmdline, int *flags);
 void monitor_init(CharDriverState *chr, int flags);
 
 int monitor_suspend(Monitor *mon);
diff --git a/vl.c b/vl.c
index 73fe68d..6b1a77a 100644
--- a/vl.c
+++ b/vl.c
@@ -4639,6 +4639,7 @@ int main(int argc, char **argv, char **envp)
     const char *r, *optarg;
     CharDriverState *monitor_hds[MAX_MONITOR_DEVICES];
     const char *monitor_devices[MAX_MONITOR_DEVICES];
+    int monitor_flags[MAX_MONITOR_DEVICES];
     int monitor_device_index;
     const char *serial_devices[MAX_SERIAL_PORTS];
     int serial_device_index;
@@ -4726,8 +4727,10 @@ int main(int argc, char **argv, char **envp)
     virtio_console_index = 0;
 
     monitor_devices[0] = "vc:80Cx24C";
+    monitor_flags[0] = MONITOR_IS_DEFAULT | MONITOR_USE_READLINE;
     for (i = 1; i < MAX_MONITOR_DEVICES; i++) {
         monitor_devices[i] = NULL;
+        monitor_flags[i] = MONITOR_USE_READLINE;
     }
     monitor_device_index = 0;
 
@@ -5150,7 +5153,9 @@ int main(int argc, char **argv, char **envp)
                     fprintf(stderr, "qemu: too many monitor devices\n");
                     exit(1);
                 }
-                monitor_devices[monitor_device_index] = optarg;
+                monitor_devices[monitor_device_index] =
+                                monitor_cmdline_parse(optarg,
+                                        &monitor_flags[monitor_device_index]);
                 monitor_device_index++;
                 break;
             case QEMU_OPTION_chardev:
@@ -5844,9 +5849,7 @@ int main(int argc, char **argv, char **envp)
 
     for (i = 0; i < MAX_MONITOR_DEVICES; i++) {
         if (monitor_devices[i] && monitor_hds[i]) {
-            monitor_init(monitor_hds[i],
-                         MONITOR_USE_READLINE |
-                         ((i == 0) ? MONITOR_IS_DEFAULT : 0));
+            monitor_init(monitor_hds[i], monitor_flags[i]);
         }
     }
 
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 03/15] monitor: Move handler calling code to its own function
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 01/15] monitor: Introduce MONITOR_USE_CONTROL flag Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 04/15] QError: Add errors used by QMP Luiz Capitulino
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

It's going to be used by QMP code as well.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/monitor.c b/monitor.c
index a98dc42..07bd21c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3268,6 +3268,18 @@ static void monitor_print_error(Monitor *mon)
     mon->error = NULL;
 }
 
+static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
+                                 const QDict *params)
+{
+    QObject *data = NULL;
+
+    cmd->mhandler.cmd_new(mon, params, &data);
+    if (data)
+        cmd->user_print(mon, data);
+
+    qobject_decref(data);
+}
+
 static void monitor_handle_command(Monitor *mon, const char *cmdline)
 {
     QDict *qdict;
@@ -3282,13 +3294,7 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
     qemu_errors_to_mon(mon);
 
     if (monitor_handler_ported(cmd)) {
-        QObject *data = NULL;
-
-        cmd->mhandler.cmd_new(mon, qdict, &data);
-        if (data)
-            cmd->user_print(mon, data);
-
-        qobject_decref(data);
+        monitor_call_handler(mon, cmd, qdict);
     } else {
         cmd->mhandler.cmd(mon, qdict);
     }
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 04/15] QError: Add errors used by QMP
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (2 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 03/15] monitor: Move handler calling code to its own function Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 05/15] QMP: chardev handling Luiz Capitulino
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

NOTE: These errors where added quickly to satisfy immediate needs,
they need to be reviewed.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c |   20 ++++++++++++++++++++
 qerror.h |   15 +++++++++++++++
 2 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/qerror.c b/qerror.c
index d8b125e..4349417 100644
--- a/qerror.c
+++ b/qerror.c
@@ -52,6 +52,26 @@ const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_KVM_MISSING_CAP,
         .desc      = "Using KVM without %(capability), %(feature) unavailable",
     },
+    {
+        .error_fmt   = QERR_BAD_SYNTAX,
+        .desc        = "wrong syntax: '%(reason)",
+    },
+    {
+        .error_fmt   = QERR_COMMAND_NOT_FOUND,
+        .desc        = "command: %(name)",
+    },
+    {
+        .error_fmt   = QERR_COMMAND_NOT_ISSUED,
+        .desc        = "a command should be issued",
+    },
+    {
+        .error_fmt   = QERR_INVALID_PARAMETER,
+        .desc        = "invalid parameter '%(parameter)': %(reason)",
+    },
+    {
+        .error_fmt   = QERR_UNDEFINED_ERROR,
+        .desc        = "an error has ocurred: %(hint)",
+    },
     {}
 };
 
diff --git a/qerror.h b/qerror.h
index 6c100af..1b704e4 100644
--- a/qerror.h
+++ b/qerror.h
@@ -47,4 +47,19 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_KVM_MISSING_CAP \
         "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
+#define QERR_BAD_SYNTAX \
+        "{ 'class': 'BadSyntax', 'data': { 'reason': %s } }"
+
+#define QERR_COMMAND_NOT_FOUND \
+        "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
+#define QERR_COMMAND_NOT_ISSUED \
+        "{ 'class': 'CommandNotIssued', 'data': { } }"
+
+#define QERR_INVALID_PARAMETER \
+        "{ 'class': 'InvalidParameter', 'data': { 'parameter': %s, 'reason': %s } }"
+
+#define QERR_UNDEFINED_ERROR \
+        "{ 'class': 'UndefinedError', 'data': { 'hint': %s } }"
+
 #endif /* QERROR_H */
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 05/15] QMP: chardev handling
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (3 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 04/15] QError: Add errors used by QMP Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 06/15] QMP: Output support Luiz Capitulino
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

This patch adds initial QMP support in QEMU. It's important
to notice that most QMP code will be part of the Monitor.

Input will be handled by monitor_control_read(). Currently it
reads the input and discards it, next patches add proper input
support.

The function monitor_json_emitter(), as its name implies, is
used by the Monitor to emit JSON output. In this commit it's
used by monitor_control_event() to print our greeting message.

Finally, control mode support is also added to monitor_init(),
allowing QMP to be really enabled.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index 07bd21c..be68dd5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -50,6 +50,7 @@
 #include "qdict.h"
 #include "qstring.h"
 #include "qerror.h"
+#include "qjson.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -92,6 +93,11 @@ struct mon_fd_t {
     QLIST_ENTRY(mon_fd_t) next;
 };
 
+typedef struct MonitorControl {
+    uint8_t buf[1024];
+    int size;
+} MonitorControl;
+
 struct Monitor {
     CharDriverState *chr;
     int mux_out;
@@ -101,6 +107,7 @@ struct Monitor {
     uint8_t outbuf[1024];
     int outbuf_index;
     ReadLineState *rs;
+    MonitorControl *mc;
     CPUState *mon_cpu;
     BlockDriverCompletionFunc *password_completion_cb;
     void *password_opaque;
@@ -255,6 +262,17 @@ static void monitor_print_qobject(Monitor *mon, const QObject *data)
     monitor_puts(mon, "\n");
 }
 
+static void monitor_json_emitter(Monitor *mon, const QObject *data)
+{
+    QString *json;
+
+    json = qobject_to_json(data);
+    assert(json != NULL);
+
+    monitor_printf(mon, "%s\n", qstring_get_str(json));
+    QDECREF(json);
+}
+
 static int compare_cmd(const char *name, const char *list)
 {
     const char *p, *pstart;
@@ -3530,6 +3548,37 @@ static int monitor_can_read(void *opaque)
     return (mon->suspend_cnt == 0) ? 128 : 0;
 }
 
+/**
+ * monitor_control_read(): Read and handle QMP input
+ */
+static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
+{
+    Monitor *old_mon = cur_mon;
+    int i;
+
+    cur_mon = opaque;
+
+    for (i = 0; i < size; i++) {
+        if (buf[i] == '\r' || buf[i] == '\n') {
+            cur_mon->mc->buf[cur_mon->mc->size] = '\0';
+            cur_mon->mc->size = 0;
+
+            /* TODO: parse QMP input */
+            break;
+        } else {
+            cur_mon->mc->buf[cur_mon->mc->size++] = buf[i];
+            if (cur_mon->mc->size == sizeof(cur_mon->mc->buf)) {
+                /* FIXME: qemu_error_new() */
+                monitor_printf(cur_mon, "Command too long\n");
+                cur_mon->mc->size = 0;
+                break;
+            }
+        }
+    }
+
+    cur_mon = old_mon;
+}
+
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
     Monitor *old_mon = cur_mon;
@@ -3573,6 +3622,24 @@ void monitor_resume(Monitor *mon)
         readline_show_prompt(mon->rs);
 }
 
+/**
+ * monitor_control_event(): Print QMP gretting on RESET
+ */
+static void monitor_control_event(void *opaque, int event)
+{
+    if (event == CHR_EVENT_OPENED) {
+        QObject *data;
+        Monitor *mon = opaque;
+
+        data = qobject_from_jsonf("{ 'QMP': { 'capabilities': [] } }");
+        assert(data != NULL);
+        monitor_json_emitter(mon, data);
+        qobject_decref(data);
+
+        mon->mc->size = 0;
+    }
+}
+
 static void monitor_event(void *opaque, int event)
 {
     Monitor *mon = opaque;
@@ -3659,8 +3726,15 @@ void monitor_init(CharDriverState *chr, int flags)
         monitor_read_command(mon, 0);
     }
 
-    qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event,
-                          mon);
+    if (monitor_ctrl_mode(mon)) {
+        mon->mc = qemu_mallocz(sizeof(MonitorControl));
+        /* Control mode requires special handlers */
+        qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
+                              monitor_control_event, mon);
+    } else {
+        qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
+                              monitor_event, mon);
+    }
 
     QLIST_INSERT_HEAD(&mon_list, mon, entry);
     if (!cur_mon || (flags & MONITOR_IS_DEFAULT))
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 06/15] QMP: Output support
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (4 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 05/15] QMP: chardev handling Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 07/15] QMP: Input support Luiz Capitulino
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

In the new Monitor, output is always done by only two
functions: do_info() and monitor_call_handler().

To support QMP output, we modify those functions to test if we
are in control mode. If so, we call monitor_protocol_emitter()
to emit QMP output, otherwise we do regular output.

QMP has two types of responses to issued commands: success and
error. The outputed data is always a JSON object.

Success responses have the following format:

{ "return": json-value, "id": json-value }

Error responses have the following format:

{ "error": { "class": json-string,
             "desc": json-string,
             "data": json-value } "id": json-value }

Please, note that the "id" key is part of the input code, and
thus is not added in this commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/monitor.c b/monitor.c
index be68dd5..e81f9e6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -273,6 +273,33 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
     QDECREF(json);
 }
 
+static void monitor_protocol_emitter(Monitor *mon, QObject *data)
+{
+    QDict *qmp;
+
+    qmp = qdict_new();
+
+    if (!monitor_has_error(mon)) {
+        /* success response */
+        if (data) {
+            qobject_incref(data);
+            qdict_put_obj(qmp, "return", data);
+        } else {
+            // FIXME: should we return json-null here?
+            qdict_put(qmp, "return", qstring_from_str("OK"));
+        }
+    } else {
+        /* error response */
+        QINCREF(mon->error->error);
+        qdict_put(qmp, "error", mon->error->error);
+        QDECREF(mon->error);
+        mon->error = NULL;
+    }
+
+    monitor_json_emitter(mon, QOBJECT(qmp));
+    QDECREF(qmp);
+}
+
 static int compare_cmd(const char *name, const char *list)
 {
     const char *p, *pstart;
@@ -360,8 +387,15 @@ static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
     if (monitor_handler_ported(cmd)) {
         cmd->mhandler.info_new(mon, ret_data);
-        if (*ret_data)
-            cmd->user_print(mon, *ret_data);
+
+        if (!monitor_ctrl_mode(mon)) {
+            /*
+             * User Protocol function is called here, Monitor Protocol is
+             * handled by monitor_handle_command()
+             */
+            if (*ret_data)
+                cmd->user_print(mon, *ret_data);
+        }
     } else {
         cmd->mhandler.info(mon);
     }
@@ -3292,8 +3326,15 @@ static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
     QObject *data = NULL;
 
     cmd->mhandler.cmd_new(mon, params, &data);
-    if (data)
-        cmd->user_print(mon, data);
+
+    if (monitor_ctrl_mode(mon)) {
+        /* Monitor Protocol */
+        monitor_protocol_emitter(mon, data);
+    } else {
+        /* User Protocol */
+         if (data)
+            cmd->user_print(mon, data);
+    }
 
     qobject_decref(data);
 }
@@ -3315,10 +3356,11 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
         monitor_call_handler(mon, cmd, qdict);
     } else {
         cmd->mhandler.cmd(mon, qdict);
-    }
 
-    if (monitor_has_error(mon))
-        monitor_print_error(mon);
+        if (monitor_has_error(mon)) {
+            monitor_print_error(mon);
+        }
+    }
 
     qemu_errors_to_previous();
 
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 07/15] QMP: Input support
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (5 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 06/15] QMP: Output support Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 08/15] QMP: Asynchronous events infrastructure Luiz Capitulino
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

QMP input is handled by monitor_handle_qmp_command().

This function's job is to check if the input is correct and
if so call the appropriate handler. In other words, it does
for QMP what monitor_parse_command() does for the user
protocol.

This means that monitor_handle_qmp_command() also has to
parse the (ugly) "args_type" format to able to get the
arguments names and types expected by the handler.

The format to input commands to QMP is as follows:

{ "execute": json-string,
  "id": json-value, "arguments": json-object }

Please, note that this commit also adds "id" support.

TODO: Use QJSON to read from the user
TODO: Errors need to be reviewed

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |  251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 244 insertions(+), 7 deletions(-)

diff --git a/monitor.c b/monitor.c
index e81f9e6..5c5ae97 100644
--- a/monitor.c
+++ b/monitor.c
@@ -96,6 +96,7 @@ struct mon_fd_t {
 typedef struct MonitorControl {
     uint8_t buf[1024];
     int size;
+    QObject *id;
 } MonitorControl;
 
 struct Monitor {
@@ -296,6 +297,11 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
         mon->error = NULL;
     }
 
+    if (mon->mc->id) {
+        qdict_put_obj(qmp, "id", mon->mc->id);
+        mon->mc->id = NULL;
+    }
+
     monitor_json_emitter(mon, QOBJECT(qmp));
     QDECREF(qmp);
 }
@@ -374,16 +380,27 @@ static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
     const mon_cmd_t *cmd;
     const char *item = qdict_get_try_str(qdict, "item");
 
-    if (!item)
+    if (!item) {
+        if (monitor_ctrl_mode(mon)) {
+            /* 'item' is mandatory in ctrl mode */
+            qemu_error_new(QERR_COMMAND_NOT_ISSUED);
+            return;
+        }
         goto help;
+    }
 
     for (cmd = info_cmds; cmd->name != NULL; cmd++) {
         if (compare_cmd(item, cmd->name))
             break;
     }
 
-    if (cmd->name == NULL)
+    if (cmd->name == NULL) {
+        if (monitor_ctrl_mode(mon)) {
+            qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
+            return;
+        }
         goto help;
+    }
 
     if (monitor_handler_ported(cmd)) {
         cmd->mhandler.info_new(mon, ret_data);
@@ -397,7 +414,12 @@ static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
                 cmd->user_print(mon, *ret_data);
         }
     } else {
-        cmd->mhandler.info(mon);
+        if (monitor_ctrl_mode(mon)) {
+            /* handler not converted yet */
+            qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd->name);
+        } else {
+            cmd->mhandler.info(mon);
+        }
     }
 
     return;
@@ -3355,10 +3377,15 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
     if (monitor_handler_ported(cmd)) {
         monitor_call_handler(mon, cmd, qdict);
     } else {
-        cmd->mhandler.cmd(mon, qdict);
+        if (monitor_ctrl_mode(mon)) {
+            /* handler not converted yet */
+            qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd->name);
+        } else {
+            cmd->mhandler.cmd(mon, qdict);
 
-        if (monitor_has_error(mon)) {
-            monitor_print_error(mon);
+            if (monitor_has_error(mon)) {
+                monitor_print_error(mon);
+            }
         }
     }
 
@@ -3590,6 +3617,216 @@ static int monitor_can_read(void *opaque)
     return (mon->suspend_cnt == 0) ? 128 : 0;
 }
 
+typedef struct CmdArgs {
+    QString *name;
+    int type;
+    int flag;
+    int optional;
+} CmdArgs;
+
+static int check_opt(const CmdArgs *cmd_args, const char *name)
+{
+    if (!cmd_args->optional) {
+        qemu_error_new(QERR_INVALID_PARAMETER, name, "parameter required");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int check_arg(const CmdArgs *cmd_args, const QDict *args)
+{
+    QObject *value;
+    const char *name;
+
+    name = qstring_get_str(cmd_args->name);
+
+    if (!args) {
+        return check_opt(cmd_args, name);
+    }
+
+    value = qdict_get(args, name);
+    if (!value) {
+        return check_opt(cmd_args, name);
+    }
+
+    switch (cmd_args->type) {
+        case 'F':
+        case 'B':
+        case 's':
+            if (qobject_type(value) != QTYPE_QSTRING) {
+                qemu_error_new(QERR_INVALID_PARAMETER, name,"must be a string");
+                return -1;
+            }
+            break;
+        case '/': {
+            int i;
+            const char *keys[] = { "count", "format", "size", NULL };
+
+            for (i = 0; keys[i]; i++) {
+                QObject *obj = qdict_get(args, keys[i]);
+                if (!obj) {
+                    qemu_error_new(QERR_INVALID_PARAMETER, name,
+                                   "missing 'count', 'format' or 'size'");
+                    return -1;
+                }
+                if (qobject_type(obj) != QTYPE_QINT) {
+                    qemu_error_new(QERR_INVALID_PARAMETER, name,
+                                   "must be integer");
+                    return -1;
+                }
+            }
+            break;
+        }
+        case 'i':
+        case 'l':
+        case '-':
+            if (qobject_type(value) != QTYPE_QINT) {
+                qemu_error_new(QERR_INVALID_PARAMETER, name,
+                               "must be an integer");
+                return -1;
+            }
+            break;
+        default:
+            /* impossible */
+            abort();
+    }
+
+    return 0;
+}
+
+static void cmd_args_init(CmdArgs *cmd_args)
+{
+    cmd_args->name = qstring_new();
+    cmd_args->type = cmd_args->flag = cmd_args->optional = 0;
+}
+
+/*
+ * This is not trivial, we have to parse Monitor command's argument
+ * type syntax to be able to check the arguments provided by clients.
+ *
+ * In the near future we will use an array for that and will drop all
+ * this parsing...
+ */
+static int monitor_check_qmp_args(const mon_cmd_t *cmd, const QDict *args)
+{
+    int err;
+    const char *p;
+    CmdArgs cmd_args;
+
+    if (cmd->args_type == '\0') {
+        return (qdict_size(args) == 0 ? 0 : -1);
+    }
+
+    err = 0;
+    cmd_args_init(&cmd_args);
+
+    for (p = cmd->args_type;; p++) {
+        if (*p == ':') {
+            cmd_args.type = *++p;
+            p++;
+            if (cmd_args.type == '-') {
+                cmd_args.flag = *p++;
+            } else if (*p == '?') {
+                cmd_args.optional = 1;
+                p++;
+            }
+
+            assert(*p == ',' || *p == '\0');
+            err = check_arg(&cmd_args, args);
+
+            QDECREF(cmd_args.name);
+            cmd_args_init(&cmd_args);
+
+            if (err < 0) {
+                break;
+            }
+        } else {
+            qstring_append_chr(cmd_args.name, *p);
+        }
+
+        if (*p == '\0') {
+            break;
+        }
+    }
+
+    QDECREF(cmd_args.name);
+    return err;
+}
+
+static void monitor_handle_qmp_command(Monitor *mon)
+{
+    int err;
+    QObject *obj;
+    QDict *input, *args;
+    const char *cmd_name;
+    const mon_cmd_t *cmd;
+
+    qemu_errors_to_mon(mon);
+
+    obj = qobject_from_json((char *) mon->mc->buf);
+    if (!obj) {
+        // FIXME: should be triggered in qobject_from_json()
+        qemu_error_new(QERR_BAD_SYNTAX, "parsing error");
+        goto error;
+    } else if (qobject_type(obj) != QTYPE_QDICT) {
+        qemu_error_new(QERR_BAD_SYNTAX, "should be a dictionary");
+        qobject_decref(obj);
+        goto error;
+    }
+
+    input = qobject_to_qdict(obj);
+
+    mon->mc->id = qdict_get(input, "id");
+    qobject_incref(mon->mc->id);
+
+    if (!qdict_haskey(input, "execute")) {
+        qemu_error_new(QERR_BAD_SYNTAX, "missing 'execute' keyword");
+        QDECREF(input);
+        goto error;
+    }
+
+    cmd_name = qdict_get_str(input, "execute");
+    for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
+        if (compare_cmd(cmd_name, cmd->name)) {
+            break;
+        }
+    }
+
+    if (cmd->name == NULL) {
+        qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+        QDECREF(input);
+        goto error;
+    }
+
+    obj = qdict_get(input, "arguments");
+    if (!obj) {
+        QDECREF(input);
+        args = qdict_new();
+    } else {
+        args = qobject_to_qdict(obj);
+        QINCREF(args);
+        QDECREF(input);
+    }
+
+    err = monitor_check_qmp_args(cmd, args);
+    if (err < 0) {
+        QDECREF(args);
+        goto error;
+    }
+
+    monitor_call_handler(mon, cmd, args);
+
+    QDECREF(args);
+
+    qemu_errors_to_previous();
+    return;
+
+error:
+    monitor_protocol_emitter(mon, NULL);
+    qemu_errors_to_previous();
+}
+
 /**
  * monitor_control_read(): Read and handle QMP input
  */
@@ -3605,7 +3842,7 @@ static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
             cur_mon->mc->buf[cur_mon->mc->size] = '\0';
             cur_mon->mc->size = 0;
 
-            /* TODO: parse QMP input */
+            monitor_handle_qmp_command(cur_mon);
             break;
         } else {
             cur_mon->mc->buf[cur_mon->mc->size++] = buf[i];
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 08/15] QMP: Asynchronous events infrastructure
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (6 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 07/15] QMP: Input support Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 09/15] QMP: Introduce basic asynchronous events Luiz Capitulino
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

Asynchronous events are generated with a call to
monitor_protocol_event().

This function builds the right data-type and emit the event
right away. The emitted data is always a JSON object and its
format is as follows:

{ "event": json-string,
  "timestamp": { "seconds": json-number, "microseconds": json-number },
  "data": json-value }

This design is based on ideas by Amit Shah <amit.shah@redhat.com>.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c   |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 monitor.h   |    6 ++++++
 qemu-tool.c |    4 ++++
 3 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/monitor.c b/monitor.c
index 5c5ae97..616f712 100644
--- a/monitor.c
+++ b/monitor.c
@@ -306,6 +306,56 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
     QDECREF(qmp);
 }
 
+static void timestamp_put(QDict *qdict)
+{
+    int err;
+    QObject *obj;
+    struct timeval tv;
+
+    err = gettimeofday(&tv, NULL);
+    if (err < 0)
+        return;
+
+    obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
+                                "'microseconds': %" PRId64 " }",
+                                (int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
+    assert(obj != NULL);
+
+    qdict_put_obj(qdict, "timestamp", obj);
+}
+
+/**
+ * monitor_protocol_event(): Generate a Monitor event
+ *
+ * Event-specific data can be emitted through the (optional) 'data' parameter.
+ */
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+    QDict *qmp;
+    const char *event_name;
+    Monitor *mon = cur_mon;
+
+    assert(event < EVENT_MAX);
+
+    if (!monitor_ctrl_mode(mon))
+        return;
+
+    switch (event) {
+        default:
+            abort();
+            break;
+    }
+
+    qmp = qdict_new();
+    timestamp_put(qmp);
+    qdict_put(qmp, "event", qstring_from_str(event_name));
+    if (data)
+        qdict_put_obj(qmp, "data", data);
+
+    monitor_json_emitter(mon, QOBJECT(qmp));
+    QDECREF(qmp);
+}
+
 static int compare_cmd(const char *name, const char *list)
 {
     const char *p, *pstart;
diff --git a/monitor.h b/monitor.h
index 556507c..a1d8b7a 100644
--- a/monitor.h
+++ b/monitor.h
@@ -13,6 +13,12 @@ extern Monitor *cur_mon;
 #define MONITOR_USE_READLINE  0x02
 #define MONITOR_USE_CONTROL   0x04
 
+/* QMP events */
+typedef enum MonitorEvent {
+    EVENT_MAX,
+} MonitorEvent;
+
+void monitor_protocol_event(MonitorEvent event, QObject *data);
 const char *monitor_cmdline_parse(const char *cmdline, int *flags);
 void monitor_init(CharDriverState *chr, int flags);
 
diff --git a/qemu-tool.c b/qemu-tool.c
index b35ea8e..18b48af 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -56,6 +56,10 @@ int get_async_context_id(void)
     return 0;
 }
 
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+}
+
 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
 {
     QEMUBH *bh;
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 09/15] QMP: Introduce basic asynchronous events
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (7 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 08/15] QMP: Asynchronous events infrastructure Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 10/15] QMP: Disable monitor print functions Luiz Capitulino
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

Debug, shutdown, reset, powerdown and stop are all basic events,
as they are very simple they can be added in the same commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   15 +++++++++++++++
 monitor.h |    5 +++++
 vl.c      |   11 +++++++++--
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index 616f712..dc4583f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -341,6 +341,21 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         return;
 
     switch (event) {
+        case EVENT_DEBUG:
+            event_name = "DEBUG";
+            break;
+        case EVENT_SHUTDOWN:
+            event_name = "SHUTDOWN";
+            break;
+        case EVENT_RESET:
+            event_name = "RESET";
+            break;
+        case EVENT_POWERDOWN:
+            event_name = "POWERDOWN";
+            break;
+        case EVENT_STOP:
+            event_name = "STOP";
+            break;
         default:
             abort();
             break;
diff --git a/monitor.h b/monitor.h
index a1d8b7a..851fd33 100644
--- a/monitor.h
+++ b/monitor.h
@@ -15,6 +15,11 @@ extern Monitor *cur_mon;
 
 /* QMP events */
 typedef enum MonitorEvent {
+    EVENT_DEBUG,
+    EVENT_SHUTDOWN,
+    EVENT_RESET,
+    EVENT_POWERDOWN,
+    EVENT_STOP,
     EVENT_MAX,
 } MonitorEvent;
 
diff --git a/vl.c b/vl.c
index 6b1a77a..5da50e7 100644
--- a/vl.c
+++ b/vl.c
@@ -4110,9 +4110,12 @@ static void main_loop(void)
 #endif
         } while (vm_can_run());
 
-        if (qemu_debug_requested())
+        if (qemu_debug_requested()) {
+            monitor_protocol_event(EVENT_DEBUG, NULL);
             vm_stop(EXCP_DEBUG);
+        }
         if (qemu_shutdown_requested()) {
+            monitor_protocol_event(EVENT_SHUTDOWN, NULL);
             if (no_shutdown) {
                 vm_stop(0);
                 no_shutdown = 0;
@@ -4120,15 +4123,19 @@ static void main_loop(void)
                 break;
         }
         if (qemu_reset_requested()) {
+            monitor_protocol_event(EVENT_RESET, NULL);
             pause_all_vcpus();
             qemu_system_reset();
             resume_all_vcpus();
         }
         if (qemu_powerdown_requested()) {
+            monitor_protocol_event(EVENT_POWERDOWN, NULL);
             qemu_irq_raise(qemu_system_powerdown);
         }
-        if ((r = qemu_vmstop_requested()))
+        if ((r = qemu_vmstop_requested())) {
+            monitor_protocol_event(EVENT_STOP, NULL);
             vm_stop(r);
+        }
     }
     pause_all_vcpus();
 }
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 10/15] QMP: Disable monitor print functions
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (8 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 09/15] QMP: Introduce basic asynchronous events Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 11/15] QMP: Introduce README file Luiz Capitulino
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

We still have handlers which will call monitor print functions
in several places.

If they do this when we are in control mode, we will be emitting
garbage to our clients.

To avoid this situation, this commit adds a way to disable
those functions. If any of them is called when in control mode,
we will emit a generic error.

Although this is far from the perfect solution, it guarantees
that only JSON is printed.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/monitor.c b/monitor.c
index dc4583f..e85f990 100644
--- a/monitor.c
+++ b/monitor.c
@@ -97,6 +97,7 @@ typedef struct MonitorControl {
     uint8_t buf[1024];
     int size;
     QObject *id;
+    int print_enabled;
 } MonitorControl;
 
 struct Monitor {
@@ -184,9 +185,13 @@ static void monitor_puts(Monitor *mon, const char *str)
 
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 {
-    char buf[4096];
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    monitor_puts(mon, buf);
+    if (mon->mc && !mon->mc->print_enabled) {
+        qemu_error_new(QERR_UNDEFINED_ERROR, "monitor print");
+    } else {
+        char buf[4096];
+        vsnprintf(buf, sizeof(buf), fmt, ap);
+        monitor_puts(mon, buf);
+    }
 }
 
 void monitor_printf(Monitor *mon, const char *fmt, ...)
@@ -270,7 +275,10 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
     json = qobject_to_json(data);
     assert(json != NULL);
 
+    mon->mc->print_enabled = 1;
     monitor_printf(mon, "%s\n", qstring_get_str(json));
+    mon->mc->print_enabled = 0;
+
     QDECREF(json);
 }
 
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 11/15] QMP: Introduce README file
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (9 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 10/15] QMP: Disable monitor print functions Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 12/15] QMP: Introduce specification Luiz Capitulino
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/README |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)
 create mode 100644 QMP/README

diff --git a/QMP/README b/QMP/README
new file mode 100644
index 0000000..5ac1742
--- /dev/null
+++ b/QMP/README
@@ -0,0 +1,47 @@
+                          QEMU Monitor Protocol
+                          =====================
+
+Introduction
+-------------
+
+The QEMU Monitor Protocol (QMP) is a JSON[1] based protocol for QEMU.
+
+By using it applications can control QEMU in reliable and "parseable" way,
+QMP also provides asynchronous events support.
+
+For more information, please, refer to the following files:
+
+o qmp-spec.txt    QEMU Monitor Protocol current draft specification
+o qmp-events.txt  List of available asynchronous events
+o vm-info         A simple QMP usage example in Python
+
+[1] http://www.json.org
+
+Usage
+-----
+
+To enable QMP, QEMU has to be started in "control mode". This is done
+by passing the flag "control" to the "-monitor" command-line option.
+
+For example:
+
+$ qemu [...] -monitor control,tcp:localhost:4444,server
+
+Will start QEMU in control mode, waiting for a client TCP connection
+on localhost port 4444.
+
+To manually test it you can connect with telnet and issue commands:
+
+$ telnet localhost 4444
+Trying ::1...
+Connected to localhost.
+Escape character is '^]'.
+{"QMP": {"capabilities": []}}
+{ "execute": "info", "arguments": { "item": "version" } }
+{"return": "0.11.50"}
+
+Contact
+-------
+
+http://www.linux-kvm.org/page/MonitorProtocol
+Luiz Fernando N. Capitulino <lcapitulino@redhat.com>
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 12/15] QMP: Introduce specification
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (10 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 11/15] QMP: Introduce README file Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 13/15] QMP: Introduce qmp-events.txt Luiz Capitulino
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/qmp-spec.txt |  193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 193 insertions(+), 0 deletions(-)
 create mode 100644 QMP/qmp-spec.txt

diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
new file mode 100644
index 0000000..e155f92
--- /dev/null
+++ b/QMP/qmp-spec.txt
@@ -0,0 +1,193 @@
+           QEMU Monitor Protocol Draft Specification - Version 0.1
+
+1. Introduction
+===============
+
+This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
+which is available for applications to control QEMU at the machine-level.
+
+To enable QMP support, QEMU has to be run in "control mode". This is done by
+starting QEMU with the appropriate command-line options. Please, refer to the
+QEMU manual page for more information.
+
+2. Protocol Specification
+=========================
+
+This section details the protocol format. For the purpose of this document
+"Client" is any application which is communicating with QEMU in control mode,
+and "Server" is QEMU itself.
+
+JSON data structures, when mentioned in this document, are always in the
+following format:
+
+    json-DATA-STRUCTURE-NAME
+
+Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
+the JSON standard:
+
+http://www.ietf.org/rfc/rfc4627.txt
+
+For convenience, json-objects mentioned in this document will have its members
+in a certain order. However, in real protocol usage json-objects members can
+be in ANY order, thus no particular order should be assumed.
+
+2.1 General Definitions
+-----------------------
+
+2.1.1 All interactions transmitted by the Server are json-objects, always
+      terminating with CRLF
+
+2.1.2 All json-objects members are mandatory when not specified otherwise
+
+2.2 Server Greeting
+-------------------
+
+Right when connected the Server will issue a greeting message, which signals
+that the connection has been successfully established and that the Server is
+waiting for commands.
+
+The format is:
+
+{ "QMP": { "capabilities": json-array } }
+
+ Where,
+
+- The "capabilities" member specify the availability of features beyond the
+  baseline specification
+
+2.3 Issuing Commands
+--------------------
+
+The format for command execution is:
+
+{ "execute": json-string, "arguments": json-object, "id": json-value }
+
+ Where,
+
+- The "execute" member identifies the command to be executed by the Server
+- The "arguments" member is used to pass any arguments required for the
+  execution of the command, it is optional when no arguments are required
+- The "id" member is a transaction identification associated with the
+  command execution, it is optional and will be part of the response if
+  provided
+
+2.4 Commands Responses
+----------------------
+
+There are two possible responses which the Server will issue as the result
+of a command execution: success or error.
+
+2.4.1 success
+-------------
+
+The success response is issued when the command execution has finished
+without errors.
+
+The format is:
+
+{ "return": json-value, "id": json-value }
+
+ Where,
+
+- The "return" member contains the command returned data, which is defined
+  in a per-command basis or "OK" if the command does not return data
+- The "id" member contains the transaction identification associated
+  with the command execution (if issued by the Client)
+
+2.4.2 error
+-----------
+
+The error response is issued when the command execution could not be
+completed because of an error condition.
+
+The format is:
+
+{ "error": { "class": json-string, "data": json-value }, "id": json-value }
+
+ Where,
+
+- The "class" member contains the error class (eg. "ServiceUnavailable")
+- The "data" member contains specific error data and is defined in a
+  per-command basis, it will be an empty json-object if the error has no data
+- The "id" member contains the transaction identification associated with
+  the command execution (if issued by the Client)
+
+Some errors can occur before the Server is able to read the "id" member,
+in these cases the "id" member will not be part of the error response, even
+if provided by the client.
+
+2.5 Asynchronous events
+-----------------------
+
+As a result of state changes, the Server may send messages unilaterally
+to the Client at any time. They are called 'asynchronous events'.
+
+The format is:
+
+{ "event": json-string, "data": json-value,
+  "timestamp": { "seconds": json-number, "microseconds": json-number } }
+
+ Where,
+
+- The "event" member contains the event's name
+- The "data" member contains event specific data, which is defined in a
+  per-event basis, it is optional
+- The "timestamp" member contains the exact time of when the event ocurred
+  in the Server. It is a fixed json-object with time in seconds and
+  microseconds
+
+For a listing of supported asynchronous events, please, refer to the
+qmp-events.txt file.
+
+3. QMP Examples
+===============
+
+This section provides some examples of real QMP usage, in all of them
+'C' stands for 'Client' and 'S' stands for 'Server'.
+
+3.1 Server greeting
+-------------------
+
+S: {"QMP": {"capabilities": []}}
+
+3.2 Simple 'stop' execution
+---------------------------
+
+C: { "execute": "stop" }
+S: {"return": "OK"}
+
+3.3 KVM information
+-------------------
+
+C: {"execute": "info", "arguments": { "item": "kvm" }, "id": "example"}
+S: {"return": "enabled", "id": "example"}
+
+3.4 Bad synax error
+-------------------
+
+C: { "execute": {{{{
+S: {"error": {"class": "BadSyntax", "data": {"reason": "parsing error"}}}
+
+3.5 Powerdown event
+-------------------
+
+S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
+"POWERDOWN"}
+
+4. Notes to Client implementors
+-------------------------------
+
+4.1 It is recommended to always start the Server in pause mode, thus the
+    Client is able to perform any setup procedure without the risk of
+    race conditions or related problems
+
+4.2 It is recommended to always check the capabilities json-array, issued
+    with the greeting message, on connection time
+
+4.3 Json-objects or json-arrays mentioned in this document are not fixed
+    and no particular size or number of members/elements should be assumed.
+    New members/elements can be added at any time to any json-object or
+    json-array mentioned in this document
+
+4.4 No particular order of json-objects members should be assumed, they
+    can change at any time
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 13/15] QMP: Introduce qmp-events.txt
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (11 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 12/15] QMP: Introduce specification Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 14/15] QMP: Introduce qmp-shell Luiz Capitulino
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/qmp-events.txt |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)
 create mode 100644 QMP/qmp-events.txt

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
new file mode 100644
index 0000000..682a5e5
--- /dev/null
+++ b/QMP/qmp-events.txt
@@ -0,0 +1,26 @@
+                   QEMU Monitor Protocol: Events
+                   =============================
+
+1 SHUTDOWN
+-----------
+
+Description: Issued when the Virtual Machine is powered down.
+Data: None.
+
+2 RESET
+-------
+
+Description: Issued when the Virtual Machine is reseted.
+Data: None.
+
+3 STOP
+------
+
+Description: Issued when the Virtual Machine is stopped.
+Data: None.
+
+4 DEBUG
+-------
+
+Description: Issued when the Virtual Machine enters debug mode.
+Data: None.
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 14/15] QMP: Introduce qmp-shell
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (12 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 13/15] QMP: Introduce qmp-events.txt Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 15/15] QMP: Introduce vm-info Luiz Capitulino
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

This is a very simple shell written in Python which works
on top of QMP.

Unfortunately it's a bit awkward right now, as the user has
to specify the arguments names, for example:

(QEMU) info item=version
0.11.50
(QEMU)

Also, if the output is not a string or integer, the user is
is going to get a low-level dictionary or list.

It's worth to note that the shell is broken into two files.
One is the shell itself, the other is the QMP class which
handles the communication with QEMU.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/qmp-shell |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 QMP/qmp.py    |   54 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 0 deletions(-)
 create mode 100755 QMP/qmp-shell
 create mode 100644 QMP/qmp.py

diff --git a/QMP/qmp-shell b/QMP/qmp-shell
new file mode 100755
index 0000000..2faf79b
--- /dev/null
+++ b/QMP/qmp-shell
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+#
+# Simple QEMU shell on top of QMP
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# $ qemu [...] -monitor control,unix:./qmp,server
+#
+# Run the shell:
+#
+# $ qmp-shell ./qmp
+#
+# Commands have the following format:
+#
+# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+#
+# For example:
+#
+# (QEMU) info item=network
+#
+# Luiz Capitulino <lcapitulino@redhat.com>
+
+import qmp
+import readline
+from sys import argv,exit
+
+def shell_help():
+    print 'bye  exit from the shell'
+
+def main():
+    if len(argv) != 2:
+        print 'qemu-shell <unix-socket>'
+        exit(1)
+
+    qemu = qmp.QEMUMonitorProtocol(argv[1])
+    qemu.connect()
+
+    print 'Connected!'
+
+    while True:
+        try:
+            cmd = raw_input('(QEMU) ')
+        except EOFError:
+            print
+            break
+        if cmd == '':
+            continue
+        elif cmd == 'bye':
+            break
+        elif cmd == 'help':
+            shell_help()
+        else:
+            try:
+                resp = qemu.send(cmd)
+                if resp == None:
+                    print 'Disconnected'
+                    break
+                print resp
+            except IndexError:
+                print '-> command format: <command-name> ',
+                print '[arg-name1=arg1] ... [arg-nameN=argN]'
+
+if __name__ == '__main__':
+    main()
diff --git a/QMP/qmp.py b/QMP/qmp.py
new file mode 100644
index 0000000..c56f143
--- /dev/null
+++ b/QMP/qmp.py
@@ -0,0 +1,54 @@
+import socket, json
+
+class QMPError(Exception):
+    pass
+
+class QMPConnectError(QMPError):
+    pass
+
+class QEMUMonitorProtocol:
+    def connect(self):
+        self.sock.connect(self.filename)
+        data = self.__json_read()
+        if data == None:
+            raise QMPConnectError
+        if not data.has_key('QMP'):
+            raise QMPConnectError
+        return data['QMP']['capabilities']
+
+    def send(self, cmdline):
+        cmd = self.__build_cmd(cmdline)
+        self.__json_send(cmd)
+        resp = self.__json_read()
+        if resp == None:
+            return
+        elif resp.has_key('error'):
+            return resp['error']
+        else:
+            return resp['return']
+
+    def __build_cmd(self, cmdline):
+        cmdargs = cmdline.split()
+        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+        for arg in cmdargs[1:]:
+            opt = arg.split('=')
+            try:
+                value = int(opt[1])
+            except ValueError:
+                value = opt[1]
+            qmpcmd['arguments'][opt[0]] = value
+        return qmpcmd
+
+    def __json_send(self, cmd):
+        self.sock.send(json.dumps(cmd) + '\n')
+
+    def __json_read(self):
+        try:
+            return json.loads(self.sock.recv(1024))
+        except ValueError:
+            return
+
+    def __init__(self, filename):
+        self.filename = filename
+        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 15/15] QMP: Introduce vm-info
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (13 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 14/15] QMP: Introduce qmp-shell Luiz Capitulino
@ 2009-11-19 15:13 ` Luiz Capitulino
  2009-11-19 15:20 ` [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol Avi Kivity
  2009-11-19 17:00 ` [Qemu-devel] " Luiz Capitulino
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 15:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

A Python script which uses qmp.py to print some simple VM info.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/vm-info |   32 ++++++++++++++++++++++++++++++++
 1 files changed, 32 insertions(+), 0 deletions(-)
 create mode 100755 QMP/vm-info

diff --git a/QMP/vm-info b/QMP/vm-info
new file mode 100755
index 0000000..76a119e
--- /dev/null
+++ b/QMP/vm-info
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+#
+# Print Virtual Machine information
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# $ qemu [...] -monitor control,unix:./qmp,server
+#
+# Run vm-info:
+#
+# $ vm-info ./qmp
+#
+# Luiz Capitulino <lcapitulino@redhat.com>
+
+import qmp
+from sys import argv,exit
+
+def main():
+    if len(argv) != 2:
+        print 'vm-info <unix-socket>'
+        exit(1)
+
+    qemu = qmp.QEMUMonitorProtocol(argv[1])
+    qemu.connect()
+
+    for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]:
+        print cmd + ': ' + str(qemu.send('info item=' + cmd))
+
+if __name__ == '__main__':
+    main()
-- 
1.6.5.3.148.g785c5

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (14 preceding siblings ...)
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 15/15] QMP: Introduce vm-info Luiz Capitulino
@ 2009-11-19 15:20 ` Avi Kivity
  2009-11-19 16:47   ` Luiz Capitulino
  2009-11-19 17:00 ` [Qemu-devel] " Luiz Capitulino
  16 siblings, 1 reply; 24+ messages in thread
From: Avi Kivity @ 2009-11-19 15:20 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, qemu-devel

On 11/19/2009 05:13 PM, Luiz Capitulino wrote:
>   Hi,
>
>   This is not stable yet, it has a few bugs and a number of things to
> be done, but I'm sending it now so that it can get an initial review
> while I'm working on it.
>
>   At the end of the series there are two simple Python scripts which are
> able to talk to QEMU by using QMP.
>
>   Main issues are:
>
> o Not all errors are being detected/handled correctly
> o Not using the stream parser to read the input
>
>   If you want to try this, you need at least the latest version of QError,
> and the conversions series to make this really useful.
>    

Can you post a capture of a few monitor commands through the new protocol?

-- 
error compiling committee.c: too many arguments to function

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-19 15:20 ` [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol Avi Kivity
@ 2009-11-19 16:47   ` Luiz Capitulino
  2009-11-22  9:41     ` Avi Kivity
  0 siblings, 1 reply; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 16:47 UTC (permalink / raw)
  To: Avi Kivity; +Cc: aliguori, qemu-devel

On Thu, 19 Nov 2009 17:20:30 +0200
Avi Kivity <avi@redhat.com> wrote:

> On 11/19/2009 05:13 PM, Luiz Capitulino wrote:
> >   Hi,
> >
> >   This is not stable yet, it has a few bugs and a number of things to
> > be done, but I'm sending it now so that it can get an initial review
> > while I'm working on it.
> >
> >   At the end of the series there are two simple Python scripts which are
> > able to talk to QEMU by using QMP.
> >
> >   Main issues are:
> >
> > o Not all errors are being detected/handled correctly
> > o Not using the stream parser to read the input
> >
> >   If you want to try this, you need at least the latest version of QError,
> > and the conversions series to make this really useful.
> >    
> 
> Can you post a capture of a few monitor commands through the new protocol?

 Here goes, it's a telnet session:

"""
{"QMP": {"capabilities": []}}

{ "execute": "info", "arguments": { "item": "balloon" } }
{"return": 1024}

{ "execute": "balloon", "arguments": { "value": 512 } }
{"return": "OK"}

{ "execute": "info", "arguments": { "item": "balloon" } }
{"return": 512}

{ "execute": "info", "arguments": { "item": "network" } }
{"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}], "id": 0}]}

{ "execute": "pci_add", "arguments": { "pci_addr": "auto", "type": "nic" } }
{"return": {"bus": 0, "slot": 5, "domain": 0, "function": 0}}

{ "execute": "info", "arguments": { "item": "network" } }
{"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}, {"name": "rtl8139.0", "info": "model=rtl8139,macaddr=52:54:00:12:34:57"}], "id": 0}]}

{ "execute": "migrate", "arguments": { "detach": "-d", "uri": "tcp:localhost:4445" } }
{"error": {"class": "InvalidParameter", "data": {"parameter": "detach", "reason": "must be an integer"}}}
"""

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
                   ` (15 preceding siblings ...)
  2009-11-19 15:20 ` [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol Avi Kivity
@ 2009-11-19 17:00 ` Luiz Capitulino
  16 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-19 17:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, avi

On Thu, 19 Nov 2009 13:13:28 -0200
Luiz Capitulino <lcapitulino@redhat.com> wrote:

> o Not using the stream parser to read the input

 Just to clarify: this only means that a '\n' is required at the end of
input. This series is already capable on reading json input.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-19 16:47   ` Luiz Capitulino
@ 2009-11-22  9:41     ` Avi Kivity
  2009-11-22 15:02       ` Luiz Capitulino
  0 siblings, 1 reply; 24+ messages in thread
From: Avi Kivity @ 2009-11-22  9:41 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, qemu-devel

On 11/19/2009 06:47 PM, Luiz Capitulino wrote:
>
>> Can you post a capture of a few monitor commands through the new protocol?
>>      
>   Here goes, it's a telnet session:
>    

Looks really good, some comments below.

> """
> {"QMP": {"capabilities": []}}
>
> { "execute": "info", "arguments": { "item": "balloon" } }
> {"return": 1024}
>    

1. I see no id attribute, but it's supported, yes?
2. I asked before for info commands to be separated into individual 
commands ("query-balloon") when in machine mode.  You wouldn't write a 
function info(enum info_thing what), would you?  What would its return 
type be?
3. Quantities, for the machine protocol, should be in natural units (in 
this case, bytes).  The human interface can use kMGT and have some 
reasonable default.

> { "execute": "info", "arguments": { "item": "balloon" } }
> {"return": 512}
>
> { "execute": "info", "arguments": { "item": "network" } }
> {"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}], "id": 0}]}
>    

The internal "info" is very worrying.  We need to make sure everything 
is returned as an object without the need for additional parsing.

> { "execute": "migrate", "arguments": { "detach": "-d", "uri": "tcp:localhost:4445" } }
> {"error": {"class": "InvalidParameter", "data": {"parameter": "detach", "reason": "must be an integer"}}}
>    

I presume true and false would work here?

-- 
error compiling committee.c: too many arguments to function

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-22  9:41     ` Avi Kivity
@ 2009-11-22 15:02       ` Luiz Capitulino
  2009-11-22 16:04         ` Anthony Liguori
  0 siblings, 1 reply; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-22 15:02 UTC (permalink / raw)
  To: Avi Kivity; +Cc: aliguori, qemu-devel

On Sun, 22 Nov 2009 11:41:02 +0200
Avi Kivity <avi@redhat.com> wrote:

> On 11/19/2009 06:47 PM, Luiz Capitulino wrote:
> >
> >> Can you post a capture of a few monitor commands through the new protocol?
> >>      
> >   Here goes, it's a telnet session:
> >    
> 
> Looks really good, some comments below.
> 
> > """
> > {"QMP": {"capabilities": []}}
> >
> > { "execute": "info", "arguments": { "item": "balloon" } }
> > {"return": 1024}
> >    
> 
> 1. I see no id attribute, but it's supported, yes?

 Yes, it can be any json-value, like this real example:

{ "execute": "info", "arguments": { "item": "balloon" }, "id": "foobar" }
{"return": 1024, "id": "foobar"}

> 2. I asked before for info commands to be separated into individual 
> commands ("query-balloon") when in machine mode.  You wouldn't write a 
> function info(enum info_thing what), would you?  What would its return 
> type be?

 Yes, you're right.. I didn't do it yet because I was focusing in getting
the protocol working first.

 There is an easy way to support it though. We could add a check for
commands which start with query- and call do_info() with the
appropriate arguments.

 This way we get this syntax valid for the first merge and postpone the
Monitor refactoring to properly support it to 0.13.

 Actually, the Monitor needs a big refactoring and that was true
even before QMP.

> 3. Quantities, for the machine protocol, should be in natural units (in 
> this case, bytes).  The human interface can use kMGT and have some 
> reasonable default.

 Will fix.

> > { "execute": "info", "arguments": { "item": "balloon" } }
> > {"return": 512}
> >
> > { "execute": "info", "arguments": { "item": "network" } }
> > {"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}], "id": 0}]}
> >    
> 
> The internal "info" is very worrying.  We need to make sure everything 
> is returned as an object without the need for additional parsing.

 That's the complicated part.

 Some (several?) Monitor commands would require deeper changes to return
100% of their information in QObject style.

 This takes time for me, as I have to dig in subsystems I'm not so
familiar with and have to work on the other series too.

 So, I've chosen to do the easy conversion now so that the project
goes forward. I know this can compromise protocol stability, but I was
planning not to declare the protocol stable for 0.12.

 This is a discussion we should have.

> > { "execute": "migrate", "arguments": { "detach": "-d", "uri": "tcp:localhost:4445" } }
> > {"error": {"class": "InvalidParameter", "data": {"parameter": "detach", "reason": "must be an integer"}}}
> >    
> 
> I presume true and false would work here?

 Yes, at the time I introduced QDict I couldn't foresee that.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-22 15:02       ` Luiz Capitulino
@ 2009-11-22 16:04         ` Anthony Liguori
  2009-11-23 13:07           ` Luiz Capitulino
  0 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2009-11-22 16:04 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, Avi Kivity, qemu-devel

Luiz Capitulino wrote:
>>> { "execute": "info", "arguments": { "item": "balloon" } }
>>> {"return": 512}
>>>
>>> { "execute": "info", "arguments": { "item": "network" } }
>>> {"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}], "id": 0}]}
>>>    
>>>       
>> The internal "info" is very worrying.  We need to make sure everything 
>> is returned as an object without the need for additional parsing.
>>     
>
>  That's the complicated part.
>
>  Some (several?) Monitor commands would require deeper changes to return
> 100% of their information in QObject style.
>
>  This takes time for me, as I have to dig in subsystems I'm not so
> familiar with and have to work on the other series too.
>
>  So, I've chosen to do the easy conversion now so that the project
> goes forward. I know this can compromise protocol stability, but I was
> planning not to declare the protocol stable for 0.12.
>
>  This is a discussion we should have.
>   

We should not partially convert commands. IOW, if there still is an 
"info" output, the command is not converted and should not be exposed in 
the protocol.

I'm okay with only exposing a few functions in QMP, but I don't want to 
expose functions whose output is either not well formed or partially 
converted.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode
  2009-11-19 15:13 ` [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode Luiz Capitulino
@ 2009-11-22 18:06   ` Anthony Liguori
  0 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2009-11-22 18:06 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, qemu-devel, avi

Luiz Capitulino wrote:
> This commit adds a flag called 'control' to the '-monitor'
> command-line option. This flag enables control mode.
>
> The syntax is:
>
> qemu [...] -monitor control,<device>
>
> Where <device> is a chardev (excluding 'vc', for obvious reasons).
>
> For example:
>
> $ qemu [...] -monitor control,tcp:localhost:4444,server
>
> Will run QEMU in control mode, waiting for a client TCP connection
> on localhost port 4444.
>
> TODO: Update manpage.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  monitor.c |   18 ++++++++++++++++++
>  monitor.h |    1 +
>  vl.c      |   11 +++++++----
>  3 files changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index e7c6451..a98dc42 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -3616,6 +3616,24 @@ static void monitor_event(void *opaque, int event)
>   * End:
>   */
>  
> +const char *monitor_cmdline_parse(const char *cmdline, int *flags)
> +{
> +    const char *dev;
> +
> +    if (strstart(cmdline, "control,", &dev)) {
> +        if (strstart(dev, "vc", NULL)) {
> +            fprintf(stderr, "qemu: control mode is for low-level interaction ");
> +            fprintf(stderr, "cannot be used with device 'vc'\n");
> +            exit(1);
> +        }
> +        *flags &= ~MONITOR_USE_READLINE;
> +        *flags |= MONITOR_USE_CONTROL;
> +        return dev;
> +    }
> +
> +    return cmdline;
> +}
>   

Should use QemuOpts for this.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol
  2009-11-22 16:04         ` Anthony Liguori
@ 2009-11-23 13:07           ` Luiz Capitulino
  0 siblings, 0 replies; 24+ messages in thread
From: Luiz Capitulino @ 2009-11-23 13:07 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: aliguori, Avi Kivity, qemu-devel

On Sun, 22 Nov 2009 10:04:15 -0600
Anthony Liguori <anthony@codemonkey.ws> wrote:

> Luiz Capitulino wrote:
> >>> { "execute": "info", "arguments": { "item": "balloon" } }
> >>> {"return": 512}
> >>>
> >>> { "execute": "info", "arguments": { "item": "network" } }
> >>> {"return": [{"devices": [{"name": "user.0", "info": "net=10.0.2.0, restricted=n"}, {"name": "e1000.0", "info": "model=e1000,macaddr=52:54:00:12:34:56"}], "id": 0}]}
> >>>    
> >>>       
> >> The internal "info" is very worrying.  We need to make sure everything 
> >> is returned as an object without the need for additional parsing.
> >>     
> >
> >  That's the complicated part.
> >
> >  Some (several?) Monitor commands would require deeper changes to return
> > 100% of their information in QObject style.
> >
> >  This takes time for me, as I have to dig in subsystems I'm not so
> > familiar with and have to work on the other series too.
> >
> >  So, I've chosen to do the easy conversion now so that the project
> > goes forward. I know this can compromise protocol stability, but I was
> > planning not to declare the protocol stable for 0.12.
> >
> >  This is a discussion we should have.
> >   
> 
> We should not partially convert commands. IOW, if there still is an 
> "info" output, the command is not converted and should not be exposed in 
> the protocol.
> 
> I'm okay with only exposing a few functions in QMP, but I don't want to 
> expose functions whose output is either not well formed or partially 
> converted.

 Ok, I'll cherry-pick the fully converted ones and submit again.

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2009-11-23 13:07 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-19 15:13 [Qemu-devel] [RFC v0 00/15] QEMU Monitor Protocol Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 01/15] monitor: Introduce MONITOR_USE_CONTROL flag Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 02/15] monitor: Command-line flag to enable control mode Luiz Capitulino
2009-11-22 18:06   ` Anthony Liguori
2009-11-19 15:13 ` [Qemu-devel] [PATCH 03/15] monitor: Move handler calling code to its own function Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 04/15] QError: Add errors used by QMP Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 05/15] QMP: chardev handling Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 06/15] QMP: Output support Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 07/15] QMP: Input support Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 08/15] QMP: Asynchronous events infrastructure Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 09/15] QMP: Introduce basic asynchronous events Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 10/15] QMP: Disable monitor print functions Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 11/15] QMP: Introduce README file Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 12/15] QMP: Introduce specification Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 13/15] QMP: Introduce qmp-events.txt Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 14/15] QMP: Introduce qmp-shell Luiz Capitulino
2009-11-19 15:13 ` [Qemu-devel] [PATCH 15/15] QMP: Introduce vm-info Luiz Capitulino
2009-11-19 15:20 ` [Qemu-devel] Re: [RFC v0 00/15] QEMU Monitor Protocol Avi Kivity
2009-11-19 16:47   ` Luiz Capitulino
2009-11-22  9:41     ` Avi Kivity
2009-11-22 15:02       ` Luiz Capitulino
2009-11-22 16:04         ` Anthony Liguori
2009-11-23 13:07           ` Luiz Capitulino
2009-11-19 17:00 ` [Qemu-devel] " Luiz Capitulino

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.