From: Marc-André Lureau <marcandre.lur...@redhat.com> Learn to give a socket to the slave to let him make requests to the master.
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> --- docs/specs/vhost-user.txt | 23 ++++++++++++++++ hw/virtio/vhost-user.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt index 0312d40..8a635fa 100644 --- a/docs/specs/vhost-user.txt +++ b/docs/specs/vhost-user.txt @@ -248,12 +248,25 @@ Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. +Slave communication +------------------- + +An optional communication channel is provided if the slave +declares VHOST_USER_PROTOCOL_F_SLAVE_CHANNEL feature, to allow +the slave to make requests to the master. + +The fd is provided via VHOST_USER_SET_SLAVE_FD ancillary data. + +A slave may then send VHOST_USER_SLAVE_* messages to the master +using this fd communication channel. + Protocol features ----------------- #define VHOST_USER_PROTOCOL_F_MQ 0 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 #define VHOST_USER_PROTOCOL_F_RARP 2 +#define VHOST_USER_PROTOCOL_F_SLAVE_CHANNEL 3 Message types ------------- @@ -464,3 +477,13 @@ Message types is present in VHOST_USER_GET_PROTOCOL_FEATURES. The first 6 bytes of the payload contain the mac address of the guest to allow the vhost user backend to construct and broadcast the fake RARP. + + * VHOST_USER_SET_SLAVE_FD + Id: 20 + Equivalent ioctl: N/A + Master payload: N/A + + Set the file descriptor for the salve to make VHOST_USER_SLAVE_* + request to the master. It is passed in the ancillary data. + This message is only sent if VHOST_USER_PROTOCOL_F_SLAVE_CHANNEL + feature is available. diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 02ac1fc..890c1bd 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -32,6 +32,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_MQ = 0, VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, VHOST_USER_PROTOCOL_F_RARP = 2, + VHOST_USER_PROTOCOL_F_SLAVE_CHANNEL = 3, VHOST_USER_PROTOCOL_F_MAX }; @@ -59,9 +60,16 @@ typedef enum VhostUserRequest { VHOST_USER_GET_QUEUE_NUM = 17, VHOST_USER_SET_VRING_ENABLE = 18, VHOST_USER_SEND_RARP = 19, + VHOST_USER_SET_SLAVE_FD = 20, + VHOST_USER_MAX } VhostUserRequest; +typedef enum VhostUserSlaveRequest { + VHOST_USER_SLAVE_NONE = 0, + VHOST_USER_SLAVE_MAX +} VhostUserSlaveRequest; + typedef struct VhostUserMemoryRegion { uint64_t guest_phys_addr; uint64_t memory_size; @@ -110,6 +118,7 @@ static VhostUserMsg m __attribute__ ((unused)); struct vhost_user { CharDriverState *chr; + int slave_fd; }; static bool ioeventfd_enabled(void) @@ -513,6 +522,55 @@ static int vhost_user_reset_device(struct vhost_dev *dev) return 0; } +static void slave_read(void *opaque) +{ + struct vhost_dev *dev = opaque; + struct vhost_user *u = dev->opaque; + VhostUserMsg msg = { 0, }; + int size; + + size = read(u->slave_fd, &msg, VHOST_USER_HDR_SIZE); + if (size != VHOST_USER_HDR_SIZE) { + error_report("Failed to read from slave."); + qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL); + close(u->slave_fd); + u->slave_fd = -1; + return; + } + + switch (msg.request) { + default: + error_report("Received unexpected msg type."); + } +} + +static int vhost_setup_slave_channel(struct vhost_dev *dev) +{ + VhostUserMsg msg = { + .request = VHOST_USER_SET_SLAVE_FD, + .flags = VHOST_USER_VERSION, + }; + struct vhost_user *u = dev->opaque; + int sv[2]; + + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_SLAVE_CHANNEL)) { + return 0; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { + error_report("socketpair() failed"); + return -1; + } + + u->slave_fd = sv[0]; + qemu_set_fd_handler(u->slave_fd, slave_read, NULL, dev); + + vhost_user_write(dev, &msg, &sv[1], 1); + + return 0; +} + static int vhost_user_init(struct vhost_dev *dev, void *opaque) { uint64_t features; @@ -523,6 +581,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) u = g_new0(struct vhost_user, 1); u->chr = opaque; + u->slave_fd = -1; dev->opaque = u; err = vhost_user_get_features(dev, &features); @@ -563,6 +622,12 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature."); } + + err = vhost_setup_slave_channel(dev); + if (err < 0) { + return err; + } + return 0; } @@ -573,6 +638,10 @@ static int vhost_user_cleanup(struct vhost_dev *dev) assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); u = dev->opaque; + if (u->slave_fd >= 0) { + close(u->slave_fd); + u->slave_fd = -1; + } g_free(u); dev->opaque = 0; -- 2.5.5