@@ -42,3 +42,5 @@ system_ss.add(when: zstd, if_true: files('multifd-zstd.c'))
specific_ss.add(when: 'CONFIG_SYSTEM_ONLY',
if_true: files('ram.c',
'target.c'))
+
+system_ss.add(when: rdma, if_true: files('rdma.c'))
@@ -25,6 +25,7 @@
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpu-throttle.h"
+#include "rdma.h"
#include "ram.h"
#include "migration/global_state.h"
#include "migration/misc.h"
@@ -145,7 +146,7 @@ static bool transport_supports_multi_channels(MigrationAddress *addr)
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
return migrate_mapped_ram();
} else {
- return false;
+ return addr->transport == MIGRATION_ADDRESS_TYPE_RDMA;
}
}
@@ -644,6 +645,10 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
} else if (saddr->type == SOCKET_ADDRESS_TYPE_FD) {
fd_start_incoming_migration(saddr->u.fd.str, errp);
}
+#ifdef CONFIG_RDMA
+ } else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
+ rdma_start_incoming_migration(&addr->u.rdma, errp);
+#endif
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
exec_start_incoming_migration(addr->u.exec.args, errp);
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
@@ -2046,6 +2051,10 @@ void qmp_migrate(const char *uri, bool has_channels,
} else if (saddr->type == SOCKET_ADDRESS_TYPE_FD) {
fd_start_outgoing_migration(s, saddr->u.fd.str, &local_err);
}
+#ifdef CONFIG_RDMA
+ } else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
+ rdma_start_outgoing_migration(s, &addr->u.rdma, &local_err);
+#endif
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
exec_start_outgoing_migration(s, addr->u.exec.args, &local_err);
} else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
new file mode 100644
@@ -0,0 +1,88 @@
+/*
+ * QEMU live migration via RDMA
+ *
+ * Copyright (c) 2024 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Jialin Wang <wangjialin23@huawei.com>
+ * Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "io/channel-rdma.h"
+#include "io/channel.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-types-sockets.h"
+#include "qapi/qapi-visit-sockets.h"
+#include "channel.h"
+#include "migration.h"
+#include "rdma.h"
+#include "trace.h"
+#include <stdio.h>
+
+static struct RDMAOutgoingArgs {
+ InetSocketAddress *addr;
+} outgoing_args;
+
+static void rdma_outgoing_migration(QIOTask *task, gpointer opaque)
+{
+ MigrationState *s = opaque;
+ QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(qio_task_get_source(task));
+
+ migration_channel_connect(s, QIO_CHANNEL(rioc), outgoing_args.addr->host,
+ NULL);
+ object_unref(OBJECT(rioc));
+}
+
+void rdma_start_outgoing_migration(MigrationState *s, InetSocketAddress *iaddr,
+ Error **errp)
+{
+ QIOChannelRDMA *rioc = qio_channel_rdma_new();
+
+ /* in case previous migration leaked it */
+ qapi_free_InetSocketAddress(outgoing_args.addr);
+ outgoing_args.addr = QAPI_CLONE(InetSocketAddress, iaddr);
+
+ qio_channel_set_name(QIO_CHANNEL(rioc), "migration-rdma-outgoing");
+ qio_channel_rdma_connect_async(rioc, iaddr, rdma_outgoing_migration, s,
+ NULL, NULL);
+}
+
+static void coroutine_fn rdma_accept_incoming_migration(void *opaque)
+{
+ QIOChannelRDMA *rioc = opaque;
+ QIOChannelRDMA *cioc;
+
+ while (!migration_has_all_channels()) {
+ cioc = qio_channel_rdma_accept(rioc, NULL);
+
+ qio_channel_set_name(QIO_CHANNEL(cioc), "migration-rdma-incoming");
+ migration_channel_process_incoming(QIO_CHANNEL(cioc));
+ object_unref(OBJECT(cioc));
+ }
+}
+
+void rdma_start_incoming_migration(InetSocketAddress *addr, Error **errp)
+{
+ QIOChannelRDMA *rioc = qio_channel_rdma_new();
+ MigrationIncomingState *mis = migration_incoming_get_current();
+ Coroutine *co;
+ int num = 1;
+
+ qio_channel_set_name(QIO_CHANNEL(rioc), "migration-rdma-listener");
+
+ if (qio_channel_rdma_listen_sync(rioc, addr, num, errp) < 0) {
+ object_unref(OBJECT(rioc));
+ return;
+ }
+
+ mis->transport_data = rioc;
+ mis->transport_cleanup = object_unref;
+
+ qio_channel_set_blocking(QIO_CHANNEL(rioc), false, NULL);
+ co = qemu_coroutine_create(rdma_accept_incoming_migration, rioc);
+ aio_co_schedule(qemu_get_current_aio_context(), co);
+}
new file mode 100644
@@ -0,0 +1,24 @@
+/*
+ * QEMU live migration via RDMA
+ *
+ * Copyright (c) 2024 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Jialin Wang <wangjialin23@huawei.com>
+ * Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_MIGRATION_RDMA_H
+#define QEMU_MIGRATION_RDMA_H
+
+#include "qemu/sockets.h"
+
+void rdma_start_outgoing_migration(MigrationState *s, InetSocketAddress *addr,
+ Error **errp);
+
+void rdma_start_incoming_migration(InetSocketAddress *addr, Error **errp);
+
+#endif /* QEMU_MIGRATION_RDMA_H */