2011-09-02 19:34:48 +02:00
|
|
|
/*
|
2019-06-13 17:33:58 +02:00
|
|
|
* Human Monitor Interface commands
|
2011-09-02 19:34:48 +02: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-13 17:44:23 +01: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-02 19:34:48 +02:00
|
|
|
*/
|
|
|
|
|
2016-01-29 18:50:05 +01:00
|
|
|
#include "qemu/osdep.h"
|
2019-06-19 22:10:36 +02:00
|
|
|
#include "monitor/hmp.h"
|
2012-10-24 08:43:34 +02:00
|
|
|
#include "net/net.h"
|
2015-06-11 03:21:21 +02:00
|
|
|
#include "net/eth.h"
|
2017-01-26 14:19:46 +01:00
|
|
|
#include "chardev/char.h"
|
2015-02-05 19:58:22 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2019-08-12 07:23:59 +02:00
|
|
|
#include "sysemu/runstate.h"
|
2016-12-12 18:22:24 +01:00
|
|
|
#include "qemu/config-file.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/timer.h"
|
|
|
|
#include "qemu/sockets.h"
|
2020-11-11 11:52:22 +01:00
|
|
|
#include "qemu/help_option.h"
|
2019-06-13 17:33:59 +02:00
|
|
|
#include "monitor/monitor-internal.h"
|
2018-02-01 12:18:31 +01:00
|
|
|
#include "qapi/error.h"
|
2019-06-20 20:47:03 +02:00
|
|
|
#include "qapi/clone-visitor.h"
|
2013-12-20 23:21:10 +01:00
|
|
|
#include "qapi/opts-visitor.h"
|
2018-02-11 10:36:05 +01:00
|
|
|
#include "qapi/qapi-builtin-visit.h"
|
2018-02-27 00:13:27 +01:00
|
|
|
#include "qapi/qapi-commands-block.h"
|
|
|
|
#include "qapi/qapi-commands-char.h"
|
2020-01-29 11:22:37 +01:00
|
|
|
#include "qapi/qapi-commands-control.h"
|
2020-09-13 21:53:43 +02:00
|
|
|
#include "qapi/qapi-commands-machine.h"
|
2018-02-27 00:13:27 +01:00
|
|
|
#include "qapi/qapi-commands-migration.h"
|
|
|
|
#include "qapi/qapi-commands-misc.h"
|
|
|
|
#include "qapi/qapi-commands-net.h"
|
2020-09-13 21:53:48 +02:00
|
|
|
#include "qapi/qapi-commands-pci.h"
|
2018-02-27 00:13:27 +01:00
|
|
|
#include "qapi/qapi-commands-rocker.h"
|
|
|
|
#include "qapi/qapi-commands-run-state.h"
|
2022-04-26 12:17:35 +02:00
|
|
|
#include "qapi/qapi-commands-stats.h"
|
2018-02-27 00:13:27 +01:00
|
|
|
#include "qapi/qapi-commands-tpm.h"
|
|
|
|
#include "qapi/qapi-commands-ui.h"
|
2022-08-11 14:24:44 +02:00
|
|
|
#include "qapi/qapi-commands-virtio.h"
|
|
|
|
#include "qapi/qapi-visit-virtio.h"
|
2019-06-20 20:47:03 +02:00
|
|
|
#include "qapi/qapi-visit-net.h"
|
2019-01-16 10:35:55 +01:00
|
|
|
#include "qapi/qapi-visit-migration.h"
|
2018-02-01 12:18:39 +01:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 17:22:46 +01:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2017-05-16 11:37:45 +02:00
|
|
|
#include "qapi/string-input-visitor.h"
|
2014-05-14 11:43:35 +02:00
|
|
|
#include "qapi/string-output-visitor.h"
|
2016-02-10 19:40:59 +01:00
|
|
|
#include "qom/object_interfaces.h"
|
2012-11-28 12:06:30 +01:00
|
|
|
#include "ui/console.h"
|
2016-03-20 18:16:19 +01: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 12:05:00 +02:00
|
|
|
#include "qemu/error-report.h"
|
2022-04-26 12:17:35 +02:00
|
|
|
#include "hw/core/cpu.h"
|
2016-09-26 22:23:27 +02:00
|
|
|
#include "hw/intc/intc.h"
|
2017-04-20 14:25:55 +02:00
|
|
|
#include "migration/snapshot.h"
|
2017-06-27 06:10:19 +02:00
|
|
|
#include "migration/misc.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
|
2015-03-01 15:29:18 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
|
|
|
#include <spice/enums.h>
|
|
|
|
#endif
|
|
|
|
|
2021-10-28 17:18:25 +02:00
|
|
|
bool hmp_handle_error(Monitor *mon, Error *err)
|
2011-11-22 19:32:37 +01:00
|
|
|
{
|
2019-12-05 18:46:18 +01:00
|
|
|
if (err) {
|
|
|
|
error_reportf_err(err, "Error: ");
|
2021-10-28 17:18:25 +02:00
|
|
|
return true;
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
2021-10-28 17:18:25 +02:00
|
|
|
return false;
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
|
|
|
|
2019-06-20 20:47:03 +02: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;
|
2021-01-13 23:10:12 +01:00
|
|
|
strList **tail = &res;
|
2019-06-20 20:47:03 +02:00
|
|
|
|
|
|
|
while (in && in[0]) {
|
|
|
|
char *comma = strchr(in, ',');
|
2021-01-13 23:10:12 +01:00
|
|
|
char *value;
|
2019-06-20 20:47:03 +02:00
|
|
|
|
|
|
|
if (comma) {
|
2021-01-13 23:10:12 +01:00
|
|
|
value = g_strndup(in, comma - in);
|
2019-06-20 20:47:03 +02:00
|
|
|
in = comma + 1; /* skip the , */
|
|
|
|
} else {
|
2021-01-13 23:10:12 +01:00
|
|
|
value = g_strdup(in);
|
2019-06-20 20:47:03 +02:00
|
|
|
in = NULL;
|
|
|
|
}
|
2021-01-13 23:10:12 +01:00
|
|
|
QAPI_LIST_APPEND(tail, value);
|
2019-06-20 20:47:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_name(Monitor *mon, const QDict *qdict)
|
2011-09-02 19:34:48 +02: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-26 22:38:13 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_version(Monitor *mon, const QDict *qdict)
|
2011-08-26 22:38:13 +02:00
|
|
|
{
|
|
|
|
VersionInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_version(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
|
2015-05-04 17:05:31 +02:00
|
|
|
info->qemu->major, info->qemu->minor, info->qemu->micro,
|
2011-08-26 22:38:13 +02:00
|
|
|
info->package);
|
|
|
|
|
|
|
|
qapi_free_VersionInfo(info);
|
|
|
|
}
|
2011-09-12 20:10:53 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_kvm(Monitor *mon, const QDict *qdict)
|
2011-09-12 20:10:53 +02: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 07:06:25 +01:00
|
|
|
void hmp_info_status(Monitor *mon, const QDict *qdict)
|
2011-09-12 22:54:20 +02: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 10:46:08 +02:00
|
|
|
monitor_printf(mon, " (%s)", RunState_str(info->status));
|
2011-09-12 22:54:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
|
|
|
|
qapi_free_StatusInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:16:25 +02:00
|
|
|
{
|
|
|
|
UuidInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_uuid(NULL);
|
|
|
|
monitor_printf(mon, "%s\n", info->UUID);
|
|
|
|
qapi_free_UuidInfo(info);
|
|
|
|
}
|
2011-09-14 21:05:49 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_chardev(Monitor *mon, const QDict *qdict)
|
2011-09-14 21:05:49 +02: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-15 19:20:28 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
2011-09-21 20:29:55 +02: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);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:37:16 +02:00
|
|
|
{
|
|
|
|
MigrationInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2012-08-06 20:42:47 +02:00
|
|
|
|
2017-06-27 06:10:19 +02:00
|
|
|
migration_global_dump(mon);
|
|
|
|
|
2021-04-29 16:04:24 +02:00
|
|
|
if (info->blocked_reasons) {
|
migration: Display the migration blockers
Update 'info migrate' to display migration blocking information.
If the outbound migration is not blocked, there is no change, however
if it is blocked a message is displayed with a list of reasons why,
e.g.
qemu-system-x86_64 -nographic -smp 4 -m 4G -M pc,usb=on \
-chardev null,id=n -device usb-serial,chardev=n \
-virtfs local,path=/home,mount_tag=fs,security_model=none \
-drive if=virtio,file=myimage.qcow2
(qemu) info migrate
globals:
store-global-state: on
only-migratable: off
send-configuration: on
send-section-footer: on
decompress-error-check: on
clear-bitmap-shift: 18
Outgoing migration blocked:
Migration is disabled when VirtFS export path '/home' is mounted in the guest using mount_tag 'fs'
non-migratable device: 0000:00:01.2/1/usb-serial
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <20210202135522.127380-3-dgilbert@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
2021-02-02 14:55:22 +01:00
|
|
|
strList *reasons = info->blocked_reasons;
|
|
|
|
monitor_printf(mon, "Outgoing migration blocked:\n");
|
|
|
|
while (reasons) {
|
|
|
|
monitor_printf(mon, " %s\n", reasons->value);
|
|
|
|
reasons = reasons->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-13 22:37:16 +02: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 12:05:00 +02:00
|
|
|
monitor_printf(mon, "Migration status: %s",
|
2017-08-24 10:46:08 +02: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 12:05:00 +02:00
|
|
|
if (info->status == MIGRATION_STATUS_FAILED &&
|
|
|
|
info->has_error_desc) {
|
|
|
|
monitor_printf(mon, " (%s)\n", info->error_desc);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
2020-03-31 10:22:07 +02:00
|
|
|
monitor_printf(mon, "total time: %" PRIu64 " ms\n",
|
2012-08-18 13:17:10 +02:00
|
|
|
info->total_time);
|
2012-08-13 09:53:12 +02:00
|
|
|
if (info->has_expected_downtime) {
|
2020-03-31 10:22:07 +02:00
|
|
|
monitor_printf(mon, "expected downtime: %" PRIu64 " ms\n",
|
2012-08-13 09:53:12 +02:00
|
|
|
info->expected_downtime);
|
|
|
|
}
|
2012-08-13 09:35:16 +02:00
|
|
|
if (info->has_downtime) {
|
2020-03-31 10:22:07 +02:00
|
|
|
monitor_printf(mon, "downtime: %" PRIu64 " ms\n",
|
2012-08-13 09:35:16 +02:00
|
|
|
info->downtime);
|
|
|
|
}
|
2013-07-22 16:01:58 +02:00
|
|
|
if (info->has_setup_time) {
|
2020-03-31 10:22:07 +02:00
|
|
|
monitor_printf(mon, "setup: %" PRIu64 " ms\n",
|
2013-07-22 16:01:58 +02:00
|
|
|
info->setup_time);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_ram) {
|
|
|
|
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->transferred >> 10);
|
2013-06-26 03:35:30 +02:00
|
|
|
monitor_printf(mon, "throughput: %0.2f mbps\n",
|
|
|
|
info->ram->mbps);
|
2011-09-13 22:37:16 +02: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-06 20:42:56 +02:00
|
|
|
monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->duplicate);
|
2013-03-26 10:58:37 +01:00
|
|
|
monitor_printf(mon, "skipped: %" PRIu64 " pages\n",
|
|
|
|
info->ram->skipped);
|
2012-08-06 20:42:56 +02: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 11:57:55 +02:00
|
|
|
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
|
|
|
info->ram->dirty_sync_count);
|
2017-03-21 03:22:43 +01:00
|
|
|
monitor_printf(mon, "page size: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->page_size >> 10);
|
2018-06-26 15:20:11 +02:00
|
|
|
monitor_printf(mon, "multifd bytes: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->multifd_bytes >> 10);
|
2019-01-11 07:37:30 +01:00
|
|
|
monitor_printf(mon, "pages-per-second: %" PRIu64 "\n",
|
|
|
|
info->ram->pages_per_second);
|
2017-03-21 03:22:43 +01:00
|
|
|
|
2012-08-13 12:31:25 +02:00
|
|
|
if (info->ram->dirty_pages_rate) {
|
|
|
|
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->dirty_pages_rate);
|
|
|
|
}
|
2016-06-13 13:16:42 +02:00
|
|
|
if (info->ram->postcopy_requests) {
|
|
|
|
monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
|
|
|
|
info->ram->postcopy_requests);
|
|
|
|
}
|
2021-12-21 10:34:41 +01:00
|
|
|
if (info->ram->precopy_bytes) {
|
|
|
|
monitor_printf(mon, "precopy ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->precopy_bytes >> 10);
|
|
|
|
}
|
|
|
|
if (info->ram->downtime_bytes) {
|
|
|
|
monitor_printf(mon, "downtime ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->downtime_bytes >> 10);
|
|
|
|
}
|
|
|
|
if (info->ram->postcopy_bytes) {
|
|
|
|
monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->postcopy_bytes >> 10);
|
|
|
|
}
|
2022-07-11 23:11:12 +02:00
|
|
|
if (info->ram->dirty_sync_missed_zero_copy) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
"Zero-copy-send fallbacks happened: %" PRIu64 " times\n",
|
|
|
|
info->ram->dirty_sync_missed_zero_copy);
|
|
|
|
}
|
2011-09-13 22:37:16 +02: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-06 20:42:57 +02: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);
|
2020-06-03 10:09:02 +02:00
|
|
|
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 " pages\n",
|
2012-08-06 20:42:57 +02:00
|
|
|
info->xbzrle_cache->cache_miss);
|
2014-04-04 11:57:56 +02:00
|
|
|
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
|
|
|
info->xbzrle_cache->cache_miss_rate);
|
2020-04-30 02:59:35 +02:00
|
|
|
monitor_printf(mon, "xbzrle encoding rate: %0.2f\n",
|
|
|
|
info->xbzrle_cache->encoding_rate);
|
2020-03-20 15:32:16 +01:00
|
|
|
monitor_printf(mon, "xbzrle overflow: %" PRIu64 "\n",
|
2012-08-06 20:42:57 +02:00
|
|
|
info->xbzrle_cache->overflow);
|
|
|
|
}
|
|
|
|
|
2018-09-06 09:01:00 +02: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);
|
2020-06-03 10:09:02 +02:00
|
|
|
monitor_printf(mon, "compressed size: %" PRIu64 " kbytes\n",
|
|
|
|
info->compression->compressed_size >> 10);
|
2018-09-06 09:01:00 +02:00
|
|
|
monitor_printf(mon, "compression rate: %0.2f\n",
|
|
|
|
info->compression->compression_rate);
|
|
|
|
}
|
|
|
|
|
2016-04-21 20:07:18 +02:00
|
|
|
if (info->has_cpu_throttle_percentage) {
|
2015-09-08 19:12:36 +02:00
|
|
|
monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n",
|
2016-04-21 20:07:18 +02:00
|
|
|
info->cpu_throttle_percentage);
|
2015-09-08 19:12:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-22 19:17:27 +01: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);
|
2020-04-24 10:43:35 +02:00
|
|
|
visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime,
|
|
|
|
&error_abort);
|
2018-03-22 19:17:27 +01:00
|
|
|
visit_complete(v, &str);
|
|
|
|
monitor_printf(mon, "postcopy vcpu blocktime: %s\n", str);
|
|
|
|
g_free(str);
|
|
|
|
visit_free(v);
|
|
|
|
}
|
2019-02-27 11:51:27 +01:00
|
|
|
if (info->has_socket_address) {
|
|
|
|
SocketAddressList *addr;
|
|
|
|
|
|
|
|
monitor_printf(mon, "socket address: [\n");
|
|
|
|
|
|
|
|
for (addr = info->socket_address; addr; addr = addr->next) {
|
2022-10-21 11:09:18 +02:00
|
|
|
char *s = socket_uri(addr->value);
|
2019-02-27 11:51:27 +01:00
|
|
|
monitor_printf(mon, "\t%s\n", s);
|
|
|
|
g_free(s);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "]\n");
|
|
|
|
}
|
2020-10-26 10:36:27 +01:00
|
|
|
|
|
|
|
if (info->has_vfio) {
|
|
|
|
monitor_printf(mon, "vfio device transferred: %" PRIu64 " kbytes\n",
|
|
|
|
info->vfio->transferred >> 10);
|
|
|
|
}
|
|
|
|
|
2011-09-13 22:37:16 +02:00
|
|
|
qapi_free_MigrationInfo(info);
|
2012-08-06 20:42:47 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
|
2012-08-06 20:42:47 +02:00
|
|
|
{
|
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
|
|
|
|
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
|
|
|
if (caps) {
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
2017-04-01 10:18:44 +02:00
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationCapability_str(cap->value->capability),
|
2012-08-06 20:42:47 +02:00
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
2015-03-23 09:32:29 +01:00
|
|
|
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
MigrationParameters *params;
|
|
|
|
|
|
|
|
params = qmp_query_migrate_parameters(NULL);
|
|
|
|
|
|
|
|
if (params) {
|
2019-02-27 14:24:06 +01: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 05:14:15 +02:00
|
|
|
assert(params->has_compress_level);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->compress_level);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_compress_threads);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_THREADS),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->compress_threads);
|
2018-08-21 10:10:20 +02: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 05:14:15 +02:00
|
|
|
assert(params->has_decompress_threads);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->decompress_threads);
|
2020-02-24 03:31:42 +01:00
|
|
|
assert(params->has_throttle_trigger_threshold);
|
|
|
|
monitor_printf(mon, "%s: %u\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD),
|
|
|
|
params->throttle_trigger_threshold);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_cpu_throttle_initial);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL),
|
2016-04-21 20:07:18 +02:00
|
|
|
params->cpu_throttle_initial);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_cpu_throttle_increment);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT),
|
2016-04-21 20:07:18 +02:00
|
|
|
params->cpu_throttle_increment);
|
2020-04-13 12:15:08 +02:00
|
|
|
assert(params->has_cpu_throttle_tailslow);
|
|
|
|
monitor_printf(mon, "%s: %s\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW),
|
|
|
|
params->cpu_throttle_tailslow ? "on" : "off");
|
2018-08-01 15:00:20 +02: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 12:04:54 +02:00
|
|
|
assert(params->has_tls_creds);
|
2017-04-01 10:18:45 +02:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
|
2017-07-18 12:04:54 +02:00
|
|
|
params->tls_creds);
|
|
|
|
assert(params->has_tls_hostname);
|
2017-04-01 10:18:45 +02:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
|
2017-07-18 12:04:54 +02:00
|
|
|
params->tls_hostname);
|
2016-09-15 18:20:28 +02:00
|
|
|
assert(params->has_max_bandwidth);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
|
2016-09-15 18:20:28 +02:00
|
|
|
params->max_bandwidth);
|
|
|
|
assert(params->has_downtime_limit);
|
2020-06-03 10:08:58 +02:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT),
|
2016-09-15 18:20:28 +02:00
|
|
|
params->downtime_limit);
|
2016-11-02 08:42:09 +01:00
|
|
|
assert(params->has_x_checkpoint_delay);
|
2020-06-03 10:08:58 +02:00
|
|
|
monitor_printf(mon, "%s: %u ms\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY),
|
2016-10-27 08:43:01 +02:00
|
|
|
params->x_checkpoint_delay);
|
2017-04-05 18:32:37 +02:00
|
|
|
assert(params->has_block_incremental);
|
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL),
|
|
|
|
params->block_incremental ? "on" : "off");
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2019-02-06 13:54:06 +01:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS),
|
|
|
|
params->multifd_channels);
|
2019-01-16 10:35:55 +01:00
|
|
|
monitor_printf(mon, "%s: %s\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION),
|
|
|
|
MultiFDCompression_str(params->multifd_compression));
|
2020-06-03 10:08:58 +02:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
|
2017-10-05 21:30:10 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
|
|
|
|
params->xbzrle_cache_size);
|
2018-06-13 12:26:40 +02:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 "\n",
|
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
|
|
|
|
params->max_postcopy_bandwidth);
|
2020-03-25 02:49:30 +01:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
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 15:53:24 +01:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
|
2020-03-25 02:49:30 +01:00
|
|
|
params->tls_authz);
|
2020-08-20 17:07:23 +02:00
|
|
|
|
|
|
|
if (params->has_block_bitmap_mapping) {
|
|
|
|
const BitmapMigrationNodeAliasList *bmnal;
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:\n",
|
|
|
|
MigrationParameter_str(
|
|
|
|
MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING));
|
|
|
|
|
|
|
|
for (bmnal = params->block_bitmap_mapping;
|
|
|
|
bmnal;
|
|
|
|
bmnal = bmnal->next)
|
|
|
|
{
|
|
|
|
const BitmapMigrationNodeAlias *bmna = bmnal->value;
|
|
|
|
const BitmapMigrationBitmapAliasList *bmbal;
|
|
|
|
|
|
|
|
monitor_printf(mon, " '%s' -> '%s'\n",
|
|
|
|
bmna->node_name, bmna->alias);
|
|
|
|
|
|
|
|
for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
|
|
|
|
const BitmapMigrationBitmapAlias *bmba = bmbal->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, " '%s' -> '%s'\n",
|
|
|
|
bmba->name, bmba->alias);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationParameters(params);
|
|
|
|
}
|
|
|
|
|
2011-09-22 20:56:36 +02: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 17:56:47 +02:00
|
|
|
#ifdef CONFIG_VNC
|
2017-07-11 17:44:14 +02: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 10:46:08 +02:00
|
|
|
NetworkAddressFamily_str(info->family),
|
2017-07-11 17:44:14 +02: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 10:46:08 +02:00
|
|
|
VncPrimaryAuth_str(auth),
|
|
|
|
vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none");
|
2017-07-11 17:44:14 +02: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 07:06:25 +01:00
|
|
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
2011-10-17 20:41:22 +02:00
|
|
|
{
|
2020-03-23 13:08:22 +01:00
|
|
|
VncInfo2List *info2l, *info2l_head;
|
2011-10-17 20:41:22 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2017-07-11 17:44:14 +02:00
|
|
|
info2l = qmp_query_vnc_servers(&err);
|
2020-03-23 13:08:22 +01:00
|
|
|
info2l_head = info2l;
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2011-10-17 20:41:22 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-07-11 17:44:14 +02:00
|
|
|
if (!info2l) {
|
|
|
|
monitor_printf(mon, "None\n");
|
|
|
|
return;
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 17:44:14 +02: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-17 20:41:22 +02:00
|
|
|
}
|
2017-07-11 17:44:14 +02:00
|
|
|
info2l = info2l->next;
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
|
|
|
|
2020-03-23 13:08:22 +01:00
|
|
|
qapi_free_VncInfo2List(info2l_head);
|
2017-07-11 17:44:14 +02:00
|
|
|
|
2011-10-17 20:41:22 +02: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 17:56:47 +02:00
|
|
|
#endif
|
2011-10-17 20:41:22 +02:00
|
|
|
|
2015-01-13 15:46:39 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
2011-10-20 21:01:33 +02:00
|
|
|
{
|
|
|
|
SpiceChannelList *chan;
|
|
|
|
SpiceInfo *info;
|
2015-03-01 15:29:18 +01: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 09:27:28 +01: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 15:29:18 +01:00
|
|
|
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
2015-03-03 09:27:28 +01:00
|
|
|
#endif
|
2015-03-01 15:29:18 +01:00
|
|
|
};
|
2011-10-20 21:01:33 +02: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 10:51:58 +02:00
|
|
|
monitor_printf(mon, " migrated: %s\n",
|
|
|
|
info->migrated ? "true" : "false");
|
2011-10-20 21:01:33 +02:00
|
|
|
monitor_printf(mon, " auth: %s\n", info->auth);
|
|
|
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
2012-03-29 23:23:14 +02:00
|
|
|
monitor_printf(mon, " mouse-mode: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
SpiceQueryMouseMode_str(info->mouse_mode));
|
2011-10-20 21:01:33 +02: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-26 23:34:49 +01:00
|
|
|
chan->value->host, chan->value->port,
|
2011-10-20 21:01:33 +02: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 15:29:18 +01: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-20 21:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_SpiceInfo(info);
|
|
|
|
}
|
2015-01-13 15:46:39 +01:00
|
|
|
#endif
|
2011-10-20 21:01:33 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
2011-10-21 15:41:37 +02:00
|
|
|
{
|
|
|
|
BalloonInfo *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
info = qmp_query_balloon(&err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2011-10-21 15:41:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-03 18:56:41 +01:00
|
|
|
monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
|
2011-10-21 15:41:37 +02:00
|
|
|
|
|
|
|
qapi_free_BalloonInfo(info);
|
|
|
|
}
|
|
|
|
|
2011-10-21 18:15:33 +02: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 17:05:32 +02:00
|
|
|
if (dev->class_info->has_desc) {
|
2022-09-29 13:42:12 +02:00
|
|
|
monitor_puts(mon, dev->class_info->desc);
|
2011-10-21 18:15:33 +02:00
|
|
|
} else {
|
2015-05-04 17:05:32 +02:00
|
|
|
monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->id->vendor, dev->id->device);
|
2018-10-02 15:55:38 +02: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-21 18:15:33 +02:00
|
|
|
|
|
|
|
if (dev->has_irq) {
|
2020-03-17 20:59:08 +01:00
|
|
|
monitor_printf(mon, " IRQ %" PRId64 ", pin %c\n",
|
|
|
|
dev->irq, (char)('A' + dev->irq_pin - 1));
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->has_pci_bridge) {
|
|
|
|
monitor_printf(mon, " BUS %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->number);
|
2011-10-21 18:15:33 +02:00
|
|
|
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->secondary);
|
2011-10-21 18:15:33 +02:00
|
|
|
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->subordinate);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->io_range->base,
|
|
|
|
dev->pci_bridge->bus->io_range->limit);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon,
|
|
|
|
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->memory_range->base,
|
|
|
|
dev->pci_bridge->bus->memory_range->limit);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon, " prefetchable memory range "
|
|
|
|
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->prefetchable_range->base,
|
|
|
|
dev->pci_bridge->bus->prefetchable_range->limit);
|
2011-10-21 18:15:33 +02: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-26 22:23:27 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
2011-10-21 18:15:33 +02:00
|
|
|
{
|
2012-01-11 16:51:52 +01:00
|
|
|
PciInfoList *info_list, *info;
|
2011-10-21 18:15:33 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
info_list = qmp_query_pci(&err);
|
2011-10-21 18:15:33 +02:00
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "PCI devices not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
for (info = info_list; info; info = info->next) {
|
2011-10-21 18:15:33 +02:00
|
|
|
PciDeviceInfoList *dev;
|
|
|
|
|
|
|
|
for (dev = info->value->devices; dev; dev = dev->next) {
|
|
|
|
hmp_info_pci_device(mon, dev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
qapi_free_PciInfoList(info_list);
|
2011-10-21 18:15:33 +02: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-27 18:47:49 +01:00
|
|
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2021-06-15 16:21:21 +02:00
|
|
|
#ifdef CONFIG_TPM
|
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-27 18:47:49 +01:00
|
|
|
TPMInfoList *info_list, *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
unsigned int c = 0;
|
|
|
|
TPMPassthroughOptions *tpo;
|
2017-09-29 13:10:20 +02: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-27 18:47:49 +01: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 10:46:08 +02: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-27 18:47:49 +01:00
|
|
|
|
|
|
|
monitor_printf(mon, " \\ %s: type=%s",
|
2021-09-17 16:31:16 +02:00
|
|
|
ti->id, TpmType_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-27 18:47:49 +01:00
|
|
|
|
2015-10-26 23:35:00 +01:00
|
|
|
switch (ti->options->type) {
|
2021-09-17 16:31:16 +02:00
|
|
|
case TPM_TYPE_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-17 23:48:37 +01: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-27 18:47:49 +01: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;
|
2021-09-17 16:31:16 +02:00
|
|
|
case TPM_TYPE_EMULATOR:
|
2017-09-29 13:10:20 +02:00
|
|
|
teo = ti->options->u.emulator.data;
|
|
|
|
monitor_printf(mon, ",chardev=%s", teo->chardev);
|
|
|
|
break;
|
2021-09-17 16:31:16 +02:00
|
|
|
case TPM_TYPE__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-27 18:47:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
qapi_free_TPMInfoList(info_list);
|
2021-06-15 16:21:21 +02:00
|
|
|
#else
|
|
|
|
monitor_printf(mon, "TPM device not supported\n");
|
|
|
|
#endif /* CONFIG_TPM */
|
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-27 18:47:49 +01:00
|
|
|
}
|
|
|
|
|
2011-09-15 19:20:28 +02:00
|
|
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
monitor_suspend(mon);
|
|
|
|
qmp_quit(NULL);
|
|
|
|
}
|
2011-09-15 19:34:39 +02:00
|
|
|
|
|
|
|
void hmp_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_stop(NULL);
|
|
|
|
}
|
2011-09-15 19:41:46 +02:00
|
|
|
|
2018-08-15 22:00:03 +02: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);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2018-08-15 22:00:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-15 19:41:46 +02:00
|
|
|
void hmp_system_reset(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_reset(NULL);
|
|
|
|
}
|
2011-09-28 16:06:15 +02:00
|
|
|
|
|
|
|
void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_powerdown(NULL);
|
|
|
|
}
|
2011-10-06 19:31:39 +02:00
|
|
|
|
2018-06-20 17:39:46 +02:00
|
|
|
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-07-05 11:14:02 +02:00
|
|
|
qmp_x_exit_preconfig(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2018-06-20 17:39:46 +02:00
|
|
|
}
|
|
|
|
|
2011-10-06 19:31:39 +02: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");
|
2020-10-05 17:58:42 +02:00
|
|
|
if (monitor_set_cpu(mon, cpu_index) < 0) {
|
2011-10-06 19:31:39 +02:00
|
|
|
monitor_printf(mon, "invalid CPU index\n");
|
|
|
|
}
|
|
|
|
}
|
2011-11-22 19:32:37 +01: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 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2020-10-05 17:58:43 +02:00
|
|
|
int cpu_index = monitor_get_cpu_index(mon);
|
2011-11-22 19:32:37 +01:00
|
|
|
|
2017-01-13 13:12:35 +01:00
|
|
|
if (cpu_index < 0) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_memsave(addr, size, filename, true, cpu_index, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
2011-11-22 20:26:46 +01: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 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:26:46 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_pmemsave(addr, size, filename, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2013-01-24 17:03:20 +01: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-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:20 +01:00
|
|
|
{
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
|
|
|
const char *data = qdict_get_str(qdict, "data");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-22 20:26:46 +01:00
|
|
|
}
|
2011-11-22 20:58:31 +01: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-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:21 +01:00
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
2013-02-06 21:27:15 +01:00
|
|
|
char *data;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-02-06 21:27:26 +01:00
|
|
|
int i;
|
2013-01-24 17:03:21 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2013-01-24 17:03:21 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-06 21:27:26 +01: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-06 21:27:15 +01:00
|
|
|
g_free(data);
|
2013-01-24 17:03:21 +01:00
|
|
|
}
|
|
|
|
|
2011-11-22 20:58:31 +01:00
|
|
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:58:31 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_cont(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-22 20:58:31 +01:00
|
|
|
}
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2012-02-23 13:45:21 +01: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-05 20:47:01 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_system_wakeup(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-02-23 13:45:21 +01: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 13:55:43 +01:00
|
|
|
void hmp_nmi(Monitor *mon, const QDict *qdict)
|
2011-11-23 15:55:53 +01:00
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_inject_nmi(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-23 15:55:53 +01:00
|
|
|
}
|
2011-11-23 16:11:55 +01:00
|
|
|
|
|
|
|
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool up = qdict_get_bool(qdict, "up");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 16:11:55 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_set_link(name, up, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-23 16:11:55 +01:00
|
|
|
}
|
2011-11-23 16:28:21 +01:00
|
|
|
|
2011-11-25 17:38:09 +01:00
|
|
|
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 17:38:09 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_balloon(value, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-11-25 17:38:09 +01:00
|
|
|
}
|
2011-11-25 17:57:10 +01:00
|
|
|
|
2017-04-18 11:40:56 +02: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-18 18:12:35 +02:00
|
|
|
Error *err = NULL;
|
2017-04-18 11:40:56 +02:00
|
|
|
|
|
|
|
vm_stop(RUN_STATE_RESTORE_VM);
|
|
|
|
|
2021-05-11 18:31:51 +02:00
|
|
|
if (load_snapshot(name, NULL, false, NULL, &err) && saved_vm_running) {
|
2017-04-18 11:40:56 +02:00
|
|
|
vm_start();
|
|
|
|
}
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-04-18 11:40:56 +02:00
|
|
|
}
|
|
|
|
|
2017-04-18 11:44:16 +02:00
|
|
|
void hmp_savevm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-04-18 18:12:35 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2021-02-04 13:48:30 +01:00
|
|
|
save_snapshot(qdict_get_try_str(qdict, "name"),
|
|
|
|
true, NULL, false, NULL, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-04-18 11:44:16 +02:00
|
|
|
}
|
|
|
|
|
2017-04-18 11:46:23 +02:00
|
|
|
void hmp_delvm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2018-02-25 02:47:51 +01:00
|
|
|
Error *err = NULL;
|
2017-04-18 11:46:23 +02:00
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
|
2021-02-04 13:48:31 +01:00
|
|
|
delete_snapshot(name, false, NULL, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-04-18 11:46:23 +02:00
|
|
|
}
|
|
|
|
|
2019-02-27 14:24:12 +01:00
|
|
|
void hmp_announce_self(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2019-06-20 20:47:03 +02:00
|
|
|
const char *interfaces_str = qdict_get_try_str(qdict, "interfaces");
|
2019-06-20 20:47:05 +02:00
|
|
|
const char *id = qdict_get_try_str(qdict, "id");
|
2019-06-20 20:47:03 +02: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-20 20:47:05 +02:00
|
|
|
params->id = g_strdup(id);
|
|
|
|
params->has_id = !!params->id;
|
2019-06-20 20:47:03 +02:00
|
|
|
qmp_announce_self(params, NULL);
|
|
|
|
qapi_free_AnnounceParameters(params);
|
2019-02-27 14:24:12 +01:00
|
|
|
}
|
|
|
|
|
2011-11-28 01:54:09 +01:00
|
|
|
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_migrate_cancel(NULL);
|
|
|
|
}
|
2011-11-28 02:18:01 +01:00
|
|
|
|
2017-10-20 11:05:54 +02: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);
|
|
|
|
}
|
|
|
|
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-10-20 11:05:54 +02:00
|
|
|
}
|
|
|
|
|
2015-02-19 12:40:28 +01: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);
|
|
|
|
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2015-02-19 12:40:28 +01:00
|
|
|
}
|
|
|
|
|
2018-05-02 12:47:37 +02: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);
|
|
|
|
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2018-05-02 12:47:37 +02:00
|
|
|
}
|
|
|
|
|
2018-05-02 12:47:40 +02:00
|
|
|
void hmp_migrate_pause(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate_pause(&err);
|
|
|
|
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2018-05-02 12:47:40 +02:00
|
|
|
}
|
|
|
|
|
2011-12-07 14:17:51 +01:00
|
|
|
|
2012-08-06 20:42:48 +02: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;
|
2020-11-13 02:13:37 +01:00
|
|
|
MigrationCapabilityStatusList *caps = NULL;
|
|
|
|
MigrationCapabilityStatus *value;
|
2017-08-24 10:46:00 +02:00
|
|
|
int val;
|
2012-08-06 20:42:48 +02:00
|
|
|
|
2017-08-24 10:46:10 +02:00
|
|
|
val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
|
2017-08-24 10:46:00 +02:00
|
|
|
if (val < 0) {
|
|
|
|
goto end;
|
2012-08-06 20:42:48 +02:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:13:37 +01:00
|
|
|
value = g_malloc0(sizeof(*value));
|
|
|
|
value->capability = val;
|
|
|
|
value->state = state;
|
|
|
|
QAPI_LIST_PREPEND(caps, value);
|
2017-08-24 10:46:00 +02:00
|
|
|
qmp_migrate_set_capabilities(caps, &err);
|
2020-11-13 02:13:37 +01:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2012-08-06 20:42:48 +02:00
|
|
|
|
2017-08-24 10:46:00 +02:00
|
|
|
end:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-08-06 20:42:48 +02:00
|
|
|
}
|
|
|
|
|
2015-03-23 09:32:29 +01:00
|
|
|
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *param = qdict_get_str(qdict, "parameter");
|
2016-04-27 12:05:15 +02:00
|
|
|
const char *valuestr = qdict_get_str(qdict, "value");
|
2017-05-16 11:37:45 +02: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 13:42:11 +02:00
|
|
|
MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
|
2017-02-21 21:14:07 +01:00
|
|
|
uint64_t valuebw = 0;
|
2017-10-05 21:30:10 +02:00
|
|
|
uint64_t cache_size;
|
2015-03-23 09:32:29 +01:00
|
|
|
Error *err = NULL;
|
2017-08-24 10:46:01 +02:00
|
|
|
int val, ret;
|
2016-04-27 12:05:15 +02:00
|
|
|
|
2017-08-24 10:46:10 +02:00
|
|
|
val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
if (val < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (val) {
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
|
|
|
|
p->has_compress_level = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->compress_level, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_THREADS:
|
|
|
|
p->has_compress_threads = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->compress_threads, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
2018-08-21 10:10:20 +02: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 10:46:01 +02:00
|
|
|
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
|
|
|
|
p->has_decompress_threads = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->decompress_threads, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
2020-02-24 03:31:42 +01:00
|
|
|
case MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD:
|
|
|
|
p->has_throttle_trigger_threshold = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->throttle_trigger_threshold, &err);
|
2020-03-18 08:16:20 +01:00
|
|
|
break;
|
2017-08-24 10:46:01 +02:00
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
|
|
|
|
p->has_cpu_throttle_initial = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->cpu_throttle_initial, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
|
|
|
p->has_cpu_throttle_increment = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->cpu_throttle_increment, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
2020-04-13 12:15:08 +02:00
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW:
|
|
|
|
p->has_cpu_throttle_tailslow = true;
|
|
|
|
visit_type_bool(v, param, &p->cpu_throttle_tailslow, &err);
|
|
|
|
break;
|
2018-08-01 15:00:20 +02:00
|
|
|
case MIGRATION_PARAMETER_MAX_CPU_THROTTLE:
|
|
|
|
p->has_max_cpu_throttle = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->max_cpu_throttle, &err);
|
2018-08-01 15:00:20 +02:00
|
|
|
break;
|
2017-08-24 10:46:01 +02: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 15:53:24 +01: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 10:46:01 +02: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 09:32:29 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-08-24 10:46:01 +02:00
|
|
|
p->max_bandwidth = valuebw;
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
|
|
|
|
p->has_downtime_limit = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_size(v, param, &p->downtime_limit, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
|
|
|
|
p->has_x_checkpoint_delay = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint32(v, param, &p->x_checkpoint_delay, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
|
|
|
|
p->has_block_incremental = true;
|
|
|
|
visit_type_bool(v, param, &p->block_incremental, &err);
|
|
|
|
break;
|
2019-02-06 13:54:06 +01:00
|
|
|
case MIGRATION_PARAMETER_MULTIFD_CHANNELS:
|
|
|
|
p->has_multifd_channels = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->multifd_channels, &err);
|
2016-01-15 08:56:17 +01:00
|
|
|
break;
|
2019-01-16 10:35:55 +01:00
|
|
|
case MIGRATION_PARAMETER_MULTIFD_COMPRESSION:
|
|
|
|
p->has_multifd_compression = true;
|
2020-07-07 18:05:44 +02:00
|
|
|
visit_type_MultiFDCompression(v, param, &p->multifd_compression,
|
|
|
|
&err);
|
2019-01-16 10:35:55 +01:00
|
|
|
break;
|
2020-01-23 17:08:52 +01:00
|
|
|
case MIGRATION_PARAMETER_MULTIFD_ZLIB_LEVEL:
|
|
|
|
p->has_multifd_zlib_level = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->multifd_zlib_level, &err);
|
2020-01-23 17:08:52 +01:00
|
|
|
break;
|
2020-01-23 17:41:36 +01:00
|
|
|
case MIGRATION_PARAMETER_MULTIFD_ZSTD_LEVEL:
|
|
|
|
p->has_multifd_zstd_level = true;
|
2021-02-02 15:17:31 +01:00
|
|
|
visit_type_uint8(v, param, &p->multifd_zstd_level, &err);
|
2020-01-23 17:41:36 +01:00
|
|
|
break;
|
2017-10-05 21:30:10 +02:00
|
|
|
case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE:
|
|
|
|
p->has_xbzrle_cache_size = true;
|
2020-07-07 18:05:46 +02:00
|
|
|
if (!visit_type_size(v, param, &cache_size, &err)) {
|
2019-04-03 13:49:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (cache_size > INT64_MAX || (size_t)cache_size != cache_size) {
|
2017-10-05 21:30:10 +02:00
|
|
|
error_setg(&err, "Invalid size %s", valuestr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p->xbzrle_cache_size = cache_size;
|
|
|
|
break;
|
2018-06-13 12:26:40 +02: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 14:24:06 +01: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;
|
2020-08-20 17:07:23 +02:00
|
|
|
case MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING:
|
|
|
|
error_setg(&err, "The block-bitmap-mapping parameter can only be set "
|
|
|
|
"through QMP");
|
|
|
|
break;
|
2017-08-24 10:46:01 +02:00
|
|
|
default:
|
|
|
|
assert(0);
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:46:01 +02:00
|
|
|
if (err) {
|
|
|
|
goto cleanup;
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:46:01 +02:00
|
|
|
qmp_migrate_set_parameters(p, &err);
|
|
|
|
|
2016-04-27 12:05:15 +02: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 13:42:11 +02:00
|
|
|
qapi_free_MigrateSetParameters(p);
|
2017-05-16 11:37:45 +02:00
|
|
|
visit_free(v);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:29:02 +01: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);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2015-03-05 17:29:02 +01:00
|
|
|
}
|
|
|
|
|
2015-11-05 19:10:56 +01:00
|
|
|
void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
qmp_migrate_start_postcopy(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2015-11-05 19:10:56 +01:00
|
|
|
}
|
|
|
|
|
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 08:43:03 +02:00
|
|
|
void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_x_colo_lost_heartbeat(&err);
|
2019-12-05 18:46:18 +01:00
|
|
|
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 08:43:03 +02:00
|
|
|
}
|
|
|
|
|
2011-12-07 14:17:51 +01: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");
|
2022-02-25 09:49:49 +01:00
|
|
|
const char *display = qdict_get_try_str(qdict, "display");
|
2011-12-07 14:17:51 +01:00
|
|
|
const char *connected = qdict_get_try_str(qdict, "connected");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2022-02-25 09:49:49 +01:00
|
|
|
SetPasswordOptions opts = {
|
|
|
|
.password = (char *)password,
|
|
|
|
.has_connected = !!connected,
|
|
|
|
};
|
|
|
|
|
|
|
|
opts.connected = qapi_enum_parse(&SetPasswordAction_lookup, connected,
|
|
|
|
SET_PASSWORD_ACTION_KEEP, &err);
|
2022-02-25 09:49:48 +01:00
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-02-25 09:49:49 +01:00
|
|
|
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
|
|
|
DISPLAY_PROTOCOL_VNC, &err);
|
2022-02-25 09:49:48 +01:00
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-02-25 09:49:49 +01:00
|
|
|
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
|
|
|
opts.u.vnc.has_display = !!display;
|
|
|
|
opts.u.vnc.display = (char *)display;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_set_password(&opts, &err);
|
2022-02-25 09:49:48 +01:00
|
|
|
|
|
|
|
out:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-12-07 14:17:51 +01:00
|
|
|
}
|
2011-12-07 14:47:57 +01: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");
|
2022-02-25 09:49:49 +01:00
|
|
|
const char *display = qdict_get_try_str(qdict, "display");
|
2011-12-07 14:47:57 +01:00
|
|
|
Error *err = NULL;
|
2022-02-25 09:49:48 +01:00
|
|
|
|
2022-02-25 09:49:49 +01:00
|
|
|
ExpirePasswordOptions opts = {
|
|
|
|
.time = (char *)whenstr,
|
|
|
|
};
|
|
|
|
|
|
|
|
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
|
|
|
DISPLAY_PROTOCOL_VNC, &err);
|
2022-02-25 09:49:48 +01:00
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-07 14:47:57 +01:00
|
|
|
|
2022-02-25 09:49:49 +01:00
|
|
|
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
|
|
|
opts.u.vnc.has_display = !!display;
|
|
|
|
opts.u.vnc.display = (char *)display;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_expire_password(&opts, &err);
|
2022-02-25 09:49:48 +01:00
|
|
|
|
|
|
|
out:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-12-07 14:47:57 +01:00
|
|
|
}
|
2011-12-07 19:02:36 +01:00
|
|
|
|
2011-12-08 14:13:50 +01: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 17:56:47 +02:00
|
|
|
#ifdef CONFIG_VNC
|
2013-11-14 11:54:14 +01:00
|
|
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
|
|
|
void *readline_opaque)
|
2011-12-08 14:13:50 +01:00
|
|
|
{
|
|
|
|
qmp_change_vnc_password(password, NULL);
|
2013-11-14 11:54:14 +01:00
|
|
|
monitor_read_command(opaque, 1);
|
2011-12-08 14:13:50 +01: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 17:56:47 +02:00
|
|
|
#endif
|
2011-12-08 14:13:50 +01:00
|
|
|
|
|
|
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
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-26 21:39:18 +01:00
|
|
|
const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
|
2022-04-13 00:18:46 +02:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
2015-10-26 21:39:18 +01:00
|
|
|
BlockdevChangeReadOnlyMode read_only_mode = 0;
|
2011-12-08 14:13:50 +01: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 17:56:47 +02:00
|
|
|
#ifdef CONFIG_VNC
|
2015-10-26 21:39:16 +01:00
|
|
|
if (strcmp(device, "vnc") == 0) {
|
2015-10-26 21:39:18 +01:00
|
|
|
if (read_only) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
"Parameter 'read-only-mode' is invalid for VNC\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-10-26 21:39:16 +01:00
|
|
|
if (strcmp(target, "passwd") == 0 ||
|
|
|
|
strcmp(target, "password") == 0) {
|
2021-09-09 10:12:18 +02:00
|
|
|
if (!arg) {
|
2019-06-25 14:39:05 +02:00
|
|
|
MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
|
2019-06-13 17:33:54 +02:00
|
|
|
monitor_read_password(hmp_mon, hmp_change_read_arg, NULL);
|
2015-10-26 21:39:16 +01:00
|
|
|
return;
|
2021-01-20 15:42:33 +01:00
|
|
|
} else {
|
|
|
|
qmp_change_vnc_password(arg, &err);
|
2015-10-26 21:39:16 +01:00
|
|
|
}
|
2021-01-20 15:42:33 +01:00
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Expected 'password' after 'vnc'\n");
|
2015-10-26 21:39:16 +01: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 17:56:47 +02:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2015-10-26 21:39:18 +01:00
|
|
|
if (read_only) {
|
|
|
|
read_only_mode =
|
2017-08-24 10:46:10 +02:00
|
|
|
qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
|
2017-08-24 10:45:57 +02:00
|
|
|
read_only,
|
2015-10-26 21:39:18 +01:00
|
|
|
BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
|
|
|
|
if (err) {
|
2020-06-03 10:09:01 +02:00
|
|
|
goto end;
|
2015-10-26 21:39:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-20 13:38:47 +02:00
|
|
|
qmp_blockdev_change_medium(true, device, false, NULL, target,
|
2022-04-13 00:18:46 +02:00
|
|
|
!!arg, arg, true, force,
|
|
|
|
!!read_only, read_only_mode,
|
2016-09-20 13:38:47 +02:00
|
|
|
&err);
|
2011-12-08 14:13:50 +01:00
|
|
|
}
|
|
|
|
|
2020-06-03 10:09:01 +02:00
|
|
|
end:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2011-12-08 14:13:50 +01:00
|
|
|
}
|
2011-12-14 19:49:14 +01:00
|
|
|
|
2020-11-25 02:45:12 +01:00
|
|
|
typedef struct HMPMigrationStatus {
|
2011-12-05 17:48:01 +01:00
|
|
|
QEMUTimer *timer;
|
|
|
|
Monitor *mon;
|
|
|
|
bool is_block_migration;
|
2015-03-13 09:08:39 +01:00
|
|
|
} HMPMigrationStatus;
|
2011-12-05 17:48:01 +01:00
|
|
|
|
|
|
|
static void hmp_migrate_status_cb(void *opaque)
|
|
|
|
{
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status = opaque;
|
2011-12-05 17:48:01 +01:00
|
|
|
MigrationInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2015-03-13 09:08:40 +01:00
|
|
|
if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE ||
|
|
|
|
info->status == MIGRATION_STATUS_SETUP) {
|
2011-12-05 17:48:01 +01: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 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
2011-12-05 17:48:01 +01: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 12:05:00 +02:00
|
|
|
if (info->has_error_desc) {
|
|
|
|
error_report("%s", info->error_desc);
|
|
|
|
}
|
2011-12-05 17:48:01 +01:00
|
|
|
monitor_resume(status->mon);
|
2018-09-01 15:46:52 +02:00
|
|
|
timer_free(status->timer);
|
2011-12-05 17:48:01 +01:00
|
|
|
g_free(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationInfo(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_migrate(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-05-16 00:25:00 +02: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 12:47:23 +02:00
|
|
|
bool resume = qdict_get_try_bool(qdict, "resume", false);
|
2011-12-05 17:48:01 +01:00
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-05-02 12:47:23 +02:00
|
|
|
qmp_migrate(uri, !!blk, blk, !!inc, inc,
|
|
|
|
false, false, true, resume, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2011-12-05 17:48:01 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status;
|
2011-12-05 17:48:01 +01: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 17:03:08 +02:00
|
|
|
status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb,
|
2011-12-05 17:48:01 +01:00
|
|
|
status);
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
|
2011-12-05 17:48:01 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-29 17:38:50 +02:00
|
|
|
|
2012-04-18 22:34:15 +02:00
|
|
|
void hmp_netdev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
2020-11-11 11:52:22 +01:00
|
|
|
const char *type = qdict_get_try_str(qdict, "type");
|
2012-04-18 22:34:15 +02:00
|
|
|
|
2020-11-11 11:52:22 +01:00
|
|
|
if (type && is_help_option(type)) {
|
|
|
|
show_netdevs();
|
|
|
|
return;
|
|
|
|
}
|
2012-04-18 22:34:15 +02:00
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
netdev_add(opts, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-04-18 22:34:15 +02:00
|
|
|
}
|
2012-04-16 19:36:32 +02: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);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-04-16 19:36:32 +02:00
|
|
|
}
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2013-12-20 23:21:10 +01:00
|
|
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2021-02-17 15:27:54 +01:00
|
|
|
const char *options = qdict_get_str(qdict, "object");
|
2013-12-20 23:21:10 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2021-02-17 15:27:54 +01:00
|
|
|
user_creatable_add_from_str(options, &err);
|
2020-06-03 10:09:00 +02:00
|
|
|
hmp_handle_error(mon, err);
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_getfd(fdname, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_closefd(fdname, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
2012-08-31 04:56:26 +02: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 13:55:43 +01:00
|
|
|
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
2012-08-31 04:56:26 +02:00
|
|
|
{
|
|
|
|
const char *keys = qdict_get_str(qdict, "keys");
|
2021-01-13 23:10:13 +01:00
|
|
|
KeyValue *v = NULL;
|
|
|
|
KeyValueList *head = NULL, **tail = &head;
|
2012-08-31 04:56:26 +02: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 12:32:10 +02:00
|
|
|
const char *separator;
|
2012-09-20 19:19:47 +02:00
|
|
|
int keyname_len;
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
while (1) {
|
2018-06-29 12:32:10 +02:00
|
|
|
separator = qemu_strchrnul(keys, '-');
|
|
|
|
keyname_len = separator - keys;
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
/* Be compatible with old interface, convert user inputted "<" */
|
2016-01-13 09:09:58 +01:00
|
|
|
if (keys[0] == '<' && keyname_len == 1) {
|
|
|
|
keys = "less";
|
2012-08-31 04:56:26 +02:00
|
|
|
keyname_len = 4;
|
|
|
|
}
|
|
|
|
|
2021-01-13 23:10:13 +01:00
|
|
|
v = g_malloc0(sizeof(*v));
|
2012-08-31 04:56:26 +02:00
|
|
|
|
2016-01-13 09:09:58 +01:00
|
|
|
if (strstart(keys, "0x", NULL)) {
|
2012-09-20 19:19:47 +02:00
|
|
|
char *endp;
|
2016-01-13 09:09:58 +01:00
|
|
|
int value = strtoul(keys, &endp, 0);
|
|
|
|
assert(endp <= keys + keyname_len);
|
|
|
|
if (endp != keys + keyname_len) {
|
2012-09-20 19:19:47 +02:00
|
|
|
goto err_out;
|
|
|
|
}
|
2021-01-13 23:10:13 +01:00
|
|
|
v->type = KEY_VALUE_KIND_NUMBER;
|
|
|
|
v->u.number.data = value;
|
2012-09-20 19:19:47 +02:00
|
|
|
} else {
|
2016-01-13 09:09:58 +01: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 09:52:57 +01:00
|
|
|
if (idx == Q_KEY_CODE__MAX) {
|
2012-09-20 19:19:47 +02:00
|
|
|
goto err_out;
|
|
|
|
}
|
2021-01-13 23:10:13 +01:00
|
|
|
v->type = KEY_VALUE_KIND_QCODE;
|
|
|
|
v->u.qcode.data = idx;
|
2012-09-20 19:19:47 +02:00
|
|
|
}
|
2021-01-13 23:10:13 +01:00
|
|
|
QAPI_LIST_APPEND(tail, v);
|
|
|
|
v = NULL;
|
2012-09-20 19:19:47 +02:00
|
|
|
|
2018-06-29 12:32:10 +02:00
|
|
|
if (!*separator) {
|
2012-08-31 04:56:26 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
keys = separator + 1;
|
|
|
|
}
|
|
|
|
|
2012-09-20 19:19:47 +02:00
|
|
|
qmp_send_key(head, has_hold_time, hold_time, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-09-20 19:19:47 +02:00
|
|
|
|
|
|
|
out:
|
2021-01-13 23:10:13 +01:00
|
|
|
qapi_free_KeyValue(v);
|
2012-09-20 19:19:47 +02:00
|
|
|
qapi_free_KeyValueList(head);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_out:
|
2016-01-13 09:09:58 +01:00
|
|
|
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
2012-09-20 19:19:47 +02:00
|
|
|
goto out;
|
2012-08-31 04:56:26 +02:00
|
|
|
}
|
2012-05-24 18:48:23 +02:00
|
|
|
|
2020-10-27 14:36:02 +01:00
|
|
|
void coroutine_fn
|
|
|
|
hmp_screendump(Monitor *mon, const QDict *qdict)
|
2012-05-24 18:48:23 +02:00
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
2018-03-05 17:37:48 +01:00
|
|
|
const char *id = qdict_get_try_str(qdict, "device");
|
|
|
|
int64_t head = qdict_get_try_int(qdict, "head", 0);
|
2022-04-08 09:13:35 +02:00
|
|
|
const char *input_format = qdict_get_try_str(qdict, "format");
|
2012-05-24 18:48:23 +02:00
|
|
|
Error *err = NULL;
|
2022-04-08 09:13:35 +02:00
|
|
|
ImageFormat format;
|
2012-05-24 18:48:23 +02:00
|
|
|
|
2022-04-08 09:13:35 +02:00
|
|
|
format = qapi_enum_parse(&ImageFormat_lookup, input_format,
|
|
|
|
IMAGE_FORMAT_PPM, &err);
|
|
|
|
if (err) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_screendump(filename, id != NULL, id, id != NULL, head,
|
|
|
|
input_format != NULL, format, &err);
|
|
|
|
end:
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-05-24 18:48:23 +02:00
|
|
|
}
|
2012-08-23 11:53:04 +02:00
|
|
|
|
2012-12-19 10:33:40 +01: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 12:50:26 +01:00
|
|
|
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, true);
|
2012-12-19 10:33:40 +01: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-08 21:22:16 +01:00
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
2012-12-19 10:33:40 +01:00
|
|
|
} else {
|
2019-02-13 14:18:13 +01: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 14:18:34 +02:00
|
|
|
qemu_opts_del(opts);
|
2012-12-19 10:33:40 +01:00
|
|
|
}
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2012-12-19 10:33:40 +01:00
|
|
|
}
|
|
|
|
|
2017-07-06 14:08:57 +02: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);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-07-06 14:08:57 +02:00
|
|
|
}
|
|
|
|
|
2012-12-19 10:33:40 +01:00
|
|
|
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, local_err);
|
2012-12-19 10:33:40 +01:00
|
|
|
}
|
2013-06-05 14:19:41 +02:00
|
|
|
|
2017-06-11 09:48:17 +02: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);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, local_err);
|
2017-06-11 09:48:17 +02:00
|
|
|
}
|
|
|
|
|
2013-12-20 23:21:09 +01:00
|
|
|
void hmp_object_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2016-02-10 19:40:59 +01:00
|
|
|
user_creatable_del(id, &err);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2013-12-20 23:21:09 +01:00
|
|
|
}
|
2014-05-14 11:43:35 +02:00
|
|
|
|
2014-09-23 07:35:19 +02:00
|
|
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
|
|
|
|
MemoryDeviceInfoList *info;
|
2019-06-19 11:49:05 +02:00
|
|
|
VirtioPMEMDeviceInfo *vpi;
|
2020-06-26 09:22:40 +02:00
|
|
|
VirtioMEMDeviceInfo *vmi;
|
2014-09-23 07:35:19 +02:00
|
|
|
MemoryDeviceInfo *value;
|
|
|
|
PCDIMMDeviceInfo *di;
|
2021-07-19 13:21:35 +02:00
|
|
|
SgxEPCDeviceInfo *se;
|
2014-09-23 07:35:19 +02:00
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
value = info->value;
|
|
|
|
|
|
|
|
if (value) {
|
2015-10-26 23:34:59 +01:00
|
|
|
switch (value->type) {
|
2014-09-23 07:35:19 +02:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
2018-03-11 04:02:12 +01:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
|
2019-06-19 11:49:05 +02:00
|
|
|
di = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ?
|
|
|
|
value->u.dimm.data : value->u.nvdimm.data;
|
2014-09-23 07:35:19 +02:00
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
2014-09-23 07:35:19 +02: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");
|
2019-06-19 11:49:05 +02:00
|
|
|
break;
|
|
|
|
case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM:
|
|
|
|
vpi = value->u.virtio_pmem.data;
|
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
|
|
|
vpi->id ? vpi->id : "");
|
|
|
|
monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vpi->memaddr);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", vpi->size);
|
|
|
|
monitor_printf(mon, " memdev: %s\n", vpi->memdev);
|
|
|
|
break;
|
2020-06-26 09:22:40 +02:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM:
|
|
|
|
vmi = value->u.virtio_mem.data;
|
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
|
|
|
vmi->id ? vmi->id : "");
|
|
|
|
monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vmi->memaddr);
|
|
|
|
monitor_printf(mon, " node: %" PRId64 "\n", vmi->node);
|
|
|
|
monitor_printf(mon, " requested-size: %" PRIu64 "\n",
|
|
|
|
vmi->requested_size);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", vmi->size);
|
|
|
|
monitor_printf(mon, " max-size: %" PRIu64 "\n", vmi->max_size);
|
|
|
|
monitor_printf(mon, " block-size: %" PRIu64 "\n",
|
|
|
|
vmi->block_size);
|
|
|
|
monitor_printf(mon, " memdev: %s\n", vmi->memdev);
|
|
|
|
break;
|
2021-07-19 13:21:35 +02:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_SGX_EPC:
|
|
|
|
se = value->u.sgx_epc.data;
|
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
|
|
|
se->id ? se->id : "");
|
|
|
|
monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", se->memaddr);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", se->size);
|
numa: Enable numa for SGX EPC sections
The basic SGX did not enable numa for SGX EPC sections, which
result in all EPC sections located in numa node 0. This patch
enable SGX numa function in the guest and the EPC section can
work with RAM as one numa node.
The Guest kernel related log:
[ 0.009981] ACPI: SRAT: Node 0 PXM 0 [mem 0x180000000-0x183ffffff]
[ 0.009982] ACPI: SRAT: Node 1 PXM 1 [mem 0x184000000-0x185bfffff]
The SRAT table can normally show SGX EPC sections menory info in different
numa nodes.
The SGX EPC numa related command:
......
-m 4G,maxmem=20G \
-smp sockets=2,cores=2 \
-cpu host,+sgx-provisionkey \
-object memory-backend-ram,size=2G,host-nodes=0,policy=bind,id=node0 \
-object memory-backend-epc,id=mem0,size=64M,prealloc=on,host-nodes=0,policy=bind \
-numa node,nodeid=0,cpus=0-1,memdev=node0 \
-object memory-backend-ram,size=2G,host-nodes=1,policy=bind,id=node1 \
-object memory-backend-epc,id=mem1,size=28M,prealloc=on,host-nodes=1,policy=bind \
-numa node,nodeid=1,cpus=2-3,memdev=node1 \
-M sgx-epc.0.memdev=mem0,sgx-epc.0.node=0,sgx-epc.1.memdev=mem1,sgx-epc.1.node=1 \
......
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20211101162009.62161-2-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2021-11-01 17:20:05 +01:00
|
|
|
monitor_printf(mon, " node: %" PRId64 "\n", se->node);
|
2021-07-19 13:21:35 +02:00
|
|
|
monitor_printf(mon, " memdev: %s\n", se->memdev);
|
|
|
|
break;
|
2019-06-19 11:49:05 +02:00
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2014-09-23 07:35:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryDeviceInfoList(info_list);
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2014-09-23 07:35:19 +02:00
|
|
|
}
|
2014-05-07 18:08:29 +02:00
|
|
|
|
2015-06-26 10:07:13 +02:00
|
|
|
void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
|
|
|
|
IOThreadInfoList *info;
|
2017-02-10 10:41:17 +01:00
|
|
|
IOThreadInfo *value;
|
2015-06-26 10:07:13 +02:00
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
2017-02-10 10:41:17 +01: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);
|
2021-07-21 11:42:10 +02:00
|
|
|
monitor_printf(mon, " aio-max-batch=%" PRId64 "\n",
|
|
|
|
value->aio_max_batch);
|
2015-06-26 10:07:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_IOThreadInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2015-06-11 03:21:21 +02:00
|
|
|
void hmp_rocker(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
RockerSwitch *rocker;
|
2015-12-18 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
rocker = qmp_query_rocker(name, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2015-06-11 03:21:21 +02: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 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_ports(name, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " ena/ speed/ auto\n");
|
|
|
|
monitor_printf(mon, " port link duplex neg?\n");
|
|
|
|
|
|
|
|
for (port = list; port; port = port->next) {
|
2021-10-09 17:24:01 +02:00
|
|
|
monitor_printf(mon, "%10s %-4s %-3s %2s %s\n",
|
2015-06-11 03:21:21 +02:00
|
|
|
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 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2015-06-11 03:21:21 +02: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 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err);
|
2021-10-28 17:18:25 +02:00
|
|
|
if (hmp_handle_error(mon, err)) {
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "id (decode) --> buckets\n");
|
|
|
|
|
|
|
|
for (g = list; g; g = g->next) {
|
|
|
|
RockerOfDpaGroup *group = g->value;
|
2020-03-02 14:07:15 +01:00
|
|
|
bool set = false;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
|
|
|
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) {
|
|
|
|
monitor_printf(mon, " set");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " dst %s", group->set_eth_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 06:16:55 +01:00
|
|
|
|
2017-02-17 00:15:37 +01:00
|
|
|
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-03-02 22:36:50 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
GuidInfo *info = qmp_query_vm_generation_id(&err);
|
2017-02-17 00:15:37 +01:00
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "%s\n", info->guid);
|
|
|
|
}
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-02-17 00:15:37 +01:00
|
|
|
qapi_free_GuidInfo(info);
|
|
|
|
}
|
2017-08-29 17:30:22 +02: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);
|
|
|
|
}
|
2019-12-05 18:46:18 +01:00
|
|
|
hmp_handle_error(mon, err);
|
2017-08-29 17:30:22 +02:00
|
|
|
}
|
2022-04-26 12:17:35 +02:00
|
|
|
|
|
|
|
static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value)
|
|
|
|
{
|
|
|
|
const char *unit = NULL;
|
|
|
|
monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type),
|
|
|
|
value->has_unit || value->exponent ? ", " : "");
|
|
|
|
|
|
|
|
if (value->has_unit) {
|
|
|
|
if (value->unit == STATS_UNIT_SECONDS) {
|
|
|
|
unit = "s";
|
|
|
|
} else if (value->unit == STATS_UNIT_BYTES) {
|
|
|
|
unit = "B";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unit && value->base == 10 &&
|
|
|
|
value->exponent >= -18 && value->exponent <= 18 &&
|
|
|
|
value->exponent % 3 == 0) {
|
2022-09-29 13:42:12 +02:00
|
|
|
monitor_puts(mon, si_prefix(value->exponent));
|
2022-04-26 12:17:35 +02:00
|
|
|
} else if (unit && value->base == 2 &&
|
|
|
|
value->exponent >= 0 && value->exponent <= 60 &&
|
|
|
|
value->exponent % 10 == 0) {
|
|
|
|
|
2022-09-29 13:42:12 +02:00
|
|
|
monitor_puts(mon, iec_binary_prefix(value->exponent));
|
2022-04-26 12:17:35 +02:00
|
|
|
} else if (value->exponent) {
|
|
|
|
/* Use exponential notation and write the unit's English name */
|
|
|
|
monitor_printf(mon, "* %d^%d%s",
|
|
|
|
value->base, value->exponent,
|
|
|
|
value->has_unit ? " " : "");
|
|
|
|
unit = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value->has_unit) {
|
2022-09-29 13:42:12 +02:00
|
|
|
monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit));
|
2022-04-26 12:17:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print bucket size for linear histograms */
|
|
|
|
if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) {
|
|
|
|
monitor_printf(mon, ", bucket size=%d", value->bucket_size);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
static StatsSchemaValueList *find_schema_value_list(
|
|
|
|
StatsSchemaList *list, StatsProvider provider,
|
|
|
|
StatsTarget target)
|
|
|
|
{
|
|
|
|
StatsSchemaList *node;
|
|
|
|
|
|
|
|
for (node = list; node; node = node->next) {
|
|
|
|
if (node->value->provider == provider &&
|
|
|
|
node->value->target == target) {
|
|
|
|
return node->value->stats;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_stats_results(Monitor *mon, StatsTarget target,
|
2022-04-26 13:58:59 +02:00
|
|
|
bool show_provider,
|
2022-04-26 12:17:35 +02:00
|
|
|
StatsResult *result,
|
|
|
|
StatsSchemaList *schema)
|
|
|
|
{
|
|
|
|
/* Find provider schema */
|
|
|
|
StatsSchemaValueList *schema_value_list =
|
|
|
|
find_schema_value_list(schema, result->provider, target);
|
|
|
|
StatsList *stats_list;
|
|
|
|
|
|
|
|
if (!schema_value_list) {
|
|
|
|
monitor_printf(mon, "failed to find schema list for %s\n",
|
|
|
|
StatsProvider_str(result->provider));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-26 13:58:59 +02:00
|
|
|
if (show_provider) {
|
|
|
|
monitor_printf(mon, "provider: %s\n",
|
|
|
|
StatsProvider_str(result->provider));
|
|
|
|
}
|
2022-04-26 12:17:35 +02:00
|
|
|
|
|
|
|
for (stats_list = result->stats; stats_list;
|
|
|
|
stats_list = stats_list->next,
|
|
|
|
schema_value_list = schema_value_list->next) {
|
|
|
|
|
|
|
|
Stats *stats = stats_list->value;
|
|
|
|
StatsValue *stats_value = stats->value;
|
|
|
|
StatsSchemaValue *schema_value = schema_value_list->value;
|
|
|
|
|
|
|
|
/* Find schema entry */
|
|
|
|
while (!g_str_equal(stats->name, schema_value->name)) {
|
|
|
|
if (!schema_value_list->next) {
|
|
|
|
monitor_printf(mon, "failed to find schema entry for %s\n",
|
|
|
|
stats->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
schema_value_list = schema_value_list->next;
|
|
|
|
schema_value = schema_value_list->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
print_stats_schema_value(mon, schema_value);
|
|
|
|
|
|
|
|
if (stats_value->type == QTYPE_QNUM) {
|
|
|
|
monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar);
|
2022-07-14 14:08:09 +02:00
|
|
|
} else if (stats_value->type == QTYPE_QBOOL) {
|
|
|
|
monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no");
|
2022-04-26 12:17:35 +02:00
|
|
|
} else if (stats_value->type == QTYPE_QLIST) {
|
|
|
|
uint64List *list;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
monitor_printf(mon, ": ");
|
|
|
|
for (list = stats_value->u.list, i = 1;
|
|
|
|
list;
|
|
|
|
list = list->next, i++) {
|
|
|
|
monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the StatsFilter that is needed for an "info stats" invocation. */
|
2022-04-26 14:09:31 +02:00
|
|
|
static StatsFilter *stats_filter(StatsTarget target, const char *names,
|
|
|
|
int cpu_index, StatsProvider provider)
|
2022-04-26 12:17:35 +02:00
|
|
|
{
|
|
|
|
StatsFilter *filter = g_malloc0(sizeof(*filter));
|
2022-04-26 14:09:31 +02:00
|
|
|
StatsProvider provider_idx;
|
|
|
|
StatsRequestList *request_list = NULL;
|
2022-04-26 12:17:35 +02:00
|
|
|
|
|
|
|
filter->target = target;
|
|
|
|
switch (target) {
|
|
|
|
case STATS_TARGET_VM:
|
|
|
|
break;
|
|
|
|
case STATS_TARGET_VCPU:
|
|
|
|
{
|
|
|
|
strList *vcpu_list = NULL;
|
|
|
|
CPUState *cpu = qemu_get_cpu(cpu_index);
|
|
|
|
char *canonical_path = object_get_canonical_path(OBJECT(cpu));
|
|
|
|
|
|
|
|
QAPI_LIST_PREPEND(vcpu_list, canonical_path);
|
|
|
|
filter->u.vcpu.has_vcpus = true;
|
|
|
|
filter->u.vcpu.vcpus = vcpu_list;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-04-26 13:58:59 +02:00
|
|
|
|
2022-04-26 14:09:31 +02:00
|
|
|
if (!names && provider == STATS_PROVIDER__MAX) {
|
2022-04-26 13:58:59 +02:00
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:09:31 +02:00
|
|
|
/*
|
|
|
|
* "info stats" can only query either one or all the providers. Querying
|
|
|
|
* by name, but not by provider, requires the creation of one filter per
|
|
|
|
* provider.
|
|
|
|
*/
|
|
|
|
for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) {
|
|
|
|
if (provider == STATS_PROVIDER__MAX || provider == provider_idx) {
|
|
|
|
StatsRequest *request = g_new0(StatsRequest, 1);
|
|
|
|
request->provider = provider_idx;
|
|
|
|
if (names && !g_str_equal(names, "*")) {
|
|
|
|
request->has_names = true;
|
|
|
|
request->names = strList_from_comma_list(names);
|
|
|
|
}
|
|
|
|
QAPI_LIST_PREPEND(request_list, request);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 13:58:59 +02:00
|
|
|
filter->has_providers = true;
|
2022-04-26 14:09:31 +02:00
|
|
|
filter->providers = request_list;
|
2022-04-26 12:17:35 +02:00
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_stats(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *target_str = qdict_get_str(qdict, "target");
|
2022-04-26 13:58:59 +02:00
|
|
|
const char *provider_str = qdict_get_try_str(qdict, "provider");
|
2022-04-26 14:09:31 +02:00
|
|
|
const char *names = qdict_get_try_str(qdict, "names");
|
2022-04-26 13:58:59 +02:00
|
|
|
|
|
|
|
StatsProvider provider = STATS_PROVIDER__MAX;
|
2022-04-26 12:17:35 +02:00
|
|
|
StatsTarget target;
|
|
|
|
Error *err = NULL;
|
|
|
|
g_autoptr(StatsSchemaList) schema = NULL;
|
|
|
|
g_autoptr(StatsResultList) stats = NULL;
|
|
|
|
g_autoptr(StatsFilter) filter = NULL;
|
|
|
|
StatsResultList *entry;
|
|
|
|
|
|
|
|
target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "invalid stats target %s\n", target_str);
|
|
|
|
goto exit_no_print;
|
|
|
|
}
|
2022-04-26 13:58:59 +02:00
|
|
|
if (provider_str) {
|
|
|
|
provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "invalid stats provider %s\n", provider_str);
|
|
|
|
goto exit_no_print;
|
|
|
|
}
|
|
|
|
}
|
2022-04-26 12:17:35 +02:00
|
|
|
|
2022-04-26 13:58:59 +02:00
|
|
|
schema = qmp_query_stats_schemas(provider_str ? true : false,
|
|
|
|
provider, &err);
|
2022-04-26 12:17:35 +02:00
|
|
|
if (err) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
case STATS_TARGET_VM:
|
2022-04-26 14:09:31 +02:00
|
|
|
filter = stats_filter(target, names, -1, provider);
|
2022-04-26 12:17:35 +02:00
|
|
|
break;
|
|
|
|
case STATS_TARGET_VCPU: {}
|
|
|
|
int cpu_index = monitor_get_cpu_index(mon);
|
2022-04-26 14:09:31 +02:00
|
|
|
filter = stats_filter(target, names, cpu_index, provider);
|
2022-04-26 12:17:35 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
stats = qmp_query_stats(filter, &err);
|
|
|
|
if (err) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
for (entry = stats; entry; entry = entry->next) {
|
2022-04-26 13:58:59 +02:00
|
|
|
print_stats_results(mon, target, provider_str == NULL, entry->value, schema);
|
2022-04-26 12:17:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
|
|
|
}
|
|
|
|
exit_no_print:
|
|
|
|
error_free(err);
|
|
|
|
}
|
2022-08-11 14:24:44 +02:00
|
|
|
|
|
|
|
static void hmp_virtio_dump_protocols(Monitor *mon,
|
|
|
|
VhostDeviceProtocols *pcol)
|
|
|
|
{
|
|
|
|
strList *pcol_list = pcol->protocols;
|
|
|
|
while (pcol_list) {
|
|
|
|
monitor_printf(mon, "\t%s", pcol_list->value);
|
|
|
|
pcol_list = pcol_list->next;
|
|
|
|
if (pcol_list != NULL) {
|
|
|
|
monitor_printf(mon, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
if (pcol->has_unknown_protocols) {
|
|
|
|
monitor_printf(mon, " unknown-protocols(0x%016"PRIx64")\n",
|
|
|
|
pcol->unknown_protocols);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_virtio_dump_status(Monitor *mon,
|
|
|
|
VirtioDeviceStatus *status)
|
|
|
|
{
|
|
|
|
strList *status_list = status->statuses;
|
|
|
|
while (status_list) {
|
|
|
|
monitor_printf(mon, "\t%s", status_list->value);
|
|
|
|
status_list = status_list->next;
|
|
|
|
if (status_list != NULL) {
|
|
|
|
monitor_printf(mon, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
if (status->has_unknown_statuses) {
|
|
|
|
monitor_printf(mon, " unknown-statuses(0x%016"PRIx32")\n",
|
|
|
|
status->unknown_statuses);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_virtio_dump_features(Monitor *mon,
|
|
|
|
VirtioDeviceFeatures *features)
|
|
|
|
{
|
|
|
|
strList *transport_list = features->transports;
|
|
|
|
while (transport_list) {
|
|
|
|
monitor_printf(mon, "\t%s", transport_list->value);
|
|
|
|
transport_list = transport_list->next;
|
|
|
|
if (transport_list != NULL) {
|
|
|
|
monitor_printf(mon, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
strList *list = features->dev_features;
|
|
|
|
if (list) {
|
|
|
|
while (list) {
|
|
|
|
monitor_printf(mon, "\t%s", list->value);
|
|
|
|
list = list->next;
|
|
|
|
if (list != NULL) {
|
|
|
|
monitor_printf(mon, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (features->has_unknown_dev_features) {
|
|
|
|
monitor_printf(mon, " unknown-features(0x%016"PRIx64")\n",
|
|
|
|
features->unknown_dev_features);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_virtio_query(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
VirtioInfoList *list = qmp_x_query_virtio(&err);
|
|
|
|
VirtioInfoList *node;
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list == NULL) {
|
|
|
|
monitor_printf(mon, "No VirtIO devices\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = list;
|
|
|
|
while (node) {
|
|
|
|
monitor_printf(mon, "%s [%s]\n", node->value->path,
|
|
|
|
node->value->name);
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
qapi_free_VirtioInfoList(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_virtio_status(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
VirtioStatus *s = qmp_x_query_virtio_status(path, &err);
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:\n", path);
|
|
|
|
monitor_printf(mon, " device_name: %s %s\n",
|
|
|
|
s->name, s->has_vhost_dev ? "(vhost)" : "");
|
|
|
|
monitor_printf(mon, " device_id: %d\n", s->device_id);
|
|
|
|
monitor_printf(mon, " vhost_started: %s\n",
|
|
|
|
s->vhost_started ? "true" : "false");
|
|
|
|
monitor_printf(mon, " bus_name: %s\n", s->bus_name);
|
|
|
|
monitor_printf(mon, " broken: %s\n",
|
|
|
|
s->broken ? "true" : "false");
|
|
|
|
monitor_printf(mon, " disabled: %s\n",
|
|
|
|
s->disabled ? "true" : "false");
|
|
|
|
monitor_printf(mon, " disable_legacy_check: %s\n",
|
|
|
|
s->disable_legacy_check ? "true" : "false");
|
|
|
|
monitor_printf(mon, " started: %s\n",
|
|
|
|
s->started ? "true" : "false");
|
|
|
|
monitor_printf(mon, " use_started: %s\n",
|
|
|
|
s->use_started ? "true" : "false");
|
|
|
|
monitor_printf(mon, " start_on_kick: %s\n",
|
|
|
|
s->start_on_kick ? "true" : "false");
|
|
|
|
monitor_printf(mon, " use_guest_notifier_mask: %s\n",
|
|
|
|
s->use_guest_notifier_mask ? "true" : "false");
|
|
|
|
monitor_printf(mon, " vm_running: %s\n",
|
|
|
|
s->vm_running ? "true" : "false");
|
|
|
|
monitor_printf(mon, " num_vqs: %"PRId64"\n", s->num_vqs);
|
|
|
|
monitor_printf(mon, " queue_sel: %d\n",
|
|
|
|
s->queue_sel);
|
|
|
|
monitor_printf(mon, " isr: %d\n", s->isr);
|
|
|
|
monitor_printf(mon, " endianness: %s\n",
|
|
|
|
s->device_endian);
|
|
|
|
monitor_printf(mon, " status:\n");
|
|
|
|
hmp_virtio_dump_status(mon, s->status);
|
|
|
|
monitor_printf(mon, " Guest features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->guest_features);
|
|
|
|
monitor_printf(mon, " Host features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->host_features);
|
|
|
|
monitor_printf(mon, " Backend features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->backend_features);
|
|
|
|
|
|
|
|
if (s->has_vhost_dev) {
|
|
|
|
monitor_printf(mon, " VHost:\n");
|
|
|
|
monitor_printf(mon, " nvqs: %d\n",
|
|
|
|
s->vhost_dev->nvqs);
|
|
|
|
monitor_printf(mon, " vq_index: %"PRId64"\n",
|
|
|
|
s->vhost_dev->vq_index);
|
|
|
|
monitor_printf(mon, " max_queues: %"PRId64"\n",
|
|
|
|
s->vhost_dev->max_queues);
|
|
|
|
monitor_printf(mon, " n_mem_sections: %"PRId64"\n",
|
|
|
|
s->vhost_dev->n_mem_sections);
|
|
|
|
monitor_printf(mon, " n_tmp_sections: %"PRId64"\n",
|
|
|
|
s->vhost_dev->n_tmp_sections);
|
|
|
|
monitor_printf(mon, " backend_cap: %"PRId64"\n",
|
|
|
|
s->vhost_dev->backend_cap);
|
|
|
|
monitor_printf(mon, " log_enabled: %s\n",
|
|
|
|
s->vhost_dev->log_enabled ? "true" : "false");
|
|
|
|
monitor_printf(mon, " log_size: %"PRId64"\n",
|
|
|
|
s->vhost_dev->log_size);
|
|
|
|
monitor_printf(mon, " Features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->vhost_dev->features);
|
|
|
|
monitor_printf(mon, " Acked features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->vhost_dev->acked_features);
|
|
|
|
monitor_printf(mon, " Backend features:\n");
|
|
|
|
hmp_virtio_dump_features(mon, s->vhost_dev->backend_features);
|
|
|
|
monitor_printf(mon, " Protocol features:\n");
|
|
|
|
hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_VirtioStatus(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
int queue = qdict_get_int(qdict, "queue");
|
|
|
|
VirtVhostQueueStatus *s =
|
|
|
|
qmp_x_query_virtio_vhost_queue_status(path, queue, &err);
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:\n", path);
|
|
|
|
monitor_printf(mon, " device_name: %s (vhost)\n",
|
|
|
|
s->name);
|
|
|
|
monitor_printf(mon, " kick: %"PRId64"\n", s->kick);
|
|
|
|
monitor_printf(mon, " call: %"PRId64"\n", s->call);
|
|
|
|
monitor_printf(mon, " VRing:\n");
|
|
|
|
monitor_printf(mon, " num: %"PRId64"\n", s->num);
|
|
|
|
monitor_printf(mon, " desc: 0x%016"PRIx64"\n", s->desc);
|
|
|
|
monitor_printf(mon, " desc_phys: 0x%016"PRIx64"\n",
|
|
|
|
s->desc_phys);
|
|
|
|
monitor_printf(mon, " desc_size: %"PRId32"\n", s->desc_size);
|
|
|
|
monitor_printf(mon, " avail: 0x%016"PRIx64"\n", s->avail);
|
|
|
|
monitor_printf(mon, " avail_phys: 0x%016"PRIx64"\n",
|
|
|
|
s->avail_phys);
|
|
|
|
monitor_printf(mon, " avail_size: %"PRId32"\n", s->avail_size);
|
|
|
|
monitor_printf(mon, " used: 0x%016"PRIx64"\n", s->used);
|
|
|
|
monitor_printf(mon, " used_phys: 0x%016"PRIx64"\n",
|
|
|
|
s->used_phys);
|
|
|
|
monitor_printf(mon, " used_size: %"PRId32"\n", s->used_size);
|
|
|
|
|
|
|
|
qapi_free_VirtVhostQueueStatus(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
int queue = qdict_get_int(qdict, "queue");
|
|
|
|
VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err);
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:\n", path);
|
|
|
|
monitor_printf(mon, " device_name: %s\n", s->name);
|
|
|
|
monitor_printf(mon, " queue_index: %d\n", s->queue_index);
|
|
|
|
monitor_printf(mon, " inuse: %d\n", s->inuse);
|
|
|
|
monitor_printf(mon, " used_idx: %d\n", s->used_idx);
|
|
|
|
monitor_printf(mon, " signalled_used: %d\n",
|
|
|
|
s->signalled_used);
|
|
|
|
monitor_printf(mon, " signalled_used_valid: %s\n",
|
|
|
|
s->signalled_used_valid ? "true" : "false");
|
|
|
|
if (s->has_last_avail_idx) {
|
|
|
|
monitor_printf(mon, " last_avail_idx: %d\n",
|
|
|
|
s->last_avail_idx);
|
|
|
|
}
|
|
|
|
if (s->has_shadow_avail_idx) {
|
|
|
|
monitor_printf(mon, " shadow_avail_idx: %d\n",
|
|
|
|
s->shadow_avail_idx);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " VRing:\n");
|
|
|
|
monitor_printf(mon, " num: %"PRId32"\n", s->vring_num);
|
|
|
|
monitor_printf(mon, " num_default: %"PRId32"\n",
|
|
|
|
s->vring_num_default);
|
|
|
|
monitor_printf(mon, " align: %"PRId32"\n",
|
|
|
|
s->vring_align);
|
|
|
|
monitor_printf(mon, " desc: 0x%016"PRIx64"\n",
|
|
|
|
s->vring_desc);
|
|
|
|
monitor_printf(mon, " avail: 0x%016"PRIx64"\n",
|
|
|
|
s->vring_avail);
|
|
|
|
monitor_printf(mon, " used: 0x%016"PRIx64"\n",
|
|
|
|
s->vring_used);
|
|
|
|
|
|
|
|
qapi_free_VirtQueueStatus(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
int queue = qdict_get_int(qdict, "queue");
|
|
|
|
int index = qdict_get_try_int(qdict, "index", -1);
|
|
|
|
VirtioQueueElement *e;
|
|
|
|
VirtioRingDescList *list;
|
|
|
|
|
|
|
|
e = qmp_x_query_virtio_queue_element(path, queue, index != -1,
|
|
|
|
index, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:\n", path);
|
|
|
|
monitor_printf(mon, " device_name: %s\n", e->name);
|
|
|
|
monitor_printf(mon, " index: %d\n", e->index);
|
|
|
|
monitor_printf(mon, " desc:\n");
|
|
|
|
monitor_printf(mon, " descs:\n");
|
|
|
|
|
|
|
|
list = e->descs;
|
|
|
|
while (list) {
|
|
|
|
monitor_printf(mon, " addr 0x%"PRIx64" len %d",
|
|
|
|
list->value->addr, list->value->len);
|
|
|
|
if (list->value->flags) {
|
|
|
|
strList *flag = list->value->flags;
|
|
|
|
monitor_printf(mon, " (");
|
|
|
|
while (flag) {
|
|
|
|
monitor_printf(mon, "%s", flag->value);
|
|
|
|
flag = flag->next;
|
|
|
|
if (flag) {
|
|
|
|
monitor_printf(mon, ", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, ")");
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
if (list) {
|
|
|
|
monitor_printf(mon, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
monitor_printf(mon, " avail:\n");
|
|
|
|
monitor_printf(mon, " flags: %d\n", e->avail->flags);
|
|
|
|
monitor_printf(mon, " idx: %d\n", e->avail->idx);
|
|
|
|
monitor_printf(mon, " ring: %d\n", e->avail->ring);
|
|
|
|
monitor_printf(mon, " used:\n");
|
|
|
|
monitor_printf(mon, " flags: %d\n", e->used->flags);
|
|
|
|
monitor_printf(mon, " idx: %d\n", e->used->idx);
|
|
|
|
|
|
|
|
qapi_free_VirtioQueueElement(e);
|
|
|
|
}
|