*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
-#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "channel.h"
-#include "migration/migration.h"
-#include "migration/qemu-file.h"
+#include "socket.h"
+#include "migration.h"
+#include "qemu-file.h"
#include "io/channel-socket.h"
+#include "io/net-listener.h"
#include "trace.h"
+#include "postcopy-ram.h"
+#include "options.h"
+struct SocketOutgoingArgs {
+ SocketAddress *saddr;
+} outgoing_args;
-static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
+void socket_send_channel_create(QIOTaskFunc f, void *data)
{
- SocketAddress *saddr;
+ QIOChannelSocket *sioc = qio_channel_socket_new();
+ qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
+ f, data, NULL, NULL);
+}
- saddr = g_new0(SocketAddress, 1);
- saddr->type = SOCKET_ADDRESS_TYPE_INET;
+QIOChannel *socket_send_channel_create_sync(Error **errp)
+{
+ QIOChannelSocket *sioc = qio_channel_socket_new();
- if (inet_parse(&saddr->u.inet, host_port, errp)) {
- qapi_free_SocketAddress(saddr);
+ if (!outgoing_args.saddr) {
+ object_unref(OBJECT(sioc));
+ error_setg(errp, "Initial sock address not set!");
return NULL;
}
- return saddr;
-}
+ if (qio_channel_socket_connect_sync(sioc, outgoing_args.saddr, errp) < 0) {
+ object_unref(OBJECT(sioc));
+ return NULL;
+ }
+ return QIO_CHANNEL(sioc);
+}
-static SocketAddress *unix_build_address(const char *path)
+int socket_send_channel_destroy(QIOChannel *send)
{
- SocketAddress *saddr;
-
- saddr = g_new0(SocketAddress, 1);
- saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
- saddr->u.q_unix.path = g_strdup(path);
-
- return saddr;
+ /* 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;
if (qio_task_propagate_error(task, &err)) {
trace_migration_socket_outgoing_error(error_get_pretty(err));
- migrate_fd_error(data->s, err);
- error_free(err);
- } else {
- trace_migration_socket_outgoing_connected(data->hostname);
- migration_channel_connect(data->s, sioc, data->hostname);
+ goto out;
}
+
+ trace_migration_socket_outgoing_connected(data->hostname);
+
+ if (migrate_zero_copy_send() &&
+ !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
+ error_setg(&err, "Zero copy send feature not detected in host kernel");
+ }
+
+out:
+ migration_channel_connect(data->s, sioc, data->hostname, err);
object_unref(OBJECT(sioc));
}
-static void socket_start_outgoing_migration(MigrationState *s,
- SocketAddress *saddr,
- Error **errp)
+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);
}
saddr,
socket_outgoing_migration,
data,
- socket_connect_data_free);
- qapi_free_SocketAddress(saddr);
+ socket_connect_data_free,
+ NULL);
}
-void tcp_start_outgoing_migration(MigrationState *s,
- const char *host_port,
- Error **errp)
+void socket_start_outgoing_migration(MigrationState *s,
+ const char *str,
+ Error **errp)
{
Error *err = NULL;
- SocketAddress *saddr = tcp_build_address(host_port, &err);
+ SocketAddress *saddr = socket_parse(str, &err);
if (!err) {
- socket_start_outgoing_migration(s, saddr, &err);
+ socket_start_outgoing_migration_internal(s, saddr, &err);
}
error_propagate(errp, err);
}
-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);
-}
-
-
-static gboolean socket_accept_incoming_migration(QIOChannel *ioc,
- GIOCondition condition,
- gpointer opaque)
+static void socket_accept_incoming_migration(QIONetListener *listener,
+ QIOChannelSocket *cioc,
+ gpointer opaque)
{
- QIOChannelSocket *sioc;
- Error *err = NULL;
+ trace_migration_socket_incoming_accepted();
- sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
- &err);
- if (!sioc) {
- error_report("could not accept migration connection (%s)",
- error_get_pretty(err));
- goto out;
+ if (migration_has_all_channels()) {
+ error_report("%s: Extra incoming migration connection; ignoring",
+ __func__);
+ return;
}
- trace_migration_socket_incoming_accepted();
+ qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
+ migration_channel_process_incoming(QIO_CHANNEL(cioc));
+}
- qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-incoming");
- migration_channel_process_incoming(migrate_get_current(),
- QIO_CHANNEL(sioc));
- object_unref(OBJECT(sioc));
+static void
+socket_incoming_migration_end(void *opaque)
+{
+ QIONetListener *listener = opaque;
-out:
- /* Close listening socket as its no longer needed */
- qio_channel_close(ioc, NULL);
- return FALSE; /* unregister */
+ qio_net_listener_disconnect(listener);
+ object_unref(OBJECT(listener));
}
-
-static void socket_start_incoming_migration(SocketAddress *saddr,
- Error **errp)
+static void
+socket_start_incoming_migration_internal(SocketAddress *saddr,
+ Error **errp)
{
- QIOChannelSocket *listen_ioc = qio_channel_socket_new();
+ QIONetListener *listener = qio_net_listener_new();
+ MigrationIncomingState *mis = migration_incoming_get_current();
+ size_t i;
+ int num = 1;
- qio_channel_set_name(QIO_CHANNEL(listen_ioc),
- "migration-socket-listener");
+ qio_net_listener_set_name(listener, "migration-socket-listener");
- if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
- object_unref(OBJECT(listen_ioc));
- qapi_free_SocketAddress(saddr);
+ if (migrate_multifd()) {
+ num = migrate_multifd_channels();
+ } else if (migrate_postcopy_preempt()) {
+ num = RAM_CHANNEL_MAX;
+ }
+
+ if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
+ object_unref(OBJECT(listener));
return;
}
- qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
- G_IO_IN,
- socket_accept_incoming_migration,
- listen_ioc,
- (GDestroyNotify)object_unref);
- qapi_free_SocketAddress(saddr);
+ 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 tcp_start_incoming_migration(const char *host_port, Error **errp)
+void socket_start_incoming_migration(const char *str, Error **errp)
{
Error *err = NULL;
- SocketAddress *saddr = tcp_build_address(host_port, &err);
+ SocketAddress *saddr = socket_parse(str, &err);
if (!err) {
- socket_start_incoming_migration(saddr, &err);
+ socket_start_incoming_migration_internal(saddr, &err);
}
+ qapi_free_SocketAddress(saddr);
error_propagate(errp, err);
}
-
-void unix_start_incoming_migration(const char *path, Error **errp)
-{
- SocketAddress *saddr = unix_build_address(path);
- socket_start_incoming_migration(saddr, errp);
-}