xref: /openbmc/qemu/monitor/qmp-cmds.c (revision cffaca0fab7ccb955c0e498c5132b801844d2c41)
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 "sysemu/kvm.h"
21 #include "sysemu/runstate.h"
22 #include "sysemu/runstate-action.h"
23 #include "sysemu/block-backend.h"
24 #include "qapi/error.h"
25 #include "qapi/qapi-commands-acpi.h"
26 #include "qapi/qapi-commands-control.h"
27 #include "qapi/qapi-commands-misc.h"
28 #include "qapi/qapi-commands-stats.h"
29 #include "qapi/type-helpers.h"
30 #include "hw/mem/memory-device.h"
31 #include "hw/acpi/acpi_dev_interface.h"
32 #include "hw/intc/intc.h"
33 #include "hw/rdma/rdma.h"
34 #include "monitor/stats.h"
35 
36 NameInfo *qmp_query_name(Error **errp)
37 {
38     NameInfo *info = g_malloc0(sizeof(*info));
39 
40     info->name = g_strdup(qemu_name);
41     return info;
42 }
43 
44 void qmp_quit(Error **errp)
45 {
46     shutdown_action = SHUTDOWN_ACTION_POWEROFF;
47     qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT);
48 }
49 
50 void qmp_stop(Error **errp)
51 {
52     /* if there is a dump in background, we should wait until the dump
53      * finished */
54     if (qemu_system_dump_in_progress()) {
55         error_setg(errp, "There is a dump in process, please wait.");
56         return;
57     }
58 
59     if (runstate_check(RUN_STATE_INMIGRATE)) {
60         autostart = 0;
61     } else {
62         vm_stop(RUN_STATE_PAUSED);
63     }
64 }
65 
66 void qmp_cont(Error **errp)
67 {
68     BlockBackend *blk;
69     BlockJob *job;
70     Error *local_err = NULL;
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_needs_reset()) {
80         error_setg(errp, "Resetting the Virtual Machine is required");
81         return;
82     } else if (runstate_check(RUN_STATE_SUSPENDED)) {
83         return;
84     } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
85         error_setg(errp, "Migration is not finalized yet");
86         return;
87     }
88 
89     for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
90         blk_iostatus_reset(blk);
91     }
92 
93     WITH_JOB_LOCK_GUARD() {
94         for (job = block_job_next_locked(NULL); job;
95              job = block_job_next_locked(job)) {
96             block_job_iostatus_reset_locked(job);
97         }
98     }
99 
100     /* Continuing after completed migration. Images have been inactivated to
101      * allow the destination to take control. Need to get control back now.
102      *
103      * If there are no inactive block nodes (e.g. because the VM was just
104      * paused rather than completing a migration), bdrv_inactivate_all() simply
105      * doesn't do anything. */
106     bdrv_activate_all(&local_err);
107     if (local_err) {
108         error_propagate(errp, local_err);
109         return;
110     }
111 
112     if (runstate_check(RUN_STATE_INMIGRATE)) {
113         autostart = 1;
114     } else {
115         vm_start();
116     }
117 }
118 
119 void qmp_add_client(const char *protocol, const char *fdname,
120                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
121                     Error **errp)
122 {
123     static const struct {
124         const char *name;
125         bool (*add_client)(int fd, bool has_skipauth, bool skipauth,
126                            bool has_tls, bool tls, Error **errp);
127     } protocol_table[] = {
128         { "spice", qmp_add_client_spice },
129 #ifdef CONFIG_VNC
130         { "vnc", qmp_add_client_vnc },
131 #endif
132 #ifdef CONFIG_DBUS_DISPLAY
133         { "@dbus-display", qmp_add_client_dbus_display },
134 #endif
135     };
136     int fd, i;
137 
138     fd = monitor_get_fd(monitor_cur(), fdname, errp);
139     if (fd < 0) {
140         return;
141     }
142 
143     for (i = 0; i < ARRAY_SIZE(protocol_table); i++) {
144         if (!strcmp(protocol, protocol_table[i].name)) {
145             if (!protocol_table[i].add_client(fd, has_skipauth, skipauth,
146                                               has_tls, tls, errp)) {
147                 close(fd);
148             }
149             return;
150         }
151     }
152 
153     if (!qmp_add_client_char(fd, has_skipauth, skipauth, has_tls, tls,
154                              protocol, errp)) {
155         close(fd);
156     }
157 }
158 
159 ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
160 {
161     bool ambig;
162     ACPIOSTInfoList *head = NULL;
163     ACPIOSTInfoList **prev = &head;
164     Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);
165 
166     if (obj) {
167         AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
168         AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
169 
170         adevc->ospm_status(adev, &prev);
171     } else {
172         error_setg(errp, "command is not supported, missing ACPI device");
173     }
174 
175     return head;
176 }
177 
178 typedef struct StatsCallbacks {
179     StatsProvider provider;
180     StatRetrieveFunc *stats_cb;
181     SchemaRetrieveFunc *schemas_cb;
182     QTAILQ_ENTRY(StatsCallbacks) next;
183 } StatsCallbacks;
184 
185 static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
186     QTAILQ_HEAD_INITIALIZER(stats_callbacks);
187 
188 void add_stats_callbacks(StatsProvider provider,
189                          StatRetrieveFunc *stats_fn,
190                          SchemaRetrieveFunc *schemas_fn)
191 {
192     StatsCallbacks *entry = g_new(StatsCallbacks, 1);
193     entry->provider = provider;
194     entry->stats_cb = stats_fn;
195     entry->schemas_cb = schemas_fn;
196 
197     QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
198 }
199 
200 static bool invoke_stats_cb(StatsCallbacks *entry,
201                             StatsResultList **stats_results,
202                             StatsFilter *filter, StatsRequest *request,
203                             Error **errp)
204 {
205     ERRP_GUARD();
206     strList *targets = NULL;
207     strList *names = NULL;
208 
209     if (request) {
210         if (request->provider != entry->provider) {
211             return true;
212         }
213         if (request->has_names && !request->names) {
214             return true;
215         }
216         names = request->has_names ? request->names : NULL;
217     }
218 
219     switch (filter->target) {
220     case STATS_TARGET_VM:
221         break;
222     case STATS_TARGET_VCPU:
223         if (filter->u.vcpu.has_vcpus) {
224             if (!filter->u.vcpu.vcpus) {
225                 /* No targets allowed?  Return no statistics.  */
226                 return true;
227             }
228             targets = filter->u.vcpu.vcpus;
229         }
230         break;
231     default:
232         abort();
233     }
234 
235     entry->stats_cb(stats_results, filter->target, names, targets, errp);
236     if (*errp) {
237         qapi_free_StatsResultList(*stats_results);
238         *stats_results = NULL;
239         return false;
240     }
241     return true;
242 }
243 
244 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
245 {
246     StatsResultList *stats_results = NULL;
247     StatsCallbacks *entry;
248     StatsRequestList *request;
249 
250     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
251         if (filter->has_providers) {
252             for (request = filter->providers; request; request = request->next) {
253                 if (!invoke_stats_cb(entry, &stats_results, filter,
254                                      request->value, errp)) {
255                     break;
256                 }
257             }
258         } else {
259             if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
260                 break;
261             }
262         }
263     }
264 
265     return stats_results;
266 }
267 
268 StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
269                                          StatsProvider provider,
270                                          Error **errp)
271 {
272     ERRP_GUARD();
273     StatsSchemaList *stats_results = NULL;
274     StatsCallbacks *entry;
275 
276     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
277         if (!has_provider || provider == entry->provider) {
278             entry->schemas_cb(&stats_results, errp);
279             if (*errp) {
280                 qapi_free_StatsSchemaList(stats_results);
281                 return NULL;
282             }
283         }
284     }
285 
286     return stats_results;
287 }
288 
289 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
290                      const char *qom_path, StatsList *stats_list)
291 {
292     StatsResult *entry = g_new0(StatsResult, 1);
293 
294     entry->provider = provider;
295     entry->qom_path = g_strdup(qom_path);
296     entry->stats = stats_list;
297 
298     QAPI_LIST_PREPEND(*stats_results, entry);
299 }
300 
301 void add_stats_schema(StatsSchemaList **schema_results,
302                       StatsProvider provider, StatsTarget target,
303                       StatsSchemaValueList *stats_list)
304 {
305     StatsSchema *entry = g_new0(StatsSchema, 1);
306 
307     entry->provider = provider;
308     entry->target = target;
309     entry->stats = stats_list;
310     QAPI_LIST_PREPEND(*schema_results, entry);
311 }
312 
313 bool apply_str_list_filter(const char *string, strList *list)
314 {
315     strList *str_list = NULL;
316 
317     if (!list) {
318         return true;
319     }
320     for (str_list = list; str_list; str_list = str_list->next) {
321         if (g_str_equal(string, str_list->value)) {
322             return true;
323         }
324     }
325     return false;
326 }
327