i) Modified the format of the qemu monitor command : 'migrate' by adding a list,
   each element in the list consisting of multifd connection parameters: source
   uri, destination uri and of the number of multifd channels between each pair.

ii) Information of all multifd connection parameters' list and length of the
    list is stored in 'OutgoingMigrateParams' struct.

Suggested-by: Manish Mishra <manish.mis...@nutanix.com>
Signed-off-by: Het Gala <het.g...@nutanix.com>
---
 migration/migration.c | 52 +++++++++++++++++++++++++++++--------
 migration/socket.c    | 60 ++++++++++++++++++++++++++++++++++++++++---
 migration/socket.h    | 19 +++++++++++++-
 monitor/hmp-cmds.c    |  1 +
 qapi/migration.json   | 47 +++++++++++++++++++++++++++++----
 5 files changed, 160 insertions(+), 19 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index e03f698a3c..572b909423 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2380,13 +2380,14 @@ static bool migrate_prepare(MigrationState *s, bool 
blk, bool blk_inc,
     return true;
 }
 
-void qmp_migrate(const char *uri, bool has_blk, bool blk,
+void qmp_migrate(const char *uri, bool has_multi_fd_uri_list,
+                 MigrateUriParameterList *cap, bool has_blk, bool blk,
                  bool has_inc, bool inc, bool has_detach, bool detach,
                  bool has_resume, bool resume, Error **errp)
 {
     Error *local_err = NULL;
     MigrationState *s = migrate_get_current();
-    const char *p = NULL;
+    const char *dst_ptr = NULL;
 
     if (!migrate_prepare(s, has_blk && blk, has_inc && inc,
                          has_resume && resume, errp)) {
@@ -2400,20 +2401,51 @@ void qmp_migrate(const char *uri, bool has_blk, bool 
blk,
         }
     }
 
+    /*
+     * In case of Multi-FD migration, source and destination uri
+     * supports only tcp network protocol.
+     */
+    if (has_multi_fd_uri_list) {
+        int length = QAPI_LIST_LENGTH(cap);
+        init_multifd_array(length);
+        for (int i = 0; i < length; i++) {
+            const char *pd = NULL, *ps = NULL;
+            const char *multifd_dst_uri = cap->value->destination_uri;
+            const char *multifd_src_uri = cap->value->source_uri;
+            uint8_t multifd_channels = cap->value->multifd_channels;
+            if (!strstart(multifd_dst_uri, "tcp:", &pd) ||
+                !strstart(multifd_src_uri, "tcp:", &ps)) {
+                error_setg(errp, "multi-fd destination and multi-fd source "
+                "uri, both should be present and follows tcp protocol only");
+                return;
+            } else {
+                store_multifd_migration_params(pd ? pd : multifd_dst_uri,
+                                            ps ? ps : multifd_src_uri,
+                                            multifd_channels, i, &local_err);
+            }
+            cap = cap->next;
+        }
+
+        if (outgoing_param_total_multifds() != migrate_multifd_channels()) {
+            error_setg(errp, "Total multifd channel number mismatch");
+            return;
+        }
+    }
+
     migrate_protocol_allow_multi_channels(false);
-    if (strstart(uri, "tcp:", &p) ||
+    if (strstart(uri, "tcp:", &dst_ptr) ||
         strstart(uri, "unix:", NULL) ||
         strstart(uri, "vsock:", NULL)) {
         migrate_protocol_allow_multi_channels(true);
-        socket_start_outgoing_migration(s, p ? p : uri, &local_err);
+        socket_start_outgoing_migration(s, dst_ptr ? dst_ptr : uri, 
&local_err);
 #ifdef CONFIG_RDMA
-    } else if (strstart(uri, "rdma:", &p)) {
-        rdma_start_outgoing_migration(s, p, &local_err);
+    } else if (strstart(uri, "rdma:", &dst_ptr)) {
+        rdma_start_outgoing_migration(s, dst_ptr, &local_err);
 #endif
-    } else if (strstart(uri, "exec:", &p)) {
-        exec_start_outgoing_migration(s, p, &local_err);
-    } else if (strstart(uri, "fd:", &p)) {
-        fd_start_outgoing_migration(s, p, &local_err);
+    } else if (strstart(uri, "exec:", &dst_ptr)) {
+        exec_start_outgoing_migration(s, dst_ptr, &local_err);
+    } else if (strstart(uri, "fd:", &dst_ptr)) {
+        fd_start_outgoing_migration(s, dst_ptr, &local_err);
     } else {
         if (!(has_resume && resume)) {
             yank_unregister_instance(MIGRATION_YANK_INSTANCE);
diff --git a/migration/socket.c b/migration/socket.c
index e6fdf3c5e1..f199430bc2 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -32,6 +32,28 @@ struct SocketOutgoingArgs {
     SocketAddress *saddr;
 } outgoing_args;
 
+struct SocketArgs {
+    struct SrcDestAddr address;
+    uint8_t multifd_channels;
+};
+
+struct OutgoingMigrateParams {
+    struct SocketArgs *socket_args;
+    size_t socket_args_arr_len;
+} outgoing_migrate_params;
+
+int outgoing_param_total_multifds(void)
+{
+    size_t len = outgoing_migrate_params.socket_args_arr_len;
+    uint64_t total_multifd_channels = 0;
+
+    for (int i = 0; i < len; i++) {
+        total_multifd_channels +=
+                outgoing_migrate_params.socket_args[i].multifd_channels;
+    }
+    return total_multifd_channels;
+}
+
 void socket_send_channel_create(QIOTaskFunc f, void *data)
 {
     QIOChannelSocket *sioc = qio_channel_socket_new();
@@ -65,6 +87,9 @@ int socket_send_channel_destroy(QIOChannel *send)
         qapi_free_SocketAddress(outgoing_args.saddr);
         outgoing_args.saddr = NULL;
     }
+    g_free(outgoing_migrate_params.socket_args);
+    outgoing_migrate_params.socket_args = NULL;
+    outgoing_migrate_params.socket_args_arr_len = 0;
     return 0;
 }
 
@@ -135,17 +160,46 @@ socket_start_outgoing_migration_internal(MigrationState 
*s,
 }
 
 void socket_start_outgoing_migration(MigrationState *s,
-                                     const char *str,
+                                     const char *dst_str,
                                      Error **errp)
 {
     Error *err = NULL;
-    SocketAddress *saddr = socket_parse(str, &err);
+    SocketAddress *dst_saddr = socket_parse(dst_str, &err);
     if (!err) {
-        socket_start_outgoing_migration_internal(s, saddr, &err);
+        socket_start_outgoing_migration_internal(s, dst_saddr, &err);
     }
     error_propagate(errp, err);
 }
 
+void init_multifd_array(int length)
+{
+    outgoing_migrate_params.socket_args = g_new0(struct SocketArgs, length);
+    outgoing_migrate_params.socket_args_arr_len = length;
+}
+
+void store_multifd_migration_params(const char *dst_uri,
+                                    const char *src_uri,
+                                    uint8_t multifd_channels,
+                                    int idx, Error **errp)
+{
+    struct SocketArgs *sa = &outgoing_migrate_params.socket_args[idx];
+    SocketAddress *src_addr, *dst_addr;
+
+    src_addr = socket_parse(src_uri, errp);
+    if (!src_addr) {
+        return;
+    }
+
+    dst_addr = socket_parse(dst_uri, errp);
+    if (!dst_addr) {
+        return;
+    }
+
+    sa->address.dst_addr = dst_addr;
+    sa->address.src_addr = src_addr;
+    sa->multifd_channels = multifd_channels;
+}
+
 static void socket_accept_incoming_migration(QIONetListener *listener,
                                              QIOChannelSocket *cioc,
                                              gpointer opaque)
diff --git a/migration/socket.h b/migration/socket.h
index dc54df4e6c..0cbb7220ac 100644
--- a/migration/socket.h
+++ b/migration/socket.h
@@ -19,13 +19,30 @@
 
 #include "io/channel.h"
 #include "io/task.h"
+#include "migration.h"
 
+/* info regarding destination and source uri */
+typedef struct SrcDestAddr {
+    SocketAddress *dst_addr;
+    SocketAddress *src_addr;
+} SrcDestAddr;
+
+
+int outgoing_param_total_multifds(void);
 void socket_send_channel_create(QIOTaskFunc f, void *data);
 QIOChannel *socket_send_channel_create_sync(Error **errp);
 int socket_send_channel_destroy(QIOChannel *send);
 
 void socket_start_incoming_migration(const char *str, Error **errp);
 
-void socket_start_outgoing_migration(MigrationState *s, const char *str,
+void socket_start_outgoing_migration(MigrationState *s, const char *dst_str,
                                      Error **errp);
+
+int multifd_list_length(MigrateUriParameterList *list);
+
+void init_multifd_array(int length);
+
+void store_multifd_migration_params(const char *dst_uri, const char *src_uri,
+                                    uint8_t multifd_channels, int idx,
+                                    Error **erp);
 #endif
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 6bb6424215..8d25fee4be 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -59,6 +59,7 @@
 #include "migration/snapshot.h"
 #include "migration/misc.h"
 
+
 #ifdef CONFIG_SPICE
 #include <spice/enums.h>
 #endif
diff --git a/qapi/migration.json b/qapi/migration.json
index 81185d4311..456247af8f 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1449,12 +1449,37 @@
 ##
 { 'command': 'migrate-continue', 'data': {'state': 'MigrationStatus'} }
 
+##
+# @MigrateUriParameter:
+#
+# Information regarding which source interface is connected to which
+# destination interface and number of multifd channels over each interface.
+#
+# @source-uri: uri of the source VM. Default port number is 0.
+#
+# @destination-uri: uri of the destination VM
+#
+# @multifd-channels: number of parallel multifd channels used to migrate data
+#                    for specific source-uri and destination-uri. Default value
+#                    in this case is 2 (Since 7.1)
+#
+##
+{ 'struct' : 'MigrateUriParameter',
+  'data' : { 'source-uri' : 'str',
+             'destination-uri' : 'str',
+             '*multifd-channels' : 'uint8'} }
+
 ##
 # @migrate:
 #
 # Migrates the current running guest to another Virtual Machine.
 #
 # @uri: the Uniform Resource Identifier of the destination VM
+#       for migration thread
+#
+# @multi-fd-uri-list: list of pair of source and destination VM Uniform
+#                     Resource Identifiers with number of multifd-channels
+#                     for each pair
 #
 # @blk: do block migration (full disk copy)
 #
@@ -1474,20 +1499,32 @@
 # 1. The 'query-migrate' command should be used to check migration's progress
 #    and final result (this information is provided by the 'status' member)
 #
-# 2. All boolean arguments default to false
+# 2. The uri argument should have the Uniform Resource Identifier of default
+#    destination VM. This connection will be bound to default network
 #
-# 3. The user Monitor's "detach" argument is invalid in QMP and should not
+# 3. All boolean arguments default to false
+#
+# 4. The user Monitor's "detach" argument is invalid in QMP and should not
 #    be used
 #
 # Example:
 #
-# -> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
+# -> { "execute": "migrate",
+#      "arguments": {
+#          "uri": "tcp:0:4446",
+#          "multi-fd-uri-list": [ { "source-uri": "tcp::6900",
+#                                   "destination-uri": "tcp:0:4480",
+#                                   "multifd-channels": 4},
+#                                 { "source-uri": "tcp:10.0.0.0: ",
+#                                   "destination-uri": "tcp:11.0.0.0:7789",
+#                                   "multifd-channels": 5} ] } }
 # <- { "return": {} }
 #
 ##
 { 'command': 'migrate',
-  'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool',
-           '*detach': 'bool', '*resume': 'bool' } }
+  'data': {'uri': 'str', '*multi-fd-uri-list': ['MigrateUriParameter'],
+           '*blk': 'bool', '*inc': 'bool', '*detach': 'bool',
+           '*resume': 'bool' } }
 
 ##
 # @migrate-incoming:
-- 
2.22.3


Reply via email to