* [Qemu-devel] [PATCH] Virtio RNG and socket reconnect patchset @ 2009-12-17 16:44 Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations Ian Molton 0 siblings, 1 reply; 6+ messages in thread From: Ian Molton @ 2009-12-17 16:44 UTC (permalink / raw) To: qemu-devel Reposting for inclusion into qemu for the next release (hopefully) I've rebased against master and rediffed. Since we've missed 0.12 I've reordered the patches so that virtio-rng depends on the socket reconnect patches, and has the matching functionality thats needed to handle reconnect events. The kernel side changes required by virtio-rng were merged into mainline 8 days ago. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations 2009-12-17 16:44 [Qemu-devel] [PATCH] Virtio RNG and socket reconnect patchset Ian Molton @ 2009-12-17 16:44 ` Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 2/4] socket: Add a reconnect option Ian Molton [not found] ` <4B37DFDF.6000902@collabora.co.uk> 0 siblings, 2 replies; 6+ messages in thread From: Ian Molton @ 2009-12-17 16:44 UTC (permalink / raw) To: qemu-devel; +Cc: Ian Molton This patch rationalises the declaration of inet_listen_opts such that it matches the other inet_{listen,connect}_opts functions. This change is needed for a patch adding socket reconection support. Signed-off-by: Ian Molton <ian.molton@collabora.co.uk> --- qemu-sockets.c | 9 +++++++-- qemu_socket.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/qemu-sockets.c b/qemu-sockets.c index 8850516..ea338de 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -116,7 +116,7 @@ static void inet_print_addrinfo(const char *tag, struct addrinfo *res) } } -int inet_listen_opts(QemuOpts *opts, int port_offset) +static int do_inet_listen(QemuOpts *opts, int port_offset) { struct addrinfo ai,*res,*e; const char *addr; @@ -216,6 +216,11 @@ listen: return slisten; } +int inet_listen_opts(QemuOpts *opts) +{ + return do_inet_listen(opts, 0); +} + int inet_connect_opts(QemuOpts *opts) { struct addrinfo ai,*res,*e; @@ -465,7 +470,7 @@ int inet_listen(const char *str, char *ostr, int olen, opts = qemu_opts_create(&dummy_opts, NULL, 0); if (inet_parse(opts, str) == 0) { - sock = inet_listen_opts(opts, port_offset); + sock = do_inet_listen(opts, port_offset); if (sock != -1 && ostr) { optstr = strchr(str, ','); if (qemu_opt_get_bool(opts, "ipv6", 0)) { diff --git a/qemu_socket.h b/qemu_socket.h index 86bdbf5..fd8b95b 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -38,7 +38,7 @@ void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ -int inet_listen_opts(QemuOpts *opts, int port_offset); +int inet_listen_opts(QemuOpts *opts); int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset); int inet_connect_opts(QemuOpts *opts); -- 1.6.5.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 2/4] socket: Add a reconnect option. 2009-12-17 16:44 ` [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations Ian Molton @ 2009-12-17 16:44 ` Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 3/4] Add SIZE type to qdev properties Ian Molton [not found] ` <4B37DFDF.6000902@collabora.co.uk> 1 sibling, 1 reply; 6+ messages in thread From: Ian Molton @ 2009-12-17 16:44 UTC (permalink / raw) To: qemu-devel; +Cc: Ian Molton Add a reconnect option that allows sockets to reconnect (after a specified delay) to the specified server. This makes the virtio-rng driver useful in production environments where the EGD server may need to be restarted. Signed-off-by: Ian Molton <ian.molton@collabora.co.uk> --- qemu-char.c | 159 +++++++++++++++++++++++++++++++++++++++++++-------------- qemu-char.h | 2 + qemu-config.c | 3 + vl.c | 4 ++ 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index b13f8d4..fabc96b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1871,8 +1871,12 @@ typedef struct { int max_size; int do_telnetopt; int do_nodelay; + int reconnect; int is_unix; int msgfd; + QemuOpts *opts; + CharDriverState *chr; + int (*setup)(QemuOpts *opts); } TCPCharDriver; static void tcp_chr_accept(void *opaque); @@ -2012,6 +2016,8 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) } #endif +static void qemu_chr_sched_reconnect(TCPCharDriver *s); + static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; @@ -2031,10 +2037,16 @@ static void tcp_chr_read(void *opaque) if (s->listen_fd >= 0) { qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); } - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + if (!s->reconnect) { + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + } closesocket(s->fd); s->fd = -1; - qemu_chr_event(chr, CHR_EVENT_CLOSED); + if (s->reconnect) { + qemu_chr_sched_reconnect(s); + } else { + qemu_chr_event(chr, CHR_EVENT_CLOSED); + } } else if (size > 0) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); @@ -2134,11 +2146,92 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } +static int qemu_chr_connect_socket(TCPCharDriver *s) +{ + QemuOpts *opts = s->opts; + int is_listen; + int fd; + int is_waitconnect; + int do_nodelay; + + is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); + is_listen = qemu_opt_get_bool(opts, "server", 0); + do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); + + + fd = s->setup(s->opts); + if (fd < 0) + return 0; + + if (!is_waitconnect) + socket_set_nonblock(fd); + + if (is_listen) { + s->listen_fd = fd; + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, s->chr); + if (is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", + s->chr->filename); + tcp_chr_accept(s->chr); + socket_set_nonblock(s->listen_fd); + } + } else { + s->fd = fd; + socket_set_nodelay(fd); + tcp_chr_connect(s->chr); + } + + return 1; +} + +static QLIST_HEAD(reconnect_list_head, reconnect_list_entry) rcl_head; + +typedef struct reconnect_list_entry { + TCPCharDriver *s; + uint64_t when; + QLIST_ENTRY(reconnect_list_entry) entries; +} reconnect_list_entry; + +static void qemu_chr_sched_reconnect(TCPCharDriver *s) +{ + reconnect_list_entry *new = qemu_malloc(sizeof(*new)); + struct timeval tv; + + qemu_gettimeofday(&tv); + new->s = s; + new->when = (s->reconnect + tv.tv_sec) * 1000000 + tv.tv_usec; + QLIST_INSERT_HEAD(&rcl_head, new, entries); +} + +void qemu_chr_reconnect(void) +{ + struct timeval tv; + uint64_t now; + reconnect_list_entry *np; + + if (!rcl_head.lh_first) + return; + + gettimeofday(&tv, NULL); + now = tv.tv_sec * 1000000 + tv.tv_usec; + + for (np = rcl_head.lh_first; np != NULL; np = np->entries.le_next) { + if (np->when <= now) { + if (qemu_chr_connect_socket(np->s)) { + qemu_chr_event(np->s->chr, CHR_EVENT_RECONNECTED); + QLIST_REMOVE(np, entries); + } + else { + np->when += np->s->reconnect * 1000000; + } + } + } +} + static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; - int fd = -1; int is_listen; int is_waitconnect; int do_nodelay; @@ -2146,34 +2239,40 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) int is_telnet; is_listen = qemu_opt_get_bool(opts, "server", 0); + is_unix = qemu_opt_get(opts, "path") != NULL; + is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); is_telnet = qemu_opt_get_bool(opts, "telnet", 0); do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); - is_unix = qemu_opt_get(opts, "path") != NULL; - if (!is_listen) + + if (!is_listen) { is_waitconnect = 0; + } else { + if (is_telnet) + s->do_telnetopt = 1; + } + - chr = qemu_mallocz(sizeof(CharDriverState)); s = qemu_mallocz(sizeof(TCPCharDriver)); + chr = qemu_mallocz(sizeof(CharDriverState)); + s->opts = opts; + + if (!is_listen && !is_telnet) + s->reconnect = qemu_opt_get_number(opts, "reconnect", 0); if (is_unix) { if (is_listen) { - fd = unix_listen_opts(opts); + s->setup = unix_listen_opts; } else { - fd = unix_connect_opts(opts); + s->setup = unix_connect_opts; } } else { if (is_listen) { - fd = inet_listen_opts(opts, 0); + s->setup = inet_listen_opts; } else { - fd = inet_connect_opts(opts); + s->setup = inet_connect_opts; } } - if (fd < 0) - goto fail; - - if (!is_waitconnect) - socket_set_nonblock(fd); s->connected = 0; s->fd = -1; @@ -2187,19 +2286,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) chr->chr_close = tcp_chr_close; chr->get_msgfd = tcp_get_msgfd; - if (is_listen) { - s->listen_fd = fd; - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); - if (is_telnet) - s->do_telnetopt = 1; - - } else { - s->connected = 1; - s->fd = fd; - socket_set_nodelay(fd); - tcp_chr_connect(chr); - } - /* for "info chardev" monitor command */ chr->filename = qemu_malloc(256); if (is_unix) { @@ -2216,19 +2302,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); } - if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", - chr->filename); - tcp_chr_accept(chr); - socket_set_nonblock(s->listen_fd); - } - return chr; + s->chr = chr; + + if(qemu_chr_connect_socket(s)) + return chr; - fail: - if (fd >= 0) - closesocket(fd); - qemu_free(s); qemu_free(chr); + qemu_free(s); + return NULL; } diff --git a/qemu-char.h b/qemu-char.h index bcc0766..32bcfd7 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -15,6 +15,7 @@ #define CHR_EVENT_MUX_IN 3 /* mux-focus was set to this terminal */ #define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */ #define CHR_EVENT_CLOSED 5 /* connection closed */ +#define CHR_EVENT_RECONNECTED 6 /* reconnect event */ #define CHR_IOCTL_SERIAL_SET_PARAMS 1 @@ -75,6 +76,7 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); void qemu_chr_close(CharDriverState *chr); +void qemu_chr_reconnect(void); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); diff --git a/qemu-config.c b/qemu-config.c index c3203c8..a229350 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -144,6 +144,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "signal", .type = QEMU_OPT_BOOL, + },{ + .name = "reconnect", + .type = QEMU_OPT_NUMBER, }, { /* end if list */ } }, diff --git a/vl.c b/vl.c index c0d98f5..fa8d2ae 100644 --- a/vl.c +++ b/vl.c @@ -3917,6 +3917,10 @@ void main_loop_wait(int timeout) host_main_loop_wait(&timeout); + /* Reconnect any disconnected sockets, if necessary */ + + qemu_chr_reconnect(); + /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1; -- 1.6.5.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 3/4] Add SIZE type to qdev properties 2009-12-17 16:44 ` [Qemu-devel] [PATCH 2/4] socket: Add a reconnect option Ian Molton @ 2009-12-17 16:44 ` Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 4/4] virtio: Add virtio-rng driver Ian Molton 0 siblings, 1 reply; 6+ messages in thread From: Ian Molton @ 2009-12-17 16:44 UTC (permalink / raw) To: qemu-devel; +Cc: Ian Molton This patch adds a 'SIZE' type property to those available to qdevs. It is the analogue of the OPT_SIZE property for options. Signed-off-by: Ian Molton <ian.molton@collabora.co.uk> --- hw/qdev-properties.c | 34 ++++++++++++++++++++++++++++++++++ hw/qdev.h | 4 ++++ parse_common.h | 40 ++++++++++++++++++++++++++++++++++++++++ qemu-option.c | 23 +++-------------------- 4 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 parse_common.h diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index fb07279..44d14ef 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -1,6 +1,7 @@ #include "sysemu.h" #include "net.h" #include "qdev.h" +#include "parse_common.h" void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { @@ -194,6 +195,39 @@ PropertyInfo qdev_prop_hex64 = { .print = print_hex64, }; +/* --- 64bit unsigned int 'size' type --- */ + +static int parse_size(DeviceState *dev, Property *prop, const char *str) +{ + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + + if(str != NULL) + return parse_common_size(str, ptr); + + return -1; +} + +static int print_size(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); + char suffixes[] = {'T', 'G', 'M', 'K', 'B'}; + int i; + uint64_t div; + + for(div = (long int)1 << 40 ; + !(*ptr / div) ; div >>= 10, i++); + + return snprintf(dest, len, "%0.03f%c", (double)*ptr/div, suffixes[i]); +} + +PropertyInfo qdev_prop_size = { + .name = "size", + .type = PROP_TYPE_SIZE, + .size = sizeof(uint64_t), + .parse = parse_size, + .print = print_size, +}; + /* --- string --- */ static int parse_string(DeviceState *dev, Property *prop, const char *str) diff --git a/hw/qdev.h b/hw/qdev.h index bbcdba1..0f985f5 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -74,6 +74,7 @@ enum PropertyType { PROP_TYPE_UINT32, PROP_TYPE_INT32, PROP_TYPE_UINT64, + PROP_TYPE_SIZE, PROP_TYPE_TADDR, PROP_TYPE_MACADDR, PROP_TYPE_DRIVE, @@ -180,6 +181,7 @@ extern PropertyInfo qdev_prop_int32; extern PropertyInfo qdev_prop_uint64; extern PropertyInfo qdev_prop_hex32; extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_size; extern PropertyInfo qdev_prop_string; extern PropertyInfo qdev_prop_chr; extern PropertyInfo qdev_prop_ptr; @@ -217,6 +219,8 @@ extern PropertyInfo qdev_prop_pci_devfn; DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) #define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_SIZE(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_size, uint64_t) #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, uint32_t) diff --git a/parse_common.h b/parse_common.h new file mode 100644 index 0000000..93b1fc2 --- /dev/null +++ b/parse_common.h @@ -0,0 +1,40 @@ +/* + * Common parsing routines + * + * Copyright Collabora 2009 + * + * Author: + * Ian Molton <ian.molton@collabora.co.uk> + * + * Derived from the parser in qemu-option.c + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +static inline int parse_common_size(const char *value, uint64_t *ptr) { + char *postfix; + double sizef; + + sizef = strtod(value, &postfix); + switch (*postfix) { + case 'T': + sizef *= 1024; + case 'G': + sizef *= 1024; + case 'M': + sizef *= 1024; + case 'K': + case 'k': + sizef *= 1024; + case 'B': + case 'b': + case '\0': + *ptr = (uint64_t) sizef; + return 0; + } + + return -1; +} + diff --git a/qemu-option.c b/qemu-option.c index 24392fc..91772c5 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -28,6 +28,7 @@ #include "qemu-common.h" #include "qemu-option.h" +#include "parse_common.h" /* * Extracts the name of an option from the parameter string (p points at the @@ -203,28 +204,10 @@ static int parse_option_number(const char *name, const char *value, uint64_t *re static int parse_option_size(const char *name, const char *value, uint64_t *ret) { - char *postfix; - double sizef; - if (value != NULL) { - sizef = strtod(value, &postfix); - switch (*postfix) { - case 'T': - sizef *= 1024; - case 'G': - sizef *= 1024; - case 'M': - sizef *= 1024; - case 'K': - case 'k': - sizef *= 1024; - case 'b': - case '\0': - *ret = (uint64_t) sizef; - break; - default: + if(parse_common_size(value, ret) == -1) { fprintf(stderr, "Option '%s' needs size as parameter\n", name); - fprintf(stderr, "You may use k, M, G or T suffixes for " + fprintf(stderr, "You may use B, K, M, G or T suffixes for bytes " "kilobytes, megabytes, gigabytes and terabytes.\n"); return -1; } -- 1.6.5.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 4/4] virtio: Add virtio-rng driver 2009-12-17 16:44 ` [Qemu-devel] [PATCH 3/4] Add SIZE type to qdev properties Ian Molton @ 2009-12-17 16:44 ` Ian Molton 0 siblings, 0 replies; 6+ messages in thread From: Ian Molton @ 2009-12-17 16:44 UTC (permalink / raw) To: qemu-devel; +Cc: Ian Molton This patch adds support for virtio-rng. Data is read from a chardev and can be either raw entropy or received via the EGD protocol. Signed-off-by: Ian Molton <ian.molton@collabora.co.uk> --- Makefile.target | 2 +- hw/pci.h | 1 + hw/virtio-pci.c | 27 +++++++ hw/virtio-rng.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio-rng.h | 19 +++++ hw/virtio.h | 2 + rng.h | 18 +++++ 7 files changed, 270 insertions(+), 1 deletions(-) create mode 100644 hw/virtio-rng.c create mode 100644 hw/virtio-rng.h create mode 100644 rng.h diff --git a/Makefile.target b/Makefile.target index 7c1f30c..89f5b42 100644 --- a/Makefile.target +++ b/Makefile.target @@ -156,7 +156,7 @@ ifdef CONFIG_SOFTMMU obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly -obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o +obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o virtio-rng.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_ISA_MMIO) += isa_mmio.o LIBS+=-lz diff --git a/hw/pci.h b/hw/pci.h index d279e3f..98fc82c 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -70,6 +70,7 @@ extern target_phys_addr_t pci_mem_base; #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1004 typedef uint64_t pcibus_t; #define FMT_PCIBUS PRIx64 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 4500130..b4261e8 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -20,6 +20,7 @@ #include "sysemu.h" #include "msix.h" #include "net.h" +#include "rng.h" #include "loader.h" /* from Linux's linux/virtio_pci.h */ @@ -92,6 +93,7 @@ typedef struct { uint32_t nvectors; DriveInfo *dinfo; NICConf nic; + RNGConf rng; } VirtIOPCIProxy; /* virtio device */ @@ -551,6 +553,21 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev) return 0; } +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); + virtio_init_pci(proxy, vdev, + PCI_VENDOR_ID_REDHAT_QUMRANET, + PCI_DEVICE_ID_VIRTIO_RNG, + PCI_CLASS_OTHERS, + 0x00); + + return 0; +} + static PCIDeviceInfo virtio_info[] = { { .qdev.name = "virtio-blk-pci", @@ -592,6 +609,16 @@ static PCIDeviceInfo virtio_info[] = { .exit = virtio_exit_pci, .qdev.reset = virtio_pci_reset, },{ + .qdev.name = "virtio-rng-pci", + .qdev.size = sizeof(VirtIOPCIProxy), + .init = virtio_rng_init_pci, + .exit = virtio_exit_pci, + .qdev.props = (Property[]) { + DEFINE_RNG_PROPERTIES(VirtIOPCIProxy, rng), + DEFINE_PROP_END_OF_LIST(), + }, + .qdev.reset = virtio_pci_reset, + },{ /* end of list */ } }; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c new file mode 100644 index 0000000..39d0833 --- /dev/null +++ b/hw/virtio-rng.c @@ -0,0 +1,202 @@ +/* + * Virtio RNG Device + * + * Copyright Collabora 2009 + * + * Authors: + * Ian Molton <ian.molton@collabora.co.uk> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "hw.h" +#include "qemu-char.h" +#include "virtio.h" +#include "virtio-rng.h" +#include "rng.h" +#include <sys/time.h> + +typedef struct VirtIORng +{ + VirtIODevice vdev; + VirtQueue *vq; + CharDriverState *chr; + struct timeval last; + int rate; + int egd; + int entropy_remaining; + int pool; +} VirtIORng; + +/* Maximum size of the buffer the guest expects */ +#define BUFF_MAX 64 + +/* EGD protocol - we only use this command */ +#define EGD_READ_BLOCK 0x2 + +#define EGD_MAX_BLOCK_SIZE 255 +#define EGD_MAX_REQUESTS 3 +#define EGD_MAX_POOL_SIZE (EGD_MAX_BLOCK_SIZE * (EGD_MAX_REQUESTS-1)) + +static inline void req_entropy(VirtIORng *s) { + static const unsigned char entropy_rq[2] = { EGD_READ_BLOCK, + EGD_MAX_BLOCK_SIZE }; + if (s->egd) { + /* Let the socket buffer up the incoming data for us. Max block size + for EGD protocol is (stupidly) 255, so make sure we always have a + block pending for performance. We can have 3 outstanding buffers */ + if (s->pool <= EGD_MAX_POOL_SIZE) { + s->chr->chr_write(s->chr, entropy_rq, sizeof(entropy_rq)); + s->pool += EGD_MAX_BLOCK_SIZE; + } + } else { + s->pool = BUFF_MAX; + } +} + +static int vrng_can_read(void *opaque) +{ + VirtIORng *s = (VirtIORng *) opaque; + struct timeval now, d; + int max_entropy; + + if (!virtio_queue_ready(s->vq) || + !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) || + virtio_queue_empty(s->vq)) + return 0; + + req_entropy(s); + + if (s->rate) { + gettimeofday(&now, NULL); + timersub(&now, &s->last, &d); + if (d.tv_sec * 1000000 + d.tv_usec > 1000000) { + s->entropy_remaining = s->rate; + s->last = now; + } + max_entropy = MIN(s->pool, s->entropy_remaining); + } else { + max_entropy = s->pool; + } + + /* current implementations have a 64 byte buffer. + * We fall back to a one byte per read if there is not enough room. + */ + max_entropy = MIN(max_entropy, BUFF_MAX); + if (max_entropy) { + if (virtqueue_avail_bytes(s->vq, max_entropy, 0)) + return max_entropy; + if (virtqueue_avail_bytes(s->vq, 1, 0)) + return 1; + } + return 0; +} + +static void vrng_read(void *opaque, const uint8_t *buf, int size) +{ + VirtIORng *s = (VirtIORng *) opaque; + VirtQueueElement elem; + int offset = 0; + + /* The current kernel implementation has only one outstanding input + * buffer of 64 bytes. + */ + while (offset < size) { + int i = 0; + if (!virtqueue_pop(s->vq, &elem)) + break; + while (offset < size && i < elem.in_num) { + int len = MIN(elem.in_sg[i].iov_len, size - offset); + memcpy(elem.in_sg[i].iov_base, buf + offset, len); + offset += len; + i++; + } + virtqueue_push(s->vq, &elem, size); + } + + if (s->rate) + s->entropy_remaining -= size; + s->pool -= size; + + virtio_notify(&s->vdev, s->vq); +} + +static void vrng_event(void *opaque, int event) +{ + VirtIORng *s = opaque; + + /* + * If our connection has been interrupted we need to kick the entropy + * gathering process if we are using EGD. + */ + + if(s->egd && event == CHR_EVENT_RECONNECTED) + s->pool = 0; +} + + + +static void virtio_rng_handle(VirtIODevice *vdev, VirtQueue *vq) +{ + /* Nothing to do - we push data when its available */ +} + +static uint32_t virtio_rng_get_features(VirtIODevice *vdev) +{ + return 0; +} + +static void virtio_rng_save(QEMUFile *f, void *opaque) +{ + VirtIORng *s = opaque; + + virtio_save(&s->vdev, f); +} + +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIORng *s = opaque; + + if (version_id != 1) + return -EINVAL; + + virtio_load(&s->vdev, f); + return 0; +} + +VirtIODevice *virtio_rng_init(DeviceState *dev, RNGConf *rngdev) +{ + VirtIORng *s; + s = (VirtIORng *)virtio_common_init("virtio-rng", + VIRTIO_ID_RNG, + 0, sizeof(VirtIORng)); + + if (!s) + return NULL; + + s->vdev.get_features = virtio_rng_get_features; + + s->vq = virtio_add_queue(&s->vdev, 128, virtio_rng_handle); + s->chr = rngdev->chrdev; + s->rate = rngdev->rate; + gettimeofday(&s->last, NULL); + + if(rngdev->proto && !strncmp(rngdev->proto, "egd", 3)) + s->egd = 1; + +#ifdef DEBUG + printf("entropy being read from %s", rngdev->chrdev->label); + if(s->rate) + printf(" at %d bytes/sec max.", s->rate); + printf(" protocol: %s\n", s->egd?"egd":"raw"); +#endif + + qemu_chr_add_handlers(s->chr, vrng_can_read, vrng_read, vrng_event, s); + + register_savevm("virtio-rng", -1, 1, virtio_rng_save, virtio_rng_load, s); + + return &s->vdev; +} + diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h new file mode 100644 index 0000000..bc4d2d8 --- /dev/null +++ b/hw/virtio-rng.h @@ -0,0 +1,19 @@ +/* + * Virtio RNG Support + * + * Copyright Collabora 2009 + * + * Authors: + * Ian Molton <ian.molton@collabora.co.uk> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#ifndef _QEMU_VIRTIO_RNG_H +#define _QEMU_VIRTIO_RNG_H + +/* The ID for virtio console */ +#define VIRTIO_ID_RNG 4 + +#endif diff --git a/hw/virtio.h b/hw/virtio.h index 35532a6..efdbb68 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -16,6 +16,7 @@ #include "hw.h" #include "net.h" +#include "rng.h" #include "qdev.h" #include "sysemu.h" @@ -173,6 +174,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo); VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf); VirtIODevice *virtio_console_init(DeviceState *dev); VirtIODevice *virtio_balloon_init(DeviceState *dev); +VirtIODevice *virtio_rng_init(DeviceState *dev, RNGConf *rngdev); void virtio_net_exit(VirtIODevice *vdev); diff --git a/rng.h b/rng.h new file mode 100644 index 0000000..faf6880 --- /dev/null +++ b/rng.h @@ -0,0 +1,18 @@ +#ifndef QEMU_RNG_H +#define QEMU_RNG_H + +#include "qemu-option.h" + +/* qdev rng properties */ + +typedef struct RNGConf { + CharDriverState *chrdev; + uint64_t rate; + char *proto; +} RNGConf; + +#define DEFINE_RNG_PROPERTIES(_state, _conf) \ + DEFINE_PROP_CHR("chardev", _state, _conf.chrdev), \ + DEFINE_PROP_SIZE("rate", _state, _conf.rate, 0), \ + DEFINE_PROP_STRING("protocol", _state, _conf.proto) +#endif -- 1.6.5.4 ^ permalink raw reply related [flat|nested] 6+ messages in thread
[parent not found: <4B37DFDF.6000902@collabora.co.uk>]
* Re: [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations [not found] ` <4B37DFDF.6000902@collabora.co.uk> @ 2010-01-04 20:53 ` Anthony Liguori 0 siblings, 0 replies; 6+ messages in thread From: Anthony Liguori @ 2010-01-04 20:53 UTC (permalink / raw) To: Ian Molton; +Cc: qemu-devel On 12/27/2009 04:29 PM, Ian Molton wrote: > Ian Molton wrote: > > Can I get the status of this patchset please ? I really dislike the idea of automatically reconnecting a socket. Mainly because I'm not sure that you can have sane universal semantics for what to do while it's disconnected. I would prefer a mechanism that allowed a user to manually reconnect a character device by basically reconnecting the full character device. IOW, reconnecting to tcp:localhost:1025 is the same thing as changing to unix:/tmp/foo.sock AFAICT. Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-01-05 19:58 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-12-17 16:44 [Qemu-devel] [PATCH] Virtio RNG and socket reconnect patchset Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 2/4] socket: Add a reconnect option Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 3/4] Add SIZE type to qdev properties Ian Molton 2009-12-17 16:44 ` [Qemu-devel] [PATCH 4/4] virtio: Add virtio-rng driver Ian Molton [not found] ` <4B37DFDF.6000902@collabora.co.uk> 2010-01-04 20:53 ` [Qemu-devel] [PATCH 1/4] socket: Rationalise function declarations Anthony Liguori
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).