2011-09-03 01:34:48 +08:00
|
|
|
/*
|
2019-06-13 23:33:58 +08:00
|
|
|
* Human Monitor Interface commands
|
2011-09-03 01:34:48 +08:00
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
2012-01-14 00:44:23 +08:00
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2011-09-03 01:34:48 +08:00
|
|
|
*/
|
|
|
|
|
2016-01-30 01:50:05 +08:00
|
|
|
#include "qemu/osdep.h"
|
2011-09-03 01:34:48 +08:00
|
|
|
#include "hmp.h"
|
2012-10-24 14:43:34 +08:00
|
|
|
#include "net/net.h"
|
2015-06-11 09:21:21 +08:00
|
|
|
#include "net/eth.h"
|
2017-01-26 21:19:46 +08:00
|
|
|
#include "chardev/char.h"
|
2015-02-06 02:58:22 +08:00
|
|
|
#include "sysemu/block-backend.h"
|
2017-04-18 17:40:56 +08:00
|
|
|
#include "sysemu/sysemu.h"
|
2016-12-13 01:22:24 +08:00
|
|
|
#include "qemu/config-file.h"
|
2012-12-18 01:20:00 +08:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/timer.h"
|
|
|
|
#include "qemu/sockets.h"
|
2019-06-13 23:33:59 +08:00
|
|
|
#include "monitor/monitor-internal.h"
|
2015-03-06 00:24:48 +08:00
|
|
|
#include "monitor/qdev.h"
|
2018-02-01 19:18:31 +08:00
|
|
|
#include "qapi/error.h"
|
2019-06-21 02:47:03 +08:00
|
|
|
#include "qapi/clone-visitor.h"
|
2013-12-21 06:21:10 +08:00
|
|
|
#include "qapi/opts-visitor.h"
|
2018-02-11 17:36:05 +08:00
|
|
|
#include "qapi/qapi-builtin-visit.h"
|
2018-02-27 07:13:27 +08:00
|
|
|
#include "qapi/qapi-commands-block.h"
|
|
|
|
#include "qapi/qapi-commands-char.h"
|
|
|
|
#include "qapi/qapi-commands-migration.h"
|
|
|
|
#include "qapi/qapi-commands-misc.h"
|
|
|
|
#include "qapi/qapi-commands-net.h"
|
|
|
|
#include "qapi/qapi-commands-rocker.h"
|
|
|
|
#include "qapi/qapi-commands-run-state.h"
|
|
|
|
#include "qapi/qapi-commands-tpm.h"
|
|
|
|
#include "qapi/qapi-commands-ui.h"
|
2019-06-21 02:47:03 +08:00
|
|
|
#include "qapi/qapi-visit-net.h"
|
2018-02-01 19:18:39 +08:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-18 00:22:46 +08:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2017-05-16 17:37:45 +08:00
|
|
|
#include "qapi/string-input-visitor.h"
|
2014-05-14 17:43:35 +08:00
|
|
|
#include "qapi/string-output-visitor.h"
|
2016-02-11 02:40:59 +08:00
|
|
|
#include "qom/object_interfaces.h"
|
2012-11-28 19:06:30 +08:00
|
|
|
#include "ui/console.h"
|
2017-04-26 15:36:41 +08:00
|
|
|
#include "block/nbd.h"
|
2013-06-06 12:28:00 +08:00
|
|
|
#include "block/qapi.h"
|
2013-06-05 20:19:41 +08:00
|
|
|
#include "qemu-io.h"
|
2016-03-21 01:16:19 +08:00
|
|
|
#include "qemu/cutils.h"
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 18:05:00 +08:00
|
|
|
#include "qemu/error-report.h"
|
2017-05-12 12:17:41 +08:00
|
|
|
#include "exec/ramlist.h"
|
2016-09-27 04:23:27 +08:00
|
|
|
#include "hw/intc/intc.h"
|
2019-03-11 18:29:09 +08:00
|
|
|
#include "hw/rdma/rdma.h"
|
2017-04-20 20:25:55 +08:00
|
|
|
#include "migration/snapshot.h"
|
2017-06-27 12:10:19 +08:00
|
|
|
#include "migration/misc.h"
|
2011-09-03 01:34:48 +08:00
|
|
|
|
2015-03-01 22:29:18 +08:00
|
|
|
#ifdef CONFIG_SPICE
|
|
|
|
#include <spice/enums.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-23 02:32:37 +08:00
|
|
|
static void hmp_handle_error(Monitor *mon, Error **errp)
|
|
|
|
{
|
2014-05-02 19:26:34 +08:00
|
|
|
assert(errp);
|
|
|
|
if (*errp) {
|
2019-02-12 21:47:56 +08:00
|
|
|
error_reportf_err(*errp, "Error: ");
|
2011-11-23 02:32:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-21 02:47:03 +08:00
|
|
|
/*
|
|
|
|
* Produce a strList from a comma separated list.
|
|
|
|
* A NULL or empty input string return NULL.
|
|
|
|
*/
|
|
|
|
static strList *strList_from_comma_list(const char *in)
|
|
|
|
{
|
|
|
|
strList *res = NULL;
|
|
|
|
strList **hook = &res;
|
|
|
|
|
|
|
|
while (in && in[0]) {
|
|
|
|
char *comma = strchr(in, ',');
|
|
|
|
*hook = g_new0(strList, 1);
|
|
|
|
|
|
|
|
if (comma) {
|
|
|
|
(*hook)->value = g_strndup(in, comma - in);
|
|
|
|
in = comma + 1; /* skip the , */
|
|
|
|
} else {
|
|
|
|
(*hook)->value = g_strdup(in);
|
|
|
|
in = NULL;
|
|
|
|
}
|
|
|
|
hook = &(*hook)->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_name(Monitor *mon, const QDict *qdict)
|
2011-09-03 01:34:48 +08:00
|
|
|
{
|
|
|
|
NameInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_name(NULL);
|
|
|
|
if (info->has_name) {
|
|
|
|
monitor_printf(mon, "%s\n", info->name);
|
|
|
|
}
|
|
|
|
qapi_free_NameInfo(info);
|
|
|
|
}
|
2011-08-27 04:38:13 +08:00
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_version(Monitor *mon, const QDict *qdict)
|
2011-08-27 04:38:13 +08:00
|
|
|
{
|
|
|
|
VersionInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_version(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
|
2015-05-04 23:05:31 +08:00
|
|
|
info->qemu->major, info->qemu->minor, info->qemu->micro,
|
2011-08-27 04:38:13 +08:00
|
|
|
info->package);
|
|
|
|
|
|
|
|
qapi_free_VersionInfo(info);
|
|
|
|
}
|
2011-09-13 02:10:53 +08:00
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_kvm(Monitor *mon, const QDict *qdict)
|
2011-09-13 02:10:53 +08:00
|
|
|
{
|
|
|
|
KvmInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_kvm(NULL);
|
|
|
|
monitor_printf(mon, "kvm support: ");
|
|
|
|
if (info->present) {
|
|
|
|
monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "not compiled\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_KvmInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_status(Monitor *mon, const QDict *qdict)
|
2011-09-13 04:54:20 +08:00
|
|
|
{
|
|
|
|
StatusInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_status(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "VM status: %s%s",
|
|
|
|
info->running ? "running" : "paused",
|
|
|
|
info->singlestep ? " (single step mode)" : "");
|
|
|
|
|
|
|
|
if (!info->running && info->status != RUN_STATE_PAUSED) {
|
2017-08-24 16:46:08 +08:00
|
|
|
monitor_printf(mon, " (%s)", RunState_str(info->status));
|
2011-09-13 04:54:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
|
|
|
|
qapi_free_StatusInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
|
2011-09-14 04:16:25 +08:00
|
|
|
{
|
|
|
|
UuidInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_uuid(NULL);
|
|
|
|
monitor_printf(mon, "%s\n", info->UUID);
|
|
|
|
qapi_free_UuidInfo(info);
|
|
|
|
}
|
2011-09-15 03:05:49 +08:00
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_chardev(Monitor *mon, const QDict *qdict)
|
2011-09-15 03:05:49 +08:00
|
|
|
{
|
|
|
|
ChardevInfoList *char_info, *info;
|
|
|
|
|
|
|
|
char_info = qmp_query_chardev(NULL);
|
|
|
|
for (info = char_info; info; info = info->next) {
|
|
|
|
monitor_printf(mon, "%s: filename=%s\n", info->value->label,
|
|
|
|
info->value->filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_ChardevInfoList(char_info);
|
|
|
|
}
|
2011-09-16 01:20:28 +08:00
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
2011-09-22 02:29:55 +08:00
|
|
|
{
|
|
|
|
MouseInfoList *mice_list, *mouse;
|
|
|
|
|
|
|
|
mice_list = qmp_query_mice(NULL);
|
|
|
|
if (!mice_list) {
|
|
|
|
monitor_printf(mon, "No mouse devices connected\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mouse = mice_list; mouse; mouse = mouse->next) {
|
|
|
|
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
|
|
|
mouse->value->current ? '*' : ' ',
|
|
|
|
mouse->value->index, mouse->value->name,
|
|
|
|
mouse->value->absolute ? " (absolute)" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MouseInfoList(mice_list);
|
|
|
|
}
|
|
|
|
|
2019-02-27 18:51:27 +08:00
|
|
|
static char *SocketAddress_to_str(SocketAddress *addr)
|
|
|
|
{
|
|
|
|
switch (addr->type) {
|
|
|
|
case SOCKET_ADDRESS_TYPE_INET:
|
|
|
|
return g_strdup_printf("tcp:%s:%s",
|
|
|
|
addr->u.inet.host,
|
|
|
|
addr->u.inet.port);
|
|
|
|
case SOCKET_ADDRESS_TYPE_UNIX:
|
|
|
|
return g_strdup_printf("unix:%s",
|
|
|
|
addr->u.q_unix.path);
|
|
|
|
case SOCKET_ADDRESS_TYPE_FD:
|
|
|
|
return g_strdup_printf("fd:%s", addr->u.fd.str);
|
|
|
|
case SOCKET_ADDRESS_TYPE_VSOCK:
|
|
|
|
return g_strdup_printf("tcp:%s:%s",
|
|
|
|
addr->u.vsock.cid,
|
|
|
|
addr->u.vsock.port);
|
|
|
|
default:
|
|
|
|
return g_strdup("unknown address type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
2011-09-14 04:37:16 +08:00
|
|
|
{
|
|
|
|
MigrationInfo *info;
|
2012-08-07 02:42:47 +08:00
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
2011-09-14 04:37:16 +08:00
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2012-08-07 02:42:47 +08:00
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
2017-06-27 12:10:19 +08:00
|
|
|
migration_global_dump(mon);
|
|
|
|
|
2012-08-07 02:42:47 +08:00
|
|
|
/* do not display parameters during setup */
|
|
|
|
if (info->has_status && caps) {
|
|
|
|
monitor_printf(mon, "capabilities: ");
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
|
|
|
monitor_printf(mon, "%s: %s ",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationCapability_str(cap->value->capability),
|
2012-08-07 02:42:47 +08:00
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
2011-09-14 04:37:16 +08:00
|
|
|
|
|
|
|
if (info->has_status) {
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 18:05:00 +08:00
|
|
|
monitor_printf(mon, "Migration status: %s",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationStatus_str(info->status));
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 18:05:00 +08:00
|
|
|
if (info->status == MIGRATION_STATUS_FAILED &&
|
|
|
|
info->has_error_desc) {
|
|
|
|
monitor_printf(mon, " (%s)\n", info->error_desc);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
2012-08-18 19:17:10 +08:00
|
|
|
monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
|
|
|
|
info->total_time);
|
2012-08-13 15:53:12 +08:00
|
|
|
if (info->has_expected_downtime) {
|
|
|
|
monitor_printf(mon, "expected downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->expected_downtime);
|
|
|
|
}
|
2012-08-13 15:35:16 +08:00
|
|
|
if (info->has_downtime) {
|
|
|
|
monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->downtime);
|
|
|
|
}
|
2013-07-22 22:01:58 +08:00
|
|
|
if (info->has_setup_time) {
|
|
|
|
monitor_printf(mon, "setup: %" PRIu64 " milliseconds\n",
|
|
|
|
info->setup_time);
|
|
|
|
}
|
2011-09-14 04:37:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_ram) {
|
|
|
|
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->transferred >> 10);
|
2013-06-26 09:35:30 +08:00
|
|
|
monitor_printf(mon, "throughput: %0.2f mbps\n",
|
|
|
|
info->ram->mbps);
|
2011-09-14 04:37:16 +08:00
|
|
|
monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->remaining >> 10);
|
|
|
|
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->total >> 10);
|
2012-08-07 02:42:56 +08:00
|
|
|
monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->duplicate);
|
2013-03-26 17:58:37 +08:00
|
|
|
monitor_printf(mon, "skipped: %" PRIu64 " pages\n",
|
|
|
|
info->ram->skipped);
|
2012-08-07 02:42:56 +08:00
|
|
|
monitor_printf(mon, "normal: %" PRIu64 " pages\n",
|
|
|
|
info->ram->normal);
|
|
|
|
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->normal_bytes >> 10);
|
2014-04-04 17:57:55 +08:00
|
|
|
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
|
|
|
info->ram->dirty_sync_count);
|
2017-03-21 10:22:43 +08:00
|
|
|
monitor_printf(mon, "page size: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->page_size >> 10);
|
2018-06-26 21:20:11 +08:00
|
|
|
monitor_printf(mon, "multifd bytes: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->multifd_bytes >> 10);
|
2019-01-11 14:37:30 +08:00
|
|
|
monitor_printf(mon, "pages-per-second: %" PRIu64 "\n",
|
|
|
|
info->ram->pages_per_second);
|
2017-03-21 10:22:43 +08:00
|
|
|
|
2012-08-13 18:31:25 +08:00
|
|
|
if (info->ram->dirty_pages_rate) {
|
|
|
|
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->dirty_pages_rate);
|
|
|
|
}
|
2016-06-13 19:16:42 +08:00
|
|
|
if (info->ram->postcopy_requests) {
|
|
|
|
monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
|
|
|
|
info->ram->postcopy_requests);
|
|
|
|
}
|
2011-09-14 04:37:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_disk) {
|
|
|
|
monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->transferred >> 10);
|
|
|
|
monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->remaining >> 10);
|
|
|
|
monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->total >> 10);
|
|
|
|
}
|
|
|
|
|
2012-08-07 02:42:57 +08:00
|
|
|
if (info->has_xbzrle_cache) {
|
|
|
|
monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
|
|
|
|
info->xbzrle_cache->cache_size);
|
|
|
|
monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
|
|
|
|
info->xbzrle_cache->bytes >> 10);
|
|
|
|
monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
|
|
|
|
info->xbzrle_cache->pages);
|
|
|
|
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->cache_miss);
|
2014-04-04 17:57:56 +08:00
|
|
|
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
|
|
|
info->xbzrle_cache->cache_miss_rate);
|
2012-08-07 02:42:57 +08:00
|
|
|
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->overflow);
|
|
|
|
}
|
|
|
|
|
2018-09-06 15:01:00 +08:00
|
|
|
if (info->has_compression) {
|
|
|
|
monitor_printf(mon, "compression pages: %" PRIu64 " pages\n",
|
|
|
|
info->compression->pages);
|
|
|
|
monitor_printf(mon, "compression busy: %" PRIu64 "\n",
|
|
|
|
info->compression->busy);
|
|
|
|
monitor_printf(mon, "compression busy rate: %0.2f\n",
|
|
|
|
info->compression->busy_rate);
|
|
|
|
monitor_printf(mon, "compressed size: %" PRIu64 "\n",
|
|
|
|
info->compression->compressed_size);
|
|
|
|
monitor_printf(mon, "compression rate: %0.2f\n",
|
|
|
|
info->compression->compression_rate);
|
|
|
|
}
|
|
|
|
|
2016-04-22 02:07:18 +08:00
|
|
|
if (info->has_cpu_throttle_percentage) {
|
2015-09-09 01:12:36 +08:00
|
|
|
monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n",
|
2016-04-22 02:07:18 +08:00
|
|
|
info->cpu_throttle_percentage);
|
2015-09-09 01:12:36 +08:00
|
|
|
}
|
|
|
|
|
2018-03-23 02:17:27 +08:00
|
|
|
if (info->has_postcopy_blocktime) {
|
|
|
|
monitor_printf(mon, "postcopy blocktime: %u\n",
|
|
|
|
info->postcopy_blocktime);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_postcopy_vcpu_blocktime) {
|
|
|
|
Visitor *v;
|
|
|
|
char *str;
|
|
|
|
v = string_output_visitor_new(false, &str);
|
|
|
|
visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, NULL);
|
|
|
|
visit_complete(v, &str);
|
|
|
|
monitor_printf(mon, "postcopy vcpu blocktime: %s\n", str);
|
|
|
|
g_free(str);
|
|
|
|
visit_free(v);
|
|
|
|
}
|
2019-02-27 18:51:27 +08:00
|
|
|
if (info->has_socket_address) {
|
|
|
|
SocketAddressList *addr;
|
|
|
|
|
|
|
|
monitor_printf(mon, "socket address: [\n");
|
|
|
|
|
|
|
|
for (addr = info->socket_address; addr; addr = addr->next) {
|
|
|
|
char *s = SocketAddress_to_str(addr->value);
|
|
|
|
monitor_printf(mon, "\t%s\n", s);
|
|
|
|
g_free(s);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "]\n");
|
|
|
|
}
|
2011-09-14 04:37:16 +08:00
|
|
|
qapi_free_MigrationInfo(info);
|
2012-08-07 02:42:47 +08:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
|
2012-08-07 02:42:47 +08:00
|
|
|
{
|
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
|
|
|
|
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
|
|
|
if (caps) {
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
2017-04-01 16:18:44 +08:00
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationCapability_str(cap->value->capability),
|
2012-08-07 02:42:47 +08:00
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2011-09-14 04:37:16 +08:00
|
|
|
}
|
|
|
|
|
2015-03-23 16:32:29 +08:00
|
|
|
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
MigrationParameters *params;
|
|
|
|
|
|
|
|
params = qmp_query_migrate_parameters(NULL);
|
|
|
|
|
|
|
|
if (params) {
|
2019-02-27 21:24:06 +08:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL),
|
|
|
|
params->announce_initial);
|
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX),
|
|
|
|
params->announce_max);
|
|
|
|
monitor_printf(mon, "%s: %" PRIu64 "\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS),
|
|
|
|
params->announce_rounds);
|
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP),
|
|
|
|
params->announce_step);
|
2016-09-09 11:14:15 +08:00
|
|
|
assert(params->has_compress_level);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL),
|
2015-03-23 16:32:29 +08:00
|
|
|
params->compress_level);
|
2016-09-09 11:14:15 +08:00
|
|
|
assert(params->has_compress_threads);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_THREADS),
|
2015-03-23 16:32:29 +08:00
|
|
|
params->compress_threads);
|
2018-08-21 16:10:20 +08:00
|
|
|
assert(params->has_compress_wait_thread);
|
|
|
|
monitor_printf(mon, "%s: %s\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD),
|
|
|
|
params->compress_wait_thread ? "on" : "off");
|
2016-09-09 11:14:15 +08:00
|
|
|
assert(params->has_decompress_threads);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS),
|
2015-03-23 16:32:29 +08:00
|
|
|
params->decompress_threads);
|
2016-09-09 11:14:15 +08:00
|
|
|
assert(params->has_cpu_throttle_initial);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL),
|
2016-04-22 02:07:18 +08:00
|
|
|
params->cpu_throttle_initial);
|
2016-09-09 11:14:15 +08:00
|
|
|
assert(params->has_cpu_throttle_increment);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT),
|
2016-04-22 02:07:18 +08:00
|
|
|
params->cpu_throttle_increment);
|
2018-08-01 21:00:20 +08:00
|
|
|
assert(params->has_max_cpu_throttle);
|
|
|
|
monitor_printf(mon, "%s: %u\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE),
|
|
|
|
params->max_cpu_throttle);
|
2017-07-18 18:04:54 +08:00
|
|
|
assert(params->has_tls_creds);
|
2017-04-01 16:18:45 +08:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
|
2017-07-18 18:04:54 +08:00
|
|
|
params->tls_creds);
|
|
|
|
assert(params->has_tls_hostname);
|
2017-04-01 16:18:45 +08:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
|
2017-07-18 18:04:54 +08:00
|
|
|
params->tls_hostname);
|
2016-09-16 00:20:28 +08:00
|
|
|
assert(params->has_max_bandwidth);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
|
2016-09-16 00:20:28 +08:00
|
|
|
params->max_bandwidth);
|
|
|
|
assert(params->has_downtime_limit);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " milliseconds\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT),
|
2016-09-16 00:20:28 +08:00
|
|
|
params->downtime_limit);
|
2016-11-02 15:42:09 +08:00
|
|
|
assert(params->has_x_checkpoint_delay);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY),
|
2016-10-27 14:43:01 +08:00
|
|
|
params->x_checkpoint_delay);
|
2017-04-06 00:32:37 +08:00
|
|
|
assert(params->has_block_incremental);
|
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL),
|
|
|
|
params->block_incremental ? "on" : "off");
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2019-02-06 20:54:06 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS),
|
|
|
|
params->multifd_channels);
|
2017-12-01 20:08:38 +08:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 "\n",
|
2017-10-06 03:30:10 +08:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
|
|
|
|
params->xbzrle_cache_size);
|
2018-06-13 18:26:40 +08:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 "\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
|
|
|
|
params->max_postcopy_bandwidth);
|
migration: add support for a "tls-authz" migration parameter
The QEMU instance that runs as the server for the migration data
transport (ie the target QEMU) needs to be able to configure access
control so it can prevent unauthorized clients initiating an incoming
migration. This adds a new 'tls-authz' migration parameter that is used
to provide the QOM ID of a QAuthZ subclass instance that provides the
access control check. This is checked against the x509 certificate
obtained during the TLS handshake.
For example, when starting a QEMU for incoming migration, it is
possible to give an example identity of the source QEMU that is
intended to be connecting later:
$QEMU \
-monitor stdio \
-incoming defer \
...other args...
(qemu) object_add tls-creds-x509,id=tls0,dir=/home/berrange/qemutls,\
endpoint=server,verify-peer=yes \
(qemu) object_add authz-simple,id=auth0,identity=CN=laptop.example.com,,\
O=Example Org,,L=London,,ST=London,,C=GB \
(qemu) migrate_incoming tcp:localhost:9000
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2019-02-27 22:53:24 +08:00
|
|
|
monitor_printf(mon, " %s: '%s'\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
|
|
|
|
params->has_tls_authz ? params->tls_authz : "");
|
2015-03-23 16:32:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationParameters(params);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict)
|
2012-08-07 02:42:54 +08:00
|
|
|
{
|
|
|
|
monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
|
|
|
|
qmp_query_migrate_cache_size(NULL) >> 10);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
2011-09-22 03:38:35 +08:00
|
|
|
{
|
2018-02-17 00:08:41 +08:00
|
|
|
CpuInfoFastList *cpu_list, *cpu;
|
2011-09-22 03:38:35 +08:00
|
|
|
|
2018-02-17 00:08:41 +08:00
|
|
|
cpu_list = qmp_query_cpus_fast(NULL);
|
2011-09-22 03:38:35 +08:00
|
|
|
|
|
|
|
for (cpu = cpu_list; cpu; cpu = cpu->next) {
|
|
|
|
int active = ' ';
|
|
|
|
|
2018-02-17 00:08:41 +08:00
|
|
|
if (cpu->value->cpu_index == monitor_get_cpu_index()) {
|
2011-09-22 03:38:35 +08:00
|
|
|
active = '*';
|
|
|
|
}
|
|
|
|
|
2018-02-17 00:08:41 +08:00
|
|
|
monitor_printf(mon, "%c CPU #%" PRId64 ":", active,
|
|
|
|
cpu->value->cpu_index);
|
2018-03-27 20:38:00 +08:00
|
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
|
2011-09-22 03:38:35 +08:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:08:41 +08:00
|
|
|
qapi_free_CpuInfoFastList(cpu_list);
|
2011-09-22 03:38:35 +08:00
|
|
|
}
|
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
static void print_block_info(Monitor *mon, BlockInfo *info,
|
|
|
|
BlockDeviceInfo *inserted, bool verbose)
|
2011-09-22 04:16:47 +08:00
|
|
|
{
|
2013-06-06 12:28:00 +08:00
|
|
|
ImageInfo *image_info;
|
2011-09-22 04:16:47 +08:00
|
|
|
|
2014-09-15 18:12:52 +08:00
|
|
|
assert(!info || !info->has_inserted || info->inserted == inserted);
|
|
|
|
|
2017-07-11 20:00:57 +08:00
|
|
|
if (info && *info->device) {
|
2014-09-15 18:12:52 +08:00
|
|
|
monitor_printf(mon, "%s", info->device);
|
|
|
|
if (inserted && inserted->has_node_name) {
|
|
|
|
monitor_printf(mon, " (%s)", inserted->node_name);
|
|
|
|
}
|
|
|
|
} else {
|
2017-07-11 20:00:57 +08:00
|
|
|
assert(info || inserted);
|
2014-09-15 18:12:52 +08:00
|
|
|
monitor_printf(mon, "%s",
|
2017-07-11 20:00:57 +08:00
|
|
|
inserted && inserted->has_node_name ? inserted->node_name
|
|
|
|
: info && info->has_qdev ? info->qdev
|
2014-09-15 18:12:52 +08:00
|
|
|
: "<anonymous>");
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
if (inserted) {
|
|
|
|
monitor_printf(mon, ": %s (%s%s%s)\n",
|
|
|
|
inserted->file,
|
|
|
|
inserted->drv,
|
|
|
|
inserted->ro ? ", read-only" : "",
|
|
|
|
inserted->encrypted ? ", encrypted" : "");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, ": [not inserted]\n");
|
|
|
|
}
|
2011-09-22 04:16:47 +08:00
|
|
|
|
2014-09-15 18:12:52 +08:00
|
|
|
if (info) {
|
2017-07-11 19:27:38 +08:00
|
|
|
if (info->has_qdev) {
|
|
|
|
monitor_printf(mon, " Attached to: %s\n", info->qdev);
|
|
|
|
}
|
2014-09-15 18:12:52 +08:00
|
|
|
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
|
|
|
monitor_printf(mon, " I/O status: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
BlockDeviceIoStatus_str(info->io_status));
|
2014-09-15 18:12:52 +08:00
|
|
|
}
|
2011-09-22 04:16:47 +08:00
|
|
|
|
2014-09-15 18:12:52 +08:00
|
|
|
if (info->removable) {
|
|
|
|
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
|
|
|
info->locked ? "" : "not ",
|
|
|
|
info->tray_open ? "open" : "closed");
|
|
|
|
}
|
2014-09-15 18:06:39 +08:00
|
|
|
}
|
2013-06-19 22:10:55 +08:00
|
|
|
|
2011-09-22 04:16:47 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
if (!inserted) {
|
|
|
|
return;
|
|
|
|
}
|
2011-09-22 04:16:47 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
monitor_printf(mon, " Cache mode: %s%s%s\n",
|
|
|
|
inserted->cache->writeback ? "writeback" : "writethrough",
|
|
|
|
inserted->cache->direct ? ", direct" : "",
|
|
|
|
inserted->cache->no_flush ? ", ignore flushes" : "");
|
|
|
|
|
|
|
|
if (inserted->has_backing_file) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
" Backing file: %s "
|
|
|
|
"(chain depth: %" PRId64 ")\n",
|
|
|
|
inserted->backing_file,
|
|
|
|
inserted->backing_file_depth);
|
|
|
|
}
|
2011-11-08 13:00:31 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
|
|
|
monitor_printf(mon, " Detect zeroes: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
BlockdevDetectZeroesOptions_str(inserted->detect_zeroes));
|
2014-09-15 18:06:39 +08:00
|
|
|
}
|
2013-06-19 22:10:55 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
|
|
|
|
inserted->iops || inserted->iops_rd || inserted->iops_wr)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
|
|
|
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
|
|
|
" bps_max=%" PRId64
|
|
|
|
" bps_rd_max=%" PRId64
|
|
|
|
" bps_wr_max=%" PRId64
|
|
|
|
" iops=%" PRId64 " iops_rd=%" PRId64
|
|
|
|
" iops_wr=%" PRId64
|
|
|
|
" iops_max=%" PRId64
|
|
|
|
" iops_rd_max=%" PRId64
|
|
|
|
" iops_wr_max=%" PRId64
|
2015-06-09 00:17:46 +08:00
|
|
|
" iops_size=%" PRId64
|
|
|
|
" group=%s\n",
|
2014-09-15 18:06:39 +08:00
|
|
|
inserted->bps,
|
|
|
|
inserted->bps_rd,
|
|
|
|
inserted->bps_wr,
|
|
|
|
inserted->bps_max,
|
|
|
|
inserted->bps_rd_max,
|
|
|
|
inserted->bps_wr_max,
|
|
|
|
inserted->iops,
|
|
|
|
inserted->iops_rd,
|
|
|
|
inserted->iops_wr,
|
|
|
|
inserted->iops_max,
|
|
|
|
inserted->iops_rd_max,
|
|
|
|
inserted->iops_wr_max,
|
2015-06-09 00:17:46 +08:00
|
|
|
inserted->iops_size,
|
|
|
|
inserted->group);
|
2014-09-15 18:06:39 +08:00
|
|
|
}
|
2013-06-19 22:10:55 +08:00
|
|
|
|
2015-04-22 18:15:10 +08:00
|
|
|
if (verbose) {
|
2014-09-15 18:06:39 +08:00
|
|
|
monitor_printf(mon, "\nImages:\n");
|
|
|
|
image_info = inserted->image;
|
|
|
|
while (1) {
|
2019-04-18 03:17:55 +08:00
|
|
|
bdrv_image_info_dump(image_info);
|
2014-09-15 18:06:39 +08:00
|
|
|
if (image_info->has_backing_image) {
|
|
|
|
image_info = image_info->backing_image;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-22 19:28:45 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockInfoList *block_list, *info;
|
2014-09-15 18:19:14 +08:00
|
|
|
BlockDeviceInfoList *blockdev_list, *blockdev;
|
2014-09-15 18:06:39 +08:00
|
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool verbose = qdict_get_try_bool(qdict, "verbose", false);
|
|
|
|
bool nodes = qdict_get_try_bool(qdict, "nodes", false);
|
2014-09-15 18:19:14 +08:00
|
|
|
bool printed = false;
|
2014-05-22 19:28:45 +08:00
|
|
|
|
2014-09-15 18:19:14 +08:00
|
|
|
/* Print BlockBackend information */
|
|
|
|
if (!nodes) {
|
2015-02-08 22:40:48 +08:00
|
|
|
block_list = qmp_query_block(NULL);
|
2014-09-15 18:19:14 +08:00
|
|
|
} else {
|
|
|
|
block_list = NULL;
|
|
|
|
}
|
2013-06-19 22:10:55 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (device && strcmp(device, info->value->device)) {
|
|
|
|
continue;
|
2014-05-18 06:58:19 +08:00
|
|
|
}
|
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
if (info != block_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
2013-06-19 22:10:55 +08:00
|
|
|
}
|
2013-06-06 12:28:00 +08:00
|
|
|
|
2014-09-15 18:06:39 +08:00
|
|
|
print_block_info(mon, info->value, info->value->has_inserted
|
|
|
|
? info->value->inserted : NULL,
|
|
|
|
verbose);
|
2014-09-15 18:19:14 +08:00
|
|
|
printed = true;
|
2011-09-22 04:16:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
2014-09-15 18:19:14 +08:00
|
|
|
|
|
|
|
if ((!device && !nodes) || printed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print node information */
|
|
|
|
blockdev_list = qmp_query_named_block_nodes(NULL);
|
|
|
|
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
|
|
|
|
assert(blockdev->value->has_node_name);
|
|
|
|
if (device && strcmp(device, blockdev->value->node_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blockdev != blockdev_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
print_block_info(mon, NULL, blockdev->value, verbose);
|
|
|
|
}
|
|
|
|
qapi_free_BlockDeviceInfoList(blockdev_list);
|
2011-09-22 04:16:47 +08:00
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
2011-09-23 02:56:36 +08:00
|
|
|
{
|
|
|
|
BlockStatsList *stats_list, *stats;
|
|
|
|
|
2014-10-31 11:32:57 +08:00
|
|
|
stats_list = qmp_query_blockstats(false, false, NULL);
|
2011-09-23 02:56:36 +08:00
|
|
|
|
|
|
|
for (stats = stats_list; stats; stats = stats->next) {
|
|
|
|
if (!stats->value->has_device) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:", stats->value->device);
|
|
|
|
monitor_printf(mon, " rd_bytes=%" PRId64
|
|
|
|
" wr_bytes=%" PRId64
|
|
|
|
" rd_operations=%" PRId64
|
|
|
|
" wr_operations=%" PRId64
|
|
|
|
" flush_operations=%" PRId64
|
|
|
|
" wr_total_time_ns=%" PRId64
|
|
|
|
" rd_total_time_ns=%" PRId64
|
|
|
|
" flush_total_time_ns=%" PRId64
|
2015-02-02 21:52:18 +08:00
|
|
|
" rd_merged=%" PRId64
|
|
|
|
" wr_merged=%" PRId64
|
2015-10-28 23:33:02 +08:00
|
|
|
" idle_time_ns=%" PRId64
|
2011-09-23 02:56:36 +08:00
|
|
|
"\n",
|
|
|
|
stats->value->stats->rd_bytes,
|
|
|
|
stats->value->stats->wr_bytes,
|
|
|
|
stats->value->stats->rd_operations,
|
|
|
|
stats->value->stats->wr_operations,
|
|
|
|
stats->value->stats->flush_operations,
|
|
|
|
stats->value->stats->wr_total_time_ns,
|
|
|
|
stats->value->stats->rd_total_time_ns,
|
2015-02-02 21:52:18 +08:00
|
|
|
stats->value->stats->flush_total_time_ns,
|
|
|
|
stats->value->stats->rd_merged,
|
2015-10-28 23:33:02 +08:00
|
|
|
stats->value->stats->wr_merged,
|
|
|
|
stats->value->stats->idle_time_ns);
|
2011-09-23 02:56:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockStatsList(stats_list);
|
|
|
|
}
|
|
|
|
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
#ifdef CONFIG_VNC
|
2017-07-11 23:44:14 +08:00
|
|
|
/* Helper for hmp_info_vnc_clients, _servers */
|
|
|
|
static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, " %s: %s:%s (%s%s)\n",
|
|
|
|
name,
|
|
|
|
info->host,
|
|
|
|
info->service,
|
2017-08-24 16:46:08 +08:00
|
|
|
NetworkAddressFamily_str(info->family),
|
2017-07-11 23:44:14 +08:00
|
|
|
info->websocket ? " (Websocket)" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Helper displaying and auth and crypt info */
|
|
|
|
static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent,
|
|
|
|
VncPrimaryAuth auth,
|
|
|
|
VncVencryptSubAuth *vencrypt)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent,
|
2017-08-24 16:46:08 +08:00
|
|
|
VncPrimaryAuth_str(auth),
|
|
|
|
vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none");
|
2017-07-11 23:44:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client)
|
|
|
|
{
|
|
|
|
while (client) {
|
|
|
|
VncClientInfo *cinfo = client->value;
|
|
|
|
|
|
|
|
hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client");
|
|
|
|
monitor_printf(mon, " x509_dname: %s\n",
|
|
|
|
cinfo->has_x509_dname ?
|
|
|
|
cinfo->x509_dname : "none");
|
|
|
|
monitor_printf(mon, " sasl_username: %s\n",
|
|
|
|
cinfo->has_sasl_username ?
|
|
|
|
cinfo->sasl_username : "none");
|
|
|
|
|
|
|
|
client = client->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server)
|
|
|
|
{
|
|
|
|
while (server) {
|
|
|
|
VncServerInfo2 *sinfo = server->value;
|
|
|
|
hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server");
|
|
|
|
hmp_info_vnc_authcrypt(mon, " ", sinfo->auth,
|
|
|
|
sinfo->has_vencrypt ? &sinfo->vencrypt : NULL);
|
|
|
|
server = server->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
2011-10-18 02:41:22 +08:00
|
|
|
{
|
2017-07-11 23:44:14 +08:00
|
|
|
VncInfo2List *info2l;
|
2011-10-18 02:41:22 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2017-07-11 23:44:14 +08:00
|
|
|
info2l = qmp_query_vnc_servers(&err);
|
2011-10-18 02:41:22 +08:00
|
|
|
if (err) {
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-10-18 02:41:22 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-07-11 23:44:14 +08:00
|
|
|
if (!info2l) {
|
|
|
|
monitor_printf(mon, "None\n");
|
|
|
|
return;
|
2011-10-18 02:41:22 +08:00
|
|
|
}
|
|
|
|
|
2017-07-11 23:44:14 +08:00
|
|
|
while (info2l) {
|
|
|
|
VncInfo2 *info = info2l->value;
|
|
|
|
monitor_printf(mon, "%s:\n", info->id);
|
|
|
|
hmp_info_vnc_servers(mon, info->server);
|
|
|
|
hmp_info_vnc_clients(mon, info->clients);
|
|
|
|
if (!info->server) {
|
|
|
|
/* The server entry displays its auth, we only
|
|
|
|
* need to display in the case of 'reverse' connections
|
|
|
|
* where there's no server.
|
|
|
|
*/
|
|
|
|
hmp_info_vnc_authcrypt(mon, " ", info->auth,
|
|
|
|
info->has_vencrypt ? &info->vencrypt : NULL);
|
|
|
|
}
|
|
|
|
if (info->has_display) {
|
|
|
|
monitor_printf(mon, " Display: %s\n", info->display);
|
2011-10-18 02:41:22 +08:00
|
|
|
}
|
2017-07-11 23:44:14 +08:00
|
|
|
info2l = info2l->next;
|
2011-10-18 02:41:22 +08:00
|
|
|
}
|
|
|
|
|
2017-07-11 23:44:14 +08:00
|
|
|
qapi_free_VncInfo2List(info2l);
|
|
|
|
|
2011-10-18 02:41:22 +08:00
|
|
|
}
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
#endif
|
2011-10-18 02:41:22 +08:00
|
|
|
|
2015-01-13 22:46:39 +08:00
|
|
|
#ifdef CONFIG_SPICE
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
2011-10-21 03:01:33 +08:00
|
|
|
{
|
|
|
|
SpiceChannelList *chan;
|
|
|
|
SpiceInfo *info;
|
2015-03-01 22:29:18 +08:00
|
|
|
const char *channel_name;
|
|
|
|
const char * const channel_names[] = {
|
|
|
|
[SPICE_CHANNEL_MAIN] = "main",
|
|
|
|
[SPICE_CHANNEL_DISPLAY] = "display",
|
|
|
|
[SPICE_CHANNEL_INPUTS] = "inputs",
|
|
|
|
[SPICE_CHANNEL_CURSOR] = "cursor",
|
|
|
|
[SPICE_CHANNEL_PLAYBACK] = "playback",
|
|
|
|
[SPICE_CHANNEL_RECORD] = "record",
|
|
|
|
[SPICE_CHANNEL_TUNNEL] = "tunnel",
|
|
|
|
[SPICE_CHANNEL_SMARTCARD] = "smartcard",
|
|
|
|
[SPICE_CHANNEL_USBREDIR] = "usbredir",
|
|
|
|
[SPICE_CHANNEL_PORT] = "port",
|
2015-03-03 16:27:28 +08:00
|
|
|
#if 0
|
|
|
|
/* minimum spice-protocol is 0.12.3, webdav was added in 0.12.7,
|
|
|
|
* no easy way to #ifdef (SPICE_CHANNEL_* is a enum). Disable
|
|
|
|
* as quick fix for build failures with older versions. */
|
2015-03-01 22:29:18 +08:00
|
|
|
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
2015-03-03 16:27:28 +08:00
|
|
|
#endif
|
2015-03-01 22:29:18 +08:00
|
|
|
};
|
2011-10-21 03:01:33 +08:00
|
|
|
|
|
|
|
info = qmp_query_spice(NULL);
|
|
|
|
|
|
|
|
if (!info->enabled) {
|
|
|
|
monitor_printf(mon, "Server: disabled\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "Server:\n");
|
|
|
|
if (info->has_port) {
|
|
|
|
monitor_printf(mon, " address: %s:%" PRId64 "\n",
|
|
|
|
info->host, info->port);
|
|
|
|
}
|
|
|
|
if (info->has_tls_port) {
|
|
|
|
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
|
|
|
info->host, info->tls_port);
|
|
|
|
}
|
2012-08-21 16:51:58 +08:00
|
|
|
monitor_printf(mon, " migrated: %s\n",
|
|
|
|
info->migrated ? "true" : "false");
|
2011-10-21 03:01:33 +08:00
|
|
|
monitor_printf(mon, " auth: %s\n", info->auth);
|
|
|
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
2012-03-30 05:23:14 +08:00
|
|
|
monitor_printf(mon, " mouse-mode: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
SpiceQueryMouseMode_str(info->mouse_mode));
|
2011-10-21 03:01:33 +08:00
|
|
|
|
|
|
|
if (!info->has_channels || info->channels == NULL) {
|
|
|
|
monitor_printf(mon, "Channels: none\n");
|
|
|
|
} else {
|
|
|
|
for (chan = info->channels; chan; chan = chan->next) {
|
|
|
|
monitor_printf(mon, "Channel:\n");
|
|
|
|
monitor_printf(mon, " address: %s:%s%s\n",
|
qapi: Unbox base members
Rather than storing a base class as a pointer to a box, just
store the fields of that base class in the same order, so that
a child struct can be directly cast to its parent. This gives
less malloc overhead, less pointer dereferencing, and even less
generated code. Compare to the earlier commit 1e6c1616a "qapi:
Generate a nicer struct for flat unions" (although that patch
had fewer places to change, as less of qemu was directly using
qapi structs for flat unions). It also allows us to turn on
automatic type-safe wrappers for upcasting to the base class
of a struct.
Changes to the generated code look like this in qapi-types.h:
| struct SpiceChannel {
|- SpiceBasicInfo *base;
|+ /* Members inherited from SpiceBasicInfo: */
|+ char *host;
|+ char *port;
|+ NetworkAddressFamily family;
|+ /* Own members: */
| int64_t connection_id;
as well as additional upcast functions like qapi_SpiceChannel_base().
Meanwhile, changes to qapi-visit.c look like:
| static void visit_type_SpiceChannel_fields(Visitor *v, SpiceChannel **obj, Error **errp)
| {
| Error *err = NULL;
|
|- visit_type_implicit_SpiceBasicInfo(v, &(*obj)->base, &err);
|+ visit_type_SpiceBasicInfo_fields(v, (SpiceBasicInfo **)obj, &err);
| if (err) {
(the cast is necessary, since our upcast wrappers only deal with a
single pointer, not pointer-to-pointer); plus the wholesale
elimination of some now-unused visit_type_implicit_FOO() functions.
Without boxing, the corner case of one empty struct having
another empty struct as its base type now requires inserting a
dummy member (previously, the 'Base *base' member sufficed).
And now that we no longer consume a 'base' member in the generated
C struct, we can delete the former negative struct-base-clash-base
test.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1445898903-12082-11-git-send-email-eblake@redhat.com>
[Commit message tweaked slightly]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-27 06:34:49 +08:00
|
|
|
chan->value->host, chan->value->port,
|
2011-10-21 03:01:33 +08:00
|
|
|
chan->value->tls ? " [tls]" : "");
|
|
|
|
monitor_printf(mon, " session: %" PRId64 "\n",
|
|
|
|
chan->value->connection_id);
|
|
|
|
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
|
|
|
|
chan->value->channel_type, chan->value->channel_id);
|
2015-03-01 22:29:18 +08:00
|
|
|
|
|
|
|
channel_name = "unknown";
|
|
|
|
if (chan->value->channel_type > 0 &&
|
|
|
|
chan->value->channel_type < ARRAY_SIZE(channel_names) &&
|
|
|
|
channel_names[chan->value->channel_type]) {
|
|
|
|
channel_name = channel_names[chan->value->channel_type];
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " channel name: %s\n", channel_name);
|
2011-10-21 03:01:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_SpiceInfo(info);
|
|
|
|
}
|
2015-01-13 22:46:39 +08:00
|
|
|
#endif
|
2011-10-21 03:01:33 +08:00
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
2011-10-21 21:41:37 +08:00
|
|
|
{
|
|
|
|
BalloonInfo *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
info = qmp_query_balloon(&err);
|
|
|
|
if (err) {
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-10-21 21:41:37 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-04 01:56:41 +08:00
|
|
|
monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
|
2011-10-21 21:41:37 +08:00
|
|
|
|
|
|
|
qapi_free_BalloonInfo(info);
|
|
|
|
}
|
|
|
|
|
2011-10-22 00:15:33 +08:00
|
|
|
static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
|
|
|
|
{
|
|
|
|
PciMemoryRegionList *region;
|
|
|
|
|
|
|
|
monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus);
|
|
|
|
monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
|
|
|
|
dev->slot, dev->function);
|
|
|
|
monitor_printf(mon, " ");
|
|
|
|
|
2015-05-04 23:05:32 +08:00
|
|
|
if (dev->class_info->has_desc) {
|
|
|
|
monitor_printf(mon, "%s", dev->class_info->desc);
|
2011-10-22 00:15:33 +08:00
|
|
|
} else {
|
2015-05-04 23:05:32 +08:00
|
|
|
monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class);
|
2011-10-22 00:15:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->id->vendor, dev->id->device);
|
2018-10-02 21:55:38 +08:00
|
|
|
if (dev->id->has_subsystem_vendor && dev->id->has_subsystem) {
|
|
|
|
monitor_printf(mon, " PCI subsystem %04" PRIx64 ":%04" PRIx64 "\n",
|
|
|
|
dev->id->subsystem_vendor, dev->id->subsystem);
|
|
|
|
}
|
2011-10-22 00:15:33 +08:00
|
|
|
|
|
|
|
if (dev->has_irq) {
|
|
|
|
monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->has_pci_bridge) {
|
|
|
|
monitor_printf(mon, " BUS %" PRId64 ".\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->number);
|
2011-10-22 00:15:33 +08:00
|
|
|
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->secondary);
|
2011-10-22 00:15:33 +08:00
|
|
|
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->subordinate);
|
2011-10-22 00:15:33 +08:00
|
|
|
|
|
|
|
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->io_range->base,
|
|
|
|
dev->pci_bridge->bus->io_range->limit);
|
2011-10-22 00:15:33 +08:00
|
|
|
|
|
|
|
monitor_printf(mon,
|
|
|
|
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->memory_range->base,
|
|
|
|
dev->pci_bridge->bus->memory_range->limit);
|
2011-10-22 00:15:33 +08:00
|
|
|
|
|
|
|
monitor_printf(mon, " prefetchable memory range "
|
|
|
|
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 23:05:32 +08:00
|
|
|
dev->pci_bridge->bus->prefetchable_range->base,
|
|
|
|
dev->pci_bridge->bus->prefetchable_range->limit);
|
2011-10-22 00:15:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (region = dev->regions; region; region = region->next) {
|
|
|
|
uint64_t addr, size;
|
|
|
|
|
|
|
|
addr = region->value->address;
|
|
|
|
size = region->value->size;
|
|
|
|
|
|
|
|
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
|
|
|
|
|
|
|
|
if (!strcmp(region->value->type, "io")) {
|
|
|
|
monitor_printf(mon, "I/O at 0x%04" PRIx64
|
|
|
|
" [0x%04" PRIx64 "].\n",
|
|
|
|
addr, addr + size - 1);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
|
|
|
|
" [0x%08" PRIx64 "].\n",
|
|
|
|
region->value->mem_type_64 ? 64 : 32,
|
|
|
|
region->value->prefetch ? " prefetchable" : "",
|
|
|
|
addr, addr + size - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " id \"%s\"\n", dev->qdev_id);
|
|
|
|
|
|
|
|
if (dev->has_pci_bridge) {
|
|
|
|
if (dev->pci_bridge->has_devices) {
|
|
|
|
PciDeviceInfoList *cdev;
|
|
|
|
for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
|
|
|
|
hmp_info_pci_device(mon, cdev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 04:23:27 +08:00
|
|
|
static int hmp_info_irq_foreach(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
InterruptStatsProvider *intc;
|
|
|
|
InterruptStatsProviderClass *k;
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
|
|
|
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
|
|
|
intc = INTERRUPT_STATS_PROVIDER(obj);
|
|
|
|
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
|
|
|
uint64_t *irq_counts;
|
|
|
|
unsigned int nb_irqs, i;
|
|
|
|
if (k->get_statistics &&
|
|
|
|
k->get_statistics(intc, &irq_counts, &nb_irqs)) {
|
|
|
|
if (nb_irqs > 0) {
|
|
|
|
monitor_printf(mon, "IRQ statistics for %s:\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
for (i = 0; i < nb_irqs; i++) {
|
|
|
|
if (irq_counts[i] > 0) {
|
|
|
|
monitor_printf(mon, "%2d: %" PRId64 "\n", i,
|
|
|
|
irq_counts[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "IRQ statistics not available for %s.\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
object_child_foreach_recursive(object_get_root(),
|
|
|
|
hmp_info_irq_foreach, mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hmp_info_pic_foreach(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
InterruptStatsProvider *intc;
|
|
|
|
InterruptStatsProviderClass *k;
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
|
|
|
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
|
|
|
intc = INTERRUPT_STATS_PROVIDER(obj);
|
|
|
|
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
|
|
|
if (k->print_info) {
|
|
|
|
k->print_info(intc, mon);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Interrupt controller information not available for %s.\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
object_child_foreach_recursive(object_get_root(),
|
|
|
|
hmp_info_pic_foreach, mon);
|
|
|
|
}
|
|
|
|
|
2019-03-11 18:29:09 +08:00
|
|
|
static int hmp_info_rdma_foreach(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
RdmaProvider *rdma;
|
|
|
|
RdmaProviderClass *k;
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
|
|
|
if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) {
|
|
|
|
rdma = RDMA_PROVIDER(obj);
|
|
|
|
k = RDMA_PROVIDER_GET_CLASS(obj);
|
|
|
|
if (k->print_statistics) {
|
|
|
|
k->print_statistics(mon, rdma);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "RDMA statistics not available for %s.\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_rdma(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
object_child_foreach_recursive(object_get_root(),
|
|
|
|
hmp_info_rdma_foreach, mon);
|
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
2011-10-22 00:15:33 +08:00
|
|
|
{
|
2012-01-11 23:51:52 +08:00
|
|
|
PciInfoList *info_list, *info;
|
2011-10-22 00:15:33 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2012-01-11 23:51:52 +08:00
|
|
|
info_list = qmp_query_pci(&err);
|
2011-10-22 00:15:33 +08:00
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "PCI devices not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-11 23:51:52 +08:00
|
|
|
for (info = info_list; info; info = info->next) {
|
2011-10-22 00:15:33 +08:00
|
|
|
PciDeviceInfoList *dev;
|
|
|
|
|
|
|
|
for (dev = info->value->devices; dev; dev = dev->next) {
|
|
|
|
hmp_info_pci_device(mon, dev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 23:51:52 +08:00
|
|
|
qapi_free_PciInfoList(info_list);
|
2011-10-22 00:15:33 +08:00
|
|
|
}
|
|
|
|
|
2013-01-14 14:06:25 +08:00
|
|
|
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
|
2012-01-18 22:40:49 +08:00
|
|
|
{
|
|
|
|
BlockJobInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
list = qmp_query_block_jobs(&err);
|
|
|
|
assert(!err);
|
|
|
|
|
|
|
|
if (!list) {
|
|
|
|
monitor_printf(mon, "No active jobs\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (list) {
|
|
|
|
if (strcmp(list->value->type, "stream") == 0) {
|
|
|
|
monitor_printf(mon, "Streaming device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->type,
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
2014-09-16 21:36:55 +08:00
|
|
|
|
|
|
|
qapi_free_BlockJobInfoList(list);
|
2012-01-18 22:40:49 +08:00
|
|
|
}
|
|
|
|
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
TPMInfoList *info_list, *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
unsigned int c = 0;
|
|
|
|
TPMPassthroughOptions *tpo;
|
2017-09-29 19:10:20 +08:00
|
|
|
TPMEmulatorOptions *teo;
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
|
|
|
|
info_list = qmp_query_tpm(&err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "TPM device not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info_list) {
|
|
|
|
monitor_printf(mon, "TPM device:\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
TPMInfo *ti = info->value;
|
|
|
|
monitor_printf(mon, " tpm%d: model=%s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
c, TpmModel_str(ti->model));
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
|
|
|
|
monitor_printf(mon, " \\ %s: type=%s",
|
2017-08-24 16:46:08 +08:00
|
|
|
ti->id, TpmTypeOptionsKind_str(ti->options->type));
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
|
2015-10-27 06:35:00 +08:00
|
|
|
switch (ti->options->type) {
|
2013-03-21 00:34:48 +08:00
|
|
|
case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
tpo = ti->options->u.passthrough.data;
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
monitor_printf(mon, "%s%s%s%s",
|
|
|
|
tpo->has_path ? ",path=" : "",
|
|
|
|
tpo->has_path ? tpo->path : "",
|
|
|
|
tpo->has_cancel_path ? ",cancel-path=" : "",
|
|
|
|
tpo->has_cancel_path ? tpo->cancel_path : "");
|
|
|
|
break;
|
2017-09-29 19:10:20 +08:00
|
|
|
case TPM_TYPE_OPTIONS_KIND_EMULATOR:
|
|
|
|
teo = ti->options->u.emulator.data;
|
|
|
|
monitor_printf(mon, ",chardev=%s", teo->chardev);
|
|
|
|
break;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 16:52:57 +08:00
|
|
|
case TPM_TYPE_OPTIONS_KIND__MAX:
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-28 01:47:49 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
qapi_free_TPMInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2011-09-16 01:20:28 +08:00
|
|
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
monitor_suspend(mon);
|
|
|
|
qmp_quit(NULL);
|
|
|
|
}
|
2011-09-16 01:34:39 +08:00
|
|
|
|
|
|
|
void hmp_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_stop(NULL);
|
|
|
|
}
|
2011-09-16 01:41:46 +08:00
|
|
|
|
2018-08-16 04:00:03 +08:00
|
|
|
void hmp_sync_profile(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *op = qdict_get_try_str(qdict, "op");
|
|
|
|
|
|
|
|
if (op == NULL) {
|
|
|
|
bool on = qsp_is_enabled();
|
|
|
|
|
|
|
|
monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!strcmp(op, "on")) {
|
|
|
|
qsp_enable();
|
|
|
|
} else if (!strcmp(op, "off")) {
|
|
|
|
qsp_disable();
|
|
|
|
} else if (!strcmp(op, "reset")) {
|
|
|
|
qsp_reset();
|
|
|
|
} else {
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
error_setg(&err, QERR_INVALID_PARAMETER, op);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-16 01:41:46 +08:00
|
|
|
void hmp_system_reset(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_reset(NULL);
|
|
|
|
}
|
2011-09-28 22:06:15 +08:00
|
|
|
|
|
|
|
void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_powerdown(NULL);
|
|
|
|
}
|
2011-10-07 01:31:39 +08:00
|
|
|
|
2018-06-20 23:39:46 +08:00
|
|
|
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-07-05 17:14:02 +08:00
|
|
|
qmp_x_exit_preconfig(&err);
|
2018-06-20 23:39:46 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2011-10-07 01:31:39 +08:00
|
|
|
void hmp_cpu(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t cpu_index;
|
|
|
|
|
|
|
|
/* XXX: drop the monitor_set_cpu() usage when all HMP commands that
|
|
|
|
use it are converted to the QAPI */
|
|
|
|
cpu_index = qdict_get_int(qdict, "index");
|
|
|
|
if (monitor_set_cpu(cpu_index) < 0) {
|
|
|
|
monitor_printf(mon, "invalid CPU index\n");
|
|
|
|
}
|
|
|
|
}
|
2011-11-23 02:32:37 +08:00
|
|
|
|
|
|
|
void hmp_memsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2017-01-13 20:12:35 +08:00
|
|
|
int cpu_index = monitor_get_cpu_index();
|
2011-11-23 02:32:37 +08:00
|
|
|
|
2017-01-13 20:12:35 +08:00
|
|
|
if (cpu_index < 0) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_memsave(addr, size, filename, true, cpu_index, &err);
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 02:32:37 +08:00
|
|
|
}
|
2011-11-23 03:26:46 +08:00
|
|
|
|
|
|
|
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-23 03:26:46 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_pmemsave(addr, size, filename, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-01-25 00:03:20 +08:00
|
|
|
}
|
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-07 04:27:24 +08:00
|
|
|
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
2013-01-25 00:03:20 +08:00
|
|
|
{
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
|
|
|
const char *data = qdict_get_str(qdict, "data");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2013-01-25 00:03:20 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
2013-01-25 00:03:20 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 03:26:46 +08:00
|
|
|
}
|
2011-11-23 03:58:31 +08:00
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-07 04:27:24 +08:00
|
|
|
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
2013-01-25 00:03:21 +08:00
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
2013-02-07 04:27:15 +08:00
|
|
|
char *data;
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2013-02-07 04:27:26 +08:00
|
|
|
int i;
|
2013-01-25 00:03:21 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
|
|
|
if (err) {
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-01-25 00:03:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-07 04:27:26 +08:00
|
|
|
for (i = 0; data[i]; i++) {
|
|
|
|
unsigned char ch = data[i];
|
|
|
|
|
|
|
|
if (ch == '\\') {
|
|
|
|
monitor_printf(mon, "\\\\");
|
|
|
|
} else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) {
|
|
|
|
monitor_printf(mon, "\\u%04X", ch);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%c", ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
2013-02-07 04:27:15 +08:00
|
|
|
g_free(data);
|
2013-01-25 00:03:21 +08:00
|
|
|
}
|
|
|
|
|
2011-11-23 03:58:31 +08:00
|
|
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-23 03:58:31 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_cont(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 03:58:31 +08:00
|
|
|
}
|
2011-11-23 22:55:53 +08:00
|
|
|
|
2012-02-23 20:45:21 +08:00
|
|
|
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
qmp hmp: Make system_wakeup check wake-up support and run state
The qmp/hmp command 'system_wakeup' is simply a direct call to
'qemu_system_wakeup_request' from vl.c. This function verifies if
runstate is SUSPENDED and if the wake up reason is valid before
proceeding. However, no error or warning is thrown if any of those
pre-requirements isn't met. There is no way for the caller to
differentiate between a successful wakeup or an error state caused
when trying to wake up a guest that wasn't suspended.
This means that system_wakeup is silently failing, which can be
considered a bug. Adding error handling isn't an API break in this
case - applications that didn't check the result will remain broken,
the ones that check it will have a chance to deal with it.
Adding to that, the commit before previous created a new QMP API called
query-current-machine, with a new flag called wakeup-suspend-support,
that indicates if the guest has the capability of waking up from suspended
state. Although such guest will never reach SUSPENDED state and erroring
it out in this scenario would suffice, it is more informative for the user
to differentiate between a failure because the guest isn't suspended versus
a failure because the guest does not have support for wake up at all.
All this considered, this patch changes qmp_system_wakeup to check if
the guest is capable of waking up from suspend, and if it is suspended.
After this patch, this is the output of system_wakeup in a guest that
does not have wake-up from suspend support (ppc64):
(qemu) system_wakeup
wake-up from suspend is not supported by this guest
(qemu)
And this is the output of system_wakeup in a x86 guest that has the
support but isn't suspended:
(qemu) system_wakeup
Unable to wake up: guest is not in suspended state
(qemu)
Reported-by: Balamuruhan S <bala24@linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-Id: <20181205194701.17836-4-danielhb413@gmail.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-12-06 03:47:01 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_system_wakeup(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-02-23 20:45:21 +08:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 20:55:43 +08:00
|
|
|
void hmp_nmi(Monitor *mon, const QDict *qdict)
|
2011-11-23 22:55:53 +08:00
|
|
|
{
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-23 22:55:53 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_inject_nmi(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 22:55:53 +08:00
|
|
|
}
|
2011-11-23 23:11:55 +08:00
|
|
|
|
|
|
|
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool up = qdict_get_bool(qdict, "up");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-23 23:11:55 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_set_link(name, up, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 23:11:55 +08:00
|
|
|
}
|
2011-11-23 23:28:21 +08:00
|
|
|
|
|
|
|
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-23 23:28:21 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_block_passwd(true, device, false, NULL, password, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 23:28:21 +08:00
|
|
|
}
|
2011-11-26 00:38:09 +08:00
|
|
|
|
|
|
|
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-26 00:38:09 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_balloon(value, &err);
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-26 00:38:09 +08:00
|
|
|
}
|
2011-11-26 00:57:10 +08:00
|
|
|
|
|
|
|
void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
int64_t size = qdict_get_int(qdict, "size");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-26 00:57:10 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_block_resize(true, device, false, NULL, size, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-26 00:57:10 +08:00
|
|
|
}
|
2011-11-26 02:15:19 +08:00
|
|
|
|
2012-10-18 22:49:24 +08:00
|
|
|
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
|
|
|
bool full = qdict_get_try_bool(qdict, "full", false);
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2016-07-15 06:37:58 +08:00
|
|
|
DriveMirror mirror = {
|
|
|
|
.device = (char *)qdict_get_str(qdict, "device"),
|
|
|
|
.target = (char *)filename,
|
|
|
|
.has_format = !!format,
|
|
|
|
.format = (char *)format,
|
|
|
|
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
|
|
|
.has_mode = true,
|
|
|
|
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
|
|
|
.unmap = true,
|
|
|
|
};
|
2012-10-18 22:49:24 +08:00
|
|
|
|
|
|
|
if (!filename) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 22:49:24 +08:00
|
|
|
return;
|
|
|
|
}
|
2016-07-15 06:37:58 +08:00
|
|
|
qmp_drive_mirror(&mirror, &err);
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 22:49:24 +08:00
|
|
|
}
|
|
|
|
|
2013-06-26 20:11:58 +08:00
|
|
|
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
|
|
|
bool full = qdict_get_try_bool(qdict, "full", false);
|
2016-07-22 16:17:52 +08:00
|
|
|
bool compress = qdict_get_try_bool(qdict, "compress", false);
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2016-07-22 16:17:50 +08:00
|
|
|
DriveBackup backup = {
|
|
|
|
.device = (char *)device,
|
|
|
|
.target = (char *)filename,
|
|
|
|
.has_format = !!format,
|
|
|
|
.format = (char *)format,
|
|
|
|
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
|
|
|
.has_mode = true,
|
|
|
|
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
2016-07-22 16:17:52 +08:00
|
|
|
.has_compress = !!compress,
|
|
|
|
.compress = compress,
|
2016-07-22 16:17:50 +08:00
|
|
|
};
|
2013-06-26 20:11:58 +08:00
|
|
|
|
|
|
|
if (!filename) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 20:11:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-22 16:17:50 +08:00
|
|
|
qmp_drive_backup(&backup, &err);
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 20:11:58 +08:00
|
|
|
}
|
|
|
|
|
2011-11-26 02:15:19 +08:00
|
|
|
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_try_str(qdict, "snapshot-file");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
2012-03-07 01:55:59 +08:00
|
|
|
enum NewImageMode mode;
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2011-11-26 02:15:19 +08:00
|
|
|
|
|
|
|
if (!filename) {
|
|
|
|
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
|
|
|
will be taken internally. Today it's actually required. */
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-26 02:15:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-07 01:55:59 +08:00
|
|
|
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
2014-01-24 04:31:38 +08:00
|
|
|
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
|
|
|
filename, false, NULL,
|
|
|
|
!!format, format,
|
2014-05-02 19:26:29 +08:00
|
|
|
true, mode, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-26 02:15:19 +08:00
|
|
|
}
|
2011-11-28 08:54:09 +08:00
|
|
|
|
2013-09-11 14:04:37 +08:00
|
|
|
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2013-09-11 14:04:37 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_blockdev_snapshot_internal_sync(device, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 14:04:37 +08:00
|
|
|
}
|
|
|
|
|
2013-09-11 14:04:38 +08:00
|
|
|
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
const char *id = qdict_get_try_str(qdict, "id");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2013-09-11 14:04:38 +08:00
|
|
|
|
|
|
|
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
2014-05-02 19:26:29 +08:00
|
|
|
true, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 14:04:38 +08:00
|
|
|
}
|
|
|
|
|
2017-04-18 17:40:56 +08:00
|
|
|
void hmp_loadvm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int saved_vm_running = runstate_is_running();
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2017-04-19 00:12:35 +08:00
|
|
|
Error *err = NULL;
|
2017-04-18 17:40:56 +08:00
|
|
|
|
|
|
|
vm_stop(RUN_STATE_RESTORE_VM);
|
|
|
|
|
2017-04-20 20:25:55 +08:00
|
|
|
if (load_snapshot(name, &err) == 0 && saved_vm_running) {
|
2017-04-18 17:40:56 +08:00
|
|
|
vm_start();
|
|
|
|
}
|
2017-04-19 00:12:35 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-04-18 17:40:56 +08:00
|
|
|
}
|
|
|
|
|
2017-04-18 17:44:16 +08:00
|
|
|
void hmp_savevm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-04-19 00:12:35 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2017-04-20 20:25:55 +08:00
|
|
|
save_snapshot(qdict_get_try_str(qdict, "name"), &err);
|
2017-04-19 00:12:35 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-04-18 17:44:16 +08:00
|
|
|
}
|
|
|
|
|
2017-04-18 17:46:23 +08:00
|
|
|
void hmp_delvm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockDriverState *bs;
|
2018-02-25 09:47:51 +08:00
|
|
|
Error *err = NULL;
|
2017-04-18 17:46:23 +08:00
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
|
|
|
|
if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
|
2019-04-25 05:49:08 +08:00
|
|
|
error_prepend(&err,
|
|
|
|
"deleting snapshot on device '%s': ",
|
|
|
|
bdrv_get_device_name(bs));
|
2017-04-18 17:46:23 +08:00
|
|
|
}
|
2019-04-25 05:49:08 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-04-18 17:46:23 +08:00
|
|
|
}
|
|
|
|
|
2017-04-18 17:51:06 +08:00
|
|
|
void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockDriverState *bs, *bs1;
|
|
|
|
BdrvNextIterator it1;
|
|
|
|
QEMUSnapshotInfo *sn_tab, *sn;
|
|
|
|
bool no_snapshot = true;
|
|
|
|
int nb_sns, i;
|
|
|
|
int total;
|
|
|
|
int *global_snapshots;
|
|
|
|
AioContext *aio_context;
|
|
|
|
|
|
|
|
typedef struct SnapshotEntry {
|
|
|
|
QEMUSnapshotInfo sn;
|
|
|
|
QTAILQ_ENTRY(SnapshotEntry) next;
|
|
|
|
} SnapshotEntry;
|
|
|
|
|
|
|
|
typedef struct ImageEntry {
|
|
|
|
const char *imagename;
|
|
|
|
QTAILQ_ENTRY(ImageEntry) next;
|
|
|
|
QTAILQ_HEAD(, SnapshotEntry) snapshots;
|
|
|
|
} ImageEntry;
|
|
|
|
|
|
|
|
QTAILQ_HEAD(, ImageEntry) image_list =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(image_list);
|
|
|
|
|
|
|
|
ImageEntry *image_entry, *next_ie;
|
|
|
|
SnapshotEntry *snapshot_entry;
|
|
|
|
|
|
|
|
bs = bdrv_all_find_vmstate_bs();
|
|
|
|
if (!bs) {
|
|
|
|
monitor_printf(mon, "No available block device supports snapshots\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aio_context = bdrv_get_aio_context(bs);
|
|
|
|
|
|
|
|
aio_context_acquire(aio_context);
|
|
|
|
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
|
|
|
|
aio_context_release(aio_context);
|
|
|
|
|
|
|
|
if (nb_sns < 0) {
|
|
|
|
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
|
|
|
|
int bs1_nb_sns = 0;
|
|
|
|
ImageEntry *ie;
|
|
|
|
SnapshotEntry *se;
|
|
|
|
AioContext *ctx = bdrv_get_aio_context(bs1);
|
|
|
|
|
|
|
|
aio_context_acquire(ctx);
|
|
|
|
if (bdrv_can_snapshot(bs1)) {
|
|
|
|
sn = NULL;
|
|
|
|
bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
|
|
|
|
if (bs1_nb_sns > 0) {
|
|
|
|
no_snapshot = false;
|
|
|
|
ie = g_new0(ImageEntry, 1);
|
|
|
|
ie->imagename = bdrv_get_device_name(bs1);
|
|
|
|
QTAILQ_INIT(&ie->snapshots);
|
|
|
|
QTAILQ_INSERT_TAIL(&image_list, ie, next);
|
|
|
|
for (i = 0; i < bs1_nb_sns; i++) {
|
|
|
|
se = g_new0(SnapshotEntry, 1);
|
|
|
|
se->sn = sn[i];
|
|
|
|
QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free(sn);
|
|
|
|
}
|
|
|
|
aio_context_release(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (no_snapshot) {
|
|
|
|
monitor_printf(mon, "There is no snapshot available.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
global_snapshots = g_new0(int, nb_sns);
|
|
|
|
total = 0;
|
|
|
|
for (i = 0; i < nb_sns; i++) {
|
|
|
|
SnapshotEntry *next_sn;
|
|
|
|
if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
|
|
|
|
global_snapshots[total] = i;
|
|
|
|
total++;
|
|
|
|
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
|
|
|
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
|
|
|
|
next, next_sn) {
|
|
|
|
if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
|
|
|
|
QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
|
|
|
|
next);
|
|
|
|
g_free(snapshot_entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "List of snapshots present on all disks:\n");
|
|
|
|
|
|
|
|
if (total > 0) {
|
2019-04-18 03:17:55 +08:00
|
|
|
bdrv_snapshot_dump(NULL);
|
2017-04-18 17:51:06 +08:00
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
for (i = 0; i < total; i++) {
|
|
|
|
sn = &sn_tab[global_snapshots[i]];
|
|
|
|
/* The ID is not guaranteed to be the same on all images, so
|
|
|
|
* overwrite it.
|
|
|
|
*/
|
|
|
|
pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
|
2019-04-18 03:17:55 +08:00
|
|
|
bdrv_snapshot_dump(sn);
|
2017-04-18 17:51:06 +08:00
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "None\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
|
|
|
if (QTAILQ_EMPTY(&image_entry->snapshots)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
monitor_printf(mon,
|
|
|
|
"\nList of partial (non-loadable) snapshots on '%s':\n",
|
|
|
|
image_entry->imagename);
|
2019-04-18 03:17:55 +08:00
|
|
|
bdrv_snapshot_dump(NULL);
|
2017-04-18 17:51:06 +08:00
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
|
2019-04-18 03:17:55 +08:00
|
|
|
bdrv_snapshot_dump(&snapshot_entry->sn);
|
2017-04-18 17:51:06 +08:00
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
|
|
|
|
SnapshotEntry *next_sn;
|
|
|
|
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
|
|
|
|
next_sn) {
|
|
|
|
g_free(snapshot_entry);
|
|
|
|
}
|
|
|
|
g_free(image_entry);
|
|
|
|
}
|
|
|
|
g_free(sn_tab);
|
|
|
|
g_free(global_snapshots);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-02-27 21:24:12 +08:00
|
|
|
void hmp_announce_self(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2019-06-21 02:47:03 +08:00
|
|
|
const char *interfaces_str = qdict_get_try_str(qdict, "interfaces");
|
2019-06-21 02:47:05 +08:00
|
|
|
const char *id = qdict_get_try_str(qdict, "id");
|
2019-06-21 02:47:03 +08:00
|
|
|
AnnounceParameters *params = QAPI_CLONE(AnnounceParameters,
|
|
|
|
migrate_announce_params());
|
|
|
|
|
|
|
|
qapi_free_strList(params->interfaces);
|
|
|
|
params->interfaces = strList_from_comma_list(interfaces_str);
|
|
|
|
params->has_interfaces = params->interfaces != NULL;
|
2019-06-21 02:47:05 +08:00
|
|
|
params->id = g_strdup(id);
|
|
|
|
params->has_id = !!params->id;
|
2019-06-21 02:47:03 +08:00
|
|
|
qmp_announce_self(params, NULL);
|
|
|
|
qapi_free_AnnounceParameters(params);
|
2019-02-27 21:24:12 +08:00
|
|
|
}
|
|
|
|
|
2011-11-28 08:54:09 +08:00
|
|
|
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_migrate_cancel(NULL);
|
|
|
|
}
|
2011-11-28 09:18:01 +08:00
|
|
|
|
2017-10-20 17:05:54 +08:00
|
|
|
void hmp_migrate_continue(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *state = qdict_get_str(qdict, "state");
|
|
|
|
int val = qapi_enum_parse(&MigrationStatus_lookup, state, -1, &err);
|
|
|
|
|
|
|
|
if (val >= 0) {
|
|
|
|
qmp_migrate_continue(val, &err);
|
|
|
|
}
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2015-02-19 19:40:28 +08:00
|
|
|
void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
|
|
|
|
qmp_migrate_incoming(uri, &err);
|
|
|
|
|
2015-02-26 22:54:39 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2015-02-19 19:40:28 +08:00
|
|
|
}
|
|
|
|
|
2018-05-02 18:47:37 +08:00
|
|
|
void hmp_migrate_recover(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
|
|
|
|
qmp_migrate_recover(uri, &err);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2018-05-02 18:47:40 +08:00
|
|
|
void hmp_migrate_pause(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate_pause(&err);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2016-09-16 00:20:28 +08:00
|
|
|
/* Kept for backwards compatibility */
|
2011-11-28 09:18:01 +08:00
|
|
|
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
double value = qdict_get_double(qdict, "value");
|
|
|
|
qmp_migrate_set_downtime(value, NULL);
|
|
|
|
}
|
2011-11-28 21:59:37 +08:00
|
|
|
|
2012-08-07 02:42:54 +08:00
|
|
|
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate_set_cache_size(value, &err);
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-07 02:42:54 +08:00
|
|
|
}
|
|
|
|
|
2016-09-16 00:20:28 +08:00
|
|
|
/* Kept for backwards compatibility */
|
2011-11-28 21:59:37 +08:00
|
|
|
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
qmp_migrate_set_speed(value, NULL);
|
|
|
|
}
|
2011-12-07 21:17:51 +08:00
|
|
|
|
2012-08-07 02:42:48 +08:00
|
|
|
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *cap = qdict_get_str(qdict, "capability");
|
|
|
|
bool state = qdict_get_bool(qdict, "state");
|
|
|
|
Error *err = NULL;
|
|
|
|
MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
|
2017-08-24 16:46:00 +08:00
|
|
|
int val;
|
2012-08-07 02:42:48 +08:00
|
|
|
|
2017-08-24 16:46:10 +08:00
|
|
|
val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
|
2017-08-24 16:46:00 +08:00
|
|
|
if (val < 0) {
|
|
|
|
goto end;
|
2012-08-07 02:42:48 +08:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:46:00 +08:00
|
|
|
caps->value = g_malloc0(sizeof(*caps->value));
|
|
|
|
caps->value->capability = val;
|
|
|
|
caps->value->state = state;
|
|
|
|
caps->next = NULL;
|
|
|
|
qmp_migrate_set_capabilities(caps, &err);
|
2012-08-07 02:42:48 +08:00
|
|
|
|
2017-08-24 16:46:00 +08:00
|
|
|
end:
|
2012-08-07 02:42:48 +08:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-07 02:42:48 +08:00
|
|
|
}
|
|
|
|
|
2015-03-23 16:32:29 +08:00
|
|
|
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *param = qdict_get_str(qdict, "parameter");
|
2016-04-27 18:05:15 +08:00
|
|
|
const char *valuestr = qdict_get_str(qdict, "value");
|
2017-05-16 17:37:45 +08:00
|
|
|
Visitor *v = string_input_visitor_new(valuestr);
|
migration: Unshare MigrationParameters struct for now
Commit de63ab6 "migrate: Share common MigrationParameters struct"
reused MigrationParameters for the arguments of
migrate-set-parameters, with the following rationale:
It is rather verbose, and slightly error-prone, to repeat
the same set of parameters for input (migrate-set-parameters)
as for output (query-migrate-parameters), where the only
difference is whether the members are optional. We can just
document that the optional members will always be present
on output, and then share a common struct between both
commands. The next patch can then reduce the amount of
code needed on input.
I need to unshare them to correct a design flaw in a stupid, but
minimally invasive way, in the next commit. We can restore the
sharing when we redo that patch in a less stupid way. Add a suitable
TODO comment.
Note that I revert only the sharing part of commit de63ab6, not the
part that made the members of query-migrate-parameters' result
optional. The schema (and thus introspection) remains inaccurate for
query-migrate-parameters. If we decide not to restore the sharing, we
should revert that part, too.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-07-18 19:42:11 +08:00
|
|
|
MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
|
2017-02-22 04:14:07 +08:00
|
|
|
uint64_t valuebw = 0;
|
2017-10-06 03:30:10 +08:00
|
|
|
uint64_t cache_size;
|
2015-03-23 16:32:29 +08:00
|
|
|
Error *err = NULL;
|
2017-08-24 16:46:01 +08:00
|
|
|
int val, ret;
|
2016-04-27 18:05:15 +08:00
|
|
|
|
2017-08-24 16:46:10 +08:00
|
|
|
val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err);
|
2017-08-24 16:46:01 +08:00
|
|
|
if (val < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (val) {
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
|
|
|
|
p->has_compress_level = true;
|
|
|
|
visit_type_int(v, param, &p->compress_level, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_THREADS:
|
|
|
|
p->has_compress_threads = true;
|
|
|
|
visit_type_int(v, param, &p->compress_threads, &err);
|
|
|
|
break;
|
2018-08-21 16:10:20 +08:00
|
|
|
case MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD:
|
|
|
|
p->has_compress_wait_thread = true;
|
|
|
|
visit_type_bool(v, param, &p->compress_wait_thread, &err);
|
|
|
|
break;
|
2017-08-24 16:46:01 +08:00
|
|
|
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
|
|
|
|
p->has_decompress_threads = true;
|
|
|
|
visit_type_int(v, param, &p->decompress_threads, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
|
|
|
|
p->has_cpu_throttle_initial = true;
|
|
|
|
visit_type_int(v, param, &p->cpu_throttle_initial, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
|
|
|
p->has_cpu_throttle_increment = true;
|
|
|
|
visit_type_int(v, param, &p->cpu_throttle_increment, &err);
|
|
|
|
break;
|
2018-08-01 21:00:20 +08:00
|
|
|
case MIGRATION_PARAMETER_MAX_CPU_THROTTLE:
|
|
|
|
p->has_max_cpu_throttle = true;
|
|
|
|
visit_type_int(v, param, &p->max_cpu_throttle, &err);
|
|
|
|
break;
|
2017-08-24 16:46:01 +08:00
|
|
|
case MIGRATION_PARAMETER_TLS_CREDS:
|
|
|
|
p->has_tls_creds = true;
|
|
|
|
p->tls_creds = g_new0(StrOrNull, 1);
|
|
|
|
p->tls_creds->type = QTYPE_QSTRING;
|
|
|
|
visit_type_str(v, param, &p->tls_creds->u.s, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_TLS_HOSTNAME:
|
|
|
|
p->has_tls_hostname = true;
|
|
|
|
p->tls_hostname = g_new0(StrOrNull, 1);
|
|
|
|
p->tls_hostname->type = QTYPE_QSTRING;
|
|
|
|
visit_type_str(v, param, &p->tls_hostname->u.s, &err);
|
|
|
|
break;
|
migration: add support for a "tls-authz" migration parameter
The QEMU instance that runs as the server for the migration data
transport (ie the target QEMU) needs to be able to configure access
control so it can prevent unauthorized clients initiating an incoming
migration. This adds a new 'tls-authz' migration parameter that is used
to provide the QOM ID of a QAuthZ subclass instance that provides the
access control check. This is checked against the x509 certificate
obtained during the TLS handshake.
For example, when starting a QEMU for incoming migration, it is
possible to give an example identity of the source QEMU that is
intended to be connecting later:
$QEMU \
-monitor stdio \
-incoming defer \
...other args...
(qemu) object_add tls-creds-x509,id=tls0,dir=/home/berrange/qemutls,\
endpoint=server,verify-peer=yes \
(qemu) object_add authz-simple,id=auth0,identity=CN=laptop.example.com,,\
O=Example Org,,L=London,,ST=London,,C=GB \
(qemu) migrate_incoming tcp:localhost:9000
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2019-02-27 22:53:24 +08:00
|
|
|
case MIGRATION_PARAMETER_TLS_AUTHZ:
|
|
|
|
p->has_tls_authz = true;
|
|
|
|
p->tls_authz = g_new0(StrOrNull, 1);
|
|
|
|
p->tls_authz->type = QTYPE_QSTRING;
|
|
|
|
visit_type_str(v, param, &p->tls_authz->u.s, &err);
|
|
|
|
break;
|
2017-08-24 16:46:01 +08:00
|
|
|
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
|
|
|
|
p->has_max_bandwidth = true;
|
|
|
|
/*
|
|
|
|
* Can't use visit_type_size() here, because it
|
|
|
|
* defaults to Bytes rather than Mebibytes.
|
|
|
|
*/
|
|
|
|
ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
|
|
|
|
if (ret < 0 || valuebw > INT64_MAX
|
|
|
|
|| (size_t)valuebw != valuebw) {
|
|
|
|
error_setg(&err, "Invalid size %s", valuestr);
|
2015-03-23 16:32:29 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-08-24 16:46:01 +08:00
|
|
|
p->max_bandwidth = valuebw;
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
|
|
|
|
p->has_downtime_limit = true;
|
|
|
|
visit_type_int(v, param, &p->downtime_limit, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
|
|
|
|
p->has_x_checkpoint_delay = true;
|
|
|
|
visit_type_int(v, param, &p->x_checkpoint_delay, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
|
|
|
|
p->has_block_incremental = true;
|
|
|
|
visit_type_bool(v, param, &p->block_incremental, &err);
|
|
|
|
break;
|
2019-02-06 20:54:06 +08:00
|
|
|
case MIGRATION_PARAMETER_MULTIFD_CHANNELS:
|
|
|
|
p->has_multifd_channels = true;
|
|
|
|
visit_type_int(v, param, &p->multifd_channels, &err);
|
2016-01-15 15:56:17 +08:00
|
|
|
break;
|
2017-10-06 03:30:10 +08:00
|
|
|
case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE:
|
|
|
|
p->has_xbzrle_cache_size = true;
|
|
|
|
visit_type_size(v, param, &cache_size, &err);
|
2019-04-03 19:49:51 +08:00
|
|
|
if (err) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (cache_size > INT64_MAX || (size_t)cache_size != cache_size) {
|
2017-10-06 03:30:10 +08:00
|
|
|
error_setg(&err, "Invalid size %s", valuestr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p->xbzrle_cache_size = cache_size;
|
|
|
|
break;
|
2018-06-13 18:26:40 +08:00
|
|
|
case MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH:
|
|
|
|
p->has_max_postcopy_bandwidth = true;
|
|
|
|
visit_type_size(v, param, &p->max_postcopy_bandwidth, &err);
|
|
|
|
break;
|
2019-02-27 21:24:06 +08:00
|
|
|
case MIGRATION_PARAMETER_ANNOUNCE_INITIAL:
|
|
|
|
p->has_announce_initial = true;
|
|
|
|
visit_type_size(v, param, &p->announce_initial, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_ANNOUNCE_MAX:
|
|
|
|
p->has_announce_max = true;
|
|
|
|
visit_type_size(v, param, &p->announce_max, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_ANNOUNCE_ROUNDS:
|
|
|
|
p->has_announce_rounds = true;
|
|
|
|
visit_type_size(v, param, &p->announce_rounds, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_ANNOUNCE_STEP:
|
|
|
|
p->has_announce_step = true;
|
|
|
|
visit_type_size(v, param, &p->announce_step, &err);
|
|
|
|
break;
|
2017-08-24 16:46:01 +08:00
|
|
|
default:
|
|
|
|
assert(0);
|
2015-03-23 16:32:29 +08:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:46:01 +08:00
|
|
|
if (err) {
|
|
|
|
goto cleanup;
|
2015-03-23 16:32:29 +08:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:46:01 +08:00
|
|
|
qmp_migrate_set_parameters(p, &err);
|
|
|
|
|
2016-04-27 18:05:15 +08:00
|
|
|
cleanup:
|
migration: Unshare MigrationParameters struct for now
Commit de63ab6 "migrate: Share common MigrationParameters struct"
reused MigrationParameters for the arguments of
migrate-set-parameters, with the following rationale:
It is rather verbose, and slightly error-prone, to repeat
the same set of parameters for input (migrate-set-parameters)
as for output (query-migrate-parameters), where the only
difference is whether the members are optional. We can just
document that the optional members will always be present
on output, and then share a common struct between both
commands. The next patch can then reduce the amount of
code needed on input.
I need to unshare them to correct a design flaw in a stupid, but
minimally invasive way, in the next commit. We can restore the
sharing when we redo that patch in a less stupid way. Add a suitable
TODO comment.
Note that I revert only the sharing part of commit de63ab6, not the
part that made the members of query-migrate-parameters' result
optional. The schema (and thus introspection) remains inaccurate for
query-migrate-parameters. If we decide not to restore the sharing, we
should revert that part, too.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-07-18 19:42:11 +08:00
|
|
|
qapi_free_MigrateSetParameters(p);
|
2017-05-16 17:37:45 +08:00
|
|
|
visit_free(v);
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2015-03-23 16:32:29 +08:00
|
|
|
}
|
|
|
|
|
2015-03-06 00:29:02 +08:00
|
|
|
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *hostname = qdict_get_str(qdict, "hostname");
|
|
|
|
bool has_port = qdict_haskey(qdict, "port");
|
|
|
|
int port = qdict_get_try_int(qdict, "port", -1);
|
|
|
|
bool has_tls_port = qdict_haskey(qdict, "tls-port");
|
|
|
|
int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
|
|
|
|
const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
|
|
|
|
|
|
|
|
qmp_client_migrate_info(protocol, hostname,
|
|
|
|
has_port, port, has_tls_port, tls_port,
|
|
|
|
!!cert_subject, cert_subject, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2015-11-06 02:10:56 +08:00
|
|
|
void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
qmp_migrate_start_postcopy(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
COLO: Add 'x-colo-lost-heartbeat' command to trigger failover
We leave users to choose whatever heartbeat solution they want,
if the heartbeat is lost, or other errors they detect, they can use
experimental command 'x_colo_lost_heartbeat' to tell COLO to do failover,
COLO will do operations accordingly.
For example, if the command is sent to the Primary side,
the Primary side will exit COLO mode, does cleanup work,
and then, PVM will take over the service work. If sent to the Secondary side,
the Secondary side will run failover work, then takes over PVM's service work.
Cc: Luiz Capitulino <lcapitulino@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Amit Shah <amit@amitshah.net>
2016-10-27 14:43:03 +08:00
|
|
|
void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_x_colo_lost_heartbeat(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2011-12-07 21:17:51 +08:00
|
|
|
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
|
|
|
const char *connected = qdict_get_try_str(qdict, "connected");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_set_password(protocol, password, !!connected, connected, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-07 21:47:57 +08:00
|
|
|
|
|
|
|
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *whenstr = qdict_get_str(qdict, "time");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_expire_password(protocol, whenstr, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-08 02:02:36 +08:00
|
|
|
|
|
|
|
void hmp_eject(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-05-16 06:25:00 +08:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
2011-12-08 02:02:36 +08:00
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2016-09-20 19:38:46 +08:00
|
|
|
qmp_eject(true, device, false, NULL, true, force, &err);
|
2011-12-08 02:02:36 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-08 21:13:50 +08:00
|
|
|
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
#ifdef CONFIG_VNC
|
2013-11-14 18:54:14 +08:00
|
|
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
|
|
|
void *readline_opaque)
|
2011-12-08 21:13:50 +08:00
|
|
|
{
|
|
|
|
qmp_change_vnc_password(password, NULL);
|
2013-11-14 18:54:14 +08:00
|
|
|
monitor_read_command(opaque, 1);
|
2011-12-08 21:13:50 +08:00
|
|
|
}
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
#endif
|
2011-12-08 21:13:50 +08:00
|
|
|
|
|
|
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2019-06-13 23:33:59 +08:00
|
|
|
MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
|
2011-12-08 21:13:50 +08:00
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *target = qdict_get_str(qdict, "target");
|
|
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
2015-10-27 04:39:18 +08:00
|
|
|
const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
|
|
|
|
BlockdevChangeReadOnlyMode read_only_mode = 0;
|
2011-12-08 21:13:50 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
#ifdef CONFIG_VNC
|
2015-10-27 04:39:16 +08:00
|
|
|
if (strcmp(device, "vnc") == 0) {
|
2015-10-27 04:39:18 +08:00
|
|
|
if (read_only) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
"Parameter 'read-only-mode' is invalid for VNC\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-10-27 04:39:16 +08:00
|
|
|
if (strcmp(target, "passwd") == 0 ||
|
|
|
|
strcmp(target, "password") == 0) {
|
|
|
|
if (!arg) {
|
2019-06-13 23:33:54 +08:00
|
|
|
monitor_read_password(hmp_mon, hmp_change_read_arg, NULL);
|
2015-10-27 04:39:16 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qmp_change("vnc", target, !!arg, arg, &err);
|
qapi: add conditions to VNC type/commands/events on the schema
Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.
query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.
Commands made conditional:
* query-vnc, query-vnc-servers, change-vnc-password
Before the patch, the commands for !CONFIG_VNC are stubs that fail
like this:
{"error": {"class": "GenericError",
"desc": "The feature 'vnc' is not enabled"}}
Afterwards, they fail like this:
{"error": {"class": "CommandNotFound",
"desc": "The command FOO has not been found"}}
I call that an improvement, because it lets clients distinguish
between command unavailable (class CommandNotFound) and command failed
(class GenericError).
Events made conditional:
* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
HMP change:
* info vnc
Will return "unknown command: 'info vnc'" when VNC is compiled
out (same as error for spice when --disable-spice)
Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:
* add_client
Command has other uses, including "socket bases character devices".
These are unconditional as far as I can tell.
* set_password, expire_password
In theory, these commands could be used for managing any service's
password. In practice, they're used for VNC and SPICE services.
They're documented for "remote display session" / "remote display
server".
The service is selected by argument @protocol. The code special-cases
protocol-specific argument checking, then calls a protocol-specific
function to do the work. If it fails, the command fails with "Could
not set password". It does when the service isn't compiled in (it's a
stub then).
We could make these commands conditional on the conjunction of all
services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
but I doubt it's worthwhile.
* change
Command has other uses, namely changing media.
This patch inlines a stub; no functional change.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-14-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-03 23:56:47 +08:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2015-10-27 04:39:18 +08:00
|
|
|
if (read_only) {
|
|
|
|
read_only_mode =
|
2017-08-24 16:46:10 +08:00
|
|
|
qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
|
2017-08-24 16:45:57 +08:00
|
|
|
read_only,
|
2015-10-27 04:39:18 +08:00
|
|
|
BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
|
|
|
|
if (err) {
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:47 +08:00
|
|
|
qmp_blockdev_change_medium(true, device, false, NULL, target,
|
|
|
|
!!arg, arg, !!read_only, read_only_mode,
|
|
|
|
&err);
|
2011-12-08 21:13:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-15 02:49:14 +08:00
|
|
|
|
|
|
|
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
2018-03-09 22:11:07 +08:00
|
|
|
char *device = (char *) qdict_get_str(qdict, "device");
|
2016-07-14 11:50:21 +08:00
|
|
|
BlockIOThrottle throttle = {
|
|
|
|
.bps = qdict_get_int(qdict, "bps"),
|
|
|
|
.bps_rd = qdict_get_int(qdict, "bps_rd"),
|
|
|
|
.bps_wr = qdict_get_int(qdict, "bps_wr"),
|
|
|
|
.iops = qdict_get_int(qdict, "iops"),
|
|
|
|
.iops_rd = qdict_get_int(qdict, "iops_rd"),
|
|
|
|
.iops_wr = qdict_get_int(qdict, "iops_wr"),
|
|
|
|
};
|
2011-12-15 02:49:14 +08:00
|
|
|
|
2018-03-09 22:11:07 +08:00
|
|
|
/* qmp_block_set_io_throttle has separate parameters for the
|
|
|
|
* (deprecated) block device name and the qdev ID but the HMP
|
|
|
|
* version has only one, so we must decide which one to pass. */
|
|
|
|
if (blk_by_name(device)) {
|
|
|
|
throttle.has_device = true;
|
|
|
|
throttle.device = device;
|
|
|
|
} else {
|
|
|
|
throttle.has_id = true;
|
|
|
|
throttle.id = device;
|
|
|
|
}
|
|
|
|
|
2016-07-14 11:50:21 +08:00
|
|
|
qmp_block_set_io_throttle(&throttle, &err);
|
2011-12-15 02:49:14 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-01-18 22:40:46 +08:00
|
|
|
|
|
|
|
void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *base = qdict_get_try_str(qdict, "base");
|
2012-04-25 23:51:03 +08:00
|
|
|
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
|
2012-01-18 22:40:46 +08:00
|
|
|
|
2016-11-04 21:44:43 +08:00
|
|
|
qmp_block_stream(true, device, device, base != NULL, base, false, NULL,
|
2018-09-06 21:02:23 +08:00
|
|
|
false, NULL, qdict_haskey(qdict, "speed"), speed, true,
|
|
|
|
BLOCKDEV_ON_ERROR_REPORT, false, false, false, false,
|
|
|
|
&error);
|
2012-01-18 22:40:46 +08:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 22:40:47 +08:00
|
|
|
|
|
|
|
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2012-05-08 22:51:56 +08:00
|
|
|
int64_t value = qdict_get_int(qdict, "speed");
|
2012-01-18 22:40:47 +08:00
|
|
|
|
|
|
|
qmp_block_job_set_speed(device, value, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 22:40:48 +08:00
|
|
|
|
|
|
|
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
2012-01-18 22:40:48 +08:00
|
|
|
|
2012-09-28 23:22:51 +08:00
|
|
|
qmp_block_job_cancel(device, true, force, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_pause(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_resume(device, &error);
|
2012-01-18 22:40:48 +08:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2011-12-06 00:48:01 +08:00
|
|
|
|
2012-10-18 22:49:21 +08:00
|
|
|
void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_complete(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
2015-03-13 16:08:39 +08:00
|
|
|
typedef struct HMPMigrationStatus
|
2011-12-06 00:48:01 +08:00
|
|
|
{
|
|
|
|
QEMUTimer *timer;
|
|
|
|
Monitor *mon;
|
|
|
|
bool is_block_migration;
|
2015-03-13 16:08:39 +08:00
|
|
|
} HMPMigrationStatus;
|
2011-12-06 00:48:01 +08:00
|
|
|
|
|
|
|
static void hmp_migrate_status_cb(void *opaque)
|
|
|
|
{
|
2015-03-13 16:08:39 +08:00
|
|
|
HMPMigrationStatus *status = opaque;
|
2011-12-06 00:48:01 +08:00
|
|
|
MigrationInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2015-03-13 16:08:40 +08:00
|
|
|
if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE ||
|
|
|
|
info->status == MIGRATION_STATUS_SETUP) {
|
2011-12-06 00:48:01 +08:00
|
|
|
if (info->has_disk) {
|
|
|
|
int progress;
|
|
|
|
|
|
|
|
if (info->disk->remaining) {
|
|
|
|
progress = info->disk->transferred * 100 / info->disk->total;
|
|
|
|
} else {
|
|
|
|
progress = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(status->mon, "Completed %d %%\r", progress);
|
|
|
|
monitor_flush(status->mon);
|
|
|
|
}
|
|
|
|
|
2013-08-21 23:03:08 +08:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
2011-12-06 00:48:01 +08:00
|
|
|
} else {
|
|
|
|
if (status->is_block_migration) {
|
|
|
|
monitor_printf(status->mon, "\n");
|
|
|
|
}
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 18:05:00 +08:00
|
|
|
if (info->has_error_desc) {
|
|
|
|
error_report("%s", info->error_desc);
|
|
|
|
}
|
2011-12-06 00:48:01 +08:00
|
|
|
monitor_resume(status->mon);
|
2013-08-21 23:03:08 +08:00
|
|
|
timer_del(status->timer);
|
2018-09-01 21:46:52 +08:00
|
|
|
timer_free(status->timer);
|
2011-12-06 00:48:01 +08:00
|
|
|
g_free(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationInfo(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_migrate(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-05-16 06:25:00 +08:00
|
|
|
bool detach = qdict_get_try_bool(qdict, "detach", false);
|
|
|
|
bool blk = qdict_get_try_bool(qdict, "blk", false);
|
|
|
|
bool inc = qdict_get_try_bool(qdict, "inc", false);
|
2018-05-02 18:47:23 +08:00
|
|
|
bool resume = qdict_get_try_bool(qdict, "resume", false);
|
2011-12-06 00:48:01 +08:00
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-05-02 18:47:23 +08:00
|
|
|
qmp_migrate(uri, !!blk, blk, !!inc, inc,
|
|
|
|
false, false, true, resume, &err);
|
2011-12-06 00:48:01 +08:00
|
|
|
if (err) {
|
2017-10-19 19:16:33 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-12-06 00:48:01 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
2015-03-13 16:08:39 +08:00
|
|
|
HMPMigrationStatus *status;
|
2011-12-06 00:48:01 +08:00
|
|
|
|
|
|
|
if (monitor_suspend(mon) < 0) {
|
|
|
|
monitor_printf(mon, "terminal does not allow synchronous "
|
|
|
|
"migration, continuing detached\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = g_malloc0(sizeof(*status));
|
|
|
|
status->mon = mon;
|
|
|
|
status->is_block_migration = blk || inc;
|
2013-08-21 23:03:08 +08:00
|
|
|
status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb,
|
2011-12-06 00:48:01 +08:00
|
|
|
status);
|
2013-08-21 23:03:08 +08:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
|
2011-12-06 00:48:01 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-29 23:38:50 +08:00
|
|
|
|
2015-03-06 00:24:48 +08:00
|
|
|
void hmp_device_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_add((QDict *)qdict, NULL, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-03-06 00:24:48 +08:00
|
|
|
}
|
|
|
|
|
2012-03-29 23:38:50 +08:00
|
|
|
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-05-07 12:10:47 +08:00
|
|
|
|
|
|
|
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2018-05-18 00:23:39 +08:00
|
|
|
bool win_dmp = qdict_get_try_bool(qdict, "windmp", false);
|
2015-05-16 06:25:00 +08:00
|
|
|
bool paging = qdict_get_try_bool(qdict, "paging", false);
|
|
|
|
bool zlib = qdict_get_try_bool(qdict, "zlib", false);
|
|
|
|
bool lzo = qdict_get_try_bool(qdict, "lzo", false);
|
|
|
|
bool snappy = qdict_get_try_bool(qdict, "snappy", false);
|
2012-09-22 00:53:00 +08:00
|
|
|
const char *file = qdict_get_str(qdict, "filename");
|
2012-05-07 12:10:47 +08:00
|
|
|
bool has_begin = qdict_haskey(qdict, "begin");
|
|
|
|
bool has_length = qdict_haskey(qdict, "length");
|
2016-02-18 13:16:47 +08:00
|
|
|
bool has_detach = qdict_haskey(qdict, "detach");
|
2012-05-07 12:10:47 +08:00
|
|
|
int64_t begin = 0;
|
|
|
|
int64_t length = 0;
|
2016-02-18 13:16:47 +08:00
|
|
|
bool detach = false;
|
2014-02-18 14:11:36 +08:00
|
|
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
2012-09-22 00:53:00 +08:00
|
|
|
char *prot;
|
2012-05-07 12:10:47 +08:00
|
|
|
|
2018-05-18 00:23:39 +08:00
|
|
|
if (zlib + lzo + snappy + win_dmp > 1) {
|
|
|
|
error_setg(&err, "only one of '-z|-l|-s|-w' can be set");
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2014-04-17 16:15:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-18 00:23:39 +08:00
|
|
|
if (win_dmp) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_WIN_DMP;
|
|
|
|
}
|
|
|
|
|
2014-04-17 16:15:07 +08:00
|
|
|
if (zlib) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lzo) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snappy) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
|
|
|
}
|
|
|
|
|
2012-05-07 12:10:47 +08:00
|
|
|
if (has_begin) {
|
|
|
|
begin = qdict_get_int(qdict, "begin");
|
|
|
|
}
|
|
|
|
if (has_length) {
|
|
|
|
length = qdict_get_int(qdict, "length");
|
|
|
|
}
|
2016-02-18 13:16:47 +08:00
|
|
|
if (has_detach) {
|
|
|
|
detach = qdict_get_bool(qdict, "detach");
|
|
|
|
}
|
2012-05-07 12:10:47 +08:00
|
|
|
|
2012-09-22 00:53:00 +08:00
|
|
|
prot = g_strconcat("file:", file, NULL);
|
|
|
|
|
2016-02-18 13:16:47 +08:00
|
|
|
qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
|
|
|
|
has_length, length, true, dump_format, &err);
|
2014-05-02 19:26:29 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-22 00:53:00 +08:00
|
|
|
g_free(prot);
|
2012-05-07 12:10:47 +08:00
|
|
|
}
|
2012-04-19 04:34:15 +08:00
|
|
|
|
|
|
|
void hmp_netdev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
2014-01-30 22:07:28 +08:00
|
|
|
if (err) {
|
2012-04-19 04:34:15 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
netdev_add(opts, &err);
|
2014-01-30 22:07:28 +08:00
|
|
|
if (err) {
|
2012-04-19 04:34:15 +08:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-04-17 01:36:32 +08:00
|
|
|
|
|
|
|
void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_netdev_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-06-23 02:36:09 +08:00
|
|
|
|
2013-12-21 06:21:10 +08:00
|
|
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
2016-02-11 02:40:59 +08:00
|
|
|
Object *obj = NULL;
|
2013-12-21 06:21:10 +08:00
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
|
|
|
if (err) {
|
2016-02-11 02:40:59 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
2013-12-21 06:21:10 +08:00
|
|
|
}
|
|
|
|
|
2017-01-10 20:53:14 +08:00
|
|
|
obj = user_creatable_add_opts(opts, &err);
|
2016-02-11 02:40:59 +08:00
|
|
|
qemu_opts_del(opts);
|
2013-12-21 06:21:10 +08:00
|
|
|
|
|
|
|
if (err) {
|
2016-02-11 02:40:59 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-12-21 06:21:10 +08:00
|
|
|
}
|
2016-02-11 02:40:59 +08:00
|
|
|
if (obj) {
|
|
|
|
object_unref(obj);
|
2013-12-21 06:21:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-23 02:36:09 +08:00
|
|
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2012-06-23 02:36:09 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_getfd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-23 02:36:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2012-06-23 02:36:09 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_closefd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-23 02:36:09 +08:00
|
|
|
}
|
2012-08-31 10:56:26 +08:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 20:55:43 +08:00
|
|
|
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
2012-08-31 10:56:26 +08:00
|
|
|
{
|
|
|
|
const char *keys = qdict_get_str(qdict, "keys");
|
2012-09-21 01:19:47 +08:00
|
|
|
KeyValueList *keylist, *head = NULL, *tmp = NULL;
|
2012-08-31 10:56:26 +08:00
|
|
|
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
|
|
|
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
|
|
|
Error *err = NULL;
|
2018-06-29 18:32:10 +08:00
|
|
|
const char *separator;
|
2012-09-21 01:19:47 +08:00
|
|
|
int keyname_len;
|
2012-08-31 10:56:26 +08:00
|
|
|
|
|
|
|
while (1) {
|
2018-06-29 18:32:10 +08:00
|
|
|
separator = qemu_strchrnul(keys, '-');
|
|
|
|
keyname_len = separator - keys;
|
2012-08-31 10:56:26 +08:00
|
|
|
|
|
|
|
/* Be compatible with old interface, convert user inputted "<" */
|
2016-01-13 16:09:58 +08:00
|
|
|
if (keys[0] == '<' && keyname_len == 1) {
|
|
|
|
keys = "less";
|
2012-08-31 10:56:26 +08:00
|
|
|
keyname_len = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
keylist = g_malloc0(sizeof(*keylist));
|
2012-09-21 01:19:47 +08:00
|
|
|
keylist->value = g_malloc0(sizeof(*keylist->value));
|
2012-08-31 10:56:26 +08:00
|
|
|
|
|
|
|
if (!head) {
|
|
|
|
head = keylist;
|
|
|
|
}
|
|
|
|
if (tmp) {
|
|
|
|
tmp->next = keylist;
|
|
|
|
}
|
|
|
|
tmp = keylist;
|
|
|
|
|
2016-01-13 16:09:58 +08:00
|
|
|
if (strstart(keys, "0x", NULL)) {
|
2012-09-21 01:19:47 +08:00
|
|
|
char *endp;
|
2016-01-13 16:09:58 +08:00
|
|
|
int value = strtoul(keys, &endp, 0);
|
|
|
|
assert(endp <= keys + keyname_len);
|
|
|
|
if (endp != keys + keyname_len) {
|
2012-09-21 01:19:47 +08:00
|
|
|
goto err_out;
|
|
|
|
}
|
2015-10-27 06:34:58 +08:00
|
|
|
keylist->value->type = KEY_VALUE_KIND_NUMBER;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
keylist->value->u.number.data = value;
|
2012-09-21 01:19:47 +08:00
|
|
|
} else {
|
2016-01-13 16:09:58 +08:00
|
|
|
int idx = index_from_key(keys, keyname_len);
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 16:52:57 +08:00
|
|
|
if (idx == Q_KEY_CODE__MAX) {
|
2012-09-21 01:19:47 +08:00
|
|
|
goto err_out;
|
|
|
|
}
|
2015-10-27 06:34:58 +08:00
|
|
|
keylist->value->type = KEY_VALUE_KIND_QCODE;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
keylist->value->u.qcode.data = idx;
|
2012-09-21 01:19:47 +08:00
|
|
|
}
|
|
|
|
|
2018-06-29 18:32:10 +08:00
|
|
|
if (!*separator) {
|
2012-08-31 10:56:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
keys = separator + 1;
|
|
|
|
}
|
|
|
|
|
2012-09-21 01:19:47 +08:00
|
|
|
qmp_send_key(head, has_hold_time, hold_time, &err);
|
2012-08-31 10:56:26 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-21 01:19:47 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_KeyValueList(head);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_out:
|
2016-01-13 16:09:58 +08:00
|
|
|
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
2012-09-21 01:19:47 +08:00
|
|
|
goto out;
|
2012-08-31 10:56:26 +08:00
|
|
|
}
|
2012-05-25 00:48:23 +08:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 20:55:43 +08:00
|
|
|
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
2012-05-25 00:48:23 +08:00
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
2018-03-06 00:37:48 +08:00
|
|
|
const char *id = qdict_get_try_str(qdict, "device");
|
|
|
|
int64_t head = qdict_get_try_int(qdict, "head", 0);
|
2012-05-25 00:48:23 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-03-06 00:37:48 +08:00
|
|
|
qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
|
2012-05-25 00:48:23 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-08-23 17:53:04 +08:00
|
|
|
|
|
|
|
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool writable = qdict_get_try_bool(qdict, "writable", false);
|
|
|
|
bool all = qdict_get_try_bool(qdict, "all", false);
|
2012-08-23 17:53:04 +08:00
|
|
|
Error *local_err = NULL;
|
|
|
|
BlockInfoList *block_list, *info;
|
2017-04-26 15:36:41 +08:00
|
|
|
SocketAddress *addr;
|
2012-08-23 17:53:04 +08:00
|
|
|
|
|
|
|
if (writable && !all) {
|
|
|
|
error_setg(&local_err, "-w only valid together with -a");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First check if the address is valid and start the server. */
|
|
|
|
addr = socket_parse(uri, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
nbd: allow authorization with nbd-server-start QMP command
As with the previous patch to qemu-nbd, the nbd-server-start QMP command
also needs to be able to specify authorization when enabling TLS encryption.
First the client must create a QAuthZ object instance using the
'object-add' command:
{
'execute': 'object-add',
'arguments': {
'qom-type': 'authz-list',
'id': 'authz0',
'parameters': {
'policy': 'deny',
'rules': [
{
'match': '*CN=fred',
'policy': 'allow'
}
]
}
}
}
They can then reference this in the new 'tls-authz' parameter when
executing the 'nbd-server-start' command:
{
'execute': 'nbd-server-start',
'arguments': {
'addr': {
'type': 'inet',
'host': '127.0.0.1',
'port': '9000'
},
'tls-creds': 'tls0',
'tls-authz': 'authz0'
}
}
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20190227162035.18543-3-berrange@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2019-02-28 00:20:34 +08:00
|
|
|
nbd_server_start(addr, NULL, NULL, &local_err);
|
2017-04-26 15:36:41 +08:00
|
|
|
qapi_free_SocketAddress(addr);
|
2012-08-23 17:53:04 +08:00
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!all) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then try adding all block devices. If one fails, close all and
|
|
|
|
* exit.
|
|
|
|
*/
|
|
|
|
block_list = qmp_query_block(NULL);
|
|
|
|
|
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (!info->value->has_inserted) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 21:57:15 +08:00
|
|
|
qmp_nbd_server_add(info->value->device, false, NULL,
|
nbd: Allow bitmap export during QMP nbd-server-add
With the experimental x-nbd-server-add-bitmap command, there was
a window of time where an NBD client could see the export but not
the associated dirty bitmap, which can cause a client that planned
on using the dirty bitmap to be forced to treat the entire image
as dirty as a safety fallback. Furthermore, if the QMP client
successfully exports a disk but then fails to add the bitmap, it
has to take on the burden of removing the export. Since we don't
allow changing the exposed dirty bitmap (whether to a different
bitmap, or removing advertisement of the bitmap), it is nicer to
make the bitmap tied to the export at the time the export is
created, with automatic failure to export if the bitmap is not
available.
The experimental command included an optional 'bitmap-export-name'
field for remapping the name exposed over NBD to be different from
the bitmap name stored on disk. However, my libvirt demo code
for implementing differential backups on top of persistent bitmaps
did not need to take advantage of that feature (it is instead
possible to create a new temporary bitmap with the desired name,
use block-dirty-bitmap-merge to merge one or more persistent
bitmaps into the temporary, then associate the temporary with the
NBD export, if control is needed over the exported bitmap name).
Hence, I'm not copying that part of the experiment over to the
stable addition. For more details on the libvirt demo, see
https://www.redhat.com/archives/libvir-list/2018-October/msg01254.html,
https://kvmforum2018.sched.com/event/FzuB/facilitating-incremental-backup-eric-blake-red-hat
This patch focuses on the user interface, and reduces (but does
not completely eliminate) the window where an NBD client can see
the export but not the dirty bitmap, with less work to clean up
after errors. Later patches will add further cleanups now that
this interface is declared stable via a single QMP command,
including removing the race window.
Update test 223 to use the new interface.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20190111194720.15671-6-eblake@redhat.com>
2019-01-12 03:47:17 +08:00
|
|
|
true, writable, false, NULL, &local_err);
|
2012-08-23 17:53:04 +08:00
|
|
|
|
|
|
|
if (local_err != NULL) {
|
|
|
|
qmp_nbd_server_stop(NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
|
|
|
|
|
|
|
exit:
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2018-01-10 03:28:02 +08:00
|
|
|
const char *name = qdict_get_try_str(qdict, "name");
|
2015-05-16 06:25:00 +08:00
|
|
|
bool writable = qdict_get_try_bool(qdict, "writable", false);
|
2012-08-23 17:53:04 +08:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
nbd: Allow bitmap export during QMP nbd-server-add
With the experimental x-nbd-server-add-bitmap command, there was
a window of time where an NBD client could see the export but not
the associated dirty bitmap, which can cause a client that planned
on using the dirty bitmap to be forced to treat the entire image
as dirty as a safety fallback. Furthermore, if the QMP client
successfully exports a disk but then fails to add the bitmap, it
has to take on the burden of removing the export. Since we don't
allow changing the exposed dirty bitmap (whether to a different
bitmap, or removing advertisement of the bitmap), it is nicer to
make the bitmap tied to the export at the time the export is
created, with automatic failure to export if the bitmap is not
available.
The experimental command included an optional 'bitmap-export-name'
field for remapping the name exposed over NBD to be different from
the bitmap name stored on disk. However, my libvirt demo code
for implementing differential backups on top of persistent bitmaps
did not need to take advantage of that feature (it is instead
possible to create a new temporary bitmap with the desired name,
use block-dirty-bitmap-merge to merge one or more persistent
bitmaps into the temporary, then associate the temporary with the
NBD export, if control is needed over the exported bitmap name).
Hence, I'm not copying that part of the experiment over to the
stable addition. For more details on the libvirt demo, see
https://www.redhat.com/archives/libvir-list/2018-October/msg01254.html,
https://kvmforum2018.sched.com/event/FzuB/facilitating-incremental-backup-eric-blake-red-hat
This patch focuses on the user interface, and reduces (but does
not completely eliminate) the window where an NBD client can see
the export but not the dirty bitmap, with less work to clean up
after errors. Later patches will add further cleanups now that
this interface is declared stable via a single QMP command,
including removing the race window.
Update test 223 to use the new interface.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20190111194720.15671-6-eblake@redhat.com>
2019-01-12 03:47:17 +08:00
|
|
|
qmp_nbd_server_add(device, !!name, name, true, writable,
|
|
|
|
false, NULL, &local_err);
|
2018-01-25 22:45:57 +08:00
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
2012-08-23 17:53:04 +08:00
|
|
|
|
2018-01-25 22:45:57 +08:00
|
|
|
void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
/* Rely on NBD_SERVER_REMOVE_MODE_SAFE being the default */
|
|
|
|
qmp_nbd_server_remove(name, force, NBD_SERVER_REMOVE_MODE_HARD, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-23 17:53:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 19:26:29 +08:00
|
|
|
Error *err = NULL;
|
2012-08-23 17:53:04 +08:00
|
|
|
|
2014-05-02 19:26:29 +08:00
|
|
|
qmp_nbd_server_stop(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-23 17:53:04 +08:00
|
|
|
}
|
2012-12-19 17:33:40 +08:00
|
|
|
|
2013-12-12 02:24:14 +08:00
|
|
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int cpuid;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-10-30 20:35:25 +08:00
|
|
|
error_report("cpu_add is deprecated, please use device_add instead");
|
|
|
|
|
2013-12-12 02:24:14 +08:00
|
|
|
cpuid = qdict_get_int(qdict, "id");
|
|
|
|
qmp_cpu_add(cpuid, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-12-19 17:33:40 +08:00
|
|
|
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *args = qdict_get_str(qdict, "args");
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 19:50:26 +08:00
|
|
|
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, true);
|
2012-12-19 17:33:40 +08:00
|
|
|
if (opts == NULL) {
|
error: Strip trailing '\n' from error string arguments (again)
Commit 6daf194d and be62a2eb got rid of a bunch, but they keep coming
back. Tracked down with this Coccinelle semantic patch:
@r@
expression err, eno, cls, fmt;
position p;
@@
(
error_report(fmt, ...)@p
|
error_set(err, cls, fmt, ...)@p
|
error_set_errno(err, eno, cls, fmt, ...)@p
|
error_setg(err, fmt, ...)@p
|
error_setg_errno(err, eno, fmt, ...)@p
)
@script:python@
fmt << r.fmt;
p << r.p;
@@
if "\\n" in str(fmt):
print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-id: 1360354939-10994-4-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-09 04:22:16 +08:00
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
2012-12-19 17:33:40 +08:00
|
|
|
} else {
|
2019-02-13 21:18:13 +08:00
|
|
|
qemu_chr_new_from_opts(opts, NULL, &err);
|
net: don't poke at chardev internal QemuOpts
The vhost-user & colo code is poking at the QemuOpts instance
in the CharDriverState struct, not realizing that it is valid
for this to be NULL. e.g. the following crash shows a codepath
where it will be NULL:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
617 QTAILQ_FOREACH(opt, &opts->head, next) {
[Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))]
(gdb) bt
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
#1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314
#2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360
#3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051
#4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108
#5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186
#6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205
#7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978
#8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105
#9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319
#10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369
#11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124
#12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994
#13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387
#14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399
#15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927
#16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a <tcp_chr_read>, user_data=0x55baf7610a40) at io/channel-watch.c:84
#17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0
#18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213
#19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258
#20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506
#21 0x000055baf676587b in main_loop () at vl.c:1908
#22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604
(gdb) p opts
$1 = (QemuOpts *) 0x0
The crash occurred when attaching vhost-user net via QMP:
{
"execute": "chardev-add",
"arguments": {
"id": "charnet2",
"backend": {
"type": "socket",
"data": {
"addr": {
"type": "unix",
"data": {
"path": "/var/run/openvswitch/vhost-user1"
}
},
"wait": false,
"server": false
}
}
},
"id": "libvirt-19"
}
{
"return": {
},
"id": "libvirt-19"
}
{
"execute": "netdev_add",
"arguments": {
"type": "vhost-user",
"chardev": "charnet2",
"id": "hostnet2"
},
"id": "libvirt-20"
}
Code using chardevs should not be poking at the internals of the
CharDriverState struct. What vhost-user wants is a chardev that is
operating as reconnectable network service, along with the ability
to do FD passing over the connection. The colo code simply wants
a network service. Add a feature concept to the char drivers so
that chardev users can query the actual features they wish to have
supported. The QemuOpts member is removed to prevent future mistakes
in this area.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-10-07 20:18:34 +08:00
|
|
|
qemu_opts_del(opts);
|
2012-12-19 17:33:40 +08:00
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2017-07-06 20:08:57 +08:00
|
|
|
void hmp_chardev_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *args = qdict_get_str(qdict, "args");
|
|
|
|
const char *id;
|
|
|
|
Error *err = NULL;
|
|
|
|
ChardevBackend *backend = NULL;
|
|
|
|
ChardevReturn *ret = NULL;
|
|
|
|
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args,
|
|
|
|
true);
|
|
|
|
if (!opts) {
|
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = qdict_get_str(qdict, "id");
|
|
|
|
if (qemu_opts_id(opts)) {
|
|
|
|
error_setg(&err, "Unexpected 'id' parameter");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
backend = qemu_chr_parse_opts(opts, &err);
|
|
|
|
if (!backend) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = qmp_chardev_change(id, backend, &err);
|
|
|
|
|
|
|
|
end:
|
|
|
|
qapi_free_ChardevReturn(ret);
|
|
|
|
qapi_free_ChardevBackend(backend);
|
|
|
|
qemu_opts_del(opts);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-12-19 17:33:40 +08:00
|
|
|
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
2013-06-05 20:19:41 +08:00
|
|
|
|
2017-06-11 15:48:17 +08:00
|
|
|
void hmp_chardev_send_break(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_send_break(qdict_get_str(qdict, "id"), &local_err);
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
|
2013-06-05 20:19:41 +08:00
|
|
|
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-02-06 02:58:22 +08:00
|
|
|
BlockBackend *blk;
|
2016-07-13 23:27:51 +08:00
|
|
|
BlockBackend *local_blk = NULL;
|
2013-06-05 20:19:41 +08:00
|
|
|
const char* device = qdict_get_str(qdict, "device");
|
|
|
|
const char* command = qdict_get_str(qdict, "command");
|
|
|
|
Error *err = NULL;
|
2017-01-14 02:02:32 +08:00
|
|
|
int ret;
|
2013-06-05 20:19:41 +08:00
|
|
|
|
2015-02-06 02:58:22 +08:00
|
|
|
blk = blk_by_name(device);
|
2016-07-13 23:27:51 +08:00
|
|
|
if (!blk) {
|
|
|
|
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
|
|
|
|
if (bs) {
|
2019-04-25 20:25:10 +08:00
|
|
|
blk = local_blk = blk_new(bdrv_get_aio_context(bs),
|
|
|
|
0, BLK_PERM_ALL);
|
2017-01-14 02:02:32 +08:00
|
|
|
ret = blk_insert_bs(blk, bs, &err);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-07-13 23:27:51 +08:00
|
|
|
} else {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 23:24:56 +08:00
|
|
|
/*
|
|
|
|
* Notably absent: Proper permission management. This is sad, but it seems
|
|
|
|
* almost impossible to achieve without changing the semantics and thereby
|
|
|
|
* limiting the use cases of the qemu-io HMP command.
|
|
|
|
*
|
|
|
|
* In an ideal world we would unconditionally create a new BlockBackend for
|
|
|
|
* qemuio_command(), but we have commands like 'reopen' and want them to
|
|
|
|
* take effect on the exact BlockBackend whose name the user passed instead
|
|
|
|
* of just on a temporary copy of it.
|
|
|
|
*
|
|
|
|
* Another problem is that deleting the temporary BlockBackend involves
|
|
|
|
* draining all requests on it first, but some qemu-iotests cases want to
|
|
|
|
* issue multiple aio_read/write requests and expect them to complete in
|
|
|
|
* the background while the monitor has already returned.
|
|
|
|
*
|
|
|
|
* This is also what prevents us from saving the original permissions and
|
|
|
|
* restoring them later: We can't revoke permissions until all requests
|
|
|
|
* have completed, and we don't know when that is nor can we really let
|
|
|
|
* anything else run before we have revoken them to avoid race conditions.
|
|
|
|
*
|
|
|
|
* What happens now is that command() in qemu-io-cmds.c can extend the
|
|
|
|
* permissions if necessary for the qemu-io command. And they simply stay
|
|
|
|
* extended, possibly resulting in a read-only guest device keeping write
|
|
|
|
* permissions. Ugly, but it appears to be the lesser evil.
|
|
|
|
*/
|
2016-09-15 23:44:16 +08:00
|
|
|
qemuio_command(blk, command);
|
2013-06-05 20:19:41 +08:00
|
|
|
|
2016-07-13 23:27:51 +08:00
|
|
|
fail:
|
|
|
|
blk_unref(local_blk);
|
2013-06-05 20:19:41 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2013-12-21 06:21:09 +08:00
|
|
|
|
|
|
|
void hmp_object_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2016-02-11 02:40:59 +08:00
|
|
|
user_creatable_del(id, &err);
|
2013-12-21 06:21:09 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-14 17:43:35 +08:00
|
|
|
|
|
|
|
void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemdevList *memdev_list = qmp_query_memdev(&err);
|
|
|
|
MemdevList *m = memdev_list;
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-10 00:48:43 +08:00
|
|
|
Visitor *v;
|
2014-08-18 14:46:34 +08:00
|
|
|
char *str;
|
2014-05-14 17:43:35 +08:00
|
|
|
|
|
|
|
while (m) {
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-10 00:48:43 +08:00
|
|
|
v = string_output_visitor_new(false, &str);
|
|
|
|
visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
|
2017-01-10 20:53:15 +08:00
|
|
|
monitor_printf(mon, "memory backend: %s\n", m->value->id);
|
2014-05-14 17:43:35 +08:00
|
|
|
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
|
|
|
monitor_printf(mon, " merge: %s\n",
|
|
|
|
m->value->merge ? "true" : "false");
|
|
|
|
monitor_printf(mon, " dump: %s\n",
|
|
|
|
m->value->dump ? "true" : "false");
|
|
|
|
monitor_printf(mon, " prealloc: %s\n",
|
|
|
|
m->value->prealloc ? "true" : "false");
|
|
|
|
monitor_printf(mon, " policy: %s\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
HostMemPolicy_str(m->value->policy));
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-10 00:48:43 +08:00
|
|
|
visit_complete(v, &str);
|
2014-08-18 14:46:34 +08:00
|
|
|
monitor_printf(mon, " host nodes: %s\n", str);
|
2014-05-14 17:43:35 +08:00
|
|
|
|
2014-08-18 14:46:34 +08:00
|
|
|
g_free(str);
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-10 00:48:43 +08:00
|
|
|
visit_free(v);
|
2014-05-14 17:43:35 +08:00
|
|
|
m = m->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
2014-08-18 14:46:35 +08:00
|
|
|
|
|
|
|
qapi_free_MemdevList(memdev_list);
|
2017-08-17 18:42:15 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2014-05-14 17:43:35 +08:00
|
|
|
}
|
2014-09-23 13:35:19 +08:00
|
|
|
|
|
|
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
|
|
|
|
MemoryDeviceInfoList *info;
|
|
|
|
MemoryDeviceInfo *value;
|
|
|
|
PCDIMMDeviceInfo *di;
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
value = info->value;
|
|
|
|
|
|
|
|
if (value) {
|
2015-10-27 06:34:59 +08:00
|
|
|
switch (value->type) {
|
2014-09-23 13:35:19 +08:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 06:48:37 +08:00
|
|
|
di = value->u.dimm.data;
|
2018-03-11 11:02:12 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
|
|
|
|
di = value->u.nvdimm.data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
di = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2014-09-23 13:35:19 +08:00
|
|
|
|
2018-03-11 11:02:12 +08:00
|
|
|
if (di) {
|
2014-09-23 13:35:19 +08:00
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
2017-08-24 16:46:08 +08:00
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
2014-09-23 13:35:19 +08:00
|
|
|
di->id ? di->id : "");
|
|
|
|
monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr);
|
|
|
|
monitor_printf(mon, " slot: %" PRId64 "\n", di->slot);
|
|
|
|
monitor_printf(mon, " node: %" PRId64 "\n", di->node);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", di->size);
|
|
|
|
monitor_printf(mon, " memdev: %s\n", di->memdev);
|
|
|
|
monitor_printf(mon, " hotplugged: %s\n",
|
|
|
|
di->hotplugged ? "true" : "false");
|
|
|
|
monitor_printf(mon, " hotpluggable: %s\n",
|
|
|
|
di->hotpluggable ? "true" : "false");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryDeviceInfoList(info_list);
|
2017-08-17 18:42:15 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2014-09-23 13:35:19 +08:00
|
|
|
}
|
2014-05-08 00:08:29 +08:00
|
|
|
|
2015-06-26 16:07:13 +08:00
|
|
|
void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
|
|
|
|
IOThreadInfoList *info;
|
2017-02-10 17:41:17 +08:00
|
|
|
IOThreadInfo *value;
|
2015-06-26 16:07:13 +08:00
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
2017-02-10 17:41:17 +08:00
|
|
|
value = info->value;
|
|
|
|
monitor_printf(mon, "%s:\n", value->id);
|
|
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
|
|
|
|
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
|
|
|
|
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
|
|
|
|
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
|
2015-06-26 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_IOThreadInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2014-05-08 00:08:29 +08:00
|
|
|
void hmp_qom_list(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
ObjectPropertyInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
if (path == NULL) {
|
|
|
|
monitor_printf(mon, "/\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = qmp_qom_list(path, &err);
|
|
|
|
if (err == NULL) {
|
|
|
|
ObjectPropertyInfoList *start = list;
|
|
|
|
while (list != NULL) {
|
|
|
|
ObjectPropertyInfo *value = list->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s (%s)\n",
|
|
|
|
value->name, value->type);
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ObjectPropertyInfoList(start);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-08 01:48:15 +08:00
|
|
|
|
|
|
|
void hmp_qom_set(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_str(qdict, "path");
|
|
|
|
const char *property = qdict_get_str(qdict, "property");
|
|
|
|
const char *value = qdict_get_str(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
bool ambiguous = false;
|
|
|
|
Object *obj;
|
|
|
|
|
|
|
|
obj = object_resolve_path(path, &ambiguous);
|
|
|
|
if (obj == NULL) {
|
2015-03-16 15:57:47 +08:00
|
|
|
error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", path);
|
2014-05-08 01:48:15 +08:00
|
|
|
} else {
|
|
|
|
if (ambiguous) {
|
|
|
|
monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
|
|
|
|
}
|
|
|
|
object_property_parse(obj, value, property, &err);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2015-06-11 09:21:21 +08:00
|
|
|
|
|
|
|
void hmp_rocker(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
RockerSwitch *rocker;
|
2015-12-18 23:35:27 +08:00
|
|
|
Error *err = NULL;
|
2015-06-11 09:21:21 +08:00
|
|
|
|
2015-12-18 23:35:27 +08:00
|
|
|
rocker = qmp_query_rocker(name, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 09:21:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "name: %s\n", rocker->name);
|
|
|
|
monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id);
|
|
|
|
monitor_printf(mon, "ports: %d\n", rocker->ports);
|
|
|
|
|
|
|
|
qapi_free_RockerSwitch(rocker);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_ports(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerPortList *list, *port;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2015-12-18 23:35:27 +08:00
|
|
|
Error *err = NULL;
|
2015-06-11 09:21:21 +08:00
|
|
|
|
2015-12-18 23:35:27 +08:00
|
|
|
list = qmp_query_rocker_ports(name, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 09:21:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " ena/ speed/ auto\n");
|
|
|
|
monitor_printf(mon, " port link duplex neg?\n");
|
|
|
|
|
|
|
|
for (port = list; port; port = port->next) {
|
|
|
|
monitor_printf(mon, "%10s %-4s %-3s %2s %-3s\n",
|
|
|
|
port->value->name,
|
|
|
|
port->value->enabled ? port->value->link_up ?
|
|
|
|
"up" : "down" : "!ena",
|
|
|
|
port->value->speed == 10000 ? "10G" : "??",
|
|
|
|
port->value->duplex ? "FD" : "HD",
|
|
|
|
port->value->autoneg ? "Yes" : "No");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerPortList(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerOfDpaFlowList *list, *info;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1);
|
2015-12-18 23:35:27 +08:00
|
|
|
Error *err = NULL;
|
2015-06-11 09:21:21 +08:00
|
|
|
|
2015-12-18 23:35:27 +08:00
|
|
|
list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 09:21:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "prio tbl hits key(mask) --> actions\n");
|
|
|
|
|
|
|
|
for (info = list; info; info = info->next) {
|
|
|
|
RockerOfDpaFlow *flow = info->value;
|
|
|
|
RockerOfDpaFlowKey *key = flow->key;
|
|
|
|
RockerOfDpaFlowMask *mask = flow->mask;
|
|
|
|
RockerOfDpaFlowAction *action = flow->action;
|
|
|
|
|
|
|
|
if (flow->hits) {
|
|
|
|
monitor_printf(mon, "%-4d %-3d %-4" PRIu64,
|
|
|
|
key->priority, key->tbl_id, flow->hits);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%-4d %-3d ",
|
|
|
|
key->priority, key->tbl_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_in_pport) {
|
|
|
|
monitor_printf(mon, " pport %d", key->in_pport);
|
|
|
|
if (mask->has_in_pport) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->in_pport);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_vlan_id) {
|
|
|
|
monitor_printf(mon, " vlan %d",
|
|
|
|
key->vlan_id & VLAN_VID_MASK);
|
|
|
|
if (mask->has_vlan_id) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->vlan_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_tunnel_id) {
|
|
|
|
monitor_printf(mon, " tunnel %d", key->tunnel_id);
|
|
|
|
if (mask->has_tunnel_id) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->tunnel_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_type) {
|
|
|
|
switch (key->eth_type) {
|
|
|
|
case 0x0806:
|
|
|
|
monitor_printf(mon, " ARP");
|
|
|
|
break;
|
|
|
|
case 0x0800:
|
|
|
|
monitor_printf(mon, " IP");
|
|
|
|
break;
|
|
|
|
case 0x86dd:
|
|
|
|
monitor_printf(mon, " IPv6");
|
|
|
|
break;
|
|
|
|
case 0x8809:
|
|
|
|
monitor_printf(mon, " LACP");
|
|
|
|
break;
|
|
|
|
case 0x88cc:
|
|
|
|
monitor_printf(mon, " LLDP");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
monitor_printf(mon, " eth type 0x%04x", key->eth_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_src) {
|
|
|
|
if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_src) &&
|
|
|
|
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " src <any mcast/bcast>");
|
|
|
|
} else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_src) &&
|
|
|
|
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " src <any ucast>");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, " src %s", key->eth_src);
|
|
|
|
if (mask->has_eth_src) {
|
|
|
|
monitor_printf(mon, "(%s)", mask->eth_src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_dst) {
|
|
|
|
if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_dst) &&
|
|
|
|
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " dst <any mcast/bcast>");
|
|
|
|
} else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_dst) &&
|
|
|
|
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " dst <any ucast>");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, " dst %s", key->eth_dst);
|
|
|
|
if (mask->has_eth_dst) {
|
|
|
|
monitor_printf(mon, "(%s)", mask->eth_dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_proto) {
|
|
|
|
monitor_printf(mon, " proto %d", key->ip_proto);
|
|
|
|
if (mask->has_ip_proto) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->ip_proto);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_tos) {
|
|
|
|
monitor_printf(mon, " TOS %d", key->ip_tos);
|
|
|
|
if (mask->has_ip_tos) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->ip_tos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_dst) {
|
|
|
|
monitor_printf(mon, " dst %s", key->ip_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_goto_tbl || action->has_group_id ||
|
|
|
|
action->has_new_vlan_id) {
|
|
|
|
monitor_printf(mon, " -->");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_new_vlan_id) {
|
|
|
|
monitor_printf(mon, " apply new vlan %d",
|
|
|
|
ntohs(action->new_vlan_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_group_id) {
|
|
|
|
monitor_printf(mon, " write group 0x%08x", action->group_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_goto_tbl) {
|
|
|
|
monitor_printf(mon, " goto tbl %d", action->goto_tbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerOfDpaFlowList(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerOfDpaGroupList *list, *g;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
uint8_t type = qdict_get_try_int(qdict, "type", 9);
|
2015-12-18 23:35:27 +08:00
|
|
|
Error *err = NULL;
|
2015-06-11 09:21:21 +08:00
|
|
|
bool set = false;
|
|
|
|
|
2015-12-18 23:35:27 +08:00
|
|
|
list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 09:21:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "id (decode) --> buckets\n");
|
|
|
|
|
|
|
|
for (g = list; g; g = g->next) {
|
|
|
|
RockerOfDpaGroup *group = g->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, "0x%08x", group->id);
|
|
|
|
|
|
|
|
monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" :
|
|
|
|
group->type == 1 ? "L2 rewrite" :
|
|
|
|
group->type == 2 ? "L3 unicast" :
|
|
|
|
group->type == 3 ? "L2 multicast" :
|
|
|
|
group->type == 4 ? "L2 flood" :
|
|
|
|
group->type == 5 ? "L3 interface" :
|
|
|
|
group->type == 6 ? "L3 multicast" :
|
|
|
|
group->type == 7 ? "L3 ECMP" :
|
|
|
|
group->type == 8 ? "L2 overlay" :
|
|
|
|
"unknown");
|
|
|
|
|
|
|
|
if (group->has_vlan_id) {
|
|
|
|
monitor_printf(mon, " vlan %d", group->vlan_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_pport) {
|
|
|
|
monitor_printf(mon, " pport %d", group->pport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_index) {
|
|
|
|
monitor_printf(mon, " index %d", group->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, ") -->");
|
|
|
|
|
|
|
|
if (group->has_set_vlan_id && group->set_vlan_id) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set vlan %d",
|
|
|
|
group->set_vlan_id & VLAN_VID_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_set_eth_src) {
|
|
|
|
if (!set) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " src %s", group->set_eth_src);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_set_eth_dst) {
|
|
|
|
if (!set) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " dst %s", group->set_eth_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
set = false;
|
|
|
|
|
|
|
|
if (group->has_ttl_check && group->ttl_check) {
|
|
|
|
monitor_printf(mon, " check TTL");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_group_id && group->group_id) {
|
|
|
|
monitor_printf(mon, " group id 0x%08x", group->group_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_pop_vlan && group->pop_vlan) {
|
|
|
|
monitor_printf(mon, " pop vlan");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_out_pport) {
|
|
|
|
monitor_printf(mon, " out pport %d", group->out_pport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_group_ids) {
|
|
|
|
struct uint32List *id;
|
|
|
|
|
|
|
|
monitor_printf(mon, " groups [");
|
|
|
|
for (id = group->group_ids; id; id = id->next) {
|
|
|
|
monitor_printf(mon, "0x%08x", id->value);
|
|
|
|
if (id->next) {
|
|
|
|
monitor_printf(mon, ",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "]");
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerOfDpaGroupList(list);
|
|
|
|
}
|
2016-02-18 13:16:55 +08:00
|
|
|
|
|
|
|
void hmp_info_dump(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
DumpQueryResult *result = qmp_query_dump(NULL);
|
|
|
|
|
|
|
|
assert(result && result->status < DUMP_STATUS__MAX);
|
2017-08-24 16:46:08 +08:00
|
|
|
monitor_printf(mon, "Status: %s\n", DumpStatus_str(result->status));
|
2016-02-18 13:16:55 +08:00
|
|
|
|
|
|
|
if (result->status == DUMP_STATUS_ACTIVE) {
|
|
|
|
float percent = 0;
|
|
|
|
assert(result->total != 0);
|
|
|
|
percent = 100.0 * result->completed / result->total;
|
|
|
|
monitor_printf(mon, "Finished: %.2f %%\n", percent);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_DumpQueryResult(result);
|
|
|
|
}
|
2016-06-10 08:59:07 +08:00
|
|
|
|
2017-05-12 12:17:41 +08:00
|
|
|
void hmp_info_ramblock(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
ram_block_dump(mon);
|
|
|
|
}
|
|
|
|
|
2016-06-10 08:59:07 +08:00
|
|
|
void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
HotpluggableCPUList *l = qmp_query_hotpluggable_cpus(&err);
|
|
|
|
HotpluggableCPUList *saved = l;
|
|
|
|
CpuInstanceProperties *c;
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "Hotpluggable CPUs:\n");
|
|
|
|
while (l) {
|
|
|
|
monitor_printf(mon, " type: \"%s\"\n", l->value->type);
|
|
|
|
monitor_printf(mon, " vcpus_count: \"%" PRIu64 "\"\n",
|
|
|
|
l->value->vcpus_count);
|
|
|
|
if (l->value->has_qom_path) {
|
|
|
|
monitor_printf(mon, " qom_path: \"%s\"\n", l->value->qom_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
c = l->value->props;
|
|
|
|
monitor_printf(mon, " CPUInstance Properties:\n");
|
2016-06-24 05:23:34 +08:00
|
|
|
if (c->has_node_id) {
|
|
|
|
monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
|
2016-06-10 08:59:07 +08:00
|
|
|
}
|
2016-06-24 05:23:34 +08:00
|
|
|
if (c->has_socket_id) {
|
|
|
|
monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
|
2016-06-10 08:59:07 +08:00
|
|
|
}
|
2016-06-24 05:23:34 +08:00
|
|
|
if (c->has_core_id) {
|
|
|
|
monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
|
2016-06-10 08:59:07 +08:00
|
|
|
}
|
2016-06-24 05:23:34 +08:00
|
|
|
if (c->has_thread_id) {
|
|
|
|
monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
|
2016-06-10 08:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
l = l->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_HotpluggableCPUList(saved);
|
|
|
|
}
|
2017-02-17 07:15:37 +08:00
|
|
|
|
|
|
|
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-03-03 05:36:50 +08:00
|
|
|
Error *err = NULL;
|
|
|
|
GuidInfo *info = qmp_query_vm_generation_id(&err);
|
2017-02-17 07:15:37 +08:00
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "%s\n", info->guid);
|
|
|
|
}
|
2017-03-03 05:36:50 +08:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-02-17 07:15:37 +08:00
|
|
|
qapi_free_GuidInfo(info);
|
|
|
|
}
|
2017-08-29 23:30:22 +08:00
|
|
|
|
|
|
|
void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryInfo *info = qmp_query_memory_size_summary(&err);
|
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "base memory: %" PRIu64 "\n",
|
|
|
|
info->base_memory);
|
|
|
|
|
|
|
|
if (info->has_plugged_memory) {
|
|
|
|
monitor_printf(mon, "plugged memory: %" PRIu64 "\n",
|
|
|
|
info->plugged_memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryInfo(info);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|