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