@@ -136,10 +136,23 @@ As older slaves don't support negotiating protocol features,
a feature bit was dedicated for this purpose:
#define VHOST_USER_F_PROTOCOL_FEATURES 30
+Slave communication
+-------------------
+
+Since the vhost-user protocol do not let slave make requests back to
+the master, an optional communication channel is provided if the slave
+declares VHOST_USER_PROTOCOL_F_SLAVE_REQ feature.
+
+The fd is provided via VHOST_USER_SET_SLAVE_FD ancillary data.
+
+A slave may then send VHOST_USER_SLAVE_* messages to the master by
+using this fd.
+
Protocol features
-----------------
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 0
+#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 1
Message types
-------------
@@ -308,6 +321,16 @@ Message types
invalid FD flag. This flag is set when there is no file descriptor
in the ancillary data.
+ * VHOST_USER_SET_SLAVE_FD
+ Id: 17
+ 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_REQ
+ feature is available.
+
Migration
---------
@@ -27,8 +27,9 @@
#define VHOST_USER_F_PROTOCOL_FEATURES 30
-#define VHOST_USER_PROTOCOL_FEATURE_MASK 0x1ULL
+#define VHOST_USER_PROTOCOL_FEATURE_MASK 0x3ULL
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 0
+#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 1
typedef enum VhostUserRequest {
VHOST_USER_NONE = 0,
@@ -48,9 +49,15 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_VRING_ERR = 14,
VHOST_USER_GET_PROTOCOL_FEATURES = 15,
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+ VHOST_USER_SET_SLAVE_FD = 17,
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;
@@ -93,6 +100,7 @@ static VhostUserMsg m __attribute__ ((unused));
struct vhost_user {
CharDriverState *chr;
+ CharDriverState *slave_chr;
};
static bool ioeventfd_enabled(void)
@@ -277,6 +285,7 @@ static int vhost_user_call(struct vhost_dev *dev,
break;
+ case VHOST_USER_SET_SLAVE_FD:
case VHOST_USER_SET_LOG_FD:
fds[fd_num++] = *((int *) arg);
break;
@@ -361,6 +370,43 @@ end:
return ret;
}
+static int slave_can_receive(void *opaque)
+{
+ return VHOST_USER_HDR_SIZE;
+}
+
+static void slave_receive(void *opaque, const uint8_t *buf, int size)
+{
+ struct vhost_dev *dev = opaque;
+ VhostUserMsg *msg = (VhostUserMsg *)buf;
+
+ if (size != VHOST_USER_HDR_SIZE) {
+ error_report("Failed to read from slave.");
+ return;
+ }
+
+ switch (msg->request) {
+ default:
+ error_report("Received unexpected msg type.");
+ }
+}
+
+static void slave_event(void *opaque, int event)
+{
+ struct vhost_dev *dev = opaque;
+ struct vhost_user *u = dev->opaque;
+ CharDriverState *slave_chr = u->slave_chr;
+
+ switch (event) {
+ case CHR_EVENT_CLOSED:
+ if (slave_chr) {
+ u->slave_chr = NULL;
+ qemu_chr_free(slave_chr);
+ }
+ break;
+ }
+}
+
static int vhost_user_init(struct vhost_dev *dev, void *opaque)
{
VhostUserMsg msg = { 0 };
@@ -417,16 +463,39 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)
}
}
+ if (__virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
+ int sv[2];
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+ error_report("socketpair() failed");
+ return -1;
+ }
+
+ vhost_user_call(dev, VHOST_USER_SET_SLAVE_FD, &sv[1]);
+
+ u->slave_chr = qemu_chr_open_eventfd(sv[0]);
+ qemu_chr_add_handlers(u->slave_chr, slave_can_receive, slave_receive,
+ slave_event, dev);
+ }
+
+
return 0;
}
static int vhost_user_cleanup(struct vhost_dev *dev)
{
struct vhost_user *u;
+ CharDriverState *slave_chr;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
u = dev->opaque;
+ if (u->slave_chr) {
+ slave_chr = u->slave_chr;
+ u->slave_chr = NULL;
+ qemu_chr_free(slave_chr);
+ }
g_free(u);
dev->opaque = 0;