* [Qemu-devel] [RFC 1/4] backend: multi-client-socket
2016-03-24 13:16 [Qemu-devel] [RFC 0/4] QEMU shared-memory over network Baptiste Reynal
@ 2016-03-24 13:16 ` Baptiste Reynal
2016-03-24 13:16 ` [Qemu-devel] [RFC 2/4] backend: shared memory over network backend Baptiste Reynal
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Baptiste Reynal @ 2016-03-24 13:16 UTC (permalink / raw)
To: qemu-devel; +Cc: pbonzini, Jani.Kokkonen, tech, Claudio.Fontana, b.reynal
This patch updates the multi-client-socket, adding the following
functionalities :
- both UNIX and network socket are now supported :
-object multi-socket-backend,id=<id>,path=<socket_path>,listen=<on/off>
-object multi-socket-backend,host=<host>,port=<port>,,listen=<on/off>
- the socket now uses NMMessage for communication. The old API is kept
for backward compatibility
- multi_socket_send_and_block_to function added, to send a message and
wait for the answer
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
---
backends/multi-socket.c | 420 ++++++++++++++++++++++++++++++--------------
include/qemu/multi-socket.h | 57 +++++-
2 files changed, 334 insertions(+), 143 deletions(-)
diff --git a/backends/multi-socket.c b/backends/multi-socket.c
index 2cfbb50..daf06b7 100644
--- a/backends/multi-socket.c
+++ b/backends/multi-socket.c
@@ -12,25 +12,128 @@
#include "qemu/multi-socket.h"
#include "qemu/error-report.h"
-typedef struct MSHandler MSHandler;
-typedef struct MSRegHandler MSRegHandler;
+void multi_socket_add_reg_handler(MSBackend *backend,
+ void (*reg)(MSClient *client, void *opaque),
+ void *opaque)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(backend);
-struct MSHandler {
- char *name;
- void (*read)(MSClient *client, const char *message, void *opaque);
- void *opaque;
+ if (msc->add_reg_handler) {
+ msc->add_reg_handler(backend, reg, opaque);
+ }
+}
- QLIST_ENTRY(MSHandler) next;
-};
+void multi_socket_add_handler(MSBackend *backend, const char *name,
+ void (*read)(MSClient *client, const char *message, void *opaque),
+ void *opaque)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(backend);
-struct MSRegHandler {
- void (*reg)(MSClient *client, void *opaque);
- void *opaque;
+ if (strlen(name) > MS_CMD_SIZE) {
+ error_report("Command \"%s\" size is too big.", name);
+ return;
+ }
- QLIST_ENTRY(MSRegHandler) next;
-};
+ if (msc->add_handler) {
+ msc->add_handler(backend, name, read, opaque);
+ }
+}
+
+int multi_socket_send_fds_to(MSClient *client, int *fds, int count,
+ const char *message, int size) {
+ int cmd_len, payload_len;
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+ MSMessage ms_message;
+
+ cmd_len = strlen(message) + 1;
+ payload_len = size - cmd_len;
+
+ if (cmd_len > MS_CMD_SIZE ||
+ payload_len > MS_PAYLOAD_SIZE) {
+ error_report("Command \"%s\" size is too big.", message);
+ }
+
+ memcpy(ms_message.cmd, message, cmd_len);
+ memcpy(ms_message.payload, message + cmd_len, payload_len);
+
+ if (msc->send_fds_to) {
+ return msc->send_fds_to(client, fds, count, &ms_message);
+ } else {
+ return -1;
+ }
+}
+
+int multi_socket_write_to(MSClient *client, const char *message, int size)
+{
+ int cmd_len, payload_len;
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+ MSMessage ms_message;
+
+ cmd_len = strlen(message) + 1;
+ payload_len = size - cmd_len;
+
+ msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+ if (cmd_len > MS_CMD_SIZE ||
+ payload_len > MS_PAYLOAD_SIZE) {
+ error_report("Command \"%s\" size is too big.", message);
+ }
+
+ memcpy(ms_message.cmd, message, cmd_len);
+ memcpy(ms_message.payload, message + cmd_len, payload_len);
+
+ if (msc->write_to) {
+ return msc->write_to(client, &ms_message);
+ } else {
+ return -1;
+ }
+}
+
+int multi_socket_write_message_to(MSClient *client, MSMessage *message)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+
+ if (msc->write_to) {
+ return msc->write_to(client, message);
+ } else {
+ return -1;
+ }
+}
+
+int multi_socket_get_fds_num_from(MSClient *client)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+
+ if (msc->get_fds_num_from) {
+ return msc->get_fds_num_from(client);
+ } else {
+ return -1;
+ }
+}
+
+int multi_socket_get_fds_from(MSClient *client, int *fds)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+
+ if (msc->get_fds_from) {
+ return msc->get_fds_from(client, fds);
+ } else {
+ return -1;
+ }
+}
+
+int multi_socket_write_and_block_to(MSClient *client, MSMessage *message)
+{
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_GET_CLASS(client->backend);
+
+ if (msc->write_and_block_to) {
+ return msc->write_and_block_to(client, message);
+ } else {
+ return -1;
+ }
+}
-static void multi_socket_get_fds(MSClient *client, struct msghdr msg)
+typedef struct MSHandler MSHandler;
+static void ms_get_fds(MSClient *client, struct msghdr msg)
{
struct cmsghdr *cmsg;
@@ -58,51 +161,7 @@ static void multi_socket_get_fds(MSClient *client, struct msghdr msg)
}
}
-static gboolean
-multi_socket_read_handler(GIOChannel *channel, GIOCondition cond, void *opaque)
-{
- MSClient *client = (MSClient *) opaque;
- MSBackend *backend = client->backend;
-
- char message[BUFFER_SIZE];
- struct MSHandler *h;
-
- struct msghdr msg = { NULL, };
- struct iovec iov[1];
- union {
- struct cmsghdr cmsg;
- char control[CMSG_SPACE(sizeof(int) * MAX_FDS)];
- } msg_control;
- int flags = 0;
- ssize_t ret;
-
- iov[0].iov_base = message;
- iov[0].iov_len = BUFFER_SIZE;
-
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- ret = recvmsg(client->fd, &msg, flags);
-
- if (ret > 0) {
- multi_socket_get_fds(client, msg);
-
- /* handler callback */
- QLIST_FOREACH(h, &backend->handlers, next) {
- if (!strncmp(h->name, message, strlen(h->name))) {
- h->read(client, message + strlen(h->name) + 1, h->opaque);
- return TRUE;
- }
- }
- error_report("Unrecognized message: %s", message);
- }
-
- return FALSE;
-}
-
-void multi_socket_add_reg_handler(MSBackend *backend,
+static void ms_add_reg_handler(MSBackend *backend,
void (*reg)(MSClient *client, void *opaque), void *opaque)
{
struct MSRegHandler *h;
@@ -115,44 +174,32 @@ void multi_socket_add_reg_handler(MSBackend *backend,
QLIST_INSERT_HEAD(&backend->reg_handlers, h, next);
}
-void multi_socket_add_handler(MSBackend *backend,
- const char *name,
- void (*read)(MSClient *c, const char *message, void *opaque),
+static void ms_add_handler(MSBackend *backend,
+ const char *cmd,
+ void (*read)(MSClient *client, const char *payload, void *opaque),
void *opaque)
{
- struct MSHandler *h;
+ struct MSHandler *handler;
- /* check that the handler name is not taken */
- QLIST_FOREACH(h, &backend->handlers, next) {
- if (!strcmp(h->name, name)) {
- error_report("Handler %s already exists", name);
- return;
+ /* check the command is available */
+ QLIST_FOREACH(handler, &backend->handlers, next) {
+ if (!strcmp(handler->cmd, cmd)) {
+ error_report("Handler %s already exists", cmd);
+ return;
}
}
- h = g_malloc(sizeof(struct MSHandler));
+ handler = g_malloc(sizeof(struct MSHandler));
- h->name = g_strdup(name);
- h->read = read;
- h->opaque = opaque;
+ handler->cmd = g_strdup(cmd);
+ handler->read = read;
+ handler->opaque = opaque;
- QLIST_INSERT_HEAD(&backend->handlers, h, next);
+ QLIST_INSERT_HEAD(&backend->handlers, handler, next);
}
-static void multi_socket_init_client(MSBackend *backend,
- MSClient *client, int fd, GIOFunc handler)
-{
- client->backend = backend;
- client->fd = fd;
- client->chan = g_io_channel_unix_new(fd);
- client->tag = g_io_add_watch(client->chan, G_IO_IN, handler, client);
-
- g_io_channel_set_encoding(client->chan, NULL, NULL);
- g_io_channel_set_buffered(client->chan, FALSE);
-}
-
-int multi_socket_send_fds_to(MSClient *client, int *fds, int count,
- const char *message, int size)
+static int ms_send_fds_to(MSClient *client, int *fds, int count,
+ MSMessage *message)
{
struct msghdr msgh;
struct iovec iov;
@@ -165,9 +212,8 @@ int multi_socket_send_fds_to(MSClient *client, int *fds, int count,
memset(&msgh, 0, sizeof(msgh));
memset(control, 0, sizeof(control));
- /* set the payload */
- iov.iov_base = (uint8_t *) message;
- iov.iov_len = size;
+ iov.iov_base = message;
+ iov.iov_len = sizeof(MSMessage);
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
@@ -189,38 +235,92 @@ int multi_socket_send_fds_to(MSClient *client, int *fds, int count,
return r;
}
-int multi_socket_write_to(MSClient *client, const char *message, int size)
+static int ms_write_to(MSClient *client, MSMessage *message)
{
- return multi_socket_send_fds_to(client, 0, 0, message, size);
+ return ms_send_fds_to(client, 0, 0, message);
}
-int multi_socket_get_fds_num_from(MSClient *client)
+static int ms_get_fds_num_from(MSClient *client)
{
return client->rcvfds_num;
}
-int multi_socket_get_fds_from(MSClient *client, int *fds)
+static int ms_get_fds_from(MSClient *client, int *fds)
{
memcpy(fds, client->rcvfds, client->rcvfds_num * sizeof(int));
+ return ms_get_fds_num_from(client);
+}
- return client->rcvfds_num;
+static gboolean
+ms_read(GIOChannel *channel, GIOCondition cond, void *opaque)
+{
+ MSClient *client = (MSClient *) opaque;
+ MSBackend *backend = client->backend;
+ MSMessage message;
+ MSHandler *handler;
+ int ret;
+
+ struct msghdr msg = { NULL };
+ struct iovec iov[1];
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(int) * MS_MAX_FDS)];
+ } msg_control;
+ int flags = MSG_WAITALL;
+
+ iov[0].iov_base = &message;
+ iov[0].iov_len = sizeof(MSMessage);
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+ ret = recvmsg(client->fd, &msg, flags);
+
+ if (ret > 0) {
+ ms_get_fds(client, msg);
+
+ /* handler callback */
+ QLIST_FOREACH(handler, &backend->handlers, next) {
+ if (!strcmp(handler->cmd, message.cmd)) {
+ handler->read(client, message.payload, handler->opaque);
+ return TRUE;
+ }
+ }
+
+ error_report("Unrecognized command: %s", message.cmd);
+ }
+
+ return FALSE;
}
-static void multi_socket_add_client(MSBackend *backend, int fd)
+static void multi_socket_init_client(MSBackend *backend, MSClient *client,
+ int fd, GIOFunc handler)
{
- MSClient *c = g_malloc(sizeof(MSClient));
- MSRegHandler *h;
+ client->backend = backend;
+ client->fd = fd;
+ client->chan = g_io_channel_unix_new(fd);
+ client->tag = g_io_add_watch(client->chan, G_IO_IN, handler, client);
- multi_socket_init_client(backend, c, fd, multi_socket_read_handler);
- QLIST_FOREACH(h, &backend->reg_handlers, next) {
- h->reg(c, h->opaque);
+ g_io_channel_set_encoding(client->chan, NULL, NULL);
+ g_io_channel_set_buffered(client->chan, FALSE);
+}
+
+static void ms_add_client(MSBackend *backend, int fd)
+{
+ MSClient *client = g_malloc(sizeof(MSClient));
+ MSRegHandler *handler;
+
+ multi_socket_init_client(backend, client, fd, ms_read);
+ QLIST_FOREACH(handler, &backend->reg_handlers, next) {
+ handler->reg(client, handler->opaque);
}
- QLIST_INSERT_HEAD(&backend->clients, c, next);
+ QLIST_INSERT_HEAD(&backend->clients, client, next);
}
-static gboolean
-multi_socket_accept(GIOChannel *channel, GIOCondition cond, void *opaque)
+static gboolean ms_accept(GIOChannel *channel, GIOCondition cond, void *opaque)
{
MSClient *client = (MSClient *) opaque;
MSBackend *backend = client->backend;
@@ -230,11 +330,10 @@ multi_socket_accept(GIOChannel *channel, GIOCondition cond, void *opaque)
int fd;
len = sizeof(uaddr);
-
fd = qemu_accept(backend->listener.fd, (struct sockaddr *) &uaddr, &len);
if (fd > 0) {
- multi_socket_add_client(backend, fd);
+ ms_add_client(backend, fd);
return true;
} else {
perror("Error creating socket.");
@@ -242,54 +341,73 @@ multi_socket_accept(GIOChannel *channel, GIOCondition cond, void *opaque)
}
}
-static void multi_socket_init_socket(MSBackend *backend)
+static int ms_write_and_block_to(MSClient *client, MSMessage *message)
{
- int fd;
+ int ret;
- backend->addr = g_new0(SocketAddress, 1);
- backend->addr->kind = SOCKET_ADDRESS_KIND_UNIX;
- backend->addr->q_unix = g_new0(UnixSocketAddress, 1);
- /* TODO change name with real path */
- backend->addr->q_unix->path = g_strdup(backend->path);
-
- if (backend->listen) {
- fd = socket_listen(backend->addr, NULL);
+ g_source_remove(client->tag);
- if (fd < 0) {
- perror("Error: Impossible to open socket.");
- exit(-1);
- }
-
- multi_socket_init_client(backend, &backend->listener, fd,
- multi_socket_accept);
- } else {
- fd = socket_connect(backend->addr, NULL, NULL, NULL);
+ ret = ms_write_to(client, message);
+ ms_read(client->chan, G_IO_IN, client);
- if (fd < 0) {
- perror("Error: Unavailable socket server.");
- exit(-1);
- }
+ g_io_add_watch(client->chan, G_IO_IN, ms_read, client);
- multi_socket_init_client(backend, &backend->listener,
- fd, multi_socket_read_handler);
- }
+ return ret;
}
static void multi_socket_backend_complete(UserCreatable *uc, Error **errp)
{
MSBackend *backend = MULTI_SOCKET_BACKEND(uc);
+ GIOFunc handler;
QLIST_INIT(&backend->clients);
+ QLIST_INIT(&backend->reg_handlers);
QLIST_INIT(&backend->handlers);
- multi_socket_init_socket(backend);
+ backend->addr = g_new0(SocketAddress, 1);
+
+ if (backend->path) {
+ backend->addr->kind = SOCKET_ADDRESS_KIND_UNIX;
+ backend->addr->q_unix = g_new0(UnixSocketAddress, 1);
+ backend->addr->q_unix->path = g_strdup(backend->path);
+ } else {
+ backend->addr->kind = SOCKET_ADDRESS_KIND_INET;
+ backend->addr->inet = g_new0(InetSocketAddress, 1);
+ backend->addr->inet->host = g_strdup(backend->host);
+ backend->addr->inet->port = g_strdup(backend->port);
+ }
+
+ if (backend->listen) {
+ backend->fd = socket_listen(backend->addr, NULL);
+ handler = ms_accept;
+ } else {
+ backend->fd = socket_connect(backend->addr, NULL, NULL, NULL);
+ handler = ms_read;
+ }
+
+ if (backend->fd < 0) {
+ perror("Error: Impossible to open socket.");
+ exit(-1);
+ }
+
+ multi_socket_init_client(backend, &backend->listener,
+ backend->fd, handler);
}
static void multi_socket_class_init(ObjectClass *oc, void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ MSBackendClass *msc = MULTI_SOCKET_BACKEND_CLASS(oc);
ucc->complete = multi_socket_backend_complete;
+
+ msc->add_reg_handler = ms_add_reg_handler;
+ msc->add_handler = ms_add_handler;
+ msc->write_to = ms_write_to;
+ msc->send_fds_to = ms_send_fds_to;
+ msc->get_fds_num_from = ms_get_fds_num_from;
+ msc->get_fds_from = ms_get_fds_from;
+ msc->write_and_block_to = ms_write_and_block_to;
}
static bool multi_socket_backend_get_listen(Object *o, Error **errp)
@@ -325,13 +443,45 @@ static void multi_socket_set_path(Object *o, const char *str, Error **errp)
backend->path = g_strdup(str);
}
+static char *multi_socket_get_host(Object *o, Error **errp)
+{
+ MSBackend *backend = MULTI_SOCKET_BACKEND(o);
+
+ return g_strdup(backend->host);
+}
+
+static void multi_socket_set_host(Object *o, const char *str, Error **errp)
+{
+ MSBackend *backend = MULTI_SOCKET_BACKEND(o);
+
+ backend->host = g_strdup(str);
+}
+
+static char *multi_socket_get_port(Object *o, Error **errp)
+{
+ MSBackend *backend = MULTI_SOCKET_BACKEND(o);
+
+ return g_strdup(backend->port);
+}
+
+static void multi_socket_set_port(Object *o, const char *str, Error **errp)
+{
+ MSBackend *backend = MULTI_SOCKET_BACKEND(o);
+
+ backend->port = g_strdup(str);
+}
+
static void multi_socket_instance_init(Object *o)
{
object_property_add_bool(o, "listen",
- multi_socket_backend_get_listen,
- multi_socket_backend_set_listen, NULL);
+ multi_socket_backend_get_listen,
+ multi_socket_backend_set_listen, NULL);
object_property_add_str(o, "path", multi_socket_get_path,
multi_socket_set_path, NULL);
+ object_property_add_str(o, "host", multi_socket_get_host,
+ multi_socket_set_host, NULL);
+ object_property_add_str(o, "port", multi_socket_get_port,
+ multi_socket_set_port, NULL);
}
static const TypeInfo multi_socket_backend_info = {
diff --git a/include/qemu/multi-socket.h b/include/qemu/multi-socket.h
index dee866a..8a43e8a 100644
--- a/include/qemu/multi-socket.h
+++ b/include/qemu/multi-socket.h
@@ -1,13 +1,14 @@
/*
- * QEMU Multi Client socket
+ * QEMU multi client socket
*
* Copyright (C) 2015 - Virtual Open Systems
*
* Author: Baptiste Reynal <b.reynal@virtualopensystems.com>
*
- * This work is licensed under the terms of the GNU GPL, version 2. See
+ * This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
+
#ifndef QEMU_MS_H
#define QEMU_MS_H
@@ -25,15 +26,23 @@
#define MULTI_SOCKET_BACKEND_CLASS(klass) \
OBJECT_CLASS_CHECK(MSBackendClass, (klass), TYPE_MULTI_SOCKET_BACKEND)
-#define MAX_FDS 32
-#define BUFFER_SIZE 32
+#define MS_CMD_SIZE 32
+#define MS_PAYLOAD_SIZE 256
+#define MS_MAX_FDS 32
typedef struct MSBackend MSBackend;
typedef struct MSBackendClass MSBackendClass;
typedef struct MSClient MSClient;
+typedef struct MSHandler MSHandler;
+typedef struct MSRegHandler MSRegHandler;
+typedef struct MSMessage MSMessage;
+
+struct MSMessage {
+ char cmd[MS_CMD_SIZE];
+ char payload[MS_PAYLOAD_SIZE];
+};
struct MSClient {
- /* private */
int fd;
MSBackend *backend;
GIOChannel *chan;
@@ -45,17 +54,46 @@ struct MSClient {
QLIST_ENTRY(MSClient) next;
};
+struct MSHandler {
+ char *cmd;
+ void (*read)(MSClient *client, const char *payload, void *opaque);
+ void *opaque;
+
+ QLIST_ENTRY(MSHandler) next;
+};
+
+struct MSRegHandler {
+ void (*reg)(MSClient *client, void *opaque);
+ void *opaque;
+
+ QLIST_ENTRY(MSRegHandler) next;
+};
+
struct MSBackendClass {
- /* private */
ObjectClass parent_class;
+
+ void (*add_reg_handler)(MSBackend *backend,
+ void (*reg)(MSClient *client, void *opaque),
+ void *opaque);
+ void (*add_handler)(MSBackend *backend, const char *cmd,
+ void (*read)(MSClient *client, const char *payload, void *opaque),
+ void *opaque);
+ int (*write_to)(MSClient *client, MSMessage *message);
+ int (*send_fds_to)(MSClient *client, int *fds, int count,
+ MSMessage *message);
+ int (*get_fds_num_from)(MSClient *client);
+ int (*get_fds_from)(MSClient *client, int *fds);
+ int (*write_and_block_to)(MSClient *client, MSMessage *message);
};
struct MSBackend {
- /* private */
Object parent;
- /* protected */
+ int fd;
+
char *path;
+ char *host;
+ char *port;
SocketAddress *addr;
QLIST_HEAD(clients_head, MSClient) clients;
@@ -107,6 +145,7 @@ int multi_socket_send_fds_to(MSClient *client, int *fds, int count,
* @size: size of the message
*/
int multi_socket_write_to(MSClient *client, const char *message, int size);
+int multi_socket_write_message_to(MSClient *client, MSMessage *message);
/* Get fds size received with the last message.
*
@@ -121,4 +160,6 @@ int multi_socket_get_fds_num_from(MSClient *client);
*/
int multi_socket_get_fds_from(MSClient *client, int *fds);
+int multi_socket_write_and_block_to(MSClient *client, MSMessage *message);
+
#endif
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC 2/4] backend: shared memory over network backend
2016-03-24 13:16 [Qemu-devel] [RFC 0/4] QEMU shared-memory over network Baptiste Reynal
2016-03-24 13:16 ` [Qemu-devel] [RFC 1/4] backend: multi-client-socket Baptiste Reynal
@ 2016-03-24 13:16 ` Baptiste Reynal
2016-03-24 13:16 ` [Qemu-devel] [RFC 3/4] migration: extend shared migration type Baptiste Reynal
2016-03-24 13:16 ` [Qemu-devel] [RFC 4/4] hw/misc: sdm signal nboot Baptiste Reynal
3 siblings, 0 replies; 5+ messages in thread
From: Baptiste Reynal @ 2016-03-24 13:16 UTC (permalink / raw)
To: qemu-devel; +Cc: pbonzini, Jani.Kokkonen, tech, Claudio.Fontana, b.reynal
This patch extends the shared memory backend with the capability to
share a memory region over the network.
On the master side, when a slave connects an mmio region is created and
each access is trapped and sent over the network through the multi-client
socket.
Instantiation on the master:
-object memory-backend-network,id=<id>,size=<memory_sizeK,M,G>,
socket=<socket>,shared_size=<shared_sizeK,M,G>,master
Instantiation on the slave:
-object memory-backend-network,id=<id>,size=<memory_sizeK,M,H>,
socket=<socket>
To allocate the memory, the master will start from (size - shared_size),
and search for an area of the slave size (round up to the power of 2).
It is meant to be coherent with the dma_alloc_coherent allocator.
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
---
backends/Makefile.objs | 2 +-
backends/hostmem-network.c | 301 +++++++++++++++++++++++++++++++++++++++
include/sysemu/hostmem-network.h | 79 ++++++++++
3 files changed, 381 insertions(+), 1 deletion(-)
create mode 100644 backends/hostmem-network.c
create mode 100644 include/sysemu/hostmem-network.h
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index de76906..b66c097 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -8,6 +8,6 @@ baum.o-cflags := $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += hostmem.o hostmem-ram.o
-common-obj-$(CONFIG_LINUX) += hostmem-file.o hostmem-shared.o
+common-obj-$(CONFIG_LINUX) += hostmem-file.o hostmem-shared.o hostmem-network.o
common-obj-y += multi-socket.o
diff --git a/backends/hostmem-network.c b/backends/hostmem-network.c
new file mode 100644
index 0000000..4317d63
--- /dev/null
+++ b/backends/hostmem-network.c
@@ -0,0 +1,301 @@
+/*
+ * QEMU Host Memory Backend over network
+ *
+ * Copyright (C) 2016 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <b.reynal@virtualopensystems.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "sysemu/hostmem-network.h"
+#include "migration/vmstate.h"
+#include "qapi-visit.h"
+
+static uint64_t socket_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+ NMArea *area = opaque;
+ MSMessage message;
+ NMData nm_data;
+
+ nm_data.addr = addr;
+ nm_data.size = size;
+
+ strcpy(message.cmd, MBN_READ_CMD);
+ memcpy(message.payload, &nm_data, sizeof(NMData));
+
+ multi_socket_write_and_block_to(area->client, &message);
+
+ return area->nhm->last_read.data;
+}
+
+static void
+socket_mmio_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+ NMArea *area = opaque;
+ MSMessage message;
+ NMData nm_data;
+
+ nm_data.addr = addr;
+ nm_data.data = data;
+ nm_data.size = size;
+
+ strcpy(message.cmd, MBN_WRITE_CMD);
+ memcpy(message.payload, &nm_data, sizeof(NMData));
+
+ multi_socket_write_message_to(area->client, &message);
+}
+
+static const MemoryRegionOps socket_mmio_ops = {
+ .read = socket_mmio_read,
+ .write = socket_mmio_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void
+network_memory_register(MSClient *c, const char *message, void *opaque)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+ HostMemoryBackendNetwork *nhm = MEMORY_BACKEND_NETWORK(opaque);
+ NMArea *area, *new_area;
+ int hw_size = 1, size = *(int *) message;
+
+ /* Search for available space */
+ while (hw_size < size) {
+ hw_size <<= 1;
+ }
+
+ QLIST_FOREACH(area, &nhm->areas, next) {
+ if (!area->client && area->size >= hw_size) {
+ if (area->size > hw_size) {
+ new_area = g_new(NMArea, 1);
+ new_area->size = area->size - hw_size;
+ new_area->addr = area->addr + hw_size;
+ new_area->client = NULL;
+ new_area->nhm = nhm;
+
+ QLIST_INSERT_AFTER(area, new_area, next);
+ }
+
+ area->size = hw_size;
+ area->client = c;
+
+ break;
+ }
+ }
+
+ memory_region_init_io(&area->region,
+ OBJECT(opaque),
+ &socket_mmio_ops,
+ area,
+ "socket_region",
+ size
+ );
+
+ memory_region_add_subregion(&backend->mr, area->addr, &area->region);
+}
+
+static void
+network_memory_read_cb(MSClient *c, const char *message, void *opaque)
+{
+ HostMemoryBackendNetwork *nhm = opaque;
+ NMData *data = (NMData *) message;
+
+ memcpy(&nhm->last_read, message, sizeof(NMData));
+}
+
+static void
+network_memory_read(MSClient *c, const char *message, void *opaque)
+{
+ MSMessage nm_message;
+ NMData *data = (NMData *) message;
+ HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+
+ memcpy(&data->data, memory_region_get_ram_ptr(&backend->mr) + data->addr,
+ data->size);
+
+ strcpy(nm_message.cmd, MBN_READ_CMD);
+ memcpy(nm_message.payload, data, sizeof(NMData));
+
+ multi_socket_write_message_to(c, &nm_message);
+}
+
+static void
+network_memory_write(MSClient *c, const char *message, void *opaque)
+{
+ NMData *data = (NMData *) message;
+ HostMemoryBackend *backend = MEMORY_BACKEND(opaque);
+
+ memcpy(memory_region_get_ram_ptr(&backend->mr) + data->addr, &data->data,
+ data->size);
+}
+
+static void
+network_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+ HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(backend);
+ MSMessage message;
+
+ if (!backend->size) {
+ error_setg(errp, "can't create backend with size 0");
+ return;
+ }
+
+ if (!memory_region_size(&backend->mr)) {
+ backend->force_prealloc = mem_prealloc;
+ memory_region_init_ram(&backend->mr,
+ OBJECT(backend),
+ object_get_canonical_path(OBJECT(backend)),
+ backend->size,
+ errp);
+
+ if (shm->master) {
+ multi_socket_add_handler(shm->ms, MBN_REGISTER_CMD,
+ network_memory_register, shm);
+ multi_socket_add_handler(shm->ms, MBN_READ_CMD,
+ network_memory_read_cb, shm);
+ } else {
+ multi_socket_add_handler(shm->ms, MBN_READ_CMD,
+ network_memory_read, shm);
+ multi_socket_add_handler(shm->ms, MBN_WRITE_CMD,
+ network_memory_write, shm);
+
+ strcpy(message.cmd, MBN_REGISTER_CMD);
+ memcpy(message.payload, &backend->size, sizeof(int));
+
+ multi_socket_write_message_to(&shm->ms->listener, &message);
+ }
+ }
+
+ shm->levent = g_new(EventNotifier, 1);
+ event_notifier_init(shm->levent, 0);
+
+ shm->event = event_notifier_get_fd(shm->levent);
+}
+
+
+static void
+network_memory_backend_complete(UserCreatable *uc, Error **errp)
+{
+ HostMemoryBackend *hm = MEMORY_BACKEND(uc);
+ HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(uc);
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
+ HostMemoryBackendNetworkClass *bnc = MEMORY_BACKEND_NETWORK_GET_CLASS(uc);
+
+ QLIST_INIT(&shm->areas);
+
+ NMArea *area = g_new(NMArea, 1);
+ area->size = shm->shared_size;
+ area->addr = hm->size - shm->shared_size;
+ area->client = NULL;
+ area->nhm = shm;
+
+ QLIST_INSERT_HEAD(&shm->areas, area, next);
+
+ if (shm->master) {
+ bnc->parent_complete(uc, errp);
+ } else {
+ bc->alloc(hm, errp);
+ }
+}
+
+static void ms_boot(HostMemoryBackendNetwork *nhm)
+{
+ event_notifier_set(nhm->levent);
+}
+
+static void network_backend_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+ HostMemoryBackendNetworkClass *bnc = MEMORY_BACKEND_NETWORK_CLASS(oc);
+
+ bc->alloc = network_backend_memory_alloc;
+ bnc->parent_complete = ucc->complete;
+ bnc->boot = ms_boot;
+ ucc->complete = network_memory_backend_complete;
+}
+
+static bool get_master(Object *o, Error **errp)
+{
+ HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+ return shm->master;
+}
+
+static void set_master(Object *o, bool value, Error **errp)
+{
+ HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+ shm->master = value;
+}
+
+static void
+host_memory_backend_get_size(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackendNetwork *backend = MEMORY_BACKEND_NETWORK(obj);
+ uint64_t value = backend->shared_size;
+
+ visit_type_size(v, &value, name, errp);
+}
+
+static void
+host_memory_backend_set_size(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ HostMemoryBackendNetwork *nhm = MEMORY_BACKEND_NETWORK(obj);
+ Error *local_err = NULL;
+ uint64_t value;
+
+ if (memory_region_size(&backend->mr)) {
+ error_setg(&local_err, "cannot change property value");
+ goto out;
+ }
+
+ visit_type_size(v, &value, name, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ if (!value) {
+ error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
+ PRIu64 "'", object_get_typename(obj), name, value);
+ goto out;
+ }
+ nhm->shared_size = value;
+out:
+ error_propagate(errp, local_err);
+}
+
+static void network_backend_instance_init(Object *o)
+{
+ HostMemoryBackendNetwork *shm = MEMORY_BACKEND_NETWORK(o);
+
+ object_property_add_bool(o, "master", get_master, set_master, NULL);
+ object_property_add_link(o, "socket", TYPE_MULTI_SOCKET_BACKEND,
+ (Object **)&shm->ms,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ &error_abort);
+ object_property_add(o, "shared-size", "int",
+ host_memory_backend_get_size,
+ host_memory_backend_set_size, NULL, NULL, NULL);
+}
+
+static const TypeInfo network_backend_info = {
+ .name = TYPE_MEMORY_BACKEND_NETWORK,
+ .parent = TYPE_MEMORY_BACKEND,
+ .class_init = network_backend_class_init,
+ .class_size = sizeof(HostMemoryBackendNetworkClass),
+ .instance_init = network_backend_instance_init,
+ .instance_size = sizeof(HostMemoryBackendNetwork),
+};
+
+static void register_types(void)
+{
+ type_register_static(&network_backend_info);
+}
+
+type_init(register_types);
diff --git a/include/sysemu/hostmem-network.h b/include/sysemu/hostmem-network.h
new file mode 100644
index 0000000..ffadad9
--- /dev/null
+++ b/include/sysemu/hostmem-network.h
@@ -0,0 +1,79 @@
+/*
+ * QEMU Host Memory Backend over network
+ *
+ * Copyright (C) 2016 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal <b.reynal@virtualopensystems.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HMN_H
+#define QEMU_HMN_H
+
+#include "qemu-common.h"
+#include "sysemu/hostmem.h"
+#include "qom/object_interfaces.h"
+#include "qemu/multi-socket.h"
+#include "qemu/queue.h"
+
+#define MBN_REGISTER_CMD "nm-register"
+#define MBN_READ_CMD "nm-read"
+#define MBN_WRITE_CMD "nm-write"
+
+#define TYPE_MEMORY_BACKEND_NETWORK "memory-backend-network"
+
+#define MEMORY_BACKEND_NETWORK(obj) \
+ OBJECT_CHECK(HostMemoryBackendNetwork, (obj), TYPE_MEMORY_BACKEND_NETWORK)
+#define MEMORY_BACKEND_NETWORK_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(HostMemoryBackendNetworkClass, (obj), \
+ TYPE_MEMORY_BACKEND_NETWORK)
+#define MEMORY_BACKEND_NETWORK_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HostMemoryBackendNetworkClass, (klass), \
+ TYPE_MEMORY_BACKEND_NETWORK)
+
+typedef struct HostMemoryBackendNetwork HostMemoryBackendNetwork;
+typedef struct HostMemoryBackendNetworkClass HostMemoryBackendNetworkClass;
+typedef struct NMData NMData;
+typedef struct NMArea NMArea;
+
+struct NMData {
+ hwaddr addr;
+ uint64_t data;
+ unsigned size;
+};
+
+struct NMArea {
+ unsigned size;
+ hwaddr addr;
+
+ MemoryRegion region;
+ MSClient *client;
+ HostMemoryBackendNetwork *nhm;
+
+ QLIST_ENTRY(NMArea) next;
+};
+
+struct HostMemoryBackendNetwork {
+ HostMemoryBackend parent_obj;
+
+ bool master;
+ int shared_size;
+ MSBackend *ms;
+
+ int event;
+ EventNotifier *levent;
+
+ NMData last_read;
+
+ QLIST_HEAD(areas_head, NMArea) areas;
+};
+
+struct HostMemoryBackendNetworkClass {
+ HostMemoryBackendClass parent_class;
+
+ void (*parent_complete)(UserCreatable *uc, Error **errp);
+ void (*boot)(HostMemoryBackendNetwork *nhm);
+};
+#endif
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread