mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 00:03:54 -06:00
qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first capability, "oob", to allow out-of-band messages. After this patch, we will allow QMP clients to enable QMP capabilities when sending the first "qmp_capabilities" command. Originally we are starting QMP session with no arguments like: { "execute": "qmp_capabilities" } Now we can enable some QMP capabilities using (take OOB as example, which is the only capability that we support): { "execute": "qmp_capabilities", "arguments": { "enable": [ "oob" ] } } When the "arguments" key is not provided, no capability is enabled. For capability "oob", the monitor needs to be run on a dedicated IO thread, otherwise the command will fail. For example, trying to enable OOB on a MUXed typed QMP monitor will fail. One thing to mention is that QMP capabilities are per-monitor, and also when the connection is closed due to some reason, the capabilities will be reset. Also, touch up qmp-test.c to test the new bits. Signed-off-by: Peter Xu <peterx@redhat.com> Message-Id: <20180309090006.10018-11-peterx@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [eblake: touch up commit message] Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
a5ed352596
commit
02130314d8
3 changed files with 110 additions and 9 deletions
77
monitor.c
77
monitor.c
|
@ -59,6 +59,7 @@
|
|||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
#include "qapi/qmp/json-parser.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace/control.h"
|
||||
|
@ -170,6 +171,7 @@ typedef struct {
|
|||
* mode.
|
||||
*/
|
||||
QmpCommandList *commands;
|
||||
bool qmp_caps[QMP_CAPABILITY__MAX];
|
||||
} MonitorQMP;
|
||||
|
||||
/*
|
||||
|
@ -1042,8 +1044,42 @@ static void monitor_init_qmp_commands(void)
|
|||
qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
|
||||
}
|
||||
|
||||
void qmp_qmp_capabilities(Error **errp)
|
||||
static void qmp_caps_check(Monitor *mon, QMPCapabilityList *list,
|
||||
Error **errp)
|
||||
{
|
||||
for (; list; list = list->next) {
|
||||
assert(list->value < QMP_CAPABILITY__MAX);
|
||||
switch (list->value) {
|
||||
case QMP_CAPABILITY_OOB:
|
||||
if (!mon->use_io_thr) {
|
||||
/*
|
||||
* Out-Of-Band only works with monitors that are
|
||||
* running on dedicated IOThread.
|
||||
*/
|
||||
error_setg(errp, "This monitor does not support "
|
||||
"Out-Of-Band (OOB)");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function should only be called after capabilities are checked. */
|
||||
static void qmp_caps_apply(Monitor *mon, QMPCapabilityList *list)
|
||||
{
|
||||
for (; list; list = list->next) {
|
||||
mon->qmp.qmp_caps[list->value] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (cur_mon->qmp.commands == &qmp_commands) {
|
||||
error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
|
||||
"Capabilities negotiation is already complete, command "
|
||||
|
@ -1051,6 +1087,21 @@ void qmp_qmp_capabilities(Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Enable QMP capabilities provided by the client if applicable. */
|
||||
if (has_enable) {
|
||||
qmp_caps_check(cur_mon, enable, &local_err);
|
||||
if (local_err) {
|
||||
/*
|
||||
* Failed check on any of the capabilities will fail the
|
||||
* entire command (and thus not apply any of the other
|
||||
* capabilities that were also requested).
|
||||
*/
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
qmp_caps_apply(cur_mon, enable);
|
||||
}
|
||||
|
||||
cur_mon->qmp.commands = &qmp_commands;
|
||||
}
|
||||
|
||||
|
@ -3896,14 +3947,29 @@ void monitor_resume(Monitor *mon)
|
|||
readline_show_prompt(mon->rs);
|
||||
}
|
||||
|
||||
static QObject *get_qmp_greeting(void)
|
||||
static QObject *get_qmp_greeting(Monitor *mon)
|
||||
{
|
||||
QList *cap_list = qlist_new();
|
||||
QObject *ver = NULL;
|
||||
QMPCapability cap;
|
||||
|
||||
qmp_marshal_query_version(NULL, &ver, NULL);
|
||||
|
||||
return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': []}}",
|
||||
ver);
|
||||
for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) {
|
||||
if (!mon->use_io_thr && cap == QMP_CAPABILITY_OOB) {
|
||||
/* Monitors that are not using IOThread won't support OOB */
|
||||
continue;
|
||||
}
|
||||
qlist_append(cap_list, qstring_from_str(QMPCapability_str(cap)));
|
||||
}
|
||||
|
||||
return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': %p}}",
|
||||
ver, cap_list);
|
||||
}
|
||||
|
||||
static void monitor_qmp_caps_reset(Monitor *mon)
|
||||
{
|
||||
memset(mon->qmp.qmp_caps, 0, sizeof(mon->qmp.qmp_caps));
|
||||
}
|
||||
|
||||
static void monitor_qmp_event(void *opaque, int event)
|
||||
|
@ -3914,7 +3980,8 @@ static void monitor_qmp_event(void *opaque, int event)
|
|||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
mon->qmp.commands = &qmp_cap_negotiation_commands;
|
||||
data = get_qmp_greeting();
|
||||
monitor_qmp_caps_reset(mon);
|
||||
data = get_qmp_greeting(mon);
|
||||
monitor_json_emitter(mon, data);
|
||||
qobject_decref(data);
|
||||
mon_refcount++;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue