diff mbox

[5/6] migration: Now set the migration uri

Message ID 20171030112112.6952-6-quintela@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Juan Quintela Oct. 30, 2017, 11:21 a.m. UTC
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/migration.c | 25 ++++++++++++++++++-------
 migration/migration.h |  2 ++
 migration/socket.c    |  7 +++++++
 3 files changed, 27 insertions(+), 7 deletions(-)

Comments

Daniel P. Berrangé Nov. 3, 2017, 10:07 a.m. UTC | #1
On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
>  migration/migration.c | 25 ++++++++++++++++++-------
>  migration/migration.h |  2 ++
>  migration/socket.c    |  7 +++++++
>  3 files changed, 27 insertions(+), 7 deletions(-)


> diff --git a/migration/socket.c b/migration/socket.c
> index 3a8232dd2d..c3ab81d1fb 100644
> --- a/migration/socket.c
> +++ b/migration/socket.c
> @@ -187,7 +187,14 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
>      Error *err = NULL;
>      SocketAddress *saddr = tcp_build_address(host_port, &err);
>      if (!err) {
> +        char *new_uri;
>          socket_start_incoming_migration(saddr, &err);
> +        if (!err) {
> +            new_uri = g_strdup_printf("tcp:%s:%s", saddr->u.inet.host,
> +                                      saddr->u.inet.port);

This is bad as it is throwing away data that the original URI had. In particular
you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
original URI for later, then why not just keep the 'host_port' parameter that
was passed into this function instead of trying to reverse engineeer the URI ?


Regards,
Daniel
Juan Quintela Nov. 22, 2017, 12:29 p.m. UTC | #2
"Daniel P. Berrange" <berrange@redhat.com> wrote:
> On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>>  migration/migration.c | 25 ++++++++++++++++++-------
>>  migration/migration.h |  2 ++
>>  migration/socket.c    |  7 +++++++
>>  3 files changed, 27 insertions(+), 7 deletions(-)
>
>
>> diff --git a/migration/socket.c b/migration/socket.c
>> index 3a8232dd2d..c3ab81d1fb 100644
>> --- a/migration/socket.c
>> +++ b/migration/socket.c
>> @@ -187,7 +187,14 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
>>      Error *err = NULL;
>>      SocketAddress *saddr = tcp_build_address(host_port, &err);
>>      if (!err) {
>> +        char *new_uri;
>>          socket_start_incoming_migration(saddr, &err);
>> +        if (!err) {
>> +            new_uri = g_strdup_printf("tcp:%s:%s", saddr->u.inet.host,
>> +                                      saddr->u.inet.port);
>
> This is bad as it is throwing away data that the original URI had. In particular
> you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
> original URI for later, then why not just keep the 'host_port' parameter that
> was passed into this function instead of trying to reverse engineeer the URI ?

I don't need the original uri anymore, this is the incoming side of
migration, and we can only set that once, if migration fails, we need to
restart qemu anymore.

I changed it to this:

            new_uri = g_strdup_printf("tcp:%s:%s%s%s", address->u.inet.host,
                                      address->u.inet.port,
                                      iaddr->has_ipv4 ? ",ipv4" : "",
                                      iaddr->has_ipv6 ? ",ipv6" : "");


Clearly, we don't care about the to= parameter.

The whole point of this exercise is that in destination, we use

-incoming tcp:0:0

and with the output of info migrate_parameters (uri) we are able to
migrate to that place.  For rest of migration posibilities, there is no
changes at all.


Thanks, Juan.
Daniel P. Berrangé Nov. 22, 2017, 12:54 p.m. UTC | #3
On Wed, Nov 22, 2017 at 01:29:57PM +0100, Juan Quintela wrote:
> "Daniel P. Berrange" <berrange@redhat.com> wrote:
> > On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:
> >> Signed-off-by: Juan Quintela <quintela@redhat.com>
> >> ---
> >>  migration/migration.c | 25 ++++++++++++++++++-------
> >>  migration/migration.h |  2 ++
> >>  migration/socket.c    |  7 +++++++
> >>  3 files changed, 27 insertions(+), 7 deletions(-)
> >
> >
> >> diff --git a/migration/socket.c b/migration/socket.c
> >> index 3a8232dd2d..c3ab81d1fb 100644
> >> --- a/migration/socket.c
> >> +++ b/migration/socket.c
> >> @@ -187,7 +187,14 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
> >>      Error *err = NULL;
> >>      SocketAddress *saddr = tcp_build_address(host_port, &err);
> >>      if (!err) {
> >> +        char *new_uri;
> >>          socket_start_incoming_migration(saddr, &err);
> >> +        if (!err) {
> >> +            new_uri = g_strdup_printf("tcp:%s:%s", saddr->u.inet.host,
> >> +                                      saddr->u.inet.port);
> >
> > This is bad as it is throwing away data that the original URI had. In particular
> > you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
> > original URI for later, then why not just keep the 'host_port' parameter that
> > was passed into this function instead of trying to reverse engineeer the URI ?
> 
> I don't need the original uri anymore, this is the incoming side of
> migration, and we can only set that once, if migration fails, we need to
> restart qemu anymore.
> 
> I changed it to this:
> 
>             new_uri = g_strdup_printf("tcp:%s:%s%s%s", address->u.inet.host,
>                                       address->u.inet.port,
>                                       iaddr->has_ipv4 ? ",ipv4" : "",
>                                       iaddr->has_ipv6 ? ",ipv6" : "");
> 
> 
> Clearly, we don't care about the to= parameter.
> 
> The whole point of this exercise is that in destination, we use
> 
> -incoming tcp:0:0
> 
> and with the output of info migrate_parameters (uri) we are able to
> migrate to that place.  For rest of migration posibilities, there is no
> changes at all.

That doesn't work typically. When the incoming QEMU listens for connections,
by default it will listen on 0.0.0.0, or ::, so that's what the address
you're creating will contain.  You can't use 0.0.0.0 or :: in a connect()
call on the other side as that's a wildcard address that refers to "any 
valid IP address on the current host".

When you connect to the listening QEMU you need the actual IP address
of one (of the possibly many) NICs on the target host.  IOW, the only
time the listen address is useful is if you have told QEMU to listen on
a specific NIC's IP address, instead of the wildcard address.

This is the core reason why libvirt calls 'gethostname()' on the target
host to identify the primary IP address of the host, and uses that on the
source host to establish the connection.

Regards,
Daniel
Daniel P. Berrangé Nov. 22, 2017, 12:58 p.m. UTC | #4
On Wed, Nov 22, 2017 at 12:54:58PM +0000, Daniel P. Berrange wrote:
> On Wed, Nov 22, 2017 at 01:29:57PM +0100, Juan Quintela wrote:
> > "Daniel P. Berrange" <berrange@redhat.com> wrote:
> > > On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:
> > >> Signed-off-by: Juan Quintela <quintela@redhat.com>
> > >> ---
> > >>  migration/migration.c | 25 ++++++++++++++++++-------
> > >>  migration/migration.h |  2 ++
> > >>  migration/socket.c    |  7 +++++++
> > >>  3 files changed, 27 insertions(+), 7 deletions(-)
> > >
> > >
> > >> diff --git a/migration/socket.c b/migration/socket.c
> > >> index 3a8232dd2d..c3ab81d1fb 100644
> > >> --- a/migration/socket.c
> > >> +++ b/migration/socket.c
> > >> @@ -187,7 +187,14 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
> > >>      Error *err = NULL;
> > >>      SocketAddress *saddr = tcp_build_address(host_port, &err);
> > >>      if (!err) {
> > >> +        char *new_uri;
> > >>          socket_start_incoming_migration(saddr, &err);
> > >> +        if (!err) {
> > >> +            new_uri = g_strdup_printf("tcp:%s:%s", saddr->u.inet.host,
> > >> +                                      saddr->u.inet.port);
> > >
> > > This is bad as it is throwing away data that the original URI had. In particular
> > > you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
> > > original URI for later, then why not just keep the 'host_port' parameter that
> > > was passed into this function instead of trying to reverse engineeer the URI ?
> > 
> > I don't need the original uri anymore, this is the incoming side of
> > migration, and we can only set that once, if migration fails, we need to
> > restart qemu anymore.
> > 
> > I changed it to this:
> > 
> >             new_uri = g_strdup_printf("tcp:%s:%s%s%s", address->u.inet.host,
> >                                       address->u.inet.port,
> >                                       iaddr->has_ipv4 ? ",ipv4" : "",
> >                                       iaddr->has_ipv6 ? ",ipv6" : "");
> > 
> > 
> > Clearly, we don't care about the to= parameter.
> > 
> > The whole point of this exercise is that in destination, we use
> > 
> > -incoming tcp:0:0
> > 
> > and with the output of info migrate_parameters (uri) we are able to
> > migrate to that place.  For rest of migration posibilities, there is no
> > changes at all.
> 
> That doesn't work typically. When the incoming QEMU listens for connections,
> by default it will listen on 0.0.0.0, or ::, so that's what the address
> you're creating will contain.  You can't use 0.0.0.0 or :: in a connect()
> call on the other side as that's a wildcard address that refers to "any 
> valid IP address on the current host".
> 
> When you connect to the listening QEMU you need the actual IP address
> of one (of the possibly many) NICs on the target host.  IOW, the only
> time the listen address is useful is if you have told QEMU to listen on
> a specific NIC's IP address, instead of the wildcard address.
> 
> This is the core reason why libvirt calls 'gethostname()' on the target
> host to identify the primary IP address of the host, and uses that on the
> source host to establish the connection.

I should have said the port number info will still be useful (if you're
using the dynamic port allocation), it is just the IP address that's not
usable in general.

Regards,
Daniel
Juan Quintela Nov. 29, 2017, 4:43 p.m. UTC | #5
"Daniel P. Berrange" <berrange@redhat.com> wrote:
> On Wed, Nov 22, 2017 at 12:54:58PM +0000, Daniel P. Berrange wrote:
>> On Wed, Nov 22, 2017 at 01:29:57PM +0100, Juan Quintela wrote:
>> > "Daniel P. Berrange" <berrange@redhat.com> wrote:
>> > > On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:

> > > This is bad as it is throwing away data that the original URI
>> > > had. In particular
>> > > you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
>> > > original URI for later, then why not just keep the 'host_port' parameter that
>> > > was passed into this function instead of trying to reverse
>> > > engineeer the URI ?
>> > 
>> > I don't need the original uri anymore, this is the incoming side of
>> > migration, and we can only set that once, if migration fails, we need to
>> > restart qemu anymore.
>> > 
>> > I changed it to this:
>> > 
>> >             new_uri = g_strdup_printf("tcp:%s:%s%s%s", address->u.inet.host,
>> >                                       address->u.inet.port,
>> >                                       iaddr->has_ipv4 ? ",ipv4" : "",
>> >                                       iaddr->has_ipv6 ? ",ipv6" : "");
>> > 
>> > 
>> > Clearly, we don't care about the to= parameter.
>> > 
>> > The whole point of this exercise is that in destination, we use
>> > 
>> > -incoming tcp:0:0
>> > 
>> > and with the output of info migrate_parameters (uri) we are able to
>> > migrate to that place.  For rest of migration posibilities, there is no
>> > changes at all.
>> 
>> That doesn't work typically. When the incoming QEMU listens for connections,
>> by default it will listen on 0.0.0.0, or ::, so that's what the address
>> you're creating will contain.  You can't use 0.0.0.0 or :: in a connect()
>> call on the other side as that's a wildcard address that refers to "any 
>> valid IP address on the current host".
>> 
>> When you connect to the listening QEMU you need the actual IP address
>> of one (of the possibly many) NICs on the target host.  IOW, the only
>> time the listen address is useful is if you have told QEMU to listen on
>> a specific NIC's IP address, instead of the wildcard address.
>> 
>> This is the core reason why libvirt calls 'gethostname()' on the target
>> host to identify the primary IP address of the host, and uses that on the
>> source host to establish the connection.
>
> I should have said the port number info will still be useful (if you're
> using the dynamic port allocation), it is just the IP address that's not
> usable in general.

I gave up O:-)

I introduced tcp_port parameter, that is really what I wanted to know.
The test use case (the one that I am interested right now) is that I
do:

qemu-system-x86_64 ..... --incomping tcp:127.0.0.1:0

And I want to know the port that the destination gets to connect to it.
For migration, it don't really matters if we _also_ set the
address/ip/whatever it gets translated to, because it is not possible
right now to restart the migration incoming side (you need to restart
qemu for long and boring historic reasons).

So, I ended just adding:

+#
+# @tcp-port: Only used for tcp, to know what is the real port
+#                     (Since 2.12)
 #

And all the boilerplate code to access/setup this one.

BTW, I am not sure how  well the current code will work with a range of
ports, because we don't have a way to tell the source which one the
kernel/qemu decided to use O:-)

Later, Juan.
Daniel P. Berrangé Nov. 29, 2017, 4:48 p.m. UTC | #6
On Wed, Nov 29, 2017 at 05:43:35PM +0100, Juan Quintela wrote:
> "Daniel P. Berrange" <berrange@redhat.com> wrote:
> > On Wed, Nov 22, 2017 at 12:54:58PM +0000, Daniel P. Berrange wrote:
> >> On Wed, Nov 22, 2017 at 01:29:57PM +0100, Juan Quintela wrote:
> >> > "Daniel P. Berrange" <berrange@redhat.com> wrote:
> >> > > On Mon, Oct 30, 2017 at 12:21:11PM +0100, Juan Quintela wrote:
> 
> > > > This is bad as it is throwing away data that the original URI
> >> > > had. In particular
> >> > > you loose the 'ipv4=on|off' and 'ipv6=on|off' flags. If you need to keep the
> >> > > original URI for later, then why not just keep the 'host_port' parameter that
> >> > > was passed into this function instead of trying to reverse
> >> > > engineeer the URI ?
> >> > 
> >> > I don't need the original uri anymore, this is the incoming side of
> >> > migration, and we can only set that once, if migration fails, we need to
> >> > restart qemu anymore.
> >> > 
> >> > I changed it to this:
> >> > 
> >> >             new_uri = g_strdup_printf("tcp:%s:%s%s%s", address->u.inet.host,
> >> >                                       address->u.inet.port,
> >> >                                       iaddr->has_ipv4 ? ",ipv4" : "",
> >> >                                       iaddr->has_ipv6 ? ",ipv6" : "");
> >> > 
> >> > 
> >> > Clearly, we don't care about the to= parameter.
> >> > 
> >> > The whole point of this exercise is that in destination, we use
> >> > 
> >> > -incoming tcp:0:0
> >> > 
> >> > and with the output of info migrate_parameters (uri) we are able to
> >> > migrate to that place.  For rest of migration posibilities, there is no
> >> > changes at all.
> >> 
> >> That doesn't work typically. When the incoming QEMU listens for connections,
> >> by default it will listen on 0.0.0.0, or ::, so that's what the address
> >> you're creating will contain.  You can't use 0.0.0.0 or :: in a connect()
> >> call on the other side as that's a wildcard address that refers to "any 
> >> valid IP address on the current host".
> >> 
> >> When you connect to the listening QEMU you need the actual IP address
> >> of one (of the possibly many) NICs on the target host.  IOW, the only
> >> time the listen address is useful is if you have told QEMU to listen on
> >> a specific NIC's IP address, instead of the wildcard address.
> >> 
> >> This is the core reason why libvirt calls 'gethostname()' on the target
> >> host to identify the primary IP address of the host, and uses that on the
> >> source host to establish the connection.
> >
> > I should have said the port number info will still be useful (if you're
> > using the dynamic port allocation), it is just the IP address that's not
> > usable in general.
> 
> I gave up O:-)
> 
> I introduced tcp_port parameter, that is really what I wanted to know.
> The test use case (the one that I am interested right now) is that I
> do:
> 
> qemu-system-x86_64 ..... --incomping tcp:127.0.0.1:0
> 
> And I want to know the port that the destination gets to connect to it.
> For migration, it don't really matters if we _also_ set the
> address/ip/whatever it gets translated to, because it is not possible
> right now to restart the migration incoming side (you need to restart
> qemu for long and boring historic reasons).
> 
> So, I ended just adding:
> 
> +#
> +# @tcp-port: Only used for tcp, to know what is the real port
> +#                     (Since 2.12)
>  #
> 
> And all the boilerplate code to access/setup this one.
> 
> BTW, I am not sure how  well the current code will work with a range of
> ports, because we don't have a way to tell the source which one the
> kernel/qemu decided to use O:-)

Ultimately I think we need to be able to report a full list of
SocketAddress structs representing the listening addresses, because
we will eventually be listening on multiple distinct sockets. Currently
if a hostname resolves to multiple IP addrs, we only listen on the first
successful IP, but I have patches that fix this so we listen on multiple
IPs....

Regards,
Daniel
diff mbox

Patch

diff --git a/migration/migration.c b/migration/migration.c
index 3e48d37880..507226907b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -240,10 +240,21 @@  void migrate_send_rp_req_pages(MigrationIncomingState *mis, const char *rbname,
     }
 }
 
+void migrate_set_uri(const char *uri, Error **errp)
+{
+    MigrateSetParameters p = {
+        .has_uri = true,
+        .uri = (char *)uri,
+    };
+
+    qmp_migrate_set_parameters(&p, errp);
+}
+
 void qemu_start_incoming_migration(const char *uri, Error **errp)
 {
     const char *p;
 
+    migrate_set_uri(uri, errp);
     qapi_event_send_migration(MIGRATION_STATUS_SETUP, &error_abort);
     if (!strcmp(uri, "defer")) {
         deferred_incoming_migration(errp);
@@ -1363,7 +1374,7 @@  void qmp_migrate(const char *uri, bool has_blk, bool blk,
         error_setg(errp, "Guest is waiting for an incoming migration");
         return;
     }
-
+    migrate_set_uri(uri, errp);
     if (migration_is_blocked(errp)) {
         return;
     }
@@ -1388,20 +1399,20 @@  void qmp_migrate(const char *uri, bool has_blk, bool blk,
 
     s = migrate_init();
 
-    if (strstart(uri, "tcp:", &p)) {
+    if (strstart(s->parameters.uri, "tcp:", &p)) {
         tcp_start_outgoing_migration(s, p, &local_err);
 #ifdef CONFIG_RDMA
-    } else if (strstart(uri, "rdma:", &p)) {
+    } else if (strstart(s->parameters.uri, "rdma:", &p)) {
         rdma_start_outgoing_migration(s, p, &local_err);
 #endif
-    } else if (strstart(uri, "exec:", &p)) {
+    } else if (strstart(s->parameters.uri, "exec:", &p)) {
         exec_start_outgoing_migration(s, p, &local_err);
-    } else if (strstart(uri, "unix:", &p)) {
+    } else if (strstart(s->parameters.uri, "unix:", &p)) {
         unix_start_outgoing_migration(s, p, &local_err);
-    } else if (strstart(uri, "fd:", &p)) {
+    } else if (strstart(s->parameters.uri, "fd:", &p)) {
         fd_start_outgoing_migration(s, p, &local_err);
     } else {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri",
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "s->parameters.uri",
                    "a valid migration protocol");
         migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
                           MIGRATION_STATUS_FAILED);
diff --git a/migration/migration.h b/migration/migration.h
index 663415fe48..cb0ab4807a 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -210,4 +210,6 @@  void migrate_send_rp_pong(MigrationIncomingState *mis,
 void migrate_send_rp_req_pages(MigrationIncomingState *mis, const char* rbname,
                               ram_addr_t start, size_t len);
 
+void migrate_set_uri(const char *uri, Error **errp);
+
 #endif
diff --git a/migration/socket.c b/migration/socket.c
index 3a8232dd2d..c3ab81d1fb 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -187,7 +187,14 @@  void tcp_start_incoming_migration(const char *host_port, Error **errp)
     Error *err = NULL;
     SocketAddress *saddr = tcp_build_address(host_port, &err);
     if (!err) {
+        char *new_uri;
         socket_start_incoming_migration(saddr, &err);
+        if (!err) {
+            new_uri = g_strdup_printf("tcp:%s:%s", saddr->u.inet.host,
+                                      saddr->u.inet.port);
+            migrate_set_uri(new_uri, &err);
+            g_free(new_uri);
+        }
     }
     qapi_free_SocketAddress(saddr);
     error_propagate(errp, err);