xref: /openbmc/qemu/monitor/qmp-cmds.c (revision 9949b06e)
1 /*
2  * QEMU Management Protocol commands
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  * Contributions after 2012-01-13 are licensed under the terms of the
13  * GNU GPL, version 2 or (at your option) any later version.
14  */
15 
16 #include "qemu/osdep.h"
17 #include "qemu/cutils.h"
18 #include "qemu/option.h"
19 #include "monitor/monitor.h"
20 #include "sysemu/sysemu.h"
21 #include "qemu/config-file.h"
22 #include "qemu/uuid.h"
23 #include "chardev/char.h"
24 #include "ui/qemu-spice.h"
25 #include "ui/console.h"
26 #include "ui/dbus-display.h"
27 #include "sysemu/kvm.h"
28 #include "sysemu/runstate.h"
29 #include "sysemu/runstate-action.h"
30 #include "sysemu/blockdev.h"
31 #include "sysemu/block-backend.h"
32 #include "qapi/error.h"
33 #include "qapi/qapi-commands-acpi.h"
34 #include "qapi/qapi-commands-block.h"
35 #include "qapi/qapi-commands-control.h"
36 #include "qapi/qapi-commands-machine.h"
37 #include "qapi/qapi-commands-misc.h"
38 #include "qapi/qapi-commands-stats.h"
39 #include "qapi/type-helpers.h"
40 #include "exec/ramlist.h"
41 #include "hw/mem/memory-device.h"
42 #include "hw/acpi/acpi_dev_interface.h"
43 #include "hw/intc/intc.h"
44 #include "hw/rdma/rdma.h"
45 #include "monitor/stats.h"
46 
47 NameInfo *qmp_query_name(Error **errp)
48 {
49     NameInfo *info = g_malloc0(sizeof(*info));
50 
51     info->name = g_strdup(qemu_name);
52     return info;
53 }
54 
55 KvmInfo *qmp_query_kvm(Error **errp)
56 {
57     KvmInfo *info = g_malloc0(sizeof(*info));
58 
59     info->enabled = kvm_enabled();
60     info->present = accel_find("kvm");
61 
62     return info;
63 }
64 
65 UuidInfo *qmp_query_uuid(Error **errp)
66 {
67     UuidInfo *info = g_malloc0(sizeof(*info));
68 
69     info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid);
70     return info;
71 }
72 
73 void qmp_quit(Error **errp)
74 {
75     shutdown_action = SHUTDOWN_ACTION_POWEROFF;
76     qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT);
77 }
78 
79 void qmp_stop(Error **errp)
80 {
81     /* if there is a dump in background, we should wait until the dump
82      * finished */
83     if (qemu_system_dump_in_progress()) {
84         error_setg(errp, "There is a dump in process, please wait.");
85         return;
86     }
87 
88     if (runstate_check(RUN_STATE_INMIGRATE)) {
89         autostart = 0;
90     } else {
91         vm_stop(RUN_STATE_PAUSED);
92     }
93 }
94 
95 void qmp_system_reset(Error **errp)
96 {
97     qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
98 }
99 
100 void qmp_system_powerdown(Error **errp)
101 {
102     qemu_system_powerdown_request();
103 }
104 
105 void qmp_cont(Error **errp)
106 {
107     BlockBackend *blk;
108     BlockJob *job;
109     Error *local_err = NULL;
110 
111     /* if there is a dump in background, we should wait until the dump
112      * finished */
113     if (qemu_system_dump_in_progress()) {
114         error_setg(errp, "There is a dump in process, please wait.");
115         return;
116     }
117 
118     if (runstate_needs_reset()) {
119         error_setg(errp, "Resetting the Virtual Machine is required");
120         return;
121     } else if (runstate_check(RUN_STATE_SUSPENDED)) {
122         return;
123     } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
124         error_setg(errp, "Migration is not finalized yet");
125         return;
126     }
127 
128     for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
129         blk_iostatus_reset(blk);
130     }
131 
132     WITH_JOB_LOCK_GUARD() {
133         for (job = block_job_next_locked(NULL); job;
134              job = block_job_next_locked(job)) {
135             block_job_iostatus_reset_locked(job);
136         }
137     }
138 
139     /* Continuing after completed migration. Images have been inactivated to
140      * allow the destination to take control. Need to get control back now.
141      *
142      * If there are no inactive block nodes (e.g. because the VM was just
143      * paused rather than completing a migration), bdrv_inactivate_all() simply
144      * doesn't do anything. */
145     bdrv_activate_all(&local_err);
146     if (local_err) {
147         error_propagate(errp, local_err);
148         return;
149     }
150 
151     if (runstate_check(RUN_STATE_INMIGRATE)) {
152         autostart = 1;
153     } else {
154         vm_start();
155     }
156 }
157 
158 void qmp_system_wakeup(Error **errp)
159 {
160     if (!qemu_wakeup_suspend_enabled()) {
161         error_setg(errp,
162                    "wake-up from suspend is not supported by this guest");
163         return;
164     }
165 
166     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
167 }
168 
169 void qmp_add_client(const char *protocol, const char *fdname,
170                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
171                     Error **errp)
172 {
173     Chardev *s;
174     int fd;
175 
176     fd = monitor_get_fd(monitor_cur(), fdname, errp);
177     if (fd < 0) {
178         return;
179     }
180 
181     if (strcmp(protocol, "spice") == 0) {
182         if (!qemu_using_spice(errp)) {
183             close(fd);
184             return;
185         }
186         skipauth = has_skipauth ? skipauth : false;
187         tls = has_tls ? tls : false;
188         if (qemu_spice.display_add_client(fd, skipauth, tls) < 0) {
189             error_setg(errp, "spice failed to add client");
190             close(fd);
191         }
192 #ifdef CONFIG_VNC
193     } else if (strcmp(protocol, "vnc") == 0) {
194         skipauth = has_skipauth ? skipauth : false;
195         vnc_display_add_client(NULL, fd, skipauth);
196 #endif
197 #ifdef CONFIG_DBUS_DISPLAY
198     } else if (strcmp(protocol, "@dbus-display") == 0) {
199         if (!qemu_using_dbus_display(errp)) {
200             close(fd);
201             return;
202         }
203         if (!qemu_dbus_display.add_client(fd, errp)) {
204             close(fd);
205             return;
206         }
207 #endif
208     } else {
209         s = qemu_chr_find(protocol);
210         if (!s) {
211             error_setg(errp, "protocol '%s' is invalid", protocol);
212             close(fd);
213             return;
214         }
215         if (qemu_chr_add_client(s, fd) < 0) {
216             error_setg(errp, "failed to add client");
217             close(fd);
218             return;
219         }
220     }
221 }
222 
223 MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
224 {
225     return qmp_memory_device_list();
226 }
227 
228 ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
229 {
230     bool ambig;
231     ACPIOSTInfoList *head = NULL;
232     ACPIOSTInfoList **prev = &head;
233     Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);
234 
235     if (obj) {
236         AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
237         AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
238 
239         adevc->ospm_status(adev, &prev);
240     } else {
241         error_setg(errp, "command is not supported, missing ACPI device");
242     }
243 
244     return head;
245 }
246 
247 MemoryInfo *qmp_query_memory_size_summary(Error **errp)
248 {
249     MemoryInfo *mem_info = g_new0(MemoryInfo, 1);
250     MachineState *ms = MACHINE(qdev_get_machine());
251 
252     mem_info->base_memory = ms->ram_size;
253 
254     mem_info->plugged_memory = get_plugged_memory_size();
255     mem_info->has_plugged_memory =
256         mem_info->plugged_memory != (uint64_t)-1;
257 
258     return mem_info;
259 }
260 
261 static int qmp_x_query_rdma_foreach(Object *obj, void *opaque)
262 {
263     RdmaProvider *rdma;
264     RdmaProviderClass *k;
265     GString *buf = opaque;
266 
267     if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) {
268         rdma = RDMA_PROVIDER(obj);
269         k = RDMA_PROVIDER_GET_CLASS(obj);
270         if (k->format_statistics) {
271             k->format_statistics(rdma, buf);
272         } else {
273             g_string_append_printf(buf,
274                                    "RDMA statistics not available for %s.\n",
275                                    object_get_typename(obj));
276         }
277     }
278 
279     return 0;
280 }
281 
282 HumanReadableText *qmp_x_query_rdma(Error **errp)
283 {
284     g_autoptr(GString) buf = g_string_new("");
285 
286     object_child_foreach_recursive(object_get_root(),
287                                    qmp_x_query_rdma_foreach, buf);
288 
289     return human_readable_text_from_str(buf);
290 }
291 
292 HumanReadableText *qmp_x_query_ramblock(Error **errp)
293 {
294     g_autoptr(GString) buf = ram_block_format();
295 
296     return human_readable_text_from_str(buf);
297 }
298 
299 static int qmp_x_query_irq_foreach(Object *obj, void *opaque)
300 {
301     InterruptStatsProvider *intc;
302     InterruptStatsProviderClass *k;
303     GString *buf = opaque;
304 
305     if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
306         intc = INTERRUPT_STATS_PROVIDER(obj);
307         k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
308         uint64_t *irq_counts;
309         unsigned int nb_irqs, i;
310         if (k->get_statistics &&
311             k->get_statistics(intc, &irq_counts, &nb_irqs)) {
312             if (nb_irqs > 0) {
313                 g_string_append_printf(buf, "IRQ statistics for %s:\n",
314                                        object_get_typename(obj));
315                 for (i = 0; i < nb_irqs; i++) {
316                     if (irq_counts[i] > 0) {
317                         g_string_append_printf(buf, "%2d: %" PRId64 "\n", i,
318                                                irq_counts[i]);
319                     }
320                 }
321             }
322         } else {
323             g_string_append_printf(buf,
324                                    "IRQ statistics not available for %s.\n",
325                                    object_get_typename(obj));
326         }
327     }
328 
329     return 0;
330 }
331 
332 HumanReadableText *qmp_x_query_irq(Error **errp)
333 {
334     g_autoptr(GString) buf = g_string_new("");
335 
336     object_child_foreach_recursive(object_get_root(),
337                                    qmp_x_query_irq_foreach, buf);
338 
339     return human_readable_text_from_str(buf);
340 }
341 
342 typedef struct StatsCallbacks {
343     StatsProvider provider;
344     StatRetrieveFunc *stats_cb;
345     SchemaRetrieveFunc *schemas_cb;
346     QTAILQ_ENTRY(StatsCallbacks) next;
347 } StatsCallbacks;
348 
349 static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
350     QTAILQ_HEAD_INITIALIZER(stats_callbacks);
351 
352 void add_stats_callbacks(StatsProvider provider,
353                          StatRetrieveFunc *stats_fn,
354                          SchemaRetrieveFunc *schemas_fn)
355 {
356     StatsCallbacks *entry = g_new(StatsCallbacks, 1);
357     entry->provider = provider;
358     entry->stats_cb = stats_fn;
359     entry->schemas_cb = schemas_fn;
360 
361     QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
362 }
363 
364 static bool invoke_stats_cb(StatsCallbacks *entry,
365                             StatsResultList **stats_results,
366                             StatsFilter *filter, StatsRequest *request,
367                             Error **errp)
368 {
369     ERRP_GUARD();
370     strList *targets = NULL;
371     strList *names = NULL;
372 
373     if (request) {
374         if (request->provider != entry->provider) {
375             return true;
376         }
377         if (request->has_names && !request->names) {
378             return true;
379         }
380         names = request->has_names ? request->names : NULL;
381     }
382 
383     switch (filter->target) {
384     case STATS_TARGET_VM:
385         break;
386     case STATS_TARGET_VCPU:
387         if (filter->u.vcpu.has_vcpus) {
388             if (!filter->u.vcpu.vcpus) {
389                 /* No targets allowed?  Return no statistics.  */
390                 return true;
391             }
392             targets = filter->u.vcpu.vcpus;
393         }
394         break;
395     default:
396         abort();
397     }
398 
399     entry->stats_cb(stats_results, filter->target, names, targets, errp);
400     if (*errp) {
401         qapi_free_StatsResultList(*stats_results);
402         *stats_results = NULL;
403         return false;
404     }
405     return true;
406 }
407 
408 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
409 {
410     StatsResultList *stats_results = NULL;
411     StatsCallbacks *entry;
412     StatsRequestList *request;
413 
414     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
415         if (filter->has_providers) {
416             for (request = filter->providers; request; request = request->next) {
417                 if (!invoke_stats_cb(entry, &stats_results, filter,
418                                      request->value, errp)) {
419                     break;
420                 }
421             }
422         } else {
423             if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
424                 break;
425             }
426         }
427     }
428 
429     return stats_results;
430 }
431 
432 StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
433                                          StatsProvider provider,
434                                          Error **errp)
435 {
436     ERRP_GUARD();
437     StatsSchemaList *stats_results = NULL;
438     StatsCallbacks *entry;
439 
440     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
441         if (!has_provider || provider == entry->provider) {
442             entry->schemas_cb(&stats_results, errp);
443             if (*errp) {
444                 qapi_free_StatsSchemaList(stats_results);
445                 return NULL;
446             }
447         }
448     }
449 
450     return stats_results;
451 }
452 
453 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
454                      const char *qom_path, StatsList *stats_list)
455 {
456     StatsResult *entry = g_new0(StatsResult, 1);
457 
458     entry->provider = provider;
459     entry->qom_path = g_strdup(qom_path);
460     entry->stats = stats_list;
461 
462     QAPI_LIST_PREPEND(*stats_results, entry);
463 }
464 
465 void add_stats_schema(StatsSchemaList **schema_results,
466                       StatsProvider provider, StatsTarget target,
467                       StatsSchemaValueList *stats_list)
468 {
469     StatsSchema *entry = g_new0(StatsSchema, 1);
470 
471     entry->provider = provider;
472     entry->target = target;
473     entry->stats = stats_list;
474     QAPI_LIST_PREPEND(*schema_results, entry);
475 }
476 
477 bool apply_str_list_filter(const char *string, strList *list)
478 {
479     strList *str_list = NULL;
480 
481     if (!list) {
482         return true;
483     }
484     for (str_list = list; str_list; str_list = str_list->next) {
485         if (g_str_equal(string, str_list->value)) {
486             return true;
487         }
488     }
489     return false;
490 }
491