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 socket_error(); 35 } 36 37 static int socket_write(FdMigrationState *s, const void * buf, size_t size) 38 { 39 return send(s->fd, buf, size, 0); 40 } 41 42 static int tcp_close(FdMigrationState *s) 43 { 44 dprintf("tcp_close\n"); 45 if (s->fd != -1) { 46 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 val, ret; 57 socklen_t valsize = sizeof(val); 58 59 dprintf("connect completed\n"); 60 do { 61 ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); 62 } while (ret == -1 && (s->get_error(s)) == EINTR); 63 64 if (ret < 0) { 65 migrate_fd_error(s); 66 return; 67 } 68 69 qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); 70 71 if (val == 0) 72 migrate_fd_connect(s); 73 else { 74 dprintf("error connecting %d\n", val); 75 migrate_fd_error(s); 76 } 77 } 78 79 MigrationState *tcp_start_outgoing_migration(const char *host_port, 80 int64_t bandwidth_limit, 81 int detach) 82 { 83 struct sockaddr_in addr; 84 FdMigrationState *s; 85 int ret; 86 87 if (parse_host_port(&addr, host_port) < 0) 88 return NULL; 89 90 s = qemu_mallocz(sizeof(*s)); 91 92 s->get_error = socket_errno; 93 s->write = socket_write; 94 s->close = tcp_close; 95 s->mig_state.cancel = migrate_fd_cancel; 96 s->mig_state.get_status = migrate_fd_get_status; 97 s->mig_state.release = migrate_fd_release; 98 99 s->state = MIG_STATE_ACTIVE; 100 s->mon_resume = NULL; 101 s->bandwidth_limit = bandwidth_limit; 102 s->fd = socket(PF_INET, SOCK_STREAM, 0); 103 if (s->fd == -1) { 104 qemu_free(s); 105 return NULL; 106 } 107 108 socket_set_nonblock(s->fd); 109 110 if (!detach) 111 migrate_fd_monitor_suspend(s); 112 113 do { 114 ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); 115 if (ret == -1) 116 ret = -(s->get_error(s)); 117 118 if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) 119 qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); 120 } while (ret == -EINTR); 121 122 if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) { 123 dprintf("connect failed\n"); 124 close(s->fd); 125 qemu_free(s); 126 return NULL; 127 } else if (ret >= 0) 128 migrate_fd_connect(s); 129 130 return &s->mig_state; 131 } 132 133 static void tcp_accept_incoming_migration(void *opaque) 134 { 135 struct sockaddr_in addr; 136 socklen_t addrlen = sizeof(addr); 137 int s = (unsigned long)opaque; 138 QEMUFile *f; 139 int c, ret; 140 141 do { 142 c = accept(s, (struct sockaddr *)&addr, &addrlen); 143 } while (c == -1 && socket_error() == EINTR); 144 145 dprintf("accepted migration\n"); 146 147 if (c == -1) { 148 fprintf(stderr, "could not accept migration connection\n"); 149 return; 150 } 151 152 f = qemu_fopen_socket(c); 153 if (f == NULL) { 154 fprintf(stderr, "could not qemu_fopen socket\n"); 155 goto out; 156 } 157 158 vm_stop(0); /* just in case */ 159 ret = qemu_loadvm_state(f); 160 if (ret < 0) { 161 fprintf(stderr, "load of migration failed\n"); 162 goto out_fopen; 163 } 164 qemu_announce_self(); 165 dprintf("successfully loaded vm state\n"); 166 167 /* we've successfully migrated, close the server socket */ 168 qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); 169 close(s); 170 171 vm_start(); 172 173 out_fopen: 174 qemu_fclose(f); 175 out: 176 close(c); 177 } 178 179 int tcp_start_incoming_migration(const char *host_port) 180 { 181 struct sockaddr_in addr; 182 int val; 183 int s; 184 185 if (parse_host_port(&addr, host_port) < 0) { 186 fprintf(stderr, "invalid host/port combination: %s\n", host_port); 187 return -EINVAL; 188 } 189 190 s = socket(PF_INET, SOCK_STREAM, 0); 191 if (s == -1) 192 return -socket_error(); 193 194 val = 1; 195 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); 196 197 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) 198 goto err; 199 200 if (listen(s, 1) == -1) 201 goto err; 202 203 qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, 204 (void *)(unsigned long)s); 205 206 return 0; 207 208 err: 209 close(s); 210 return -socket_error(); 211 } 212