1 /* 2 * QEMU live migration 3 * 4 * Copyright IBM, Corp. 2008 5 * 6 * Authors: 7 * Anthony Liguori <aliguori (at) us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 */ 13 14 #include "qemu-common.h" 15 #include "qemu_socket.h" 16 #include "migration.h" 17 #include "qemu-char.h" 18 #include "sysemu.h" 19 #include "buffered_file.h" 20 #include "block.h" 21 22 //#define DEBUG_MIGRATION_TCP 23 24 #ifdef DEBUG_MIGRATION_TCP 25 #define dprintf(fmt, ...) \ 26 do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0) 27 #else 28 #define dprintf(fmt, ...) \ 29 do { } while (0) 30 #endif 31 32 static int socket_errno(FdMigrationState *s) 33 { 34 return errno; 35 } 36 37 static int socket_write(FdMigrationState *s, const void * buf, size_t size) 38 { 39 return socket_send(s->fd, buf, size); 40 } 41 42 static int tcp_close(FdMigrationState *s) 43 { 44 dprintf("tcp_close\n"); 45 if (s->fd != -1) { 46 socket_close(s->fd); 47 s->fd = -1; 48 } 49 return 0; 50 } 51 52 53 static void tcp_wait_for_connect(void *opaque) 54 { 55 FdMigrationState *s = opaque; 56 int ret; 57 58 dprintf("connect completed\n"); 59 ret = socket_get_error(s->fd); 60 if (ret < 0) { 61 dprintf("error connecting %d\n", val); 62 migrate_fd_error(s); 63 return; 64 } 65 66 qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); 67 68 migrate_fd_connect(s); 69 } 70 71 MigrationState *tcp_start_outgoing_migration(const char *host_port, 72 int64_t bandwidth_limit, 73 int detach) 74 { 75 SockAddress addr; 76 FdMigrationState *s; 77 int ret; 78 79 if (parse_host_port(&addr, host_port) < 0) 80 return NULL; 81 82 s = qemu_mallocz(sizeof(*s)); 83 84 s->get_error = socket_errno; 85 s->write = socket_write; 86 s->close = tcp_close; 87 s->mig_state.cancel = migrate_fd_cancel; 88 s->mig_state.get_status = migrate_fd_get_status; 89 s->mig_state.release = migrate_fd_release; 90 91 s->state = MIG_STATE_ACTIVE; 92 s->mon_resume = NULL; 93 s->bandwidth_limit = bandwidth_limit; 94 s->fd = socket_create_inet(SOCKET_STREAM); 95 if (s->fd == -1) { 96 qemu_free(s); 97 return NULL; 98 } 99 100 socket_set_nonblock(s->fd); 101 102 if (!detach) 103 migrate_fd_monitor_suspend(s); 104 105 do { 106 ret = socket_connect(s->fd, &addr); 107 if (ret == -1) 108 ret = -(s->get_error(s)); 109 110 if (ret == -EINPROGRESS || ret == -EWOULDBLOCK || ret == -EAGAIN) 111 qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); 112 } while (ret == -EINTR); 113 114 if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK && ret != -EAGAIN) { 115 dprintf("connect failed\n"); 116 socket_close(s->fd); 117 qemu_free(s); 118 return NULL; 119 } else if (ret >= 0) 120 migrate_fd_connect(s); 121 122 return &s->mig_state; 123 } 124 125 static void tcp_accept_incoming_migration(void *opaque) 126 { 127 SockAddress addr; 128 int s = (unsigned long)opaque; 129 QEMUFile *f; 130 int c, ret; 131 132 c = socket_accept(s, &addr); 133 dprintf("accepted migration\n"); 134 135 if (c == -1) { 136 fprintf(stderr, "could not accept migration connection\n"); 137 return; 138 } 139 140 f = qemu_fopen_socket(c); 141 if (f == NULL) { 142 fprintf(stderr, "could not qemu_fopen socket\n"); 143 goto out; 144 } 145 146 vm_stop(0); /* just in case */ 147 ret = qemu_loadvm_state(f); 148 if (ret < 0) { 149 fprintf(stderr, "load of migration failed\n"); 150 goto out_fopen; 151 } 152 qemu_announce_self(); 153 dprintf("successfully loaded vm state\n"); 154 155 /* we've successfully migrated, close the server socket */ 156 qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); 157 socket_close(s); 158 159 vm_start(); 160 161 out_fopen: 162 qemu_fclose(f); 163 out: 164 socket_close(c); 165 } 166 167 int tcp_start_incoming_migration(const char *host_port) 168 { 169 SockAddress addr; 170 int s; 171 172 if (parse_host_port(&addr, host_port) < 0) { 173 fprintf(stderr, "invalid host/port combination: %s\n", host_port); 174 return -EINVAL; 175 } 176 177 s = socket_create_inet(SOCKET_STREAM); 178 if (s == -1) 179 return -socket_error(); 180 181 socket_set_xreuseaddr(s); 182 183 if (socket_bind(s, &addr) == -1) 184 goto err; 185 186 if (socket_listen(s, 1) == -1) 187 goto err; 188 189 qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, 190 (void *)(unsigned long)s); 191 192 return 0; 193 194 err: 195 socket_close(s); 196 return -socket_error(); 197 } 198