2009-08-05 17:24:29 +02:00
|
|
|
/*
|
|
|
|
* QEMU live migration via Unix Domain Sockets
|
|
|
|
*
|
2016-04-27 12:05:02 +02:00
|
|
|
* Copyright Red Hat, Inc. 2009-2016
|
2009-08-05 17:24:29 +02:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Chris Lalancette <clalance@redhat.com>
|
2016-04-27 12:05:02 +02:00
|
|
|
* Daniel P. Berrange <berrange@redhat.com>
|
2009-08-05 17:24:29 +02:00
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
2012-01-13 17:44:23 +01:00
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2009-08-05 17:24:29 +02:00
|
|
|
*/
|
|
|
|
|
2016-01-26 19:16:54 +01:00
|
|
|
#include "qemu/osdep.h"
|
2014-03-19 14:34:28 +01:00
|
|
|
|
2009-08-05 17:24:29 +02:00
|
|
|
#include "qemu-common.h"
|
2014-03-19 14:34:28 +01:00
|
|
|
#include "qemu/error-report.h"
|
2016-04-27 12:05:02 +02:00
|
|
|
#include "qapi/error.h"
|
2012-12-17 18:19:50 +01:00
|
|
|
#include "migration/migration.h"
|
2012-10-03 14:07:31 +02:00
|
|
|
#include "migration/qemu-file.h"
|
2016-04-27 12:05:02 +02:00
|
|
|
#include "io/channel-socket.h"
|
|
|
|
#include "trace.h"
|
2009-08-05 17:24:29 +02:00
|
|
|
|
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
static SocketAddress *unix_build_address(const char *path)
|
|
|
|
{
|
|
|
|
SocketAddress *saddr;
|
|
|
|
|
|
|
|
saddr = g_new0(SocketAddress, 1);
|
|
|
|
saddr->type = SOCKET_ADDRESS_KIND_UNIX;
|
|
|
|
saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
|
|
saddr->u.q_unix.data->path = g_strdup(path);
|
|
|
|
|
|
|
|
return saddr;
|
|
|
|
}
|
2009-08-05 17:24:29 +02:00
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
static void socket_outgoing_migration(Object *src,
|
|
|
|
Error *err,
|
|
|
|
gpointer opaque)
|
2009-08-05 17:24:29 +02:00
|
|
|
{
|
2010-05-11 15:56:35 +02:00
|
|
|
MigrationState *s = opaque;
|
2016-04-27 12:05:02 +02:00
|
|
|
QIOChannel *sioc = QIO_CHANNEL(src);
|
2009-08-05 17:24:29 +02:00
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
if (err) {
|
2016-04-27 12:05:03 +02:00
|
|
|
trace_migration_socket_outgoing_error(error_get_pretty(err));
|
2016-01-15 04:37:42 +01:00
|
|
|
s->to_dst_file = NULL;
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 12:05:00 +02:00
|
|
|
migrate_fd_error(s, err);
|
2012-10-03 14:05:49 +02:00
|
|
|
} else {
|
2016-04-27 12:05:03 +02:00
|
|
|
trace_migration_socket_outgoing_connected();
|
2016-04-27 12:05:02 +02:00
|
|
|
migration_set_outgoing_channel(s, sioc);
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
2016-04-27 12:05:02 +02:00
|
|
|
object_unref(src);
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
static void socket_start_outgoing_migration(MigrationState *s,
|
|
|
|
SocketAddress *saddr,
|
|
|
|
Error **errp)
|
2009-08-05 17:24:29 +02:00
|
|
|
{
|
2016-04-27 12:05:03 +02:00
|
|
|
QIOChannelSocket *sioc = qio_channel_socket_new();
|
2016-04-27 12:05:02 +02:00
|
|
|
qio_channel_socket_connect_async(sioc,
|
|
|
|
saddr,
|
2016-04-27 12:05:03 +02:00
|
|
|
socket_outgoing_migration,
|
2016-04-27 12:05:02 +02:00
|
|
|
s,
|
|
|
|
NULL);
|
|
|
|
qapi_free_SocketAddress(saddr);
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
void unix_start_outgoing_migration(MigrationState *s,
|
|
|
|
const char *path,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
SocketAddress *saddr = unix_build_address(path);
|
|
|
|
socket_start_outgoing_migration(s, saddr, errp);
|
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
static gboolean socket_accept_incoming_migration(QIOChannel *ioc,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer opaque)
|
2009-08-05 17:24:29 +02:00
|
|
|
{
|
2016-04-27 12:05:02 +02:00
|
|
|
QIOChannelSocket *sioc;
|
|
|
|
Error *err = NULL;
|
2009-08-05 17:24:29 +02:00
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
|
|
|
|
&err);
|
|
|
|
if (!sioc) {
|
|
|
|
error_report("could not accept migration connection (%s)",
|
|
|
|
error_get_pretty(err));
|
2009-08-05 17:24:29 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
trace_migration_socket_incoming_accepted();
|
2016-04-27 12:05:02 +02:00
|
|
|
|
|
|
|
migration_set_incoming_channel(migrate_get_current(),
|
|
|
|
QIO_CHANNEL(sioc));
|
|
|
|
object_unref(OBJECT(sioc));
|
2012-08-07 10:50:26 +02:00
|
|
|
|
2009-08-05 17:24:29 +02:00
|
|
|
out:
|
2016-04-27 12:05:02 +02:00
|
|
|
/* Close listening socket as its no longer needed */
|
|
|
|
qio_channel_close(ioc, NULL);
|
|
|
|
return FALSE; /* unregister */
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
|
2016-04-27 12:05:03 +02:00
|
|
|
static void socket_start_incoming_migration(SocketAddress *saddr,
|
|
|
|
Error **errp)
|
2009-08-05 17:24:29 +02:00
|
|
|
{
|
2016-04-27 12:05:03 +02:00
|
|
|
QIOChannelSocket *listen_ioc = qio_channel_socket_new();
|
2009-08-05 17:24:29 +02:00
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
|
|
|
|
object_unref(OBJECT(listen_ioc));
|
|
|
|
qapi_free_SocketAddress(saddr);
|
2012-10-02 18:21:18 +02:00
|
|
|
return;
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 12:05:02 +02:00
|
|
|
qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
|
|
|
|
G_IO_IN,
|
2016-04-27 12:05:03 +02:00
|
|
|
socket_accept_incoming_migration,
|
2016-04-27 12:05:02 +02:00
|
|
|
listen_ioc,
|
|
|
|
(GDestroyNotify)object_unref);
|
|
|
|
qapi_free_SocketAddress(saddr);
|
2009-08-05 17:24:29 +02:00
|
|
|
}
|
2016-04-27 12:05:03 +02:00
|
|
|
|
|
|
|
void unix_start_incoming_migration(const char *path, Error **errp)
|
|
|
|
{
|
|
|
|
SocketAddress *saddr = unix_build_address(path);
|
|
|
|
socket_start_incoming_migration(saddr, errp);
|
|
|
|
}
|