From: "Dr. David Alan Gilbert" <dgilb...@redhat.com> For an incoming migration it's potentially useful to be able to set capabilities and parameters prior to opening the connection, while a separate option for that would have been possible it seems better to give access to all the existing migration capabilities, parameters etc. The least restrictive way of doing this is to allow arbitrary QMP commands to be executed prior to the -incoming being processed.
As an example: ./bin/qemu-system-x86_64 -nographic -nodefaults -qmp-command '{"execute": "migrate-set-capabilities", "arguments":{"capabilities":[{"capability":"xbzrle","state":true}]}}' -qmp-command '{"execute": "query-migrate-capabilities"}' -incoming tcp::444 Signed-off-by: Dr. David Alan Gilbert <dgilb...@redhat.com> --- include/monitor/monitor.h | 1 + monitor.c | 41 +++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 9 +++++++++ vl.c | 37 ++++++++++++++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 47606d0..3fdac1c 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -25,6 +25,7 @@ void monitor_init(CharDriverState *chr, int flags); int monitor_suspend(Monitor *mon); void monitor_resume(Monitor *mon); +void monitor_command_line_qmp(const char *command); int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, BlockCompletionFunc *completion_cb, diff --git a/monitor.c b/monitor.c index 7e4f605..be9ea57 100644 --- a/monitor.c +++ b/monitor.c @@ -5284,6 +5284,47 @@ static void sortcmdlist(void) qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); } +/* + * Process a command presented on the command line. + */ +void monitor_command_line_qmp(const char *command) +{ + Monitor *old_mon = cur_mon; + Monitor *mon = g_malloc(sizeof(*mon)); + QemuOpts *opts; + monitor_data_init(mon); + bool possibly_more; + + /* Create a char dev into a ringbuffer to hold output */ + opts = qemu_opts_create(qemu_find_opts("chardev"), "cmdline-mon", 1, NULL); + qemu_opt_set(opts, "backend", "ringbuf"); + + mon->chr = qemu_chr_new_from_opts(opts, NULL, NULL); + mon->flags = MONITOR_USE_CONTROL; + + mon->mc = g_malloc0(sizeof(MonitorControl)); + + do_qmp_capabilities(mon, NULL, NULL); + cur_mon = mon; + json_message_parser_init(&mon->mc->parser, handle_qmp_command); + json_message_parser_feed(&mon->mc->parser, command, strlen(command)); + json_message_parser_flush(&mon->mc->parser); + cur_mon = old_mon; + + json_message_parser_destroy(&mon->mc->parser); + + /* Dump the output */ + do { + char *to_print = qmp_ringbuf_read("cmdline-mon", 1024, false, 0, NULL); + fprintf(stderr, "%s", to_print); + possibly_more = to_print[0] != '\0'; + g_free(to_print); + } while (possibly_more); + + qemu_chr_delete(mon->chr); + monitor_data_destroy(mon); + g_free(mon); +} /* * Local variables: diff --git a/qemu-options.hx b/qemu-options.hx index 10b9568..aa84ad8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2799,6 +2799,15 @@ STEXI Like -qmp but uses pretty JSON formatting. ETEXI +DEF("qmp-command", HAS_ARG, QEMU_OPTION_qmp_command, \ + "-qmp-command qmp Execute individual QMP command prior to startup\n", + QEMU_ARCH_ALL) +STEXI +@item -qmp-command @var{command} +@findex --qmp-command +Execute individual QMP command prior to startup +ETEXI + DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ "-mon [chardev=]name[,mode=readline|control][,default]\n", QEMU_ARCH_ALL) STEXI diff --git a/vl.c b/vl.c index fbf4240..62161f6 100644 --- a/vl.c +++ b/vl.c @@ -239,6 +239,14 @@ static struct { { .driver = "qxl-vga", .flag = &default_vga }, }; +/* A list of qmp commands specified on the command line */ +struct qmp_command_queue_entry { + char *command; + QSIMPLEQ_ENTRY(qmp_command_queue_entry) next; +}; + +static QSIMPLEQ_HEAD(, qmp_command_queue_entry) qmp_command_queue_head; + static QemuOptsList qemu_rtc_opts = { .name = "rtc", .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), @@ -2595,6 +2603,17 @@ static int machine_set_property(const char *name, const char *value, return 0; } +static void handle_qmp_commands(void) +{ + struct qmp_command_queue_entry *entry, *tmp; + + QSIMPLEQ_FOREACH_SAFE(entry, &qmp_command_queue_head, next, tmp) { + monitor_command_line_qmp(entry->command); + free(entry->command); + g_free(entry); + } +} + static int object_create(QemuOpts *opts, void *opaque) { Error *err = NULL; @@ -2814,7 +2833,8 @@ int main(int argc, char **argv, char **envp) rtc_clock = QEMU_CLOCK_HOST; - QLIST_INIT (&vm_change_state_head); + QLIST_INIT(&vm_change_state_head); + QSIMPLEQ_INIT(&qmp_command_queue_head); os_setup_early_signal_handling(); module_call_init(MODULE_INIT_MACHINE); @@ -3218,6 +3238,18 @@ int main(int argc, char **argv, char **envp) monitor_parse(optarg, "control", true); default_monitor = 0; break; + case QEMU_OPTION_qmp_command: + /* + * We can't execute these commands until after the monitor + * has initialised, so just stuff them on a queue for now. + */ + { + struct qmp_command_queue_entry *entry; + entry = g_new(struct qmp_command_queue_entry, 1); + entry->command = strdup(optarg); + QSIMPLEQ_INSERT_TAIL(&qmp_command_queue_head, entry, next); + } + break; case QEMU_OPTION_mon: opts = qemu_opts_parse(qemu_find_opts("mon"), optarg, 1); if (!opts) { @@ -4328,6 +4360,9 @@ int main(int argc, char **argv, char **envp) rom_load_done(); qemu_system_reset(VMRESET_SILENT); + + handle_qmp_commands(); + if (loadvm) { if (load_vmstate(loadvm) < 0) { autostart = 0; -- 2.1.0