diff mbox

[1/2] socket: treat ipv4=on,ipv6=on uniformly

Message ID 1393582579-10366-2-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Feb. 28, 2014, 10:16 a.m. UTC
In some cases, "ipv4=on,ipv6=on" means "try both kinds of address";
in others, it means "try IPv6 only" just by virtue of how the code
is structured.

Fix this to make things more consistent, and adjust coding style too.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 util/qemu-sockets.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

Comments

Markus Armbruster Feb. 28, 2014, 11:56 a.m. UTC | #1
Paolo Bonzini <pbonzini@redhat.com> writes:

> In some cases, "ipv4=on,ipv6=on" means "try both kinds of address";
> in others, it means "try IPv6 only" just by virtue of how the code
> is structured.
>
> Fix this to make things more consistent, and adjust coding style too.

Begs the question which one you're picking as the consistent
interpretation, "both" or "v6 only".
Gerd Hoffmann Feb. 28, 2014, 12:23 p.m. UTC | #2
On Fr, 2014-02-28 at 11:16 +0100, Paolo Bonzini wrote:
> In some cases, "ipv4=on,ipv6=on" means "try both kinds of address";
> in others, it means "try IPv6 only" just by virtue of how the code
> is structured.

> @@ -127,10 +127,13 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)

> -    if (qemu_opt_get_bool(opts, "ipv4", 0))
> -        ai.ai_family = PF_INET;
> -    if (qemu_opt_get_bool(opts, "ipv6", 0))
> -        ai.ai_family = PF_INET6;
> +    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
> +        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
> +            ai.ai_family = PF_INET;
> +        } else {
> +            ai.ai_family = PF_INET6;
> +        }
> +    }

This is wrong for the listening side.

ipv6 sockets can listen on both ipv4 and ipv6.  qemu configures ipv6
sockets to do that, unconditionally.

So ipv4=yes,ipv6=no works correctly.
ipv4=yes,ipv6=yes works too.
ipv4=no,ipv6=yes doesn't work, but to fix that you have to set the
IPV6_V6ONLY socket option according to the ipv4 option.

Canevat: Listening on both ipv4+ipv6 with a single file handle works for
the wildcard address only.  Specifying -- say --
host=localhost,ipv4=yes,ipv6=yes, then expect qemu to listen on both
127.0.0.1 and ::1 doesn't work.

This can only be fixed by allowing multiple listening filehandles.
Which is a non-trivial change as this also affects the public api (which
will have to report a list of listening addresses instead of a single
address).
 
> @@ -319,11 +322,12 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)

> -    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
> -        ai.ai_family = PF_INET;
> -    }
> -    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
> -        ai.ai_family = PF_INET6;
> +    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
> +        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
> +            ai.ai_family = PF_INET;
> +        } else {
> +            ai.ai_family = PF_INET6;
> +        }

For connect this change is fine I think.

> @@ -418,10 +422,13 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp)

> -    if (qemu_opt_get_bool(opts, "ipv4", 0))
> -        ai.ai_family = PF_INET;
> -    if (qemu_opt_get_bool(opts, "ipv6", 0))
> -        ai.ai_family = PF_INET6;
> +    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
> +        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
> +            ai.ai_family = PF_INET;
> +        } else {
> +            ai.ai_family = PF_INET6;
> +        }
> +    }

Not fully sure, but I think this is fine too.

cheers,
  Gerd
Paolo Bonzini Feb. 28, 2014, 12:44 p.m. UTC | #3
Il 28/02/2014 13:23, Gerd Hoffmann ha scritto:
> On Fr, 2014-02-28 at 11:16 +0100, Paolo Bonzini wrote:
>> In some cases, "ipv4=on,ipv6=on" means "try both kinds of address";
>> in others, it means "try IPv6 only" just by virtue of how the code
>> is structured.
>
>> @@ -127,10 +127,13 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
>
>> -    if (qemu_opt_get_bool(opts, "ipv4", 0))
>> -        ai.ai_family = PF_INET;
>> -    if (qemu_opt_get_bool(opts, "ipv6", 0))
>> -        ai.ai_family = PF_INET6;
>> +    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
>> +        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
>> +            ai.ai_family = PF_INET;
>> +        } else {
>> +            ai.ai_family = PF_INET6;
>> +        }
>> +    }
>
> This is wrong for the listening side.
>
> ipv6 sockets can listen on both ipv4 and ipv6.  qemu configures ipv6
> sockets to do that, unconditionally.
>
> So ipv4=yes,ipv6=no works correctly.
> ipv4=yes,ipv6=yes works too.
> ipv4=no,ipv6=yes doesn't work, but to fix that you have to set the
> IPV6_V6ONLY socket option according to the ipv4 option.
>
> Canevat: Listening on both ipv4+ipv6 with a single file handle works for
> the wildcard address only.  Specifying -- say --
> host=localhost,ipv4=yes,ipv6=yes, then expect qemu to listen on both
> 127.0.0.1 and ::1 doesn't work.
>
> This can only be fixed by allowing multiple listening filehandles.
> Which is a non-trivial change as this also affects the public api (which
> will have to report a list of listening addresses instead of a single
> address).

Thanks for teaching me!

Do you think patch 2 is okay alone?

Paolo
diff mbox

Patch

diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8818d7c..7a9065b 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -127,10 +127,13 @@  int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
     addr = qemu_opt_get(opts, "host");
 
     to = qemu_opt_get_number(opts, "to", 0);
-    if (qemu_opt_get_bool(opts, "ipv4", 0))
-        ai.ai_family = PF_INET;
-    if (qemu_opt_get_bool(opts, "ipv6", 0))
-        ai.ai_family = PF_INET6;
+    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
+        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+            ai.ai_family = PF_INET;
+        } else {
+            ai.ai_family = PF_INET6;
+        }
+    }
 
     /* lookup */
     if (port_offset)
@@ -319,11 +322,12 @@  static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
         return NULL;
     }
 
-    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
-        ai.ai_family = PF_INET;
-    }
-    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
-        ai.ai_family = PF_INET6;
+    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
+        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+            ai.ai_family = PF_INET;
+        } else {
+            ai.ai_family = PF_INET6;
+        }
     }
 
     /* lookup */
@@ -418,10 +422,13 @@  int inet_dgram_opts(QemuOpts *opts, Error **errp)
         return -1;
     }
 
-    if (qemu_opt_get_bool(opts, "ipv4", 0))
-        ai.ai_family = PF_INET;
-    if (qemu_opt_get_bool(opts, "ipv6", 0))
-        ai.ai_family = PF_INET6;
+    if (qemu_opt_get_bool(opts, "ipv4", 0) != qemu_opt_get_bool(opts, "ipv6", 0)) {
+        if (qemu_opt_get_bool(opts, "ipv4", 0)) {
+            ai.ai_family = PF_INET;
+        } else {
+            ai.ai_family = PF_INET6;
+        }
+    }
 
     if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,