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:
Paolo Bonzini 2013-12-20 23:21:10 +01:00 committed by Luiz Capitulino
parent ab2d0531b2
commit cff8b2c6fc
9 changed files with 187 additions and 2 deletions

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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:
# #

View File

@ -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
View File

@ -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;