Statistics
| Branch: | Revision:

root / migration-tcp.c @ 07ef34c3

History | View | Annotate | Download (4.9 kB)

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