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