aboutsummaryrefslogtreecommitdiff
path: root/tests/qtest/vhost-user-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/qtest/vhost-user-test.c')
-rw-r--r--tests/qtest/vhost-user-test.c175
1 files changed, 157 insertions, 18 deletions
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index 84498941a6..e8d2da7228 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -26,11 +26,13 @@
#include "libqos/virtio-pci.h"
#include "libqos/malloc-pc.h"
+#include "libqos/qgraph_internal.h"
#include "hw/virtio/virtio-net.h"
#include "standard-headers/linux/vhost_types.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_net.h"
+#include "standard-headers/linux/virtio_gpio.h"
#ifdef CONFIG_LINUX
#include <sys/vfs.h>
@@ -52,9 +54,12 @@
#define VHOST_MAX_VIRTQUEUES 0x100
#define VHOST_USER_F_PROTOCOL_FEATURES 30
+#define VIRTIO_F_VERSION_1 32
+
#define VHOST_USER_PROTOCOL_F_MQ 0
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
+#define VHOST_USER_PROTOCOL_F_CONFIG 9
#define VHOST_LOG_PAGE 0x1000
@@ -78,6 +83,8 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
VHOST_USER_GET_QUEUE_NUM = 17,
VHOST_USER_SET_VRING_ENABLE = 18,
+ VHOST_USER_GET_CONFIG = 24,
+ VHOST_USER_SET_CONFIG = 25,
VHOST_USER_MAX
} VhostUserRequest;
@@ -137,6 +144,7 @@ enum {
enum {
VHOST_USER_NET,
+ VHOST_USER_GPIO,
};
typedef struct TestServer {
@@ -168,10 +176,11 @@ struct vhost_user_ops {
const char *chr_opts);
/* VHOST-USER commands. */
+ uint64_t (*get_features)(TestServer *s);
void (*set_features)(TestServer *s, CharBackend *chr,
- VhostUserMsg *msg);
+ VhostUserMsg *msg);
void (*get_protocol_features)(TestServer *s,
- CharBackend *chr, VhostUserMsg *msg);
+ CharBackend *chr, VhostUserMsg *msg);
};
static const char *init_hugepagefs(void);
@@ -194,6 +203,19 @@ static void append_vhost_net_opts(TestServer *s, GString *cmd_line,
chr_opts, s->chr_name);
}
+/*
+ * For GPIO there are no other magic devices we need to add (like
+ * block or netdev) so all we need to worry about is the vhost-user
+ * chardev socket.
+ */
+static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line,
+ const char *chr_opts)
+{
+ g_string_append_printf(cmd_line, QEMU_CMD_CHR,
+ s->chr_name, s->socket_path,
+ chr_opts);
+}
+
static void append_mem_opts(TestServer *server, GString *cmd_line,
int size, enum test_memfd memfd)
{
@@ -316,7 +338,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
}
if (size != VHOST_USER_HDR_SIZE) {
- g_test_message("Wrong message size received %d", size);
+ qos_printf("%s: Wrong message size received %d\n", __func__, size);
return;
}
@@ -327,28 +349,30 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
p += VHOST_USER_HDR_SIZE;
size = qemu_chr_fe_read_all(chr, p, msg.size);
if (size != msg.size) {
- g_test_message("Wrong message size received %d != %d",
- size, msg.size);
+ qos_printf("%s: Wrong message size received %d != %d\n",
+ __func__, size, msg.size);
return;
}
}
switch (msg.request) {
case VHOST_USER_GET_FEATURES:
+ /* Mandatory for tests to define get_features */
+ g_assert(s->vu_ops->get_features);
+
/* send back features to qemu */
msg.flags |= VHOST_USER_REPLY_MASK;
msg.size = sizeof(m.payload.u64);
- msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
- 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
- if (s->queues > 1) {
- msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
- }
+
if (s->test_flags >= TEST_FLAGS_BAD) {
msg.payload.u64 = 0;
s->test_flags = TEST_FLAGS_END;
+ } else {
+ msg.payload.u64 = s->vu_ops->get_features(s);
}
- p = (uint8_t *) &msg;
- qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+
+ qemu_chr_fe_write_all(chr, (uint8_t *) &msg,
+ VHOST_USER_HDR_SIZE + msg.size);
break;
case VHOST_USER_SET_FEATURES:
@@ -357,12 +381,55 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
}
break;
+ case VHOST_USER_SET_OWNER:
+ /*
+ * We don't need to do anything here, the remote is just
+ * letting us know it is in charge. Just log it.
+ */
+ qos_printf("set_owner: start of session\n");
+ break;
+
case VHOST_USER_GET_PROTOCOL_FEATURES:
if (s->vu_ops->get_protocol_features) {
s->vu_ops->get_protocol_features(s, chr, &msg);
}
break;
+ case VHOST_USER_GET_CONFIG:
+ /*
+ * Treat GET_CONFIG as a NOP and just reply and let the guest
+ * consider we have updated its memory. Tests currently don't
+ * require working configs.
+ */
+ msg.flags |= VHOST_USER_REPLY_MASK;
+ p = (uint8_t *) &msg;
+ qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+ break;
+
+ case VHOST_USER_SET_PROTOCOL_FEATURES:
+ /*
+ * We did set VHOST_USER_F_PROTOCOL_FEATURES so its valid for
+ * the remote end to send this. There is no handshake reply so
+ * just log the details for debugging.
+ */
+ qos_printf("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64);
+ break;
+
+ /*
+ * A real vhost-user backend would actually set the size and
+ * address of the vrings but we can simply report them.
+ */
+ case VHOST_USER_SET_VRING_NUM:
+ qos_printf("set_vring_num: %d/%d\n",
+ msg.payload.state.index, msg.payload.state.num);
+ break;
+ case VHOST_USER_SET_VRING_ADDR:
+ qos_printf("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n",
+ msg.payload.addr.avail_user_addr,
+ msg.payload.addr.desc_user_addr,
+ msg.payload.addr.used_user_addr);
+ break;
+
case VHOST_USER_GET_VRING_BASE:
/* send back vring base to qemu */
msg.flags |= VHOST_USER_REPLY_MASK;
@@ -427,7 +494,18 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
break;
+ case VHOST_USER_SET_VRING_ENABLE:
+ /*
+ * Another case we ignore as we don't need to respond. With a
+ * fully functioning vhost-user we would enable/disable the
+ * vring monitoring.
+ */
+ qos_printf("set_vring(%d)=%s\n", msg.payload.state.index,
+ msg.payload.state.num ? "enabled" : "disabled");
+ break;
+
default:
+ qos_printf("vhost-user: un-handled message: %d\n", msg.request);
break;
}
@@ -450,7 +528,7 @@ static const char *init_hugepagefs(void)
}
if (access(path, R_OK | W_OK | X_OK)) {
- g_test_message("access on path (%s): %s", path, strerror(errno));
+ qos_printf("access on path (%s): %s", path, strerror(errno));
g_test_fail();
return NULL;
}
@@ -460,13 +538,13 @@ static const char *init_hugepagefs(void)
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
- g_test_message("statfs on path (%s): %s", path, strerror(errno));
+ qos_printf("statfs on path (%s): %s", path, strerror(errno));
g_test_fail();
return NULL;
}
if (fs.f_type != HUGETLBFS_MAGIC) {
- g_test_message("Warning: path not on HugeTLBFS: %s", path);
+ qos_printf("Warning: path not on HugeTLBFS: %s", path);
g_test_fail();
return NULL;
}
@@ -938,11 +1016,23 @@ static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
wait_for_rings_started(s, s->queues * 2);
}
+
+static uint64_t vu_net_get_features(TestServer *s)
+{
+ uint64_t features = 0x1ULL << VHOST_F_LOG_ALL |
+ 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+
+ if (s->queues > 1) {
+ features |= 0x1ULL << VIRTIO_NET_F_MQ;
+ }
+
+ return features;
+}
+
static void vu_net_set_features(TestServer *s, CharBackend *chr,
- VhostUserMsg *msg)
+ VhostUserMsg *msg)
{
- g_assert_cmpint(msg->payload.u64 &
- (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL);
+ g_assert(msg->payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES));
if (s->test_flags == TEST_FLAGS_DISCONNECT) {
qemu_chr_fe_disconnect(chr);
s->test_flags = TEST_FLAGS_BAD;
@@ -969,6 +1059,7 @@ static struct vhost_user_ops g_vu_net_ops = {
.append_opts = append_vhost_net_opts,
+ .get_features = vu_net_get_features,
.set_features = vu_net_set_features,
.get_protocol_features = vu_net_get_protocol_features,
};
@@ -1017,3 +1108,51 @@ static void register_vhost_user_test(void)
test_multiqueue, &opts);
}
libqos_init(register_vhost_user_test);
+
+static uint64_t vu_gpio_get_features(TestServer *s)
+{
+ return 0x1ULL << VIRTIO_F_VERSION_1 |
+ 0x1ULL << VIRTIO_GPIO_F_IRQ |
+ 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+}
+
+/*
+ * This stub can't handle all the message types but we should reply
+ * that we support VHOST_USER_PROTOCOL_F_CONFIG as gpio would use it
+ * talking to a read vhost-user daemon.
+ */
+static void vu_gpio_get_protocol_features(TestServer *s, CharBackend *chr,
+ VhostUserMsg *msg)
+{
+ /* send back features to qemu */
+ msg->flags |= VHOST_USER_REPLY_MASK;
+ msg->size = sizeof(m.payload.u64);
+ msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_CONFIG;
+
+ qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
+}
+
+static struct vhost_user_ops g_vu_gpio_ops = {
+ .type = VHOST_USER_GPIO,
+
+ .append_opts = append_vhost_gpio_opts,
+
+ .get_features = vu_gpio_get_features,
+ .set_features = vu_net_set_features,
+ .get_protocol_features = vu_gpio_get_protocol_features,
+};
+
+static void register_vhost_gpio_test(void)
+{
+ QOSGraphTestOptions opts = {
+ .before = vhost_user_test_setup,
+ .subprocess = true,
+ .arg = &g_vu_gpio_ops,
+ };
+
+ qemu_add_opts(&qemu_chardev_opts);
+
+ qos_add_test("read-guest-mem/memfile",
+ "vhost-user-gpio", test_read_guest_mem, &opts);
+}
+libqos_init(register_vhost_gpio_test);