master
c 407 lines 10.4 KB
Raw
1 /*
2 * QTest migration utilities
3 *
4 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5 * based on the vhost-user-test.c that is:
6 * Copyright (c) 2014 Virtual Open Systems Sarl.
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
10 *
11 */
12
13 #include "qemu/osdep.h"
14 #include "qemu/ctype.h"
15 #include "qapi/qapi-visit-sockets.h"
16 #include "qapi/qobject-input-visitor.h"
17 #include "qapi/error.h"
18 #include "qobject/qlist.h"
19 #include "qemu/cutils.h"
20 #include "qemu/memalign.h"
21
22 #include "migration/bootfile.h"
23 #include "migration/migration-util.h"
24
25 #if defined(__linux__)
26 #include <sys/ioctl.h>
27 #include <sys/syscall.h>
28 #endif
29
30 /* for uffd_version_check() */
31 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
32 #include <sys/eventfd.h>
33 #include "qemu/userfaultfd.h"
34 #endif
35
36 /* For dirty ring test; so far only x86_64 is supported */
37 #if defined(__linux__) && defined(HOST_X86_64)
38 #include "linux/kvm.h"
39 #endif
40
41 GQueue *tests;
42
43 static char *SocketAddress_to_str(SocketAddress *addr)
44 {
45 switch (addr->type) {
46 case SOCKET_ADDRESS_TYPE_INET:
47 return g_strdup_printf("tcp:%s:%s",
48 addr->u.inet.host,
49 addr->u.inet.port);
50 case SOCKET_ADDRESS_TYPE_UNIX:
51 return g_strdup_printf("unix:%s",
52 addr->u.q_unix.path);
53 case SOCKET_ADDRESS_TYPE_FD:
54 return g_strdup_printf("fd:%s", addr->u.fd.str);
55 case SOCKET_ADDRESS_TYPE_VSOCK:
56 return g_strdup_printf("vsock:%s:%s",
57 addr->u.vsock.cid,
58 addr->u.vsock.port);
59 default:
60 return g_strdup("unknown address type");
61 }
62 }
63
64 static QDict *SocketAddress_to_qdict(SocketAddress *addr)
65 {
66 QDict *dict = qdict_new();
67
68 switch (addr->type) {
69 case SOCKET_ADDRESS_TYPE_INET:
70 qdict_put_str(dict, "type", "inet");
71 qdict_put_str(dict, "host", addr->u.inet.host);
72 qdict_put_str(dict, "port", addr->u.inet.port);
73 break;
74 case SOCKET_ADDRESS_TYPE_UNIX:
75 qdict_put_str(dict, "type", "unix");
76 qdict_put_str(dict, "path", addr->u.q_unix.path);
77 break;
78 case SOCKET_ADDRESS_TYPE_FD:
79 qdict_put_str(dict, "type", "fd");
80 qdict_put_str(dict, "str", addr->u.fd.str);
81 break;
82 case SOCKET_ADDRESS_TYPE_VSOCK:
83 qdict_put_str(dict, "type", "vsock");
84 qdict_put_str(dict, "cid", addr->u.vsock.cid);
85 qdict_put_str(dict, "port", addr->u.vsock.port);
86 break;
87 default:
88 g_assert_not_reached();
89 }
90
91 return dict;
92 }
93
94 static SocketAddressList *migrate_get_socket_address(QTestState *who)
95 {
96 QDict *rsp;
97 SocketAddressList *addrs;
98 Visitor *iv = NULL;
99 QObject *object;
100
101 rsp = migrate_query(who);
102 object = qdict_get(rsp, "socket-address");
103
104 iv = qobject_input_visitor_new(object);
105 visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
106 visit_free(iv);
107
108 qobject_unref(rsp);
109 return addrs;
110 }
111
112 char *migrate_get_connect_uri(QTestState *who)
113 {
114 SocketAddressList *addrs;
115 char *connect_uri;
116
117 addrs = migrate_get_socket_address(who);
118 connect_uri = SocketAddress_to_str(addrs->value);
119
120 qapi_free_SocketAddressList(addrs);
121 return connect_uri;
122 }
123
124 static QDict *
125 migrate_get_connect_qdict(QTestState *who)
126 {
127 SocketAddressList *addrs;
128 QDict *connect_qdict;
129
130 addrs = migrate_get_socket_address(who);
131 connect_qdict = SocketAddress_to_qdict(addrs->value);
132
133 qapi_free_SocketAddressList(addrs);
134 return connect_qdict;
135 }
136
137 void migrate_set_ports(QTestState *to, QList *channel_list)
138 {
139 g_autoptr(QDict) addr = NULL;
140 QListEntry *entry;
141 const char *addr_port = NULL;
142
143 QLIST_FOREACH_ENTRY(channel_list, entry) {
144 QDict *channel = qobject_to(QDict, qlist_entry_obj(entry));
145 QDict *addrdict = qdict_get_qdict(channel, "addr");
146
147 if (!qdict_haskey(addrdict, "port") ||
148 strcmp(qdict_get_str(addrdict, "port"), "0")) {
149 continue;
150 }
151
152 /*
153 * Fetch addr only if needed, so tests that are not yet connected to
154 * the monitor do not query it. Such tests cannot use port=0.
155 */
156 if (!addr) {
157 addr = migrate_get_connect_qdict(to);
158 }
159
160 if (qdict_haskey(addr, "port")) {
161 addr_port = qdict_get_str(addr, "port");
162 qdict_put_str(addrdict, "port", addr_port);
163 }
164 }
165 }
166
167 bool migrate_watch_for_events(QTestState *who, const char *name,
168 QDict *event, void *opaque)
169 {
170 QTestMigrationState *state = opaque;
171
172 if (g_str_equal(name, "STOP")) {
173 state->stop_seen = true;
174 return true;
175 } else if (g_str_equal(name, "SUSPEND")) {
176 state->suspend_seen = true;
177 return true;
178 } else if (g_str_equal(name, "RESUME")) {
179 state->resume_seen = true;
180 return true;
181 }
182
183 return false;
184 }
185
186 char *find_common_machine_version(const char *mtype, const char *var1,
187 const char *var2)
188 {
189 g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype);
190 g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype);
191
192 g_assert(type1 && type2);
193
194 if (g_str_equal(type1, type2)) {
195 /* either can be used */
196 return g_strdup(type1);
197 }
198
199 if (qtest_has_machine_with_env(var2, type1)) {
200 return g_strdup(type1);
201 }
202
203 if (qtest_has_machine_with_env(var1, type2)) {
204 return g_strdup(type2);
205 }
206
207 g_test_message("No common machine version for machine type '%s' between "
208 "binaries %s and %s", mtype, getenv(var1), getenv(var2));
209 g_assert_not_reached();
210 }
211
212 char *resolve_machine_version(const char *alias, const char *var1,
213 const char *var2)
214 {
215 const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE");
216 g_autofree char *machine_name = NULL;
217
218 if (mname) {
219 const char *dash = strrchr(mname, '-');
220 const char *dot = strrchr(mname, '.');
221
222 machine_name = g_strdup(mname);
223
224 if (dash && dot) {
225 assert(qtest_has_machine(machine_name));
226 return g_steal_pointer(&machine_name);
227 }
228 /* else: probably an alias, let it be resolved below */
229 } else {
230 /* use the hardcoded alias */
231 machine_name = g_strdup(alias);
232 }
233
234 return find_common_machine_version(machine_name, var1, var2);
235 }
236
237 typedef struct {
238 char *name;
239 MigrateCommon *data;
240 void (*func)(char *name, MigrateCommon *args);
241 } MigrationTest;
242
243 static void migration_test_destroy(gpointer data)
244 {
245 MigrationTest *test = (MigrationTest *)data;
246
247 g_queue_remove(tests, test);
248
249 g_free(test->data);
250 g_free(test->name);
251 g_free(test);
252 }
253
254 static void migration_test_wrapper(const void *data)
255 {
256 MigrationTest *test = (MigrationTest *)data;
257
258 test->data = g_new0(MigrateCommon, 1);
259
260 g_test_message("Running /%s%s", qtest_get_arch(), test->name);
261 test->func(test->name, test->data);
262 }
263
264 void migration_test_add(const char *path,
265 void (*fn)(char *name, MigrateCommon *args))
266 {
267 MigrationTest *test = g_new0(MigrationTest, 1);
268
269 test->func = fn;
270 test->name = g_strdup(path);
271
272 qtest_add_data_func_full(path, test, migration_test_wrapper,
273 migration_test_destroy);
274 if (!tests) {
275 tests = g_queue_new();
276 }
277 g_queue_push_tail(tests, test);
278 }
279
280 void migration_test_add_suffix(const char *path, const char *suffix,
281 void (*fn)(char *name, MigrateCommon *args))
282 {
283 g_autofree char *name = NULL;
284
285 g_assert(g_str_has_suffix(path, "/"));
286 g_assert(!g_str_has_prefix(suffix, "/"));
287
288 name = g_strconcat(path, suffix, NULL);
289 migration_test_add(name, fn);
290 }
291
292 void migration_tests_free(void)
293 {
294 g_queue_free_full(tests, migration_test_destroy);
295 }
296
297 #ifdef O_DIRECT
298 /*
299 * Probe for O_DIRECT support on the filesystem. Since this is used
300 * for tests, be conservative, if anything fails, assume it's
301 * unsupported.
302 */
303 bool probe_o_direct_support(const char *tmpfs)
304 {
305 g_autofree char *filename = g_strdup_printf("%s/probe-o-direct", tmpfs);
306 int fd, flags = O_CREAT | O_RDWR | O_TRUNC | O_DIRECT;
307 void *buf;
308 ssize_t ret, len;
309 uint64_t offset;
310
311 fd = open(filename, flags, 0660);
312 if (fd < 0) {
313 unlink(filename);
314 return false;
315 }
316
317 /*
318 * Using 1MB alignment as conservative choice to satisfy any
319 * plausible architecture default page size, and/or filesystem
320 * alignment restrictions.
321 */
322 len = 0x100000;
323 offset = 0x100000;
324
325 buf = qemu_try_memalign(len, len);
326 g_assert(buf);
327 memset(buf, 0, len);
328
329 ret = pwrite(fd, buf, len, offset);
330 unlink(filename);
331 g_free(buf);
332
333 if (ret < 0) {
334 return false;
335 }
336
337 return true;
338 }
339 #endif
340
341 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
342 bool ufd_version_check(bool *uffd_feature_thread_id)
343 {
344 struct uffdio_api api_struct;
345 uint64_t ioctl_mask;
346 bool ret = false;
347
348 int ufd = uffd_open(O_CLOEXEC);
349
350 if (ufd == -1) {
351 g_test_message("Skipping test: userfaultfd not available");
352 return false;
353 }
354
355 api_struct.api = UFFD_API;
356 api_struct.features = 0;
357 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
358 g_test_message("Skipping test: UFFDIO_API failed");
359 goto release_ufd;
360 }
361
362 if (uffd_feature_thread_id) {
363 *uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
364 }
365
366 ioctl_mask = (1ULL << _UFFDIO_REGISTER |
367 1ULL << _UFFDIO_UNREGISTER);
368 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
369 g_test_message("Skipping test: Missing userfault feature");
370 goto release_ufd;
371 }
372
373 ret = true;
374 release_ufd:
375 close(ufd);
376 return ret;
377 }
378 #else
379 bool ufd_version_check(bool *uffd_feature_thread_id)
380 {
381 g_test_message("Skipping test: Userfault not available (builtdtime)");
382 return false;
383 }
384 #endif
385
386 bool kvm_dirty_ring_supported(void)
387 {
388 #if defined(__linux__) && defined(HOST_X86_64)
389 int ret, kvm_fd = open("/dev/kvm", O_RDONLY);
390
391 if (kvm_fd < 0) {
392 return false;
393 }
394
395 ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING);
396 close(kvm_fd);
397
398 /* We test with 4096 slots */
399 if (ret < 4096) {
400 return false;
401 }
402
403 return true;
404 #else
405 return false;
406 #endif
407 }