monitor: add object-add (QMP) and object_add (HMP) command
Add two commands that are the monitor counterparts of -object. The commands have the same Visitor-based implementation, but use different kinds of visitors so that the HMP command has a DWIM string-based syntax, while the QMP variant accepts a stricter JSON-based properties dictionary. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> Tested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
parent
ab2d0531b2
commit
cff8b2c6fc
@ -1241,6 +1241,20 @@ STEXI
|
|||||||
@item netdev_del
|
@item netdev_del
|
||||||
@findex netdev_del
|
@findex netdev_del
|
||||||
Remove host network device.
|
Remove host network device.
|
||||||
|
ETEXI
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "object_add",
|
||||||
|
.args_type = "object:O",
|
||||||
|
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
||||||
|
.help = "create QOM object",
|
||||||
|
.mhandler.cmd = hmp_object_add,
|
||||||
|
},
|
||||||
|
|
||||||
|
STEXI
|
||||||
|
@item object_add
|
||||||
|
@findex object_add
|
||||||
|
Create QOM object.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
|
58
hmp.c
58
hmp.c
@ -21,6 +21,7 @@
|
|||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
|
#include "qapi/opts-visitor.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "block/qapi.h"
|
#include "block/qapi.h"
|
||||||
#include "qemu-io.h"
|
#include "qemu-io.h"
|
||||||
@ -1354,6 +1355,63 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
|||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
QemuOpts *opts;
|
||||||
|
char *type = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
void *dummy = NULL;
|
||||||
|
OptsVisitor *ov;
|
||||||
|
QDict *pdict;
|
||||||
|
|
||||||
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ov = opts_visitor_new(opts);
|
||||||
|
pdict = qdict_clone_shallow(qdict);
|
||||||
|
|
||||||
|
visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out_clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdict_del(pdict, "qom-type");
|
||||||
|
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
||||||
|
if (err) {
|
||||||
|
goto out_clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdict_del(pdict, "id");
|
||||||
|
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
||||||
|
if (err) {
|
||||||
|
goto out_clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
||||||
|
if (err) {
|
||||||
|
goto out_clean;
|
||||||
|
}
|
||||||
|
visit_end_struct(opts_get_visitor(ov), &err);
|
||||||
|
if (err) {
|
||||||
|
qmp_object_del(id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_clean:
|
||||||
|
opts_visitor_cleanup(ov);
|
||||||
|
|
||||||
|
QDECREF(pdict);
|
||||||
|
qemu_opts_del(opts);
|
||||||
|
g_free(id);
|
||||||
|
g_free(type);
|
||||||
|
g_free(dummy);
|
||||||
|
|
||||||
|
out:
|
||||||
|
hmp_handle_error(mon, &err);
|
||||||
|
}
|
||||||
|
|
||||||
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *fdname = qdict_get_str(qdict, "fdname");
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
||||||
|
1
hmp.h
1
hmp.h
@ -90,6 +90,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
|
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,6 +93,9 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
|||||||
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
|
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
|
||||||
|
|
||||||
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
|
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
|
||||||
|
int qmp_object_add(Monitor *mon, const QDict *qdict, QObject **ret);
|
||||||
|
void object_add(const char *type, const char *id, const QDict *qdict,
|
||||||
|
Visitor *v, Error **errp);
|
||||||
|
|
||||||
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
|
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
|
||||||
bool has_opaque, const char *opaque,
|
bool has_opaque, const char *opaque,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#ifndef QAPI_VISITOR_CORE_H
|
#ifndef QAPI_VISITOR_CORE_H
|
||||||
#define QAPI_VISITOR_CORE_H
|
#define QAPI_VISITOR_CORE_H
|
||||||
|
|
||||||
|
#include "qemu/typedefs.h"
|
||||||
#include "qapi/qmp/qobject.h"
|
#include "qapi/qmp/qobject.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -26,8 +27,6 @@ typedef struct GenericList
|
|||||||
struct GenericList *next;
|
struct GenericList *next;
|
||||||
} GenericList;
|
} GenericList;
|
||||||
|
|
||||||
typedef struct Visitor Visitor;
|
|
||||||
|
|
||||||
void visit_start_handle(Visitor *v, void **obj, const char *kind,
|
void visit_start_handle(Visitor *v, void **obj, const char *kind,
|
||||||
const char *name, Error **errp);
|
const char *name, Error **errp);
|
||||||
void visit_end_handle(Visitor *v, Error **errp);
|
void visit_end_handle(Visitor *v, Error **errp);
|
||||||
|
@ -10,6 +10,8 @@ typedef struct QEMUBH QEMUBH;
|
|||||||
|
|
||||||
typedef struct AioContext AioContext;
|
typedef struct AioContext AioContext;
|
||||||
|
|
||||||
|
typedef struct Visitor Visitor;
|
||||||
|
|
||||||
struct Monitor;
|
struct Monitor;
|
||||||
typedef struct Monitor Monitor;
|
typedef struct Monitor Monitor;
|
||||||
typedef struct MigrationParams MigrationParams;
|
typedef struct MigrationParams MigrationParams;
|
||||||
|
@ -2758,6 +2758,26 @@
|
|||||||
##
|
##
|
||||||
{ 'command': 'netdev_del', 'data': {'id': 'str'} }
|
{ 'command': 'netdev_del', 'data': {'id': 'str'} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @object-add:
|
||||||
|
#
|
||||||
|
# Create a QOM object.
|
||||||
|
#
|
||||||
|
# @qom-type: the class name for the object to be created
|
||||||
|
#
|
||||||
|
# @id: the name of the new object
|
||||||
|
#
|
||||||
|
# @props: #optional a dictionary of properties to be passed to the backend
|
||||||
|
#
|
||||||
|
# Returns: Nothing on success
|
||||||
|
# Error if @qom-type is not a valid class name
|
||||||
|
#
|
||||||
|
# Since: 2.0
|
||||||
|
##
|
||||||
|
{ 'command': 'object-add',
|
||||||
|
'data': {'qom-type': 'str', 'id': 'str', '*props': 'dict'},
|
||||||
|
'gen': 'no' }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @object-del:
|
# @object-del:
|
||||||
#
|
#
|
||||||
|
@ -876,6 +876,32 @@ Example:
|
|||||||
<- { "return": {} }
|
<- { "return": {} }
|
||||||
|
|
||||||
|
|
||||||
|
EQMP
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "object-add",
|
||||||
|
.args_type = "qom-type:s,id:s,props:q?",
|
||||||
|
.mhandler.cmd_new = qmp_object_add,
|
||||||
|
},
|
||||||
|
|
||||||
|
SQMP
|
||||||
|
object-add
|
||||||
|
----------
|
||||||
|
|
||||||
|
Create QOM object.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
- "qom-type": the object's QOM type, i.e. the class name (json-string)
|
||||||
|
- "id": the object's ID, must be unique (json-string)
|
||||||
|
- "props": a dictionary of object property values (optional, json-dict)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
-> { "execute": "object-add", "arguments": { "qom-type": "rng-random", "id": "rng1",
|
||||||
|
"props": { "filename": "/dev/hwrng" } } }
|
||||||
|
<- { "return": {} }
|
||||||
|
|
||||||
EQMP
|
EQMP
|
||||||
|
|
||||||
{
|
{
|
||||||
|
62
qmp.c
62
qmp.c
@ -24,6 +24,8 @@
|
|||||||
#include "hw/qdev.h"
|
#include "hw/qdev.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "qom/qom-qobject.h"
|
#include "qom/qom-qobject.h"
|
||||||
|
#include "qapi/qmp/qobject.h"
|
||||||
|
#include "qapi/qmp-input-visitor.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
|
|
||||||
NameInfo *qmp_query_name(Error **errp)
|
NameInfo *qmp_query_name(Error **errp)
|
||||||
@ -530,6 +532,66 @@ void qmp_add_client(const char *protocol, const char *fdname,
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void object_add(const char *type, const char *id, const QDict *qdict,
|
||||||
|
Visitor *v, Error **errp)
|
||||||
|
{
|
||||||
|
Object *obj;
|
||||||
|
const QDictEntry *e;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
if (!object_class_by_name(type)) {
|
||||||
|
error_setg(errp, "invalid class name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = object_new(type);
|
||||||
|
if (qdict) {
|
||||||
|
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
|
||||||
|
object_property_set(obj, v, e->key, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
object_unref(obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_add_child(container_get(object_get_root(), "/objects"),
|
||||||
|
id, obj, errp);
|
||||||
|
object_unref(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qmp_object_add(Monitor *mon, const QDict *qdict, QObject **ret)
|
||||||
|
{
|
||||||
|
const char *type = qdict_get_str(qdict, "qom-type");
|
||||||
|
const char *id = qdict_get_str(qdict, "id");
|
||||||
|
QObject *props = qdict_get(qdict, "props");
|
||||||
|
const QDict *pdict = NULL;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
QmpInputVisitor *qiv;
|
||||||
|
|
||||||
|
if (props) {
|
||||||
|
pdict = qobject_to_qdict(props);
|
||||||
|
if (!pdict) {
|
||||||
|
error_set(&local_err, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qiv = qmp_input_visitor_new(props);
|
||||||
|
object_add(type, id, pdict, qmp_input_get_visitor(qiv), &local_err);
|
||||||
|
qmp_input_visitor_cleanup(qiv);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (local_err) {
|
||||||
|
qerror_report_err(local_err);
|
||||||
|
error_free(local_err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void qmp_object_del(const char *id, Error **errp)
|
void qmp_object_del(const char *id, Error **errp)
|
||||||
{
|
{
|
||||||
Object *container;
|
Object *container;
|
||||||
|
Loading…
Reference in New Issue
Block a user