diff options
author | 2023-10-10 11:40:56 +0000 | |
---|---|---|
committer | 2023-10-10 11:40:56 +0000 | |
commit | e02cda008591317b1625707ff8e115a4841aa889 (patch) | |
tree | aee302e3cf8b59ec2d32ec481be3d1afddfc8968 /migration/socket.c | |
parent | cc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff) |
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback
design to work with QEMU and rust-vmm vhost-user backend without require any
changes.
Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'migration/socket.c')
-rw-r--r-- | migration/socket.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/migration/socket.c b/migration/socket.c new file mode 100644 index 000000000..05705a32d --- /dev/null +++ b/migration/socket.c @@ -0,0 +1,196 @@ +/* + * QEMU live migration via socket + * + * Copyright Red Hat, Inc. 2009-2016 + * + * Authors: + * Chris Lalancette <clalance@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" + +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "channel.h" +#include "socket.h" +#include "migration.h" +#include "qemu-file.h" +#include "io/channel-socket.h" +#include "io/net-listener.h" +#include "trace.h" + + +struct SocketOutgoingArgs { + SocketAddress *saddr; +} outgoing_args; + +void socket_send_channel_create(QIOTaskFunc f, void *data) +{ + QIOChannelSocket *sioc = qio_channel_socket_new(); + qio_channel_socket_connect_async(sioc, outgoing_args.saddr, + f, data, NULL, NULL); +} + +int socket_send_channel_destroy(QIOChannel *send) +{ + /* Remove channel */ + object_unref(OBJECT(send)); + if (outgoing_args.saddr) { + qapi_free_SocketAddress(outgoing_args.saddr); + outgoing_args.saddr = NULL; + } + return 0; +} + +struct SocketConnectData { + MigrationState *s; + char *hostname; +}; + +static void socket_connect_data_free(void *opaque) +{ + struct SocketConnectData *data = opaque; + if (!data) { + return; + } + g_free(data->hostname); + g_free(data); +} + +static void socket_outgoing_migration(QIOTask *task, + gpointer opaque) +{ + struct SocketConnectData *data = opaque; + QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); + Error *err = NULL; + + if (qio_task_propagate_error(task, &err)) { + trace_migration_socket_outgoing_error(error_get_pretty(err)); + } else { + trace_migration_socket_outgoing_connected(data->hostname); + } + migration_channel_connect(data->s, sioc, data->hostname, err); + object_unref(OBJECT(sioc)); +} + +static void +socket_start_outgoing_migration_internal(MigrationState *s, + SocketAddress *saddr, + Error **errp) +{ + QIOChannelSocket *sioc = qio_channel_socket_new(); + struct SocketConnectData *data = g_new0(struct SocketConnectData, 1); + + data->s = s; + + /* in case previous migration leaked it */ + qapi_free_SocketAddress(outgoing_args.saddr); + outgoing_args.saddr = saddr; + + if (saddr->type == SOCKET_ADDRESS_TYPE_INET) { + data->hostname = g_strdup(saddr->u.inet.host); + } + + qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing"); + qio_channel_socket_connect_async(sioc, + saddr, + socket_outgoing_migration, + data, + socket_connect_data_free, + NULL); +} + +void socket_start_outgoing_migration(MigrationState *s, + const char *str, + Error **errp) +{ + Error *err = NULL; + SocketAddress *saddr = socket_parse(str, &err); + if (!err) { + socket_start_outgoing_migration_internal(s, saddr, &err); + } + error_propagate(errp, err); +} + +static void socket_accept_incoming_migration(QIONetListener *listener, + QIOChannelSocket *cioc, + gpointer opaque) +{ + trace_migration_socket_incoming_accepted(); + + if (migration_has_all_channels()) { + error_report("%s: Extra incoming migration connection; ignoring", + __func__); + return; + } + + qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming"); + migration_channel_process_incoming(QIO_CHANNEL(cioc)); +} + +static void +socket_incoming_migration_end(void *opaque) +{ + QIONetListener *listener = opaque; + + qio_net_listener_disconnect(listener); + object_unref(OBJECT(listener)); +} + +static void +socket_start_incoming_migration_internal(SocketAddress *saddr, + Error **errp) +{ + QIONetListener *listener = qio_net_listener_new(); + MigrationIncomingState *mis = migration_incoming_get_current(); + size_t i; + int num = 1; + + qio_net_listener_set_name(listener, "migration-socket-listener"); + + if (migrate_use_multifd()) { + num = migrate_multifd_channels(); + } + + if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) { + object_unref(OBJECT(listener)); + return; + } + + mis->transport_data = listener; + mis->transport_cleanup = socket_incoming_migration_end; + + qio_net_listener_set_client_func_full(listener, + socket_accept_incoming_migration, + NULL, NULL, + g_main_context_get_thread_default()); + + for (i = 0; i < listener->nsioc; i++) { + SocketAddress *address = + qio_channel_socket_get_local_address(listener->sioc[i], errp); + if (!address) { + return; + } + migrate_add_address(address); + qapi_free_SocketAddress(address); + } +} + +void socket_start_incoming_migration(const char *str, Error **errp) +{ + Error *err = NULL; + SocketAddress *saddr = socket_parse(str, &err); + if (!err) { + socket_start_incoming_migration_internal(saddr, &err); + } + qapi_free_SocketAddress(saddr); + error_propagate(errp, err); +} |