aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-09-26 19:47:00 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-09-26 19:47:00 +0100
commit7cfdc02dae0d2ff58c897496cfdbbafc0eda0f3f (patch)
tree4ab986d748b8e4f914a388fe449366f9812b0f7d /tests
parent3b71ec8516bb50e9a743645bf139571de0b39f61 (diff)
parentfb9f592623b0f9bb82a88d68d7921fb581918ef5 (diff)
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
virtio, pc: fixes and features beginning of guest error handling for virtio devices amd iommu pc compat fixes Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Fri 23 Sep 2016 23:02:09 BST # gpg: using RSA key 0x281F0DB8D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: hw/i386: AMD IOMMU IVRS table hw/i386: Introduce AMD IOMMU hw/i386/trace-events: Add AMD IOMMU trace events hw/pci: Prepare for AMD IOMMU virtio: handle virtqueue_get_head() errors virtio: handle virtqueue_num_heads() errors virtio: handle virtqueue_read_next_desc() errors virtio: use unsigned int for virtqueue_get_avail_bytes() index virtio: handle virtqueue_get_avail_bytes() errors virtio: handle virtqueue_map_desc() errors virtio: migrate vdev->broken flag virtio: stop virtqueue processing if device is broken virtio: fix stray tab character target-i386: turn off CPU.l3-cache only for 2.7 and older machine types pc: clean up COMPAT macro chaining virtio: add check for descriptor's mapped address tests: add /vhost-user/flags-mismatch test tests: add a simple /vhost-user/multiqueue test tests: add /vhost-user/connect-fail test Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/vhost-user-test.c208
2 files changed, 205 insertions, 5 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index d8101b3543..2aa78c1820 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -656,7 +656,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
tests/postcopy-test$(EXESUF): tests/postcopy-test.o
-tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y)
+tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y)
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index b89a551126..a39846e6fd 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -20,6 +20,11 @@
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
+#include "libqos/pci-pc.h"
+#include "libqos/virtio-pci.h"
+#include "libqos/malloc-pc.h"
+#include "hw/virtio/virtio-net.h"
+
#include <linux/vhost.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_net.h>
@@ -50,6 +55,7 @@
#define VHOST_MEMORY_MAX_NREGIONS 8
#define VHOST_USER_F_PROTOCOL_FEATURES 30
+#define VHOST_USER_PROTOCOL_F_MQ 0
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
#define VHOST_LOG_PAGE 0x1000
@@ -72,6 +78,7 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_VRING_ERR = 14,
VHOST_USER_GET_PROTOCOL_FEATURES = 15,
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+ VHOST_USER_GET_QUEUE_NUM = 17,
VHOST_USER_SET_VRING_ENABLE = 18,
VHOST_USER_MAX
} VhostUserRequest;
@@ -123,6 +130,13 @@ static VhostUserMsg m __attribute__ ((unused));
#define VHOST_USER_VERSION (0x1)
/*****************************************************************************/
+enum {
+ TEST_FLAGS_OK,
+ TEST_FLAGS_DISCONNECT,
+ TEST_FLAGS_BAD,
+ TEST_FLAGS_END,
+};
+
typedef struct TestServer {
gchar *socket_path;
gchar *mig_path;
@@ -135,6 +149,9 @@ typedef struct TestServer {
CompatGCond data_cond;
int log_fd;
uint64_t rings;
+ bool test_fail;
+ int test_flags;
+ int queues;
} TestServer;
static const char *tmpfs;
@@ -249,6 +266,12 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
uint8_t *p = (uint8_t *) &msg;
int fd;
+ if (s->test_fail) {
+ qemu_chr_disconnect(chr);
+ /* now switch to non-failure */
+ s->test_fail = false;
+ }
+
if (size != VHOST_USER_HDR_SIZE) {
g_test_message("Wrong message size received %d\n", size);
return;
@@ -274,6 +297,13 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
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;
+ }
p = (uint8_t *) &msg;
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
break;
@@ -281,6 +311,10 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
case VHOST_USER_SET_FEATURES:
g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
!=, 0ULL);
+ if (s->test_flags == TEST_FLAGS_DISCONNECT) {
+ qemu_chr_disconnect(chr);
+ s->test_flags = TEST_FLAGS_BAD;
+ }
break;
case VHOST_USER_GET_PROTOCOL_FEATURES:
@@ -288,6 +322,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
msg.flags |= VHOST_USER_REPLY_MASK;
msg.size = sizeof(m.payload.u64);
msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
+ if (s->queues > 1) {
+ msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
+ }
p = (uint8_t *) &msg;
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
break;
@@ -300,7 +337,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
p = (uint8_t *) &msg;
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
- assert(msg.payload.state.index < 2);
+ assert(msg.payload.state.index < s->queues * 2);
s->rings &= ~(0x1ULL << msg.payload.state.index);
break;
@@ -340,10 +377,18 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
break;
case VHOST_USER_SET_VRING_BASE:
- assert(msg.payload.state.index < 2);
+ assert(msg.payload.state.index < s->queues * 2);
s->rings |= 0x1ULL << msg.payload.state.index;
break;
+ case VHOST_USER_GET_QUEUE_NUM:
+ msg.flags |= VHOST_USER_REPLY_MASK;
+ msg.size = sizeof(m.payload.u64);
+ msg.payload.u64 = s->queues;
+ p = (uint8_t *) &msg;
+ qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+ break;
+
default:
break;
}
@@ -390,10 +435,21 @@ static TestServer *test_server_new(const gchar *name)
g_cond_init(&server->data_cond);
server->log_fd = -1;
+ server->queues = 1;
return server;
}
+static void chr_event(void *opaque, int event)
+{
+ TestServer *s = opaque;
+
+ if (s->test_flags == TEST_FLAGS_END &&
+ event == CHR_EVENT_CLOSED) {
+ s->test_flags = TEST_FLAGS_OK;
+ }
+}
+
static void test_server_create_chr(TestServer *server, const gchar *opt)
{
gchar *chr_path;
@@ -402,7 +458,8 @@ static void test_server_create_chr(TestServer *server, const gchar *opt)
server->chr = qemu_chr_new(server->chr_name, chr_path, NULL);
g_free(chr_path);
- qemu_chr_add_handlers(server->chr, chr_can_read, chr_read, NULL, server);
+ qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
+ chr_event, server);
}
static void test_server_listen(TestServer *server)
@@ -641,7 +698,6 @@ static void test_migrate(void)
global_qtest = global;
}
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static void wait_for_rings_started(TestServer *s, size_t count)
{
gint64 end_time;
@@ -659,6 +715,7 @@ static void wait_for_rings_started(TestServer *s, size_t count)
g_mutex_unlock(&s->data_mutex);
}
+#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static gboolean
reconnect_cb(gpointer user_data)
{
@@ -715,8 +772,144 @@ static void test_reconnect(void)
g_test_trap_assert_passed();
g_free(path);
}
+
+static void test_connect_fail_subprocess(void)
+{
+ TestServer *s = test_server_new("connect-fail");
+ char *cmd;
+
+ s->test_fail = true;
+ g_thread_new("connect", connect_thread, s);
+ cmd = GET_QEMU_CMDE(s, 2, ",server", "");
+ qtest_start(cmd);
+ g_free(cmd);
+
+ init_virtio_dev(s);
+ wait_for_fds(s);
+ wait_for_rings_started(s, 2);
+
+ qtest_end();
+ test_server_free(s);
+}
+
+static void test_connect_fail(void)
+{
+ gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess",
+ qtest_get_arch());
+ g_test_trap_subprocess(path, 0, 0);
+ g_test_trap_assert_passed();
+ g_free(path);
+}
+
+static void test_flags_mismatch_subprocess(void)
+{
+ TestServer *s = test_server_new("flags-mismatch");
+ char *cmd;
+
+ s->test_flags = TEST_FLAGS_DISCONNECT;
+ g_thread_new("connect", connect_thread, s);
+ cmd = GET_QEMU_CMDE(s, 2, ",server", "");
+ qtest_start(cmd);
+ g_free(cmd);
+
+ init_virtio_dev(s);
+ wait_for_fds(s);
+ wait_for_rings_started(s, 2);
+
+ qtest_end();
+ test_server_free(s);
+}
+
+static void test_flags_mismatch(void)
+{
+ gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess",
+ qtest_get_arch());
+ g_test_trap_subprocess(path, 0, 0);
+ g_test_trap_assert_passed();
+ g_free(path);
+}
+
#endif
+static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
+{
+ QVirtioPCIDevice *dev;
+
+ dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
+ g_assert(dev != NULL);
+ g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET);
+
+ qvirtio_pci_device_enable(dev);
+ qvirtio_reset(&qvirtio_pci, &dev->vdev);
+ qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev);
+ qvirtio_set_driver(&qvirtio_pci, &dev->vdev);
+
+ return dev;
+}
+
+static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
+{
+ uint32_t features;
+
+ features = qvirtio_get_features(bus, dev);
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_RING_F_EVENT_IDX));
+ qvirtio_set_features(bus, dev, features);
+
+ qvirtio_set_driver_ok(bus, dev);
+}
+
+#define PCI_SLOT 0x04
+
+static void test_multiqueue(void)
+{
+ const int queues = 2;
+ TestServer *s = test_server_new("mq");
+ QVirtioPCIDevice *dev;
+ QPCIBus *bus;
+ QVirtQueuePCI *vq[queues * 2];
+ QGuestAllocator *alloc;
+ char *cmd;
+ int i;
+
+ s->queues = queues;
+ test_server_listen(s);
+
+ cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
+ "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
+ 512, 512, root, s->chr_name,
+ s->socket_path, "", s->chr_name,
+ queues, queues * 2 + 2);
+ qtest_start(cmd);
+ g_free(cmd);
+
+ bus = qpci_init_pc();
+ dev = virtio_net_pci_init(bus, PCI_SLOT);
+
+ alloc = pc_alloc_init();
+ for (i = 0; i < queues * 2; i++) {
+ vq[i] = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
+ alloc, i);
+ }
+
+ driver_init(&qvirtio_pci, &dev->vdev);
+ wait_for_rings_started(s, queues * 2);
+
+ /* End test */
+ for (i = 0; i < queues * 2; i++) {
+ qvirtqueue_cleanup(&qvirtio_pci, &vq[i]->vq, alloc);
+ }
+ pc_alloc_uninit(alloc);
+ qvirtio_pci_device_disable(dev);
+ g_free(dev->pdev);
+ g_free(dev);
+ qpci_free_pc(bus);
+ qtest_end();
+
+ test_server_free(s);
+}
+
int main(int argc, char **argv)
{
QTestState *s = NULL;
@@ -762,10 +955,17 @@ int main(int argc, char **argv)
qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem);
qtest_add_func("/vhost-user/migrate", test_migrate);
+ qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
qtest_add_func("/vhost-user/reconnect/subprocess",
test_reconnect_subprocess);
qtest_add_func("/vhost-user/reconnect", test_reconnect);
+ qtest_add_func("/vhost-user/connect-fail/subprocess",
+ test_connect_fail_subprocess);
+ qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
+ qtest_add_func("/vhost-user/flags-mismatch/subprocess",
+ test_flags_mismatch_subprocess);
+ qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
#endif
ret = g_test_run();