1a77e6b14SNikolay Nikolaev /*
2a77e6b14SNikolay Nikolaev * QTest testcase for the vhost-user
3a77e6b14SNikolay Nikolaev *
4a77e6b14SNikolay Nikolaev * Copyright (c) 2014 Virtual Open Systems Sarl.
5a77e6b14SNikolay Nikolaev *
6a77e6b14SNikolay Nikolaev * This work is licensed under the terms of the GNU GPL, version 2 or later.
7a77e6b14SNikolay Nikolaev * See the COPYING file in the top-level directory.
8a77e6b14SNikolay Nikolaev *
9a77e6b14SNikolay Nikolaev */
10a77e6b14SNikolay Nikolaev
11681c28a3SPeter Maydell #include "qemu/osdep.h"
12bd95939fSNikolay Nikolaev
13dd210749SThomas Huth #include "libqtest-single.h"
145345fdb4SMarc-André Lureau #include "qapi/error.h"
15*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
16213dcb06SMarc-André Lureau #include "qemu/config-file.h"
17a77e6b14SNikolay Nikolaev #include "qemu/option.h"
18b1819747SMarc-André Lureau #include "qemu/range.h"
19a9c94277SMarkus Armbruster #include "qemu/sockets.h"
204d43a603SMarc-André Lureau #include "chardev/char-fe.h"
218e029fd6SMarc-André Lureau #include "qemu/memfd.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
2332cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
24cdafe929SEduardo Habkost #include "libqos/libqos.h"
25cdafe929SEduardo Habkost #include "libqos/pci-pc.h"
26cdafe929SEduardo Habkost #include "libqos/virtio-pci.h"
27a77e6b14SNikolay Nikolaev
28ed0a8d92SMarc-André Lureau #include "libqos/malloc-pc.h"
2930ea13e9SAlex Bennée #include "libqos/qgraph_internal.h"
30ed0a8d92SMarc-André Lureau #include "hw/virtio/virtio-net.h"
31ed0a8d92SMarc-André Lureau
32af3bba76SPaolo Bonzini #include "standard-headers/linux/vhost_types.h"
33af3bba76SPaolo Bonzini #include "standard-headers/linux/virtio_ids.h"
34af3bba76SPaolo Bonzini #include "standard-headers/linux/virtio_net.h"
358fcfc823SAlex Bennée #include "standard-headers/linux/virtio_gpio.h"
36b6f53ae0SMilan Zamazal #include "standard-headers/linux/virtio_scmi.h"
37af3bba76SPaolo Bonzini
38af3bba76SPaolo Bonzini #ifdef CONFIG_LINUX
39a77e6b14SNikolay Nikolaev #include <sys/vfs.h>
40af3bba76SPaolo Bonzini #endif
41a77e6b14SNikolay Nikolaev
4230de46dbSGonglei
43704b2168SMarc-André Lureau #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \
44a77e6b14SNikolay Nikolaev "mem-path=%s,share=on -numa node,memdev=mem"
458e029fd6SMarc-André Lureau #define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
468e029fd6SMarc-André Lureau " -numa node,memdev=mem"
470173ce4bSStefano Garzarella #define QEMU_CMD_SHM " -m %d -object memory-backend-shm,id=mem,size=%dM," \
480173ce4bSStefano Garzarella " -numa node,memdev=mem"
494616e359SMarc-André Lureau #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s"
50d24d1ad3SEric Auger #define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce=on"
51a77e6b14SNikolay Nikolaev
52a77e6b14SNikolay Nikolaev #define HUGETLBFS_MAGIC 0x958458f6
53a77e6b14SNikolay Nikolaev
54a77e6b14SNikolay Nikolaev /*********** FROM hw/virtio/vhost-user.c *************************************/
55a77e6b14SNikolay Nikolaev
56a77e6b14SNikolay Nikolaev #define VHOST_MEMORY_MAX_NREGIONS 8
57026eb179SMaxime Coquelin #define VHOST_MAX_VIRTQUEUES 0x100
58a77e6b14SNikolay Nikolaev
598a9b6b37SMichael S. Tsirkin #define VHOST_USER_F_PROTOCOL_FEATURES 30
608fcfc823SAlex Bennée #define VIRTIO_F_VERSION_1 32
618fcfc823SAlex Bennée
62ed0a8d92SMarc-André Lureau #define VHOST_USER_PROTOCOL_F_MQ 0
63b1819747SMarc-André Lureau #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
645a583cc5SPaolo Bonzini #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
658fcfc823SAlex Bennée #define VHOST_USER_PROTOCOL_F_CONFIG 9
66b1819747SMarc-André Lureau
67b1819747SMarc-André Lureau #define VHOST_LOG_PAGE 0x1000
688a9b6b37SMichael S. Tsirkin
69a77e6b14SNikolay Nikolaev typedef enum VhostUserRequest {
70a77e6b14SNikolay Nikolaev VHOST_USER_NONE = 0,
71a77e6b14SNikolay Nikolaev VHOST_USER_GET_FEATURES = 1,
72a77e6b14SNikolay Nikolaev VHOST_USER_SET_FEATURES = 2,
73a77e6b14SNikolay Nikolaev VHOST_USER_SET_OWNER = 3,
7460915dc4SYuanhan Liu VHOST_USER_RESET_OWNER = 4,
75a77e6b14SNikolay Nikolaev VHOST_USER_SET_MEM_TABLE = 5,
76a77e6b14SNikolay Nikolaev VHOST_USER_SET_LOG_BASE = 6,
77a77e6b14SNikolay Nikolaev VHOST_USER_SET_LOG_FD = 7,
78a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_NUM = 8,
79a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_ADDR = 9,
80a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_BASE = 10,
81a77e6b14SNikolay Nikolaev VHOST_USER_GET_VRING_BASE = 11,
82a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_KICK = 12,
83a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_CALL = 13,
84a77e6b14SNikolay Nikolaev VHOST_USER_SET_VRING_ERR = 14,
858a9b6b37SMichael S. Tsirkin VHOST_USER_GET_PROTOCOL_FEATURES = 15,
868a9b6b37SMichael S. Tsirkin VHOST_USER_SET_PROTOCOL_FEATURES = 16,
87ed0a8d92SMarc-André Lureau VHOST_USER_GET_QUEUE_NUM = 17,
8887656d50SMichael S. Tsirkin VHOST_USER_SET_VRING_ENABLE = 18,
89ff070f60SAlex Bennée VHOST_USER_GET_CONFIG = 24,
90ff070f60SAlex Bennée VHOST_USER_SET_CONFIG = 25,
91a77e6b14SNikolay Nikolaev VHOST_USER_MAX
92a77e6b14SNikolay Nikolaev } VhostUserRequest;
93a77e6b14SNikolay Nikolaev
94a77e6b14SNikolay Nikolaev typedef struct VhostUserMemoryRegion {
95a77e6b14SNikolay Nikolaev uint64_t guest_phys_addr;
96a77e6b14SNikolay Nikolaev uint64_t memory_size;
97a77e6b14SNikolay Nikolaev uint64_t userspace_addr;
98d6970e3bSNikolay Nikolaev uint64_t mmap_offset;
99a77e6b14SNikolay Nikolaev } VhostUserMemoryRegion;
100a77e6b14SNikolay Nikolaev
101a77e6b14SNikolay Nikolaev typedef struct VhostUserMemory {
102a77e6b14SNikolay Nikolaev uint32_t nregions;
103a77e6b14SNikolay Nikolaev uint32_t padding;
104a77e6b14SNikolay Nikolaev VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
105a77e6b14SNikolay Nikolaev } VhostUserMemory;
106a77e6b14SNikolay Nikolaev
1072b8819c6SVictor Kaplansky typedef struct VhostUserLog {
1082b8819c6SVictor Kaplansky uint64_t mmap_size;
1092b8819c6SVictor Kaplansky uint64_t mmap_offset;
1102b8819c6SVictor Kaplansky } VhostUserLog;
1112b8819c6SVictor Kaplansky
112a77e6b14SNikolay Nikolaev typedef struct VhostUserMsg {
113a77e6b14SNikolay Nikolaev VhostUserRequest request;
114a77e6b14SNikolay Nikolaev
115a77e6b14SNikolay Nikolaev #define VHOST_USER_VERSION_MASK (0x3)
116a77e6b14SNikolay Nikolaev #define VHOST_USER_REPLY_MASK (0x1<<2)
117a77e6b14SNikolay Nikolaev uint32_t flags;
118a77e6b14SNikolay Nikolaev uint32_t size; /* the following payload size */
119a77e6b14SNikolay Nikolaev union {
1202b8819c6SVictor Kaplansky #define VHOST_USER_VRING_IDX_MASK (0xff)
1212b8819c6SVictor Kaplansky #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
122a77e6b14SNikolay Nikolaev uint64_t u64;
123a77e6b14SNikolay Nikolaev struct vhost_vring_state state;
124a77e6b14SNikolay Nikolaev struct vhost_vring_addr addr;
125a77e6b14SNikolay Nikolaev VhostUserMemory memory;
1262b8819c6SVictor Kaplansky VhostUserLog log;
12712ebf690SMichael S. Tsirkin } payload;
128a77e6b14SNikolay Nikolaev } QEMU_PACKED VhostUserMsg;
129a77e6b14SNikolay Nikolaev
130a77e6b14SNikolay Nikolaev static VhostUserMsg m __attribute__ ((unused));
131a77e6b14SNikolay Nikolaev #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
132a77e6b14SNikolay Nikolaev + sizeof(m.flags) \
133a77e6b14SNikolay Nikolaev + sizeof(m.size))
134a77e6b14SNikolay Nikolaev
135a77e6b14SNikolay Nikolaev #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
136a77e6b14SNikolay Nikolaev
137a77e6b14SNikolay Nikolaev /* The version of the protocol we support */
138a77e6b14SNikolay Nikolaev #define VHOST_USER_VERSION (0x1)
139a77e6b14SNikolay Nikolaev /*****************************************************************************/
140a77e6b14SNikolay Nikolaev
1419294d76cSMarc-André Lureau enum {
1429294d76cSMarc-André Lureau TEST_FLAGS_OK,
1439294d76cSMarc-André Lureau TEST_FLAGS_DISCONNECT,
1449294d76cSMarc-André Lureau TEST_FLAGS_BAD,
1459294d76cSMarc-André Lureau TEST_FLAGS_END,
1469294d76cSMarc-André Lureau };
1479294d76cSMarc-André Lureau
148892040dcSDima Stepanov enum {
149892040dcSDima Stepanov VHOST_USER_NET,
1508fcfc823SAlex Bennée VHOST_USER_GPIO,
151b6f53ae0SMilan Zamazal VHOST_USER_SCMI,
152892040dcSDima Stepanov };
153892040dcSDima Stepanov
154ae31fb54SMarc-André Lureau typedef struct TestServer {
155ae31fb54SMarc-André Lureau gchar *socket_path;
156a899b1eaSMarc-André Lureau gchar *mig_path;
157ae31fb54SMarc-André Lureau gchar *chr_name;
1584d3f50ebSPaolo Bonzini gchar *tmpfs;
15932a6ebecSMarc-André Lureau CharBackend chr;
160ae31fb54SMarc-André Lureau int fds_num;
161ae31fb54SMarc-André Lureau int fds[VHOST_MEMORY_MAX_NREGIONS];
162ae31fb54SMarc-André Lureau VhostUserMemory memory;
1637d0ca3e7SPaolo Bonzini GMainContext *context;
1647d0ca3e7SPaolo Bonzini GMainLoop *loop;
1657d0ca3e7SPaolo Bonzini GThread *thread;
166e7b3af81SDaniel P. Berrangé GMutex data_mutex;
167e7b3af81SDaniel P. Berrangé GCond data_cond;
168b1819747SMarc-André Lureau int log_fd;
169d08e42a1SMichael S. Tsirkin uint64_t rings;
1705d443f5aSMarc-André Lureau bool test_fail;
1719294d76cSMarc-André Lureau int test_flags;
172ed0a8d92SMarc-André Lureau int queues;
173892040dcSDima Stepanov struct vhost_user_ops *vu_ops;
174ae31fb54SMarc-André Lureau } TestServer;
175bd95939fSNikolay Nikolaev
176892040dcSDima Stepanov struct vhost_user_ops {
177892040dcSDima Stepanov /* Device types. */
178892040dcSDima Stepanov int type;
179892040dcSDima Stepanov void (*append_opts)(TestServer *s, GString *cmd_line,
180892040dcSDima Stepanov const char *chr_opts);
181892040dcSDima Stepanov
182892040dcSDima Stepanov /* VHOST-USER commands. */
18319d55a19SAlex Bennée uint64_t (*get_features)(TestServer *s);
184892040dcSDima Stepanov void (*set_features)(TestServer *s, CharBackend *chr,
185892040dcSDima Stepanov VhostUserMsg *msg);
186892040dcSDima Stepanov void (*get_protocol_features)(TestServer *s,
187892040dcSDima Stepanov CharBackend *chr, VhostUserMsg *msg);
188892040dcSDima Stepanov };
189892040dcSDima Stepanov
190a3ebd6e0SPaolo Bonzini static const char *init_hugepagefs(void);
191892040dcSDima Stepanov static TestServer *test_server_new(const gchar *name,
192892040dcSDima Stepanov struct vhost_user_ops *ops);
19383265145SMarc-André Lureau static void test_server_free(TestServer *server);
19483265145SMarc-André Lureau static void test_server_listen(TestServer *server);
19583265145SMarc-André Lureau
1968e029fd6SMarc-André Lureau enum test_memfd {
1978e029fd6SMarc-André Lureau TEST_MEMFD_AUTO,
1988e029fd6SMarc-André Lureau TEST_MEMFD_YES,
1998e029fd6SMarc-André Lureau TEST_MEMFD_NO,
2000173ce4bSStefano Garzarella TEST_MEMFD_SHM,
2018e029fd6SMarc-André Lureau };
2028e029fd6SMarc-André Lureau
append_vhost_net_opts(TestServer * s,GString * cmd_line,const char * chr_opts)203892040dcSDima Stepanov static void append_vhost_net_opts(TestServer *s, GString *cmd_line,
204a3ebd6e0SPaolo Bonzini const char *chr_opts)
2058e029fd6SMarc-André Lureau {
206a3ebd6e0SPaolo Bonzini g_string_append_printf(cmd_line, QEMU_CMD_CHR QEMU_CMD_NETDEV,
207a3ebd6e0SPaolo Bonzini s->chr_name, s->socket_path,
208a3ebd6e0SPaolo Bonzini chr_opts, s->chr_name);
209a3ebd6e0SPaolo Bonzini }
210a3ebd6e0SPaolo Bonzini
2118fcfc823SAlex Bennée /*
2128fcfc823SAlex Bennée * For GPIO there are no other magic devices we need to add (like
2138fcfc823SAlex Bennée * block or netdev) so all we need to worry about is the vhost-user
2148fcfc823SAlex Bennée * chardev socket.
2158fcfc823SAlex Bennée */
append_vhost_gpio_opts(TestServer * s,GString * cmd_line,const char * chr_opts)2168fcfc823SAlex Bennée static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line,
2178fcfc823SAlex Bennée const char *chr_opts)
2188fcfc823SAlex Bennée {
2198fcfc823SAlex Bennée g_string_append_printf(cmd_line, QEMU_CMD_CHR,
2208fcfc823SAlex Bennée s->chr_name, s->socket_path,
2218fcfc823SAlex Bennée chr_opts);
2228fcfc823SAlex Bennée }
2238fcfc823SAlex Bennée
append_mem_opts(TestServer * server,GString * cmd_line,int size,enum test_memfd memfd)224a3ebd6e0SPaolo Bonzini static void append_mem_opts(TestServer *server, GString *cmd_line,
225a3ebd6e0SPaolo Bonzini int size, enum test_memfd memfd)
226a3ebd6e0SPaolo Bonzini {
227a3ebd6e0SPaolo Bonzini if (memfd == TEST_MEMFD_AUTO) {
2284a66c7a9SIlya Maximets memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES
2294a66c7a9SIlya Maximets : TEST_MEMFD_NO;
2308e029fd6SMarc-André Lureau }
2318e029fd6SMarc-André Lureau
2328e029fd6SMarc-André Lureau if (memfd == TEST_MEMFD_YES) {
233a3ebd6e0SPaolo Bonzini g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size);
2340173ce4bSStefano Garzarella } else if (memfd == TEST_MEMFD_SHM) {
2350173ce4bSStefano Garzarella g_string_append_printf(cmd_line, QEMU_CMD_SHM, size, size);
2368e029fd6SMarc-André Lureau } else {
237a3ebd6e0SPaolo Bonzini const char *root = init_hugepagefs() ? : server->tmpfs;
238a3ebd6e0SPaolo Bonzini
239a3ebd6e0SPaolo Bonzini g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root);
2408e029fd6SMarc-André Lureau }
2418e029fd6SMarc-André Lureau }
2428e029fd6SMarc-André Lureau
wait_for_fds(TestServer * s)2433b72ca38SPaolo Bonzini static bool wait_for_fds(TestServer *s)
244a77e6b14SNikolay Nikolaev {
245a77e6b14SNikolay Nikolaev gint64 end_time;
2463b72ca38SPaolo Bonzini bool got_region;
2473b72ca38SPaolo Bonzini int i;
248a77e6b14SNikolay Nikolaev
249ae31fb54SMarc-André Lureau g_mutex_lock(&s->data_mutex);
250a77e6b14SNikolay Nikolaev
251ca06d9ccSPaolo Bonzini end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
252ae31fb54SMarc-André Lureau while (!s->fds_num) {
253ae31fb54SMarc-André Lureau if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
254a77e6b14SNikolay Nikolaev /* timeout has passed */
255ae31fb54SMarc-André Lureau g_assert(s->fds_num);
256a77e6b14SNikolay Nikolaev break;
257a77e6b14SNikolay Nikolaev }
258a77e6b14SNikolay Nikolaev }
259a77e6b14SNikolay Nikolaev
260a77e6b14SNikolay Nikolaev /* check for sanity */
261ae31fb54SMarc-André Lureau g_assert_cmpint(s->fds_num, >, 0);
262ae31fb54SMarc-André Lureau g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
263a77e6b14SNikolay Nikolaev
264ae31fb54SMarc-André Lureau g_mutex_unlock(&s->data_mutex);
2653b72ca38SPaolo Bonzini
2663b72ca38SPaolo Bonzini got_region = false;
2673b72ca38SPaolo Bonzini for (i = 0; i < s->memory.nregions; ++i) {
2683b72ca38SPaolo Bonzini VhostUserMemoryRegion *reg = &s->memory.regions[i];
2693b72ca38SPaolo Bonzini if (reg->guest_phys_addr == 0) {
2703b72ca38SPaolo Bonzini got_region = true;
2713b72ca38SPaolo Bonzini break;
2723b72ca38SPaolo Bonzini }
2733b72ca38SPaolo Bonzini }
2743b72ca38SPaolo Bonzini if (!got_region) {
2753b72ca38SPaolo Bonzini g_test_skip("No memory at address 0x0");
2763b72ca38SPaolo Bonzini }
2773b72ca38SPaolo Bonzini return got_region;
278cf72b57fSMarc-André Lureau }
279cf72b57fSMarc-André Lureau
read_guest_mem_server(QTestState * qts,TestServer * s)280bae6b59dSPaolo Bonzini static void read_guest_mem_server(QTestState *qts, TestServer *s)
281cf72b57fSMarc-André Lureau {
2825a583cc5SPaolo Bonzini uint8_t *guest_mem;
283cf72b57fSMarc-André Lureau int i, j;
284cf72b57fSMarc-André Lureau size_t size;
285cf72b57fSMarc-André Lureau
286ae31fb54SMarc-André Lureau g_mutex_lock(&s->data_mutex);
287cf72b57fSMarc-André Lureau
288a77e6b14SNikolay Nikolaev /* iterate all regions */
289ae31fb54SMarc-André Lureau for (i = 0; i < s->fds_num; i++) {
290a77e6b14SNikolay Nikolaev
291ac9fd9b6SMilan Zamazal /* We'll check only the region starting at 0x0 */
292ae31fb54SMarc-André Lureau if (s->memory.regions[i].guest_phys_addr != 0x0) {
293a77e6b14SNikolay Nikolaev continue;
294a77e6b14SNikolay Nikolaev }
295a77e6b14SNikolay Nikolaev
296ae31fb54SMarc-André Lureau g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
297a77e6b14SNikolay Nikolaev
298ae31fb54SMarc-André Lureau size = s->memory.regions[i].memory_size +
299ae31fb54SMarc-André Lureau s->memory.regions[i].mmap_offset;
300d6970e3bSNikolay Nikolaev
301d6970e3bSNikolay Nikolaev guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
302ae31fb54SMarc-André Lureau MAP_SHARED, s->fds[i], 0);
303d6970e3bSNikolay Nikolaev
304d6970e3bSNikolay Nikolaev g_assert(guest_mem != MAP_FAILED);
305ae31fb54SMarc-André Lureau guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
306a77e6b14SNikolay Nikolaev
3075a583cc5SPaolo Bonzini for (j = 0; j < 1024; j++) {
308bae6b59dSPaolo Bonzini uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
309a77e6b14SNikolay Nikolaev uint32_t b = guest_mem[j];
310a77e6b14SNikolay Nikolaev
311a77e6b14SNikolay Nikolaev g_assert_cmpint(a, ==, b);
312a77e6b14SNikolay Nikolaev }
313a77e6b14SNikolay Nikolaev
314ae31fb54SMarc-André Lureau munmap(guest_mem, s->memory.regions[i].memory_size);
315a77e6b14SNikolay Nikolaev }
316a77e6b14SNikolay Nikolaev
317ae31fb54SMarc-André Lureau g_mutex_unlock(&s->data_mutex);
318a77e6b14SNikolay Nikolaev }
319a77e6b14SNikolay Nikolaev
thread_function(void * data)320a77e6b14SNikolay Nikolaev static void *thread_function(void *data)
321a77e6b14SNikolay Nikolaev {
3229732baf6SMarc-André Lureau GMainLoop *loop = data;
323a77e6b14SNikolay Nikolaev g_main_loop_run(loop);
324a77e6b14SNikolay Nikolaev return NULL;
325a77e6b14SNikolay Nikolaev }
326a77e6b14SNikolay Nikolaev
chr_can_read(void * opaque)327a77e6b14SNikolay Nikolaev static int chr_can_read(void *opaque)
328a77e6b14SNikolay Nikolaev {
329a77e6b14SNikolay Nikolaev return VHOST_USER_HDR_SIZE;
330a77e6b14SNikolay Nikolaev }
331a77e6b14SNikolay Nikolaev
chr_read(void * opaque,const uint8_t * buf,int size)332a77e6b14SNikolay Nikolaev static void chr_read(void *opaque, const uint8_t *buf, int size)
333a77e6b14SNikolay Nikolaev {
334b2670d1fSMarc-André Lureau g_autoptr(GError) err = NULL;
335ae31fb54SMarc-André Lureau TestServer *s = opaque;
33632a6ebecSMarc-André Lureau CharBackend *chr = &s->chr;
337a77e6b14SNikolay Nikolaev VhostUserMsg msg;
338a77e6b14SNikolay Nikolaev uint8_t *p = (uint8_t *) &msg;
33982248cd4SLi Qiang int fd = -1;
340a77e6b14SNikolay Nikolaev
3415d443f5aSMarc-André Lureau if (s->test_fail) {
3425345fdb4SMarc-André Lureau qemu_chr_fe_disconnect(chr);
3435d443f5aSMarc-André Lureau /* now switch to non-failure */
3445d443f5aSMarc-André Lureau s->test_fail = false;
3455d443f5aSMarc-André Lureau }
3465d443f5aSMarc-André Lureau
347a77e6b14SNikolay Nikolaev if (size != VHOST_USER_HDR_SIZE) {
34830ea13e9SAlex Bennée qos_printf("%s: Wrong message size received %d\n", __func__, size);
349a77e6b14SNikolay Nikolaev return;
350a77e6b14SNikolay Nikolaev }
351a77e6b14SNikolay Nikolaev
352ae31fb54SMarc-André Lureau g_mutex_lock(&s->data_mutex);
353a77e6b14SNikolay Nikolaev memcpy(p, buf, VHOST_USER_HDR_SIZE);
354a77e6b14SNikolay Nikolaev
355a77e6b14SNikolay Nikolaev if (msg.size) {
356a77e6b14SNikolay Nikolaev p += VHOST_USER_HDR_SIZE;
3575345fdb4SMarc-André Lureau size = qemu_chr_fe_read_all(chr, p, msg.size);
3584616e359SMarc-André Lureau if (size != msg.size) {
35930ea13e9SAlex Bennée qos_printf("%s: Wrong message size received %d != %d\n",
36030ea13e9SAlex Bennée __func__, size, msg.size);
3613ee7f21eSPaolo Bonzini goto out;
3624616e359SMarc-André Lureau }
363a77e6b14SNikolay Nikolaev }
364a77e6b14SNikolay Nikolaev
365a77e6b14SNikolay Nikolaev switch (msg.request) {
366a77e6b14SNikolay Nikolaev case VHOST_USER_GET_FEATURES:
36719d55a19SAlex Bennée /* Mandatory for tests to define get_features */
36819d55a19SAlex Bennée g_assert(s->vu_ops->get_features);
36919d55a19SAlex Bennée
370a77e6b14SNikolay Nikolaev /* send back features to qemu */
371a77e6b14SNikolay Nikolaev msg.flags |= VHOST_USER_REPLY_MASK;
37212ebf690SMichael S. Tsirkin msg.size = sizeof(m.payload.u64);
37319d55a19SAlex Bennée
3749294d76cSMarc-André Lureau if (s->test_flags >= TEST_FLAGS_BAD) {
3759294d76cSMarc-André Lureau msg.payload.u64 = 0;
3769294d76cSMarc-André Lureau s->test_flags = TEST_FLAGS_END;
37719d55a19SAlex Bennée } else {
37819d55a19SAlex Bennée msg.payload.u64 = s->vu_ops->get_features(s);
3799294d76cSMarc-André Lureau }
38019d55a19SAlex Bennée
38119d55a19SAlex Bennée qemu_chr_fe_write_all(chr, (uint8_t *) &msg,
38219d55a19SAlex Bennée VHOST_USER_HDR_SIZE + msg.size);
3838a9b6b37SMichael S. Tsirkin break;
3848a9b6b37SMichael S. Tsirkin
3858a9b6b37SMichael S. Tsirkin case VHOST_USER_SET_FEATURES:
386892040dcSDima Stepanov if (s->vu_ops->set_features) {
387892040dcSDima Stepanov s->vu_ops->set_features(s, chr, &msg);
3889294d76cSMarc-André Lureau }
3898a9b6b37SMichael S. Tsirkin break;
3908a9b6b37SMichael S. Tsirkin
39120a4127fSAlex Bennée case VHOST_USER_SET_OWNER:
39220a4127fSAlex Bennée /*
39320a4127fSAlex Bennée * We don't need to do anything here, the remote is just
39420a4127fSAlex Bennée * letting us know it is in charge. Just log it.
39520a4127fSAlex Bennée */
39620a4127fSAlex Bennée qos_printf("set_owner: start of session\n");
39720a4127fSAlex Bennée break;
39820a4127fSAlex Bennée
3998a9b6b37SMichael S. Tsirkin case VHOST_USER_GET_PROTOCOL_FEATURES:
400892040dcSDima Stepanov if (s->vu_ops->get_protocol_features) {
401892040dcSDima Stepanov s->vu_ops->get_protocol_features(s, chr, &msg);
402ed0a8d92SMarc-André Lureau }
403a77e6b14SNikolay Nikolaev break;
404a77e6b14SNikolay Nikolaev
405ff070f60SAlex Bennée case VHOST_USER_GET_CONFIG:
406ff070f60SAlex Bennée /*
407ff070f60SAlex Bennée * Treat GET_CONFIG as a NOP and just reply and let the guest
408ff070f60SAlex Bennée * consider we have updated its memory. Tests currently don't
409ff070f60SAlex Bennée * require working configs.
410ff070f60SAlex Bennée */
411ff070f60SAlex Bennée msg.flags |= VHOST_USER_REPLY_MASK;
412ff070f60SAlex Bennée p = (uint8_t *) &msg;
413ff070f60SAlex Bennée qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
414ff070f60SAlex Bennée break;
415ff070f60SAlex Bennée
41620a4127fSAlex Bennée case VHOST_USER_SET_PROTOCOL_FEATURES:
41720a4127fSAlex Bennée /*
41820a4127fSAlex Bennée * We did set VHOST_USER_F_PROTOCOL_FEATURES so its valid for
41920a4127fSAlex Bennée * the remote end to send this. There is no handshake reply so
42020a4127fSAlex Bennée * just log the details for debugging.
42120a4127fSAlex Bennée */
42220a4127fSAlex Bennée qos_printf("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64);
42320a4127fSAlex Bennée break;
42420a4127fSAlex Bennée
42520a4127fSAlex Bennée /*
42620a4127fSAlex Bennée * A real vhost-user backend would actually set the size and
42720a4127fSAlex Bennée * address of the vrings but we can simply report them.
42820a4127fSAlex Bennée */
42920a4127fSAlex Bennée case VHOST_USER_SET_VRING_NUM:
43020a4127fSAlex Bennée qos_printf("set_vring_num: %d/%d\n",
43120a4127fSAlex Bennée msg.payload.state.index, msg.payload.state.num);
43220a4127fSAlex Bennée break;
43320a4127fSAlex Bennée case VHOST_USER_SET_VRING_ADDR:
43420a4127fSAlex Bennée qos_printf("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n",
43520a4127fSAlex Bennée msg.payload.addr.avail_user_addr,
43620a4127fSAlex Bennée msg.payload.addr.desc_user_addr,
43720a4127fSAlex Bennée msg.payload.addr.used_user_addr);
43820a4127fSAlex Bennée break;
43920a4127fSAlex Bennée
440a77e6b14SNikolay Nikolaev case VHOST_USER_GET_VRING_BASE:
441a77e6b14SNikolay Nikolaev /* send back vring base to qemu */
442a77e6b14SNikolay Nikolaev msg.flags |= VHOST_USER_REPLY_MASK;
44312ebf690SMichael S. Tsirkin msg.size = sizeof(m.payload.state);
44412ebf690SMichael S. Tsirkin msg.payload.state.num = 0;
445a77e6b14SNikolay Nikolaev p = (uint8_t *) &msg;
4465345fdb4SMarc-André Lureau qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
447d08e42a1SMichael S. Tsirkin
448ed0a8d92SMarc-André Lureau assert(msg.payload.state.index < s->queues * 2);
449d08e42a1SMichael S. Tsirkin s->rings &= ~(0x1ULL << msg.payload.state.index);
450acca950cSPaolo Bonzini g_cond_broadcast(&s->data_cond);
451a77e6b14SNikolay Nikolaev break;
452a77e6b14SNikolay Nikolaev
453a77e6b14SNikolay Nikolaev case VHOST_USER_SET_MEM_TABLE:
454a77e6b14SNikolay Nikolaev /* received the mem table */
45512ebf690SMichael S. Tsirkin memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
4565345fdb4SMarc-André Lureau s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
45732a6ebecSMarc-André Lureau G_N_ELEMENTS(s->fds));
458a77e6b14SNikolay Nikolaev
459a77e6b14SNikolay Nikolaev /* signal the test that it can continue */
46004ad1bf6SPaolo Bonzini g_cond_broadcast(&s->data_cond);
461a77e6b14SNikolay Nikolaev break;
462a77e6b14SNikolay Nikolaev
463a77e6b14SNikolay Nikolaev case VHOST_USER_SET_VRING_KICK:
464a77e6b14SNikolay Nikolaev case VHOST_USER_SET_VRING_CALL:
465a77e6b14SNikolay Nikolaev /* consume the fd */
466f72fc169SYuxue Liu if (!qemu_chr_fe_get_msgfds(chr, &fd, 1) && fd < 0) {
467f72fc169SYuxue Liu qos_printf("call fd: %d, do not set non-blocking\n", fd);
468f72fc169SYuxue Liu break;
469f72fc169SYuxue Liu }
470a77e6b14SNikolay Nikolaev /*
471a77e6b14SNikolay Nikolaev * This is a non-blocking eventfd.
472a77e6b14SNikolay Nikolaev * The receive function forces it to be blocking,
473a77e6b14SNikolay Nikolaev * so revert it back to non-blocking.
474a77e6b14SNikolay Nikolaev */
475b2670d1fSMarc-André Lureau g_unix_set_fd_nonblocking(fd, true, &err);
476b2670d1fSMarc-André Lureau g_assert_no_error(err);
477a77e6b14SNikolay Nikolaev break;
478b1819747SMarc-André Lureau
479b1819747SMarc-André Lureau case VHOST_USER_SET_LOG_BASE:
480b1819747SMarc-André Lureau if (s->log_fd != -1) {
481b1819747SMarc-André Lureau close(s->log_fd);
482b1819747SMarc-André Lureau s->log_fd = -1;
483b1819747SMarc-André Lureau }
4845345fdb4SMarc-André Lureau qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
485b1819747SMarc-André Lureau msg.flags |= VHOST_USER_REPLY_MASK;
486b1819747SMarc-André Lureau msg.size = 0;
487b1819747SMarc-André Lureau p = (uint8_t *) &msg;
4885345fdb4SMarc-André Lureau qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
489b1819747SMarc-André Lureau
49004ad1bf6SPaolo Bonzini g_cond_broadcast(&s->data_cond);
491b1819747SMarc-André Lureau break;
492b1819747SMarc-André Lureau
493d08e42a1SMichael S. Tsirkin case VHOST_USER_SET_VRING_BASE:
494ed0a8d92SMarc-André Lureau assert(msg.payload.state.index < s->queues * 2);
495d08e42a1SMichael S. Tsirkin s->rings |= 0x1ULL << msg.payload.state.index;
496acca950cSPaolo Bonzini g_cond_broadcast(&s->data_cond);
4971d9edff7SMarc-André Lureau break;
4981d9edff7SMarc-André Lureau
499ed0a8d92SMarc-André Lureau case VHOST_USER_GET_QUEUE_NUM:
500ed0a8d92SMarc-André Lureau msg.flags |= VHOST_USER_REPLY_MASK;
501ed0a8d92SMarc-André Lureau msg.size = sizeof(m.payload.u64);
502ed0a8d92SMarc-André Lureau msg.payload.u64 = s->queues;
503ed0a8d92SMarc-André Lureau p = (uint8_t *) &msg;
5045345fdb4SMarc-André Lureau qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
505ed0a8d92SMarc-André Lureau break;
506ed0a8d92SMarc-André Lureau
50720a4127fSAlex Bennée case VHOST_USER_SET_VRING_ENABLE:
50820a4127fSAlex Bennée /*
50920a4127fSAlex Bennée * Another case we ignore as we don't need to respond. With a
51020a4127fSAlex Bennée * fully functioning vhost-user we would enable/disable the
51120a4127fSAlex Bennée * vring monitoring.
51220a4127fSAlex Bennée */
51320a4127fSAlex Bennée qos_printf("set_vring(%d)=%s\n", msg.payload.state.index,
51420a4127fSAlex Bennée msg.payload.state.num ? "enabled" : "disabled");
51520a4127fSAlex Bennée break;
51620a4127fSAlex Bennée
517a77e6b14SNikolay Nikolaev default:
51820a4127fSAlex Bennée qos_printf("vhost-user: un-handled message: %d\n", msg.request);
519a77e6b14SNikolay Nikolaev break;
520a77e6b14SNikolay Nikolaev }
521ae31fb54SMarc-André Lureau
5223ee7f21eSPaolo Bonzini out:
523ae31fb54SMarc-André Lureau g_mutex_unlock(&s->data_mutex);
524a77e6b14SNikolay Nikolaev }
525a77e6b14SNikolay Nikolaev
init_hugepagefs(void)5269ee1bb86SPaolo Bonzini static const char *init_hugepagefs(void)
527a77e6b14SNikolay Nikolaev {
5289ee1bb86SPaolo Bonzini #ifdef CONFIG_LINUX
529a3ebd6e0SPaolo Bonzini static const char *hugepagefs;
5309ee1bb86SPaolo Bonzini const char *path = getenv("QTEST_HUGETLBFS_PATH");
531a77e6b14SNikolay Nikolaev struct statfs fs;
532a77e6b14SNikolay Nikolaev int ret;
533a77e6b14SNikolay Nikolaev
534a3ebd6e0SPaolo Bonzini if (hugepagefs) {
535a3ebd6e0SPaolo Bonzini return hugepagefs;
536a3ebd6e0SPaolo Bonzini }
5379ee1bb86SPaolo Bonzini if (!path) {
5389ee1bb86SPaolo Bonzini return NULL;
5399ee1bb86SPaolo Bonzini }
5409ee1bb86SPaolo Bonzini
541a77e6b14SNikolay Nikolaev if (access(path, R_OK | W_OK | X_OK)) {
54230ea13e9SAlex Bennée qos_printf("access on path (%s): %s", path, strerror(errno));
543a3ebd6e0SPaolo Bonzini g_test_fail();
544a77e6b14SNikolay Nikolaev return NULL;
545a77e6b14SNikolay Nikolaev }
546a77e6b14SNikolay Nikolaev
547a77e6b14SNikolay Nikolaev do {
548a77e6b14SNikolay Nikolaev ret = statfs(path, &fs);
549a77e6b14SNikolay Nikolaev } while (ret != 0 && errno == EINTR);
550a77e6b14SNikolay Nikolaev
551a77e6b14SNikolay Nikolaev if (ret != 0) {
55230ea13e9SAlex Bennée qos_printf("statfs on path (%s): %s", path, strerror(errno));
553a3ebd6e0SPaolo Bonzini g_test_fail();
554a77e6b14SNikolay Nikolaev return NULL;
555a77e6b14SNikolay Nikolaev }
556a77e6b14SNikolay Nikolaev
557a77e6b14SNikolay Nikolaev if (fs.f_type != HUGETLBFS_MAGIC) {
55830ea13e9SAlex Bennée qos_printf("Warning: path not on HugeTLBFS: %s", path);
559a3ebd6e0SPaolo Bonzini g_test_fail();
560a77e6b14SNikolay Nikolaev return NULL;
561a77e6b14SNikolay Nikolaev }
562a77e6b14SNikolay Nikolaev
563a3ebd6e0SPaolo Bonzini hugepagefs = path;
564a3ebd6e0SPaolo Bonzini return hugepagefs;
5659ee1bb86SPaolo Bonzini #else
5669ee1bb86SPaolo Bonzini return NULL;
567af3bba76SPaolo Bonzini #endif
5689ee1bb86SPaolo Bonzini }
569a77e6b14SNikolay Nikolaev
test_server_new(const gchar * name,struct vhost_user_ops * ops)570892040dcSDima Stepanov static TestServer *test_server_new(const gchar *name,
571892040dcSDima Stepanov struct vhost_user_ops *ops)
572ae31fb54SMarc-André Lureau {
573ae31fb54SMarc-André Lureau TestServer *server = g_new0(TestServer, 1);
574e6efe236SBin Meng g_autofree const char *tmpfs = NULL;
575e6efe236SBin Meng GError *err = NULL;
576ae31fb54SMarc-André Lureau
5777d0ca3e7SPaolo Bonzini server->context = g_main_context_new();
5787d0ca3e7SPaolo Bonzini server->loop = g_main_loop_new(server->context, FALSE);
5797d0ca3e7SPaolo Bonzini
5807d0ca3e7SPaolo Bonzini /* run the main loop thread so the chardev may operate */
5817d0ca3e7SPaolo Bonzini server->thread = g_thread_new(NULL, thread_function, server->loop);
5827d0ca3e7SPaolo Bonzini
583e6efe236SBin Meng tmpfs = g_dir_make_tmp("vhost-test-XXXXXX", &err);
5844d3f50ebSPaolo Bonzini if (!tmpfs) {
5851c324bf9SBin Meng g_test_message("Can't create temporary directory in %s: %s",
5861c324bf9SBin Meng g_get_tmp_dir(), err->message);
587e6efe236SBin Meng g_error_free(err);
5884d3f50ebSPaolo Bonzini }
5894d3f50ebSPaolo Bonzini g_assert(tmpfs);
5904d3f50ebSPaolo Bonzini
5914d3f50ebSPaolo Bonzini server->tmpfs = g_strdup(tmpfs);
592ae31fb54SMarc-André Lureau server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
593a899b1eaSMarc-André Lureau server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
594ae31fb54SMarc-André Lureau server->chr_name = g_strdup_printf("chr-%s", name);
595ae31fb54SMarc-André Lureau
596ae31fb54SMarc-André Lureau g_mutex_init(&server->data_mutex);
597ae31fb54SMarc-André Lureau g_cond_init(&server->data_cond);
598ae31fb54SMarc-André Lureau
599b1819747SMarc-André Lureau server->log_fd = -1;
600ed0a8d92SMarc-André Lureau server->queues = 1;
601892040dcSDima Stepanov server->vu_ops = ops;
602b1819747SMarc-André Lureau
603ae31fb54SMarc-André Lureau return server;
604ae31fb54SMarc-André Lureau }
605ae31fb54SMarc-André Lureau
chr_event(void * opaque,QEMUChrEvent event)606083b266fSPhilippe Mathieu-Daudé static void chr_event(void *opaque, QEMUChrEvent event)
6079294d76cSMarc-André Lureau {
6089294d76cSMarc-André Lureau TestServer *s = opaque;
6099294d76cSMarc-André Lureau
6109294d76cSMarc-André Lureau if (s->test_flags == TEST_FLAGS_END &&
6119294d76cSMarc-André Lureau event == CHR_EVENT_CLOSED) {
6129294d76cSMarc-André Lureau s->test_flags = TEST_FLAGS_OK;
6139294d76cSMarc-André Lureau }
6149294d76cSMarc-André Lureau }
6159294d76cSMarc-André Lureau
test_server_create_chr(TestServer * server,const gchar * opt)6164616e359SMarc-André Lureau static void test_server_create_chr(TestServer *server, const gchar *opt)
6174616e359SMarc-André Lureau {
61855c26982SAlex Bennée g_autofree gchar *chr_path = g_strdup_printf("unix:%s%s",
61955c26982SAlex Bennée server->socket_path, opt);
6200ec7b3e7SMarc-André Lureau Chardev *chr;
6215345fdb4SMarc-André Lureau
6227d0ca3e7SPaolo Bonzini chr = qemu_chr_new(server->chr_name, chr_path, server->context);
62355c26982SAlex Bennée g_assert(chr);
6244616e359SMarc-André Lureau
6255345fdb4SMarc-André Lureau qemu_chr_fe_init(&server->chr, chr, &error_abort);
6265345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
6277d0ca3e7SPaolo Bonzini chr_event, NULL, server, server->context, true);
6284616e359SMarc-André Lureau }
6294616e359SMarc-André Lureau
test_server_listen(TestServer * server)6304616e359SMarc-André Lureau static void test_server_listen(TestServer *server)
6314616e359SMarc-André Lureau {
632991c180dSPaolo Bonzini test_server_create_chr(server, ",server=on,wait=off");
6334616e359SMarc-André Lureau }
6344616e359SMarc-André Lureau
test_server_free(TestServer * server)6357d0ca3e7SPaolo Bonzini static void test_server_free(TestServer *server)
636ae31fb54SMarc-André Lureau {
6374d3f50ebSPaolo Bonzini int i, ret;
638ae31fb54SMarc-André Lureau
6397d0ca3e7SPaolo Bonzini /* finish the helper thread and dispatch pending sources */
6407d0ca3e7SPaolo Bonzini g_main_loop_quit(server->loop);
6417d0ca3e7SPaolo Bonzini g_thread_join(server->thread);
6427d0ca3e7SPaolo Bonzini while (g_main_context_pending(NULL)) {
6437d0ca3e7SPaolo Bonzini g_main_context_iteration(NULL, TRUE);
6447d0ca3e7SPaolo Bonzini }
6457d0ca3e7SPaolo Bonzini
6464d3f50ebSPaolo Bonzini unlink(server->socket_path);
6474d3f50ebSPaolo Bonzini g_free(server->socket_path);
6484d3f50ebSPaolo Bonzini
6494d3f50ebSPaolo Bonzini unlink(server->mig_path);
6504d3f50ebSPaolo Bonzini g_free(server->mig_path);
6514d3f50ebSPaolo Bonzini
6524d3f50ebSPaolo Bonzini ret = rmdir(server->tmpfs);
6534d3f50ebSPaolo Bonzini if (ret != 0) {
6544d3f50ebSPaolo Bonzini g_test_message("unable to rmdir: path (%s): %s",
6554d3f50ebSPaolo Bonzini server->tmpfs, strerror(errno));
6564d3f50ebSPaolo Bonzini }
6575411f3d0SMarc-André Lureau g_free(server->tmpfs);
6584d3f50ebSPaolo Bonzini
6591ce2610cSMarc-André Lureau qemu_chr_fe_deinit(&server->chr, true);
660ae31fb54SMarc-André Lureau
661ae31fb54SMarc-André Lureau for (i = 0; i < server->fds_num; i++) {
662ae31fb54SMarc-André Lureau close(server->fds[i]);
663ae31fb54SMarc-André Lureau }
664ae31fb54SMarc-André Lureau
665b1819747SMarc-André Lureau if (server->log_fd != -1) {
666b1819747SMarc-André Lureau close(server->log_fd);
667b1819747SMarc-André Lureau }
668b1819747SMarc-André Lureau
669b1819747SMarc-André Lureau g_free(server->chr_name);
6700c0eb302SMarc-André Lureau
6717d0ca3e7SPaolo Bonzini g_main_loop_unref(server->loop);
6727d0ca3e7SPaolo Bonzini g_main_context_unref(server->context);
6735411f3d0SMarc-André Lureau g_cond_clear(&server->data_cond);
6745411f3d0SMarc-André Lureau g_mutex_clear(&server->data_mutex);
675ae31fb54SMarc-André Lureau g_free(server);
676ae31fb54SMarc-André Lureau }
677ae31fb54SMarc-André Lureau
wait_for_log_fd(TestServer * s)678b1819747SMarc-André Lureau static void wait_for_log_fd(TestServer *s)
679b1819747SMarc-André Lureau {
680b1819747SMarc-André Lureau gint64 end_time;
681b1819747SMarc-André Lureau
682b1819747SMarc-André Lureau g_mutex_lock(&s->data_mutex);
683b1819747SMarc-André Lureau end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
684b1819747SMarc-André Lureau while (s->log_fd == -1) {
685b1819747SMarc-André Lureau if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
686b1819747SMarc-André Lureau /* timeout has passed */
687b1819747SMarc-André Lureau g_assert(s->log_fd != -1);
688b1819747SMarc-André Lureau break;
689b1819747SMarc-André Lureau }
690b1819747SMarc-André Lureau }
691b1819747SMarc-André Lureau
692b1819747SMarc-André Lureau g_mutex_unlock(&s->data_mutex);
693b1819747SMarc-André Lureau }
694b1819747SMarc-André Lureau
write_guest_mem(TestServer * s,uint32_t seed)6953a87d009SPeter Maydell static void write_guest_mem(TestServer *s, uint32_t seed)
696b1819747SMarc-André Lureau {
697b1819747SMarc-André Lureau uint32_t *guest_mem;
698b1819747SMarc-André Lureau int i, j;
699b1819747SMarc-André Lureau size_t size;
700b1819747SMarc-André Lureau
701b1819747SMarc-André Lureau /* iterate all regions */
702b1819747SMarc-André Lureau for (i = 0; i < s->fds_num; i++) {
703b1819747SMarc-André Lureau
704b1819747SMarc-André Lureau /* We'll write only the region statring at 0x0 */
705b1819747SMarc-André Lureau if (s->memory.regions[i].guest_phys_addr != 0x0) {
706b1819747SMarc-André Lureau continue;
707b1819747SMarc-André Lureau }
708b1819747SMarc-André Lureau
709b1819747SMarc-André Lureau g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
710b1819747SMarc-André Lureau
711b1819747SMarc-André Lureau size = s->memory.regions[i].memory_size +
712b1819747SMarc-André Lureau s->memory.regions[i].mmap_offset;
713b1819747SMarc-André Lureau
714b1819747SMarc-André Lureau guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
715b1819747SMarc-André Lureau MAP_SHARED, s->fds[i], 0);
716b1819747SMarc-André Lureau
717b1819747SMarc-André Lureau g_assert(guest_mem != MAP_FAILED);
718b1819747SMarc-André Lureau guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
719b1819747SMarc-André Lureau
720b1819747SMarc-André Lureau for (j = 0; j < 256; j++) {
721b1819747SMarc-André Lureau guest_mem[j] = seed + j;
722b1819747SMarc-André Lureau }
723b1819747SMarc-André Lureau
724b1819747SMarc-André Lureau munmap(guest_mem, s->memory.regions[i].memory_size);
725b1819747SMarc-André Lureau break;
726b1819747SMarc-André Lureau }
727b1819747SMarc-André Lureau }
728b1819747SMarc-André Lureau
get_log_size(TestServer * s)729b1819747SMarc-André Lureau static guint64 get_log_size(TestServer *s)
730b1819747SMarc-André Lureau {
731b1819747SMarc-André Lureau guint64 log_size = 0;
732b1819747SMarc-André Lureau int i;
733b1819747SMarc-André Lureau
734b1819747SMarc-André Lureau for (i = 0; i < s->memory.nregions; ++i) {
735b1819747SMarc-André Lureau VhostUserMemoryRegion *reg = &s->memory.regions[i];
736b1819747SMarc-André Lureau guint64 last = range_get_last(reg->guest_phys_addr,
737b1819747SMarc-André Lureau reg->memory_size);
738b1819747SMarc-André Lureau log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
739b1819747SMarc-André Lureau }
740b1819747SMarc-André Lureau
741b1819747SMarc-André Lureau return log_size;
742b1819747SMarc-André Lureau }
743b1819747SMarc-André Lureau
7441d9edff7SMarc-André Lureau typedef struct TestMigrateSource {
7451d9edff7SMarc-André Lureau GSource source;
7461d9edff7SMarc-André Lureau TestServer *src;
7471d9edff7SMarc-André Lureau TestServer *dest;
7481d9edff7SMarc-André Lureau } TestMigrateSource;
7491d9edff7SMarc-André Lureau
7501d9edff7SMarc-André Lureau static gboolean
test_migrate_source_check(GSource * source)7511d9edff7SMarc-André Lureau test_migrate_source_check(GSource *source)
7521d9edff7SMarc-André Lureau {
7531d9edff7SMarc-André Lureau TestMigrateSource *t = (TestMigrateSource *)source;
754d08e42a1SMichael S. Tsirkin gboolean overlap = t->src->rings && t->dest->rings;
7551d9edff7SMarc-André Lureau
7561d9edff7SMarc-André Lureau g_assert(!overlap);
7571d9edff7SMarc-André Lureau
7581d9edff7SMarc-André Lureau return FALSE;
7591d9edff7SMarc-André Lureau }
7601d9edff7SMarc-André Lureau
7611d9edff7SMarc-André Lureau GSourceFuncs test_migrate_source_funcs = {
76245ce5126SMarc-André Lureau .check = test_migrate_source_check,
7631d9edff7SMarc-André Lureau };
7641d9edff7SMarc-André Lureau
vhost_user_test_cleanup(void * s)765a3ebd6e0SPaolo Bonzini static void vhost_user_test_cleanup(void *s)
766e364c703SMaxime Coquelin {
767a3ebd6e0SPaolo Bonzini TestServer *server = s;
768e364c703SMaxime Coquelin
769a3ebd6e0SPaolo Bonzini qos_invalidate_command_line();
770e364c703SMaxime Coquelin test_server_free(server);
771e364c703SMaxime Coquelin }
772e364c703SMaxime Coquelin
vhost_user_test_setup(GString * cmd_line,void * arg)773a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup(GString *cmd_line, void *arg)
774b1819747SMarc-André Lureau {
775892040dcSDima Stepanov TestServer *server = test_server_new("vhost-user-test", arg);
776a3ebd6e0SPaolo Bonzini test_server_listen(server);
777a3ebd6e0SPaolo Bonzini
778a3ebd6e0SPaolo Bonzini append_mem_opts(server, cmd_line, 256, TEST_MEMFD_AUTO);
779892040dcSDima Stepanov server->vu_ops->append_opts(server, cmd_line, "");
780a3ebd6e0SPaolo Bonzini
781a3ebd6e0SPaolo Bonzini g_test_queue_destroy(vhost_user_test_cleanup, server);
782a3ebd6e0SPaolo Bonzini
783a3ebd6e0SPaolo Bonzini return server;
784a3ebd6e0SPaolo Bonzini }
785a3ebd6e0SPaolo Bonzini
vhost_user_test_setup_memfd(GString * cmd_line,void * arg)786a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup_memfd(GString *cmd_line, void *arg)
787a3ebd6e0SPaolo Bonzini {
788892040dcSDima Stepanov TestServer *server = test_server_new("vhost-user-test", arg);
789a3ebd6e0SPaolo Bonzini test_server_listen(server);
790a3ebd6e0SPaolo Bonzini
791a3ebd6e0SPaolo Bonzini append_mem_opts(server, cmd_line, 256, TEST_MEMFD_YES);
792892040dcSDima Stepanov server->vu_ops->append_opts(server, cmd_line, "");
793a3ebd6e0SPaolo Bonzini
794a3ebd6e0SPaolo Bonzini g_test_queue_destroy(vhost_user_test_cleanup, server);
795a3ebd6e0SPaolo Bonzini
796a3ebd6e0SPaolo Bonzini return server;
797a3ebd6e0SPaolo Bonzini }
798a3ebd6e0SPaolo Bonzini
vhost_user_test_setup_shm(GString * cmd_line,void * arg)7990173ce4bSStefano Garzarella static void *vhost_user_test_setup_shm(GString *cmd_line, void *arg)
8000173ce4bSStefano Garzarella {
8010173ce4bSStefano Garzarella TestServer *server = test_server_new("vhost-user-test", arg);
8020173ce4bSStefano Garzarella test_server_listen(server);
8030173ce4bSStefano Garzarella
8040173ce4bSStefano Garzarella append_mem_opts(server, cmd_line, 256, TEST_MEMFD_SHM);
8050173ce4bSStefano Garzarella server->vu_ops->append_opts(server, cmd_line, "");
8060173ce4bSStefano Garzarella
8070173ce4bSStefano Garzarella g_test_queue_destroy(vhost_user_test_cleanup, server);
8080173ce4bSStefano Garzarella
8090173ce4bSStefano Garzarella return server;
8100173ce4bSStefano Garzarella }
8110173ce4bSStefano Garzarella
test_read_guest_mem(void * obj,void * arg,QGuestAllocator * alloc)812a3ebd6e0SPaolo Bonzini static void test_read_guest_mem(void *obj, void *arg, QGuestAllocator *alloc)
813a3ebd6e0SPaolo Bonzini {
814a3ebd6e0SPaolo Bonzini TestServer *server = arg;
815a3ebd6e0SPaolo Bonzini
816a3ebd6e0SPaolo Bonzini if (!wait_for_fds(server)) {
817a3ebd6e0SPaolo Bonzini return;
818a3ebd6e0SPaolo Bonzini }
819a3ebd6e0SPaolo Bonzini
820a3ebd6e0SPaolo Bonzini read_guest_mem_server(global_qtest, server);
821a3ebd6e0SPaolo Bonzini }
822a3ebd6e0SPaolo Bonzini
test_migrate(void * obj,void * arg,QGuestAllocator * alloc)823a3ebd6e0SPaolo Bonzini static void test_migrate(void *obj, void *arg, QGuestAllocator *alloc)
824a3ebd6e0SPaolo Bonzini {
825a3ebd6e0SPaolo Bonzini TestServer *s = arg;
82699fd3178SThomas Huth TestServer *dest;
82799fd3178SThomas Huth GString *dest_cmdline;
82899fd3178SThomas Huth char *uri;
829a3ebd6e0SPaolo Bonzini QTestState *to;
8301d9edff7SMarc-André Lureau GSource *source;
831b1819747SMarc-André Lureau QDict *rsp;
832b1819747SMarc-André Lureau guint8 *log;
833b1819747SMarc-André Lureau guint64 size;
834b1819747SMarc-André Lureau
8353b72ca38SPaolo Bonzini if (!wait_for_fds(s)) {
836a3ebd6e0SPaolo Bonzini return;
8373b72ca38SPaolo Bonzini }
8383b72ca38SPaolo Bonzini
839892040dcSDima Stepanov dest = test_server_new("dest", s->vu_ops);
84099fd3178SThomas Huth dest_cmdline = g_string_new(qos_get_current_command_line());
84199fd3178SThomas Huth uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
84299fd3178SThomas Huth
843b1819747SMarc-André Lureau size = get_log_size(s);
8440f9fe580SPaolo Bonzini g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
845b1819747SMarc-André Lureau
846a3ebd6e0SPaolo Bonzini test_server_listen(dest);
847a3ebd6e0SPaolo Bonzini g_string_append_printf(dest_cmdline, " -incoming %s", uri);
848a3ebd6e0SPaolo Bonzini append_mem_opts(dest, dest_cmdline, 256, TEST_MEMFD_AUTO);
849892040dcSDima Stepanov dest->vu_ops->append_opts(dest, dest_cmdline, "");
850a3ebd6e0SPaolo Bonzini to = qtest_init(dest_cmdline->str);
851a3ebd6e0SPaolo Bonzini
852a3ebd6e0SPaolo Bonzini /* This would be where you call qos_allocate_objects(to, NULL), if you want
853a3ebd6e0SPaolo Bonzini * to talk to the QVirtioNet object on the destination.
854a3ebd6e0SPaolo Bonzini */
855b1819747SMarc-André Lureau
8561d9edff7SMarc-André Lureau source = g_source_new(&test_migrate_source_funcs,
8571d9edff7SMarc-André Lureau sizeof(TestMigrateSource));
8581d9edff7SMarc-André Lureau ((TestMigrateSource *)source)->src = s;
8591d9edff7SMarc-André Lureau ((TestMigrateSource *)source)->dest = dest;
8607d0ca3e7SPaolo Bonzini g_source_attach(source, s->context);
8611d9edff7SMarc-André Lureau
862b1819747SMarc-André Lureau /* slow down migration to have time to fiddle with log */
863b1819747SMarc-André Lureau /* TODO: qtest could learn to break on some places */
864cbde7be9SDaniel P. Berrangé rsp = qmp("{ 'execute': 'migrate-set-parameters',"
865cbde7be9SDaniel P. Berrangé "'arguments': { 'max-bandwidth': 10 } }");
866b1819747SMarc-André Lureau g_assert(qdict_haskey(rsp, "return"));
867cb3e7f08SMarc-André Lureau qobject_unref(rsp);
868b1819747SMarc-André Lureau
869015715f5SMarkus Armbruster rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
870b1819747SMarc-André Lureau g_assert(qdict_haskey(rsp, "return"));
871cb3e7f08SMarc-André Lureau qobject_unref(rsp);
872b1819747SMarc-André Lureau
873b1819747SMarc-André Lureau wait_for_log_fd(s);
874b1819747SMarc-André Lureau
875b1819747SMarc-André Lureau log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
876b1819747SMarc-André Lureau g_assert(log != MAP_FAILED);
877b1819747SMarc-André Lureau
878b1819747SMarc-André Lureau /* modify first page */
879b1819747SMarc-André Lureau write_guest_mem(s, 0x42);
880b1819747SMarc-André Lureau log[0] = 1;
881b1819747SMarc-André Lureau munmap(log, size);
882b1819747SMarc-André Lureau
883b1819747SMarc-André Lureau /* speed things up */
884cbde7be9SDaniel P. Berrangé rsp = qmp("{ 'execute': 'migrate-set-parameters',"
885cbde7be9SDaniel P. Berrangé "'arguments': { 'max-bandwidth': 0 } }");
886b1819747SMarc-André Lureau g_assert(qdict_haskey(rsp, "return"));
887cb3e7f08SMarc-André Lureau qobject_unref(rsp);
888b1819747SMarc-André Lureau
889b1819747SMarc-André Lureau qmp_eventwait("STOP");
890bae6b59dSPaolo Bonzini qtest_qmp_eventwait(to, "RESUME");
891b1819747SMarc-André Lureau
892bae6b59dSPaolo Bonzini g_assert(wait_for_fds(dest));
893bae6b59dSPaolo Bonzini read_guest_mem_server(to, dest);
894b1819747SMarc-André Lureau
8951d9edff7SMarc-André Lureau g_source_destroy(source);
8961d9edff7SMarc-André Lureau g_source_unref(source);
8971d9edff7SMarc-André Lureau
898a3ebd6e0SPaolo Bonzini qtest_quit(to);
899b1819747SMarc-André Lureau test_server_free(dest);
900a899b1eaSMarc-André Lureau g_free(uri);
90199fd3178SThomas Huth g_string_free(dest_cmdline, true);
902b1819747SMarc-André Lureau }
903b1819747SMarc-André Lureau
wait_for_rings_started(TestServer * s,size_t count)9044616e359SMarc-André Lureau static void wait_for_rings_started(TestServer *s, size_t count)
9054616e359SMarc-André Lureau {
9064616e359SMarc-André Lureau gint64 end_time;
9074616e359SMarc-André Lureau
9084616e359SMarc-André Lureau g_mutex_lock(&s->data_mutex);
9094616e359SMarc-André Lureau end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
9104616e359SMarc-André Lureau while (ctpop64(s->rings) != count) {
9114616e359SMarc-André Lureau if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
9124616e359SMarc-André Lureau /* timeout has passed */
9134616e359SMarc-André Lureau g_assert_cmpint(ctpop64(s->rings), ==, count);
9144616e359SMarc-André Lureau break;
9154616e359SMarc-André Lureau }
9164616e359SMarc-André Lureau }
9174616e359SMarc-André Lureau
9184616e359SMarc-André Lureau g_mutex_unlock(&s->data_mutex);
9194616e359SMarc-André Lureau }
9204616e359SMarc-André Lureau
test_server_connect(TestServer * server)92120784087SPhilippe Mathieu-Daudé static inline void test_server_connect(TestServer *server)
92220784087SPhilippe Mathieu-Daudé {
92396e610b2SDaniil Tatianin test_server_create_chr(server, ",reconnect-ms=1000");
92420784087SPhilippe Mathieu-Daudé }
92520784087SPhilippe Mathieu-Daudé
9264616e359SMarc-André Lureau static gboolean
reconnect_cb(gpointer user_data)9274616e359SMarc-André Lureau reconnect_cb(gpointer user_data)
9284616e359SMarc-André Lureau {
9294616e359SMarc-André Lureau TestServer *s = user_data;
9304616e359SMarc-André Lureau
9315345fdb4SMarc-André Lureau qemu_chr_fe_disconnect(&s->chr);
9324616e359SMarc-André Lureau
9334616e359SMarc-André Lureau return FALSE;
9344616e359SMarc-André Lureau }
9354616e359SMarc-André Lureau
9364616e359SMarc-André Lureau static gpointer
connect_thread(gpointer data)9374616e359SMarc-André Lureau connect_thread(gpointer data)
9384616e359SMarc-André Lureau {
9394616e359SMarc-André Lureau TestServer *s = data;
9404616e359SMarc-André Lureau
9414616e359SMarc-André Lureau /* wait for qemu to start before first try, to avoid extra warnings */
9424616e359SMarc-André Lureau g_usleep(G_USEC_PER_SEC);
9434616e359SMarc-André Lureau test_server_connect(s);
9444616e359SMarc-André Lureau
9454616e359SMarc-André Lureau return NULL;
9464616e359SMarc-André Lureau }
9474616e359SMarc-André Lureau
vhost_user_test_setup_reconnect(GString * cmd_line,void * arg)948a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg)
9494616e359SMarc-André Lureau {
950892040dcSDima Stepanov TestServer *s = test_server_new("reconnect", arg);
9514616e359SMarc-André Lureau
9524ab25462SAkihiko Odaki g_thread_unref(g_thread_new("connect", connect_thread, s));
953a3ebd6e0SPaolo Bonzini append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
954991c180dSPaolo Bonzini s->vu_ops->append_opts(s, cmd_line, ",server=on");
9554616e359SMarc-André Lureau
956a3ebd6e0SPaolo Bonzini g_test_queue_destroy(vhost_user_test_cleanup, s);
957a3ebd6e0SPaolo Bonzini
958a3ebd6e0SPaolo Bonzini return s;
959a3ebd6e0SPaolo Bonzini }
960a3ebd6e0SPaolo Bonzini
test_reconnect(void * obj,void * arg,QGuestAllocator * alloc)961a3ebd6e0SPaolo Bonzini static void test_reconnect(void *obj, void *arg, QGuestAllocator *alloc)
962a3ebd6e0SPaolo Bonzini {
963a3ebd6e0SPaolo Bonzini TestServer *s = arg;
964a3ebd6e0SPaolo Bonzini GSource *src;
965a3ebd6e0SPaolo Bonzini
9663b72ca38SPaolo Bonzini if (!wait_for_fds(s)) {
967a3ebd6e0SPaolo Bonzini return;
9683b72ca38SPaolo Bonzini }
9693b72ca38SPaolo Bonzini
9704616e359SMarc-André Lureau wait_for_rings_started(s, 2);
9714616e359SMarc-André Lureau
9724616e359SMarc-André Lureau /* reconnect */
9734616e359SMarc-André Lureau s->fds_num = 0;
9744616e359SMarc-André Lureau s->rings = 0;
9757d0ca3e7SPaolo Bonzini src = g_idle_source_new();
9767d0ca3e7SPaolo Bonzini g_source_set_callback(src, reconnect_cb, s, NULL);
9777d0ca3e7SPaolo Bonzini g_source_attach(src, s->context);
9787d0ca3e7SPaolo Bonzini g_source_unref(src);
9793b72ca38SPaolo Bonzini g_assert(wait_for_fds(s));
9804616e359SMarc-André Lureau wait_for_rings_started(s, 2);
9814616e359SMarc-André Lureau }
9824616e359SMarc-André Lureau
vhost_user_test_setup_connect_fail(GString * cmd_line,void * arg)983a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg)
9845d443f5aSMarc-André Lureau {
985892040dcSDima Stepanov TestServer *s = test_server_new("connect-fail", arg);
9865d443f5aSMarc-André Lureau
9875d443f5aSMarc-André Lureau s->test_fail = true;
988a3ebd6e0SPaolo Bonzini
9894ab25462SAkihiko Odaki g_thread_unref(g_thread_new("connect", connect_thread, s));
990a3ebd6e0SPaolo Bonzini append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
991991c180dSPaolo Bonzini s->vu_ops->append_opts(s, cmd_line, ",server=on");
9925d443f5aSMarc-André Lureau
993a3ebd6e0SPaolo Bonzini g_test_queue_destroy(vhost_user_test_cleanup, s);
9945d443f5aSMarc-André Lureau
995a3ebd6e0SPaolo Bonzini return s;
9965d443f5aSMarc-André Lureau }
9975d443f5aSMarc-André Lureau
vhost_user_test_setup_flags_mismatch(GString * cmd_line,void * arg)998a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg)
9999294d76cSMarc-André Lureau {
1000892040dcSDima Stepanov TestServer *s = test_server_new("flags-mismatch", arg);
10019294d76cSMarc-André Lureau
10029294d76cSMarc-André Lureau s->test_flags = TEST_FLAGS_DISCONNECT;
10039294d76cSMarc-André Lureau
10044ab25462SAkihiko Odaki g_thread_unref(g_thread_new("connect", connect_thread, s));
1005a3ebd6e0SPaolo Bonzini append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
1006991c180dSPaolo Bonzini s->vu_ops->append_opts(s, cmd_line, ",server=on");
1007a3ebd6e0SPaolo Bonzini
1008a3ebd6e0SPaolo Bonzini g_test_queue_destroy(vhost_user_test_cleanup, s);
1009a3ebd6e0SPaolo Bonzini
1010a3ebd6e0SPaolo Bonzini return s;
1011a3ebd6e0SPaolo Bonzini }
1012a3ebd6e0SPaolo Bonzini
test_vhost_user_started(void * obj,void * arg,QGuestAllocator * alloc)1013a3ebd6e0SPaolo Bonzini static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc)
1014a3ebd6e0SPaolo Bonzini {
1015a3ebd6e0SPaolo Bonzini TestServer *s = arg;
1016a3ebd6e0SPaolo Bonzini
10173b72ca38SPaolo Bonzini if (!wait_for_fds(s)) {
1018a3ebd6e0SPaolo Bonzini return;
10193b72ca38SPaolo Bonzini }
10209294d76cSMarc-André Lureau wait_for_rings_started(s, 2);
10219294d76cSMarc-André Lureau }
10229294d76cSMarc-André Lureau
vhost_user_test_setup_multiqueue(GString * cmd_line,void * arg)1023a3ebd6e0SPaolo Bonzini static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg)
10249294d76cSMarc-André Lureau {
1025a3ebd6e0SPaolo Bonzini TestServer *s = vhost_user_test_setup(cmd_line, arg);
10269294d76cSMarc-André Lureau
1027459f5d29SMaxime Coquelin s->queues = 2;
1028a3ebd6e0SPaolo Bonzini g_string_append_printf(cmd_line,
1029a3ebd6e0SPaolo Bonzini " -set netdev.hs0.queues=%d"
1030a3ebd6e0SPaolo Bonzini " -global virtio-net-pci.vectors=%d",
1031a3ebd6e0SPaolo Bonzini s->queues, s->queues * 2 + 2);
1032ed0a8d92SMarc-André Lureau
1033a3ebd6e0SPaolo Bonzini return s;
10348e029fd6SMarc-André Lureau }
1035ed0a8d92SMarc-André Lureau
test_multiqueue(void * obj,void * arg,QGuestAllocator * alloc)1036a3ebd6e0SPaolo Bonzini static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
1037a3ebd6e0SPaolo Bonzini {
1038a3ebd6e0SPaolo Bonzini TestServer *s = arg;
1039ed0a8d92SMarc-André Lureau
1040459f5d29SMaxime Coquelin wait_for_rings_started(s, s->queues * 2);
1041ed0a8d92SMarc-André Lureau }
1042ed0a8d92SMarc-André Lureau
104319d55a19SAlex Bennée
vu_net_get_features(TestServer * s)104419d55a19SAlex Bennée static uint64_t vu_net_get_features(TestServer *s)
104519d55a19SAlex Bennée {
1046cd6406dfSThomas Huth uint64_t features = 0x1ULL << VIRTIO_F_VERSION_1 |
1047cd6406dfSThomas Huth 0x1ULL << VHOST_F_LOG_ALL |
104819d55a19SAlex Bennée 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
104919d55a19SAlex Bennée
105019d55a19SAlex Bennée if (s->queues > 1) {
105119d55a19SAlex Bennée features |= 0x1ULL << VIRTIO_NET_F_MQ;
105219d55a19SAlex Bennée }
105319d55a19SAlex Bennée
105419d55a19SAlex Bennée return features;
105519d55a19SAlex Bennée }
105619d55a19SAlex Bennée
vu_net_set_features(TestServer * s,CharBackend * chr,VhostUserMsg * msg)1057892040dcSDima Stepanov static void vu_net_set_features(TestServer *s, CharBackend *chr,
1058892040dcSDima Stepanov VhostUserMsg *msg)
1059892040dcSDima Stepanov {
1060f48d994fSAlex Bennée g_assert(msg->payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES));
1061892040dcSDima Stepanov if (s->test_flags == TEST_FLAGS_DISCONNECT) {
1062892040dcSDima Stepanov qemu_chr_fe_disconnect(chr);
1063892040dcSDima Stepanov s->test_flags = TEST_FLAGS_BAD;
1064892040dcSDima Stepanov }
1065892040dcSDima Stepanov }
1066892040dcSDima Stepanov
vu_net_get_protocol_features(TestServer * s,CharBackend * chr,VhostUserMsg * msg)1067892040dcSDima Stepanov static void vu_net_get_protocol_features(TestServer *s, CharBackend *chr,
1068892040dcSDima Stepanov VhostUserMsg *msg)
1069892040dcSDima Stepanov {
1070892040dcSDima Stepanov /* send back features to qemu */
1071892040dcSDima Stepanov msg->flags |= VHOST_USER_REPLY_MASK;
1072892040dcSDima Stepanov msg->size = sizeof(m.payload.u64);
1073892040dcSDima Stepanov msg->payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
1074892040dcSDima Stepanov msg->payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
1075892040dcSDima Stepanov if (s->queues > 1) {
1076892040dcSDima Stepanov msg->payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
1077892040dcSDima Stepanov }
1078892040dcSDima Stepanov qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
1079892040dcSDima Stepanov }
1080892040dcSDima Stepanov
1081892040dcSDima Stepanov /* Each VHOST-USER device should have its ops structure defined. */
1082892040dcSDima Stepanov static struct vhost_user_ops g_vu_net_ops = {
1083892040dcSDima Stepanov .type = VHOST_USER_NET,
1084892040dcSDima Stepanov
1085892040dcSDima Stepanov .append_opts = append_vhost_net_opts,
1086892040dcSDima Stepanov
108719d55a19SAlex Bennée .get_features = vu_net_get_features,
1088892040dcSDima Stepanov .set_features = vu_net_set_features,
1089892040dcSDima Stepanov .get_protocol_features = vu_net_get_protocol_features,
1090892040dcSDima Stepanov };
1091892040dcSDima Stepanov
register_vhost_user_test(void)1092a3ebd6e0SPaolo Bonzini static void register_vhost_user_test(void)
1093a77e6b14SNikolay Nikolaev {
1094a3ebd6e0SPaolo Bonzini QOSGraphTestOptions opts = {
1095a3ebd6e0SPaolo Bonzini .before = vhost_user_test_setup,
1096a3ebd6e0SPaolo Bonzini .subprocess = true,
1097892040dcSDima Stepanov .arg = &g_vu_net_ops,
1098a3ebd6e0SPaolo Bonzini };
1099a77e6b14SNikolay Nikolaev
1100ae31fb54SMarc-André Lureau qemu_add_opts(&qemu_chardev_opts);
1101a77e6b14SNikolay Nikolaev
1102a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/read-guest-mem/memfile",
1103a3ebd6e0SPaolo Bonzini "virtio-net",
1104a3ebd6e0SPaolo Bonzini test_read_guest_mem, &opts);
1105a3ebd6e0SPaolo Bonzini
11060173ce4bSStefano Garzarella opts.before = vhost_user_test_setup_shm;
11070173ce4bSStefano Garzarella qos_add_test("vhost-user/read-guest-mem/shm",
11080173ce4bSStefano Garzarella "virtio-net",
11090173ce4bSStefano Garzarella test_read_guest_mem, &opts);
11100173ce4bSStefano Garzarella
11114a66c7a9SIlya Maximets if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
1112a3ebd6e0SPaolo Bonzini opts.before = vhost_user_test_setup_memfd;
1113a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/read-guest-mem/memfd",
1114a3ebd6e0SPaolo Bonzini "virtio-net",
1115a3ebd6e0SPaolo Bonzini test_read_guest_mem, &opts);
11168e029fd6SMarc-André Lureau }
1117a3ebd6e0SPaolo Bonzini
1118a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/migrate",
1119a3ebd6e0SPaolo Bonzini "virtio-net",
1120a3ebd6e0SPaolo Bonzini test_migrate, &opts);
112120784087SPhilippe Mathieu-Daudé
1122a3ebd6e0SPaolo Bonzini opts.before = vhost_user_test_setup_reconnect;
1123a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/reconnect", "virtio-net",
1124a3ebd6e0SPaolo Bonzini test_reconnect, &opts);
1125a3ebd6e0SPaolo Bonzini
1126a3ebd6e0SPaolo Bonzini opts.before = vhost_user_test_setup_connect_fail;
1127a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/connect-fail", "virtio-net",
1128a3ebd6e0SPaolo Bonzini test_vhost_user_started, &opts);
1129a3ebd6e0SPaolo Bonzini
1130a3ebd6e0SPaolo Bonzini opts.before = vhost_user_test_setup_flags_mismatch;
1131a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/flags-mismatch", "virtio-net",
1132a3ebd6e0SPaolo Bonzini test_vhost_user_started, &opts);
1133a77e6b14SNikolay Nikolaev
1134a3ebd6e0SPaolo Bonzini opts.before = vhost_user_test_setup_multiqueue;
1135a3ebd6e0SPaolo Bonzini opts.edge.extra_device_opts = "mq=on";
1136a3ebd6e0SPaolo Bonzini qos_add_test("vhost-user/multiqueue",
1137a3ebd6e0SPaolo Bonzini "virtio-net",
1138a3ebd6e0SPaolo Bonzini test_multiqueue, &opts);
1139a77e6b14SNikolay Nikolaev }
1140a3ebd6e0SPaolo Bonzini libqos_init(register_vhost_user_test);
11418fcfc823SAlex Bennée
vu_gpio_get_features(TestServer * s)11428fcfc823SAlex Bennée static uint64_t vu_gpio_get_features(TestServer *s)
11438fcfc823SAlex Bennée {
11448fcfc823SAlex Bennée return 0x1ULL << VIRTIO_F_VERSION_1 |
11458fcfc823SAlex Bennée 0x1ULL << VIRTIO_GPIO_F_IRQ |
11468fcfc823SAlex Bennée 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
11478fcfc823SAlex Bennée }
11488fcfc823SAlex Bennée
11498fcfc823SAlex Bennée /*
11508fcfc823SAlex Bennée * This stub can't handle all the message types but we should reply
11518fcfc823SAlex Bennée * that we support VHOST_USER_PROTOCOL_F_CONFIG as gpio would use it
11528fcfc823SAlex Bennée * talking to a read vhost-user daemon.
11538fcfc823SAlex Bennée */
vu_gpio_get_protocol_features(TestServer * s,CharBackend * chr,VhostUserMsg * msg)11548fcfc823SAlex Bennée static void vu_gpio_get_protocol_features(TestServer *s, CharBackend *chr,
11558fcfc823SAlex Bennée VhostUserMsg *msg)
11568fcfc823SAlex Bennée {
11578fcfc823SAlex Bennée /* send back features to qemu */
11588fcfc823SAlex Bennée msg->flags |= VHOST_USER_REPLY_MASK;
11598fcfc823SAlex Bennée msg->size = sizeof(m.payload.u64);
11608fcfc823SAlex Bennée msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_CONFIG;
11618fcfc823SAlex Bennée
11628fcfc823SAlex Bennée qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
11638fcfc823SAlex Bennée }
11648fcfc823SAlex Bennée
11658fcfc823SAlex Bennée static struct vhost_user_ops g_vu_gpio_ops = {
11668fcfc823SAlex Bennée .type = VHOST_USER_GPIO,
11678fcfc823SAlex Bennée
11688fcfc823SAlex Bennée .append_opts = append_vhost_gpio_opts,
11698fcfc823SAlex Bennée
11708fcfc823SAlex Bennée .get_features = vu_gpio_get_features,
11718fcfc823SAlex Bennée .set_features = vu_net_set_features,
11728fcfc823SAlex Bennée .get_protocol_features = vu_gpio_get_protocol_features,
11738fcfc823SAlex Bennée };
11748fcfc823SAlex Bennée
register_vhost_gpio_test(void)11758fcfc823SAlex Bennée static void register_vhost_gpio_test(void)
11768fcfc823SAlex Bennée {
11778fcfc823SAlex Bennée QOSGraphTestOptions opts = {
11788fcfc823SAlex Bennée .before = vhost_user_test_setup,
11798fcfc823SAlex Bennée .subprocess = true,
11808fcfc823SAlex Bennée .arg = &g_vu_gpio_ops,
11818fcfc823SAlex Bennée };
11828fcfc823SAlex Bennée
11838fcfc823SAlex Bennée qemu_add_opts(&qemu_chardev_opts);
11848fcfc823SAlex Bennée
11858fcfc823SAlex Bennée qos_add_test("read-guest-mem/memfile",
11868fcfc823SAlex Bennée "vhost-user-gpio", test_read_guest_mem, &opts);
11878fcfc823SAlex Bennée }
11888fcfc823SAlex Bennée libqos_init(register_vhost_gpio_test);
1189b6f53ae0SMilan Zamazal
vu_scmi_get_features(TestServer * s)1190b6f53ae0SMilan Zamazal static uint64_t vu_scmi_get_features(TestServer *s)
1191b6f53ae0SMilan Zamazal {
1192b6f53ae0SMilan Zamazal return 0x1ULL << VIRTIO_F_VERSION_1 |
1193b6f53ae0SMilan Zamazal 0x1ULL << VIRTIO_SCMI_F_P2A_CHANNELS |
1194b6f53ae0SMilan Zamazal 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
1195b6f53ae0SMilan Zamazal }
1196b6f53ae0SMilan Zamazal
vu_scmi_get_protocol_features(TestServer * s,CharBackend * chr,VhostUserMsg * msg)1197b6f53ae0SMilan Zamazal static void vu_scmi_get_protocol_features(TestServer *s, CharBackend *chr,
1198b6f53ae0SMilan Zamazal VhostUserMsg *msg)
1199b6f53ae0SMilan Zamazal {
1200b6f53ae0SMilan Zamazal msg->flags |= VHOST_USER_REPLY_MASK;
1201b6f53ae0SMilan Zamazal msg->size = sizeof(m.payload.u64);
1202b6f53ae0SMilan Zamazal msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_MQ;
1203b6f53ae0SMilan Zamazal
1204b6f53ae0SMilan Zamazal qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
1205b6f53ae0SMilan Zamazal }
1206b6f53ae0SMilan Zamazal
1207b6f53ae0SMilan Zamazal static struct vhost_user_ops g_vu_scmi_ops = {
1208b6f53ae0SMilan Zamazal .type = VHOST_USER_SCMI,
1209b6f53ae0SMilan Zamazal
1210b6f53ae0SMilan Zamazal .append_opts = append_vhost_gpio_opts,
1211b6f53ae0SMilan Zamazal
1212b6f53ae0SMilan Zamazal .get_features = vu_scmi_get_features,
1213b6f53ae0SMilan Zamazal .set_features = vu_net_set_features,
1214b6f53ae0SMilan Zamazal .get_protocol_features = vu_scmi_get_protocol_features,
1215b6f53ae0SMilan Zamazal };
1216b6f53ae0SMilan Zamazal
register_vhost_scmi_test(void)1217b6f53ae0SMilan Zamazal static void register_vhost_scmi_test(void)
1218b6f53ae0SMilan Zamazal {
1219b6f53ae0SMilan Zamazal QOSGraphTestOptions opts = {
1220b6f53ae0SMilan Zamazal .before = vhost_user_test_setup,
1221b6f53ae0SMilan Zamazal .subprocess = true,
1222b6f53ae0SMilan Zamazal .arg = &g_vu_scmi_ops,
1223b6f53ae0SMilan Zamazal };
1224b6f53ae0SMilan Zamazal
1225b6f53ae0SMilan Zamazal qemu_add_opts(&qemu_chardev_opts);
1226b6f53ae0SMilan Zamazal
1227b6f53ae0SMilan Zamazal qos_add_test("scmi/read-guest-mem/memfile",
1228b6f53ae0SMilan Zamazal "vhost-user-scmi", test_read_guest_mem, &opts);
1229b6f53ae0SMilan Zamazal }
1230b6f53ae0SMilan Zamazal libqos_init(register_vhost_scmi_test);
1231