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