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