* [Qemu-devel] [PATCH 1/8] vl: add -object option to create QOM objects from the command line
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 2/8] object: add object_property_add_bool (v2) Anthony Liguori
` (7 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
This will create a new QOM object in the '/objects' path. Note that properties
are set in order which allows for simple objects to be initialized entirely
with this option and then realized.
This option is roughly equivalent to -device but for things that are not
devices.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
qemu-config.c | 10 ++++++++++
qemu-options.hx | 8 ++++++++
vl.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/qemu-config.c b/qemu-config.c
index e854fff..5dee47c 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -678,6 +678,15 @@ static QemuOptsList qemu_add_fd_opts = {
},
};
+static QemuOptsList qemu_object_opts = {
+ .name = "object",
+ .implied_opt_name = "qom-type",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
+ .desc = {
+ { }
+ },
+};
+
static QemuOptsList *vm_config_groups[32] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@@ -695,6 +704,7 @@ static QemuOptsList *vm_config_groups[32] = {
&qemu_iscsi_opts,
&qemu_sandbox_opts,
&qemu_add_fd_opts,
+ &qemu_object_opts,
NULL,
};
diff --git a/qemu-options.hx b/qemu-options.hx
index a67a255..d201a82 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2888,6 +2888,14 @@ STEXI
Enable FIPS 140-2 compliance mode.
ETEXI
+DEF("object", HAS_ARG, QEMU_OPTION_object,
+ "-object TYPENAME[,PROP1=VALUE1,...]\n"
+ " create an new object of type TYPENAME setting properties\n"
+ " in the order they are specified. Note that the 'id'\n"
+ " property must be set. These objects are placed in the\n"
+ " '/objects' path.\n",
+ QEMU_ARCH_ALL)
+
HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table
diff --git a/vl.c b/vl.c
index 5a3d316..895324e 100644
--- a/vl.c
+++ b/vl.c
@@ -168,6 +168,7 @@ int main(int argc, char **argv)
#include "osdep.h"
#include "ui/qemu-spice.h"
+#include "qapi/string-input-visitor.h"
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -2441,6 +2442,53 @@ static void free_and_trace(gpointer mem)
free(mem);
}
+static int object_set_property(const char *name, const char *value, void *opaque)
+{
+ Object *obj = OBJECT(opaque);
+ StringInputVisitor *siv;
+ Error *local_err = NULL;
+
+ if (strcmp(name, "qom-type") == 0 || strcmp(name, "id") == 0) {
+ return 0;
+ }
+
+ siv = string_input_visitor_new(value);
+ object_property_set(obj, string_input_get_visitor(siv), name, &local_err);
+ string_input_visitor_cleanup(siv);
+
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int object_create(QemuOpts *opts, void *opaque)
+{
+ const char *type = qemu_opt_get(opts, "qom-type");
+ const char *id = qemu_opts_id(opts);
+ Object *obj;
+
+ g_assert(type != NULL);
+
+ if (id == NULL) {
+ qerror_report(QERR_MISSING_PARAMETER, "id");
+ return -1;
+ }
+
+ obj = object_new(type);
+ if (qemu_opt_foreach(opts, object_set_property, obj, 1) < 0) {
+ return -1;
+ }
+
+ object_property_add_child(container_get(object_get_root(), "/objects"),
+ id, obj, NULL);
+
+ return 0;
+}
+
int qemu_init_main_loop(void)
{
return main_loop_init();
@@ -3411,6 +3459,9 @@ int main(int argc, char **argv, char **envp)
exit(1);
#endif
break;
+ case QEMU_OPTION_object:
+ opts = qemu_opts_parse(qemu_find_opts("object"), optarg, 1);
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -3441,6 +3492,11 @@ int main(int argc, char **argv, char **envp)
qemu_set_version(machine->hw_version);
}
+ if (qemu_opts_foreach(qemu_find_opts("object"),
+ object_create, NULL, 0) != 0) {
+ exit(1);
+ }
+
/* Init CPU def lists, based on config
* - Must be called after all the qemu_read_config_file() calls
* - Must be called before list_cpus()
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 2/8] object: add object_property_add_bool (v2)
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 1/8] vl: add -object option to create QOM objects from the command line Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 3/8] rng: add RndBackend abstract object class Anthony Liguori
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- Fix whitespace (Andreas Faerber)
---
include/qemu/object.h | 16 +++++++++++++++
qom/object.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/include/qemu/object.h b/include/qemu/object.h
index cc75fee..be707f1 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -947,6 +947,22 @@ void object_property_add_str(Object *obj, const char *name,
struct Error **errp);
/**
+ * object_property_add_bool:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @get: the getter or NULL if the property is write-only.
+ * @set: the setter or NULL if the property is read-only
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Add a bool property using getters/setters. This function will add a
+ * property of type 'bool'.
+ */
+void object_property_add_bool(Object *obj, const char *name,
+ bool (*get)(Object *, struct Error **),
+ void (*set)(Object *, bool, struct Error **),
+ struct Error **errp);
+
+/**
* object_child_foreach:
* @obj: the object whose children will be navigated
* @fn: the iterator function to be called
diff --git a/qom/object.c b/qom/object.c
index e3e9242..d7092b0 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1183,6 +1183,62 @@ void object_property_add_str(Object *obj, const char *name,
prop, errp);
}
+typedef struct BoolProperty
+{
+ bool (*get)(Object *, Error **);
+ void (*set)(Object *, bool, Error **);
+} BoolProperty;
+
+static void property_get_bool(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ BoolProperty *prop = opaque;
+ bool value;
+
+ value = prop->get(obj, errp);
+ visit_type_bool(v, &value, name, errp);
+}
+
+static void property_set_bool(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ BoolProperty *prop = opaque;
+ bool value;
+ Error *local_err = NULL;
+
+ visit_type_bool(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ prop->set(obj, value, errp);
+}
+
+static void property_release_bool(Object *obj, const char *name,
+ void *opaque)
+{
+ BoolProperty *prop = opaque;
+ g_free(prop);
+}
+
+void object_property_add_bool(Object *obj, const char *name,
+ bool (*get)(Object *, Error **),
+ void (*set)(Object *, bool, Error **),
+ Error **errp)
+{
+ BoolProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->get = get;
+ prop->set = set;
+
+ object_property_add(obj, name, "bool",
+ get ? property_get_bool : NULL,
+ set ? property_set_bool : NULL,
+ property_release_bool,
+ prop, errp);
+}
+
static char *qdev_get_type(Object *obj, Error **errp)
{
return g_strdup(object_get_typename(obj));
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 3/8] rng: add RndBackend abstract object class
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 1/8] vl: add -object option to create QOM objects from the command line Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 2/8] object: add object_property_add_bool (v2) Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 4/8] rng-random: add an RNG backend that uses /dev/random (v2) Anthony Liguori
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
This is the backend used by devices that need to request entropy.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile.objs | 2 ++
backends/Makefile.objs | 1 +
backends/rng.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/qemu/rng.h | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+)
create mode 100644 backends/Makefile.objs
create mode 100644 backends/rng.c
create mode 100644 include/qemu/rng.h
diff --git a/Makefile.objs b/Makefile.objs
index 9eca179..1a14de6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -101,6 +101,8 @@ common-obj-y += vl.o
common-obj-$(CONFIG_SLIRP) += slirp/
+common-obj-y += backends/
+
######################################################################
# libseccomp
ifeq ($(CONFIG_SECCOMP),y)
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
new file mode 100644
index 0000000..06e08c7
--- /dev/null
+++ b/backends/Makefile.objs
@@ -0,0 +1 @@
+common-obj-y += rng.o
diff --git a/backends/rng.c b/backends/rng.c
new file mode 100644
index 0000000..06f2611
--- /dev/null
+++ b/backends/rng.c
@@ -0,0 +1,93 @@
+/*
+ * QEMU Random Number Generator Backend
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/rng.h"
+#include "qerror.h"
+
+void rng_backend_request_entropy(RngBackend *s, size_t size,
+ EntropyReceiveFunc *receive_entropy,
+ void *opaque)
+{
+ RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
+
+ if (k->request_entropy) {
+ k->request_entropy(s, size, receive_entropy, opaque);
+ }
+}
+
+void rng_backend_cancel_requests(RngBackend *s)
+{
+ RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
+
+ if (k->cancel_requests) {
+ k->cancel_requests(s);
+ }
+}
+
+static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
+{
+ RngBackend *s = RNG_BACKEND(obj);
+
+ return s->opened;
+}
+
+void rng_backend_open(RngBackend *s, Error **errp)
+{
+ object_property_set_bool(OBJECT(s), true, "opened", errp);
+}
+
+static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
+{
+ RngBackend *s = RNG_BACKEND(obj);
+ RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
+
+ if (value == s->opened) {
+ return;
+ }
+
+ if (!value && s->opened) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ if (k->opened) {
+ k->opened(s, errp);
+ }
+
+ if (!error_is_set(errp)) {
+ s->opened = value;
+ }
+}
+
+static void rng_backend_init(Object *obj)
+{
+ object_property_add_bool(obj, "opened",
+ rng_backend_prop_get_opened,
+ rng_backend_prop_set_opened,
+ NULL);
+}
+
+static TypeInfo rng_backend_info = {
+ .name = TYPE_RNG_BACKEND,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(RngBackend),
+ .instance_init = rng_backend_init,
+ .class_size = sizeof(RngBackendClass),
+ .abstract = true,
+};
+
+static void register_types(void)
+{
+ type_register_static(&rng_backend_info);
+}
+
+type_init(register_types);
diff --git a/include/qemu/rng.h b/include/qemu/rng.h
new file mode 100644
index 0000000..7e9d672
--- /dev/null
+++ b/include/qemu/rng.h
@@ -0,0 +1,93 @@
+/*
+ * QEMU Random Number Generator Backend
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_RNG_H
+#define QEMU_RNG_H
+
+#include "qemu/object.h"
+#include "qemu-common.h"
+#include "error.h"
+
+#define TYPE_RNG_BACKEND "rng-backend"
+#define RNG_BACKEND(obj) \
+ OBJECT_CHECK(RngBackend, (obj), TYPE_RNG_BACKEND)
+#define RNG_BACKEND_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(RngBackendClass, (obj), TYPE_RNG_BACKEND)
+#define RNG_BACKEND_CLASS(klass) \
+ OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)
+
+typedef struct RngBackendClass RngBackendClass;
+typedef struct RngBackend RngBackend;
+
+typedef void (EntropyReceiveFunc)(void *opaque,
+ const void *data,
+ size_t size);
+
+struct RngBackendClass
+{
+ ObjectClass parent_class;
+
+ void (*request_entropy)(RngBackend *s, size_t size,
+ EntropyReceiveFunc *recieve_entropy, void *opaque);
+ void (*cancel_requests)(RngBackend *s);
+
+ void (*opened)(RngBackend *s, Error **errp);
+};
+
+struct RngBackend
+{
+ Object parent;
+
+ /*< protected >*/
+ bool opened;
+};
+
+/**
+ * rng_backend_request_entropy:
+ * @s: the backend to request entropy from
+ * @size: the number of bytes of data to request
+ * @receive_entropy: a function to be invoked when entropy is available
+ * @opaque: data that should be passed to @receive_entropy
+ *
+ * This function is used by the front-end to request entropy from an entropy
+ * source. This function can be called multiple times before @receive_entropy
+ * is invoked with different values of @receive_entropy and @opaque. The
+ * backend will queue each request and handle appropriate.
+ *
+ * The backend does not need to pass the full amount of data to @receive_entropy
+ * but will pass at a value greater than 0.
+ */
+void rng_backend_request_entropy(RngBackend *s, size_t size,
+ EntropyReceiveFunc *receive_entropy,
+ void *opaque);
+
+/**
+ * rng_backend_cancel_requests:
+ * @s: the backend to cancel all pending requests in
+ *
+ * Cancels all pending requests submitted by @rng_backend_request_entropy. This
+ * should be used by a device during reset or in preparation for live migration
+ * to stop tracking any request.
+ */
+void rng_backend_cancel_requests(RngBackend *s);
+
+/**
+ * rng_backend_open:
+ * @s: the backend to open
+ * @errp: a pointer to return the #Error object if an error occurs.
+ *
+ * This function will open the backend if it is not already open. Calling this
+ * function on an already opened backend will not result in an error.
+ */
+void rng_backend_open(RngBackend *s, Error **errp);
+
+#endif
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 4/8] rng-random: add an RNG backend that uses /dev/random (v2)
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (2 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 3/8] rng: add RndBackend abstract object class Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-31 7:36 ` Paolo Bonzini
2012-10-30 23:02 ` [Qemu-devel] [PATCH 5/8] rng-egd: introduce EGD compliant RNG backend Anthony Liguori
` (4 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
The filename can be overridden but it expects a non-blocking source of entropy.
A typical invocation would be:
qemu -object rng-random,id=rng0 -device virtio-rng-pci,rng=rng0
This can also be used with /dev/urandom by using the command line:
qemu -object rng-random,filename=/dev/urandom,id=rng0 \
-device virtio-rng-pci,rng=rng0
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- merged header split patch into this one
---
backends/Makefile.objs | 2 +-
backends/rng-random.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++
include/qemu/rng-random.h | 22 +++++++
3 files changed, 184 insertions(+), 1 deletion(-)
create mode 100644 backends/rng-random.c
create mode 100644 include/qemu/rng-random.h
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 06e08c7..23ca19b 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -1 +1 @@
-common-obj-y += rng.o
+common-obj-y += rng.o rng-random.o
diff --git a/backends/rng-random.c b/backends/rng-random.c
new file mode 100644
index 0000000..8325686
--- /dev/null
+++ b/backends/rng-random.c
@@ -0,0 +1,161 @@
+/*
+ * QEMU Random Number Generator Backend
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/rng-random.h"
+#include "qemu/rng.h"
+#include "qerror.h"
+#include "main-loop.h"
+
+struct RndRandom
+{
+ RngBackend parent;
+
+ int fd;
+ char *filename;
+
+ EntropyReceiveFunc *receive_func;
+ void *opaque;
+ size_t size;
+};
+
+/**
+ * A simple and incomplete backend to request entropy from /dev/random.
+ *
+ * This backend exposes an additional "filename" property that can be used to
+ * set the filename to use to open the backend.
+ */
+
+static void entropy_available(void *opaque)
+{
+ RndRandom *s = RNG_RANDOM(opaque);
+ uint8_t buffer[s->size];
+ ssize_t len;
+
+ len = read(s->fd, buffer, s->size);
+ g_assert(len != -1);
+
+ s->receive_func(s->opaque, buffer, s->size);
+ s->receive_func = NULL;
+
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+}
+
+static void rng_random_request_entropy(RngBackend *b, size_t size,
+ EntropyReceiveFunc *receive_entropy,
+ void *opaque)
+{
+ RndRandom *s = RNG_RANDOM(b);
+
+ if (s->receive_func) {
+ s->receive_func(s->opaque, NULL, 0);
+ }
+
+ s->receive_func = receive_entropy;
+ s->opaque = opaque;
+ s->size = size;
+
+ qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
+}
+
+static void rng_random_opened(RngBackend *b, Error **errp)
+{
+ RndRandom *s = RNG_RANDOM(b);
+
+ if (s->filename == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+ "filename", "a valid filename");
+ } else {
+ s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
+
+ if (s->fd == -1) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
+ }
+ }
+}
+
+static char *rng_random_get_filename(Object *obj, Error **errp)
+{
+ RndRandom *s = RNG_RANDOM(obj);
+
+ if (s->filename) {
+ return g_strdup(s->filename);
+ }
+
+ return NULL;
+}
+
+static void rng_random_set_filename(Object *obj, const char *filename,
+ Error **errp)
+{
+ RngBackend *b = RNG_BACKEND(obj);
+ RndRandom *s = RNG_RANDOM(obj);
+
+ if (b->opened) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ if (s->filename) {
+ g_free(s->filename);
+ }
+
+ s->filename = g_strdup(filename);
+}
+
+static void rng_random_init(Object *obj)
+{
+ RndRandom *s = RNG_RANDOM(obj);
+
+ object_property_add_str(obj, "filename",
+ rng_random_get_filename,
+ rng_random_set_filename,
+ NULL);
+
+ s->filename = g_strdup("/dev/random");
+}
+
+static void rng_random_finalize(Object *obj)
+{
+ RndRandom *s = RNG_RANDOM(obj);
+
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+
+ if (s->fd != -1) {
+ close(s->fd);
+ }
+
+ g_free(s->filename);
+}
+
+static void rng_random_class_init(ObjectClass *klass, void *data)
+{
+ RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
+
+ rbc->request_entropy = rng_random_request_entropy;
+ rbc->opened = rng_random_opened;
+}
+
+static TypeInfo rng_random_info = {
+ .name = TYPE_RNG_RANDOM,
+ .parent = TYPE_RNG_BACKEND,
+ .instance_size = sizeof(RndRandom),
+ .class_init = rng_random_class_init,
+ .instance_init = rng_random_init,
+ .instance_finalize = rng_random_finalize,
+};
+
+static void register_types(void)
+{
+ type_register_static(&rng_random_info);
+}
+
+type_init(register_types);
diff --git a/include/qemu/rng-random.h b/include/qemu/rng-random.h
new file mode 100644
index 0000000..6249290
--- /dev/null
+++ b/include/qemu/rng-random.h
@@ -0,0 +1,22 @@
+/*
+ * QEMU Random Number Generator Backend
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_RNG_RANDOM_H
+#define QEMU_RNG_RANDOM_H
+
+#include "qemu/object.h"
+
+#define TYPE_RNG_RANDOM "rng-random"
+#define RNG_RANDOM(obj) OBJECT_CHECK(RndRandom, (obj), TYPE_RNG_RANDOM)
+
+typedef struct RndRandom RndRandom;
+
+#endif
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH 4/8] rng-random: add an RNG backend that uses /dev/random (v2)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 4/8] rng-random: add an RNG backend that uses /dev/random (v2) Anthony Liguori
@ 2012-10-31 7:36 ` Paolo Bonzini
0 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2012-10-31 7:36 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Amit Shah, H. Peter Anvin, qemu-devel, Andreas Faerber
Il 31/10/2012 00:02, Anthony Liguori ha scritto:
> The filename can be overridden but it expects a non-blocking source of entropy.
> A typical invocation would be:
>
> qemu -object rng-random,id=rng0 -device virtio-rng-pci,rng=rng0
>
> This can also be used with /dev/urandom by using the command line:
>
> qemu -object rng-random,filename=/dev/urandom,id=rng0 \
> -device virtio-rng-pci,rng=rng0
>
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
> v1 -> v2
> - merged header split patch into this one
> ---
> backends/Makefile.objs | 2 +-
> backends/rng-random.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++
> include/qemu/rng-random.h | 22 +++++++
> 3 files changed, 184 insertions(+), 1 deletion(-)
> create mode 100644 backends/rng-random.c
> create mode 100644 include/qemu/rng-random.h
>
> diff --git a/backends/Makefile.objs b/backends/Makefile.objs
> index 06e08c7..23ca19b 100644
> --- a/backends/Makefile.objs
> +++ b/backends/Makefile.objs
> @@ -1 +1 @@
> -common-obj-y += rng.o
> +common-obj-y += rng.o rng-random.o
> diff --git a/backends/rng-random.c b/backends/rng-random.c
> new file mode 100644
> index 0000000..8325686
> --- /dev/null
> +++ b/backends/rng-random.c
> @@ -0,0 +1,161 @@
> +/*
> + * QEMU Random Number Generator Backend
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/rng-random.h"
> +#include "qemu/rng.h"
> +#include "qerror.h"
> +#include "main-loop.h"
> +
> +struct RndRandom
> +{
> + RngBackend parent;
> +
> + int fd;
> + char *filename;
> +
> + EntropyReceiveFunc *receive_func;
> + void *opaque;
> + size_t size;
> +};
> +
> +/**
> + * A simple and incomplete backend to request entropy from /dev/random.
> + *
> + * This backend exposes an additional "filename" property that can be used to
> + * set the filename to use to open the backend.
> + */
> +
> +static void entropy_available(void *opaque)
> +{
> + RndRandom *s = RNG_RANDOM(opaque);
> + uint8_t buffer[s->size];
> + ssize_t len;
> +
> + len = read(s->fd, buffer, s->size);
> + g_assert(len != -1);
> +
> + s->receive_func(s->opaque, buffer, s->size);
Should be len here, not s->size.
Otherwise looks good.
Paolo
> + s->receive_func = NULL;
> +
> + qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
> +}
> +
> +static void rng_random_request_entropy(RngBackend *b, size_t size,
> + EntropyReceiveFunc *receive_entropy,
> + void *opaque)
> +{
> + RndRandom *s = RNG_RANDOM(b);
> +
> + if (s->receive_func) {
> + s->receive_func(s->opaque, NULL, 0);
> + }
> +
> + s->receive_func = receive_entropy;
> + s->opaque = opaque;
> + s->size = size;
> +
> + qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
> +}
> +
> +static void rng_random_opened(RngBackend *b, Error **errp)
> +{
> + RndRandom *s = RNG_RANDOM(b);
> +
> + if (s->filename == NULL) {
> + error_set(errp, QERR_INVALID_PARAMETER_VALUE,
> + "filename", "a valid filename");
> + } else {
> + s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
> +
> + if (s->fd == -1) {
> + error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
> + }
> + }
> +}
> +
> +static char *rng_random_get_filename(Object *obj, Error **errp)
> +{
> + RndRandom *s = RNG_RANDOM(obj);
> +
> + if (s->filename) {
> + return g_strdup(s->filename);
> + }
> +
> + return NULL;
> +}
> +
> +static void rng_random_set_filename(Object *obj, const char *filename,
> + Error **errp)
> +{
> + RngBackend *b = RNG_BACKEND(obj);
> + RndRandom *s = RNG_RANDOM(obj);
> +
> + if (b->opened) {
> + error_set(errp, QERR_PERMISSION_DENIED);
> + return;
> + }
> +
> + if (s->filename) {
> + g_free(s->filename);
> + }
> +
> + s->filename = g_strdup(filename);
> +}
> +
> +static void rng_random_init(Object *obj)
> +{
> + RndRandom *s = RNG_RANDOM(obj);
> +
> + object_property_add_str(obj, "filename",
> + rng_random_get_filename,
> + rng_random_set_filename,
> + NULL);
> +
> + s->filename = g_strdup("/dev/random");
> +}
> +
> +static void rng_random_finalize(Object *obj)
> +{
> + RndRandom *s = RNG_RANDOM(obj);
> +
> + qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
> +
> + if (s->fd != -1) {
> + close(s->fd);
> + }
> +
> + g_free(s->filename);
> +}
> +
> +static void rng_random_class_init(ObjectClass *klass, void *data)
> +{
> + RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
> +
> + rbc->request_entropy = rng_random_request_entropy;
> + rbc->opened = rng_random_opened;
> +}
> +
> +static TypeInfo rng_random_info = {
> + .name = TYPE_RNG_RANDOM,
> + .parent = TYPE_RNG_BACKEND,
> + .instance_size = sizeof(RndRandom),
> + .class_init = rng_random_class_init,
> + .instance_init = rng_random_init,
> + .instance_finalize = rng_random_finalize,
> +};
> +
> +static void register_types(void)
> +{
> + type_register_static(&rng_random_info);
> +}
> +
> +type_init(register_types);
> diff --git a/include/qemu/rng-random.h b/include/qemu/rng-random.h
> new file mode 100644
> index 0000000..6249290
> --- /dev/null
> +++ b/include/qemu/rng-random.h
> @@ -0,0 +1,22 @@
> +/*
> + * QEMU Random Number Generator Backend
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#ifndef QEMU_RNG_RANDOM_H
> +#define QEMU_RNG_RANDOM_H
> +
> +#include "qemu/object.h"
> +
> +#define TYPE_RNG_RANDOM "rng-random"
> +#define RNG_RANDOM(obj) OBJECT_CHECK(RndRandom, (obj), TYPE_RNG_RANDOM)
> +
> +typedef struct RndRandom RndRandom;
> +
> +#endif
> -- 1.8.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 5/8] rng-egd: introduce EGD compliant RNG backend
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (3 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 4/8] rng-random: add an RNG backend that uses /dev/random (v2) Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 6/8] virtio-rng: hardware random number generator device Anthony Liguori
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
This backend talks EGD to a CharDriverState. A typical way to invoke this would
be:
qemu -chardev socket,host=localhost,port=1024,id=chr0 \
-object rng-egd,chardev=chr0,id=egd0 \
-device virtio-rng-pci,rng=egd0
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
backends/Makefile.objs | 2 +-
backends/rng-egd.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 216 insertions(+), 1 deletion(-)
create mode 100644 backends/rng-egd.c
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 23ca19b..875eebc 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -1 +1 @@
-common-obj-y += rng.o rng-random.o
+common-obj-y += rng.o rng-random.o rng-egd.o
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
new file mode 100644
index 0000000..ec58358
--- /dev/null
+++ b/backends/rng-egd.c
@@ -0,0 +1,215 @@
+/*
+ * QEMU Random Number Generator Backend
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/rng.h"
+#include "qemu-char.h"
+#include "qerror.h"
+#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
+
+#define TYPE_RNG_EGD "rng-egd"
+#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
+
+typedef struct RngEgd
+{
+ RngBackend parent;
+
+ CharDriverState *chr;
+ char *chr_name;
+
+ GSList *requests;
+} RngEgd;
+
+typedef struct RngRequest
+{
+ EntropyReceiveFunc *receive_entropy;
+ uint8_t *data;
+ void *opaque;
+ size_t offset;
+ size_t size;
+} RngRequest;
+
+static void rng_egd_request_entropy(RngBackend *b, size_t size,
+ EntropyReceiveFunc *receive_entropy,
+ void *opaque)
+{
+ RngEgd *s = RNG_EGD(b);
+ RngRequest *req;
+
+ req = g_malloc(sizeof(*req));
+
+ req->offset = 0;
+ req->size = size;
+ req->receive_entropy = receive_entropy;
+ req->opaque = opaque;
+ req->data = g_malloc(req->size);
+
+ while (size > 0) {
+ uint8_t header[2];
+ uint8_t len = MIN(size, 255);
+
+ /* synchronous entropy request */
+ header[0] = 0x02;
+ header[1] = len;
+
+ qemu_chr_fe_write(s->chr, header, sizeof(header));
+
+ size -= len;
+ }
+
+ s->requests = g_slist_append(s->requests, req);
+}
+
+static void rng_egd_free_request(RngRequest *req)
+{
+ g_free(req->data);
+ g_free(req);
+}
+
+static int rng_egd_chr_can_read(void *opaque)
+{
+ RngEgd *s = RNG_EGD(opaque);
+ GSList *i;
+ int size = 0;
+
+ for (i = s->requests; i; i = i->next) {
+ RngRequest *req = i->data;
+ size += req->size - req->offset;
+ }
+
+ return size;
+}
+
+static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ RngEgd *s = RNG_EGD(opaque);
+
+ while (size > 0 && s->requests) {
+ RngRequest *req = s->requests->data;
+ int len = MIN(size, req->size - req->offset);
+
+ memcpy(req->data + req->offset, buf, len);
+ req->offset += len;
+ size -= len;
+
+ if (req->offset == req->size) {
+ s->requests = g_slist_remove_link(s->requests, s->requests);
+
+ req->receive_entropy(req->opaque, req->data, req->size);
+
+ rng_egd_free_request(req);
+ }
+ }
+}
+
+static void rng_egd_cancel_requests(RngBackend *b)
+{
+ RngEgd *s = RNG_EGD(b);
+
+ /* We simply delete the list of pending requests. If there is data in the
+ * queue waiting to be read, this is okay, because there will always be
+ * more data than we requested originally
+ */
+ g_slist_free_full(s->requests,
+ (GDestroyNotify)rng_egd_free_request);
+ s->requests = NULL;
+}
+
+static void rng_egd_opened(RngBackend *b, Error **errp)
+{
+ RngEgd *s = RNG_EGD(b);
+
+ if (s->chr_name == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+ "chardev", "a valid character device");
+ return;
+ }
+
+ s->chr = qemu_chr_find(s->chr_name);
+ if (s->chr == NULL) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, s->chr_name);
+ return;
+ }
+
+ /* FIXME we should resubmit pending requests when the CDS reconnects. */
+ qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
+ NULL, s);
+}
+
+static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
+{
+ RngBackend *b = RNG_BACKEND(obj);
+ RngEgd *s = RNG_EGD(b);
+
+ if (b->opened) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ g_free(s->chr_name);
+ s->chr_name = g_strdup(value);
+ }
+}
+
+static char *rng_egd_get_chardev(Object *obj, Error **errp)
+{
+ RngEgd *s = RNG_EGD(obj);
+
+ if (s->chr && s->chr->label) {
+ return g_strdup(s->chr->label);
+ }
+
+ return NULL;
+}
+
+static void rng_egd_init(Object *obj)
+{
+ object_property_add_str(obj, "chardev",
+ rng_egd_get_chardev, rng_egd_set_chardev,
+ NULL);
+}
+
+static void rng_egd_finalize(Object *obj)
+{
+ RngEgd *s = RNG_EGD(obj);
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+ }
+
+ g_free(s->chr_name);
+
+ g_slist_free_full(s->requests, (GDestroyNotify)rng_egd_free_request);
+ s->requests = NULL;
+}
+
+static void rng_egd_class_init(ObjectClass *klass, void *data)
+{
+ RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
+
+ rbc->request_entropy = rng_egd_request_entropy;
+ rbc->cancel_requests = rng_egd_cancel_requests;
+ rbc->opened = rng_egd_opened;
+}
+
+static TypeInfo rng_egd_info = {
+ .name = TYPE_RNG_EGD,
+ .parent = TYPE_RNG_BACKEND,
+ .instance_size = sizeof(RngEgd),
+ .class_init = rng_egd_class_init,
+ .instance_init = rng_egd_init,
+ .instance_finalize = rng_egd_finalize,
+};
+
+static void register_types(void)
+{
+ type_register_static(&rng_egd_info);
+}
+
+type_init(register_types);
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 6/8] virtio-rng: hardware random number generator device
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (4 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 5/8] rng-egd: introduce EGD compliant RNG backend Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 7/8] virtio-rng: add rate limiting support Anthony Liguori
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
From: Amit Shah <amit.shah@redhat.com>
The Linux kernel already has a virtio-rng driver, this is the device
implementation.
When the guest asks for entropy from the virtio hwrng, it puts a buffer
in the vq. We then put entropy into that buffer, and push it back to
the guest.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
aliguori: converted to new RngBackend interface
aliguori: remove entropy needed event
aliguori: fix migration
---
hw/Makefile.objs | 1 +
hw/pci.h | 1 +
hw/s390-virtio-bus.c | 37 +++++++++
hw/s390-virtio-bus.h | 2 +
hw/virtio-pci.c | 60 +++++++++++++++
hw/virtio-pci.h | 2 +
hw/virtio-rng.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/virtio-rng.h | 24 ++++++
hw/virtio.h | 3 +
9 files changed, 341 insertions(+)
create mode 100644 hw/virtio-rng.c
create mode 100644 hw/virtio-rng.h
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index af4ab0c..ea46f81 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,6 +1,7 @@
common-obj-y = usb/ ide/
common-obj-y += loader.o
common-obj-$(CONFIG_VIRTIO) += virtio-console.o
+common-obj-$(CONFIG_VIRTIO) += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += fw_cfg.o
common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o
diff --git a/hw/pci.h b/hw/pci.h
index 241c1d8..4da0c2a 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -76,6 +76,7 @@
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
+#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define FMT_PCIBUS PRIx64
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 5849a96..e0ac2d1 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -26,6 +26,7 @@
#include "loader.h"
#include "elf.h"
#include "hw/virtio.h"
+#include "hw/virtio-rng.h"
#include "hw/virtio-serial.h"
#include "hw/virtio-net.h"
#include "hw/sysbus.h"
@@ -206,6 +207,18 @@ static int s390_virtio_scsi_init(VirtIOS390Device *dev)
return s390_virtio_device_init(dev, vdev);
}
+static int s390_virtio_rng_init(VirtIOS390Device *dev)
+{
+ VirtIODevice *vdev;
+
+ vdev = virtio_rng_init((DeviceState *)dev, &dev->rng);
+ if (!vdev) {
+ return -1;
+ }
+
+ return s390_virtio_device_init(dev, vdev);
+}
+
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
{
ram_addr_t token_off;
@@ -448,6 +461,29 @@ static TypeInfo s390_virtio_serial = {
.class_init = s390_virtio_serial_class_init,
};
+static void s390_virtio_rng_initfn(Object *obj)
+{
+ VirtIOS390Device *dev = VIRTIO_S390_DEVICE(obj);
+
+ object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+ (Object **)&dev->rng.rng, NULL);
+}
+
+static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
+{
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_rng_init;
+}
+
+static TypeInfo s390_virtio_rng = {
+ .name = "virtio-rng-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .instance_init = s390_virtio_rng_initfn,
+ .class_init = s390_virtio_rng_class_init,
+};
+
static int s390_virtio_busdev_init(DeviceState *dev)
{
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
@@ -528,6 +564,7 @@ static void s390_virtio_register_types(void)
type_register_static(&s390_virtio_blk);
type_register_static(&s390_virtio_net);
type_register_static(&s390_virtio_scsi);
+ type_register_static(&s390_virtio_rng);
type_register_static(&s390_virtio_bridge_info);
}
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 4873134..a83afe7 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -19,6 +19,7 @@
#include "virtio-blk.h"
#include "virtio-net.h"
+#include "virtio-rng.h"
#include "virtio-serial.h"
#include "virtio-scsi.h"
@@ -75,6 +76,7 @@ struct VirtIOS390Device {
virtio_serial_conf serial;
virtio_net_conf net;
VirtIOSCSIConf scsi;
+ VirtIORNGConf rng;
};
typedef struct VirtIOS390Bus {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 9603150..a3d4777 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -852,6 +852,28 @@ static void virtio_balloon_exit_pci(PCIDevice *pci_dev)
virtio_exit_pci(pci_dev);
}
+static int virtio_rng_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
+ if (!vdev) {
+ return -1;
+ }
+ virtio_init_pci(proxy, vdev);
+ return 0;
+}
+
+static void virtio_rng_exit_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ virtio_pci_stop_ioeventfd(proxy);
+ virtio_rng_exit(proxy->vdev);
+ virtio_exit_pci(pci_dev);
+}
+
static Property virtio_blk_properties[] = {
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
@@ -982,6 +1004,43 @@ static TypeInfo virtio_balloon_info = {
.class_init = virtio_balloon_class_init,
};
+static void virtio_rng_initfn(Object *obj)
+{
+ PCIDevice *pci_dev = PCI_DEVICE(obj);
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+ (Object **)&proxy->rng.rng, NULL);
+}
+
+static Property virtio_rng_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_rng_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_rng_init_pci;
+ k->exit = virtio_rng_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_rng_properties;
+}
+
+static TypeInfo virtio_rng_info = {
+ .name = "virtio-rng-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .instance_init = virtio_rng_initfn,
+ .class_init = virtio_rng_class_init,
+};
+
static int virtio_scsi_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
@@ -1046,6 +1105,7 @@ static void virtio_pci_register_types(void)
type_register_static(&virtio_serial_info);
type_register_static(&virtio_balloon_info);
type_register_static(&virtio_scsi_info);
+ type_register_static(&virtio_rng_info);
}
type_init(virtio_pci_register_types)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index ac9d522..b58d9a2 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -17,6 +17,7 @@
#include "virtio-blk.h"
#include "virtio-net.h"
+#include "virtio-rng.h"
#include "virtio-serial.h"
#include "virtio-scsi.h"
@@ -46,6 +47,7 @@ typedef struct {
virtio_serial_conf serial;
virtio_net_conf net;
VirtIOSCSIConf scsi;
+ VirtIORNGConf rng;
bool ioeventfd_disabled;
bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd;
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
new file mode 100644
index 0000000..b7fb5e9
--- /dev/null
+++ b/hw/virtio-rng.c
@@ -0,0 +1,211 @@
+/*
+ * A virtio device implementing a hardware random number generator.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ * Copyright 2012 Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "iov.h"
+#include "qdev.h"
+#include "virtio.h"
+#include "virtio-rng.h"
+#include "qemu/rng.h"
+
+typedef struct VirtIORNG {
+ VirtIODevice vdev;
+
+ DeviceState *qdev;
+
+ /* Only one vq - guest puts buffer(s) on it when it needs entropy */
+ VirtQueue *vq;
+ VirtQueueElement elem;
+
+ /* Config data for the device -- currently only chardev */
+ VirtIORNGConf *conf;
+
+ /* Whether we've popped a vq element into 'elem' above */
+ bool popped;
+
+ RngBackend *rng;
+} VirtIORNG;
+
+static bool is_guest_ready(VirtIORNG *vrng)
+{
+ if (virtio_queue_ready(vrng->vq)
+ && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ return true;
+ }
+ return false;
+}
+
+static size_t pop_an_elem(VirtIORNG *vrng)
+{
+ size_t size;
+
+ if (!vrng->popped && !virtqueue_pop(vrng->vq, &vrng->elem)) {
+ return 0;
+ }
+ vrng->popped = true;
+
+ size = iov_size(vrng->elem.in_sg, vrng->elem.in_num);
+ return size;
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const void *buf, size_t size)
+{
+ VirtIORNG *vrng = opaque;
+ size_t len;
+ int offset;
+
+ if (!is_guest_ready(vrng)) {
+ return;
+ }
+
+ offset = 0;
+ while (offset < size) {
+ if (!pop_an_elem(vrng)) {
+ break;
+ }
+ len = iov_from_buf(vrng->elem.in_sg, vrng->elem.in_num,
+ 0, buf + offset, size - offset);
+ offset += len;
+
+ virtqueue_push(vrng->vq, &vrng->elem, len);
+ vrng->popped = false;
+ }
+ virtio_notify(&vrng->vdev, vrng->vq);
+
+ /*
+ * Lastly, if we had multiple elems queued by the guest, and we
+ * didn't have enough data to fill them all, indicate we want more
+ * data.
+ */
+ len = pop_an_elem(vrng);
+ if (len) {
+ rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
+ }
+}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+ size_t size;
+
+ size = pop_an_elem(vrng);
+ if (size) {
+ rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
+ }
+}
+
+static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
+{
+ return f;
+}
+
+static void virtio_rng_save(QEMUFile *f, void *opaque)
+{
+ VirtIORNG *vrng = opaque;
+
+ virtio_save(&vrng->vdev, f);
+
+ qemu_put_byte(f, vrng->popped);
+ if (vrng->popped) {
+ int i;
+
+ qemu_put_be32(f, vrng->elem.index);
+
+ qemu_put_be32(f, vrng->elem.in_num);
+ for (i = 0; i < vrng->elem.in_num; i++) {
+ qemu_put_be64(f, vrng->elem.in_addr[i]);
+ }
+
+ qemu_put_be32(f, vrng->elem.out_num);
+ for (i = 0; i < vrng->elem.out_num; i++) {
+ qemu_put_be64(f, vrng->elem.out_addr[i]);
+ }
+ }
+}
+
+static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VirtIORNG *vrng = opaque;
+
+ if (version_id != 1) {
+ return -EINVAL;
+ }
+ virtio_load(&vrng->vdev, f);
+
+ vrng->popped = qemu_get_byte(f);
+ if (vrng->popped) {
+ int i;
+
+ vrng->elem.index = qemu_get_be32(f);
+
+ vrng->elem.in_num = qemu_get_be32(f);
+ g_assert(vrng->elem.in_num < VIRTQUEUE_MAX_SIZE);
+ for (i = 0; i < vrng->elem.in_num; i++) {
+ vrng->elem.in_addr[i] = qemu_get_be64(f);
+ }
+
+ vrng->elem.out_num = qemu_get_be32(f);
+ g_assert(vrng->elem.out_num < VIRTQUEUE_MAX_SIZE);
+ for (i = 0; i < vrng->elem.out_num; i++) {
+ vrng->elem.out_addr[i] = qemu_get_be64(f);
+ }
+
+ virtqueue_map_sg(vrng->elem.in_sg, vrng->elem.in_addr,
+ vrng->elem.in_num, 1);
+ virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr,
+ vrng->elem.out_num, 0);
+ }
+ return 0;
+}
+
+VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
+{
+ VirtIORNG *vrng;
+ VirtIODevice *vdev;
+ Error *local_err = NULL;
+
+ vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
+ sizeof(VirtIORNG));
+
+ vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+ vrng->rng = conf->rng;
+ if (vrng->rng == NULL) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
+ return NULL;
+ }
+
+ rng_backend_open(vrng->rng, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return NULL;
+ }
+
+ vrng->vq = virtio_add_queue(vdev, 8, handle_input);
+ vrng->vdev.get_features = get_features;
+
+ vrng->qdev = dev;
+ vrng->conf = conf;
+ vrng->popped = false;
+ register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
+ virtio_rng_load, vrng);
+
+ return vdev;
+}
+
+void virtio_rng_exit(VirtIODevice *vdev)
+{
+ VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+ unregister_savevm(vrng->qdev, "virtio-rng", vrng);
+ virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
new file mode 100644
index 0000000..fbb0104
--- /dev/null
+++ b/hw/virtio-rng.h
@@ -0,0 +1,24 @@
+/*
+ * Virtio RNG Support
+ *
+ * Copyright Red Hat, Inc. 2012
+ * Copyright Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef _QEMU_VIRTIO_RNG_H
+#define _QEMU_VIRTIO_RNG_H
+
+#include "qemu/rng.h"
+
+/* The Virtio ID for the virtio rng device */
+#define VIRTIO_ID_RNG 4
+
+struct VirtIORNGConf {
+ RngBackend *rng;
+};
+
+#endif
diff --git a/hw/virtio.h b/hw/virtio.h
index ac482be..df8d0f7 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -203,6 +203,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
VirtIODevice *virtio_balloon_init(DeviceState *dev);
typedef struct VirtIOSCSIConf VirtIOSCSIConf;
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
+typedef struct VirtIORNGConf VirtIORNGConf;
+VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf);
#ifdef CONFIG_LINUX
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
#endif
@@ -213,6 +215,7 @@ void virtio_blk_exit(VirtIODevice *vdev);
void virtio_serial_exit(VirtIODevice *vdev);
void virtio_balloon_exit(VirtIODevice *vdev);
void virtio_scsi_exit(VirtIODevice *vdev);
+void virtio_rng_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 7/8] virtio-rng: add rate limiting support
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (5 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 6/8] virtio-rng: hardware random number generator device Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-30 23:02 ` [Qemu-devel] [PATCH 8/8] virtio-rng-pci: create a default backend if none exists Anthony Liguori
2012-10-31 1:24 ` [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) H. Peter Anvin
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
This adds parameters to virtio-rng-pci to allow rate limiting the entropy a
guest receives. An example command line:
$ qemu -device virtio-rng-pci,max-bytes=1024,period=1000
Would limit entropy collection to 1Kb/s.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
hw/virtio-pci.c | 7 +++++++
hw/virtio-rng.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++--------
hw/virtio-rng.h | 2 ++
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index a3d4777..f90296d 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -1015,6 +1015,13 @@ static void virtio_rng_initfn(Object *obj)
static Property virtio_rng_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
+ you have an entropy source capable of generating more entropy than this
+ and you can pass it through via virtio-rng, then hats off to you. Until
+ then, this is unlimited for all practical purposes.
+ */
+ DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
+ DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
index b7fb5e9..3ca96c8 100644
--- a/hw/virtio-rng.c
+++ b/hw/virtio-rng.c
@@ -31,6 +31,12 @@ typedef struct VirtIORNG {
bool popped;
RngBackend *rng;
+
+ /* We purposefully don't migrate this state. The quota will reset on the
+ * destination as a result. Rate limiting is host state, not guest state.
+ */
+ QEMUTimer *rate_limit_timer;
+ int64_t quota_remaining;
} VirtIORNG;
static bool is_guest_ready(VirtIORNG *vrng)
@@ -55,6 +61,8 @@ static size_t pop_an_elem(VirtIORNG *vrng)
return size;
}
+static void virtio_rng_process(VirtIORNG *vrng);
+
/* Send data from a char device over to the guest */
static void chr_read(void *opaque, const void *buf, size_t size)
{
@@ -66,6 +74,8 @@ static void chr_read(void *opaque, const void *buf, size_t size)
return;
}
+ vrng->quota_remaining -= size;
+
offset = 0;
while (offset < size) {
if (!pop_an_elem(vrng)) {
@@ -85,23 +95,32 @@ static void chr_read(void *opaque, const void *buf, size_t size)
* didn't have enough data to fill them all, indicate we want more
* data.
*/
- len = pop_an_elem(vrng);
- if (len) {
- rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
- }
+ virtio_rng_process(vrng);
}
-static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+static void virtio_rng_process(VirtIORNG *vrng)
{
- VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
- size_t size;
+ ssize_t size;
+
+ if (!is_guest_ready(vrng)) {
+ return;
+ }
size = pop_an_elem(vrng);
- if (size) {
+ size = MIN(vrng->quota_remaining, size);
+
+ if (size > 0) {
rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
}
}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+ virtio_rng_process(vrng);
+}
+
static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
{
return f;
@@ -163,9 +182,27 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr,
vrng->elem.out_num, 0);
}
+
+ /* We may have an element ready but couldn't process it due to a quota
+ limit. Make sure to try again after live migration when the quota may
+ have been reset.
+ */
+ virtio_rng_process(vrng);
+
return 0;
}
+static void check_rate_limit(void *opaque)
+{
+ VirtIORNG *s = opaque;
+
+ s->quota_remaining = s->conf->max_bytes;
+ virtio_rng_process(s);
+ qemu_mod_timer(s->rate_limit_timer,
+ qemu_get_clock_ms(vm_clock) + s->conf->period_ms);
+}
+
+
VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
{
VirtIORNG *vrng;
@@ -196,6 +233,16 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
vrng->qdev = dev;
vrng->conf = conf;
vrng->popped = false;
+ vrng->quota_remaining = vrng->conf->max_bytes;
+
+ g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX);
+
+ vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
+ check_rate_limit, vrng);
+
+ qemu_mod_timer(vrng->rate_limit_timer,
+ qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms);
+
register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
virtio_rng_load, vrng);
diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
index fbb0104..7324d0a 100644
--- a/hw/virtio-rng.h
+++ b/hw/virtio-rng.h
@@ -19,6 +19,8 @@
struct VirtIORNGConf {
RngBackend *rng;
+ uint64_t max_bytes;
+ uint32_t period_ms;
};
#endif
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 8/8] virtio-rng-pci: create a default backend if none exists
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (6 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 7/8] virtio-rng: add rate limiting support Anthony Liguori
@ 2012-10-30 23:02 ` Anthony Liguori
2012-10-31 1:24 ` [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) H. Peter Anvin
8 siblings, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-30 23:02 UTC (permalink / raw)
To: qemu-devel
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, Andreas Faerber,
H. Peter Anvin
This allows you to specify:
$ qemu -device virtio-rng-pci
And things will Just Work with a reasonable default.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
hw/virtio-pci.c | 13 +++++++++++++
hw/virtio-rng.h | 2 ++
2 files changed, 15 insertions(+)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index f90296d..71f4fb5 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -857,6 +857,19 @@ static int virtio_rng_init_pci(PCIDevice *pci_dev)
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
+ if (proxy->rng.rng == NULL) {
+ proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
+
+ object_property_add_child(OBJECT(pci_dev),
+ "default-backend",
+ OBJECT(proxy->rng.default_backend),
+ NULL);
+
+ object_property_set_link(OBJECT(pci_dev),
+ OBJECT(proxy->rng.default_backend),
+ "rng", NULL);
+ }
+
vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
if (!vdev) {
return -1;
diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
index 7324d0a..f42d748 100644
--- a/hw/virtio-rng.h
+++ b/hw/virtio-rng.h
@@ -13,6 +13,7 @@
#define _QEMU_VIRTIO_RNG_H
#include "qemu/rng.h"
+#include "qemu/rng-random.h"
/* The Virtio ID for the virtio rng device */
#define VIRTIO_ID_RNG 4
@@ -21,6 +22,7 @@ struct VirtIORNGConf {
RngBackend *rng;
uint64_t max_bytes;
uint32_t period_ms;
+ RndRandom *default_backend;
};
#endif
--
1.8.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2)
2012-10-30 23:02 [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) Anthony Liguori
` (7 preceding siblings ...)
2012-10-30 23:02 ` [Qemu-devel] [PATCH 8/8] virtio-rng-pci: create a default backend if none exists Anthony Liguori
@ 2012-10-31 1:24 ` H. Peter Anvin
2012-10-31 2:12 ` Anthony Liguori
2012-10-31 7:12 ` Aurelien Jarno
8 siblings, 2 replies; 13+ messages in thread
From: H. Peter Anvin @ 2012-10-31 1:24 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Amit Shah, Paolo Bonzini, qemu-devel, Andreas Faerber
On 10/30/2012 04:02 PM, Anthony Liguori wrote:
>
> My take away from all of the various discussions on what the Right Way to
> use virtio-rng is:
>
> 1) /dev/random should always be used as the entropy source (I've left it
> configurable though)
>
> 2) I think the Right Way to configure virtio-rng is to figure out what the
> available entropy is on the host, and then decide how to allocate that
> to each guest. As such, I've implemented rate limiting.
>
> I think QEMU is the right place to do this because this is a property of
> specific virtual machines. I can imagine a cloud provider wanting to
> guarantee a certain level of entropy for different classes of VMs. Even
> if rngd could be used to do this, configuring it differently for different
> guests would be cumbersome.
>
rngd is not where this should happen, it should be in the /dev/random
implementation in the (host) kernel. That way it is applicable to all
types of clients, not just Qemu.
> 3) `qemu -device virtio-rng-pci` will Just Work but risks exhausting host
> entropy. This means we can't make it the default for machines. But for
> most command line users, I think this is the behavior they want.
It's a bit unfortunate, but I'm not going to push on that point.
Given the migration issue I'll write up an implementation of a DRNG
(RDRAND/RDSEED) backend once this is upstream. If RDRAND is disabled in
the guest, but available in the host, this would be the one to use. If
RDRAND is available in the guest it should be used directly if rngd is
new enough, but since virtio-rng has been in the kernel since 2008 there
still might be some guests which could use such an implementation
without having been RDRAND-enabled.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2)
2012-10-31 1:24 ` [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) H. Peter Anvin
@ 2012-10-31 2:12 ` Anthony Liguori
2012-10-31 7:12 ` Aurelien Jarno
1 sibling, 0 replies; 13+ messages in thread
From: Anthony Liguori @ 2012-10-31 2:12 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Amit Shah, Paolo Bonzini, qemu-devel, Andreas Faerber
"H. Peter Anvin" <hpa@zytor.com> writes:
> On 10/30/2012 04:02 PM, Anthony Liguori wrote:
>>
>> My take away from all of the various discussions on what the Right Way to
>> use virtio-rng is:
>>
>> 1) /dev/random should always be used as the entropy source (I've left it
>> configurable though)
>>
>> 2) I think the Right Way to configure virtio-rng is to figure out what the
>> available entropy is on the host, and then decide how to allocate that
>> to each guest. As such, I've implemented rate limiting.
>>
>> I think QEMU is the right place to do this because this is a property of
>> specific virtual machines. I can imagine a cloud provider wanting to
>> guarantee a certain level of entropy for different classes of VMs. Even
>> if rngd could be used to do this, configuring it differently for different
>> guests would be cumbersome.
>>
>
> rngd is not where this should happen, it should be in the /dev/random
> implementation in the (host) kernel. That way it is applicable to all
> types of clients, not just Qemu.
Even so, we still should do rate limiting in QEMU.
If you had a way to do this in the kernel (say, through cgroups), then
this limits both QEMU and the guest. QEMU does do some encryption for
things like TLS with VNC. This shouldn't affect the amount of entropy
available for the guest though.
So I can certainly understanding setting a limit on the QEMU process
beyond having QEMU limit how much entropy the guest receives. The two
mechanisms are complimentary.
>
>> 3) `qemu -device virtio-rng-pci` will Just Work but risks exhausting host
>> entropy. This means we can't make it the default for machines. But for
>> most command line users, I think this is the behavior they want.
>
> It's a bit unfortunate, but I'm not going to push on that point.
>
> Given the migration issue I'll write up an implementation of a DRNG
> (RDRAND/RDSEED) backend once this is upstream. If RDRAND is disabled in
> the guest, but available in the host, this would be the one to use. If
> RDRAND is available in the guest it should be used directly if rngd is
> new enough, but since virtio-rng has been in the kernel since 2008 there
> still might be some guests which could use such an implementation
> without having been RDRAND-enabled.
Sounds like a good idea.
Regards,
Anthony Liguori
>
> -hpa
>
>
> --
> H. Peter Anvin, Intel Open Source Technology Center
> I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2)
2012-10-31 1:24 ` [Qemu-devel] [PATCH 0/8] add paravirtualization hwrng support (v2) H. Peter Anvin
2012-10-31 2:12 ` Anthony Liguori
@ 2012-10-31 7:12 ` Aurelien Jarno
1 sibling, 0 replies; 13+ messages in thread
From: Aurelien Jarno @ 2012-10-31 7:12 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Amit Shah, Paolo Bonzini, Anthony Liguori, qemu-devel,
Andreas Faerber
On Tue, Oct 30, 2012 at 06:24:27PM -0700, H. Peter Anvin wrote:
> On 10/30/2012 04:02 PM, Anthony Liguori wrote:
> >
> >My take away from all of the various discussions on what the Right Way to
> >use virtio-rng is:
> >
> > 1) /dev/random should always be used as the entropy source (I've left it
> > configurable though)
> >
> > 2) I think the Right Way to configure virtio-rng is to figure out what the
> > available entropy is on the host, and then decide how to allocate that
> > to each guest. As such, I've implemented rate limiting.
> >
> > I think QEMU is the right place to do this because this is a property of
> > specific virtual machines. I can imagine a cloud provider wanting to
> > guarantee a certain level of entropy for different classes of VMs. Even
> > if rngd could be used to do this, configuring it differently for different
> > guests would be cumbersome.
> >
>
> rngd is not where this should happen, it should be in the
> /dev/random implementation in the (host) kernel. That way it is
> applicable to all types of clients, not just Qemu.
>
> > 3) `qemu -device virtio-rng-pci` will Just Work but risks exhausting host
> > entropy. This means we can't make it the default for machines. But for
> > most command line users, I think this is the behavior they want.
>
> It's a bit unfortunate, but I'm not going to push on that point.
>
> Given the migration issue I'll write up an implementation of a DRNG
> (RDRAND/RDSEED) backend once this is upstream. If RDRAND is
> disabled in the guest, but available in the host, this would be the
> one to use. If RDRAND is available in the guest it should be used
> directly if rngd is new enough, but since virtio-rng has been in the
> kernel since 2008 there still might be some guests which could use
> such an implementation without having been RDRAND-enabled.
>
That is also a good idea for emulation, and especially to provide
non-x86 guests with entropy.
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 13+ messages in thread